From 5e4d6cab00cb29cd088ab7b62ab13aff103b64cb Mon Sep 17 00:00:00 2001 From: onefang Date: Sun, 19 May 2019 21:24:15 +1000 Subject: Dump OpenSim 0.9.0.1 into it's own branch. --- .../AssetTransaction/AgentAssetsTransactions.cs | 30 +- .../AssetTransaction/AssetTransactionModule.cs | 12 +- .../Agent/AssetTransaction/AssetXferUploader.cs | 295 ++- .../Region/CoreModules/Agent/IPBan/IPBanModule.cs | 8 +- .../Region/CoreModules/Agent/IPBan/SceneBanner.cs | 4 +- .../Agent/TextureSender/J2KDecoderModule.cs | 11 +- .../Region/CoreModules/Agent/Xfer/XferModule.cs | 365 +++- .../Region/CoreModules/Asset/CenomeAssetCache.cs | 38 +- OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs | 23 +- .../Region/CoreModules/Asset/FlotsamAssetCache.cs | 371 +++- .../CoreModules/Asset/GlynnTuckerAssetCache.cs | 24 +- .../Asset/Tests/FlotsamAssetCacheTests.cs | 2 +- .../Avatar/Attachments/AttachmentsModule.cs | 367 +++- .../Attachments/Tests/AttachmentsModuleTests.cs | 92 +- .../Avatar/AvatarFactory/AvatarFactoryModule.cs | 616 ++++-- .../Tests/AvatarFactoryModuleTests.cs | 18 +- .../Avatar/BakedTextures/XBakesModule.cs | 97 +- .../Region/CoreModules/Avatar/Chat/ChatModule.cs | 293 ++- .../Avatar/Chat/Tests/ChatModuleTests.cs | 67 +- .../CoreModules/Avatar/Combat/CombatModule.cs | 2 - .../Avatar/Commands/UserCommandsModule.cs | 8 +- .../CoreModules/Avatar/Dialog/DialogModule.cs | 6 +- .../Avatar/Friends/CallingCardModule.cs | 5 +- .../CoreModules/Avatar/Friends/FriendsModule.cs | 169 +- .../Avatar/Friends/FriendsRequestHandler.cs | 17 +- .../CoreModules/Avatar/Friends/HGFriendsModule.cs | 58 +- .../CoreModules/Avatar/Friends/HGStatusNotifier.cs | 2 +- .../Avatar/Friends/Tests/FriendModuleTests.cs | 2 +- .../CoreModules/Avatar/Gestures/GesturesModule.cs | 20 +- .../Region/CoreModules/Avatar/Gods/GodsModule.cs | 213 +- .../CoreModules/Avatar/Groups/GroupsModule.cs | 19 +- .../InstantMessage/HGMessageTransferModule.cs | 31 +- .../Avatar/InstantMessage/InstantMessageModule.cs | 69 +- .../Avatar/InstantMessage/MessageTransferModule.cs | 297 ++- .../Avatar/InstantMessage/MuteListModule.cs | 4 +- .../Avatar/InstantMessage/MuteListModuleTst.cs | 229 +++ .../Avatar/InstantMessage/OfflineMessageModule.cs | 132 +- .../Avatar/InstantMessage/XMuteModule.cs | 239 +++ .../Archiver/InventoryArchiveReadRequest.cs | 297 +-- .../Inventory/Archiver/InventoryArchiveUtils.cs | 38 +- .../Archiver/InventoryArchiveWriteRequest.cs | 48 +- .../Inventory/Archiver/InventoryArchiverModule.cs | 217 +- .../Tests/InventoryArchiveLoadPathTests.cs | 120 +- .../Archiver/Tests/InventoryArchiveLoadTests.cs | 84 +- .../Archiver/Tests/InventoryArchiveSaveTests.cs | 60 +- .../Archiver/Tests/InventoryArchiveTestCase.cs | 74 +- .../Inventory/Transfer/InventoryTransferModule.cs | 236 ++- .../Transfer/Tests/InventoryTransferModuleTests.cs | 178 +- .../Region/CoreModules/Avatar/Lure/HGLureModule.cs | 6 +- .../Region/CoreModules/Avatar/Lure/LureModule.cs | 30 +- .../Avatar/Profile/BasicProfileModule.cs | 6 +- .../Avatar/UserProfiles/UserProfileModule.cs | 986 +++++++-- .../Framework/Caps/CapabilitiesModule.cs | 150 +- .../Framework/DynamicAttributes/DAExampleModule.cs | 30 +- .../Framework/DynamicAttributes/DOExampleModule.cs | 24 +- .../EntityTransfer/EntityTransferModule.cs | 1709 ++++++++-------- .../EntityTransfer/EntityTransferStateMachine.cs | 44 +- .../EntityTransfer/HGEntityTransferModule.cs | 84 +- .../Framework/InterfaceCommander/Commander.cs | 20 +- .../Framework/InventoryAccess/HGAssetMapper.cs | 8 +- .../InventoryAccess/HGInventoryAccessModule.cs | 86 +- .../InventoryAccess/InventoryAccessModule.cs | 557 ++++-- .../InventoryAccess/Tests/HGAssetMapperTests.cs | 9 +- .../Tests/InventoryAccessModuleTests.cs | 64 +- .../CoreModules/Framework/Library/LibraryModule.cs | 6 +- .../Framework/Library/LocalInventoryService.cs | 15 +- .../Framework/Monitoring/MonitorModule.cs | 12 +- .../Framework/Search/BasicSearchModule.cs | 2 +- .../ServiceThrottle/ServiceThrottleModule.cs | 148 +- .../Statistics/Logging/BinaryLoggingModule.cs | 24 +- .../UserManagement/HGUserManagementModule.cs | 14 +- .../Tests/HGUserManagementModuleTests.cs | 2 +- .../UserManagement/UserManagementModule.cs | 345 +++- .../CoreModules/Hypergrid/HGWorldMapModule.cs | 8 +- .../Region/CoreModules/Properties/AssemblyInfo.cs | 10 +- .../DynamicTexture/DynamicTextureModule.cs | 147 +- .../Scripting/EMailModules/EmailModule.cs | 31 +- .../Scripting/HttpRequest/ScriptsHttpRequests.cs | 259 ++- .../HttpRequest/Tests/ScriptsHttpRequestsTests.cs | 22 +- .../CoreModules/Scripting/LSLHttp/UrlModule.cs | 542 +++-- .../Scripting/LoadImageURL/LoadImageURLModule.cs | 56 +- .../ScriptModuleComms/ScriptModuleCommsModule.cs | 10 +- .../VectorRender/Tests/VectorRenderModuleTests.cs | 48 +- .../Scripting/VectorRender/VectorRenderModule.cs | 122 +- .../Scripting/WorldComm/WorldCommModule.cs | 124 +- .../CoreModules/Scripting/XMLRPC/XMLRPCModule.cs | 6 +- .../Asset/AssetServiceInConnectorModule.cs | 6 +- .../AuthenticationServiceInConnectorModule.cs | 4 +- .../Grid/GridInfoServiceInConnectorModule.cs | 4 +- .../Hypergrid/HypergridServiceInConnectorModule.cs | 6 +- .../Inventory/InventoryServiceInConnectorModule.cs | 4 +- .../Land/LandServiceInConnectorModule.cs | 33 +- .../Login/LLLoginServiceInConnectorModule.cs | 4 +- .../MapImage/MapImageServiceInConnectorModule.cs | 4 +- .../Neighbour/NeighbourServiceInConnectorModule.cs | 2 +- .../SimulationServiceInConnectorModule.cs | 2 +- .../LocalUserProfilesServiceConnector.cs | 36 +- .../LocalAgentPreferencesServiceConnector.cs | 2 +- .../RemoteAgentPreferencesServiceConnector.cs | 6 +- .../ServiceConnectorsOut/Asset/HGAssetBroker.cs | 73 +- .../Asset/LocalAssetServiceConnector.cs | 44 +- .../Asset/RemoteAssetServiceConnector.cs | 6 +- .../LocalAuthenticationServiceConnector.cs | 11 +- .../RemoteAuthenticationServiceConnector.cs | 2 +- .../LocalAuthorizationServiceConnector.cs | 4 +- .../RemoteAuthorizationServiceConnector.cs | 16 +- .../Avatar/LocalAvatarServiceConnector.cs | 8 +- .../Avatar/RemoteAvatarServiceConnector.cs | 2 +- .../Grid/LocalGridServiceConnector.cs | 164 +- .../ServiceConnectorsOut/Grid/RegionCache.cs | 102 - .../ServiceConnectorsOut/Grid/RegionInfoCache.cs | 965 ++++++++- .../Grid/RemoteGridServiceConnector.cs | 154 +- .../Grid/Tests/GridConnectorsTests.cs | 6 +- .../GridUser/ActivityDetector.cs | 35 +- .../Inventory/HGInventoryBroker.cs | 70 +- .../Inventory/InventoryCache.cs | 13 +- .../Inventory/LocalInventoryServiceConnector.cs | 18 +- .../Inventory/RemoteXInventoryServiceConnector.cs | 16 +- .../Land/LocalLandServiceConnector.cs | 25 +- .../Land/RemoteLandServiceConnector.cs | 2 +- .../MapImage/MapImageServiceModule.cs | 52 +- .../MuteList/LocalMuteListServiceConnector.cs | 188 ++ .../MuteList/RemoteMuteListServiceConnector.cs | 143 ++ .../Neighbour/LocalNeighbourServiceConnector.cs | 147 -- .../Neighbour/NeighbourServiceOutConnector.cs | 136 ++ .../Neighbour/RemoteNeighourServiceConnector.cs | 157 -- .../Presence/PresenceDetector.cs | 18 +- .../Presence/Tests/PresenceConnectorsTests.cs | 2 +- .../Simulation/LocalSimulationConnector.cs | 10 +- .../Simulation/RemoteSimulationConnector.cs | 17 +- .../LocalUserAccountServiceConnector.cs | 55 +- .../RemoteUserAccountServiceConnector.cs | 61 +- .../UserAccounts/UserAccountCache.cs | 103 +- .../CoreModules/World/Access/AccessModule.cs | 2 +- .../World/Archiver/ArchiveReadRequest.cs | 363 +++- .../World/Archiver/ArchiveScenesGroup.cs | 4 +- .../World/Archiver/ArchiveWriteRequest.cs | 122 +- .../CoreModules/World/Archiver/ArchiverModule.cs | 93 +- .../CoreModules/World/Archiver/AssetsArchiver.cs | 11 +- .../CoreModules/World/Archiver/AssetsDearchiver.cs | 1 + .../CoreModules/World/Archiver/AssetsRequest.cs | 232 +-- .../World/Archiver/DearchiveScenesGroup.cs | 39 +- .../World/Archiver/Tests/ArchiverTests.cs | 209 +- .../World/Archiver/Tests/Resources/test-sound.wav | Bin .../Region/CoreModules/World/Cloud/CloudModule.cs | 86 +- .../CoreModules/World/Estate/EstateConnector.cs | 228 +++ .../World/Estate/EstateManagementCommands.cs | 38 +- .../World/Estate/EstateManagementModule.cs | 648 +++--- .../CoreModules/World/Estate/EstateModule.cs | 271 +++ .../World/Estate/EstateRequestHandler.cs | 300 +++ .../CoreModules/World/Estate/XEstateConnector.cs | 218 -- .../CoreModules/World/Estate/XEstateModule.cs | 255 --- .../World/Estate/XEstateRequestHandler.cs | 288 --- .../Region/CoreModules/World/Land/DwellModule.cs | 27 +- .../Region/CoreModules/World/Land/LandChannel.cs | 62 +- .../CoreModules/World/Land/LandManagementModule.cs | 1333 ++++++++----- .../Region/CoreModules/World/Land/LandObject.cs | 886 +++++++-- .../CoreModules/World/Land/PrimCountModule.cs | 177 +- .../World/Land/Tests/LandManagementModuleTests.cs | 40 +- .../World/Land/Tests/PrimCountModuleTests.cs | 224 +-- .../CoreModules/World/LegacyMap/MapImageModule.cs | 23 +- .../World/LegacyMap/ShadedMapTileRenderer.cs | 12 +- .../World/LegacyMap/TexturedMapTileRenderer.cs | 53 +- .../World/LightShare/LightShareModule.cs | 7 +- .../CoreModules/World/Media/Moap/MoapModule.cs | 255 +-- .../World/Media/Moap/Tests/MoapTests.cs | 36 +- .../World/Objects/BuySell/BuySellModule.cs | 92 +- .../World/Objects/Commands/ObjectCommandsModule.cs | 120 +- .../World/Permissions/PermissionsModule.cs | 2096 +++++++++++++------- .../World/Region/RegionCommandsModule.cs | 91 +- .../CoreModules/World/Region/RestartModule.cs | 186 +- .../World/Serialiser/SerialiseObjects.cs | 2 +- .../World/Serialiser/SerialiserModule.cs | 10 +- .../World/Serialiser/Tests/SerialiserTests.cs | 28 +- .../Region/CoreModules/World/Sound/SoundModule.cs | 174 +- OpenSim/Region/CoreModules/World/Sun/SunModule.cs | 12 +- .../World/Terrain/Effects/ChannelDigger.cs | 4 +- .../World/Terrain/Effects/CookieCutter.cs | 2 +- .../Terrain/Effects/DefaultTerrainGenerator.cs | 2 +- .../CoreModules/World/Terrain/FileLoaders/BMP.cs | 10 +- .../CoreModules/World/Terrain/FileLoaders/GIF.cs | 10 +- .../Terrain/FileLoaders/GenericSystemDrawing.cs | 81 +- .../CoreModules/World/Terrain/FileLoaders/JPEG.cs | 14 +- .../CoreModules/World/Terrain/FileLoaders/LLRAW.cs | 10 +- .../CoreModules/World/Terrain/FileLoaders/PNG.cs | 10 +- .../CoreModules/World/Terrain/FileLoaders/TIFF.cs | 10 +- .../World/Terrain/FloodBrushes/FlattenArea.cs | 11 +- .../World/Terrain/FloodBrushes/LowerArea.cs | 10 +- .../World/Terrain/FloodBrushes/NoiseArea.cs | 13 +- .../World/Terrain/FloodBrushes/RaiseArea.cs | 10 +- .../World/Terrain/FloodBrushes/RevertArea.cs | 10 +- .../World/Terrain/FloodBrushes/SmoothArea.cs | 11 +- .../World/Terrain/ITerrainFloodEffect.cs | 3 +- .../CoreModules/World/Terrain/ITerrainLoader.cs | 2 +- .../World/Terrain/ITerrainPaintableEffect.cs | 3 +- .../World/Terrain/PaintBrushes/ErodeSphere.cs | 29 +- .../World/Terrain/PaintBrushes/FlattenSphere.cs | 9 +- .../World/Terrain/PaintBrushes/LowerSphere.cs | 30 +- .../World/Terrain/PaintBrushes/NoiseSphere.cs | 13 +- .../World/Terrain/PaintBrushes/OlsenSphere.cs | 12 +- .../World/Terrain/PaintBrushes/RaiseSphere.cs | 32 +- .../World/Terrain/PaintBrushes/RevertSphere.cs | 14 +- .../World/Terrain/PaintBrushes/SmoothSphere.cs | 20 +- .../World/Terrain/PaintBrushes/WeatherSphere.cs | 10 +- .../CoreModules/World/Terrain/TerrainModifier.cs | 3 - .../CoreModules/World/Terrain/TerrainModule.cs | 698 ++++--- .../World/Terrain/Tests/TerrainModuleTests.cs | 4 +- .../CoreModules/World/Terrain/Tests/TerrainTest.cs | 10 +- .../World/Vegetation/VegetationModule.cs | 25 +- .../CoreModules/World/Warp3DMap/TerrainSplat.cs | 12 +- .../World/Warp3DMap/Warp3DImageModule.cs | 239 +-- .../World/Wind/Plugins/ConfigurableWind.cs | 19 +- .../World/Wind/Plugins/SimpleRandomWind.cs | 21 +- .../Region/CoreModules/World/Wind/WindModule.cs | 88 +- .../CoreModules/World/WorldMap/MapSearchModule.cs | 167 +- .../CoreModules/World/WorldMap/WorldMapModule.cs | 1579 ++++++++------- 216 files changed, 16956 insertions(+), 9969 deletions(-) create mode 100644 OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModuleTst.cs create mode 100644 OpenSim/Region/CoreModules/Avatar/InstantMessage/XMuteModule.cs delete mode 100644 OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs create mode 100644 OpenSim/Region/CoreModules/ServiceConnectorsOut/MuteList/LocalMuteListServiceConnector.cs create mode 100644 OpenSim/Region/CoreModules/ServiceConnectorsOut/MuteList/RemoteMuteListServiceConnector.cs delete mode 100644 OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs create mode 100644 OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/NeighbourServiceOutConnector.cs delete mode 100644 OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/RemoteNeighourServiceConnector.cs mode change 100644 => 100755 OpenSim/Region/CoreModules/World/Archiver/Tests/Resources/test-sound.wav create mode 100644 OpenSim/Region/CoreModules/World/Estate/EstateConnector.cs create mode 100644 OpenSim/Region/CoreModules/World/Estate/EstateModule.cs create mode 100644 OpenSim/Region/CoreModules/World/Estate/EstateRequestHandler.cs delete mode 100644 OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs delete mode 100644 OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs delete mode 100644 OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs index f56d17d..f48710f 100644 --- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs +++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs @@ -127,7 +127,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction if (estateModule.IsTerrainXfer(xferID)) return; } - + m_log.ErrorFormat( "[AGENT ASSET TRANSACTIONS]: Could not find uploader for xfer id {0}, packet id {1}, data length {2}", xferID, packetID, data.Length); @@ -152,7 +152,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction } } - public void RequestCreateInventoryItem(IClientAPI remoteClient, + public bool RequestCreateInventoryItem(IClientAPI remoteClient, UUID transactionID, UUID folderID, uint callbackID, string description, string name, sbyte invType, sbyte type, byte wearableType, uint nextOwnerMask) @@ -162,6 +162,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction uploader.RequestCreateInventoryItem( remoteClient, folderID, callbackID, description, name, invType, type, wearableType, nextOwnerMask); + + return true; } public void RequestUpdateTaskInventoryItem(IClientAPI remoteClient, @@ -170,6 +172,17 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction { AssetXferUploader uploader = RequestXferUploader(transactionID); + // Here we need to get the old asset to extract the + // texture UUIDs if it's a wearable. + if (item.Type == (int)AssetType.Bodypart || + item.Type == (int)AssetType.Clothing || + item.Type == (int)CustomAssetType.AnimationSet) + { + AssetBase oldAsset = m_Scene.AssetService.Get(item.AssetID.ToString()); + if (oldAsset != null) + uploader.SetOldData(oldAsset.Data); + } + uploader.RequestUpdateTaskInventoryItem(remoteClient, item); } @@ -178,7 +191,18 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction { AssetXferUploader uploader = RequestXferUploader(transactionID); + // Here we need to get the old asset to extract the + // texture UUIDs if it's a wearable. + if (item.AssetType == (int)AssetType.Bodypart || + item.AssetType == (int)AssetType.Clothing || + item.AssetType == (int)CustomAssetType.AnimationSet) + { + AssetBase oldAsset = m_Scene.AssetService.Get(item.AssetID.ToString()); + if (oldAsset != null) + uploader.SetOldData(oldAsset.Data); + } + uploader.RequestUpdateInventoryItem(remoteClient, item); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs index b67c0df..7d9f3b3 100644 --- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs +++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs @@ -43,7 +43,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction IAgentAssetTransactions { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + protected Scene m_Scene; private bool m_dumpAssetsToFile = false; private int m_levelUpload = 0; @@ -53,7 +53,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction /// private Dictionary AgentTransactions = new Dictionary(); - + #region Region Module interface public void Initialise(IConfigSource source) @@ -158,7 +158,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction /// /// /// - public void HandleItemCreationFromTransaction(IClientAPI remoteClient, + public bool HandleItemCreationFromTransaction(IClientAPI remoteClient, UUID transactionID, UUID folderID, uint callbackID, string description, string name, sbyte invType, sbyte type, byte wearableType, uint nextOwnerMask) @@ -169,7 +169,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); - transactions.RequestCreateInventoryItem(remoteClient, transactionID, + return transactions.RequestCreateInventoryItem(remoteClient, transactionID, folderID, callbackID, description, name, invType, type, wearableType, nextOwnerMask); } @@ -241,7 +241,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction // m_log.DebugFormat( // "[ASSET TRANSACTION MODULE]: HandleUDPUploadRequest - assetID: {0}, transaction {1}, type {2}, storeLocal {3}, tempFile {4}, data.Length {5}", // assetID, transactionID, type, storeLocal, tempFile, data.Length); - + if (((AssetType)type == AssetType.Texture || (AssetType)type == AssetType.Sound || (AssetType)type == AssetType.TextureTGA || @@ -255,7 +255,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction // check user level if (avatar != null) { - if (avatar.UserLevel < m_levelUpload) + if (avatar.GodController.UserLevel < m_levelUpload) { remoteClient.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); return; diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs index 5143204..52b9d0e 100644 --- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs +++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs @@ -28,6 +28,7 @@ using System; using System.IO; using System.Reflection; +using System.Collections.Generic; using log4net; using OpenMetaverse; using OpenSim.Framework; @@ -40,6 +41,23 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction { public class AssetXferUploader { + + private List defaultIDs = new List { + // Viewer's notion of the default texture + new UUID("5748decc-f629-461c-9a36-a35a221fe21f"), // others == default blank + new UUID("7ca39b4c-bd19-4699-aff7-f93fd03d3e7b"), // hair + new UUID("6522e74d-1660-4e7f-b601-6f48c1659a77"), // eyes + new UUID("c228d1cf-4b5d-4ba8-84f4-899a0796aa97"), // skin + new UUID("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"), // transparency for alpha + // opensim assets textures possibly obsolete now + new UUID("00000000-0000-1111-9999-000000000010"), + new UUID("00000000-0000-1111-9999-000000000011"), + new UUID("00000000-0000-1111-9999-000000000012"), + // other transparency defined in assets + new UUID("3a367d1c-bef1-6d43-7595-e88c1e3aadb3"), + new UUID("1578a2b1-5179-4b53-b618-fe00ca5a5594"), + }; + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); /// @@ -87,6 +105,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction private sbyte type = 0; private byte wearableType = 0; + private byte[] m_oldData = null; public ulong XferID; private Scene m_Scene; @@ -129,18 +148,27 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction if (XferID == xferID) { - if (m_asset.Data.Length > 1) - { - byte[] destinationArray = new byte[m_asset.Data.Length + data.Length]; - Array.Copy(m_asset.Data, 0, destinationArray, 0, m_asset.Data.Length); - Array.Copy(data, 0, destinationArray, m_asset.Data.Length, data.Length); - m_asset.Data = destinationArray; - } - else + lock (this) { - byte[] buffer2 = new byte[data.Length - 4]; - Array.Copy(data, 4, buffer2, 0, data.Length - 4); - m_asset.Data = buffer2; + int assetLength = m_asset.Data.Length; + int dataLength = data.Length; + + if (m_asset.Data.Length > 1) + { + byte[] destinationArray = new byte[assetLength + dataLength]; + Array.Copy(m_asset.Data, 0, destinationArray, 0, assetLength); + Array.Copy(data, 0, destinationArray, assetLength, dataLength); + m_asset.Data = destinationArray; + } + else + { + if (dataLength > 4) + { + byte[] buffer2 = new byte[dataLength - 4]; + Array.Copy(data, 4, buffer2, 0, dataLength - 4); + m_asset.Data = buffer2; + } + } } ourClient.SendConfirmXfer(xferID, packetID); @@ -230,24 +258,24 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction { m_uploadState = UploadState.Complete; - ourClient.SendAssetUploadCompleteMessage(m_asset.Type, true, m_asset.FullID); - + bool sucess = true; if (m_createItem) { - CompleteCreateItem(m_createItemCallback); + sucess = CompleteCreateItem(m_createItemCallback); } else if (m_updateItem) { - CompleteItemUpdate(m_updateItemData); + sucess = CompleteItemUpdate(m_updateItemData); } else if (m_updateTaskItem) { - CompleteTaskItemUpdate(m_updateTaskItemData); + sucess = CompleteTaskItemUpdate(m_updateTaskItemData); } -// else if (m_storeLocal) -// { -// m_Scene.AssetService.Store(m_asset); -// } + else if (m_asset.Local) + { + m_Scene.AssetService.Store(m_asset); + } + ourClient.SendAssetUploadCompleteMessage(m_asset.Type, sucess, m_asset.FullID); } m_log.DebugFormat( @@ -319,14 +347,16 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction m_asset.Description = item.Description; m_asset.Type = (sbyte)item.AssetType; - if (m_asset.FullID != UUID.Zero) - { + // remove redundante m_Scene.InventoryService.UpdateItem + // if uploadState == UploadState.Complete) +// if (m_asset.FullID != UUID.Zero) +// { // We must always store the item at this point even if the asset hasn't finished uploading, in order // to avoid a race condition when the appearance module retrieves the item to set the asset id in // the AvatarAppearance structure. - item.AssetID = m_asset.FullID; - m_Scene.InventoryService.UpdateItem(item); - } +// item.AssetID = m_asset.FullID; +// m_Scene.InventoryService.UpdateItem(item); +// } if (m_uploadState == UploadState.Complete) { @@ -334,10 +364,21 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction } else { -// m_log.DebugFormat( -// "[ASSET XFER UPLOADER]: Holding update inventory item request {0} for {1} pending completion of asset xfer for transaction {2}", -// item.Name, remoteClient.Name, transactionID); - + // do it here to avoid the eventual race condition + if (m_asset.FullID != UUID.Zero) + { + // We must always store the item at this point even if the asset hasn't finished uploading, in order + // to avoid a race condition when the appearance module retrieves the item to set the asset id in + // the AvatarAppearance structure. + item.AssetID = m_asset.FullID; + m_Scene.InventoryService.UpdateItem(item); + } + + + // m_log.DebugFormat( + // "[ASSET XFER UPLOADER]: Holding update inventory item request {0} for {1} pending completion of asset xfer for transaction {2}", + // item.Name, remoteClient.Name, transactionID); + m_updateItem = true; m_updateItemData = item; } @@ -370,36 +411,70 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction /// Store the asset for the given item when it has been uploaded. /// /// - private void CompleteItemUpdate(InventoryItemBase item) + private bool CompleteItemUpdate(InventoryItemBase item) { // m_log.DebugFormat( // "[ASSET XFER UPLOADER]: Storing asset {0} for earlier item update for {1} for {2}", // m_asset.FullID, item.Name, ourClient.Name); - m_Scene.AssetService.Store(m_asset); - - m_transactions.RemoveXferUploader(m_transactionID); + uint perms = ValidateAssets(); + if(perms == 0) + { + string error = string.Format("Not enough permissions on asset(s) referenced by item '{0}', update failed", item.Name); + ourClient.SendAlertMessage(error); + m_transactions.RemoveXferUploader(m_transactionID); + ourClient.SendBulkUpdateInventory(item); // invalid the change item on viewer cache + } + else + { + m_Scene.AssetService.Store(m_asset); + if (m_asset.FullID != UUID.Zero) + { + item.AssetID = m_asset.FullID; + m_Scene.InventoryService.UpdateItem(item); + } + ourClient.SendInventoryItemCreateUpdate(item, m_transactionID, 0); + m_transactions.RemoveXferUploader(m_transactionID); + m_Scene.EventManager.TriggerOnNewInventoryItemUploadComplete(item, 0); + } - m_Scene.EventManager.TriggerOnNewInventoryItemUploadComplete(ourClient.AgentId, (AssetType)type, m_asset.FullID, m_asset.Name, 0); + return perms != 0; } /// /// Store the asset for the given task item when it has been uploaded. /// /// - private void CompleteTaskItemUpdate(TaskInventoryItem taskItem) + private bool CompleteTaskItemUpdate(TaskInventoryItem taskItem) { // m_log.DebugFormat( // "[ASSET XFER UPLOADER]: Storing asset {0} for earlier task item update for {1} for {2}", // m_asset.FullID, taskItem.Name, ourClient.Name); - m_Scene.AssetService.Store(m_asset); + if(ValidateAssets() == 0) + { + m_transactions.RemoveXferUploader(m_transactionID); + string error = string.Format("Not enough permissions on asset(s) referenced by task item '{0}', update failed", taskItem.Name); + ourClient.SendAlertMessage(error); + // force old asset to viewers ?? + return false; + } + m_Scene.AssetService.Store(m_asset); m_transactions.RemoveXferUploader(m_transactionID); + return true; } - private void CompleteCreateItem(uint callbackID) + private bool CompleteCreateItem(uint callbackID) { + if(ValidateAssets() == 0) + { + m_transactions.RemoveXferUploader(m_transactionID); + string error = string.Format("Not enough permissions on asset(s) referenced by item '{0}', creation failed", m_name); + ourClient.SendAlertMessage(error); + return false; + } + m_Scene.AssetService.Store(m_asset); InventoryItemBase item = new InventoryItemBase(); @@ -420,13 +495,155 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction item.Flags = (uint) wearableType; item.CreationDate = Util.UnixTimeSinceEpoch(); + m_log.DebugFormat("[XFER]: Created item {0} with asset {1}", + item.ID, item.AssetID); + if (m_Scene.AddInventoryItem(item)) - ourClient.SendInventoryItemCreateUpdate(item, callbackID); + ourClient.SendInventoryItemCreateUpdate(item, m_transactionID, callbackID); else ourClient.SendAlertMessage("Unable to create inventory item"); m_transactions.RemoveXferUploader(m_transactionID); + return true; + } + + private uint ValidateAssets() + { + uint retPerms = 0x7fffffff; +// if(m_Scene.Permissions.BypassPermissions()) +// return retPerms; + + if (m_asset.Type == (sbyte)CustomAssetType.AnimationSet) + { + + AnimationSet animSet = new AnimationSet(m_asset.Data); + + retPerms &= animSet.Validate(x => { + const uint required = (uint)(PermissionMask.Transfer | PermissionMask.Copy); + uint perms = (uint)m_Scene.InventoryService.GetAssetPermissions(ourClient.AgentId, x); + // currrent yes/no rule + if ((perms & required) != required) + return 0; + return perms; + }); + + return retPerms; + } + + if (m_asset.Type == (sbyte)AssetType.Clothing || + m_asset.Type == (sbyte)AssetType.Bodypart) + { + const uint texturesfullPermMask = (uint)(PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Copy); + string content = System.Text.Encoding.ASCII.GetString(m_asset.Data); + string[] lines = content.Split(new char[] {'\n'}); + + // on current requiriment of full rigths assume old assets where accepted + Dictionary allowed = ExtractTexturesFromOldData(); + + int textures = 0; + + foreach (string line in lines) + { + try + { + if (line.StartsWith("textures ")) + textures = Convert.ToInt32(line.Substring(9)); + + else if (textures > 0) + { + string[] parts = line.Split(new char[] {' '}); + + UUID tx = new UUID(parts[1]); + int id = Convert.ToInt32(parts[0]); + + if (defaultIDs.Contains(tx) || tx == UUID.Zero || + (allowed.ContainsKey(id) && allowed[id] == tx)) + { + continue; + } + else + { + uint perms = (uint)m_Scene.InventoryService.GetAssetPermissions(ourClient.AgentId, tx); + + if ((perms & texturesfullPermMask) != texturesfullPermMask) + { + m_log.ErrorFormat("[ASSET UPLOADER]: REJECTED update with texture {0} from {1} because they do not own the texture", tx, ourClient.AgentId); + return 0; + } + else + { + retPerms &= perms; + } + } + textures--; + } + } + catch + { + // If it's malformed, skip it + } + } + } + return retPerms; + } + +/* not in use + /// + /// Get the asset data uploaded in this transfer. + /// + /// null if the asset has not finished uploading + public AssetBase GetAssetData() + { + if (m_uploadState == UploadState.Complete) + { + ValidateAssets(); + return m_asset; + } + + return null; + } +*/ + public void SetOldData(byte[] d) + { + m_oldData = d; } + private Dictionary ExtractTexturesFromOldData() + { + Dictionary result = new Dictionary(); + if (m_oldData == null) + return result; + + string content = System.Text.Encoding.ASCII.GetString(m_oldData); + string[] lines = content.Split(new char[] {'\n'}); + + int textures = 0; + + foreach (string line in lines) + { + try + { + if (line.StartsWith("textures ")) + { + textures = Convert.ToInt32(line.Substring(9)); + } + else if (textures > 0) + { + string[] parts = line.Split(new char[] {' '}); + + UUID tx = new UUID(parts[1]); + int id = Convert.ToInt32(parts[0]); + result[id] = tx; + textures--; + } + } + catch + { + // If it's malformed, skip it + } + } + + return result; + } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/Agent/IPBan/IPBanModule.cs b/OpenSim/Region/CoreModules/Agent/IPBan/IPBanModule.cs index 4b457b1..ff71593 100644 --- a/OpenSim/Region/CoreModules/Agent/IPBan/IPBanModule.cs +++ b/OpenSim/Region/CoreModules/Agent/IPBan/IPBanModule.cs @@ -38,7 +38,7 @@ using OpenSim.Region.Framework.Scenes; namespace OpenSim.Region.CoreModules.Agent.IPBan { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "IPBanModule")] - public class IPBanModule : ISharedRegionModule + public class IPBanModule : ISharedRegionModule { #region Implementation of ISharedRegionModule @@ -86,7 +86,7 @@ namespace OpenSim.Region.CoreModules.Agent.IPBan public void Close() { - + } public string Name @@ -107,9 +107,9 @@ namespace OpenSim.Region.CoreModules.Agent.IPBan /// matching domain (including "betasomewhere.com", "beta.somewhere.com", /// "somewhere.com.beta") - make sure to be reasonably specific in DNS /// bans. - /// + /// /// IP address bans match on first characters, so, - /// "127.0.0.1" will ban only that address, + /// "127.0.0.1" will ban only that address, /// "127.0.1" will ban "127.0.10.0" /// but "127.0.1." will ban only the "127.0.1.*" network /// diff --git a/OpenSim/Region/CoreModules/Agent/IPBan/SceneBanner.cs b/OpenSim/Region/CoreModules/Agent/IPBan/SceneBanner.cs index 8502006..b4c68e2 100644 --- a/OpenSim/Region/CoreModules/Agent/IPBan/SceneBanner.cs +++ b/OpenSim/Region/CoreModules/Agent/IPBan/SceneBanner.cs @@ -53,9 +53,9 @@ namespace OpenSim.Region.CoreModules.Agent.IPBan if (bans.Count > 0) { IClientIPEndpoint ipEndpoint; - if (client.TryGet(out ipEndpoint)) + if (client.TryGet(out ipEndpoint) && ipEndpoint.RemoteEndPoint != null) { - IPAddress end = ipEndpoint.EndPoint; + IPAddress end = ipEndpoint.RemoteEndPoint.Address; try { diff --git a/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs b/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs index 47dcbcd..6e4a710 100644 --- a/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs +++ b/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs @@ -57,13 +57,13 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender /// List of client methods to notify of results of decode private readonly Dictionary> m_notifyList = new Dictionary>(); /// Cache that will store decoded JPEG2000 layer boundary data - private IImprovedAssetCache m_cache; - private IImprovedAssetCache Cache + private IAssetCache m_cache; + private IAssetCache Cache { get { if (m_cache == null) - m_cache = m_scene.RequestModuleInterface(); + m_cache = m_scene.RequestModuleInterface(); return m_cache; } @@ -285,7 +285,7 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender // Cache Decoded layers SaveFileCacheForAsset(assetID, layers); } - + // Notify Interested Parties lock (m_notifyList) { @@ -369,7 +369,8 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender else if (Cache != null) { string assetName = "j2kCache_" + AssetId.ToString(); - AssetBase layerDecodeAsset = Cache.Get(assetName); + AssetBase layerDecodeAsset; + Cache.Get(assetName, out layerDecodeAsset); if (layerDecodeAsset != null) { diff --git a/OpenSim/Region/CoreModules/Agent/Xfer/XferModule.cs b/OpenSim/Region/CoreModules/Agent/Xfer/XferModule.cs index 4299726..1b6401a 100644 --- a/OpenSim/Region/CoreModules/Agent/Xfer/XferModule.cs +++ b/OpenSim/Region/CoreModules/Agent/Xfer/XferModule.cs @@ -28,10 +28,12 @@ using System; using System.Collections.Generic; using System.Reflection; +using System.Threading; using Nini.Config; using log4net; using OpenMetaverse; using OpenSim.Framework; +using OpenSim.Framework.Monitoring; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; @@ -45,9 +47,13 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer private Scene m_scene; private Dictionary NewFiles = new Dictionary(); private Dictionary Transfers = new Dictionary(); - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private object timeTickLock = new object(); + private double lastTimeTick = 0.0; + private double lastFilesExpire = 0.0; + private bool inTimeTick = false; + public struct XferRequest { public IClientAPI remoteClient; @@ -59,26 +65,30 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer private class FileData { public byte[] Data; - public int Count; + public int refsCount; + public double timeStampMS; } - + #region INonSharedRegionModule Members public void Initialise(IConfigSource config) { + lastTimeTick = Util.GetTimeStampMS() + 30000.0; + lastFilesExpire = lastTimeTick + 180000.0; } public void AddRegion(Scene scene) { m_scene = scene; - m_scene.EventManager.OnNewClient += NewClient; - m_scene.RegisterModuleInterface(this); + m_scene.EventManager.OnNewClient += NewClient; + m_scene.EventManager.OnRegionHeartbeatEnd += OnTimeTick; } public void RemoveRegion(Scene scene) { m_scene.EventManager.OnNewClient -= NewClient; + m_scene.EventManager.OnRegionHeartbeatEnd -= OnTimeTick; m_scene.UnregisterModuleInterface(this); m_scene = null; @@ -104,6 +114,41 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer #endregion + public void OnTimeTick(Scene scene) + { + // we are on a heartbeat thread we there can be several + if(Monitor.TryEnter(timeTickLock)) + { + if(!inTimeTick) + { + double now = Util.GetTimeStampMS(); + if(now - lastTimeTick > 1750.0) + { + + if(Transfers.Count == 0 && NewFiles.Count == 0) + lastTimeTick = now; + else + { + inTimeTick = true; + + //don't overload busy heartbeat + WorkManager.RunInThreadPool( + delegate + { + transfersTimeTick(now); + expireFiles(now); + + lastTimeTick = now; + inTimeTick = false; + }, + null, + "XferTimeTick"); + } + } + } + Monitor.Exit(timeTickLock); + } + } #region IXfer Members /// @@ -118,24 +163,45 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer { lock (NewFiles) { + double now = Util.GetTimeStampMS(); if (NewFiles.ContainsKey(fileName)) { - NewFiles[fileName].Count++; + NewFiles[fileName].refsCount++; NewFiles[fileName].Data = data; + NewFiles[fileName].timeStampMS = now; } else { FileData fd = new FileData(); - fd.Count = 1; + fd.refsCount = 1; fd.Data = data; + fd.timeStampMS = now; NewFiles.Add(fileName, fd); } } - return true; } #endregion + public void expireFiles(double now) + { + lock (NewFiles) + { + // hopefully we will not have many files so nasty code will do it + if(now - lastFilesExpire > 120000.0) + { + lastFilesExpire = now; + List expires = new List(); + foreach(string fname in NewFiles.Keys) + { + if(NewFiles[fname].refsCount == 0 && now - NewFiles[fname].timeStampMS > 120000.0) + expires.Add(fname); + } + foreach(string fname in expires) + NewFiles.Remove(fname); + } + } + } public void NewClient(IClientAPI client) { @@ -144,6 +210,51 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer client.OnAbortXfer += AbortXfer; } + public void OnClientClosed(IClientAPI client) + { + client.OnRequestXfer -= RequestXfer; + client.OnConfirmXfer -= AckPacket; + client.OnAbortXfer -= AbortXfer; + } + + private void RemoveOrDecrementFile(string fileName) + { + // NewFiles must be locked + + if (NewFiles.ContainsKey(fileName)) + { + if (NewFiles[fileName].refsCount == 1) + NewFiles.Remove(fileName); + else + NewFiles[fileName].refsCount--; + } + } + + public void transfersTimeTick(double now) + { + XferDownLoad[] xfrs; + lock(Transfers) + { + if(Transfers.Count == 0) + return; + + xfrs = new XferDownLoad[Transfers.Count]; + Transfers.Values.CopyTo(xfrs,0); + } + foreach(XferDownLoad xfr in xfrs) + { + if(xfr.checkTime(now)) + { + ulong xfrID = xfr.XferID; + lock(Transfers) + { + if(Transfers.ContainsKey(xfrID)) + Transfers.Remove(xfrID); + } + } + } + } + /// /// /// @@ -156,78 +267,52 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer { if (NewFiles.ContainsKey(fileName)) { - if (!Transfers.ContainsKey(xferID)) + lock(Transfers) { - byte[] fileData = NewFiles[fileName].Data; - XferDownLoad transaction = new XferDownLoad(fileName, fileData, xferID, remoteClient); - - Transfers.Add(xferID, transaction); - - if (transaction.StartSend()) - RemoveXferData(xferID); - - // The transaction for this file is either complete or on its way - RemoveOrDecrement(fileName); - + if (!Transfers.ContainsKey(xferID)) + { + byte[] fileData = NewFiles[fileName].Data; + int burstSize = remoteClient.GetAgentThrottleSilent((int)ThrottleOutPacketType.Asset) >> 11; + if(Transfers.Count > 1) + burstSize /= Transfers.Count; + XferDownLoad transaction = + new XferDownLoad(fileName, fileData, xferID, remoteClient, burstSize); + + Transfers.Add(xferID, transaction); + + transaction.StartSend(); + + // The transaction for this file is on its way + RemoveOrDecrementFile(fileName); + } } } else m_log.WarnFormat("[Xfer]: {0} not found", fileName); - } } public void AckPacket(IClientAPI remoteClient, ulong xferID, uint packet) { - lock (NewFiles) // This is actually to lock Transfers + lock (Transfers) { if (Transfers.ContainsKey(xferID)) { - XferDownLoad dl = Transfers[xferID]; if (Transfers[xferID].AckPacket(packet)) - { - RemoveXferData(xferID); - RemoveOrDecrement(dl.FileName); - } + Transfers.Remove(xferID); } } } - private void RemoveXferData(ulong xferID) - { - // NewFiles must be locked! - if (Transfers.ContainsKey(xferID)) - { - XferModule.XferDownLoad xferItem = Transfers[xferID]; - //string filename = xferItem.FileName; - Transfers.Remove(xferID); - xferItem.Data = new byte[0]; // Clear the data - xferItem.DataPointer = 0; - - } - } - public void AbortXfer(IClientAPI remoteClient, ulong xferID) { - lock (NewFiles) + lock (Transfers) { if (Transfers.ContainsKey(xferID)) - RemoveOrDecrement(Transfers[xferID].FileName); - - RemoveXferData(xferID); - } - } - - private void RemoveOrDecrement(string fileName) - { - // NewFiles must be locked - - if (NewFiles.ContainsKey(fileName)) - { - if (NewFiles[fileName].Count == 1) - NewFiles.Remove(fileName); - else - NewFiles[fileName].Count--; + { + Transfers[xferID].done(); + Transfers.Remove(xferID); + } } } @@ -236,52 +321,124 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer public class XferDownLoad { public IClientAPI Client; - private bool complete; public byte[] Data = new byte[0]; - public int DataPointer = 0; public string FileName = String.Empty; - public uint Packet = 0; - public uint Serial = 1; public ulong XferID = 0; - - public XferDownLoad(string fileName, byte[] data, ulong xferID, IClientAPI client) + public bool isDeleted = false; + + private object myLock = new object(); + private double lastsendTimeMS; + private int LastPacket; + private int lastBytes; + private int lastSentPacket; + private int lastAckPacket; + private int burstSize; + private int retries = 0; + + public XferDownLoad(string fileName, byte[] data, ulong xferID, IClientAPI client, int burstsz) { FileName = fileName; Data = data; XferID = xferID; Client = client; + burstSize = burstsz; } public XferDownLoad() { } + public void done() + { + if(!isDeleted) + { + Data = new byte[0]; + isDeleted = true; + } + } + /// /// Start a transfer /// /// True if the transfer is complete, false if not - public bool StartSend() + public void StartSend() { - if (Data.Length < 1000) + lock(myLock) { - // for now (testing) we only support files under 1000 bytes - byte[] transferData = new byte[Data.Length + 4]; - Array.Copy(Utils.IntToBytes(Data.Length), 0, transferData, 0, 4); - Array.Copy(Data, 0, transferData, 4, Data.Length); - Client.SendXferPacket(XferID, 0 + 0x80000000, transferData); - complete = true; + if(Data.Length == 0) //?? + { + LastPacket = 0; + lastBytes = 0; + burstSize = 0; + } + else + { + // payload of 1024bytes + LastPacket = Data.Length >> 10; + lastBytes = Data.Length & 0x3ff; + if(lastBytes == 0) + { + lastBytes = 1024; + LastPacket--; + } + + } + + lastAckPacket = -1; + lastSentPacket = -1; + + double now = Util.GetTimeStampMS(); + + SendBurst(now); + return; + } + } + + private void SendBurst(double now) + { + int start = lastAckPacket + 1; + int end = start + burstSize; + if (end > LastPacket) + end = LastPacket; + while(start <= end) + SendPacket(start++ , now); + } + + private void SendPacket(int pkt, double now) + { + if(pkt > LastPacket) + return; + + int pktsize; + uint pktid; + if (pkt == LastPacket) + { + pktsize = lastBytes; + pktid = (uint)pkt | 0x80000000u; } else { - byte[] transferData = new byte[1000 + 4]; + pktsize = 1024; + pktid = (uint)pkt; + } + + byte[] transferData; + if(pkt == 0) + { + transferData = new byte[pktsize + 4]; Array.Copy(Utils.IntToBytes(Data.Length), 0, transferData, 0, 4); - Array.Copy(Data, 0, transferData, 4, 1000); - Client.SendXferPacket(XferID, 0, transferData); - Packet++; - DataPointer = 1000; + Array.Copy(Data, 0, transferData, 4, pktsize); } + else + { + transferData = new byte[pktsize]; + Array.Copy(Data, pkt << 10, transferData, 0, pktsize); + } + + Client.SendXferPacket(XferID, pktid, transferData, false); - return complete; + lastSentPacket = pkt; + lastsendTimeMS = now; } /// @@ -291,30 +448,46 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer /// True if the transfer is complete, false otherwise public bool AckPacket(uint packet) { - if (!complete) + lock(myLock) { - if ((Data.Length - DataPointer) > 1000) + if(isDeleted) + return true; + + packet &= 0x7fffffff; + if(lastAckPacket < packet) + lastAckPacket = (int)packet; + + if(lastAckPacket == LastPacket) { - byte[] transferData = new byte[1000]; - Array.Copy(Data, DataPointer, transferData, 0, 1000); - Client.SendXferPacket(XferID, Packet, transferData); - Packet++; - DataPointer += 1000; + done(); + return true; } - else + double now = Util.GetTimeStampMS(); + SendPacket(lastSentPacket + 1, now); + return false; + } + } + + public bool checkTime(double now) + { + if(Monitor.TryEnter(myLock)) + { + if(!isDeleted) { - byte[] transferData = new byte[Data.Length - DataPointer]; - Array.Copy(Data, DataPointer, transferData, 0, Data.Length - DataPointer); - uint endPacket = Packet |= (uint) 0x80000000; - Client.SendXferPacket(XferID, endPacket, transferData); - Packet++; - DataPointer += (Data.Length - DataPointer); - - complete = true; + double timeMS = now - lastsendTimeMS; + if(timeMS > 60000.0) + done(); + else if(timeMS > 3500.0 && retries++ < 3) + { + burstSize >>= 1; + SendBurst(now); + } } - } - return complete; + Monitor.Exit(myLock); + return isDeleted; + } + return false; } } diff --git a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs index ebec9d2..403236c 100644 --- a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs @@ -41,16 +41,16 @@ namespace OpenSim.Region.CoreModules.Asset /// /// /// - /// Cache is enabled by setting "AssetCaching" configuration to value "CenomeMemoryAssetCache". - /// When cache is successfully enable log should have message + /// Cache is enabled by setting "AssetCaching" configuration to value "CenomeMemoryAssetCache". + /// When cache is successfully enable log should have message /// "[ASSET CACHE]: Cenome asset cache enabled (MaxSize = XXX bytes, MaxCount = XXX, ExpirationTime = XXX)". /// /// /// Cache's size is limited by two parameters: - /// maximal allowed size in bytes and maximal allowed asset count. When new asset + /// maximal allowed size in bytes and maximal allowed asset count. When new asset /// is added to cache that have achieved either size or count limitation, cache /// will automatically remove less recently used assets from cache. Additionally - /// asset's lifetime is controlled by expiration time. + /// asset's lifetime is controlled by expiration time. /// /// /// @@ -91,10 +91,10 @@ namespace OpenSim.Region.CoreModules.Asset /// /// [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "CenomeMemoryAssetCache")] - public class CenomeMemoryAssetCache : IImprovedAssetCache, ISharedRegionModule + public class CenomeMemoryAssetCache : IAssetCache, ISharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + /// /// Cache's default maximal asset count. /// @@ -119,7 +119,7 @@ namespace OpenSim.Region.CoreModules.Asset /// Asset's default expiration time in the cache. /// public static readonly TimeSpan DefaultExpirationTime = TimeSpan.FromMinutes(30.0); - + /// /// Cache object. /// @@ -192,7 +192,7 @@ namespace OpenSim.Region.CoreModules.Asset expirationTime); } - #region IImprovedAssetCache Members + #region IAssetCache Members public bool Check(string id) { @@ -213,7 +213,7 @@ namespace OpenSim.Region.CoreModules.Asset if (asset != null) { // m_log.DebugFormat("[CENOME ASSET CACHE]: Caching asset {0}", asset.ID); - + long size = asset.Data != null ? asset.Data.Length : 1; m_cache.Set(asset.ID, asset, size); m_cachedCount++; @@ -221,6 +221,11 @@ namespace OpenSim.Region.CoreModules.Asset } + public void CacheNegative(string id) + { + // We don't do negative caching + } + /// /// Clear asset cache. /// @@ -241,7 +246,7 @@ namespace OpenSim.Region.CoreModules.Asset } /// - /// Get asset stored + /// Get asset stored /// /// /// The asset's id. @@ -255,10 +260,9 @@ namespace OpenSim.Region.CoreModules.Asset /// Cache doesn't guarantee in any situation that asset is stored to it. /// /// - public AssetBase Get(string id) + public bool Get(string id, out AssetBase assetBase) { m_getCount++; - AssetBase assetBase; if (m_cache.TryGetValue(id, out assetBase)) m_hitCount++; @@ -278,8 +282,8 @@ namespace OpenSim.Region.CoreModules.Asset // if (null == assetBase) // m_log.DebugFormat("[CENOME ASSET CACHE]: Asset {0} not in cache", id); - - return assetBase; + + return true; } #endregion @@ -294,7 +298,7 @@ namespace OpenSim.Region.CoreModules.Asset get { return "CenomeMemoryAssetCache"; } } - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -308,7 +312,7 @@ namespace OpenSim.Region.CoreModules.Asset public void AddRegion(Scene scene) { if (m_enabled) - scene.RegisterModuleInterface(this); + scene.RegisterModuleInterface(this); } /// @@ -344,7 +348,7 @@ namespace OpenSim.Region.CoreModules.Asset if (name != Name) return; - + long maxSize = DefaultMaxSize; int maxCount = DefaultMaxCount; TimeSpan expirationTime = DefaultExpirationTime; diff --git a/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs index f720748..10c0e85 100644 --- a/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs @@ -40,7 +40,7 @@ using OpenSim.Services.Interfaces; namespace OpenSim.Region.CoreModules.Asset { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "CoreAssetCache")] - public class CoreAssetCache : ISharedRegionModule, IImprovedAssetCache + public class CoreAssetCache : ISharedRegionModule, IAssetCache { private static readonly ILog m_log = LogManager.GetLogger( @@ -54,7 +54,7 @@ namespace OpenSim.Region.CoreModules.Asset get { return "CoreAssetCache"; } } - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -98,7 +98,7 @@ namespace OpenSim.Region.CoreModules.Asset public void AddRegion(Scene scene) { if (m_Enabled) - scene.RegisterModuleInterface(this); + scene.RegisterModuleInterface(this); } public void RemoveRegion(Scene scene) @@ -110,12 +110,15 @@ namespace OpenSim.Region.CoreModules.Asset } //////////////////////////////////////////////////////////// - // IImprovedAssetCache + // IAssetCache // public bool Check(string id) { // XXX This is probably not an efficient implementation. - return Get(id) != null; + AssetBase asset; + if (!Get(id, out asset)) + return false; + return asset != null; } public void Cache(AssetBase asset) @@ -124,9 +127,15 @@ namespace OpenSim.Region.CoreModules.Asset m_Cache.Store(asset.ID, asset); } - public AssetBase Get(string id) + public void CacheNegative(string id) { - return (AssetBase)m_Cache.Get(id); + // We don't do negative caching + } + + public bool Get(string id, out AssetBase asset) + { + asset = (AssetBase)m_Cache.Get(id); + return true; } public void Expire(string id) diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index 17646fb..c1bf544 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -25,7 +25,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Uncomment to make asset Get requests for existing +// Uncomment to make asset Get requests for existing // #define WAIT_ON_INPROGRESS_REQUESTS using System; @@ -55,16 +55,18 @@ using OpenSim.Services.Interfaces; namespace OpenSim.Region.CoreModules.Asset { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "FlotsamAssetCache")] - public class FlotsamAssetCache : ISharedRegionModule, IImprovedAssetCache, IAssetService + public class FlotsamAssetCache : ISharedRegionModule, IAssetCache, IAssetService { private static readonly ILog m_log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); private bool m_Enabled; + private bool m_timerRunning; + private bool m_cleanupRunning; private const string m_ModuleName = "FlotsamAssetCache"; - private const string m_DefaultCacheDirectory = "../caches/assetcache"; + private const string m_DefaultCacheDirectory = "./assetcache"; private string m_CacheDirectory = m_DefaultCacheDirectory; private readonly List m_InvalidChars = new List(); @@ -76,6 +78,7 @@ namespace OpenSim.Region.CoreModules.Asset private static ulong m_RequestsForInprogress; private static ulong m_DiskHits; private static ulong m_MemoryHits; + private static ulong m_weakRefHits; #if WAIT_ON_INPROGRESS_REQUESTS private Dictionary m_CurrentlyWriting = new Dictionary(); @@ -89,12 +92,17 @@ namespace OpenSim.Region.CoreModules.Asset private ExpiringCache m_MemoryCache; private bool m_MemoryCacheEnabled = false; + private ExpiringCache m_negativeCache; + private bool m_negativeCacheEnabled = true; + private bool m_negativeCacheSliding = false; + // Expiration is expressed in hours. - private const double m_DefaultMemoryExpiration = 2; + private double m_MemoryExpiration = 0.016; private const double m_DefaultFileExpiration = 48; - private TimeSpan m_MemoryExpiration = TimeSpan.FromHours(m_DefaultMemoryExpiration); + // Negative cache is in seconds + private int m_negativeExpiration = 120; private TimeSpan m_FileExpiration = TimeSpan.FromHours(m_DefaultFileExpiration); - private TimeSpan m_FileExpirationCleanupTimer = TimeSpan.FromHours(0.166); + private TimeSpan m_FileExpirationCleanupTimer = TimeSpan.FromHours(1.0); private static int m_CacheDirectoryTiers = 1; private static int m_CacheDirectoryTierLen = 3; @@ -104,6 +112,11 @@ namespace OpenSim.Region.CoreModules.Asset private IAssetService m_AssetService; private List m_Scenes = new List(); + private object timerLock = new object(); + + private Dictionary weakAssetReferences = new Dictionary(); + private object weakAssetReferencesLock = new object(); + private bool m_updateFileTimeOnCacheHit = false; public FlotsamAssetCache() { @@ -111,7 +124,7 @@ namespace OpenSim.Region.CoreModules.Asset m_InvalidChars.AddRange(Path.GetInvalidFileNameChars()); } - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -124,7 +137,7 @@ namespace OpenSim.Region.CoreModules.Asset public void Initialise(IConfigSource source) { IConfig moduleConfig = source.Configs["Modules"]; - + if (moduleConfig != null) { string name = moduleConfig.GetString("AssetCaching", String.Empty); @@ -132,6 +145,7 @@ namespace OpenSim.Region.CoreModules.Asset if (name == Name) { m_MemoryCache = new ExpiringCache(); + m_negativeCache = new ExpiringCache(); m_Enabled = true; m_log.InfoFormat("[FLOTSAM ASSET CACHE]: {0} enabled", this.Name); @@ -148,12 +162,18 @@ namespace OpenSim.Region.CoreModules.Asset m_CacheDirectory = assetConfig.GetString("CacheDirectory", m_DefaultCacheDirectory); m_MemoryCacheEnabled = assetConfig.GetBoolean("MemoryCacheEnabled", m_MemoryCacheEnabled); - m_MemoryExpiration = TimeSpan.FromHours(assetConfig.GetDouble("MemoryCacheTimeout", m_DefaultMemoryExpiration)); - + m_MemoryExpiration = assetConfig.GetDouble("MemoryCacheTimeout", m_MemoryExpiration); + m_MemoryExpiration *= 3600.0; // config in hours to seconds + + m_negativeCacheEnabled = assetConfig.GetBoolean("NegativeCacheEnabled", m_negativeCacheEnabled); + m_negativeExpiration = assetConfig.GetInt("NegativeCacheTimeout", m_negativeExpiration); + m_negativeCacheSliding = assetConfig.GetBoolean("NegativeCacheSliding", m_negativeCacheSliding); + m_updateFileTimeOnCacheHit = assetConfig.GetBoolean("UpdateFileTimeOnCacheHit", m_updateFileTimeOnCacheHit); + #if WAIT_ON_INPROGRESS_REQUESTS m_WaitOnInprogressTimeout = assetConfig.GetInt("WaitOnInprogressTimeout", 3000); #endif - + m_LogLevel = assetConfig.GetInt("LogLevel", m_LogLevel); m_HitRateDisplay = (ulong)assetConfig.GetLong("HitRateDisplay", (long)m_HitRateDisplay); @@ -170,14 +190,6 @@ namespace OpenSim.Region.CoreModules.Asset m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Directory {0}", m_CacheDirectory); - if (m_FileCacheEnabled && (m_FileExpiration > TimeSpan.Zero) && (m_FileExpirationCleanupTimer > TimeSpan.Zero)) - { - m_CacheCleanTimer = new System.Timers.Timer(m_FileExpirationCleanupTimer.TotalMilliseconds); - m_CacheCleanTimer.AutoReset = true; - m_CacheCleanTimer.Elapsed += CleanupExpiredFiles; - lock (m_CacheCleanTimer) - m_CacheCleanTimer.Start(); - } if (m_CacheDirectoryTiers < 1) { @@ -217,9 +229,8 @@ namespace OpenSim.Region.CoreModules.Asset { if (m_Enabled) { - scene.RegisterModuleInterface(this); + scene.RegisterModuleInterface(this); m_Scenes.Add(scene); - } } @@ -227,23 +238,61 @@ namespace OpenSim.Region.CoreModules.Asset { if (m_Enabled) { - scene.UnregisterModuleInterface(this); + scene.UnregisterModuleInterface(this); m_Scenes.Remove(scene); + lock(timerLock) + { + if(m_timerRunning && m_Scenes.Count <= 0) + { + m_timerRunning = false; + m_CacheCleanTimer.Stop(); + m_CacheCleanTimer.Close(); + } + } } } public void RegionLoaded(Scene scene) { - if (m_Enabled && m_AssetService == null) - m_AssetService = scene.RequestModuleInterface(); + if (m_Enabled) + { + if(m_AssetService == null) + m_AssetService = scene.RequestModuleInterface(); + lock(timerLock) + { + if(!m_timerRunning) + { + if (m_FileCacheEnabled && (m_FileExpiration > TimeSpan.Zero) && (m_FileExpirationCleanupTimer > TimeSpan.Zero)) + { + m_CacheCleanTimer = new System.Timers.Timer(m_FileExpirationCleanupTimer.TotalMilliseconds); + m_CacheCleanTimer.AutoReset = false; + m_CacheCleanTimer.Elapsed += CleanupExpiredFiles; + m_CacheCleanTimer.Start(); + m_timerRunning = true; + } + } + } + if (m_MemoryCacheEnabled) + m_MemoryCache = new ExpiringCache(); + + lock(weakAssetReferencesLock) + weakAssetReferences = new Dictionary(); + } } //////////////////////////////////////////////////////////// - // IImprovedAssetCache + // IAssetCache // + private void UpdateWeakReference(string key, AssetBase asset) + { + WeakReference aref = new WeakReference(asset); + lock(weakAssetReferencesLock) + weakAssetReferences[key] = aref; + } private void UpdateMemoryCache(string key, AssetBase asset) { + // NOTE DO NOT USE SLIDEEXPIRE option on current libomv m_MemoryCache.AddOrUpdate(key, asset, m_MemoryExpiration); } @@ -257,11 +306,11 @@ namespace OpenSim.Region.CoreModules.Asset if (File.Exists(filename)) { UpdateFileLastAccessTime(filename); - } - else + } + else { // Once we start writing, make sure we flag that we're writing - // that object to the cache so that we don't try to write the + // that object to the cache so that we don't try to write the // same file multiple times. lock (m_CurrentlyWriting) { @@ -306,6 +355,7 @@ namespace OpenSim.Region.CoreModules.Asset if (asset != null) { //m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Caching asset with id {0}", asset.ID); + UpdateWeakReference(asset.ID, asset); if (m_MemoryCacheEnabled) UpdateMemoryCache(asset.ID, asset); @@ -315,6 +365,17 @@ namespace OpenSim.Region.CoreModules.Asset } } + public void CacheNegative(string id) + { + if (m_negativeCacheEnabled) + { + if (m_negativeCacheSliding) + m_negativeCache.AddOrUpdate(id, null, TimeSpan.FromSeconds(m_negativeExpiration)); + else + m_negativeCache.AddOrUpdate(id, null, m_negativeExpiration); + } + } + /// /// Updates the cached file with the current time. /// @@ -333,6 +394,25 @@ namespace OpenSim.Region.CoreModules.Asset } } + private AssetBase GetFromWeakReference(string id) + { + AssetBase asset = null; + WeakReference aref; + + lock(weakAssetReferencesLock) + { + if (weakAssetReferences.TryGetValue(id, out aref)) + { + asset = aref.Target as AssetBase; + if(asset == null) + weakAssetReferences.Remove(id); + else + m_weakRefHits++; + } + } + return asset; + } + /// /// Try to get an asset from the in-memory cache. /// @@ -359,7 +439,7 @@ namespace OpenSim.Region.CoreModules.Asset /// /// An asset retrieved from the file cache. null if there was a problem retrieving an asset. private AssetBase GetFromFileCache(string id) - { + { string filename = GetFileName(id); #if WAIT_ON_INPROGRESS_REQUESTS @@ -394,6 +474,8 @@ namespace OpenSim.Region.CoreModules.Asset { using (FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) { + if (stream.Length == 0) // Empty file will trigger exception below + return null; BinaryFormatter bformatter = new BinaryFormatter(); asset = (AssetBase)bformatter.Deserialize(stream); @@ -451,23 +533,57 @@ namespace OpenSim.Region.CoreModules.Asset return found; } + // For IAssetService public AssetBase Get(string id) { + AssetBase asset; + Get(id, out asset); + return asset; + } + + public bool Get(string id, out AssetBase asset) + { + asset = null; + m_Requests++; - AssetBase asset = null; + object dummy; + if (m_negativeCache.TryGetValue(id, out dummy)) + { + return false; + } - if (m_MemoryCacheEnabled) + asset = GetFromWeakReference(id); + if (asset != null && m_updateFileTimeOnCacheHit) + { + string filename = GetFileName(id); + UpdateFileLastAccessTime(filename); + } + + if (m_MemoryCacheEnabled && asset == null) + { asset = GetFromMemoryCache(id); + if(asset != null) + { + UpdateWeakReference(id,asset); + if (m_updateFileTimeOnCacheHit) + { + string filename = GetFileName(id); + UpdateFileLastAccessTime(filename); + } + } + } if (asset == null && m_FileCacheEnabled) { asset = GetFromFileCache(id); - - if (m_MemoryCacheEnabled && asset != null) - UpdateMemoryCache(id, asset); + if(asset != null) + UpdateWeakReference(id,asset); } + if (m_MemoryCacheEnabled && asset != null) + UpdateMemoryCache(id, asset); + if (((m_LogLevel >= 1)) && (m_HitRateDisplay != 0) && (m_Requests % m_HitRateDisplay == 0)) { m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Get :: {0} :: {1}", id, asset == null ? "Miss" : "Hit"); @@ -475,7 +591,7 @@ namespace OpenSim.Region.CoreModules.Asset GenerateCacheHitReport().ForEach(l => m_log.InfoFormat("[FLOTSAM ASSET CACHE]: {0}", l)); } - return asset; + return true; } public bool Check(string id) @@ -490,7 +606,9 @@ namespace OpenSim.Region.CoreModules.Asset public AssetBase GetCached(string id) { - return Get(id); + AssetBase asset; + Get(id, out asset); + return asset; } public void Expire(string id) @@ -511,6 +629,9 @@ namespace OpenSim.Region.CoreModules.Asset if (m_MemoryCacheEnabled) m_MemoryCache.Remove(id); + + lock(weakAssetReferencesLock) + weakAssetReferences.Remove(id); } catch (Exception e) { @@ -525,7 +646,7 @@ namespace OpenSim.Region.CoreModules.Asset if (m_LogLevel >= 2) m_log.Debug("[FLOTSAM ASSET CACHE]: Clearing caches."); - if (m_FileCacheEnabled) + if (m_FileCacheEnabled && Directory.Exists(m_CacheDirectory)) { foreach (string dir in Directory.GetDirectories(m_CacheDirectory)) { @@ -534,7 +655,12 @@ namespace OpenSim.Region.CoreModules.Asset } if (m_MemoryCacheEnabled) - m_MemoryCache.Clear(); + m_MemoryCache = new ExpiringCache(); + if (m_negativeCacheEnabled) + m_negativeCache = new ExpiringCache(); + + lock(weakAssetReferencesLock) + weakAssetReferences = new Dictionary(); } private void CleanupExpiredFiles(object source, ElapsedEventArgs e) @@ -542,6 +668,12 @@ namespace OpenSim.Region.CoreModules.Asset if (m_LogLevel >= 2) m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Checking for expired files older then {0}.", m_FileExpiration); + lock(timerLock) + { + if(!m_timerRunning || m_cleanupRunning) + return; + m_cleanupRunning = true; + } // Purge all files last accessed prior to this point DateTime purgeLine = DateTime.Now - m_FileExpiration; @@ -549,27 +681,34 @@ namespace OpenSim.Region.CoreModules.Asset // before cleaning up expired files we must scan the objects in the scene to make sure that we retain // such local assets if they have not been recently accessed. TouchAllSceneAssets(false); + if(Directory.Exists(m_CacheDirectory)) + { + foreach (string dir in Directory.GetDirectories(m_CacheDirectory)) + CleanExpiredFiles(dir, purgeLine); + } - foreach (string dir in Directory.GetDirectories(m_CacheDirectory)) + lock(timerLock) { - CleanExpiredFiles(dir, purgeLine); + if(m_timerRunning) + m_CacheCleanTimer.Start(); + m_cleanupRunning = false; } } /// - /// Recurses through specified directory checking for asset files last - /// accessed prior to the specified purge line and deletes them. Also + /// Recurses through specified directory checking for asset files last + /// accessed prior to the specified purge line and deletes them. Also /// removes empty tier directories. /// /// /// private void CleanExpiredFiles(string dir, DateTime purgeLine) { - // Yet another "directory we are trying to remove doesn't exist, so don't complain" idiocy fix. - if (!Directory.Exists(dir)) - return; try { + if(!Directory.Exists(dir)) + return; + foreach (string file in Directory.GetFiles(dir)) { if (File.GetLastAccessTime(file) < purgeLine) @@ -593,14 +732,19 @@ namespace OpenSim.Region.CoreModules.Asset else if (dirSize >= m_CacheWarnAt) { m_log.WarnFormat( - "[FLOTSAM ASSET CACHE]: Cache folder exceeded CacheWarnAt limit {0} {1}. Suggest increasing tiers, tier length, or reducing cache expiration", + "[FLOTSAM ASSET CACHE]: Cache folder exceeded CacheWarnAt limit {0} {1}. Suggest increasing tiers, tier length, or reducing cache expiration", dir, dirSize); } } + catch (DirectoryNotFoundException) + { + // If we get here, another node on the same box has + // already removed the directory. Continue with next. + } catch (Exception e) { -//// TODO - I'm almost sure this is another case of failing to delete something that doesn't actually exist. -//// m_log.Warn(string.Format("[FLOTSAM ASSET CACHE]: Could not complete clean of expired files in {0}", dir)); + m_log.Warn( + string.Format("[FLOTSAM ASSET CACHE]: Could not complete clean of expired files in {0}, exception ", dir), e); } } @@ -628,7 +772,7 @@ namespace OpenSim.Region.CoreModules.Asset } /// - /// Writes a file to the file cache, creating any nessesary + /// Writes a file to the file cache, creating any nessesary /// tier directories along the way /// /// @@ -640,7 +784,7 @@ namespace OpenSim.Region.CoreModules.Asset // Make sure the target cache directory exists string directory = Path.GetDirectoryName(filename); - // Write file first to a temp name, so that it doesn't look + // Write file first to a temp name, so that it doesn't look // like it's already cached while it's still writing. string tempname = Path.Combine(directory, Path.GetRandomFileName()); @@ -652,7 +796,7 @@ namespace OpenSim.Region.CoreModules.Asset { Directory.CreateDirectory(directory); } - + stream = File.Open(tempname, FileMode.Create); BinaryFormatter bformatter = new BinaryFormatter(); bformatter.Serialize(stream, asset); @@ -665,6 +809,9 @@ namespace OpenSim.Region.CoreModules.Asset return; } + catch (UnauthorizedAccessException) + { + } finally { if (stream != null) @@ -686,7 +833,7 @@ namespace OpenSim.Region.CoreModules.Asset // This situation occurs fairly rarely anyway. We assume in this that moves are atomic on the // filesystem. File.Move(tempname, filename); - + if (m_LogLevel >= 2) m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Cache Stored :: {0}", asset.ID); } @@ -725,6 +872,9 @@ namespace OpenSim.Region.CoreModules.Asset /// private int GetFileCacheCount(string dir) { + if(!Directory.Exists(dir)) + return 0; + int count = Directory.GetFiles(dir).Length; foreach (string subdir in Directory.GetDirectories(dir)) @@ -743,7 +893,7 @@ namespace OpenSim.Region.CoreModules.Asset { string RegionCacheStatusFile = Path.Combine(m_CacheDirectory, "RegionStatus_" + regionID.ToString() + ".fac"); - try + try { if (File.Exists(RegionCacheStatusFile)) { @@ -752,7 +902,7 @@ namespace OpenSim.Region.CoreModules.Asset else { File.WriteAllText( - RegionCacheStatusFile, + RegionCacheStatusFile, "Please do not delete this file unless you are manually clearing your Flotsam Asset Cache."); } } @@ -760,14 +910,14 @@ namespace OpenSim.Region.CoreModules.Asset { m_log.Warn( string.Format( - "[FLOTSAM ASSET CACHE]: Could not stamp region status file for region {0}. Exception ", - regionID), + "[FLOTSAM ASSET CACHE]: Could not stamp region status file for region {0}. Exception ", + regionID), e); } } /// - /// Iterates through all Scenes, doing a deep scan through assets + /// Iterates through all Scenes, doing a deep scan through assets /// to update the access time of all assets present in the scene or referenced by assets /// in the scene. /// @@ -786,10 +936,16 @@ namespace OpenSim.Region.CoreModules.Asset StampRegionStatusFile(s.RegionInfo.RegionID); s.ForEachSOG(delegate(SceneObjectGroup e) - { + { + if(!m_timerRunning && !storeUncached) + return; + gatherer.AddForInspection(e); gatherer.GatherAll(); + if(!m_timerRunning && !storeUncached) + return; + foreach (UUID assetID in gatherer.GatheredUuids.Keys) { if (!assetsFound.ContainsKey(assetID)) @@ -799,6 +955,7 @@ namespace OpenSim.Region.CoreModules.Asset if (File.Exists(filename)) { UpdateFileLastAccessTime(filename); + assetsFound[assetID] = true; } else if (storeUncached) { @@ -818,7 +975,14 @@ namespace OpenSim.Region.CoreModules.Asset } gatherer.GatheredUuids.Clear(); + if(!m_timerRunning && !storeUncached) + return; + + if(!storeUncached) + Thread.Sleep(50); }); + if(!m_timerRunning && !storeUncached) + break; } return assetsFound.Count; @@ -829,6 +993,9 @@ namespace OpenSim.Region.CoreModules.Asset /// private void ClearFileCache() { + if(!Directory.Exists(m_CacheDirectory)) + return; + foreach (string dir in Directory.GetDirectories(m_CacheDirectory)) { try @@ -862,22 +1029,35 @@ namespace OpenSim.Region.CoreModules.Asset { List outputLines = new List(); - double fileHitRate = (double)m_DiskHits / m_Requests * 100.0; + double invReq = 100.0 / m_Requests; + + double weakHitRate = m_weakRefHits * invReq; + int weakEntries = weakAssetReferences.Count; + + double fileHitRate = m_DiskHits * invReq; + double TotalHitRate = weakHitRate + fileHitRate; + + outputLines.Add( + string.Format("Total requests: {0}", m_Requests)); outputLines.Add( - string.Format("File Hit Rate: {0}% for {1} requests", fileHitRate.ToString("0.00"), m_Requests)); + string.Format("unCollected Hit Rate: {0}% ({1} entries)", weakHitRate.ToString("0.00"),weakEntries)); + outputLines.Add( + string.Format("File Hit Rate: {0}%", fileHitRate.ToString("0.00"))); if (m_MemoryCacheEnabled) { - double memHitRate = (double)m_MemoryHits / m_Requests * 100.0; - + double HitRate = m_MemoryHits * invReq; outputLines.Add( - string.Format("Memory Hit Rate: {0}% for {1} requests", memHitRate.ToString("0.00"), m_Requests)); + string.Format("Memory Hit Rate: {0}%", HitRate.ToString("0.00"))); + + TotalHitRate += HitRate; } + outputLines.Add( + string.Format("Total Hit Rate: {0}%", TotalHitRate.ToString("0.00"))); outputLines.Add( string.Format( - "Unnecessary requests due to requests for assets that are currently downloading: {0}", - m_RequestsForInprogress)); + "Requests overlap during file writing: {0}", m_RequestsForInprogress)); return outputLines; } @@ -914,9 +1094,9 @@ namespace OpenSim.Region.CoreModules.Asset if (m_FileCacheEnabled) { con.Output("Deep scans have previously been performed on the following regions:"); - + foreach (string s in Directory.GetFiles(m_CacheDirectory, "*.fac")) - { + { string RegionID = s.Remove(0,s.IndexOf("_")).Replace(".fac",""); DateTime RegionDeepScanTMStamp = File.GetLastWriteTime(s); con.OutputFormat("Region: {0}, {1}", RegionID, RegionDeepScanTMStamp.ToString("MM/dd/yyyy hh:mm:ss")); @@ -959,7 +1139,7 @@ namespace OpenSim.Region.CoreModules.Asset con.Output("Memory cache not enabled."); } } - + if (clearFile) { if (m_FileCacheEnabled) @@ -976,13 +1156,44 @@ namespace OpenSim.Region.CoreModules.Asset break; case "assets": - con.Output("Ensuring assets are cached for all scenes."); + lock(timerLock) + { + if(m_cleanupRunning) + { + con.OutputFormat("FloatSam assets check already running"); + return; + } + m_cleanupRunning = true; + } - WorkManager.RunInThread(delegate + con.Output("FloatSam Ensuring assets are cached for all scenes."); + + WorkManager.RunInThreadPool(delegate { + bool wasRunning= false; + lock(timerLock) + { + if(m_timerRunning) + { + m_CacheCleanTimer.Stop(); + m_timerRunning = false; + wasRunning = true; + Thread.Sleep(100); + } + } int assetReferenceTotal = TouchAllSceneAssets(true); + GC.Collect(); + lock(timerLock) + { + if(wasRunning) + { + m_CacheCleanTimer.Start(); + m_timerRunning = true; + } + m_cleanupRunning = false; + } con.OutputFormat("Completed check with {0} assets.", assetReferenceTotal); - }, null, "TouchAllSceneAssets"); + }, null, "TouchAllSceneAssets", false); break; @@ -1037,19 +1248,23 @@ namespace OpenSim.Region.CoreModules.Asset public AssetMetadata GetMetadata(string id) { - AssetBase asset = Get(id); + AssetBase asset; + Get(id, out asset); return asset.Metadata; } public byte[] GetData(string id) { - AssetBase asset = Get(id); + AssetBase asset; + Get(id, out asset); return asset.Data; } public bool Get(string id, object sender, AssetRetrieved handler) { - AssetBase asset = Get(id); + AssetBase asset; + if (!Get(id, out asset)) + return false; handler(id, sender, asset); return true; } @@ -1057,12 +1272,12 @@ namespace OpenSim.Region.CoreModules.Asset public bool[] AssetsExist(string[] ids) { bool[] exist = new bool[ids.Length]; - + for (int i = 0; i < ids.Length; i++) { exist[i] = Check(ids[i]); } - + return exist; } @@ -1080,7 +1295,9 @@ namespace OpenSim.Region.CoreModules.Asset public bool UpdateContent(string id, byte[] data) { - AssetBase asset = Get(id); + AssetBase asset; + if (!Get(id, out asset)) + return false; asset.Data = data; Cache(asset); return true; diff --git a/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs b/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs index 5f76ac2..abe9b23 100644 --- a/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs @@ -41,7 +41,7 @@ using OpenSim.Services.Interfaces; namespace OpenSim.Region.CoreModules.Asset { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GlynnTuckerAssetCache")] - public class GlynnTuckerAssetCache : ISharedRegionModule, IImprovedAssetCache + public class GlynnTuckerAssetCache : ISharedRegionModule, IAssetCache { private static readonly ILog m_log = LogManager.GetLogger( @@ -55,7 +55,7 @@ namespace OpenSim.Region.CoreModules.Asset // Instrumentation private uint m_DebugRate; - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -100,7 +100,7 @@ namespace OpenSim.Region.CoreModules.Asset public void AddRegion(Scene scene) { if (m_Enabled) - scene.RegisterModuleInterface(this); + scene.RegisterModuleInterface(this); } public void RemoveRegion(Scene scene) @@ -112,7 +112,7 @@ namespace OpenSim.Region.CoreModules.Asset } //////////////////////////////////////////////////////////// - // IImprovedAssetCache + // IAssetCache // public bool Check(string id) @@ -126,14 +126,20 @@ namespace OpenSim.Region.CoreModules.Asset m_Cache.AddOrUpdate(asset.ID, asset); } - public AssetBase Get(string id) + public void CacheNegative(string id) { - Object asset = null; - m_Cache.TryGet(id, out asset); + // We don't do negative caching + } + + public bool Get(string id, out AssetBase asset) + { + Object a = null; + m_Cache.TryGet(id, out a); - Debug(asset); + Debug(a); - return (AssetBase)asset; + asset = (AssetBase)a; + return true; } public void Expire(string id) diff --git a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs index 73e4431..dbb7941 100644 --- a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs +++ b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs @@ -112,7 +112,7 @@ namespace OpenSim.Region.CoreModules.Asset.Tests { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - + AssetBase asset = AssetHelpers.CreateNotecardAsset(); asset.ID = TestHelpers.ParseTail(0x2).ToString(); diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 2f67c4e..9f52a14 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -41,6 +41,8 @@ using OpenSim.Region.Framework; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes.Serialization; +using OpenSim.Services.Interfaces; +using PermissionMask = OpenSim.Framework.PermissionMask; namespace OpenSim.Region.CoreModules.Avatar.Attachments { @@ -60,7 +62,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments /// A value of 0 will apply no pause. The pause is specified in milliseconds. /// public int ThrottlePer100PrimsRezzed { get; set; } - + private Scene m_scene; private IInventoryAccessModule m_invAccessModule; @@ -68,7 +70,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments /// Are attachments enabled? /// public bool Enabled { get; private set; } - + public string Name { get { return "Attachments Module"; } } public Type ReplaceableInterface { get { return null; } } @@ -86,14 +88,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments Enabled = true; } } - + public void AddRegion(Scene scene) { m_scene = scene; if (Enabled) { // Only register module with scene if it is enabled. All callers check for a null attachments module. - // Ideally, there should be a null attachments module for when this core attachments module has been + // Ideally, there should be a null attachments module for when this core attachments module has been // disabled. Registering only when enabled allows for other attachments module implementations. m_scene.RegisterModuleInterface(this); m_scene.EventManager.OnNewClient += SubscribeToClientEvents; @@ -180,7 +182,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments private void HandleScriptStateChange(uint localID, bool started) { SceneObjectGroup sog = m_scene.GetGroupByPrim(localID); - if (sog != null && sog.IsAttachment) + if (sog != null && sog.IsAttachment) { if (!started) { @@ -197,21 +199,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments } } } - - public void RemoveRegion(Scene scene) + + public void RemoveRegion(Scene scene) { m_scene.UnregisterModuleInterface(this); if (Enabled) m_scene.EventManager.OnNewClient -= SubscribeToClientEvents; } - + public void RegionLoaded(Scene scene) { m_invAccessModule = m_scene.RequestModuleInterface(); } - - public void Close() + + public void Close() { RemoveRegion(m_scene); } @@ -269,7 +271,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments ((SceneObjectGroup)so).RootPart.ClearUpdateSchedule(); // m_log.DebugFormat( -// "[ATTACHMENTS MODULE]: Copying script state with {0} bytes for object {1} for {2} in {3}", +// "[ATTACHMENTS MODULE]: Copying script state with {0} bytes for object {1} for {2} in {3}", // ad.AttachmentObjectStates[i].Length, so.Name, sp.Name, m_scene.Name); so.SetState(ad.AttachmentObjectStates[i++], m_scene); @@ -294,7 +296,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments { if (DebugLevel > 0) m_log.DebugFormat( - "[ATTACHMENTS MODULE]: Not doing simulator-side attachment rez for {0} in {1} as their viewer has already rezzed attachments", + "[ATTACHMENTS MODULE]: Not doing simulator-side attachment rez for {0} in {1} as their viewer has already rezzed attachments", m_scene.Name, sp.Name); return; @@ -303,6 +305,41 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (DebugLevel > 0) m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing any attachments for {0} from simulator-side", sp.Name); + XmlDocument doc = new XmlDocument(); + doc.XmlResolver=null; + string stateData = String.Empty; + + IAttachmentsService attServ = m_scene.RequestModuleInterface(); + if (attServ != null) + { + m_log.DebugFormat("[ATTACHMENT]: Loading attachment data from attachment service"); + stateData = attServ.Get(sp.UUID.ToString()); + if (stateData != String.Empty) + { + try + { + doc.LoadXml(stateData); + } + catch { } + } + } + + Dictionary itemData = new Dictionary(); + + XmlNodeList nodes = doc.GetElementsByTagName("Attachment"); + if (nodes.Count > 0) + { + foreach (XmlNode n in nodes) + { + XmlElement elem = (XmlElement)n; + string itemID = elem.GetAttribute("ItemID"); + string xml = elem.InnerXml; + + itemData[new UUID(itemID)] = xml; + } + } + + List attachments = sp.Appearance.GetAttachments(); // Let's get all items at once, so they get cached @@ -322,7 +359,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // For some reason assetIDs are being written as Zero's in the DB -- need to track tat down // But they're not used anyway, the item is being looked up for now, so let's proceed. - //if (UUID.Zero == assetID) + //if (UUID.Zero == assetID) //{ // m_log.DebugFormat("[ATTACHMENT]: Cannot rez attachment in point {0} with itemID {1}", p, itemID); // continue; @@ -330,10 +367,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments try { + string xmlData; + XmlDocument d = null; + UUID asset; + if (itemData.TryGetValue(attach.ItemID, out xmlData)) + { + d = new XmlDocument(); + d.XmlResolver=null; + d.LoadXml(xmlData); + m_log.InfoFormat("[ATTACHMENT]: Found saved state for item {0}, loading it", attach.ItemID); + } + // If we're an NPC then skip all the item checks and manipulations since we don't have an // inventory right now. RezSingleAttachmentFromInventoryInternal( - sp, sp.PresenceType == PresenceType.Npc ? UUID.Zero : attach.ItemID, attach.AssetID, attachmentPt, true); + sp, sp.PresenceType == PresenceType.Npc ? UUID.Zero : attach.ItemID, attach.AssetID, attachmentPt, true, d); } catch (Exception e) { @@ -361,26 +409,34 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments Dictionary scriptStates = new Dictionary(); - foreach (SceneObjectGroup so in attachments) + + if (sp.PresenceType != PresenceType.Npc) { - // Scripts MUST be snapshotted before the object is - // removed from the scene because doing otherwise will - // clobber the run flag - // This must be done outside the sp.AttachmentSyncLock so that there is no risk of a deadlock from - // scripts performing attachment operations at the same time. Getting object states stops the scripts. - scriptStates[so] = PrepareScriptInstanceForSave(so, false); + foreach (SceneObjectGroup so in attachments) + { + // Scripts MUST be snapshotted before the object is + // removed from the scene because doing otherwise will + // clobber the run flag + // This must be done outside the sp.AttachmentSyncLock so that there is no risk of a deadlock from + // scripts performing attachment operations at the same time. Getting object states stops the scripts. + scriptStates[so] = PrepareScriptInstanceForSave(so, false); + } -// m_log.DebugFormat( -// "[ATTACHMENTS MODULE]: For object {0} for {1} in {2} got saved state {3}", -// so.Name, sp.Name, m_scene.Name, scriptStates[so]); + lock (sp.AttachmentsSyncLock) + { + foreach (SceneObjectGroup so in attachments) + UpdateDetachedObject(sp, so, scriptStates[so]); + sp.ClearAttachments(); + } } - - lock (sp.AttachmentsSyncLock) + else { - foreach (SceneObjectGroup so in attachments) - UpdateDetachedObject(sp, so, scriptStates[so]); - - sp.ClearAttachments(); + lock (sp.AttachmentsSyncLock) + { + foreach (SceneObjectGroup so in attachments) + UpdateDetachedObject(sp, so, String.Empty); + sp.ClearAttachments(); + } } } @@ -392,7 +448,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (DebugLevel > 0) m_log.DebugFormat( "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}", - m_scene.RegionInfo.RegionName, sp.Name, silent); + m_scene.RegionInfo.RegionName, sp.Name, silent); foreach (SceneObjectGroup sop in sp.GetAttachments()) { @@ -401,21 +457,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments sp.ClearAttachments(); } - - public bool AttachObject( - IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool addToInventory, bool append) + + public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, + bool addToInventory, bool append) { if (!Enabled) return false; - group.DetachFromBackup(); - - bool success = AttachObjectInternal(sp, group, attachmentPt, silent, addToInventory, false, append); - - if (!success) - group.AttachToBackup(); - - return success; + return AttachObjectInternal(sp, group, attachmentPt, silent, addToInventory, false, append); } /// @@ -428,10 +477,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments /// /// If true then add object to user inventory. /// If true then scripts are resumed on the attached object. - /// Append to attachment point rather than replace. - private bool AttachObjectInternal( - IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool addToInventory, bool resumeScripts, bool append) + private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, + bool silent, bool addToInventory, bool resumeScripts, bool append) { +// m_log.DebugFormat( +// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})", +// group.Name, group.LocalId, sp.Name, attachmentPt, silent); + + if (group.GetSittingAvatarsCount() != 0) { if (DebugLevel > 0) @@ -442,7 +495,23 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return false; } + List attachments = sp.GetAttachments(attachmentPt); + if (attachments.Contains(group)) + { +// if (DebugLevel > 0) +// m_log.WarnFormat( +// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached", +// group.Name, group.LocalId, sp.Name, attachmentPt); + + return false; + } + Vector3 attachPos = group.AbsolutePosition; + + // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should + // be removed when that functionality is implemented in opensim + attachmentPt &= 0x7f; + // If the attachment point isn't the same as the one previously used // set it's offset position = 0 so that it appears on the attachment point // and not in a weird location somewhere unknown. @@ -470,7 +539,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments { attachmentPt = (uint)group.RootPart.Shape.LastAttachPoint; attachPos = group.RootPart.AttachedPos; - group.HasGroupChanged = true; } // if we still didn't find a suitable attachment point....... @@ -481,21 +549,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments attachPos = Vector3.Zero; } - group.AttachmentPoint = attachmentPt; - group.AbsolutePosition = attachPos; - - List attachments = sp.GetAttachments(attachmentPt); - - if (attachments.Contains(group)) - { - if (DebugLevel > 0) - m_log.WarnFormat( - "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached", - group.Name, group.LocalId, sp.Name, attachmentPt); - - return false; - } - // If we already have 5, remove the oldest until only 4 are left. Skip over temp ones while (attachments.Count >= 5) { @@ -514,11 +567,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments } } + group.DetachFromBackup(); + lock (sp.AttachmentsSyncLock) { + group.AttachmentPoint = attachmentPt; + group.RootPart.AttachedPos = attachPos; + if (addToInventory && sp.PresenceType != PresenceType.Npc) UpdateUserInventoryWithAttachment(sp, group, attachmentPt, append); - + AttachToAgent(sp, group, attachmentPt, attachPos, silent); if (resumeScripts) @@ -529,8 +587,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments group.ResumeScripts(); } + else // Do this last so that event listeners have access to all the effects of the attachment - m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID); + // this can't be done when creating scripts: + // scripts do internal enqueue of attach event + // and not all scripts are loaded at this point + m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID); } return true; @@ -546,7 +608,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group, append); } - public SceneObjectGroup RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt) + public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt) + { + return RezSingleAttachmentFromInventory(sp, itemID, AttachmentPt, null); + } + + public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt, XmlDocument doc) { if (!Enabled) return null; @@ -557,8 +624,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments (AttachmentPoint)AttachmentPt, itemID, sp.Name, m_scene.Name); // We check the attachments in the avatar appearance here rather than the objects attached to the - // ScenePresence itself so that we can ignore calls by viewer 2/3 to attach objects on startup. We are - // already doing this in ScenePresence.MakeRootAgent(). Simulator-side attaching needs to be done + // ScenePresence itself so that we can ignore calls by viewer 2/3 to attach objects on startup. We are + // already doing this in ScenePresence.MakeRootAgent(). Simulator-side attaching needs to be done // because pre-outfit folder viewers (most version 1 viewers) require it. bool alreadyOn = false; List existingAttachments = sp.Appearance.GetAttachments(); @@ -584,7 +651,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments bool append = (AttachmentPt & 0x80) != 0; AttachmentPt &= 0x7f; - return RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt, append); + return RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt, append, doc); } public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List> rezlist) @@ -594,7 +661,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (DebugLevel > 0) m_log.DebugFormat( - "[ATTACHMENTS MODULE]: Rezzing {0} attachments from inventory for {1} in {2}", + "[ATTACHMENTS MODULE]: Rezzing {0} attachments from inventory for {1} in {2}", rezlist.Count, sp.Name, m_scene.Name); foreach (KeyValuePair rez in rezlist) @@ -605,7 +672,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments public void DetachSingleAttachmentToGround(IScenePresence sp, uint soLocalId) { - DetachSingleAttachmentToGround(sp, soLocalId, sp.AbsolutePosition, Quaternion.Identity); + Vector3 pos = new Vector3(2.5f, 0f, 0f); + pos *= ((ScenePresence)sp).Rotation; + pos += sp.AbsolutePosition; + DetachSingleAttachmentToGround(sp, soLocalId, pos, Quaternion.Identity); } public void DetachSingleAttachmentToGround(IScenePresence sp, uint soLocalId, Vector3 absolutePos, Quaternion absoluteRot) @@ -649,26 +719,31 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (changed && m_scene.AvatarFactory != null) m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); + so.RootPart.Shape.LastAttachPoint = (byte)so.AttachmentPoint; + sp.RemoveAttachment(so); so.FromItemID = UUID.Zero; + so.AttachedAvatar = UUID.Zero; + so.ClearPartAttachmentData(); + SceneObjectPart rootPart = so.RootPart; + + rootPart.SetParentLocalId(0); so.AbsolutePosition = absolutePos; if (absoluteRot != Quaternion.Identity) { so.UpdateGroupRotationR(absoluteRot); } - so.AttachedAvatar = UUID.Zero; - rootPart.SetParentLocalId(0); - so.ClearPartAttachmentData(); - rootPart.ApplyPhysics(rootPart.GetEffectiveObjectFlags(), rootPart.VolumeDetectActive); - so.HasGroupChanged = true; - so.RootPart.Shape.LastAttachPoint = (byte)so.AttachmentPoint; - rootPart.Rezzed = DateTime.Now; + rootPart.RemFlag(PrimFlags.TemporaryOnRez); + + so.ApplyPhysics(); + + rootPart.Rezzed = DateTime.Now; so.AttachToBackup(); m_scene.EventManager.TriggerParcelPrimCountTainted(); - rootPart.ScheduleFullUpdate(); + rootPart.ClearUndoState(); List uuids = new List(); @@ -678,6 +753,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments } m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero); + + // Attach (NULL) stops scripts. We don't want that. Resume them. + so.ResumeScripts(); + so.HasGroupChanged = true; + so.RootPart.ScheduleFullUpdate(); + so.ScheduleGroupForTerseUpdate(); } public void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup so) @@ -691,9 +772,32 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return; } + // If this didn't come from inventory, it also shouldn't go there + // on detach. It's likely a temp attachment. + if (so.FromItemID == UUID.Zero) + { + // Retirn value is ignored + PrepareScriptInstanceForSave(so, true); + + lock (sp.AttachmentsSyncLock) + { + bool changed = sp.Appearance.DetachAttachment(so.FromItemID); + if (changed && m_scene.AvatarFactory != null) + m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); + + sp.RemoveAttachment(so); + } + + m_scene.DeleteSceneObject(so, false, false); + so.RemoveScriptInstances(true); + so.Clear(); + + return; + } + if (DebugLevel > 0) m_log.DebugFormat( - "[ATTACHMENTS MODULE]: Detaching object {0} {1} (FromItemID {2}) for {3} in {4}", + "[ATTACHMENTS MODULE]: Detaching object {0} {1} (FromItemID {2}) for {3} in {4}", so.Name, so.LocalId, so.FromItemID, sp.Name, m_scene.Name); // Scripts MUST be snapshotted before the object is @@ -716,14 +820,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments UpdateDetachedObject(sp, so, scriptedState); } } - + public void UpdateAttachmentPosition(SceneObjectGroup sog, Vector3 pos) { if (!Enabled) return; sog.UpdateGroupPosition(pos); - sog.HasGroupChanged = true; + sog.HasGroupChanged = true; } #endregion @@ -732,7 +836,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // This is public but is not part of the IAttachmentsModule interface. // RegionCombiner module needs to poke at it to deliver client events. - // This breaks the encapsulation of the module and should get fixed somehow. + // This breaks the encapsulation of the module and should get fixed somehow. public void SubscribeToClientEvents(IClientAPI client) { client.OnRezSingleAttachmentFromInv += Client_OnRezSingleAttachmentFromInv; @@ -745,7 +849,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // This is public but is not part of the IAttachmentsModule interface. // RegionCombiner module needs to poke at it to deliver client events. - // This breaks the encapsulation of the module and should get fixed somehow. + // This breaks the encapsulation of the module and should get fixed somehow. public void UnsubscribeFromClientEvents(IClientAPI client) { client.OnRezSingleAttachmentFromInv -= Client_OnRezSingleAttachmentFromInv; @@ -791,11 +895,34 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp, scriptedState); - InventoryItemBase item = new InventoryItemBase(grp.FromItemID, sp.UUID); - item = m_scene.InventoryService.GetItem(item); + InventoryItemBase item = m_scene.InventoryService.GetItem(sp.UUID, grp.FromItemID); if (item != null) { + // attach is rez, need to update permissions + item.Flags &= ~(uint)(InventoryItemFlags.ObjectSlamPerm | InventoryItemFlags.ObjectOverwriteBase | + InventoryItemFlags.ObjectOverwriteOwner | InventoryItemFlags.ObjectOverwriteGroup | + InventoryItemFlags.ObjectOverwriteEveryone | InventoryItemFlags.ObjectOverwriteNextOwner); + + uint permsBase = (uint)(PermissionMask.Copy | PermissionMask.Transfer | + PermissionMask.Modify | PermissionMask.Move | + PermissionMask.Export | PermissionMask.FoldedMask); + + permsBase &= grp.CurrentAndFoldedNextPermissions(); + permsBase |= (uint)PermissionMask.Move; + item.BasePermissions = permsBase; + item.CurrentPermissions = permsBase; + item.NextPermissions = permsBase & grp.RootPart.NextOwnerMask | (uint)PermissionMask.Move; + item.EveryOnePermissions = permsBase & grp.RootPart.EveryoneMask; + item.GroupPermissions = permsBase & grp.RootPart.GroupMask; + item.CurrentPermissions &= + ((uint)PermissionMask.Copy | + (uint)PermissionMask.Transfer | + (uint)PermissionMask.Modify | + (uint)PermissionMask.Move | + (uint)PermissionMask.Export | + (uint)PermissionMask.FoldedMask); // Preserve folded permissions ?? + AssetBase asset = m_scene.CreateAsset( grp.GetPartName(grp.LocalId), grp.GetPartDescription(grp.LocalId), @@ -826,7 +953,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments /// Attach this scene object to the given avatar. /// /// - /// This isn't publicly available since attachments should always perform the corresponding inventory + /// This isn't publicly available since attachments should always perform the corresponding inventory /// operation (to show the attach in user inventory and update the asset with positional information). /// /// @@ -846,16 +973,24 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments m_scene.DeleteFromStorage(so.UUID); m_scene.EventManager.TriggerParcelPrimCountTainted(); - so.AttachedAvatar = sp.UUID; - if (so.RootPart.PhysActor != null) - so.RootPart.RemoveFromPhysics(); + foreach (SceneObjectPart part in so.Parts) + { +// if (part.KeyframeMotion != null) +// part.KeyframeMotion.Suspend(); + + if (part.PhysActor != null) + { + part.RemoveFromPhysics(); + } + } - so.AbsolutePosition = attachOffset; - so.RootPart.AttachedPos = attachOffset; - so.IsAttachment = true; so.RootPart.SetParentLocalId(sp.LocalId); + so.AttachedAvatar = sp.UUID; so.AttachmentPoint = attachmentpoint; + so.RootPart.AttachedPos = attachOffset; + so.AbsolutePosition = attachOffset; + so.IsAttachment = true; sp.AddAttachment(so); @@ -879,7 +1014,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // Fudge below is an extremely unhelpful comment. It's probably here so that the scheduled full update // will succeed, as that will not update if an attachment is selected. - so.IsSelected = false; // fudge.... + so.IsSelected = false; // fudge.... so.ScheduleGroupForFullUpdate(); } @@ -923,7 +1058,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments /// /// /// This involves triggering the detach event and getting the script state (which also stops the script) - /// This MUST be done outside sp.AttachmentsSyncLock, since otherwise there is a chance of deadlock if a + /// This MUST be done outside sp.AttachmentsSyncLock, since otherwise there is a chance of deadlock if a /// running script is performing attachment operations. /// /// @@ -939,7 +1074,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (fireDetachEvent) { m_scene.EventManager.TriggerOnAttach(grp.LocalId, grp.FromItemID, UUID.Zero); - // Allow detach event time to do some work before stopping the script Thread.Sleep(2); } @@ -971,6 +1105,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // Remove the object from the scene so no more updates // are sent. Doing this before the below changes will ensure // updates can't cause "HUD artefacts" + m_scene.DeleteSceneObject(so, false, false); // Prepare sog for storage @@ -989,23 +1124,37 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // Now, remove the scripts so.RemoveScriptInstances(true); + so.Clear(); } protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( - IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, bool append) + IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, bool append, XmlDocument doc) { if (m_invAccessModule == null) return null; SceneObjectGroup objatt; + UUID rezGroupID; + + // This will fail if the user aborts login. sp will exist + // but ControllintClient will be null. + try + { + rezGroupID = sp.ControllingClient.ActiveGroupId; + } + catch + { + return null; + } + if (itemID != UUID.Zero) objatt = m_invAccessModule.RezObject(sp.ControllingClient, - itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, + itemID, rezGroupID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, false, false, sp.UUID, true); else objatt = m_invAccessModule.RezObject(sp.ControllingClient, - null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, + null, rezGroupID, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, false, false, sp.UUID, true); if (objatt == null) @@ -1018,7 +1167,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments } else if (itemID == UUID.Zero) { - // We need to have a FromItemID for multiple attachments on a single attach point to appear. This is + // We need to have a FromItemID for multiple attachments on a single attach point to appear. This is // true on Singularity 1.8.5 and quite possibly other viewers as well. As NPCs don't have an inventory // we will satisfy this requirement by inserting a random UUID. objatt.FromItemID = UUID.Random(); @@ -1043,6 +1192,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // This will throw if the attachment fails try { + if (doc != null) + { + objatt.LoadScriptState(doc); + objatt.ResetOwnerChangeFlag(); + } + AttachObjectInternal(sp, objatt, attachmentPt, false, true, true, append); } catch (Exception e) @@ -1058,7 +1213,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments } if (tainted) - objatt.HasGroupChanged = true; + objatt.HasGroupChanged = true; if (ThrottlePer100PrimsRezzed > 0) { @@ -1100,8 +1255,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return; } - InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID); - item = m_scene.InventoryService.GetItem(item); + InventoryItemBase item = m_scene.InventoryService.GetItem(sp.UUID, itemID); if (item == null) return; @@ -1185,7 +1339,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (part == null) return; - if (!m_scene.Permissions.CanTakeObject(part.UUID, remoteClient.AgentId)) + SceneObjectGroup group = part.ParentGroup; + + if (!m_scene.Permissions.CanTakeObject(group, sp)) { remoteClient.SendAgentAlertMessage( "You don't have sufficient permissions to attach this object", false); @@ -1197,7 +1353,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments AttachmentPt &= 0x7f; // Calls attach with a Zero position - if (AttachObject(sp, part.ParentGroup, AttachmentPt, false, true, append)) + if (AttachObject(sp, group , AttachmentPt, false, true, append)) { if (DebugLevel > 0) m_log.Debug( @@ -1205,7 +1361,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments + ", AttachmentPoint: " + AttachmentPt); // Save avatar attachment information - m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.FromItemID, remoteClient.AgentId); + m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); } } catch (Exception e) @@ -1222,7 +1378,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID); - if (sp != null && group != null && group.FromItemID != UUID.Zero) + if (sp != null && group != null) DetachSingleAttachmentToInv(sp, group); } @@ -1256,7 +1412,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (sp != null) DetachSingleAttachmentToGround(sp, soLocalId); } - #endregion } } diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 0ac3add..941853c 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -55,6 +55,7 @@ using OpenSim.Tests.Common; namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests { +/* /// /// Attachment tests /// @@ -200,7 +201,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Assert.That(so.Backup, Is.True); m_numberOfAttachEventsFired = 0; - scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, true, false); + scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, true, false); // Check status on scene presence Assert.That(sp.HasAttachments(), Is.True); @@ -215,11 +216,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Assert.That(attSo.Backup, Is.False); // Check item status - Assert.That( - sp.Appearance.GetAttachpoint(attSo.FromItemID), - Is.EqualTo((int)AttachmentPoint.Chest)); +// Assert.That( +// sp.Appearance.GetAttachpoint(attSo.FromItemID), +// Is.EqualTo((int)AttachmentPoint.Chest)); - InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID)); + InventoryItemBase attachmentItem = scene.InventoryService.GetItem(sp.UUID, attSo.FromItemID); Assert.That(attachmentItem, Is.Not.Null); Assert.That(attachmentItem.Name, Is.EqualTo(attName)); @@ -262,11 +263,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Assert.That(attSo.IsTemporary, Is.False); // Check item status - Assert.That( - sp.Appearance.GetAttachpoint(attSo.FromItemID), - Is.EqualTo((int)AttachmentPoint.LeftHand)); +// Assert.That( +// sp.Appearance.GetAttachpoint(attSo.FromItemID), +// Is.EqualTo((int)AttachmentPoint.LeftHand)); - InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID)); + InventoryItemBase attachmentItem = scene.InventoryService.GetItem(sp.UUID, attSo.FromItemID); Assert.That(attachmentItem, Is.Not.Null); Assert.That(attachmentItem.Name, Is.EqualTo(so.Name)); @@ -281,7 +282,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests // Test wearing a different attachment from the ground. { - scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, true, false); + scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, true, false); // Check status on scene presence Assert.That(sp.HasAttachments(), Is.True); @@ -295,11 +296,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Assert.That(attSo.IsTemporary, Is.False); // Check item status - Assert.That( - sp.Appearance.GetAttachpoint(attSo.FromItemID), - Is.EqualTo((int)AttachmentPoint.LeftHand)); +// Assert.That( +// sp.Appearance.GetAttachpoint(attSo.FromItemID), +// Is.EqualTo((int)AttachmentPoint.LeftHand)); - InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID)); + InventoryItemBase attachmentItem = scene.InventoryService.GetItem(sp.UUID, attSo.FromItemID); Assert.That(attachmentItem, Is.Not.Null); Assert.That(attachmentItem.Name, Is.EqualTo(so2.Name)); @@ -314,7 +315,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests // Test rewearing an already worn attachment from ground. Nothing should happen. { - scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, true, false); + scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, true, false); // Check status on scene presence Assert.That(sp.HasAttachments(), Is.True); @@ -328,11 +329,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Assert.That(attSo.IsTemporary, Is.False); // Check item status - Assert.That( - sp.Appearance.GetAttachpoint(attSo.FromItemID), - Is.EqualTo((int)AttachmentPoint.LeftHand)); +// Assert.That( +// sp.Appearance.GetAttachpoint(attSo.FromItemID), +// Is.EqualTo((int)AttachmentPoint.LeftHand)); - InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID)); + InventoryItemBase attachmentItem = scene.InventoryService.GetItem(sp.UUID, attSo.FromItemID); Assert.That(attachmentItem, Is.Not.Null); Assert.That(attachmentItem.Name, Is.EqualTo(so2.Name)); @@ -372,7 +373,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests sp2.AbsolutePosition = new Vector3(0, 0, 0); sp2.HandleAgentRequestSit(sp2.ControllingClient, sp2.UUID, so.UUID, Vector3.Zero); - scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, true, false); + scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, true, false); Assert.That(sp.HasAttachments(), Is.False); Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); @@ -410,8 +411,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Assert.IsFalse(attSo.Backup); // Check appearance status - Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); - Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); +// Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); +// Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); // Check events @@ -435,8 +436,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Assert.That(attSo.IsTemporary, Is.False); // Check appearance status - Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); - Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); +// Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); +// Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); // Check events @@ -474,8 +475,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Assert.That(attSo.IsAttachment); // Check appearance status - Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); - Assert.That(sp.Appearance.GetAttachpoint(attItem1.ID), Is.EqualTo((int)AttachmentPoint.LeftHand)); +// Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); +// Assert.That(sp.Appearance.GetAttachpoint(attItem1.ID), Is.EqualTo((int)AttachmentPoint.LeftHand)); Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); // Check events @@ -484,7 +485,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests // Test wearing a second attachment at the same position // Until multiple attachments at one point is implemented, this will remove the first attachment - // This test relies on both attachments having the same default attachment point (in this case LeftHand + // This test relies on both attachments having the same default attachment point (in this case LeftHand // since none other has been set). { scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem2.ID, (uint)AttachmentPoint.Default); @@ -499,8 +500,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Assert.That(attSo.IsAttachment); // Check appearance status - Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); - Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand)); +// Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); +// Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand)); Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); // Check events @@ -521,8 +522,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Assert.That(attSo.IsAttachment); // Check appearance status - Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); - Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand)); +// Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); +// Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand)); Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); // Check events @@ -556,6 +557,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests // In the future, we need to be able to do this programatically more predicably. scene.EventManager.OnChatFromWorld += OnChatFromWorld; + m_chatEvent.Reset(); scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest); m_chatEvent.WaitOne(60000); @@ -596,10 +598,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Assert.That(attachments.Count, Is.EqualTo(0)); // Check appearance status - Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(0)); +// Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(0)); // Check item status - Assert.That(scene.InventoryService.GetItem(new InventoryItemBase(attItem.ID)), Is.Null); + Assert.That(scene.InventoryService.GetItem(sp.UUID, attItem.ID), Is.Null); // Check object in scene SceneObjectGroup soInScene = scene.GetSceneObjectGroup("att"); @@ -634,7 +636,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Assert.That(attachments.Count, Is.EqualTo(0)); // Check item status - Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo(0)); +// Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo(0)); Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(0)); @@ -669,15 +671,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests // In the future, we need to be able to do this programatically more predicably. scene.EventManager.OnChatFromWorld += OnChatFromWorld; + m_chatEvent.Reset(); SceneObjectGroup rezzedSo - = scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest); + = (SceneObjectGroup)(scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest)); // Wait for chat to signal rezzed script has been started. m_chatEvent.WaitOne(60000); scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, rezzedSo); - InventoryItemBase userItemUpdated = scene.InventoryService.GetItem(userItem); + InventoryItemBase userItemUpdated = scene.InventoryService.GetItem(userItem.Owner, userItem.ID); AssetBase asset = scene.AssetService.Get(userItemUpdated.AssetID.ToString()); // TODO: It would probably be better here to check script state via the saving and retrieval of state @@ -689,7 +692,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Assert.That(scriptStateNodes.Count, Is.EqualTo(1)); // Re-rez the attachment to check script running state - SceneObjectGroup reRezzedSo = scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest); + SceneObjectGroup reRezzedSo = (SceneObjectGroup)(scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest)); // Wait for chat to signal rezzed script has been started. m_chatEvent.WaitOne(60000); @@ -719,13 +722,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID); ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd); - SceneObjectGroup rezzedAtt = presence.GetAttachments()[0]; + UUID rezzedAttID = presence.GetAttachments()[0].UUID; m_numberOfAttachEventsFired = 0; scene.CloseAgent(presence.UUID, false); // Check that we can't retrieve this attachment from the scene. - Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null); + Assert.That(scene.GetSceneObjectGroup(rezzedAttID), Is.Null); // Check events Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0)); @@ -802,7 +805,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0)); } -/* + [Test] public void TestSameSimulatorNeighbouringRegionsTeleportV1() { @@ -842,7 +845,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule()); // FIXME: Hack - this is here temporarily to revert back to older entity transfer behaviour - lscm.ServiceVersion = 0.1f; + //lscm.ServiceVersion = 0.1f; UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1); @@ -910,7 +913,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests // Check events Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0)); } -*/ + [Test] public void TestSameSimulatorNeighbouringRegionsTeleportV2() @@ -972,8 +975,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests // Both these operations will occur on different threads and will wait for each other. // We have to do this via ThreadPool directly since FireAndForget has been switched to sync for the V1 // test protocol, where we are trying to avoid unpredictable async operations in regression tests. - tc.OnTestClientSendRegionTeleport - += (regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL) + tc.OnTestClientSendRegionTeleport + += (regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL) => ThreadPool.UnsafeQueueUserWorkItem(o => destinationTestClients[0].CompleteMovement(), null); m_numberOfAttachEventsFired = 0; @@ -1023,4 +1026,5 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0)); } } +*/ } diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index cfb082b..4abac43 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs @@ -75,7 +75,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory m_savetime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSave",Convert.ToString(m_savetime))); m_sendtime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSend",Convert.ToString(m_sendtime))); m_reusetextures = appearanceConfig.GetBoolean("ReuseTextures",m_reusetextures); - + // m_log.InfoFormat("[AVFACTORY] configured for {0} save and {1} send",m_savetime,m_sendtime); } @@ -166,7 +166,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory } /// - /// Set appearance data (texture asset IDs and slider settings) + /// Set appearance data (texture asset IDs and slider settings) /// /// /// @@ -188,29 +188,9 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // Process the visual params, this may change height as well if (visualParams != null) { - // string[] visualParamsStrings = new string[visualParams.Length]; - // for (int i = 0; i < visualParams.Length; i++) - // visualParamsStrings[i] = visualParams[i].ToString(); - // m_log.DebugFormat( - // "[AVFACTORY]: Setting visual params for {0} to {1}", - // client.Name, string.Join(", ", visualParamsStrings)); -/* - float oldHeight = sp.Appearance.AvatarHeight; - changed = sp.Appearance.SetVisualParams(visualParams); - - if (sp.Appearance.AvatarHeight != oldHeight && sp.Appearance.AvatarHeight > 0) - ((ScenePresence)sp).SetHeight(sp.Appearance.AvatarHeight); - */ -// float oldoff = sp.Appearance.AvatarFeetOffset; -// Vector3 oldbox = sp.Appearance.AvatarBoxSize; changed = sp.Appearance.SetVisualParams(visualParams); -// float off = sp.Appearance.AvatarFeetOffset; -// Vector3 box = sp.Appearance.AvatarBoxSize; -// if(oldoff != off || oldbox != box) -// ((ScenePresence)sp).SetSize(box,off); - } - + // Process the baked texture array if (textureEntry != null) { @@ -222,9 +202,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // WriteBakedTexturesReport(sp, m_log.DebugFormat); - // If bake textures are missing and this is not an NPC, request a rebake from client - if (!ValidateBakedTextureCache(sp) && (((ScenePresence)sp).PresenceType != PresenceType.Npc)) - RequestRebake(sp, true); + UpdateBakedTextureCache(sp, cacheItems); // This appears to be set only in the final stage of the appearance // update transaction. In theory, we should be able to do an immediate @@ -251,7 +229,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory private void SendAppearance(ScenePresence sp) { // Send the appearance to everyone in the scene - sp.SendAppearanceToAllOtherClients(); + sp.SendAppearanceToAllOtherAgents(); // Send animations back to the avatar as well sp.Animator.SendAnimPack(); @@ -289,7 +267,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory WearableCacheItem[] items = sp.Appearance.WearableCacheItems; //foreach (WearableCacheItem item in items) //{ - + //} return items; } @@ -310,23 +288,25 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory if (bakedTextures.Count == 0) return false; + IAssetCache cache = sp.Scene.RequestModuleInterface(); + if(cache == null) + return true; // no baked local caching so nothing to do + foreach (BakeType bakeType in bakedTextures.Keys) { Primitive.TextureEntryFace bakedTextureFace = bakedTextures[bakeType]; if (bakedTextureFace == null) - { - // This can happen legitimately, since some baked textures might not exist - //m_log.WarnFormat( - // "[AV FACTORY]: No texture ID set for {0} for {1} in {2} not found when trying to save permanently", - // bakeType, sp.Name, m_scene.RegionInfo.RegionName); continue; - } - AssetBase asset = m_scene.AssetService.Get(bakedTextureFace.TextureID.ToString()); + AssetBase asset; + cache.Get(bakedTextureFace.TextureID.ToString(), out asset); - if (asset != null) + if (asset != null && asset.Local) { + // cache does not update asset contents + cache.Expire(bakedTextureFace.TextureID.ToString()); + // Replace an HG ID with the simple asset ID so that we can persist textures for foreign HG avatars asset.ID = asset.FullID.ToString(); @@ -334,7 +314,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory asset.Local = false; m_scene.AssetService.Store(asset); } - else + + if (asset == null) { m_log.WarnFormat( "[AV FACTORY]: Baked texture id {0} not found for bake {1} for avatar {2} in {3} when trying to save permanently", @@ -377,116 +358,366 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory } } - public bool ValidateBakedTextureCache(IScenePresence sp) + // called on textures update + public bool UpdateBakedTextureCache(IScenePresence sp, WearableCacheItem[] cacheItems) { - bool defonly = true; // are we only using default textures - IImprovedAssetCache cache = m_scene.RequestModuleInterface(); - IBakedTextureModule bakedModule = m_scene.RequestModuleInterface(); - WearableCacheItem[] wearableCache = null; - - // Cache wearable data for teleport. - // Only makes sense if there's a bake module and a cache module - if (bakedModule != null && cache != null) + if(cacheItems == null) + return false; + + // npcs dont have baked cache + if (((ScenePresence)sp).IsNPC) + return true; + + // uploaded baked textures will be in assets local cache + IAssetCache cache = m_scene.RequestModuleInterface(); + IBakedTextureModule m_BakedTextureModule = m_scene.RequestModuleInterface(); + + int validDirtyBakes = 0; + int hits = 0; + + // our main cacheIDs mapper is p.Appearance.WearableCacheItems + WearableCacheItem[] wearableCache = sp.Appearance.WearableCacheItems; + + if (wearableCache == null) + { + wearableCache = WearableCacheItem.GetDefaultCacheItem(); + } + + List missing = new List(); + + bool haveSkirt = (wearableCache[19].TextureID != UUID.Zero); + bool haveNewSkirt = false; + + // Process received baked textures + for (int i = 0; i < cacheItems.Length; i++) { - try + int idx = (int)cacheItems[i].TextureIndex; + Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx]; + + // No face + if (face == null) { - wearableCache = bakedModule.Get(sp.UUID); + // for some reason viewer is cleaning this + if(idx != 19) // skirt is optional + { + sp.Appearance.Texture.FaceTextures[idx] = sp.Appearance.Texture.CreateFace((uint) idx); + sp.Appearance.Texture.FaceTextures[idx].TextureID = AppearanceManager.DEFAULT_AVATAR_TEXTURE; + } + wearableCache[idx].CacheId = UUID.Zero; + wearableCache[idx].TextureID = UUID.Zero; + wearableCache[idx].TextureAsset = null; + continue; } - catch (Exception) + else { + if (face.TextureID == UUID.Zero || face.TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE) + { + wearableCache[idx].CacheId = UUID.Zero; + wearableCache[idx].TextureID = UUID.Zero; + wearableCache[idx].TextureAsset = null; + continue; + } - } - if (wearableCache != null) - { - for (int i = 0; i < wearableCache.Length; i++) + if(idx == 19) + haveNewSkirt = true; +/* + if (face.TextureID == wearableCache[idx].TextureID && m_BakedTextureModule != null) { - cache.Cache(wearableCache[i].TextureAsset); + if (wearableCache[idx].CacheId != cacheItems[i].CacheId) + { + wearableCache[idx].CacheId = cacheItems[i].CacheId; + validDirtyBakes++; + + //assuming this can only happen if asset is in cache + } + hits++; + continue; + } +*/ + wearableCache[idx].TextureAsset = null; + if (cache != null) + { + AssetBase asb = null; + cache.Get(face.TextureID.ToString(), out asb); + wearableCache[idx].TextureAsset = asb; + } + + if (wearableCache[idx].TextureAsset != null) + { + if ( wearableCache[idx].TextureID != face.TextureID || + wearableCache[idx].CacheId != cacheItems[i].CacheId) + validDirtyBakes++; + + wearableCache[idx].TextureID = face.TextureID; + wearableCache[idx].CacheId = cacheItems[i].CacheId; + hits++; + } + else + { + wearableCache[idx].CacheId = UUID.Zero; + wearableCache[idx].TextureID = UUID.Zero; + wearableCache[idx].TextureAsset = null; + missing.Add(face.TextureID); + continue; } } } - /* - IBakedTextureModule bakedModule = m_scene.RequestModuleInterface(); - if (invService.GetRootFolder(userID) != null) + + // handle optional skirt case + if(!haveNewSkirt && haveSkirt) + { + wearableCache[19].CacheId = UUID.Zero; + wearableCache[19].TextureID = UUID.Zero; + wearableCache[19].TextureAsset = null; + validDirtyBakes++; + } + + sp.Appearance.WearableCacheItems = wearableCache; + + if (missing.Count > 0) { - WearableCacheItem[] wearableCache = null; - if (bakedModule != null) + foreach (UUID id in missing) + sp.ControllingClient.SendRebakeAvatarTextures(id); + } + + if (validDirtyBakes > 0 && hits == cacheItems.Length) + { + // if we got a full set of baked textures save all in BakedTextureModule + if (m_BakedTextureModule != null) { - try + m_log.DebugFormat("[UpdateBakedCache] Uploading to Bakes Server: cache hits: {0} changed entries: {1} rebakes {2}", + hits.ToString(), validDirtyBakes.ToString(), missing.Count); + + m_BakedTextureModule.Store(sp.UUID, wearableCache); + } + } + else + m_log.DebugFormat("[UpdateBakedCache] cache hits: {0} changed entries: {1} rebakes {2}", + hits.ToString(), validDirtyBakes.ToString(), missing.Count); + + for (int iter = 0; iter < AvatarAppearance.BAKE_INDICES.Length; iter++) + { + int j = AvatarAppearance.BAKE_INDICES[iter]; + sp.Appearance.WearableCacheItems[j].TextureAsset = null; +// m_log.Debug("[UpdateBCache] {" + iter + "/" + +// sp.Appearance.WearableCacheItems[j].TextureIndex + "}: c-" + +// sp.Appearance.WearableCacheItems[j].CacheId + ", t-" + +// sp.Appearance.WearableCacheItems[j].TextureID); + } + + return (hits == cacheItems.Length); + } + + // called when we get a new root avatar + public bool ValidateBakedTextureCache(IScenePresence sp) + { + int hits = 0; + + if (((ScenePresence)sp).IsNPC) + return true; + + lock (m_setAppearanceLock) + { + IAssetCache cache = m_scene.RequestModuleInterface(); + IBakedTextureModule bakedModule = m_scene.RequestModuleInterface(); + WearableCacheItem[] bakedModuleCache = null; + + if (cache == null) + return false; + + WearableCacheItem[] wearableCache = sp.Appearance.WearableCacheItems; + + // big debug + //m_log.DebugFormat("[AVFACTORY]: ValidateBakedTextureCache start for {0} {1}", sp.Name, sp.UUID); +/* + for (int iter = 0; iter < AvatarAppearance.BAKE_INDICES.Length; iter++) + { + int j = AvatarAppearance.BAKE_INDICES[iter]; + Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[j]; + if (wearableCache == null) + { + if (face != null) + m_log.Debug("[ValidateBakedCache] {" + iter + "/" + j + " t- " + face.TextureID); + else + m_log.Debug("[ValidateBakedCache] {" + iter + "/" + j + " t- No texture"); + } + else + { + if (face != null) + m_log.Debug("[ValidateBakedCache] {" + iter + "/" + j + " ft- " + face.TextureID + + "}: cc-" + + wearableCache[j].CacheId + ", ct-" + + wearableCache[j].TextureID + ); + else + m_log.Debug("[ValidateBakedCache] {" + iter + "/" + j + " t - No texture" + + "}: cc-" + + wearableCache[j].CacheId + ", ct-" + + wearableCache[j].TextureID + ); + } + } +*/ + + bool wearableCacheValid = false; + if (wearableCache == null) + { + wearableCache = WearableCacheItem.GetDefaultCacheItem(); + } + else + { + // we may have received a full cache + // check same coerence and store + wearableCacheValid = true; + for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) { - wearableCache = bakedModule.Get(userID); - appearance.WearableCacheItems = wearableCache; - appearance.WearableCacheItemsDirty = false; - foreach (WearableCacheItem item in wearableCache) + int idx = AvatarAppearance.BAKE_INDICES[i]; + Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx]; + if (face != null) { - appearance.Texture.FaceTextures[item.TextureIndex].TextureID = item.TextureID; + if (face.TextureID == wearableCache[idx].TextureID && + face.TextureID != UUID.Zero) + { + if (wearableCache[idx].TextureAsset != null) + { + hits++; + wearableCache[idx].TextureAsset.Temporary = true; + wearableCache[idx].TextureAsset.Local = true; + cache.Cache(wearableCache[idx].TextureAsset); + wearableCache[idx].TextureAsset = null; + continue; + } + + if (cache.Check((wearableCache[idx].TextureID).ToString())) + { + hits++; + continue; + } + } + wearableCacheValid = false; } } - catch (Exception) + + wearableCacheValid = (wearableCacheValid && (hits >= AvatarAppearance.BAKE_INDICES.Length - 1)); + if (wearableCacheValid) { - + //m_log.Debug("[ValidateBakedCache] have valid local cache"); } + else + wearableCache[19].TextureAsset = null; // clear optional skirt } - */ - // Process the texture entry - for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) - { - int idx = AvatarAppearance.BAKE_INDICES[i]; - Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx]; + bool checkExternal = false; - // No face, so lets check our baked service cache, teleport or login. - if (face == null) + if (!wearableCacheValid) { - if (wearableCache != null) + hits = 0; + // only use external bake module on login condition check +// ScenePresence ssp = null; +// if (sp is ScenePresence) { - // If we find the an appearance item, set it as the textureentry and the face - WearableCacheItem searchitem = WearableCacheItem.SearchTextureIndex((uint) idx, wearableCache); - if (searchitem != null) - { - sp.Appearance.Texture.FaceTextures[idx] = sp.Appearance.Texture.CreateFace((uint) idx); - sp.Appearance.Texture.FaceTextures[idx].TextureID = searchitem.TextureID; - face = sp.Appearance.Texture.FaceTextures[idx]; - } - else +// ssp = (ScenePresence)sp; +// checkExternal = (((uint)ssp.TeleportFlags & (uint)TeleportFlags.ViaLogin) != 0) && +// bakedModule != null; + + // or do it anytime we dont have the cache + checkExternal = bakedModule != null; + } + } + + if (checkExternal) + { + bool gotbacked = false; + + m_log.Debug("[ValidateBakedCache] local cache invalid, checking bakedModule"); + try + { + bakedModuleCache = bakedModule.Get(sp.UUID); + } + catch (Exception e) + { + m_log.ErrorFormat(e.ToString()); + bakedModuleCache = null; + } + + if (bakedModuleCache != null) + { + //m_log.Debug("[ValidateBakedCache] got bakedModule " + bakedModuleCache.Length + " cached textures"); + + for (int i = 0; i < bakedModuleCache.Length; i++) { - // if there is no texture entry and no baked cache, skip it - continue; + int j = (int)bakedModuleCache[i].TextureIndex; + + if (bakedModuleCache[i].TextureAsset != null) + { + wearableCache[j].TextureID = bakedModuleCache[i].TextureID; + wearableCache[j].CacheId = bakedModuleCache[i].CacheId; + wearableCache[j].TextureAsset = bakedModuleCache[i].TextureAsset; + bakedModuleCache[i].TextureAsset.Temporary = true; + bakedModuleCache[i].TextureAsset.Local = true; + cache.Cache(bakedModuleCache[i].TextureAsset); + } } + gotbacked = true; } - else + + if (gotbacked) { - //No texture entry face and no cache. Skip this face. - continue; + // force the ones we got + for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) + { + int idx = AvatarAppearance.BAKE_INDICES[i]; + if(wearableCache[idx].TextureAsset == null) + { + if(idx == 19) + { + sp.Appearance.Texture.FaceTextures[idx] = null; + hits++; + } + continue; + } + + Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx]; + + if (face == null) + { + face = sp.Appearance.Texture.CreateFace((uint)idx); + sp.Appearance.Texture.FaceTextures[idx] = face; + } + + face.TextureID = wearableCache[idx].TextureID; + hits++; + wearableCache[idx].TextureAsset = null; + } } } - -// m_log.DebugFormat( -// "[AVFACTORY]: Looking for texture {0}, id {1} for {2} {3}", -// face.TextureID, idx, client.Name, client.AgentId); - // if the texture is one of the "defaults" then skip it - // this should probably be more intelligent (skirt texture doesnt matter - // if the avatar isnt wearing a skirt) but if any of the main baked - // textures is default then the rest should be as well - if (face.TextureID == UUID.Zero || face.TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE) - continue; - - defonly = false; // found a non-default texture reference + sp.Appearance.WearableCacheItems = wearableCache; - if (m_scene.AssetService.Get(face.TextureID.ToString()) == null) - return false; } -// m_log.DebugFormat("[AVFACTORY]: Completed texture check for {0} {1}", sp.Name, sp.UUID); - - // If we only found default textures, then the appearance is not cached - return (defonly ? false : true); + // debug + //m_log.DebugFormat("[ValidateBakedCache]: Completed texture check for {0} {1} with {2} hits", sp.Name, sp.UUID, hits); +/* + for (int iter = 0; iter < AvatarAppearance.BAKE_INDICES.Length; iter++) + { + int j = AvatarAppearance.BAKE_INDICES[iter]; + m_log.Debug("[ValidateBakedCache] {" + iter + "/" + + sp.Appearance.WearableCacheItems[j].TextureIndex + "}: c-" + + sp.Appearance.WearableCacheItems[j].CacheId + ", t-" + + sp.Appearance.WearableCacheItems[j].TextureID); + } +*/ + return (hits >= AvatarAppearance.BAKE_INDICES.Length - 1); // skirt is optional } public int RequestRebake(IScenePresence sp, bool missingTexturesOnly) { + if (((ScenePresence)sp).IsNPC) + return 0; + int texturesRebaked = 0; -// IImprovedAssetCache cache = m_scene.RequestModuleInterface(); + IAssetCache cache = m_scene.RequestModuleInterface(); for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) { @@ -497,31 +728,17 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory if (face == null) continue; -// m_log.DebugFormat( -// "[AVFACTORY]: Looking for texture {0}, id {1} for {2} {3}", -// face.TextureID, idx, client.Name, client.AgentId); - - // if the texture is one of the "defaults" then skip it - // this should probably be more intelligent (skirt texture doesnt matter - // if the avatar isnt wearing a skirt) but if any of the main baked - // textures is default then the rest should be as well if (face.TextureID == UUID.Zero || face.TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE) continue; if (missingTexturesOnly) { - if (m_scene.AssetService.Get(face.TextureID.ToString()) != null) + if (cache != null && cache.Check(face.TextureID.ToString())) { continue; } else { - // On inter-simulator teleports, this occurs if baked textures are not being stored by the - // grid asset service (which means that they are not available to the new region and so have - // to be re-requested from the client). - // - // The only available core OpenSimulator behaviour right now - // is not to store these textures, temporarily or otherwise. m_log.DebugFormat( "[AVFACTORY]: Missing baked texture {0} ({1}) for {2}, requesting rebake.", face.TextureID, idx, sp.Name); @@ -605,7 +822,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory foreach (KeyValuePair kvp in saves) { // We have to load the key and value into local parameters to avoid a race condition if we loop - // around and load kvp with a different value before FireAndForget has launched its thread. + // around and load kvp with a different value before FireAndForget has launched its thread. UUID avatarID = kvp.Key; long sendTime = kvp.Value; @@ -658,13 +875,13 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory m_scene.AvatarService.SetAppearance(agentid, sp.Appearance); - // Trigger this here because it's the final step in the set/queue/save process for appearance setting. + // Trigger this here because it's the final step in the set/queue/save process for appearance setting. // Everything has been updated and stored. Ensures bakes have been persisted (if option is set to persist bakes). m_scene.EventManager.TriggerAvatarAppearanceChanged(sp); } /// - /// For a given set of appearance items, check whether the items are valid and add their asset IDs to + /// For a given set of appearance items, check whether the items are valid and add their asset IDs to /// appearance data. /// /// @@ -675,25 +892,27 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory if (invService.GetRootFolder(userID) != null) { - for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++) + for (int i = 0; i < appearance.Wearables.Length; i++) { for (int j = 0; j < appearance.Wearables[i].Count; j++) { if (appearance.Wearables[i][j].ItemID == UUID.Zero) { m_log.WarnFormat( - "[AVFACTORY]: Wearable item {0}:{1} for user {2} unexpectedly UUID.Zero. Ignoring.", + "[AVFACTORY]: Wearable item {0}:{1} for user {2} unexpectedly UUID.Zero. Ignoring.", i, j, userID); continue; } // Ignore ruth's assets - if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID) - continue; + if (i < AvatarWearable.DefaultWearables.Length) + { + if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID) + continue; + } - InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i][j].ItemID, userID); - baseItem = invService.GetItem(baseItem); + InventoryItemBase baseItem = invService.GetItem(userID, appearance.Wearables[i][j].ItemID); if (baseItem != null) { @@ -754,7 +973,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // case WearableType.Skin: // //case WearableType.Underpants: // TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance); -// +// // m_log.WarnFormat("[AVFACTORY]: {0} Default Wearables, passing existing values.", (WearableType)i); // resetwearable = true; // break; @@ -762,7 +981,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // } // continue; // } -// +// // InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i][j].ItemID, userID); // baseItem = invService.GetItem(baseItem); // @@ -789,7 +1008,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // // TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance); // resetwearable = true; -// +// // } // } // } @@ -798,7 +1017,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // if (appearance.Wearables[(int) WearableType.Eyes] == null) // { // m_log.WarnFormat("[AVFACTORY]: {0} Eyes are Null, passing existing values.", (WearableType.Eyes)); -// +// // TryAndRepairBrokenWearable(WearableType.Eyes, invService, userID, appearance); // resetwearable = true; // } @@ -902,85 +1121,45 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory { UUID newInvItem = UUID.Random(); InventoryItemBase itembase = new InventoryItemBase(newInvItem, userID) - { - AssetID = - defaultwearable, - AssetType - = - (int) - FolderType - .BodyPart, - CreatorId - = - userID - .ToString - (), - //InvType = (int)InventoryType.Wearable, - - Description - = - "Failed Wearable Replacement", - Folder = - invService - .GetFolderForType - (userID, - FolderType - .BodyPart) - .ID, - Flags = (uint) type, - Name = Enum.GetName(typeof (WearableType), type), - BasePermissions = (uint) PermissionMask.Copy, - CurrentPermissions = (uint) PermissionMask.Copy, - EveryOnePermissions = (uint) PermissionMask.Copy, - GroupPermissions = (uint) PermissionMask.Copy, - NextPermissions = (uint) PermissionMask.Copy - }; + { + AssetID = defaultwearable, + AssetType = (int)FolderType.BodyPart, + CreatorId = userID.ToString(), + //InvType = (int)InventoryType.Wearable, + Description = "Failed Wearable Replacement", + Folder = invService.GetFolderForType(userID, FolderType.BodyPart).ID, + Flags = (uint) type, Name = Enum.GetName(typeof (WearableType), type), + BasePermissions = (uint) PermissionMask.Copy, + CurrentPermissions = (uint) PermissionMask.Copy, + EveryOnePermissions = (uint) PermissionMask.Copy, + GroupPermissions = (uint) PermissionMask.Copy, + NextPermissions = (uint) PermissionMask.Copy + }; invService.AddItem(itembase); UUID LinkInvItem = UUID.Random(); itembase = new InventoryItemBase(LinkInvItem, userID) - { - AssetID = - newInvItem, - AssetType - = - (int) - AssetType - .Link, - CreatorId - = - userID - .ToString - (), - InvType = (int) InventoryType.Wearable, - - Description - = - "Failed Wearable Replacement", - Folder = - invService - .GetFolderForType - (userID, - FolderType - .CurrentOutfit) - .ID, - Flags = (uint) type, - Name = Enum.GetName(typeof (WearableType), type), - BasePermissions = (uint) PermissionMask.Copy, - CurrentPermissions = (uint) PermissionMask.Copy, - EveryOnePermissions = (uint) PermissionMask.Copy, - GroupPermissions = (uint) PermissionMask.Copy, - NextPermissions = (uint) PermissionMask.Copy - }; + { + AssetID = newInvItem, + AssetType = (int)AssetType.Link, + CreatorId = userID.ToString(), + InvType = (int) InventoryType.Wearable, + Description = "Failed Wearable Replacement", + Folder = invService.GetFolderForType(userID, FolderType.CurrentOutfit).ID, + Flags = (uint) type, + Name = Enum.GetName(typeof (WearableType), type), + BasePermissions = (uint) PermissionMask.Copy, + CurrentPermissions = (uint) PermissionMask.Copy, + EveryOnePermissions = (uint) PermissionMask.Copy, + GroupPermissions = (uint) PermissionMask.Copy, + NextPermissions = (uint) PermissionMask.Copy + }; invService.AddItem(itembase); appearance.Wearables[(int)type] = new AvatarWearable(newInvItem, GetDefaultItem(type)); ScenePresence presence = null; if (m_scene.TryGetScenePresence(userID, out presence)) { m_scene.SendInventoryUpdate(presence.ControllingClient, - invService.GetFolderForType(userID, - FolderType - .CurrentOutfit), - false, true); + invService.GetFolderForType(userID, FolderType.CurrentOutfit), false, true); } } } @@ -1040,7 +1219,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory m_log.WarnFormat("[AVFACTORY]: Client_OnRequestWearables unable to find presence for {0}", client.AgentId); }, null, "AvatarFactoryModule.OnClientRequestWearables"); } - + /// /// Set appearance data (texture asset IDs and slider settings) received from a client /// @@ -1080,8 +1259,17 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory foreach (AvatarWearingArgs.Wearable wear in e.NowWearing) { - if (wear.Type < AvatarWearable.MAX_WEARABLES) - avatAppearance.Wearables[wear.Type].Add(wear.ItemID, UUID.Zero); + // If the wearable type is larger than the current array, expand it + if (avatAppearance.Wearables.Length <= wear.Type) + { + int currentLength = avatAppearance.Wearables.Length; + AvatarWearable[] wears = avatAppearance.Wearables; + Array.Resize(ref wears, wear.Type + 1); + for (int i = currentLength ; i <= wear.Type ; i++) + wears[i] = new AvatarWearable(); + avatAppearance.Wearables = wears; + } + avatAppearance.Wearables[wear.Type].Add(wear.ItemID, UUID.Zero); } avatAppearance.GetAssetsFrom(sp.Appearance); @@ -1117,12 +1305,12 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory { UUID texture = UUID.Zero; int index = request.BakedTextureIndex; - + if (m_reusetextures) { // this is the most insanely dumb way to do this... however it seems to // actually work. if the appearance has been reset because wearables have - // changed then the texture entries are zero'd out until the bakes are + // changed then the texture entries are zero'd out until the bakes are // uploaded. on login, if the textures exist in the cache (eg if you logged // into the simulator recently, then the appearance will pull those and send // them back in the packet and you won't have to rebake. if the textures aren't @@ -1138,7 +1326,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // m_log.WarnFormat("[AVFACTORY]: reuse texture {0} for index {1}",texture,index); } - + CachedTextureResponseArg response = new CachedTextureResponseArg(); response.BakedTextureIndex = index; response.BakedTextureID = texture; @@ -1146,7 +1334,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory cachedTextureResponse.Add(response); } - + // m_log.WarnFormat("[AVFACTORY]: serial is {0}",serial); // The serial number appears to be used to match requests and responses // in the texture transaction. We just send back the serial number diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs index 9513408..33489d1 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs @@ -55,7 +55,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // We need an asset cache because otherwise the LocalAssetServiceConnector will short-circuit directly // to the AssetService, which will then store temporary and local assets permanently CoreAssetCache assetCache = new CoreAssetCache(); - + AvatarFactoryModule afm = new AvatarFactoryModule(); TestScene scene = new SceneHelpers(assetCache).SetupScene(); SceneHelpers.SetupSceneModules(scene, afm); @@ -63,7 +63,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // TODO: Use the actual BunchOfCaps functionality once we slot in the CapabilitiesModules AssetBase bakedTextureAsset; - bakedTextureAsset + bakedTextureAsset = new AssetBase( bakedTextureID, "Test Baked Texture", (sbyte)AssetType.Texture, userId.ToString()); bakedTextureAsset.Data = new byte[] { 2 }; // Not necessary to have a genuine JPEG2000 asset here yet @@ -85,7 +85,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // This is the alpha texture eyesFace.TextureID = bakedTextureID; afm.SetAppearance(sp, bakedTextureEntry, visualParams, null); - + Assert.That(rebakeRequestsReceived, Is.EqualTo(0)); AssetBase eyesBake = scene.AssetService.Get(bakedTextureID.ToString()); @@ -98,7 +98,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory /// Test appearance setting where the baked texture UUID are library alpha textures. /// /// - /// For a mesh avatar, it appears these 'baked textures' are used. So these should not trigger a request to + /// For a mesh avatar, it appears these 'baked textures' are used. So these should not trigger a request to /// rebake. /// [Test] @@ -113,14 +113,14 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // We need an asset cache because otherwise the LocalAssetServiceConnector will short-circuit directly // to the AssetService, which will then store temporary and local assets permanently CoreAssetCache assetCache = new CoreAssetCache(); - + AvatarFactoryModule afm = new AvatarFactoryModule(); TestScene scene = new SceneHelpers(assetCache).SetupScene(); SceneHelpers.SetupSceneModules(scene, afm); ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId); AssetBase libraryAsset; - libraryAsset + libraryAsset = new AssetBase( alphaTextureID, "Default Alpha Layer Texture", (sbyte)AssetType.Texture, userId.ToString()); libraryAsset.Data = new byte[] { 2 }; // Not necessary to have a genuine JPEG2000 asset here yet @@ -142,7 +142,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // This is the alpha texture eyesFace.TextureID = alphaTextureID; afm.SetAppearance(sp, bakedTextureEntry, visualParams, null); - + Assert.That(rebakeRequestsReceived, Is.EqualTo(0)); } @@ -158,7 +158,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // We need an asset cache because otherwise the LocalAssetServiceConnector will short-circuit directly // to the AssetService, which will then store temporary and local assets permanently CoreAssetCache assetCache = new CoreAssetCache(); - + AvatarFactoryModule afm = new AvatarFactoryModule(); TestScene scene = new SceneHelpers(assetCache).SetupScene(); SceneHelpers.SetupSceneModules(scene, afm); @@ -181,7 +181,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory Primitive.TextureEntryFace eyesFace = bakedTextureEntry.CreateFace(eyesFaceIndex); eyesFace.TextureID = eyesTextureId; - afm.SetAppearance(sp, bakedTextureEntry, visualParams, null); + afm.SetAppearance(sp, bakedTextureEntry, visualParams, new WearableCacheItem[0]); afm.SaveBakedTextures(userId); // Dictionary bakedTextures = afm.GetBakedTextureFaces(userId); diff --git a/OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs b/OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs index 414f06a..61e461a 100644 --- a/OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs @@ -53,6 +53,7 @@ namespace OpenSim.Region.CoreModules.Avatar.BakedTextures private UTF8Encoding enc = new UTF8Encoding(); private string m_URL = String.Empty; private static XmlSerializer m_serializer = new XmlSerializer(typeof(AssetBase)); + private static bool m_enabled = false; private static IServiceAuth m_Auth; @@ -63,11 +64,19 @@ namespace OpenSim.Region.CoreModules.Avatar.BakedTextures return; m_URL = config.GetString("URL", String.Empty); + if (m_URL == String.Empty) + return; + + m_enabled = true; + m_Auth = ServiceAuth.Create(configSource, "XBakes"); } public void AddRegion(Scene scene) { + if (!m_enabled) + return; + // m_log.InfoFormat("[XBakes]: Enabled for region {0}", scene.RegionInfo.RegionName); m_Scene = scene; @@ -101,8 +110,6 @@ namespace OpenSim.Region.CoreModules.Avatar.BakedTextures if (m_URL == String.Empty) return null; - int size = 0; - using (RestClient rc = new RestClient(m_URL)) { List ret = new List(); @@ -113,35 +120,42 @@ namespace OpenSim.Region.CoreModules.Avatar.BakedTextures try { - Stream s = rc.Request(m_Auth); - - using (XmlTextReader sr = new XmlTextReader(s)) + using(Stream s = rc.Request(m_Auth)) { - sr.ReadStartElement("BakedAppearance"); - while (sr.LocalName == "BakedTexture") + using(XmlTextReader sr = new XmlTextReader(s)) { - string sTextureIndex = sr.GetAttribute("TextureIndex"); - int lTextureIndex = Convert.ToInt32(sTextureIndex); - string sCacheId = sr.GetAttribute("CacheId"); - UUID lCacheId = UUID.Zero; - if (!(UUID.TryParse(sCacheId, out lCacheId))) + sr.ProhibitDtd = true; + + sr.ReadStartElement("BakedAppearance"); + while(sr.LocalName == "BakedTexture") { + string sTextureIndex = sr.GetAttribute("TextureIndex"); + int lTextureIndex = Convert.ToInt32(sTextureIndex); + string sCacheId = sr.GetAttribute("CacheId"); + UUID lCacheId = UUID.Zero; + if(!(UUID.TryParse(sCacheId,out lCacheId))) + { // ?? Nothing here + } + + sr.ReadStartElement("BakedTexture"); + if(sr.Name=="AssetBase") + { + AssetBase a = (AssetBase)m_serializer.Deserialize(sr); + ret.Add(new WearableCacheItem() + { + CacheId = lCacheId, + TextureIndex = (uint)lTextureIndex, + TextureAsset = a, + TextureID = a.FullID + }); + sr.ReadEndElement(); + } } - - ++size; - - sr.ReadStartElement("BakedTexture"); - AssetBase a = (AssetBase)m_serializer.Deserialize(sr); - ret.Add(new WearableCacheItem() { CacheId = lCacheId, TextureIndex = (uint)lTextureIndex, TextureAsset = a, TextureID = a.FullID }); - - sr.ReadEndElement(); + m_log.DebugFormat("[XBakes]: read {0} textures for user {1}",ret.Count,id); } - - m_log.DebugFormat("[XBakes]: read {0} textures for user {1}", ret.Count, id); + return ret.ToArray(); } - - return ret.ToArray(); } catch (XmlException) { @@ -150,11 +164,20 @@ namespace OpenSim.Region.CoreModules.Avatar.BakedTextures } } + public void Store(UUID agentId) + { + } + + public void UpdateMeshAvatar(UUID agentId) + { + } + public void Store(UUID agentId, WearableCacheItem[] data) { if (m_URL == String.Empty) return; + int numberWears = 0; MemoryStream reqStream; using (MemoryStream bakeStream = new MemoryStream()) @@ -164,15 +187,16 @@ namespace OpenSim.Region.CoreModules.Avatar.BakedTextures for (int i = 0; i < data.Length; i++) { - if (data[i] != null) + if (data[i] != null && data[i].TextureAsset != null) { bakeWriter.WriteStartElement(String.Empty, "BakedTexture", String.Empty); bakeWriter.WriteAttributeString(String.Empty, "TextureIndex", String.Empty, data[i].TextureIndex.ToString()); bakeWriter.WriteAttributeString(String.Empty, "CacheId", String.Empty, data[i].CacheId.ToString()); - if (data[i].TextureAsset != null) +// if (data[i].TextureAsset != null) m_serializer.Serialize(bakeWriter, data[i].TextureAsset); bakeWriter.WriteEndElement(); + numberWears++; } } @@ -182,19 +206,22 @@ namespace OpenSim.Region.CoreModules.Avatar.BakedTextures reqStream = new MemoryStream(bakeStream.ToArray()); } - RestClient rc = new RestClient(m_URL); - rc.AddResourcePath("bakes"); - rc.AddResourcePath(agentId.ToString()); - - rc.RequestMethod = "POST"; - Util.FireAndForget( delegate { - rc.Request(reqStream, m_Auth); - m_log.DebugFormat("[XBakes]: stored {0} textures for user {1}", data.Length, agentId); + using(RestClient rc = new RestClient(m_URL)) + { + rc.AddResourcePath("bakes"); + rc.AddResourcePath(agentId.ToString()); + rc.RequestMethod = "POST"; + + rc.Request(reqStream, m_Auth); + m_log.DebugFormat("[XBakes]: stored {0} textures for user {1}", numberWears, agentId); + } + if(reqStream != null) + reqStream.Dispose(); }, null, "XBakesModule.Store" ); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs index f0b1e67..ea90185 100644 --- a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs @@ -45,17 +45,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private const int DEBUG_CHANNEL = 2147483647; - - private bool m_enabled = true; - private int m_saydistance = 20; - private int m_shoutdistance = 100; - private int m_whisperdistance = 10; - - internal object m_syncy = new object(); - - internal IConfig m_config; - + protected const int DEBUG_CHANNEL = 2147483647; + + protected bool m_enabled = true; + protected int m_saydistance = 20; + protected int m_shoutdistance = 100; + protected int m_whisperdistance = 10; + protected List m_scenes = new List(); + protected List FreezeCache = new List(); + protected string m_adminPrefix = ""; + protected object m_syncy = new object(); + protected IConfig m_config; #region ISharedRegionModule Members public virtual void Initialise(IConfigSource config) { @@ -69,21 +69,28 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat m_enabled = false; return; } - } - m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance); - m_saydistance = config.Configs["Chat"].GetInt("say_distance", m_saydistance); - m_shoutdistance = config.Configs["Chat"].GetInt("shout_distance", m_shoutdistance); + m_whisperdistance = m_config.GetInt("whisper_distance", m_whisperdistance); + m_saydistance = m_config.GetInt("say_distance", m_saydistance); + m_shoutdistance = m_config.GetInt("shout_distance", m_shoutdistance); + m_adminPrefix = m_config.GetString("admin_prefix", ""); + } } public virtual void AddRegion(Scene scene) { - if (!m_enabled) - return; + if (!m_enabled) return; - scene.EventManager.OnNewClient += OnNewClient; - scene.EventManager.OnChatFromWorld += OnChatFromWorld; - scene.EventManager.OnChatBroadcast += OnChatBroadcast; + lock (m_syncy) + { + if (!m_scenes.Contains(scene)) + { + m_scenes.Add(scene); + scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnChatFromWorld += OnChatFromWorld; + scene.EventManager.OnChatBroadcast += OnChatBroadcast; + } + } m_log.InfoFormat("[CHAT]: Initialized for {0} w:{1} s:{2} S:{3}", scene.RegionInfo.RegionName, m_whisperdistance, m_saydistance, m_shoutdistance); @@ -103,14 +110,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat public virtual void RemoveRegion(Scene scene) { - if (!m_enabled) - return; + if (!m_enabled) return; - scene.EventManager.OnNewClient -= OnNewClient; - scene.EventManager.OnChatFromWorld -= OnChatFromWorld; - scene.EventManager.OnChatBroadcast -= OnChatBroadcast; + lock (m_syncy) + { + if (m_scenes.Contains(scene)) + { + scene.EventManager.OnNewClient -= OnNewClient; + scene.EventManager.OnChatFromWorld -= OnChatFromWorld; + scene.EventManager.OnChatBroadcast -= OnChatBroadcast; + m_scenes.Remove(scene); + } + } } - + public virtual void Close() { } @@ -119,7 +132,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat { } - public Type ReplaceableInterface + public virtual Type ReplaceableInterface { get { return null; } } @@ -137,7 +150,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat client.OnChatFromClient += OnChatFromClient; } - protected OSChatMessage FixPositionOfChatMessage(OSChatMessage c) + protected virtual OSChatMessage FixPositionOfChatMessage(OSChatMessage c) { ScenePresence avatar; Scene scene = (Scene)c.Scene; @@ -165,7 +178,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat return; } - DeliverChatToAvatars(ChatSourceType.Agent, c); + if (FreezeCache.Contains(c.Sender.AgentId.ToString())) + { + if (c.Type != ChatTypeEnum.StartTyping || c.Type != ChatTypeEnum.StopTyping) + c.Sender.SendAgentAlertMessage("You may not talk as you are frozen.", false); + } + else + { + DeliverChatToAvatars(ChatSourceType.Agent, c); + } } public virtual void OnChatFromWorld(Object sender, OSChatMessage c) @@ -179,34 +200,63 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat protected virtual void DeliverChatToAvatars(ChatSourceType sourceType, OSChatMessage c) { string fromName = c.From; + string fromNamePrefix = ""; UUID fromID = UUID.Zero; UUID ownerID = UUID.Zero; - UUID targetID = c.TargetUUID; string message = c.Message; - Scene scene = (Scene)c.Scene; + Scene scene = c.Scene as Scene; + UUID destination = c.Destination; Vector3 fromPos = c.Position; Vector3 regionPos = new Vector3(scene.RegionInfo.WorldLocX, scene.RegionInfo.WorldLocY, 0); + bool checkParcelHide = false; + UUID sourceParcelID = UUID.Zero; + Vector3 hidePos = fromPos; + if (c.Channel == DEBUG_CHANNEL) c.Type = ChatTypeEnum.DebugChannel; - switch (sourceType) + if(!m_scenes.Contains(scene)) { - case ChatSourceType.Agent: - ScenePresence avatar = scene.GetScenePresence(c.Sender.AgentId); - fromPos = avatar.AbsolutePosition; - fromName = avatar.Name; - fromID = c.Sender.AgentId; - ownerID = c.Sender.AgentId; + m_log.WarnFormat("[CHAT]: message from unkown scene {0} ignored", + scene.RegionInfo.RegionName); + return; + } - break; + switch (sourceType) + { + case ChatSourceType.Agent: + ScenePresence avatar = (scene as Scene).GetScenePresence(c.Sender.AgentId); + fromPos = avatar.AbsolutePosition; + fromName = avatar.Name; + fromID = c.Sender.AgentId; + if (avatar.IsViewerUIGod) + { // let gods speak to outside or things may get confusing + fromNamePrefix = m_adminPrefix; + checkParcelHide = false; + } + else + { + checkParcelHide = true; + } + destination = UUID.Zero; // Avatars cant "SayTo" + ownerID = c.Sender.AgentId; - case ChatSourceType.Object: - fromID = c.SenderUUID; + hidePos = fromPos; + break; - if (c.SenderObject != null && c.SenderObject is SceneObjectPart) - ownerID = ((SceneObjectPart)c.SenderObject).OwnerID; + case ChatSourceType.Object: + fromID = c.SenderUUID; - break; + if (c.SenderObject != null && c.SenderObject is SceneObjectPart) + { + ownerID = ((SceneObjectPart)c.SenderObject).OwnerID; + if (((SceneObjectPart)c.SenderObject).ParentGroup.IsAttachment) + { + checkParcelHide = true; + hidePos = ((SceneObjectPart)c.SenderObject).ParentGroup.AbsolutePosition; + } + } + break; } // TODO: iterate over message @@ -214,43 +264,66 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat message = message.Substring(0, 1000); // m_log.DebugFormat( -// "[CHAT]: DCTA: fromID {0} fromName {1}, region{2}, cType {3}, sType {4}, targetID {5}", -// fromID, fromName, scene.RegionInfo.RegionName, c.Type, sourceType, targetID); +// "[CHAT]: DCTA: fromID {0} fromName {1}, region{2}, cType {3}, sType {4}", +// fromID, fromName, scene.RegionInfo.RegionName, c.Type, sourceType); HashSet receiverIDs = new HashSet(); - if (targetID == UUID.Zero) + if (checkParcelHide) { - // This should use ForEachClient, but clients don't have a position. - // If camera is moved into client, then camera position can be used - scene.ForEachScenePresence( - delegate(ScenePresence presence) + checkParcelHide = false; + if (c.Type < ChatTypeEnum.DebugChannel && destination == UUID.Zero) + { + ILandObject srcland = scene.LandChannel.GetLandObject(hidePos.X, hidePos.Y); + if (srcland != null && !srcland.LandData.SeeAVs) { - if (TrySendChatMessage( - presence, fromPos, regionPos, fromID, ownerID, fromName, c.Type, message, sourceType, false)) - receiverIDs.Add(presence.UUID); + sourceParcelID = srcland.LandData.GlobalID; + checkParcelHide = true; } - ); - } - else - { - // This is a send to a specific client eg from llRegionSayTo - // no need to check distance etc, jand send is as say - ScenePresence presence = scene.GetScenePresence(targetID); - if (presence != null && !presence.IsChildAgent) - { - if (TrySendChatMessage( - presence, fromPos, regionPos, fromID, ownerID, fromName, ChatTypeEnum.Say, message, sourceType, true)) - receiverIDs.Add(presence.UUID); } } + scene.ForEachScenePresence( + delegate(ScenePresence presence) + { + if (destination != UUID.Zero && presence.UUID != destination) + return; + + if(presence.IsChildAgent) + { + if(checkParcelHide) + return; + if (TrySendChatMessage(presence, fromPos, regionPos, fromID, + ownerID, fromNamePrefix + fromName, c.Type, + message, sourceType, (destination != UUID.Zero))) + receiverIDs.Add(presence.UUID); + return; + } + + ILandObject Presencecheck = scene.LandChannel.GetLandObject(presence.AbsolutePosition.X, presence.AbsolutePosition.Y); + if (Presencecheck != null) + { + if (checkParcelHide) + { + if (sourceParcelID != Presencecheck.LandData.GlobalID && !presence.IsViewerUIGod) + return; + } + if (c.Sender == null || Presencecheck.IsEitherBannedOrRestricted(c.Sender.AgentId) != true) + { + if (TrySendChatMessage(presence, fromPos, regionPos, fromID, + ownerID, fromNamePrefix + fromName, c.Type, + message, sourceType, (destination != UUID.Zero))) + receiverIDs.Add(presence.UUID); + } + } + }); + scene.EventManager.TriggerOnChatToClients( fromID, receiverIDs, message, c.Type, fromPos, fromName, sourceType, ChatAudibleLevel.Fully); } - static private Vector3 CenterOfRegion = new Vector3(128, 128, 30); - + static protected Vector3 CenterOfRegion = new Vector3(128, 128, 30); + public virtual void OnChatBroadcast(Object sender, OSChatMessage c) { if (c.Channel != 0 && c.Channel != DEBUG_CHANNEL) return; @@ -268,7 +341,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat // broadcast chat works by redistributing every incoming chat // message to each avatar in the scene. string fromName = c.From; - + UUID fromID = UUID.Zero; UUID ownerID = UUID.Zero; ChatSourceType sourceType = ChatSourceType.Object; @@ -280,35 +353,36 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat ownerID = c.Sender.AgentId; sourceType = ChatSourceType.Agent; } - else if (c.SenderUUID != UUID.Zero) + else if (c.SenderUUID != UUID.Zero) { fromID = c.SenderUUID; ownerID = ((SceneObjectPart)c.SenderObject).OwnerID; } - - // m_log.DebugFormat("[CHAT] Broadcast: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, cType, sourceType); + // m_log.DebugFormat("[CHAT] Broadcast: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, cType, sourceType); HashSet receiverIDs = new HashSet(); - - ((Scene)c.Scene).ForEachRootClient( - delegate(IClientAPI client) - { - // don't forward SayOwner chat from objects to - // non-owner agents - if ((c.Type == ChatTypeEnum.Owner) && - (null != c.SenderObject) && - (((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId)) - return; - client.SendChatMessage( - c.Message, (byte)cType, CenterOfRegion, fromName, fromID, ownerID, - (byte)sourceType, (byte)ChatAudibleLevel.Fully); - - receiverIDs.Add(client.AgentId); - }); - - (c.Scene as Scene).EventManager.TriggerOnChatToClients( - fromID, receiverIDs, c.Message, cType, CenterOfRegion, fromName, sourceType, ChatAudibleLevel.Fully); + if (c.Scene != null) + { + ((Scene)c.Scene).ForEachRootClient + ( + delegate(IClientAPI client) + { + // don't forward SayOwner chat from objects to + // non-owner agents + if ((c.Type == ChatTypeEnum.Owner) && + (null != c.SenderObject) && + (((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId)) + return; + + client.SendChatMessage(c.Message, (byte)cType, CenterOfRegion, fromName, fromID, fromID, + (byte)sourceType, (byte)ChatAudibleLevel.Fully); + receiverIDs.Add(client.AgentId); + } + ); + (c.Scene as Scene).EventManager.TriggerOnChatToClients( + fromID, receiverIDs, c.Message, cType, CenterOfRegion, fromName, sourceType, ChatAudibleLevel.Fully); + } } /// @@ -326,7 +400,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat /// /// /// - /// true if the message was sent to the receiver, false if it was not sent due to failing a + /// true if the message was sent to the receiver, false if it was not sent due to failing a /// precondition protected virtual bool TrySendChatMessage( ScenePresence presence, Vector3 fromPos, Vector3 regionPos, @@ -356,15 +430,44 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat presence.ControllingClient.SendChatMessage( message, (byte) type, fromPos, fromName, fromAgentID, ownerID, (byte)src, (byte)ChatAudibleLevel.Fully); - + return true; } + Dictionary Timers = new Dictionary(); + public virtual void ParcelFreezeUser(IClientAPI client, UUID parcelowner, uint flags, UUID target) + { + System.Threading.Timer Timer; + if (flags == 0) + { + FreezeCache.Add(target.ToString()); + System.Threading.TimerCallback timeCB = new System.Threading.TimerCallback(OnEndParcelFrozen); + Timer = new System.Threading.Timer(timeCB, target, 30000, 0); + Timers.Add(target, Timer); + } + else + { + FreezeCache.Remove(target.ToString()); + Timers.TryGetValue(target, out Timer); + Timers.Remove(target); + Timer.Dispose(); + } + } + + protected virtual void OnEndParcelFrozen(object avatar) + { + UUID target = (UUID)avatar; + FreezeCache.Remove(target.ToString()); + System.Threading.Timer Timer; + Timers.TryGetValue(target, out Timer); + Timers.Remove(target); + Timer.Dispose(); + } #region SimulatorFeaturesRequest - static OSDInteger m_SayRange, m_WhisperRange, m_ShoutRange; + protected static OSDInteger m_SayRange, m_WhisperRange, m_ShoutRange; - private void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features) + protected virtual void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features) { OSD extras = new OSDMap(); if (features.ContainsKey("OpenSimExtras")) diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs index 3018d94..5457dc3 100644 --- a/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs @@ -41,12 +41,13 @@ using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; using OpenSim.Region.Framework.Scenes; using OpenSim.Services.Interfaces; using OpenSim.Tests.Common; +using System.Threading; namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests { [TestFixture] public class ChatModuleTests : OpenSimTestCase - { + { [TestFixtureSetUp] public void FixtureInit() { @@ -65,14 +66,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests } private void SetupNeighbourRegions(TestScene sceneA, TestScene sceneB) - { - // XXX: HTTP server is not (and should not be) necessary for this test, though it's absence makes the + { + // XXX: HTTP server is not (and should not be) necessary for this test, though it's absence makes the // CapabilitiesModule complain when it can't set up HTTP endpoints. - // BaseHttpServer httpServer = new BaseHttpServer(99999); - // MainServer.AddHttpServer(httpServer); - // MainServer.Instance = httpServer; + BaseHttpServer httpServer = new BaseHttpServer(99999); + MainServer.AddHttpServer(httpServer); + MainServer.Instance = httpServer; - // We need entity transfer modules so that when sp2 logs into the east region, the region calls + // We need entity transfer modules so that when sp2 logs into the east region, the region calls // EntityTransferModuleto set up a child agent on the west region. // XXX: However, this is not an entity transfer so is misleading. EntityTransferModule etmA = new EntityTransferModule(); @@ -86,7 +87,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests modulesConfig.Set("SimulationServices", lscm.Name); SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); - SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA, new ChatModule()); + SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA, new ChatModule()); SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB, new ChatModule()); } @@ -110,8 +111,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests Vector3 sp2Position = new Vector3(250, 128, 20); SceneHelpers sh = new SceneHelpers(); - TestScene sceneWest = sh.SetupScene("sceneWest", TestHelpers.ParseTail(0x1), 1000, 1000); - TestScene sceneEast = sh.SetupScene("sceneEast", TestHelpers.ParseTail(0x2), 1001, 1000); + TestScene sceneWest = sh.SetupScene("sceneWest", TestHelpers.ParseTail(0x1), 1000, 1000); + TestScene sceneEast = sh.SetupScene("sceneEast", TestHelpers.ParseTail(0x2), 1001, 1000); SetupNeighbourRegions(sceneWest, sceneEast); @@ -123,12 +124,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests // physics is irrelevant to this test. sp1.Flying = true; - // When sp1 logs in to sceneEast, it sets up a child agent in sceneWest and informs the sp2 client to + // When sp1 logs in to sceneEast, it sets up a child agent in sceneWest and informs the sp2 client to // make the connection. For this test, will simplify this chain by making the connection directly. ScenePresence sp1Child = SceneHelpers.AddChildScenePresence(sceneWest, sp1Uuid); TestClient sp1ChildClient = (TestClient)sp1Child.ControllingClient; - sp1.AbsolutePosition = sp1Position; + sp1.AbsolutePosition = sp1Position; ScenePresence sp2 = SceneHelpers.AddScenePresence(sceneWest, sp2Uuid); TestClient sp2Client = (TestClient)sp2.ControllingClient; @@ -137,7 +138,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests ScenePresence sp2Child = SceneHelpers.AddChildScenePresence(sceneEast, sp2Uuid); TestClient sp2ChildClient = (TestClient)sp2Child.ControllingClient; - sp2.AbsolutePosition = sp2Position; + sp2.AbsolutePosition = sp2Position; // We must update the scenes in order to make the root new root agents trigger position updates in their // children. @@ -146,19 +147,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests // Check child positions are correct. Assert.AreEqual( - new Vector3(sp1Position.X + sceneEast.RegionInfo.RegionSizeX, sp1Position.Y, sp1Position.Z), + new Vector3(sp1Position.X + sceneEast.RegionInfo.RegionSizeX, sp1Position.Y, sp1Position.Z), sp1ChildClient.SceneAgent.AbsolutePosition); Assert.AreEqual( - new Vector3(sp2Position.X - sceneWest.RegionInfo.RegionSizeX, sp2Position.Y, sp2Position.Z), + new Vector3(sp2Position.X - sceneWest.RegionInfo.RegionSizeX, sp2Position.Y, sp2Position.Z), sp2ChildClient.SceneAgent.AbsolutePosition); string receivedSp1ChatMessage = ""; string receivedSp2ChatMessage = ""; - sp1ChildClient.OnReceivedChatMessage + sp1ChildClient.OnReceivedChatMessage += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp1ChatMessage = message; - sp2ChildClient.OnReceivedChatMessage + sp2ChildClient.OnReceivedChatMessage += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp2ChatMessage = message; TestUserInRange(sp1Client, "ello darling", ref receivedSp2ChatMessage); @@ -166,11 +167,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests sp1Position = new Vector3(30, 128, 20); sp1.AbsolutePosition = sp1Position; + sceneWest.Update(1); sceneEast.Update(1); + Thread.Sleep(12000); // child updates are now time limited + sceneWest.Update(5); + sceneEast.Update(5); // Check child position is correct. Assert.AreEqual( - new Vector3(sp1Position.X + sceneEast.RegionInfo.RegionSizeX, sp1Position.Y, sp1Position.Z), + new Vector3(sp1Position.X + sceneEast.RegionInfo.RegionSizeX, sp1Position.Y, sp1Position.Z), sp1ChildClient.SceneAgent.AbsolutePosition); TestUserOutOfRange(sp1Client, "beef", ref receivedSp2ChatMessage); @@ -197,8 +202,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests Vector3 sp2Position = new Vector3(128, 6, 20); SceneHelpers sh = new SceneHelpers(); - TestScene sceneNorth = sh.SetupScene("sceneNorth", TestHelpers.ParseTail(0x1), 1000, 1000); - TestScene sceneSouth = sh.SetupScene("sceneSouth", TestHelpers.ParseTail(0x2), 1000, 1001); + TestScene sceneNorth = sh.SetupScene("sceneNorth", TestHelpers.ParseTail(0x1), 1000, 1000); + TestScene sceneSouth = sh.SetupScene("sceneSouth", TestHelpers.ParseTail(0x2), 1000, 1001); SetupNeighbourRegions(sceneNorth, sceneSouth); @@ -210,12 +215,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests // physics is irrelevant to this test. sp1.Flying = true; - // When sp1 logs in to sceneEast, it sets up a child agent in sceneNorth and informs the sp2 client to + // When sp1 logs in to sceneEast, it sets up a child agent in sceneNorth and informs the sp2 client to // make the connection. For this test, will simplify this chain by making the connection directly. ScenePresence sp1Child = SceneHelpers.AddChildScenePresence(sceneSouth, sp1Uuid); TestClient sp1ChildClient = (TestClient)sp1Child.ControllingClient; - sp1.AbsolutePosition = sp1Position; + sp1.AbsolutePosition = sp1Position; ScenePresence sp2 = SceneHelpers.AddScenePresence(sceneSouth, sp2Uuid); TestClient sp2Client = (TestClient)sp2.ControllingClient; @@ -224,7 +229,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests ScenePresence sp2Child = SceneHelpers.AddChildScenePresence(sceneNorth, sp2Uuid); TestClient sp2ChildClient = (TestClient)sp2Child.ControllingClient; - sp2.AbsolutePosition = sp2Position; + sp2.AbsolutePosition = sp2Position; // We must update the scenes in order to make the root new root agents trigger position updates in their // children. @@ -233,19 +238,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests // Check child positions are correct. Assert.AreEqual( - new Vector3(sp1Position.X, sp1Position.Y - sceneNorth.RegionInfo.RegionSizeY, sp1Position.Z), + new Vector3(sp1Position.X, sp1Position.Y - sceneNorth.RegionInfo.RegionSizeY, sp1Position.Z), sp1ChildClient.SceneAgent.AbsolutePosition); Assert.AreEqual( - new Vector3(sp2Position.X, sp2Position.Y + sceneSouth.RegionInfo.RegionSizeY, sp2Position.Z), + new Vector3(sp2Position.X, sp2Position.Y + sceneSouth.RegionInfo.RegionSizeY, sp2Position.Z), sp2ChildClient.SceneAgent.AbsolutePosition); string receivedSp1ChatMessage = ""; string receivedSp2ChatMessage = ""; - sp1ChildClient.OnReceivedChatMessage + sp1ChildClient.OnReceivedChatMessage += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp1ChatMessage = message; - sp2ChildClient.OnReceivedChatMessage + sp2ChildClient.OnReceivedChatMessage += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp2ChatMessage = message; TestUserInRange(sp1Client, "ello darling", ref receivedSp2ChatMessage); @@ -254,16 +259,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests sp1Position = new Vector3(30, 128, 20); sp1.AbsolutePosition = sp1Position; sceneNorth.Update(1); + sceneSouth.Update(1); + Thread.Sleep(12000); // child updates are now time limited + sceneNorth.Update(5); + sceneSouth.Update(5); // Check child position is correct. Assert.AreEqual( - new Vector3(sp1Position.X, sp1Position.Y - sceneNorth.RegionInfo.RegionSizeY, sp1Position.Z), + new Vector3(sp1Position.X, sp1Position.Y - sceneNorth.RegionInfo.RegionSizeY, sp1Position.Z), sp1ChildClient.SceneAgent.AbsolutePosition); TestUserOutOfRange(sp1Client, "beef", ref receivedSp2ChatMessage); TestUserOutOfRange(sp2Client, "lentils", ref receivedSp1ChatMessage); } - + private void TestUserInRange(TestClient speakClient, string testMessage, ref string receivedMessage) { receivedMessage = ""; diff --git a/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs b/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs index fc23b72..4e1958a 100644 --- a/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs @@ -183,10 +183,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Combat.CombatModule try { ILandObject obj = avatar.Scene.LandChannel.GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); - if (obj == null) return; - if ((obj.LandData.Flags & (uint)ParcelFlags.AllowDamage) != 0 || avatar.Scene.RegionInfo.RegionSettings.AllowDamage) { diff --git a/OpenSim/Region/CoreModules/Avatar/Commands/UserCommandsModule.cs b/OpenSim/Region/CoreModules/Avatar/Commands/UserCommandsModule.cs index 764adf9..cf65c47 100644 --- a/OpenSim/Region/CoreModules/Avatar/Commands/UserCommandsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Commands/UserCommandsModule.cs @@ -62,19 +62,19 @@ namespace OpenSim.Region.CoreModules.Avatars.Commands private Dictionary m_scenes = new Dictionary(); public string Name { get { return "User Commands Module"; } } - + public Type ReplaceableInterface { get { return null; } } - + public void Initialise(IConfigSource source) { // m_log.DebugFormat("[USER COMMANDS MODULE]: INITIALIZED MODULE"); } - + public void PostInitialise() { // m_log.DebugFormat("[USER COMMANDS MODULE]: POST INITIALIZED MODULE"); } - + public void Close() { // m_log.DebugFormat("[USER COMMANDS MODULE]: CLOSED MODULE"); diff --git a/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs b/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs index a896897..56819fa 100644 --- a/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs @@ -203,8 +203,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Dialog { m_scene.ForEachRootClient(delegate(IClientAPI client) { - client.SendBlueBoxMessage(fromAvatarID, fromAvatarName, - message); + client.SendAgentAlertMessage( + message, false); }); } @@ -260,4 +260,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Dialog return result; } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs index eb23e83..4a55a7e 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs @@ -118,7 +118,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends // If we're in god mode, we reverse the meaning. Offer // calling card becomes "Take a calling card" for that // person, no matter if they agree or not. - if (sp.GodLevel >= 200) + if (sp.IsViewerUIGod) { CreateCallingCard(client.AgentId, destID, UUID.Zero, true); return; @@ -239,8 +239,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends InventoryFolderBase trashFolder = invService.GetFolderForType(client.AgentId, FolderType.Trash); - InventoryItemBase item = new InventoryItemBase(transactionID, client.AgentId); - item = invService.GetItem(item); + InventoryItemBase item = invService.GetItem(client.AgentId, transactionID); if (item != null && trashFolder != null) { diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index 08e7dd2..772485c 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -167,7 +167,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends m_Enabled = true; m_log.DebugFormat("[FRIENDS MODULE]: {0} enabled.", Name); } - } + } } protected virtual void InitModule(IConfigSource config) @@ -247,14 +247,30 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends { FriendInfo[] friends = GetFriendsFromCache(principalID); FriendInfo finfo = GetFriend(friends, friendID); - if (finfo != null) + if (finfo != null && finfo.TheirFlags != -1) { return finfo.TheirFlags; } - return 0; } + private void OnMakeRootAgent(ScenePresence sp) + { + if(sp.gotCrossUpdate) + return; + + RecacheFriends(sp.ControllingClient); + + lock (m_NeedsToNotifyStatus) + { + if (m_NeedsToNotifyStatus.Remove(sp.UUID)) + { + // Inform the friends that this user is online. This can only be done once the client is a Root Agent. + StatusChange(sp.UUID, true); + } + } + } + private void OnNewClient(IClientAPI client) { client.OnInstantMessage += OnInstantMessage; @@ -262,6 +278,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends client.OnDenyFriendRequest += OnDenyFriendRequest; client.OnTerminateFriendship += RemoveFriendship; client.OnGrantUserRights += GrantRights; + client.OnFindAgent += FindFriend; // We need to cache information for child agents as well as root agents so that friend edit/move/delete // permissions will work across borders where both regions are on different simulators. @@ -326,20 +343,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends } } - private void OnMakeRootAgent(ScenePresence sp) - { - RecacheFriends(sp.ControllingClient); - - lock (m_NeedsToNotifyStatus) - { - if (m_NeedsToNotifyStatus.Remove(sp.UUID)) - { - // Inform the friends that this user is online. This can only be done once the client is a Root Agent. - StatusChange(sp.UUID, true); - } - } - } - private void OnClientLogin(IClientAPI client) { UUID agentID = client.AgentId; @@ -358,8 +361,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends m_NeedsListOfOnlineFriends.Add(agentID); } + public void IsNowRoot(ScenePresence sp) + { + OnMakeRootAgent(sp); + } + public virtual bool SendFriendsOnlineIfNeeded(IClientAPI client) { + if (client == null) + return false; + UUID agentID = client.AgentId; // Check if the online friends list is needed @@ -500,18 +511,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends if (((fi.MyFlags & (int)FriendRights.CanSeeOnline) != 0) && (fi.TheirFlags != -1)) friendList.Add(fi); } - - Util.FireAndForget( - delegate - { -// m_log.DebugFormat( -// "[FRIENDS MODULE]: Notifying {0} friends of {1} of online status {2}", -// friendList.Count, agentID, online); - - // Notify about this user status - StatusNotify(friendList, agentID, online); - }, null, "FriendsModule.StatusChange" - ); + if(friendList.Count > 0) + { + Util.FireAndForget( + delegate + { +// m_log.DebugFormat( +// "[FRIENDS MODULE]: Notifying {0} friends of {1} of online status {2}", +// friendList.Count, agentID, online); + + // Notify about this user status + StatusNotify(friendList, agentID, online); + }, null, "FriendsModule.StatusChange" + ); + } } } @@ -540,6 +553,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends // We do this regrouping so that we can efficiently send a single request rather than one for each // friend in what may be a very large friends list. PresenceInfo[] friendSessions = PresenceService.GetAgents(remoteFriendStringIds.ToArray()); + if(friendSessions == null) + return; foreach (PresenceInfo friendSession in friendSessions) { @@ -561,7 +576,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends protected virtual void OnInstantMessage(IClientAPI client, GridInstantMessage im) { if ((InstantMessageDialog)im.dialog == InstantMessageDialog.FriendshipOffered) - { + { // we got a friendship offer UUID principalID = new UUID(im.fromAgentID); UUID friendID = new UUID(im.toAgentID); @@ -596,7 +611,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends im.imSessionID = im.fromAgentID; im.fromAgentName = GetFriendshipRequesterName(agentID); - // Try the local sim + // Try the local sim if (LocalFriendshipOffered(friendID, im)) return true; @@ -639,7 +654,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends ccm.CreateCallingCard(client.AgentId, friendID, UUID.Zero); } - // Update the local cache. + // Update the local cache. RecacheFriends(client); // @@ -695,7 +710,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends } } } - + public void RemoveFriendship(IClientAPI client, UUID exfriendID) { if (!DeleteFriendship(client.AgentId, exfriendID)) @@ -723,7 +738,65 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID); m_FriendsSimConnector.FriendshipTerminated(region, client.AgentId, exfriendID); } - } + } + } + + public void FindFriend(IClientAPI remoteClient,UUID HunterID ,UUID PreyID) + { + UUID requester = remoteClient.AgentId; + if(requester != HunterID) // only allow client agent to be the hunter (?) + return; + + FriendInfo[] friends = GetFriendsFromCache(requester); + if (friends.Length == 0) + return; + + FriendInfo friend = GetFriend(friends, PreyID); + if (friend == null) + return; + + if(friend.TheirFlags == -1 || (friend.TheirFlags & (int)FriendRights.CanSeeOnMap) == 0) + return; + + Scene hunterScene = (Scene)remoteClient.Scene; + + if(hunterScene == null) + return; + + // check local + ScenePresence sp; + double px; + double py; + if(hunterScene.TryGetScenePresence(PreyID, out sp)) + { + if(sp == null) + return; + px = hunterScene.RegionInfo.WorldLocX + sp.AbsolutePosition.X; + py = hunterScene.RegionInfo.WorldLocY + sp.AbsolutePosition.Y; + + remoteClient.SendFindAgent(HunterID, PreyID, px, py); + return; + } + + PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { PreyID.ToString() }); + + if (friendSessions == null || friendSessions.Length == 0) + return; + + PresenceInfo friendSession = friendSessions[0]; + if (friendSession == null) + return; + + GridRegion region = GridService.GetRegionByUUID(hunterScene.RegionInfo.ScopeID, friendSession.RegionID); + + if(region == null) + return; + + // we don't have presence location so point to a standard region center for now + px = region.RegionLocX + 128.0; + py = region.RegionLocY + 128.0; + + remoteClient.SendFindAgent(HunterID, PreyID, px, py); } public void GrantRights(IClientAPI remoteClient, UUID friendID, int rights) @@ -745,7 +818,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends if (friend != null) // Found it { - // Store it on the DB + // Store it on service if (!StoreRights(requester, friendID, rights)) { remoteClient.SendAlertMessage("Unable to grant rights."); @@ -869,28 +942,26 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends return false; } - public bool LocalGrantRights(UUID userID, UUID friendID, int userFlags, int rights) + public bool LocalGrantRights(UUID userID, UUID friendID, int oldRights, int newRights) { IClientAPI friendClient = LocateClientObject(friendID); if (friendClient != null) { - bool onlineBitChanged = ((rights ^ userFlags) & (int)FriendRights.CanSeeOnline) != 0; + int changedRights = newRights ^ oldRights; + bool onlineBitChanged = (changedRights & (int)FriendRights.CanSeeOnline) != 0; if (onlineBitChanged) { - if ((rights & (int)FriendRights.CanSeeOnline) == 1) + if ((newRights & (int)FriendRights.CanSeeOnline) == 1) friendClient.SendAgentOnline(new UUID[] { userID }); else friendClient.SendAgentOffline(new UUID[] { userID }); } - else - { - bool canEditObjectsChanged = ((rights ^ userFlags) & (int)FriendRights.CanModifyObjects) != 0; - if (canEditObjectsChanged) - friendClient.SendChangeUserRights(userID, friendID, rights); - } + + if(changedRights != 0) + friendClient.SendChangeUserRights(userID, friendID, newRights); // Update local cache - UpdateLocalCache(userID, friendID, rights); + UpdateLocalCache(userID, friendID, newRights); return true; } @@ -946,8 +1017,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends lock (m_Friends) { FriendInfo[] friends = GetFriendsFromCache(friendID); - FriendInfo finfo = GetFriend(friends, userID); - finfo.TheirFlags = rights; + if(friends != EMPTY_FRIENDS) + { + FriendInfo finfo = GetFriend(friends, userID); + if(finfo!= null) + finfo.TheirFlags = rights; + } } } diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs index 13512a2..091b197 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs @@ -65,9 +65,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends protected override byte[] ProcessRequest( string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { - StreamReader sr = new StreamReader(requestData); - string body = sr.ReadToEnd(); - sr.Close(); + string body; + using(StreamReader sr = new StreamReader(requestData)) + body = sr.ReadToEnd(); + body = body.Trim(); //m_log.DebugFormat("[XXX]: query String: {0}", body); @@ -127,7 +128,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends UserAccount account = m_FriendsModule.UserAccountService.GetUserAccount(UUID.Zero, fromID); string name = (account == null) ? "Unknown" : account.FirstName + " " + account.LastName; - GridInstantMessage im = new GridInstantMessage(m_FriendsModule.Scene, fromID, name, toID, + GridInstantMessage im = new GridInstantMessage(m_FriendsModule.Scene, fromID, name, toID, (byte)InstantMessageDialog.FriendshipOffered, message, false, Vector3.Zero); // !! HACK @@ -211,7 +212,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends { UUID fromID = UUID.Zero; UUID toID = UUID.Zero; - int rights = 0, userFlags = 0; + int oldRights = 0, newRights = 0; if (!request.ContainsKey("FromID") || !request.ContainsKey("ToID")) return FailureResult(); @@ -222,13 +223,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends if (!UUID.TryParse(request["ToID"].ToString(), out toID)) return FailureResult(); - if (!Int32.TryParse(request["UserFlags"].ToString(), out userFlags)) + if (!Int32.TryParse(request["UserFlags"].ToString(), out oldRights)) return FailureResult(); - if (!Int32.TryParse(request["Rights"].ToString(), out rights)) + if (!Int32.TryParse(request["Rights"].ToString(), out newRights)) return FailureResult(); - if (m_FriendsModule.LocalGrantRights(UUID.Zero, UUID.Zero, userFlags, rights)) + if (m_FriendsModule.LocalGrantRights(fromID, toID, oldRights, newRights)) return SuccessResult(); return FailureResult(); diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs index 27b7376..fae1e05 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs @@ -141,7 +141,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends if (avatar == null) return; - if (avatar.UserLevel < m_levelHGFriends) + if (avatar.GodController.UserLevel < m_levelHGFriends) { client.SendAgentAlertMessage("Unable to send friendship invitation to foreigner. Insufficient permissions.", false); return; @@ -214,7 +214,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends FriendInfo[] friends = GetFriendsFromCache(client.AgentId); foreach (FriendInfo f in friends) { - client.SendChangeUserRights(new UUID(f.Friend), client.AgentId, f.TheirFlags); + int rights = f.TheirFlags; + if(rights != -1 ) + client.SendChangeUserRights(new UUID(f.Friend), client.AgentId, rights); } } } @@ -337,7 +339,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends if (UUID.TryParse(friendID, out id)) return base.FriendshipMessage(friendID); - return "Please confirm this friendship you made while you were away."; + return "Please confirm this friendship you made while you where on another HG grid"; } protected override FriendInfo GetFriend(FriendInfo[] friends, UUID friendID) @@ -456,6 +458,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends { // local grid users m_log.DebugFormat("[HGFRIENDS MODULE]: Users are both local"); + DeletePreviousHGRelations(agentID, friendID); base.StoreFriendships(agentID, friendID); return; } @@ -538,8 +541,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends // m_log.DebugFormat("[HGFRIENDS MODULE] HG Friendship! thisUUI={0}; friendUUI={1}; foreignThisFriendService={2}; foreignFriendFriendService={3}", // agentUUI, friendUUI, agentFriendService, friendFriendService); - } - + } + // Delete any previous friendship relations DeletePreviousRelations(agentID, friendID); @@ -624,6 +627,45 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends } } + private void DeletePreviousHGRelations(UUID a1, UUID a2) + { + // Delete any previous friendship relations + FriendInfo[] finfos = null; + finfos = GetFriendsFromCache(a1); + if (finfos != null) + { + foreach (FriendInfo f in finfos) + { + if (f.TheirFlags == -1) + { + if (f.Friend.StartsWith(a2.ToString())) + { + FriendsService.Delete(a1, f.Friend); + // and also the converse + FriendsService.Delete(f.Friend, a1.ToString()); + } + } + } + } + + finfos = GetFriendsFromCache(a1); + if (finfos != null) + { + foreach (FriendInfo f in finfos) + { + if (f.TheirFlags == -1) + { + if (f.Friend.StartsWith(a1.ToString())) + { + FriendsService.Delete(a2, f.Friend); + // and also the converse + FriendsService.Delete(f.Friend, a2.ToString()); + } + } + } + } + } + protected override bool DeleteFriendship(UUID agentID, UUID exfriendID) { Boolean agentIsLocal = true; @@ -743,7 +785,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends m_log.DebugFormat("[HGFRIENDS MODULE]: Forwading friendship from {0} to {1} @ {2}", agentID, friendID, friendsURL); GridRegion region = new GridRegion(); region.ServerURI = friendsURL; - + string name = im.fromAgentName; if (m_uMan.IsLocalGridUser(agentID)) { @@ -775,7 +817,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends } m_HGFriendsConnector.FriendshipOffered(region, agentID, friendID, im.message, name); - + return true; } } @@ -804,4 +846,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends return false; } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGStatusNotifier.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGStatusNotifier.cs index 1fa4dd6..3fae271 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/HGStatusNotifier.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGStatusNotifier.cs @@ -32,7 +32,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends { if (kvp.Key != "local") { - // For the others, call the user agent service + // For the others, call the user agent service List ids = new List(); foreach (FriendInfo f in kvp.Value) ids.Add(f.Friend); diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs index e6fd54e..3d9bd35 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs @@ -67,7 +67,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests // so that different services and simulator can share the data in standalone mode. This is pretty horrible // effectively the statics are global variables. NullFriendsData.Clear(); - + IConfigSource config = new IniConfigSource(); config.AddConfig("Modules"); // Not strictly necessary since FriendsModule assumes it is the default (!) diff --git a/OpenSim/Region/CoreModules/Avatar/Gestures/GesturesModule.cs b/OpenSim/Region/CoreModules/Avatar/Gestures/GesturesModule.cs index 095c57b..03e2c5a 100644 --- a/OpenSim/Region/CoreModules/Avatar/Gestures/GesturesModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Gestures/GesturesModule.cs @@ -42,11 +42,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Gestures { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GesturesModule")] public class GesturesModule : INonSharedRegionModule - { + { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + protected Scene m_scene; - + public void Initialise(IConfigSource source) { } @@ -67,7 +67,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gestures m_scene.EventManager.OnNewClient -= OnNewClient; m_scene = null; } - + public void Close() {} public string Name { get { return "Gestures Module"; } } @@ -81,19 +81,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Gestures client.OnActivateGesture += ActivateGesture; client.OnDeactivateGesture += DeactivateGesture; } - + public virtual void ActivateGesture(IClientAPI client, UUID assetId, UUID gestureId) { IInventoryService invService = m_scene.InventoryService; - InventoryItemBase item = new InventoryItemBase(gestureId, client.AgentId); - item = invService.GetItem(item); + InventoryItemBase item = invService.GetItem(client.AgentId, gestureId); if (item != null) { item.Flags |= 1; invService.UpdateItem(item); } - else + else m_log.WarnFormat( "[GESTURES]: Unable to find gesture {0} to activate for {1}", gestureId, client.Name); } @@ -102,14 +101,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Gestures { IInventoryService invService = m_scene.InventoryService; - InventoryItemBase item = new InventoryItemBase(gestureId, client.AgentId); - item = invService.GetItem(item); + InventoryItemBase item = invService.GetItem(client.AgentId, gestureId); if (item != null) { item.Flags &= ~(uint)1; invService.UpdateItem(item); } - else + else m_log.ErrorFormat( "[GESTURES]: Unable to find gesture to deactivate {0} for {1}", gestureId, client.Name); } diff --git a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs index 3b6d970..6e6974a 100644 --- a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs @@ -59,19 +59,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods /// Special UUID for actions that apply to all agents private static readonly UUID ALL_AGENTS = new UUID("44e87126-e794-4ded-05b3-7c42da3d5cdb"); + private static readonly UUID UUID_GRID_GOD = new UUID("6571e388-6218-4574-87db-f9379718315e"); protected Scene m_scene; protected IDialogModule m_dialogModule; - protected IDialogModule DialogModule - { - get - { - if (m_dialogModule == null) - m_dialogModule = m_scene.RequestModuleInterface(); - - return m_dialogModule; - } - } public void Initialise(IConfigSource source) { @@ -96,6 +87,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods public void RegionLoaded(Scene scene) { + m_dialogModule = m_scene.RequestModuleInterface(); } public void Close() {} @@ -111,19 +103,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods client.OnGodKickUser += KickUser; client.OnRequestGodlikePowers += RequestGodlikePowers; } - + public void UnsubscribeFromClientEvents(IClientAPI client) { client.OnGodKickUser -= KickUser; client.OnRequestGodlikePowers -= RequestGodlikePowers; } - + private void OnRegisterCaps(UUID agentID, Caps caps) { string uri = "/CAPS/" + UUID.Random(); caps.RegisterHandler( - "UntrustedSimulatorMessage", + "UntrustedSimulatorMessage", new RestStreamHandler("POST", uri, HandleUntrustedSimulatorMessage, "UntrustedSimulatorMessage", null)); } @@ -146,11 +138,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods UUID godSessionID = userData["GodSessionID"].AsUUID(); uint kickFlags = userData["KickFlags"].AsUInteger(); string reason = userData["Reason"].AsString(); + ScenePresence god = m_scene.GetScenePresence(godID); if (god == null || god.ControllingClient.SessionId != godSessionID) return String.Empty; - KickUser(godID, godSessionID, agentID, kickFlags, Util.StringToBytes1024(reason)); + KickUser(godID, agentID, kickFlags, reason); } else { @@ -160,59 +153,63 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods } public void RequestGodlikePowers( - UUID agentID, UUID sessionID, UUID token, bool godLike, IClientAPI controllingClient) + UUID agentID, UUID sessionID, UUID token, bool godLike) { ScenePresence sp = m_scene.GetScenePresence(agentID); + if(sp == null || sp.IsDeleted || sp.IsNPC) + return; - if (sp != null) - { - if (godLike == false) - { - sp.GrantGodlikePowers(agentID, sessionID, token, godLike); - return; - } + if (sessionID != sp.ControllingClient.SessionId) + return; - // First check that this is the sim owner - if (m_scene.Permissions.IsGod(agentID)) - { - // Next we check for spoofing..... - UUID testSessionID = sp.ControllingClient.SessionId; - if (sessionID == testSessionID) - { - if (sessionID == controllingClient.SessionId) - { - //m_log.Info("godlike: " + godLike.ToString()); - sp.GrantGodlikePowers(agentID, testSessionID, token, godLike); - } - } - } - else - { - if (DialogModule != null) - DialogModule.SendAlertToUser(agentID, "Request for god powers denied"); - } - } + sp.GrantGodlikePowers(token, godLike); + + if (godLike && !sp.IsViewerUIGod && m_dialogModule != null) + m_dialogModule.SendAlertToUser(agentID, "Request for god powers denied"); } - + + public void KickUser(UUID godID, UUID agentID, uint kickflags, byte[] reason) + { + KickUser(godID, agentID, kickflags, Utils.BytesToString(reason)); + } + /// - /// Kicks User specified from the simulator. This logs them off of the grid - /// If the client gets the UUID: 44e87126e7944ded05b37c42da3d5cdb it assumes - /// that you're kicking it even if the avatar's UUID isn't the UUID that the - /// agent is assigned + /// Kicks or freezes User specified from the simulator. This logs them off of the grid /// /// The person doing the kicking - /// The session of the person doing the kicking /// the person that is being kicked /// Tells what to do to the user /// The message to send to the user after it's been turned into a field - public void KickUser(UUID godID, UUID sessionID, UUID agentID, uint kickflags, byte[] reason) + public void KickUser(UUID godID, UUID agentID, uint kickflags, string reason) { - if (!m_scene.Permissions.IsGod(godID)) + // assuming automatic god rights on this for fast griefing reaction + // this is also needed for kick via message + if(!m_scene.Permissions.IsGod(godID)) return; - ScenePresence sp = m_scene.GetScenePresence(agentID); + int godlevel = 200; + // update level so higher gods can kick lower ones + ScenePresence god = m_scene.GetScenePresence(godID); + if(god != null && god.GodController.GodLevel > godlevel) + godlevel = god.GodController.GodLevel; + + if(agentID == ALL_AGENTS) + { + m_scene.ForEachRootScenePresence(delegate(ScenePresence p) + { + if (p.UUID != godID) + { + if(godlevel > p.GodController.GodLevel) + doKickmodes(godID, p, kickflags, reason); + else if(m_dialogModule != null) + m_dialogModule.SendAlertToUser(p.UUID, "Kick from " + godID.ToString() + " ignored, kick reason: " + reason); + } + }); + return; + } - if (sp == null && agentID != ALL_AGENTS) + ScenePresence sp = m_scene.GetScenePresence(agentID); + if (sp == null || sp.IsChildAgent) { IMessageTransferModule transferModule = m_scene.RequestModuleInterface(); @@ -221,58 +218,95 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods m_log.DebugFormat("[GODS]: Sending nonlocal kill for agent {0}", agentID); transferModule.SendInstantMessage(new GridInstantMessage( m_scene, godID, "God", agentID, (byte)250, false, - Utils.BytesToString(reason), UUID.Zero, true, + reason, UUID.Zero, true, new Vector3(), new byte[] {(byte)kickflags}, true), delegate(bool success) {} ); } return; } + if (godlevel <= sp.GodController.GodLevel) // no god wars + { + if(m_dialogModule != null) + m_dialogModule.SendAlertToUser(sp.UUID, "Kick from " + godID.ToString() + " ignored, kick reason: " + reason); + return; + } + + if(sp.UUID == godID) + return; + + doKickmodes(godID, sp, kickflags, reason); + } + + private void doKickmodes(UUID godID, ScenePresence sp, uint kickflags, string reason) + { switch (kickflags) { - case 0: - if (sp != null) - { - KickPresence(sp, Utils.BytesToString(reason)); - } - else if (agentID == ALL_AGENTS) - { - m_scene.ForEachRootScenePresence( - delegate(ScenePresence p) - { - if (p.UUID != godID && (!m_scene.Permissions.IsGod(p.UUID))) - KickPresence(p, Utils.BytesToString(reason)); - } - ); - } - break; - case 1: - if (sp != null) - { + case 0: + KickPresence(sp, reason); + break; + case 1: sp.AllowMovement = false; - m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason)); - m_dialogModule.SendAlertToUser(godID, "User Frozen"); - } - break; - case 2: - if (sp != null) - { + if(m_dialogModule != null) + { + m_dialogModule.SendAlertToUser(sp.UUID, reason); + m_dialogModule.SendAlertToUser(godID, "User Frozen"); + } + break; + case 2: sp.AllowMovement = true; - m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason)); - m_dialogModule.SendAlertToUser(godID, "User Unfrozen"); - } - break; - default: - break; + if(m_dialogModule != null) + { + m_dialogModule.SendAlertToUser(sp.UUID, reason); + m_dialogModule.SendAlertToUser(godID, "User Unfrozen"); + } + break; + default: + break; } } private void KickPresence(ScenePresence sp, string reason) { - if (sp.IsChildAgent) + if(sp.IsDeleted || sp.IsChildAgent) + return; + sp.ControllingClient.Kick(reason); + sp.Scene.CloseAgent(sp.UUID, true); + } + + public void GridKickUser(UUID agentID, string reason) + { + int godlevel = 240; // grid god default + + ScenePresence sp = m_scene.GetScenePresence(agentID); + if (sp == null || sp.IsChildAgent) + { + IMessageTransferModule transferModule = + m_scene.RequestModuleInterface(); + if (transferModule != null) + { + m_log.DebugFormat("[GODS]: Sending nonlocal kill for agent {0}", agentID); + transferModule.SendInstantMessage(new GridInstantMessage( + m_scene, UUID_GRID_GOD, "GRID", agentID, (byte)250, false, + reason, UUID.Zero, true, + new Vector3(), new byte[] {0}, true), + delegate(bool success) {} ); + } + return; + } + + if(sp.IsDeleted) + return; + + if (godlevel <= sp.GodController.GodLevel) // no god wars + { + if(m_dialogModule != null) + m_dialogModule.SendAlertToUser(sp.UUID, "GRID kick detected and ignored, kick reason: " + reason); return; + } + sp.ControllingClient.Kick(reason); - sp.Scene.CloseAgent(sp.UUID, true); + sp.Scene.CloseAgent(sp.UUID, true); } private void OnIncomingInstantMessage(GridInstantMessage msg) @@ -284,7 +318,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods UUID godID = new UUID(msg.fromAgentID); uint kickMode = (uint)msg.binaryBucket[0]; - KickUser(godID, UUID.Zero, agentID, kickMode, Util.StringToBytes1024(reason)); + if(godID == UUID_GRID_GOD) + GridKickUser(agentID, reason); + else + KickUser(godID, agentID, kickMode, reason); } } } diff --git a/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs b/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs index b735c61..7f91a61 100644 --- a/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs @@ -145,7 +145,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Groups return; // m_log.Debug("[GROUPS]: Shutting down group module."); - + lock (m_ClientMap) { m_ClientMap.Clear(); @@ -182,11 +182,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Groups m_ClientMap.Add(client.AgentId, client); } } - - GroupMembershipData[] updateGroups = new GroupMembershipData[1]; - updateGroups[0] = osGroup; - - client.SendGroupMembership(updateGroups); } private void OnAgentDataUpdateRequest(IClientAPI remoteClient, @@ -237,6 +232,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Groups remote_client.SendGroupNameReply(groupUUID, groupnamereply); } + public GroupMembershipData[] GetMembershipData(UUID agentID) + { + GroupMembershipData[] updateGroups = new GroupMembershipData[1]; + updateGroups[0] = osGroup; + return updateGroups; + } + + public GroupMembershipData GetActiveMembershipData(UUID agentID) + { + return osGroup; + } + private void OnClientClosed(UUID agentID, Scene scene) { lock (m_ClientMap) diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs index a1b918a..16e2ec3 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs @@ -144,11 +144,11 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage foreach (Scene scene in m_Scenes) { // m_log.DebugFormat( -// "[HG INSTANT MESSAGE]: Looking for root agent {0} in {1}", +// "[HG INSTANT MESSAGE]: Looking for root agent {0} in {1}", // toAgentID.ToString(), scene.RegionInfo.RegionName); - ScenePresence sp = scene.GetScenePresence(toAgentID); - if (sp != null && !sp.IsChildAgent) - { + ScenePresence sp = scene.GetScenePresence(toAgentID); + if (sp != null && !sp.IsChildAgent && !sp.IsDeleted) + { // Local message // m_log.DebugFormat("[HG INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", user.Name, toAgentID); sp.ControllingClient.SendInstantMessage(im); @@ -159,25 +159,6 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage } } - // try child avatar second - foreach (Scene scene in m_Scenes) - { -// m_log.DebugFormat( -// "[HG INSTANT MESSAGE]: Looking for child of {0} in {1}", -// toAgentID, scene.RegionInfo.RegionName); - ScenePresence sp = scene.GetScenePresence(toAgentID); - if (sp != null) - { - // Local message -// m_log.DebugFormat("[HG INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", user.Name, toAgentID); - sp.ControllingClient.SendInstantMessage(im); - - // Message sent - result(true); - return; - } - } - // m_log.DebugFormat("[HG INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID); // Is the user a local user? string url = string.Empty; @@ -224,7 +205,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage foreach (Scene scene in m_Scenes) { ScenePresence sp = scene.GetScenePresence(toAgentID); - if(sp != null && !sp.IsChildAgent) + if(sp != null && !sp.IsChildAgent && !sp.IsDeleted) { scene.EventManager.TriggerIncomingInstantMessage(gim); successful = true; @@ -310,7 +291,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage foreach (Scene scene in m_Scenes) { ScenePresence presence = scene.GetScenePresence(agentID); - if (presence != null && !presence.IsChildAgent) + if (presence != null && !presence.IsChildAgent && !presence.IsDeleted) return presence.ControllingClient; } } diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs index c33a296..71c0a8a 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; using System.Reflection; +using System.Timers; using log4net; using Mono.Addins; using Nini.Config; @@ -47,15 +48,15 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage /// /// Is this module enabled? /// - private bool m_enabled = false; - - private readonly List m_scenes = new List(); + protected bool m_enabled = false; + + protected readonly List m_scenes = new List(); #region Region Module interface - private IMessageTransferModule m_TransferModule = null; + protected IMessageTransferModule m_TransferModule = null; - public void Initialise(IConfigSource config) + public virtual void Initialise(IConfigSource config) { if (config.Configs["Messaging"] != null) { @@ -64,11 +65,11 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage "InstantMessageModule") return; } - + m_enabled = true; } - public void AddRegion(Scene scene) + public virtual void AddRegion(Scene scene) { if (!m_enabled) return; @@ -84,7 +85,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage } } - public void RegionLoaded(Scene scene) + public virtual void RegionLoaded(Scene scene) { if (!m_enabled) return; @@ -106,7 +107,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage } } - public void RemoveRegion(Scene scene) + public virtual void RemoveRegion(Scene scene) { if (!m_enabled) return; @@ -117,7 +118,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage } } - void OnClientConnect(IClientCore client) + protected virtual void OnClientConnect(IClientCore client) { IClientIM clientIM; if (client.TryGet(out clientIM)) @@ -126,27 +127,33 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage } } - public void PostInitialise() + public virtual void PostInitialise() { } - public void Close() + public virtual void Close() { } - public string Name + public virtual string Name { get { return "InstantMessageModule"; } } - public Type ReplaceableInterface + public virtual Type ReplaceableInterface { get { return null; } } #endregion - - public void OnInstantMessage(IClientAPI client, GridInstantMessage im) +/* + public virtual void OnViewerInstantMessage(IClientAPI client, GridInstantMessage im) + { + im.fromAgentName = client.FirstName + " " + client.LastName; + OnInstantMessage(client, im); + } +*/ + public virtual void OnInstantMessage(IClientAPI client, GridInstantMessage im) { byte dialog = im.dialog; @@ -159,10 +166,34 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage return; } + //DateTime dt = DateTime.UtcNow; + + // Ticks from UtcNow, but make it look like local. Evil, huh? + //dt = DateTime.SpecifyKind(dt, DateTimeKind.Local); + + //try + //{ + // // Convert that to the PST timezone + // TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles"); + // dt = TimeZoneInfo.ConvertTime(dt, timeZoneInfo); + //} + //catch + //{ + // //m_log.Info("[OFFLINE MESSAGING]: No PST timezone found on this machine. Saving with local timestamp."); + //} + + //// And make it look local again to fool the unix time util + //dt = DateTime.SpecifyKind(dt, DateTimeKind.Utc); + + // If client is null, this message comes from storage and IS offline + if (client != null) + im.offline = 0; + + if (im.offline == 0) + im.timestamp = (uint)Util.UnixTimeSinceEpoch(); + if (m_TransferModule != null) { - if (client != null) - im.fromAgentName = client.FirstName + " " + client.LastName; m_TransferModule.SendInstantMessage(im, delegate(bool success) { @@ -193,7 +224,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage /// /// /// - private void OnGridInstantMessage(GridInstantMessage msg) + protected virtual void OnGridInstantMessage(GridInstantMessage msg) { // Just call the Text IM handler above // This event won't be raised unless we have that agent, diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs index 2462ff8..efb9421 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs @@ -50,6 +50,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private bool m_Enabled = false; + protected string m_MessageKey = String.Empty; protected List m_Scenes = new List(); protected Dictionary m_UserRegionMap = new Dictionary(); @@ -69,14 +70,17 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage public virtual void Initialise(IConfigSource config) { IConfig cnf = config.Configs["Messaging"]; - if (cnf != null && cnf.GetString( - "MessageTransferModule", "MessageTransferModule") != - "MessageTransferModule") + if (cnf != null) { - m_log.Debug("[MESSAGE TRANSFER]: Disabled by configuration"); - return; - } + if (cnf.GetString("MessageTransferModule", + "MessageTransferModule") != "MessageTransferModule") + { + return; + } + m_MessageKey = cnf.GetString("MessageKey", String.Empty); + } + m_log.Debug("[MESSAGE TRANSFER]: Module enabled"); m_Enabled = true; } @@ -135,53 +139,45 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage { UUID toAgentID = new UUID(im.toAgentID); + if (toAgentID == UUID.Zero) + return; + + IClientAPI client = null; + // Try root avatar only first foreach (Scene scene in m_Scenes) { -// m_log.DebugFormat( -// "[INSTANT MESSAGE]: Looking for root agent {0} in {1}", -// toAgentID.ToString(), scene.RegionInfo.RegionName); - ScenePresence sp = scene.GetScenePresence(toAgentID); - if (sp != null && !sp.IsChildAgent) + if (sp != null && !sp.IsDeleted && sp.ControllingClient.IsActive) { - // Local message -// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", sp.Name, toAgentID); - - sp.ControllingClient.SendInstantMessage(im); + // actualy don't send via child agents + // ims can be complex things, and not sure viewers will not mess up + if(sp.IsChildAgent) + continue; - // Message sent - result(true); - return; + client = sp.ControllingClient; + if(!sp.IsChildAgent) + break; } } - // try child avatar second - foreach (Scene scene in m_Scenes) + if(client != null) { -// m_log.DebugFormat( -// "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName); - - ScenePresence sp = scene.GetScenePresence(toAgentID); - if (sp != null) - { - // Local message -// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", sp.Name, toAgentID); + // Local message +// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", sp.Name, toAgentID); - sp.ControllingClient.SendInstantMessage(im); + client.SendInstantMessage(im); // Message sent - result(true); - return; - } + result(true); + return; } - // m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID); SendGridInstantMessageViaXMLRPC(im, result); } - public void HandleUndeliverableMessage(GridInstantMessage im, MessageResultNotification result) + public virtual void HandleUndeliverableMessage(GridInstantMessage im, MessageResultNotification result) { UndeliveredMessage handlerUndeliveredMessage = OnUndeliveredMessage; @@ -211,10 +207,10 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage protected virtual XmlRpcResponse processXMLRPCGridInstantMessage(XmlRpcRequest request, IPEndPoint remoteClient) { bool successful = false; - + // TODO: For now, as IMs seem to be a bit unreliable on OSGrid, catch all exception that // happen here and aren't caught and log them. - try + try { // various rational defaults UUID fromAgentID = UUID.Zero; @@ -236,7 +232,6 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage float pos_z = 0; //m_log.Info("Processing IM"); - Hashtable requestData = (Hashtable)request.Params[0]; // Check if it's got all the data if (requestData.ContainsKey("from_agent_id") @@ -249,6 +244,19 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage && requestData.ContainsKey("position_z") && requestData.ContainsKey("region_id") && requestData.ContainsKey("binary_bucket")) { + if (m_MessageKey != String.Empty) + { + XmlRpcResponse error_resp = new XmlRpcResponse(); + Hashtable error_respdata = new Hashtable(); + error_respdata["success"] = "FALSE"; + error_resp.Value = error_respdata; + + if (!requestData.Contains("message_key")) + return error_resp; + if (m_MessageKey != (string)requestData["message_key"]) + return error_resp; + } + // Do the easy way of validating the UUIDs UUID.TryParse((string)requestData["from_agent_id"], out fromAgentID); UUID.TryParse((string)requestData["to_agent_id"], out toAgentID); @@ -382,7 +390,6 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage gim.Position = Position; gim.binaryBucket = binaryBucket; - // Trigger the Instant message in the scene. foreach (Scene scene in m_Scenes) { @@ -425,104 +432,191 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage return resp; } + /// /// delegate for sending a grid instant message asynchronously /// - public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result); + private delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result); + + private class GIM { + public GridInstantMessage im; + public MessageResultNotification result; + }; - protected virtual void GridInstantMessageCompleted(IAsyncResult iar) + private Queue pendingInstantMessages = new Queue(); + private int numInstantMessageThreads = 0; + + private void SendGridInstantMessageViaXMLRPC(GridInstantMessage im, MessageResultNotification result) { - GridInstantMessageDelegate icon = - (GridInstantMessageDelegate)iar.AsyncState; - icon.EndInvoke(iar); + lock (pendingInstantMessages) { + if (numInstantMessageThreads >= 4) { + GIM gim = new GIM(); + gim.im = im; + gim.result = result; + pendingInstantMessages.Enqueue(gim); + } else { + ++ numInstantMessageThreads; + //m_log.DebugFormat("[SendGridInstantMessageViaXMLRPC]: ++numInstantMessageThreads={0}", numInstantMessageThreads); + GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsyncMain; + d.BeginInvoke(im, result, GridInstantMessageCompleted, d); + } + } } - protected virtual void SendGridInstantMessageViaXMLRPC(GridInstantMessage im, MessageResultNotification result) + private void GridInstantMessageCompleted(IAsyncResult iar) { - GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync; - - d.BeginInvoke(im, result, GridInstantMessageCompleted, d); + GridInstantMessageDelegate d = (GridInstantMessageDelegate)iar.AsyncState; + d.EndInvoke(iar); } /// /// Internal SendGridInstantMessage over XMLRPC method. /// - /// - /// This is called from within a dedicated thread. - /// - private void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result) + + /// + /// Pass in 0 the first time this method is called. It will be called recursively with the last + /// regionhandle tried + /// + private void SendGridInstantMessageViaXMLRPCAsyncMain(GridInstantMessage im, MessageResultNotification result) + { + GIM gim; + do { + try { + SendGridInstantMessageViaXMLRPCAsync(im, result, UUID.Zero); + } catch (Exception e) { + m_log.Error("[SendGridInstantMessageViaXMLRPC]: exception " + e.Message); + } + lock (pendingInstantMessages) { + if (pendingInstantMessages.Count > 0) { + gim = pendingInstantMessages.Dequeue(); + im = gim.im; + result = gim.result; + } else { + gim = null; + -- numInstantMessageThreads; + //m_log.DebugFormat("[SendGridInstantMessageViaXMLRPC]: --numInstantMessageThreads={0}", numInstantMessageThreads); + } + } + } while (gim != null); + } + + private void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID) { + UUID toAgentID = new UUID(im.toAgentID); - UUID regionID; - bool needToLookupAgent; + PresenceInfo upd = null; + bool lookupAgent = false; lock (m_UserRegionMap) - needToLookupAgent = !m_UserRegionMap.TryGetValue(toAgentID, out regionID); - - while (true) { - if (needToLookupAgent) + if (m_UserRegionMap.ContainsKey(toAgentID)) { - PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() }); - - UUID foundRegionID = UUID.Zero; + upd = new PresenceInfo(); + upd.RegionID = m_UserRegionMap[toAgentID]; - if (presences != null) + // We need to compare the current regionhandle with the previous region handle + // or the recursive loop will never end because it will never try to lookup the agent again + if (prevRegionID == upd.RegionID) { - foreach (PresenceInfo p in presences) - { - if (p.RegionID != UUID.Zero) - { - foundRegionID = p.RegionID; - break; - } - } + lookupAgent = true; } - - // If not found or the found region is the same as the last lookup, then message is undeliverable - if (foundRegionID == UUID.Zero || foundRegionID == regionID) - break; - else - regionID = foundRegionID; } - - GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, regionID); - if (reginfo == null) + else { - m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", regionID); - break; + lookupAgent = true; } + } - // Try to send the message to the agent via the retrieved region. - Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im); - msgdata["region_handle"] = 0; - bool imresult = doIMSending(reginfo, msgdata); - // If the message delivery was successful, then cache the entry. - if (imresult) + // Are we needing to look-up an agent? + if (lookupAgent) + { + // Non-cached user agent lookup. + PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() }); + if (presences != null && presences.Length > 0) { - lock (m_UserRegionMap) + foreach (PresenceInfo p in presences) { - m_UserRegionMap[toAgentID] = regionID; + if (p.RegionID != UUID.Zero) + { + upd = p; + break; + } } - result(true); - return; } - // If we reach this point in the first iteration of the while, then we may have unsuccessfully tried - // to use a locally cached region ID. All subsequent attempts need to lookup agent details from - // the presence service. - needToLookupAgent = true; + if (upd != null) + { + // check if we've tried this before.. + // This is one way to end the recursive loop + // + if (upd.RegionID == prevRegionID) + { + // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); + HandleUndeliverableMessage(im, result); + return; + } + } + else + { + // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); + HandleUndeliverableMessage(im, result); + return; + } } - // If we reached this point then the message was not deliverable. Remove the bad cache entry and - // signal the delivery failure. - lock (m_UserRegionMap) - m_UserRegionMap.Remove(toAgentID); + if (upd != null) + { + GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(UUID.Zero, + upd.RegionID); + if (reginfo != null) + { + Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im); + // Not actually used anymore, left in for compatibility + // Remove at next interface change + // + msgdata["region_handle"] = 0; + bool imresult = doIMSending(reginfo, msgdata); + if (imresult) + { + // IM delivery successful, so store the Agent's location in our local cache. + lock (m_UserRegionMap) + { + if (m_UserRegionMap.ContainsKey(toAgentID)) + { + m_UserRegionMap[toAgentID] = upd.RegionID; + } + else + { + m_UserRegionMap.Add(toAgentID, upd.RegionID); + } + } + result(true); + } + else + { + // try again, but lookup user this time. + // Warning, this must call the Async version + // of this method or we'll be making thousands of threads + // The version within the spawned thread is SendGridInstantMessageViaXMLRPCAsync + // The version that spawns the thread is SendGridInstantMessageViaXMLRPC - // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); - HandleUndeliverableMessage(im, result); + // This is recursive!!!!! + SendGridInstantMessageViaXMLRPCAsync(im, result, + upd.RegionID); + } + } + else + { + m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", upd.RegionID); + HandleUndeliverableMessage(im, result); + } + } + else + { + HandleUndeliverableMessage(im, result); + } } /// @@ -622,8 +716,9 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage gim["position_z"] = msg.Position.Z.ToString(); gim["region_id"] = new UUID(msg.RegionID).ToString(); gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket,Base64FormattingOptions.None); + if (m_MessageKey != String.Empty) + gim["message_key"] = m_MessageKey; return gim; } - } } diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs index 315d372..2d57193 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs @@ -118,11 +118,11 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage { get { return null; } } - + public void Close() { } - + private void OnNewClient(IClientAPI client) { client.OnMuteListRequest += OnMuteListRequest; diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModuleTst.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModuleTst.cs new file mode 100644 index 0000000..6857f35 --- /dev/null +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModuleTst.cs @@ -0,0 +1,229 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 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 OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Client; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using Mono.Addins; + +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; + +namespace OpenSim.Region.CoreModules.Avatar.InstantMessage +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MuteListModuleTst")] + public class MuteListModuleTst : ISharedRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + protected bool m_Enabled = false; + protected List m_SceneList = new List(); + protected IMuteListService m_service = null; + + public void Initialise(IConfigSource config) + { + IConfig cnf = config.Configs["Messaging"]; + if (cnf == null) + return; + + if (cnf.GetString("MuteListModule", "None") != "MuteListModuleTst") + return; + + m_Enabled = true; + } + + public void AddRegion(Scene scene) + { + } + + public void RegionLoaded(Scene scene) + { + if (!m_Enabled) + return; + + IXfer xfer = scene.RequestModuleInterface(); + if (xfer == null) + { + m_log.ErrorFormat("[MuteListModuleTst]: Xfer not availble in region {0}. Module Disabled", scene.Name); + m_Enabled = false; + return; + } + + IMuteListService srv = scene.RequestModuleInterface(); + if(srv == null) + { + m_log.ErrorFormat("[MuteListModuleTst]: MuteListService not availble in region {0}. Module Disabled", scene.Name); + m_Enabled = false; + return; + } + lock (m_SceneList) + { + if(m_service == null) + m_service = srv; + m_SceneList.Add(scene); + scene.EventManager.OnNewClient += OnNewClient; + } + } + + public void RemoveRegion(Scene scene) + { + lock (m_SceneList) + { + if(m_SceneList.Contains(scene)) + { + m_SceneList.Remove(scene); + scene.EventManager.OnNewClient -= OnNewClient; + } + } + } + + public void PostInitialise() + { + if (!m_Enabled) + return; + + m_log.Debug("[MuteListModuleTst]: enabled"); + } + + public string Name + { + get { return "MuteListModuleTst"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void Close() + { + } + + private void OnNewClient(IClientAPI client) + { + client.OnMuteListRequest += OnMuteListRequest; + client.OnUpdateMuteListEntry += OnUpdateMuteListEntry; + client.OnRemoveMuteListEntry += OnRemoveMuteListEntry; + } + + private void OnMuteListRequest(IClientAPI client, uint crc) + { + if (!m_Enabled) + { + if(crc == 0) + client.SendEmpytMuteList(); + else + client.SendUseCachedMuteList(); + return; + } + + IXfer xfer = client.Scene.RequestModuleInterface(); + if (xfer == null) + { + if(crc == 0) + client.SendEmpytMuteList(); + else + client.SendUseCachedMuteList(); + return; + } + + Byte[] data = m_service.MuteListRequest(client.AgentId, crc); + if (data == null) + { + if(crc == 0) + client.SendEmpytMuteList(); + else + client.SendUseCachedMuteList(); + return; + } + + if (data.Length == 0) + { + client.SendEmpytMuteList(); + return; + } + + if (data.Length == 1) + { + if(crc == 0) + client.SendEmpytMuteList(); + else + client.SendUseCachedMuteList(); + return; + } + + string filename = "mutes" + client.AgentId.ToString(); + xfer.AddNewFile(filename, data); + client.SendMuteListUpdate(filename); + } + + private void OnUpdateMuteListEntry(IClientAPI client, UUID muteID, string muteName, int muteType, uint muteFlags) + { + if (!m_Enabled) + return; + + UUID agentID = client.AgentId; + if(muteType == 1) // agent + { + if(agentID == muteID) + return; + if(m_SceneList[0].Permissions.IsAdministrator(muteID)) + { + OnMuteListRequest(client, 0); + return; + } + } + + MuteData mute = new MuteData(); + mute.AgentID = agentID; + mute.MuteID = muteID; + mute.MuteName = muteName; + mute.MuteType = muteType; + mute.MuteFlags = (int)muteFlags; + mute.Stamp = Util.UnixTimeSinceEpoch(); + + m_service.UpdateMute(mute); + } + + private void OnRemoveMuteListEntry(IClientAPI client, UUID muteID, string muteName) + { + if (!m_Enabled) + return; + m_service.RemoveMute(client.AgentId, muteID, muteName); + } + } +} + diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs index 9cdb1c2..315ce1b 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs @@ -39,16 +39,25 @@ using OpenSim.Region.Framework.Scenes; namespace OpenSim.Region.CoreModules.Avatar.InstantMessage { + public struct SendReply + { + public bool Success; + public string Message; + public int Disposition; + } + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "OfflineMessageModule")] public class OfflineMessageModule : ISharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private bool enabled = true; + private bool m_UseNewAvnCode = false; private List m_SceneList = new List(); private string m_RestURL = String.Empty; IMessageTransferModule m_TransferModule = null; private bool m_ForwardOfflineGroupMessages = true; + private Dictionary> m_repliesSent= new Dictionary>(); public void Initialise(IConfigSource config) { @@ -74,6 +83,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage } m_ForwardOfflineGroupMessages = cnf.GetBoolean("ForwardOfflineGroupMessages", m_ForwardOfflineGroupMessages); + m_UseNewAvnCode = cnf.GetBoolean("UseNewAvnCode", m_UseNewAvnCode); } public void AddRegion(Scene scene) @@ -138,7 +148,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage { get { return null; } } - + public void Close() { } @@ -168,11 +178,21 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage private void OnNewClient(IClientAPI client) { client.OnRetrieveInstantMessages += RetrieveInstantMessages; + client.OnLogout += OnClientLoggedOut; + } + + public void OnClientLoggedOut(IClientAPI client) + { + m_repliesSent.Remove(client); } private void RetrieveInstantMessages(IClientAPI client) { - if (m_RestURL != "") + if (m_RestURL == String.Empty) + { + return; + } + else { m_log.DebugFormat("[OFFLINE MESSAGING]: Retrieving stored messages for {0}", client.AgentId); @@ -180,28 +200,28 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage = SynchronousRestObjectRequester.MakeRequest>( "POST", m_RestURL + "/RetrieveMessages/", client.AgentId); - if (msglist == null) - { - m_log.WarnFormat("[OFFLINE MESSAGING]: WARNING null message list."); - return; - } - - foreach (GridInstantMessage im in msglist) + if (msglist != null) { - if (im.dialog == (byte)InstantMessageDialog.InventoryOffered) - // send it directly or else the item will be given twice - client.SendInstantMessage(im); - else + foreach (GridInstantMessage im in msglist) { - // 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); + 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 + // + + im.offline = 1; + + Scene s = FindScene(client.AgentId); + if (s != null) + s.EventManager.TriggerIncomingInstantMessage(im); + } } } } @@ -213,7 +233,8 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage im.dialog != (byte)InstantMessageDialog.MessageFromAgent && im.dialog != (byte)InstantMessageDialog.GroupNotice && im.dialog != (byte)InstantMessageDialog.GroupInvitation && - im.dialog != (byte)InstantMessageDialog.InventoryOffered) + im.dialog != (byte)InstantMessageDialog.InventoryOffered && + im.dialog != (byte)InstantMessageDialog.TaskInventoryOffered) { return; } @@ -225,22 +246,73 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage return; } - bool success = SynchronousRestObjectRequester.MakeRequest( - "POST", m_RestURL+"/SaveMessage/", im, 10000); + if(m_UseNewAvnCode) + { + Scene scene = FindScene(new UUID(im.fromAgentID)); + if (scene == null) + scene = m_SceneList[0]; - if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent) + UUID scopeID = scene.RegionInfo.ScopeID; + SendReply reply = SynchronousRestObjectRequester.MakeRequest( + "POST", m_RestURL+"/SaveMessage/?scope=" + scopeID.ToString(), im, 20000); + + if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent) + { + IClientAPI client = FindClient(new UUID(im.fromAgentID)); + if (client == null) + return; + + if (string.IsNullOrEmpty(reply.Message)) + reply.Message = "User is not logged in. " + (reply.Success ? "Message saved." : "Message not saved"); + + bool sendReply = true; + + switch (reply.Disposition) + { + case 0: // Normal + break; + case 1: // Only once per user + if (m_repliesSent.ContainsKey(client) && m_repliesSent[client].Contains(new UUID(im.toAgentID))) + sendReply = false; + else + { + if (!m_repliesSent.ContainsKey(client)) + m_repliesSent[client] = new List(); + m_repliesSent[client].Add(new UUID(im.toAgentID)); + } + break; + } + + if (sendReply) + { + client.SendInstantMessage(new GridInstantMessage( + null, new UUID(im.toAgentID), + "System", new UUID(im.fromAgentID), + (byte)InstantMessageDialog.MessageFromAgent, + reply.Message, + false, new Vector3())); + } + } + } + else { - IClientAPI client = FindClient(new UUID(im.fromAgentID)); - if (client == null) - return; + bool success = SynchronousRestObjectRequester.MakeRequest( + "POST", m_RestURL+"/SaveMessage/", im, 20000); + + if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent) + { + IClientAPI client = FindClient(new UUID(im.fromAgentID)); + if (client == null) + return; - client.SendInstantMessage(new GridInstantMessage( + 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"), false, new Vector3())); + } } } } diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/XMuteModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/XMuteModule.cs new file mode 100644 index 0000000..b61e848 --- /dev/null +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/XMuteModule.cs @@ -0,0 +1,239 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 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 OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using Mono.Addins; +using OpenSim.Data.MySQL; +using MySql.Data.MySqlClient; + + +namespace OpenSim.Region.CoreModules.Avatar.InstantMessage +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XMute")] + public class XMuteModule : ISharedRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + protected bool m_Enabled = true; + protected List m_SceneList = new List(); + protected MuteTableHandler m_MuteTable; + protected string m_DatabaseConnect; + + public void Initialise(IConfigSource config) + { + IConfig cnf = config.Configs["Messaging"]; + if (cnf == null) + { + m_Enabled = false; + return; + } + + if (cnf.GetString("MuteListModule", "None") != + "XMute") + { + m_Enabled = false; + return; + } + + m_DatabaseConnect = cnf.GetString("MuteDatabaseConnect", String.Empty); + if (m_DatabaseConnect == String.Empty) + { + m_log.Debug("[XMute]: MuteDatabaseConnect missing or empty"); + m_Enabled = false; + return; + } + + m_MuteTable = new MuteTableHandler( + m_DatabaseConnect, "XMute", String.Empty); + } + + public void AddRegion(Scene scene) + { + if (!m_Enabled) + return; + + lock (m_SceneList) + { + m_SceneList.Add(scene); + + scene.EventManager.OnNewClient += OnNewClient; + } + } + + public void RegionLoaded(Scene scene) + { + } + + public void RemoveRegion(Scene scene) + { + if (!m_Enabled) + return; + + lock (m_SceneList) + { + m_SceneList.Remove(scene); + } + } + + public void PostInitialise() + { + if (!m_Enabled) + return; + + m_log.Debug("[XMute]: Mute list enabled"); + } + + public string Name + { + get { return "XMuteModule"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void Close() + { + } + + private void OnNewClient(IClientAPI client) + { + client.OnMuteListRequest += OnMuteListRequest; + client.OnUpdateMuteListEntry += OnUpdateMuteListEntry; + client.OnRemoveMuteListEntry += OnRemoveMuteListEntry; + } + + private void OnMuteListRequest(IClientAPI client, uint crc) + { + string filename = "mutes"+client.AgentId.ToString(); + + IXfer xfer = client.Scene.RequestModuleInterface(); + if (xfer != null) + { + MuteData[] data = m_MuteTable.Get("AgentID", client.AgentId.ToString()); + if (data == null || data.Length == 0) + { + xfer.AddNewFile(filename, new Byte[0]); + } + else + { + StringBuilder sb = new StringBuilder(1024); + + foreach (MuteData d in data) + sb.AppendFormat("{0} {1} {2}|{3}\n", + d.MuteType, + d.MuteID.ToString(), + d.MuteName, + d.MuteFlags); + + Byte[] filedata = Util.UTF8.GetBytes(sb.ToString()); + + uint dataCrc = Crc32.Compute(filedata); + + if (dataCrc == crc) + { + client.SendUseCachedMuteList(); + return; + } + + xfer.AddNewFile(filename, filedata); + } + + client.SendMuteListUpdate(filename); + } + } + + private void OnUpdateMuteListEntry(IClientAPI client, UUID muteID, string muteName, int muteType, uint muteFlags) + { + MuteData mute = new MuteData(); + + mute.AgentID = client.AgentId; + mute.MuteID = muteID; + mute.MuteName = muteName; + mute.MuteType = muteType; + mute.MuteFlags = (int)muteFlags; + mute.Stamp = Util.UnixTimeSinceEpoch(); + + m_MuteTable.Store(mute); + } + + private void OnRemoveMuteListEntry(IClientAPI client, UUID muteID, string muteName) + { + m_MuteTable.Delete(new string[] { "AgentID", + "MuteID", + "MuteName" }, + new string[] { client.AgentId.ToString(), + muteID.ToString(), + muteName }); + } + } + + public class MuteTableHandler : MySQLGenericTableHandler + { + public MuteTableHandler(string conn, string realm, string m) : base(conn, realm, m) + { + } + + public bool Delete(string[] fields, string[] val) + { + if (fields.Length != val.Length) + return false; + + using (MySqlCommand cmd = new MySqlCommand()) + { + string text = String.Format("delete from {0} where ", m_Realm); + + List terms = new List(); + + for (int i = 0 ; i < fields.Length ; i++) + { + terms.Add(String.Format("{0} = ?{0}", fields[i])); + cmd.Parameters.AddWithValue("?" + fields[i], val[i]); + } + + text += string.Join(" and ", terms.ToArray()); + + cmd.CommandText = text; + + if (ExecuteNonQuery(cmd) > 0) + return true; + return false; + } + } + } +} + diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs index 4a06fd1..1e21b74 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs @@ -56,7 +56,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// bumps here should be compatible. /// public static int MAX_MAJOR_VERSION = 1; - + protected TarArchiveReader archive; private UserAccount m_userInfo; @@ -66,7 +66,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// ID of this request /// protected UUID m_id; - + /// /// Do we want to merge this load with existing inventory? /// @@ -82,46 +82,49 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// The stream from which the inventory archive will be loaded. /// private Stream m_loadStream; - + /// /// Has the control file been loaded for this archive? /// public bool ControlFileLoaded { get; private set; } - + /// /// Do we want to enforce the check. IAR versions before 0.2 and 1.1 do not guarantee this order, so we can't /// enforce. /// public bool EnforceControlFileCheck { get; private set; } - + protected bool m_assetsLoaded; protected bool m_inventoryNodesLoaded; - + protected int m_successfulAssetRestores; protected int m_failedAssetRestores; - protected int m_successfulItemRestores; - + protected int m_successfulItemRestores; + /// /// Root destination folder for the IAR load. /// protected InventoryFolderBase m_rootDestinationFolder; - + /// /// Inventory nodes loaded from the iar. /// - protected HashSet m_loadedNodes = new HashSet(); - + protected Dictionary m_loadedNodes = new Dictionary(); + /// /// In order to load identically named folders, we need to keep track of the folders that we have already /// resolved. /// - Dictionary m_resolvedFolders = new Dictionary(); - + Dictionary m_resolvedFolders = new Dictionary(); + /// /// Record the creator id that should be associated with an asset. This is used to adjust asset creator ids /// after OSP resolution (since OSP creators are only stored in the item /// protected Dictionary m_creatorIdForAssetId = new Dictionary(); + protected Dictionary m_itemIDs = new Dictionary(); + protected List m_invLinks = new List(); + protected Dictionary m_invLinksFolders = new Dictionary(); public InventoryArchiveReadRequest( IInventoryService inv, IAssetService assets, IUserAccountService uacc, UserAccount userInfo, string invPath, string loadPath, bool merge) @@ -163,9 +166,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver m_invPath = invPath; m_loadStream = loadStream; m_module = module; - + // FIXME: Do not perform this check since older versions of OpenSim do save the control file after other things - // (I thought they weren't). We will need to bump the version number and perform this check on all + // (I thought they weren't). We will need to bump the version number and perform this check on all // subsequent IAR versions only ControlFileLoaded = true; } @@ -181,26 +184,26 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// returned /// /// Thrown if load fails. - public HashSet Execute() + public Dictionary Execute() { try { Exception reportedException = null; string filePath = "ERROR"; - + List folderCandidates = InventoryArchiveUtils.FindFoldersByPath( m_InventoryService, m_userInfo.PrincipalID, m_invPath); - + if (folderCandidates.Count == 0) { // Possibly provide an option later on to automatically create this folder if it does not exist m_log.ErrorFormat("[INVENTORY ARCHIVER]: Inventory path {0} does not exist", m_invPath); - + return m_loadedNodes; } - + m_rootDestinationFolder = folderCandidates[0]; archive = new TarArchiveReader(m_loadStream); byte[] data; @@ -211,7 +214,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver if (filePath == ArchiveConstants.CONTROL_FILE_PATH) { LoadControlFile(filePath, data); - } + } else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH)) { LoadAssetFile(filePath, data); @@ -221,17 +224,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver LoadInventoryFile(filePath, entryType, data); } } - + archive.Close(); + LoadInventoryLinks(); m_log.DebugFormat( - "[INVENTORY ARCHIVER]: Successfully loaded {0} assets with {1} failures", + "[INVENTORY ARCHIVER]: Successfully loaded {0} assets with {1} failures", m_successfulAssetRestores, m_failedAssetRestores); //Alicia: When this is called by LibraryModule or Tests, m_module will be null as event is not required if(m_module != null) m_module.TriggerInventoryArchiveLoaded(m_id, true, m_userInfo, m_invPath, m_loadStream, reportedException, m_successfulItemRestores); - + return m_loadedNodes; } catch(Exception Ex) @@ -268,36 +272,36 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// /// The last user inventory folder created or found for the archive path public InventoryFolderBase ReplicateArchivePathToUserInventory( - string iarPath, - InventoryFolderBase rootDestFolder, + string iarPath, + InventoryFolderBase rootDestFolder, Dictionary resolvedFolders, - HashSet loadedNodes) + Dictionary loadedNodes) { string iarPathExisting = iarPath; // m_log.DebugFormat( // "[INVENTORY ARCHIVER]: Loading folder {0} {1}", rootDestFolder.Name, rootDestFolder.ID); - - InventoryFolderBase destFolder + + InventoryFolderBase destFolder = ResolveDestinationFolder(rootDestFolder, ref iarPathExisting, resolvedFolders); - + // m_log.DebugFormat( -// "[INVENTORY ARCHIVER]: originalArchivePath [{0}], section already loaded [{1}]", +// "[INVENTORY ARCHIVER]: originalArchivePath [{0}], section already loaded [{1}]", // iarPath, iarPathExisting); - + string iarPathToCreate = iarPath.Substring(iarPathExisting.Length); CreateFoldersForPath(destFolder, iarPathExisting, iarPathToCreate, resolvedFolders, loadedNodes); - + return destFolder; } /// /// Resolve a destination folder /// - /// + /// /// We require here a root destination folder (usually the root of the user's inventory) and the archive /// path. We also pass in a list of previously resolved folders in case we've found this one previously. - /// + /// /// /// The item archive path to resolve. The portion of the path passed back is that /// which corresponds to the resolved desintation folder. @@ -321,7 +325,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver while (archivePath.Length > 0) { // m_log.DebugFormat("[INVENTORY ARCHIVER]: Trying to resolve destination folder {0}", archivePath); - + if (resolvedFolders.ContainsKey(archivePath)) { // m_log.DebugFormat( @@ -332,13 +336,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver { if (m_merge) { - // TODO: Using m_invPath is totally wrong - what we need to do is strip the uuid from the + // TODO: Using m_invPath is totally wrong - what we need to do is strip the uuid from the // iar name and try to find that instead. string plainPath = ArchiveConstants.ExtractPlainPathFromIarPath(archivePath); List folderCandidates = InventoryArchiveUtils.FindFoldersByPath( m_InventoryService, m_userInfo.PrincipalID, plainPath); - + if (folderCandidates.Count != 0) { InventoryFolderBase destFolder = folderCandidates[0]; @@ -346,7 +350,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver return destFolder; } } - + // Don't include the last slash so find the penultimate one int penultimateSlashIndex = archivePath.LastIndexOf("/", archivePath.Length - 2); @@ -365,10 +369,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver } } } - + return rootDestFolder; } - + /// /// Create a set of folders for the given path. /// @@ -388,11 +392,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// Track the inventory nodes created. /// protected void CreateFoldersForPath( - InventoryFolderBase destFolder, + InventoryFolderBase destFolder, string iarPathExisting, - string iarPathToReplicate, - Dictionary resolvedFolders, - HashSet loadedNodes) + string iarPathToReplicate, + Dictionary resolvedFolders, + Dictionary loadedNodes) { string[] rawDirsToCreate = iarPathToReplicate.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); @@ -402,7 +406,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver if (!rawDirsToCreate[i].Contains(ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR)) continue; - + int identicalNameIdentifierIndex = rawDirsToCreate[i].LastIndexOf( ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR); @@ -412,7 +416,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver newFolderName = InventoryArchiveUtils.UnescapeArchivePath(newFolderName); UUID newFolderId = UUID.Random(); - destFolder + destFolder = new InventoryFolderBase( newFolderId, newFolderName, m_userInfo.PrincipalID, (short)FolderType.None, destFolder.ID, 1); @@ -424,10 +428,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver resolvedFolders[iarPathExisting] = destFolder; if (0 == i) - loadedNodes.Add(destFolder); + loadedNodes[destFolder.ID] = destFolder; } } - + /// /// Load an item from the archive /// @@ -438,15 +442,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver protected InventoryItemBase LoadItem(byte[] data, InventoryFolderBase loadFolder) { InventoryItemBase item = UserInventoryItemSerializer.Deserialize(data); - + + UUID oldID = item.ID; // Don't use the item ID that's in the file item.ID = UUID.Random(); + m_itemIDs[oldID] = item.ID; UUID ospResolvedId = OspResolver.ResolveOspa(item.CreatorId, m_UserAccountService); if (UUID.Zero != ospResolvedId) // The user exists in this grid { // m_log.DebugFormat("[INVENTORY ARCHIVER]: Found creator {0} via OSPA resolution", ospResolvedId); - + // item.CreatorIdAsUuid = ospResolvedId; // Don't preserve the OSPA in the creator id (which actually gets persisted to the @@ -457,7 +463,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver else if (string.IsNullOrEmpty(item.CreatorData)) { item.CreatorId = m_userInfo.PrincipalID.ToString(); -// item.CreatorIdAsUuid = new UUID(item.CreatorId); } item.Owner = m_userInfo.PrincipalID; @@ -470,11 +475,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver // FIXME: This relies on the items coming before the assets in the TAR file. Need to create stronger // checks for this, and maybe even an external tool for creating OARs which enforces this, rather than // relying on native tar tools. - m_creatorIdForAssetId[item.AssetID] = item.CreatorIdAsUuid; + if(item.AssetType == (int)AssetType.Link) + { + m_invLinks.Add(item); + if(!m_loadedNodes.ContainsKey(item.Folder) && !m_invLinksFolders.ContainsKey(item.Folder)) + m_invLinksFolders[item.Folder] = loadFolder; + return null; + } + else + { + m_creatorIdForAssetId[item.AssetID] = item.CreatorIdAsUuid; + if (!m_InventoryService.AddItem(item)) + m_log.WarnFormat("[INVENTORY ARCHIVER]: Unable to save item {0} in folder {1}", item.Name, item.Folder); + } - if (!m_InventoryService.AddItem(item)) - m_log.WarnFormat("[INVENTORY ARCHIVER]: Unable to save item {0} in folder {1}", item.Name, item.Folder); - return item; } @@ -504,56 +518,57 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver string rawUuid = filename.Remove(filename.Length - extension.Length); UUID assetId = new UUID(rawUuid); - if (ArchiveConstants.EXTENSION_TO_ASSET_TYPE.ContainsKey(extension)) + if (!ArchiveConstants.EXTENSION_TO_ASSET_TYPE.ContainsKey(extension)) { - sbyte assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension]; + m_log.ErrorFormat( + "[INVENTORY ARCHIVER]: Tried to dearchive data with path {0} with an unknown type extension {1}", + assetPath, extension); + return false; + } - if (assetType == (sbyte)AssetType.Unknown) - { - m_log.WarnFormat("[INVENTORY ARCHIVER]: Importing {0} byte asset {1} with unknown type", data.Length, assetId); - } - else if (assetType == (sbyte)AssetType.Object) - { - if (m_creatorIdForAssetId.ContainsKey(assetId)) + sbyte assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension]; + if (assetType == (sbyte)AssetType.Unknown) + { + m_log.WarnFormat("[INVENTORY ARCHIVER]: Importing {0} byte asset {1} with unknown type", data.Length, assetId); + return false; + } + + if(assetType == (sbyte)AssetType.Object) + { + UUID owner = m_userInfo.PrincipalID; + bool doCreatorID = m_creatorIdForAssetId.ContainsKey(assetId); + + data = SceneObjectSerializer.ModifySerializedObject(assetId, data, + sog => { - data = SceneObjectSerializer.ModifySerializedObject(assetId, data, - sog => { - bool modified = false; - - foreach (SceneObjectPart sop in sog.Parts) - { - if (string.IsNullOrEmpty(sop.CreatorData)) - { - sop.CreatorID = m_creatorIdForAssetId[assetId]; - modified = true; - } - } - - return modified; - }); - - if (data == null) - return false; - } - } + foreach(SceneObjectPart sop in sog.Parts) + { + sop.OwnerID = owner; + if(doCreatorID && string.IsNullOrEmpty(sop.CreatorData)) + sop.CreatorID = m_creatorIdForAssetId[assetId]; + + foreach(TaskInventoryItem it in sop.Inventory.GetInventoryItems()) + { + it.OwnerID = owner; + if(string.IsNullOrEmpty(it.CreatorData) && m_creatorIdForAssetId.ContainsKey(it.AssetID)) + it.CreatorID = m_creatorIdForAssetId[it.AssetID]; + } + } + return true; + }); - //m_log.DebugFormat("[INVENTORY ARCHIVER]: Importing asset {0}, type {1}", uuid, assetType); + if(data == null) + return false; + } - AssetBase asset = new AssetBase(assetId, "From IAR", assetType, UUID.Zero.ToString()); - asset.Data = data; + //m_log.DebugFormat("[INVENTORY ARCHIVER]: Importing asset {0}, type {1}", uuid, assetType); - m_AssetService.Store(asset); + AssetBase asset = new AssetBase(assetId, "From IAR", assetType, UUID.Zero.ToString()); + asset.Data = data; - return true; - } - else - { - m_log.ErrorFormat( - "[INVENTORY ARCHIVER]: Tried to dearchive data with path {0} with an unknown type extension {1}", - assetPath, extension); + m_AssetService.Store(asset); - return false; - } + return true; } /// @@ -568,7 +583,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver int majorVersion = int.Parse(archiveElement.Attribute("major_version").Value); int minorVersion = int.Parse(archiveElement.Attribute("minor_version").Value); string version = string.Format("{0}.{1}", majorVersion, minorVersion); - + if (majorVersion > MAX_MAJOR_VERSION) { throw new Exception( @@ -576,38 +591,38 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver "The IAR you are trying to load has major version number of {0} but this version of OpenSim can only load IARs with major version number {1} and below", majorVersion, MAX_MAJOR_VERSION)); } - - ControlFileLoaded = true; - m_log.InfoFormat("[INVENTORY ARCHIVER]: Loading IAR with version {0}", version); + + ControlFileLoaded = true; + m_log.InfoFormat("[INVENTORY ARCHIVER]: Loading IAR with version {0}", version); } - + /// /// Load inventory file /// /// /// - /// + /// protected void LoadInventoryFile(string path, TarArchiveReader.TarEntryType entryType, byte[] data) { if (!ControlFileLoaded) throw new Exception( string.Format( - "The IAR you are trying to load does not list {0} before {1}. Aborting load", + "The IAR you are trying to load does not list {0} before {1}. Aborting load", ArchiveConstants.CONTROL_FILE_PATH, ArchiveConstants.INVENTORY_PATH)); - + if (m_assetsLoaded) throw new Exception( string.Format( - "The IAR you are trying to load does not list all {0} before {1}. Aborting load", - ArchiveConstants.INVENTORY_PATH, ArchiveConstants.ASSETS_PATH)); - + "The IAR you are trying to load does not list all {0} before {1}. Aborting load", + ArchiveConstants.INVENTORY_PATH, ArchiveConstants.ASSETS_PATH)); + path = path.Substring(ArchiveConstants.INVENTORY_PATH.Length); - + // Trim off the file portion if we aren't already dealing with a directory path if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY != entryType) path = path.Remove(path.LastIndexOf("/") + 1); - - InventoryFolderBase foundFolder + + InventoryFolderBase foundFolder = ReplicateArchivePathToUserInventory( path, m_rootDestinationFolder, m_resolvedFolders, m_loadedNodes); @@ -618,17 +633,41 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver if (item != null) { m_successfulItemRestores++; - - // If we aren't loading the folder containing the item then well need to update the + + // If we aren't loading the folder containing the item then well need to update the // viewer separately for that item. - if (!m_loadedNodes.Contains(foundFolder)) - m_loadedNodes.Add(item); + if (!m_loadedNodes.ContainsKey(foundFolder.ID)) + m_loadedNodes[foundFolder.ID] = item; + } + } + + m_inventoryNodesLoaded = true; + } + + private void LoadInventoryLinks() + { + foreach(InventoryItemBase it in m_invLinks) + { + UUID target = it.AssetID; + if(m_itemIDs.ContainsKey(target)) + { + it.AssetID = m_itemIDs[target]; + if(!m_InventoryService.AddItem(it)) + m_log.WarnFormat("[INVENTORY ARCHIVER]: Unable to save item {0} in folder {1}",it.Name,it.Folder); + else + { + m_successfulItemRestores++; + UUID fid = it.Folder; + if (!m_loadedNodes.ContainsKey(fid) && m_invLinksFolders.ContainsKey(fid)) + m_loadedNodes[fid] = m_invLinksFolders[fid]; + } } } - - m_inventoryNodesLoaded = true; + + m_itemIDs.Clear(); + m_invLinks.Clear(); + m_invLinksFolders.Clear(); } - /// /// Load asset file /// @@ -639,15 +678,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver if (!ControlFileLoaded) throw new Exception( string.Format( - "The IAR you are trying to load does not list {0} before {1}. Aborting load", + "The IAR you are trying to load does not list {0} before {1}. Aborting load", ArchiveConstants.CONTROL_FILE_PATH, ArchiveConstants.ASSETS_PATH)); - + if (!m_inventoryNodesLoaded) throw new Exception( string.Format( - "The IAR you are trying to load does not list all {0} before {1}. Aborting load", - ArchiveConstants.INVENTORY_PATH, ArchiveConstants.ASSETS_PATH)); - + "The IAR you are trying to load does not list all {0} before {1}. Aborting load", + ArchiveConstants.INVENTORY_PATH, ArchiveConstants.ASSETS_PATH)); + if (LoadAsset(path, data)) m_successfulAssetRestores++; else @@ -655,10 +694,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver if ((m_successfulAssetRestores) % 50 == 0) m_log.DebugFormat( - "[INVENTORY ARCHIVER]: Loaded {0} assets...", - m_successfulAssetRestores); - - m_assetsLoaded = true; - } + "[INVENTORY ARCHIVER]: Loaded {0} assets...", + m_successfulAssetRestores); + + m_assetsLoaded = true; + } } } diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs index dbaf2aa..b66aad5 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs @@ -69,7 +69,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// The path to the required folder. /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned. /// - /// The folder found. Please note that if there are multiple folders with the same name then an + /// The folder found. Please note that if there are multiple folders with the same name then an /// unspecified one will be returned. If no such folder eixsts then null is returned public static InventoryFolderBase FindFolderByPath( IInventoryService inventoryService, UUID userId, string path) @@ -102,7 +102,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// The path to the required folder. /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned. /// - /// The folder found. Please note that if there are multiple folders with the same name then an + /// The folder found. Please note that if there are multiple folders with the same name then an /// unspecified one will be returned. If no such folder eixsts then null is returned public static InventoryFolderBase FindFolderByPath( IInventoryService inventoryService, InventoryFolderBase startFolder, string path) @@ -149,7 +149,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver return FindFoldersByPath(inventoryService, rootFolder, path); } - + /// /// Find a set of folders given a PATH_DELIMITER delimited path starting from this folder /// @@ -175,7 +175,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver IInventoryService inventoryService, InventoryFolderBase startFolder, string path) { List foundFolders = new List(); - + if (path == string.Empty) { foundFolders.Add(startFolder); @@ -189,17 +189,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver foundFolders.Add(startFolder); return foundFolders; } - + // If the path isn't just / then trim any starting extraneous slashes path = path.TrimStart(new char[] { PATH_DELIMITER }); - + // m_log.DebugFormat("[INVENTORY ARCHIVE UTILS]: Adjusted path in FindFolderByPath() is [{0}]", path); string[] components = SplitEscapedPath(path); components[0] = UnescapePath(components[0]); //string[] components = path.Split(new string[] { PATH_DELIMITER.ToString() }, 2, StringSplitOptions.None); - + InventoryCollection contents = inventoryService.GetFolderContent(startFolder.Owner, startFolder.ID); // m_log.DebugFormat( @@ -230,7 +230,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// /// FIXME: Delimitors which occur in names themselves are not currently escapable. /// - /// + /// /// /// Inventory service to query /// @@ -301,7 +301,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// /// FIXME: Delimitors which occur in names themselves are not currently escapable. /// - /// + /// /// Inventory service to query /// The folder from which the path starts /// The path to the required item. @@ -313,10 +313,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver // If the path isn't just / then trim any starting extraneous slashes path = path.TrimStart(new char[] { PATH_DELIMITER }); - + string[] components = SplitEscapedPath(path); components[0] = UnescapePath(components[0]); - + //string[] components = path.Split(new string[] { PATH_DELIMITER }, 2, StringSplitOptions.None); if (components.Length == 1) @@ -324,15 +324,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver // m_log.DebugFormat( // "FOUND SINGLE COMPONENT [{0}]. Looking for this in [{1}] {2}", // components[0], startFolder.Name, startFolder.ID); - + List items = inventoryService.GetFolderItems(startFolder.Owner, startFolder.ID); // m_log.DebugFormat("[INVENTORY ARCHIVE UTILS]: Found {0} items in FindItemByPath()", items.Count); - + foreach (InventoryItemBase item in items) { // m_log.DebugFormat("[INVENTORY ARCHIVE UTILS]: Inspecting item {0} {1}", item.Name, item.ID); - + if (item.Name == components[0]) foundItems.Add(item); } @@ -342,7 +342,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver // m_log.DebugFormat("FOUND COMPONENTS [{0}] and [{1}]", components[0], components[1]); InventoryCollection contents = inventoryService.GetFolderContent(startFolder.Owner, startFolder.ID); - + foreach (InventoryFolderBase folder in contents.Folders) { if (folder.Name == components[0]) @@ -365,9 +365,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver public static string[] SplitEscapedPath(string path) { // m_log.DebugFormat("SPLITTING PATH {0}", path); - + bool singleEscapeChar = false; - + for (int i = 0; i < path.Length; i++) { if (path[i] == ESCAPE_CHARACTER && !singleEscapeChar) @@ -395,7 +395,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver public static string UnescapePath(string path) { // m_log.DebugFormat("ESCAPING PATH {0}", path); - + StringBuilder sb = new StringBuilder(); bool singleEscapeChar = false; @@ -418,7 +418,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver } // m_log.DebugFormat("ESCAPED PATH TO {0}", sb); - + return sb.ToString(); } diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs index f002ad7..ad46107 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs @@ -218,10 +218,39 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver // Count inventory items (different to asset count) CountItems++; - + // Don't chase down link asset items as they actually point to their target item IDs rather than an asset if (SaveAssets && itemAssetType != AssetType.Link && itemAssetType != AssetType.LinkFolder) + { + int curErrorCntr = m_assetGatherer.ErrorCount; + int possible = m_assetGatherer.possibleNotAssetCount; m_assetGatherer.AddForInspection(inventoryItem.AssetID); + m_assetGatherer.GatherAll(); + curErrorCntr = m_assetGatherer.ErrorCount - curErrorCntr; + possible = m_assetGatherer.possibleNotAssetCount - possible; + + if(curErrorCntr > 0 || possible > 0) + { + string spath; + int indx = path.IndexOf("__"); + if(indx > 0) + spath = path.Substring(0,indx); + else + spath = path; + + if(curErrorCntr > 0) + { + m_log.ErrorFormat("[INVENTORY ARCHIVER Warning]: item {0} '{1}', type {2}, in '{3}', contains {4} references to missing or damaged assets", + inventoryItem.ID, inventoryItem.Name, itemAssetType.ToString(), spath, curErrorCntr); + if(possible > 0) + m_log.WarnFormat("[INVENTORY ARCHIVER Warning]: item also contains {0} references that may be to missing or damaged assets or not a problem", possible); + } + else if(possible > 0) + { + m_log.WarnFormat("[INVENTORY ARCHIVER Warning]: item {0} '{1}', type {2}, in '{3}', contains {4} references that may be to missing or damaged assets or not a problem", inventoryItem.ID, inventoryItem.Name, itemAssetType.ToString(), spath, possible); + } + } + } } /// @@ -381,6 +410,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver string errorMessage = string.Format("Aborted save. Could not find inventory path {0}", m_invPath); Exception e = new InventoryArchiverException(errorMessage); m_module.TriggerInventoryArchiveSaved(m_id, false, m_userInfo, m_invPath, m_saveStream, e, 0, 0); + if(m_saveStream != null && m_saveStream.CanWrite) + m_saveStream.Close(); throw e; } @@ -420,17 +451,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver { m_assetGatherer.GatherAll(); + int errors = m_assetGatherer.FailedUUIDs.Count; + m_log.DebugFormat( - "[INVENTORY ARCHIVER]: Saving {0} assets for items", m_assetGatherer.GatheredUuids.Count); + "[INVENTORY ARCHIVER]: The items to save reference {0} possible assets", m_assetGatherer.GatheredUuids.Count + errors); + if(errors > 0) + m_log.DebugFormat("[INVENTORY ARCHIVER]: {0} of these have problems or are not assets and will be ignored", errors); - AssetsRequest ar - = new AssetsRequest( + AssetsRequest ar = new AssetsRequest( new AssetsArchiver(m_archiveWriter), - m_assetGatherer.GatheredUuids, m_scene.AssetService, + m_assetGatherer.GatheredUuids, m_assetGatherer.FailedUUIDs.Count, + m_scene.AssetService, m_scene.UserAccountService, m_scene.RegionInfo.ScopeID, options, ReceivedAllAssets); - - WorkManager.RunInThread(o => ar.Execute(), null, string.Format("AssetsRequest ({0})", m_scene.Name)); + ar.Execute(); } else { diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs index 9c005e4..d50ebf5 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs @@ -50,6 +50,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + /// + /// Enable or disable checking whether the iar user is actually logged in + /// +// public bool DisablePresenceChecks { get; set; } + public event InventoryArchiveSaved OnInventoryArchiveSaved; public event InventoryArchiveLoaded OnInventoryArchiveLoaded; @@ -89,6 +94,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver public InventoryArchiverModule() {} +// public InventoryArchiverModule(bool disablePresenceChecks) +// { +// DisablePresenceChecks = disablePresenceChecks; + // } + #region ISharedRegionModule public void Initialise(IConfigSource source) @@ -162,7 +172,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver public string Name { get { return "Inventory Archiver Module"; } } - #endregion + #endregion /// /// Trigger the inventory archive saved event. @@ -204,21 +214,31 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver if (userInfo != null) { - try - { - new InventoryArchiveWriteRequest(id, this, m_aScene, userInfo, invPath, saveStream).Execute(options, UserAccountService); - } - catch (EntryPointNotFoundException e) - { - m_log.ErrorFormat( - "[INVENTORY ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream." - + "If you've manually installed Mono, have you appropriately updated zlib1g as well?"); - m_log.Error(e); - - return false; - } - - return true; +// if (CheckPresence(userInfo.PrincipalID)) +// { + try + { + InventoryArchiveWriteRequest iarReq = new InventoryArchiveWriteRequest(id, this, m_aScene, userInfo, invPath, saveStream); + iarReq.Execute(options, UserAccountService); + } + catch (EntryPointNotFoundException e) + { + m_log.ErrorFormat( + "[INVENTORY ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream." + + "If you've manually installed Mono, have you appropriately updated zlib1g as well?"); + m_log.Error(e); + + return false; + } + + return true; +// } +// else +// { +// m_log.ErrorFormat( +// "[INVENTORY ARCHIVER]: User {0} {1} {2} not logged in to this region simulator", +// userInfo.FirstName, userInfo.LastName, userInfo.PrincipalID); +// } } } @@ -238,21 +258,31 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver if (userInfo != null) { - try - { - new InventoryArchiveWriteRequest(id, this, m_aScene, userInfo, invPath, savePath).Execute(options, UserAccountService); - } - catch (EntryPointNotFoundException e) - { - m_log.ErrorFormat( - "[INVENTORY ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream." - + "If you've manually installed Mono, have you appropriately updated zlib1g as well?"); - m_log.Error(e); - - return false; - } - - return true; +// if (CheckPresence(userInfo.PrincipalID)) +// { + try + { + InventoryArchiveWriteRequest iarReq = new InventoryArchiveWriteRequest(id, this, m_aScene, userInfo, invPath, savePath); + iarReq.Execute(options, UserAccountService); + } + catch (EntryPointNotFoundException e) + { + m_log.ErrorFormat( + "[INVENTORY ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream." + + "If you've manually installed Mono, have you appropriately updated zlib1g as well?"); + m_log.Error(e); + + return false; + } + + return true; +// } +// else +// { +// m_log.ErrorFormat( +// "[INVENTORY ARCHIVER]: User {0} {1} {2} not logged in to this region simulator", +// userInfo.FirstName, userInfo.LastName, userInfo.PrincipalID); +// } } } @@ -274,26 +304,35 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver if (userInfo != null) { - InventoryArchiveReadRequest request; - bool merge = (options.ContainsKey("merge") ? (bool)options["merge"] : false); - - try - { - request = new InventoryArchiveReadRequest(id, this, m_aScene.InventoryService, m_aScene.AssetService, m_aScene.UserAccountService, userInfo, invPath, loadStream, merge); - } - catch (EntryPointNotFoundException e) - { - m_log.ErrorFormat( - "[INVENTORY ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream." - + "If you've manually installed Mono, have you appropriately updated zlib1g as well?"); - m_log.Error(e); - - return false; - } - - UpdateClientWithLoadedNodes(userInfo, request.Execute()); - - return true; +// if (CheckPresence(userInfo.PrincipalID)) +// { + InventoryArchiveReadRequest request; + bool merge = (options.ContainsKey("merge") ? (bool)options["merge"] : false); + + try + { + request = new InventoryArchiveReadRequest(id, this, m_aScene.InventoryService, m_aScene.AssetService, m_aScene.UserAccountService, userInfo, invPath, loadStream, merge); + } + catch (EntryPointNotFoundException e) + { + m_log.ErrorFormat( + "[INVENTORY ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream." + + "If you've manually installed Mono, have you appropriately updated zlib1g as well?"); + m_log.Error(e); + + return false; + } + + UpdateClientWithLoadedNodes(userInfo, request.Execute()); + + return true; +// } +// else +// { +// m_log.ErrorFormat( +// "[INVENTORY ARCHIVER]: User {0} {1} {2} not logged in to this region simulator", +// userInfo.FirstName, userInfo.LastName, userInfo.PrincipalID); +// } } else m_log.ErrorFormat("[INVENTORY ARCHIVER]: User {0} {1} not found", @@ -313,26 +352,35 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver if (userInfo != null) { - InventoryArchiveReadRequest request; - bool merge = (options.ContainsKey("merge") ? (bool)options["merge"] : false); - - try - { - request = new InventoryArchiveReadRequest(id, this, m_aScene.InventoryService, m_aScene.AssetService, m_aScene.UserAccountService, userInfo, invPath, loadPath, merge); - } - catch (EntryPointNotFoundException e) - { - m_log.ErrorFormat( - "[INVENTORY ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream." - + "If you've manually installed Mono, have you appropriately updated zlib1g as well?"); - m_log.Error(e); - - return false; - } - - UpdateClientWithLoadedNodes(userInfo, request.Execute()); - - return true; +// if (CheckPresence(userInfo.PrincipalID)) +// { + InventoryArchiveReadRequest request; + bool merge = (options.ContainsKey("merge") ? (bool)options["merge"] : false); + + try + { + request = new InventoryArchiveReadRequest(id, this, m_aScene.InventoryService, m_aScene.AssetService, m_aScene.UserAccountService, userInfo, invPath, loadPath, merge); + } + catch (EntryPointNotFoundException e) + { + m_log.ErrorFormat( + "[INVENTORY ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream." + + "If you've manually installed Mono, have you appropriately updated zlib1g as well?"); + m_log.Error(e); + + return false; + } + + UpdateClientWithLoadedNodes(userInfo, request.Execute()); + + return true; +// } +// else +// { +// m_log.ErrorFormat( +// "[INVENTORY ARCHIVER]: User {0} {1} {2} not logged in to this region simulator", +// userInfo.FirstName, userInfo.LastName, userInfo.PrincipalID); +// } } } @@ -545,7 +593,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// Notify the client of loaded nodes if they are logged in /// /// Can be empty. In which case, nothing happens - private void UpdateClientWithLoadedNodes(UserAccount userInfo, HashSet loadedNodes) + private void UpdateClientWithLoadedNodes(UserAccount userInfo, Dictionary loadedNodes) { if (loadedNodes.Count == 0) return; @@ -556,7 +604,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver if (user != null && !user.IsChildAgent) { - foreach (InventoryNodeBase node in loadedNodes) + foreach (InventoryNodeBase node in loadedNodes.Values) { // m_log.DebugFormat( // "[INVENTORY ARCHIVER]: Notifying {0} of loaded inventory node {1}", @@ -569,5 +617,28 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver } } } + +// /// +// /// Check if the given user is present in any of the scenes. +// /// +// /// The user to check +// /// true if the user is in any of the scenes, false otherwise +// protected bool CheckPresence(UUID userId) +// { +// if (DisablePresenceChecks) +// return true; +// +// foreach (Scene scene in m_scenes.Values) +// { +// ScenePresence p; +// if ((p = scene.GetScenePresence(userId)) != null) +// { +// p.ControllingClient.SendAgentAlertMessage("Inventory operation has been started", false); +// return true; +// } +// } +// +// return false; +// } } } diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs index c2e645f..86eca17 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs @@ -56,23 +56,23 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - + SerialiserModule serialiserModule = new SerialiserModule(); InventoryArchiverModule archiverModule = new InventoryArchiverModule(); - + // Annoyingly, we have to set up a scene even though inventory loading has nothing to do with a scene Scene scene = new SceneHelpers().SetupScene(); - + SceneHelpers.SetupSceneModules(scene, serialiserModule, archiverModule); UserAccountHelpers.CreateUserWithInventory(scene, m_uaMT, "meowfood"); UserAccountHelpers.CreateUserWithInventory(scene, m_uaLL1, "hampshire"); - archiverModule.DearchiveInventory(UUID.Random(), m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream); + archiverModule.DearchiveInventory(UUID.Random(), m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream); InventoryItemBase foundItem1 = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, m_uaMT.PrincipalID, m_item1Name); - - Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1"); + + Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1"); // Now try loading to a root child folder UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, m_uaMT.PrincipalID, "xA", false); @@ -90,9 +90,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests InventoryItemBase foundItem3 = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, m_uaMT.PrincipalID, "xB/xC/" + m_item1Name); - Assert.That(foundItem3, Is.Not.Null, "Didn't find loaded item 3"); + Assert.That(foundItem3, Is.Not.Null, "Didn't find loaded item 3"); } - + /// /// Test that things work when the load path specified starts with a slash /// @@ -101,22 +101,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - + SerialiserModule serialiserModule = new SerialiserModule(); InventoryArchiverModule archiverModule = new InventoryArchiverModule(); Scene scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(scene, serialiserModule, archiverModule); - + UserAccountHelpers.CreateUserWithInventory(scene, m_uaMT, "password"); archiverModule.DearchiveInventory(UUID.Random(), m_uaMT.FirstName, m_uaMT.LastName, "/Objects", "password", m_iarStream); InventoryItemBase foundItem1 = InventoryArchiveUtils.FindItemByPath( scene.InventoryService, m_uaMT.PrincipalID, "/Objects/" + m_item1Name); - + Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1 in TestLoadIarFolderStartsWithSlash()"); } - + [Test] public void TestLoadIarPathWithEscapedChars() { @@ -137,7 +137,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests string userLastName = "Stirrup"; UUID userId = UUID.Parse("00000000-0000-0000-0000-000000000020"); UserAccountHelpers.CreateUserWithInventory(scene, userFirstName, userLastName, userId, "meowfood"); - + // Create asset SceneObjectGroup object1; SceneObjectPart part1; @@ -168,7 +168,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests item1.Name = itemName; item1.AssetID = asset1.FullID; item1.ID = item1Id; - InventoryFolderBase objsFolder + InventoryFolderBase objsFolder = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, userId, "Objects")[0]; item1.Folder = objsFolder.ID; scene.AddInventoryItem(item1); @@ -189,16 +189,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests InventoryItemBase foundItem1 = InventoryArchiveUtils.FindItemByPath( scene.InventoryService, userId, "Scripts/Objects/" + humanEscapedItemName); - + Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1"); // Assert.That( -// foundItem1.CreatorId, Is.EqualTo(userUuid), +// foundItem1.CreatorId, Is.EqualTo(userUuid), // "Loaded item non-uuid creator doesn't match that of the loading user"); Assert.That( - foundItem1.Name, Is.EqualTo(itemName), + foundItem1.Name, Is.EqualTo(itemName), "Loaded item name doesn't match saved name"); } - + /// /// Test replication of an archive path to the user's inventory. /// @@ -207,21 +207,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - + Scene scene = new SceneHelpers().SetupScene(); UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene); - + Dictionary foldersCreated = new Dictionary(); - HashSet nodesLoaded = new HashSet(); - + Dictionary nodesLoaded = new Dictionary(); + string folder1Name = "1"; string folder2aName = "2a"; string folder2bName = "2b"; - + string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1Name, UUID.Random()); string folder2aArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2aName, UUID.Random()); string folder2bArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2bName, UUID.Random()); - + string iarPath1 = string.Join("", new string[] { folder1ArchiveName, folder2aArchiveName }); string iarPath2 = string.Join("", new string[] { folder1ArchiveName, folder2bArchiveName }); @@ -229,42 +229,42 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests // Test replication of path1 new InventoryArchiveReadRequest(UUID.Random(), null, scene.InventoryService, scene.AssetService, scene.UserAccountService, ua1, null, (Stream)null, false) .ReplicateArchivePathToUserInventory( - iarPath1, scene.InventoryService.GetRootFolder(ua1.PrincipalID), + iarPath1, scene.InventoryService.GetRootFolder(ua1.PrincipalID), foldersCreated, nodesLoaded); - + List folder1Candidates = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1Name); Assert.That(folder1Candidates.Count, Is.EqualTo(1)); - + InventoryFolderBase folder1 = folder1Candidates[0]; - List folder2aCandidates + List folder2aCandidates = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1, folder2aName); Assert.That(folder2aCandidates.Count, Is.EqualTo(1)); } - + { // Test replication of path2 new InventoryArchiveReadRequest(UUID.Random(), null, scene.InventoryService, scene.AssetService, scene.UserAccountService, ua1, null, (Stream)null, false) .ReplicateArchivePathToUserInventory( - iarPath2, scene.InventoryService.GetRootFolder(ua1.PrincipalID), + iarPath2, scene.InventoryService.GetRootFolder(ua1.PrincipalID), foldersCreated, nodesLoaded); - + List folder1Candidates = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1Name); Assert.That(folder1Candidates.Count, Is.EqualTo(1)); - - InventoryFolderBase folder1 = folder1Candidates[0]; - - List folder2aCandidates + + InventoryFolderBase folder1 = folder1Candidates[0]; + + List folder2aCandidates = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1, folder2aName); Assert.That(folder2aCandidates.Count, Is.EqualTo(1)); - - List folder2bCandidates + + List folder2bCandidates = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1, folder2bName); Assert.That(folder2bCandidates.Count, Is.EqualTo(1)); } } - + /// /// Test replication of a partly existing archive path to the user's inventory. This should create /// a duplicate path without the merge option. @@ -274,31 +274,31 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests { TestHelpers.InMethod(); //log4net.Config.XmlConfigurator.Configure(); - + Scene scene = new SceneHelpers().SetupScene(); UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene); - + string folder1ExistingName = "a"; string folder2Name = "b"; - - InventoryFolderBase folder1 + + InventoryFolderBase folder1 = UserInventoryHelpers.CreateInventoryFolder( scene.InventoryService, ua1.PrincipalID, folder1ExistingName, false); - + string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random()); string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random()); - + string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName }); new InventoryArchiveReadRequest(UUID.Random(), null, scene.InventoryService, scene.AssetService, scene.UserAccountService, ua1, null, (Stream)null, false) .ReplicateArchivePathToUserInventory( - itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID), - new Dictionary(), new HashSet()); + itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID), + new Dictionary(), new Dictionary()); - List folder1PostCandidates + List folder1PostCandidates = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName); Assert.That(folder1PostCandidates.Count, Is.EqualTo(2)); - + // FIXME: Temporarily, we're going to do something messy to make sure we pick up the created folder. InventoryFolderBase folder1Post = null; foreach (InventoryFolderBase folder in folder1PostCandidates) @@ -311,11 +311,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests } // Assert.That(folder1Post.ID, Is.EqualTo(folder1.ID)); - List folder2PostCandidates + List folder2PostCandidates = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1Post, "b"); Assert.That(folder2PostCandidates.Count, Is.EqualTo(1)); } - + /// /// Test replication of a partly existing archive path to the user's inventory. This should create /// a merged path. @@ -325,33 +325,33 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - + Scene scene = new SceneHelpers().SetupScene(); UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene); - + string folder1ExistingName = "a"; string folder2Name = "b"; - - InventoryFolderBase folder1 + + InventoryFolderBase folder1 = UserInventoryHelpers.CreateInventoryFolder( scene.InventoryService, ua1.PrincipalID, folder1ExistingName, false); - + string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random()); string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random()); - + string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName }); new InventoryArchiveReadRequest(UUID.Random(), null, scene.InventoryService, scene.AssetService, scene.UserAccountService, ua1, folder1ExistingName, (Stream)null, true) .ReplicateArchivePathToUserInventory( - itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID), - new Dictionary(), new HashSet()); + itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID), + new Dictionary(), new Dictionary()); - List folder1PostCandidates + List folder1PostCandidates = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName); Assert.That(folder1PostCandidates.Count, Is.EqualTo(1)); Assert.That(folder1PostCandidates[0].ID, Is.EqualTo(folder1.ID)); - List folder2PostCandidates + List folder2PostCandidates = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1PostCandidates[0], "b"); Assert.That(folder2PostCandidates.Count, Is.EqualTo(1)); } diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs index 57b4f80..d0bdc91 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs @@ -47,7 +47,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests { [TestFixture] public class InventoryArchiveLoadTests : InventoryArchiveTestCase - { + { protected TestScene m_scene; protected InventoryArchiverModule m_archiverModule; @@ -55,12 +55,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests public override void SetUp() { base.SetUp(); - + SerialiserModule serialiserModule = new SerialiserModule(); m_archiverModule = new InventoryArchiverModule(); m_scene = new SceneHelpers().SetupScene(); - SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule); + SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule); } [Test] @@ -68,35 +68,35 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests { TestHelpers.InMethod(); // TestHelpers.EnableLogging(); - + UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "password"); - m_archiverModule.DearchiveInventory(UUID.Random(), m_uaLL1.FirstName, m_uaLL1.LastName, "/", "password", m_iarStream); - + m_archiverModule.DearchiveInventory(UUID.Random(), m_uaLL1.FirstName, m_uaLL1.LastName, "/", "password", m_iarStream); + InventoryItemBase coaItem = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_coaItemName); - - Assert.That(coaItem, Is.Not.Null, "Didn't find loaded item 1"); - + + Assert.That(coaItem, Is.Not.Null, "Didn't find loaded item 1"); + string assetXml = AssetHelpers.ReadAssetAsString(m_scene.AssetService, coaItem.AssetID); - - CoalescedSceneObjects coa; + + CoalescedSceneObjects coa; bool readResult = CoalescedSceneObjectsSerializer.TryFromXml(assetXml, out coa); - + Assert.That(readResult, Is.True); Assert.That(coa.Count, Is.EqualTo(2)); - + List coaObjects = coa.Objects; Assert.That(coaObjects[0].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000120"))); Assert.That(coaObjects[0].AbsolutePosition, Is.EqualTo(new Vector3(15, 30, 45))); - + Assert.That(coaObjects[1].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000140"))); - Assert.That(coaObjects[1].AbsolutePosition, Is.EqualTo(new Vector3(25, 50, 75))); - } + Assert.That(coaObjects[1].AbsolutePosition, Is.EqualTo(new Vector3(25, 50, 75))); + } /// /// Test case where a creator account exists for the creator UUID embedded in item metadata and serialized /// objects. - /// + /// [Test] public void TestLoadIarCreatorAccountPresent() { @@ -105,26 +105,26 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "meowfood"); - m_archiverModule.DearchiveInventory(UUID.Random(), m_uaLL1.FirstName, m_uaLL1.LastName, "/", "meowfood", m_iarStream); + m_archiverModule.DearchiveInventory(UUID.Random(), m_uaLL1.FirstName, m_uaLL1.LastName, "/", "meowfood", m_iarStream); InventoryItemBase foundItem1 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_item1Name); Assert.That( - foundItem1.CreatorId, Is.EqualTo(m_uaLL1.PrincipalID.ToString()), - "Loaded item non-uuid creator doesn't match original"); + foundItem1.CreatorId, Is.EqualTo(m_uaLL1.PrincipalID.ToString()), + "Loaded item non-uuid creator doesn't match original"); Assert.That( - foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL1.PrincipalID), + foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL1.PrincipalID), "Loaded item uuid creator doesn't match original"); Assert.That(foundItem1.Owner, Is.EqualTo(m_uaLL1.PrincipalID), "Loaded item owner doesn't match inventory reciever"); - - AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString()); + + AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString()); string xmlData = Utils.BytesToString(asset1.Data); SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); - - Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL1.PrincipalID)); + + Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL1.PrincipalID)); } - + // /// // /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where // /// an account exists with the same name as the creator, though not the same id. @@ -137,24 +137,24 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests // // UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "meowfood"); // UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL2, "hampshire"); -// -// m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream); +// +// m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream); // InventoryItemBase foundItem1 // = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name); // // Assert.That( -// foundItem1.CreatorId, Is.EqualTo(m_uaLL2.PrincipalID.ToString()), -// "Loaded item non-uuid creator doesn't match original"); +// foundItem1.CreatorId, Is.EqualTo(m_uaLL2.PrincipalID.ToString()), +// "Loaded item non-uuid creator doesn't match original"); // Assert.That( -// foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL2.PrincipalID), +// foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL2.PrincipalID), // "Loaded item uuid creator doesn't match original"); // Assert.That(foundItem1.Owner, Is.EqualTo(m_uaMT.PrincipalID), // "Loaded item owner doesn't match inventory reciever"); -// -// AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString()); +// +// AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString()); // string xmlData = Utils.BytesToString(asset1.Data); // SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); -// +// // Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL2.PrincipalID)); // } @@ -167,26 +167,26 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - + UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "password"); m_archiverModule.DearchiveInventory(UUID.Random(), m_uaMT.FirstName, m_uaMT.LastName, "/", "password", m_iarStream); InventoryItemBase foundItem1 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name); - + Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1"); Assert.That( - foundItem1.CreatorId, Is.EqualTo(m_uaMT.PrincipalID.ToString()), + foundItem1.CreatorId, Is.EqualTo(m_uaMT.PrincipalID.ToString()), "Loaded item non-uuid creator doesn't match that of the loading user"); Assert.That( - foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaMT.PrincipalID), + foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaMT.PrincipalID), "Loaded item uuid creator doesn't match that of the loading user"); - - AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString()); + + AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString()); string xmlData = Utils.BytesToString(asset1.Data); SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); - - Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaMT.PrincipalID)); + + Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaMT.PrincipalID)); } } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs index 7265405..bd112b4 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs @@ -50,19 +50,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests { protected TestScene m_scene; protected InventoryArchiverModule m_archiverModule; - + [SetUp] public override void SetUp() { base.SetUp(); - + SerialiserModule serialiserModule = new SerialiserModule(); m_archiverModule = new InventoryArchiverModule(); m_scene = new SceneHelpers().SetupScene(); - SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule); + SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule); } - + /// /// Test that the IAR has the required files in the right order. /// @@ -73,20 +73,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests public void TestOrder() { TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); - +// log4net.Config.XmlConfigurator.Configure(); + MemoryStream archiveReadStream = new MemoryStream(m_iarStreamBytes); - TarArchiveReader tar = new TarArchiveReader(archiveReadStream); + TarArchiveReader tar = new TarArchiveReader(archiveReadStream); string filePath; TarArchiveReader.TarEntryType tarEntryType; - + byte[] data = tar.ReadEntry(out filePath, out tarEntryType); Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); - + InventoryArchiveReadRequest iarr = new InventoryArchiveReadRequest(UUID.Random(), null, null, null, null, null, null, (Stream)null, false); iarr.LoadControlFile(filePath, data); - + Assert.That(iarr.ControlFileLoaded, Is.True); } @@ -119,22 +119,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests // InventoryArchiveUtils. bool gotObjectsFolder = false; - string objectsFolderName + string objectsFolderName = string.Format( - "{0}{1}", - ArchiveConstants.INVENTORY_PATH, + "{0}{1}", + ArchiveConstants.INVENTORY_PATH, InventoryArchiveWriteRequest.CreateArchiveFolderName( UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, userId, "Objects"))); string filePath; TarArchiveReader.TarEntryType tarEntryType; - + while (tar.ReadEntry(out filePath, out tarEntryType) != null) { // Console.WriteLine("Got {0}", filePath); // Lazily, we only bother to look for the system objects folder created when we call CreateUserWithInventory() - // XXX: But really we need to stop all that stuff being created in tests or check for such folders + // XXX: But really we need to stop all that stuff being created in tests or check for such folders // more thoroughly if (filePath == objectsFolderName) gotObjectsFolder = true; @@ -157,19 +157,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests UserAccountHelpers.CreateUserWithInventory(m_scene, userFirstName, userLastName, userId, userPassword); // Create base folder - InventoryFolderBase f1 + InventoryFolderBase f1 = UserInventoryHelpers.CreateInventoryFolder(m_scene.InventoryService, userId, "f1", true); - + // Create item1 - SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(1, userId, "My Little Dog Object", 0x5); + SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(1, userId, "My Little Dog Object", 0x5); InventoryItemBase i1 = UserInventoryHelpers.AddInventoryItem(m_scene, so1, 0x50, 0x60, "f1"); // Create embedded folder - InventoryFolderBase f1_1 + InventoryFolderBase f1_1 = UserInventoryHelpers.CreateInventoryFolder(m_scene.InventoryService, userId, "f1/f1.1", true); // Create embedded item - SceneObjectGroup so1_1 = SceneHelpers.CreateSceneObject(1, userId, "My Little Cat Object", 0x6); + SceneObjectGroup so1_1 = SceneHelpers.CreateSceneObject(1, userId, "My Little Cat Object", 0x6); InventoryItemBase i2 = UserInventoryHelpers.AddInventoryItem(m_scene, so1_1, 0x500, 0x600, "f1/f1.1"); MemoryStream archiveWriteStream = new MemoryStream(); @@ -188,18 +188,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests // InventoryArchiveUtils. bool gotf1 = false, gotf1_1 = false, gotso1 = false, gotso2 = false; - string f1FileName + string f1FileName = string.Format("{0}{1}", ArchiveConstants.INVENTORY_PATH, InventoryArchiveWriteRequest.CreateArchiveFolderName(f1)); - string f1_1FileName + string f1_1FileName = string.Format("{0}{1}", f1FileName, InventoryArchiveWriteRequest.CreateArchiveFolderName(f1_1)); - string so1FileName + string so1FileName = string.Format("{0}{1}", f1FileName, InventoryArchiveWriteRequest.CreateArchiveItemName(i1)); string so2FileName = string.Format("{0}{1}", f1_1FileName, InventoryArchiveWriteRequest.CreateArchiveItemName(i2)); string filePath; TarArchiveReader.TarEntryType tarEntryType; - + while (tar.ReadEntry(out filePath, out tarEntryType) != null) { // Console.WriteLine("Got {0}", filePath); @@ -222,7 +222,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests // TODO: Test presence of more files and contents of files. } - + /// /// Test saving a single inventory item to an IAR /// (subject to change since there is no fixed format yet). @@ -239,10 +239,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests string userPassword = "troll"; UUID userId = UUID.Parse("00000000-0000-0000-0000-000000000020"); UserAccountHelpers.CreateUserWithInventory(m_scene, userFirstName, userLastName, userId, userPassword); - + // Create asset UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); - SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, ownerId, "My Little Dog Object", 0x50); + SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, ownerId, "My Little Dog Object", 0x50); UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); @@ -255,7 +255,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests item1.Name = item1Name; item1.AssetID = asset1.FullID; item1.ID = item1Id; - InventoryFolderBase objsFolder + InventoryFolderBase objsFolder = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, userId, "Objects")[0]; item1.Folder = objsFolder.ID; m_scene.AddInventoryItem(item1); @@ -285,7 +285,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests TarArchiveReader.TarEntryType tarEntryType; // Console.WriteLine("Reading archive"); - + while (tar.ReadEntry(out filePath, out tarEntryType) != null) { Console.WriteLine("Got {0}", filePath); @@ -294,7 +294,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests // { // gotControlFile = true; // } - + if (filePath.StartsWith(ArchiveConstants.INVENTORY_PATH) && filePath.EndsWith(".xml")) { // string fileName = filePath.Remove(0, "Objects/".Length); diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs index 519c697..0b65829 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs @@ -49,35 +49,35 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests public class InventoryArchiveTestCase : OpenSimTestCase { protected ManualResetEvent mre = new ManualResetEvent(false); - + /// /// A raw array of bytes that we'll use to create an IAR memory stream suitable for isolated use in each test. /// protected byte[] m_iarStreamBytes; - + /// /// Stream of data representing a common IAR for load tests. /// protected MemoryStream m_iarStream; - - protected UserAccount m_uaMT - = new UserAccount { + + protected UserAccount m_uaMT + = new UserAccount { PrincipalID = UUID.Parse("00000000-0000-0000-0000-000000000555"), FirstName = "Mr", LastName = "Tiddles" }; - + protected UserAccount m_uaLL1 - = new UserAccount { + = new UserAccount { PrincipalID = UUID.Parse("00000000-0000-0000-0000-000000000666"), FirstName = "Lord", - LastName = "Lucan" }; - + LastName = "Lucan" }; + protected UserAccount m_uaLL2 - = new UserAccount { + = new UserAccount { PrincipalID = UUID.Parse("00000000-0000-0000-0000-000000000777"), FirstName = "Lord", - LastName = "Lucan" }; - + LastName = "Lucan" }; + protected string m_item1Name = "Ray Gun Item"; protected string m_coaItemName = "Coalesced Item"; @@ -105,72 +105,72 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests base.SetUp(); m_iarStream = new MemoryStream(m_iarStreamBytes); } - + protected void ConstructDefaultIarBytesForTestLoad() { // log4net.Config.XmlConfigurator.Configure(); - + InventoryArchiverModule archiverModule = new InventoryArchiverModule(); Scene scene = new SceneHelpers().SetupScene(); - SceneHelpers.SetupSceneModules(scene, archiverModule); - + SceneHelpers.SetupSceneModules(scene, archiverModule); + UserAccountHelpers.CreateUserWithInventory(scene, m_uaLL1, "hampshire"); MemoryStream archiveWriteStream = new MemoryStream(); - + // Create scene object asset UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); - SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, ownerId, "Ray Gun Object", 0x50); + SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, ownerId, "Ray Gun Object", 0x50); UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); - scene.AssetService.Store(asset1); + scene.AssetService.Store(asset1); // Create scene object item InventoryItemBase item1 = new InventoryItemBase(); item1.Name = m_item1Name; - item1.ID = UUID.Parse("00000000-0000-0000-0000-000000000020"); + item1.ID = UUID.Parse("00000000-0000-0000-0000-000000000020"); item1.AssetID = asset1.FullID; item1.GroupID = UUID.Random(); item1.CreatorId = m_uaLL1.PrincipalID.ToString(); item1.Owner = m_uaLL1.PrincipalID; - item1.Folder = scene.InventoryService.GetRootFolder(m_uaLL1.PrincipalID).ID; + item1.Folder = scene.InventoryService.GetRootFolder(m_uaLL1.PrincipalID).ID; scene.AddInventoryItem(item1); - + // Create coalesced objects asset SceneObjectGroup cobj1 = SceneHelpers.CreateSceneObject(1, m_uaLL1.PrincipalID, "Object1", 0x120); cobj1.AbsolutePosition = new Vector3(15, 30, 45); - + SceneObjectGroup cobj2 = SceneHelpers.CreateSceneObject(1, m_uaLL1.PrincipalID, "Object2", 0x140); - cobj2.AbsolutePosition = new Vector3(25, 50, 75); - + cobj2.AbsolutePosition = new Vector3(25, 50, 75); + CoalescedSceneObjects coa = new CoalescedSceneObjects(m_uaLL1.PrincipalID, cobj1, cobj2); - + AssetBase coaAsset = AssetHelpers.CreateAsset(0x160, coa); - scene.AssetService.Store(coaAsset); - + scene.AssetService.Store(coaAsset); + // Create coalesced objects inventory item InventoryItemBase coaItem = new InventoryItemBase(); coaItem.Name = m_coaItemName; - coaItem.ID = UUID.Parse("00000000-0000-0000-0000-000000000180"); + coaItem.ID = UUID.Parse("00000000-0000-0000-0000-000000000180"); coaItem.AssetID = coaAsset.FullID; coaItem.GroupID = UUID.Random(); coaItem.CreatorId = m_uaLL1.PrincipalID.ToString(); coaItem.Owner = m_uaLL1.PrincipalID; - coaItem.Folder = scene.InventoryService.GetRootFolder(m_uaLL1.PrincipalID).ID; - scene.AddInventoryItem(coaItem); - + coaItem.Folder = scene.InventoryService.GetRootFolder(m_uaLL1.PrincipalID).ID; + scene.AddInventoryItem(coaItem); + archiverModule.ArchiveInventory( - UUID.Random(), m_uaLL1.FirstName, m_uaLL1.LastName, "/*", "hampshire", archiveWriteStream); - + UUID.Random(), m_uaLL1.FirstName, m_uaLL1.LastName, "/*", "hampshire", archiveWriteStream); + m_iarStreamBytes = archiveWriteStream.ToArray(); } - + protected void SaveCompleted( - UUID id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream, + UUID id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream, Exception reportedException, int SaveCount, int FilterCount) { mre.Set(); - } + } } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs index bba48cc..5d7f25c 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs @@ -149,10 +149,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer private void OnInstantMessage(IClientAPI client, GridInstantMessage im) { // m_log.DebugFormat( -// "[INVENTORY TRANSFER]: {0} IM type received from client {1}. From={2} ({3}), To={4}", +// "[INVENTORY TRANSFER]: {0} IM type received from client {1}. From={2} ({3}), To={4}", // (InstantMessageDialog)im.dialog, client.Name, // im.fromAgentID, im.fromAgentName, im.toAgentID); - + Scene scene = FindClientScene(client.AgentId); if (scene == null) // Something seriously wrong here. @@ -164,31 +164,31 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer if (im.binaryBucket.Length < 17) // Invalid return; - - UUID receipientID = new UUID(im.toAgentID); - ScenePresence user = scene.GetScenePresence(receipientID); + + UUID recipientID = new UUID(im.toAgentID); + ScenePresence user = scene.GetScenePresence(recipientID); UUID copyID; // First byte is the asset type AssetType assetType = (AssetType)im.binaryBucket[0]; - + if (AssetType.Folder == assetType) { UUID folderID = new UUID(im.binaryBucket, 1); - + m_log.DebugFormat( "[INVENTORY TRANSFER]: Inserting original folder {0} into agent {1}'s inventory", folderID, new UUID(im.toAgentID)); - + InventoryFolderBase folderCopy - = scene.GiveInventoryFolder(client, receipientID, client.AgentId, folderID, UUID.Zero); - + = scene.GiveInventoryFolder(client, recipientID, client.AgentId, folderID, UUID.Zero); + if (folderCopy == null) { client.SendAgentAlertMessage("Can't find folder to give. Nothing given.", false); return; } - + // The outgoing binary bucket should contain only the byte which signals an asset folder is // being copied and the following bytes for the copied folder's UUID copyID = folderCopy.ID; @@ -196,7 +196,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer im.binaryBucket = new byte[1 + copyIDBytes.Length]; im.binaryBucket[0] = (byte)AssetType.Folder; Array.Copy(copyIDBytes, 0, im.binaryBucket, 1, copyIDBytes.Length); - + if (user != null) user.ControllingClient.SendBulkUpdateInventory(folderCopy); @@ -225,10 +225,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer client.SendAgentAlertMessage(message, false); return; } - + copyID = itemCopy.ID; Array.Copy(copyID.GetBytes(), 0, im.binaryBucket, 1, 16); - + if (user != null) user.ControllingClient.SendBulkUpdateInventory(itemCopy); @@ -239,6 +239,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer im.imSessionID = copyID.Guid; } + im.offline = 0; + // Send the IM to the recipient. The item is already // in their inventory, so it will not be lost if // they are offline. @@ -251,15 +253,47 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer else { if (m_TransferModule != null) - m_TransferModule.SendInstantMessage(im, delegate(bool success) + m_TransferModule.SendInstantMessage(im, delegate(bool success) { if (!success) client.SendAlertMessage("User not online. Inventory has been saved"); }); } } - else if (im.dialog == (byte) InstantMessageDialog.InventoryAccepted) + else if (im.dialog == (byte) InstantMessageDialog.InventoryAccepted || + im.dialog == (byte) InstantMessageDialog.TaskInventoryAccepted) { + UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip + IInventoryService invService = scene.InventoryService; + + // Special case: folder redirect. + // RLV uses this + if (im.dialog == (byte) InstantMessageDialog.TaskInventoryAccepted) + { + InventoryFolderBase folder = invService.GetFolder(client.AgentId, inventoryID); + + if (folder != null) + { + if (im.binaryBucket.Length >= 16) + { + UUID destFolderID = new UUID(im.binaryBucket, 0); + if (destFolderID != UUID.Zero) + { + InventoryFolderBase destFolder = invService.GetFolder(client.AgentId, destFolderID); + if (destFolder != null) + { + if (folder.ParentID != destFolder.ID) + { + folder.ParentID = destFolder.ID; + invService.MoveFolder(folder); + client.SendBulkUpdateInventory(folder); + } + } + } + } + } + } + ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID)); if (user != null) // Local @@ -269,33 +303,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer else { if (m_TransferModule != null) - m_TransferModule.SendInstantMessage(im, delegate(bool success) { - - // justincc - FIXME: Comment out for now. This code was added in commit db91044 Mon Aug 22 2011 - // and is apparently supposed to fix bulk inventory updates after accepting items. But - // instead it appears to cause two copies of an accepted folder for the receiving user in - // at least some cases. Folder/item update is already done when the offer is made (see code above) - -// // Send BulkUpdateInventory -// IInventoryService invService = scene.InventoryService; -// UUID inventoryEntityID = new UUID(im.imSessionID); // The inventory item /folder, back from it's trip -// -// InventoryFolderBase folder = new InventoryFolderBase(inventoryEntityID, client.AgentId); -// folder = invService.GetFolder(folder); -// -// ScenePresence fromUser = scene.GetScenePresence(new UUID(im.fromAgentID)); -// -// // If the user has left the scene by the time the message comes back then we can't send -// // them the update. -// if (fromUser != null) -// fromUser.ControllingClient.SendBulkUpdateInventory(folder); - }); + m_TransferModule.SendInstantMessage(im, delegate(bool success) {}); } } // XXX: This code was placed here to try and accomodate RLV which moves given folders named #RLV/~ - // to the requested folder, which in this case is #RLV. However, it is the viewer that appears to be - // response from renaming the #RLV/~example folder to ~example. For some reason this is not yet + // to the requested folder, which in this case is #RLV. However, it is the viewer that appears to be + // response from renaming the #RLV/~example folder to ~example. For some reason this is not yet // happening, possibly because we are not sending the correct inventory update messages with the correct // transaction IDs else if (im.dialog == (byte) InstantMessageDialog.TaskInventoryAccepted) @@ -310,21 +324,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer if (destinationFolderID != UUID.Zero) { InventoryFolderBase destinationFolder = new InventoryFolderBase(destinationFolderID, client.AgentId); - if (destinationFolder == null) - { - m_log.WarnFormat( - "[INVENTORY TRANSFER]: TaskInventoryAccepted message from {0} in {1} specified folder {2} which does not exist", - client.Name, scene.Name, destinationFolderID); - - return; - } - IInventoryService invService = scene.InventoryService; UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip - InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId); - item = invService.GetItem(item); + InventoryItemBase item = invService.GetItem(client.AgentId, inventoryID); InventoryFolderBase folder = null; UUID? previousParentFolderID = null; @@ -338,8 +342,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer } else { - folder = new InventoryFolderBase(inventoryID, client.AgentId); - folder = invService.GetFolder(folder); + folder = invService.GetFolder(client.AgentId, inventoryID); if (folder != null) // It's a folder { @@ -352,9 +355,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer // Tell client about updates to original parent and new parent (this should probably be factored with existing move item/folder code). if (previousParentFolderID != null) { - InventoryFolderBase previousParentFolder - = new InventoryFolderBase((UUID)previousParentFolderID, client.AgentId); - previousParentFolder = invService.GetFolder(previousParentFolder); + InventoryFolderBase previousParentFolder = invService.GetFolder(client.AgentId, (UUID)previousParentFolderID); scene.SendInventoryUpdate(client, previousParentFolder, true, true); scene.SendInventoryUpdate(client, destinationFolder, true, true); @@ -376,11 +377,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip - InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId); - item = invService.GetItem(item); + InventoryItemBase item = invService.GetItem(client.AgentId, inventoryID); InventoryFolderBase folder = null; UUID? previousParentFolderID = null; - + if (item != null && trashFolder != null) { previousParentFolderID = item.Folder; @@ -394,37 +394,35 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer } else { - folder = new InventoryFolderBase(inventoryID, client.AgentId); - folder = invService.GetFolder(folder); + folder = invService.GetFolder(client.AgentId, inventoryID); if (folder != null & trashFolder != null) { previousParentFolderID = folder.ParentID; folder.ParentID = trashFolder.ID; invService.MoveFolder(folder); + client.SendBulkUpdateInventory(folder); } } - + if ((null == item && null == folder) | null == trashFolder) { string reason = String.Empty; - + if (trashFolder == null) reason += " Trash folder not found."; if (item == null) reason += " Item not found."; if (folder == null) reason += " Folder not found."; - + client.SendAgentAlertMessage("Unable to delete "+ "received inventory" + reason, false); } // Tell client about updates to original parent and new parent (this should probably be factored with existing move item/folder code). else if (previousParentFolderID != null) { - InventoryFolderBase previousParentFolder - = new InventoryFolderBase((UUID)previousParentFolderID, client.AgentId); - previousParentFolder = invService.GetFolder(previousParentFolder); + InventoryFolderBase previousParentFolder = invService.GetFolder(client.AgentId, (UUID)previousParentFolderID); scene.SendInventoryUpdate(client, previousParentFolder, true, true); scene.SendInventoryUpdate(client, trashFolder, true, true); @@ -453,18 +451,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer /// private void OnGridInstantMessage(GridInstantMessage im) { - // Check if it's a type of message that we should handle - if (!((im.dialog == (byte) InstantMessageDialog.InventoryOffered) - || (im.dialog == (byte) InstantMessageDialog.TaskInventoryOffered) - || (im.dialog == (byte) InstantMessageDialog.InventoryAccepted) - || (im.dialog == (byte) InstantMessageDialog.InventoryDeclined) - || (im.dialog == (byte) InstantMessageDialog.TaskInventoryDeclined))) - return; - - m_log.DebugFormat( - "[INVENTORY TRANSFER]: {0} IM type received from grid. From={1} ({2}), To={3}", - (InstantMessageDialog)im.dialog, im.fromAgentID, im.fromAgentName, im.toAgentID); - // Check if this is ours to handle // Scene scene = FindClientScene(new UUID(im.toAgentID)); @@ -475,32 +461,92 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer // Find agent to deliver to // ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID)); + if (user == null) + return; - if (user != null) + // This requires a little bit of processing because we have to make the + // new item visible in the recipient's inventory here + // + if (im.dialog == (byte) InstantMessageDialog.InventoryOffered) { - user.ControllingClient.SendInstantMessage(im); + if (im.binaryBucket.Length < 17) // Invalid + return; - if (im.dialog == (byte)InstantMessageDialog.InventoryOffered) + UUID recipientID = new UUID(im.toAgentID); + + // First byte is the asset type + AssetType assetType = (AssetType)im.binaryBucket[0]; + + if (AssetType.Folder == assetType) { - AssetType assetType = (AssetType)im.binaryBucket[0]; - UUID inventoryID = new UUID(im.binaryBucket, 1); - - IInventoryService invService = scene.InventoryService; - InventoryNodeBase node = null; - if (AssetType.Folder == assetType) + UUID folderID = new UUID(im.binaryBucket, 1); + + InventoryFolderBase folder = + scene.InventoryService.GetFolder(recipientID, folderID); + + if (folder != null) + user.ControllingClient.SendBulkUpdateInventory(folder); + } + else + { + UUID itemID = new UUID(im.binaryBucket, 1); + + InventoryItemBase item = + scene.InventoryService.GetItem(recipientID, itemID); + + if (item != null) { - InventoryFolderBase folder = new InventoryFolderBase(inventoryID, new UUID(im.toAgentID)); - node = invService.GetFolder(folder); + user.ControllingClient.SendBulkUpdateInventory(item); } - else + } + user.ControllingClient.SendInstantMessage(im); + } + if (im.dialog == (byte) InstantMessageDialog.TaskInventoryOffered) + { + if (im.binaryBucket.Length < 1) // Invalid + return; + + UUID recipientID = new UUID(im.toAgentID); + + // Bucket is the asset type + AssetType assetType = (AssetType)im.binaryBucket[0]; + + if (AssetType.Folder == assetType) + { + UUID folderID = new UUID(im.imSessionID); + + InventoryFolderBase folder = + scene.InventoryService.GetFolder(recipientID, folderID); + + if (folder != null) + user.ControllingClient.SendBulkUpdateInventory(folder); + } + else + { + UUID itemID = new UUID(im.imSessionID); + + InventoryItemBase item = + scene.InventoryService.GetItem(recipientID, itemID); + + if (item != null) { - InventoryItemBase item = new InventoryItemBase(inventoryID, new UUID(im.toAgentID)); - node = invService.GetItem(item); + user.ControllingClient.SendBulkUpdateInventory(item); } - - if (node != null) - user.ControllingClient.SendBulkUpdateInventory(node); } + + // Fix up binary bucket since this may be 17 chars long here + Byte[] bucket = new Byte[1]; + bucket[0] = im.binaryBucket[0]; + im.binaryBucket = bucket; + + user.ControllingClient.SendInstantMessage(im); + } + else if (im.dialog == (byte) InstantMessageDialog.InventoryAccepted || + im.dialog == (byte) InstantMessageDialog.InventoryDeclined || + im.dialog == (byte) InstantMessageDialog.TaskInventoryDeclined || + im.dialog == (byte) InstantMessageDialog.TaskInventoryAccepted) + { + user.ControllingClient.SendInstantMessage(im); } } } diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs index 7ddc396..82ed091 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs @@ -44,9 +44,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests { [TestFixture] public class InventoryTransferModuleTests : OpenSimTestCase - { - protected TestScene m_scene; - + { + protected TestScene m_scene; + [SetUp] public override void SetUp() { @@ -56,9 +56,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests config.AddConfig("Messaging"); config.Configs["Messaging"].Set("InventoryTransferModule", "InventoryTransferModule"); - m_scene = new SceneHelpers().SetupScene(); + m_scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(m_scene, config, new InventoryTransferModule()); - } + } [Test] public void TestAcceptGivenItem() @@ -69,9 +69,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests UUID itemId = TestHelpers.ParseTail(0x100); UUID assetId = TestHelpers.ParseTail(0x200); - UserAccount ua1 + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw"); - UserAccount ua2 + UserAccount ua2 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw"); ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1); @@ -81,7 +81,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests TestClient receiverClient = (TestClient)receiverSp.ControllingClient; // Create the object to test give - InventoryItemBase originalItem + InventoryItemBase originalItem = UserInventoryHelpers.CreateInventoryItem( m_scene, "givenObj", itemId, assetId, giverSp.UUID, InventoryType.Object); @@ -89,35 +89,35 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests byte[] itemIdBytes = itemId.GetBytes(); Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length); - GridInstantMessage giveIm + GridInstantMessage giveIm = new GridInstantMessage( - m_scene, - giverSp.UUID, - giverSp.Name, - receiverSp.UUID, + m_scene, + giverSp.UUID, + giverSp.Name, + receiverSp.UUID, (byte)InstantMessageDialog.InventoryOffered, false, - "inventory offered msg", + "inventory offered msg", initialSessionId, - false, + false, Vector3.Zero, giveImBinaryBucket, true); giverClient.HandleImprovedInstantMessage(giveIm); - // These details might not all be correct. - GridInstantMessage acceptIm + // These details might not all be correct. + GridInstantMessage acceptIm = new GridInstantMessage( - m_scene, - receiverSp.UUID, - receiverSp.Name, - giverSp.UUID, - (byte)InstantMessageDialog.InventoryAccepted, + m_scene, + receiverSp.UUID, + receiverSp.Name, + giverSp.UUID, + (byte)InstantMessageDialog.InventoryAccepted, false, - "inventory accepted msg", + "inventory accepted msg", initialSessionId, - false, + false, Vector3.Zero, null, true); @@ -133,7 +133,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests Assert.That(originalItemAfterGive.ID, Is.EqualTo(originalItem.ID)); // Test for item successfully making it into the receiver's inventory - InventoryItemBase receivedItem + InventoryItemBase receivedItem = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, receiverSp.UUID, "Objects/givenObj"); Assert.That(receivedItem, Is.Not.Null); @@ -148,7 +148,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests Assert.That(originalItemAfterDelete, Is.Not.Null); // TODO: Test scenario where giver deletes their item first. - } + } /// /// Test user rejection of a given item. @@ -165,9 +165,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests UUID itemId = TestHelpers.ParseTail(0x100); UUID assetId = TestHelpers.ParseTail(0x200); - UserAccount ua1 + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw"); - UserAccount ua2 + UserAccount ua2 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw"); ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1); @@ -177,7 +177,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests TestClient receiverClient = (TestClient)receiverSp.ControllingClient; // Create the object to test give - InventoryItemBase originalItem + InventoryItemBase originalItem = UserInventoryHelpers.CreateInventoryItem( m_scene, "givenObj", itemId, assetId, giverSp.UUID, InventoryType.Object); @@ -188,36 +188,36 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests byte[] itemIdBytes = itemId.GetBytes(); Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length); - GridInstantMessage giveIm + GridInstantMessage giveIm = new GridInstantMessage( - m_scene, - giverSp.UUID, - giverSp.Name, - receiverSp.UUID, + m_scene, + giverSp.UUID, + giverSp.Name, + receiverSp.UUID, (byte)InstantMessageDialog.InventoryOffered, false, - "inventory offered msg", + "inventory offered msg", initialSessionId, - false, + false, Vector3.Zero, giveImBinaryBucket, true); giverClient.HandleImprovedInstantMessage(giveIm); - // These details might not all be correct. + // These details might not all be correct. // Session ID is now the created item ID (!) - GridInstantMessage rejectIm + GridInstantMessage rejectIm = new GridInstantMessage( - m_scene, - receiverSp.UUID, - receiverSp.Name, - giverSp.UUID, - (byte)InstantMessageDialog.InventoryDeclined, + m_scene, + receiverSp.UUID, + receiverSp.Name, + giverSp.UUID, + (byte)InstantMessageDialog.InventoryDeclined, false, - "inventory declined msg", + "inventory declined msg", new UUID(receivedIm.imSessionID), - false, + false, Vector3.Zero, null, true); @@ -233,7 +233,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests Assert.That(originalItemAfterGive.ID, Is.EqualTo(originalItem.ID)); // Test for item successfully making it into the receiver's inventory - InventoryItemBase receivedItem + InventoryItemBase receivedItem = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, receiverSp.UUID, "Trash/givenObj"); InventoryFolderBase trashFolder @@ -250,7 +250,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj"); Assert.That(originalItemAfterDelete, Is.Not.Null); - } + } [Test] public void TestAcceptGivenFolder() @@ -261,9 +261,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests UUID initialSessionId = TestHelpers.ParseTail(0x10); UUID folderId = TestHelpers.ParseTail(0x100); - UserAccount ua1 + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw"); - UserAccount ua2 + UserAccount ua2 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw"); ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1); @@ -272,7 +272,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2); TestClient receiverClient = (TestClient)receiverSp.ControllingClient; - InventoryFolderBase originalFolder + InventoryFolderBase originalFolder = UserInventoryHelpers.CreateInventoryFolder( m_scene.InventoryService, giverSp.UUID, folderId, "f1", true); @@ -281,35 +281,35 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests byte[] itemIdBytes = folderId.GetBytes(); Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length); - GridInstantMessage giveIm + GridInstantMessage giveIm = new GridInstantMessage( - m_scene, - giverSp.UUID, - giverSp.Name, - receiverSp.UUID, + m_scene, + giverSp.UUID, + giverSp.Name, + receiverSp.UUID, (byte)InstantMessageDialog.InventoryOffered, false, - "inventory offered msg", + "inventory offered msg", initialSessionId, - false, + false, Vector3.Zero, giveImBinaryBucket, true); giverClient.HandleImprovedInstantMessage(giveIm); - // These details might not all be correct. - GridInstantMessage acceptIm + // These details might not all be correct. + GridInstantMessage acceptIm = new GridInstantMessage( - m_scene, - receiverSp.UUID, - receiverSp.Name, - giverSp.UUID, - (byte)InstantMessageDialog.InventoryAccepted, + m_scene, + receiverSp.UUID, + receiverSp.Name, + giverSp.UUID, + (byte)InstantMessageDialog.InventoryAccepted, false, - "inventory accepted msg", + "inventory accepted msg", initialSessionId, - false, + false, Vector3.Zero, null, true); @@ -325,7 +325,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests Assert.That(originalFolderAfterGive.ID, Is.EqualTo(originalFolder.ID)); // Test for item successfully making it into the receiver's inventory - InventoryFolderBase receivedFolder + InventoryFolderBase receivedFolder = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, receiverSp.UUID, "f1"); Assert.That(receivedFolder, Is.Not.Null); @@ -340,7 +340,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests Assert.That(originalFolderAfterDelete, Is.Not.Null); // TODO: Test scenario where giver deletes their item first. - } + } /// /// Test user rejection of a given item. @@ -357,9 +357,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests UUID initialSessionId = TestHelpers.ParseTail(0x10); UUID folderId = TestHelpers.ParseTail(0x100); - UserAccount ua1 + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw"); - UserAccount ua2 + UserAccount ua2 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw"); ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1); @@ -369,7 +369,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests TestClient receiverClient = (TestClient)receiverSp.ControllingClient; // Create the folder to test give - InventoryFolderBase originalFolder + InventoryFolderBase originalFolder = UserInventoryHelpers.CreateInventoryFolder( m_scene.InventoryService, giverSp.UUID, folderId, "f1", true); @@ -381,36 +381,36 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests byte[] itemIdBytes = folderId.GetBytes(); Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length); - GridInstantMessage giveIm + GridInstantMessage giveIm = new GridInstantMessage( - m_scene, - giverSp.UUID, - giverSp.Name, - receiverSp.UUID, + m_scene, + giverSp.UUID, + giverSp.Name, + receiverSp.UUID, (byte)InstantMessageDialog.InventoryOffered, false, - "inventory offered msg", + "inventory offered msg", initialSessionId, - false, + false, Vector3.Zero, giveImBinaryBucket, true); giverClient.HandleImprovedInstantMessage(giveIm); - // These details might not all be correct. + // These details might not all be correct. // Session ID is now the created item ID (!) - GridInstantMessage rejectIm + GridInstantMessage rejectIm = new GridInstantMessage( - m_scene, - receiverSp.UUID, - receiverSp.Name, - giverSp.UUID, - (byte)InstantMessageDialog.InventoryDeclined, + m_scene, + receiverSp.UUID, + receiverSp.Name, + giverSp.UUID, + (byte)InstantMessageDialog.InventoryDeclined, false, - "inventory declined msg", + "inventory declined msg", new UUID(receivedIm.imSessionID), - false, + false, Vector3.Zero, null, true); @@ -426,7 +426,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests Assert.That(originalFolderAfterGive.ID, Is.EqualTo(originalFolder.ID)); // Test for folder successfully making it into the receiver's inventory - InventoryFolderBase receivedFolder + InventoryFolderBase receivedFolder = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, receiverSp.UUID, "Trash/f1"); InventoryFolderBase trashFolder @@ -443,6 +443,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1"); Assert.That(originalFolderAfterDelete, Is.Not.Null); - } + } } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs index 24286a4..10781e9 100644 --- a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs @@ -65,7 +65,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure { m_Enabled = true; - m_ThisGridURL = Util.GetConfigVarFromSections(config, "GatekeeperURI", + m_ThisGridURL = Util.GetConfigVarFromSections(config, "GatekeeperURI", new string[] { "Startup", "Hypergrid", "Messaging" }, String.Empty); // Legacy. Remove soon! m_ThisGridURL = config.Configs["Messaging"].GetString("Gatekeeper", m_ThisGridURL); @@ -154,7 +154,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure void OnIncomingInstantMessage(GridInstantMessage im) { - if (im.dialog == (byte)InstantMessageDialog.RequestTeleport + if (im.dialog == (byte)InstantMessageDialog.RequestTeleport || im.dialog == (byte)InstantMessageDialog.GodLikeRequestTeleport) { UUID sessionID = new UUID(im.imSessionID); @@ -195,7 +195,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure m_log.DebugFormat("[HG LURE MODULE]: RequestTeleport sessionID={0}, regionID={1}, message={2}", m.imSessionID, m.RegionID, m.message); m_PendingLures.Add(sessionID, m, 7200); // 2 hours - + if (m_TransferModule != null) { m_TransferModule.SendInstantMessage(m, diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs index 465ffbc..6f79676 100644 --- a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs @@ -163,16 +163,29 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure scene.RegionInfo.RegionHandle, (uint)presence.AbsolutePosition.X, (uint)presence.AbsolutePosition.Y, - (uint)Math.Ceiling(presence.AbsolutePosition.Z)); + (uint)presence.AbsolutePosition.Z + 2); m_log.DebugFormat("[LURE MODULE]: TP invite with message {0}, type {1}", message, lureType); - GridInstantMessage m = new GridInstantMessage(scene, client.AgentId, - client.FirstName+" "+client.LastName, targetid, - (byte)InstantMessageDialog.RequestTeleport, false, - message, dest, false, presence.AbsolutePosition, - new Byte[0], true); - + GridInstantMessage m; + + if (scene.Permissions.IsAdministrator(client.AgentId) && presence.IsViewerUIGod && (!scene.Permissions.IsAdministrator(targetid))) + { + m = new GridInstantMessage(scene, client.AgentId, + client.FirstName+" "+client.LastName, targetid, + (byte)InstantMessageDialog.GodLikeRequestTeleport, false, + message, dest, false, presence.AbsolutePosition, + new Byte[0], true); + } + else + { + m = new GridInstantMessage(scene, client.AgentId, + client.FirstName+" "+client.LastName, targetid, + (byte)InstantMessageDialog.RequestTeleport, false, + message, dest, false, presence.AbsolutePosition, + new Byte[0], true); + } + if (m_TransferModule != null) { m_TransferModule.SendInstantMessage(m, @@ -207,7 +220,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure { // Forward remote teleport requests // - if (msg.dialog != 22) + if (msg.dialog != (byte)InstantMessageDialog.RequestTeleport && + msg.dialog != (byte)InstantMessageDialog.GodLikeRequestTeleport) return; if (m_TransferModule != null) diff --git a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs index 2bb24ae..1e1caca 100644 --- a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs @@ -68,7 +68,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Profile { if (!m_Enabled) return; - + lock (m_Scenes) { if (!m_Scenes.Contains(scene)) @@ -154,7 +154,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Profile name = account.FirstName + " " + account.LastName; created = account.Created; } - Byte[] charterMember = Utils.StringToBytes(name); + Byte[] membershipType = Utils.StringToBytes(name); profileUrl = "No profile data"; aboutText = string.Empty; @@ -166,7 +166,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Profile remoteClient.SendAvatarProperties(avatarID, aboutText, Util.ToDateTime(created).ToString( "M/d/yyyy", CultureInfo.InvariantCulture), - charterMember, firstLifeAboutText, + membershipType, firstLifeAboutText, (uint)(0 & 0xff), firstLifeImage, image, profileUrl, partner); diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index c20369c..e02ca49 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -31,6 +31,7 @@ using System.Text; using System.Collections; using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Net; using System.Net.Sockets; using System.Reflection; @@ -56,6 +57,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserProfilesModule")] public class UserProfileModule : IProfileModule, INonSharedRegionModule { + const double PROFILECACHEEXPIRE = 300; /// /// Logging /// @@ -66,8 +68,11 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles // count. The entries are removed when the interest count reaches 0. Dictionary m_classifiedCache = new Dictionary(); Dictionary m_classifiedInterest = new Dictionary(); + ExpiringCache m_profilesCache = new ExpiringCache(); + IAssetCache m_assetCache; private JsonRpcRequestManager rpc = new JsonRpcRequestManager(); + private bool m_allowUserProfileWebURLs = true; public Scene Scene { @@ -80,7 +85,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles /// /// The configuration /// - public IConfigSource Config + public IConfigSource Config { get; set; @@ -92,7 +97,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles /// /// The profile server URI. /// - public string ProfileServerUri + public string ProfileServerUri { get; set; @@ -115,23 +120,22 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles /// /// true if enabled; otherwise, false. /// - public bool Enabled + public bool Enabled { get; set; } - public string MyGatekeeper + public string MyGatekeeper { get; private set; } - #region IRegionModuleBase implementation /// /// This is called to initialize the region module. For shared modules, this is called exactly once, after /// creating the single (shared) instance. For non-shared modules, this is called once on each instance, after - /// the instace for the region has been created. + /// the instace for the region has been created. /// /// /// Source. @@ -145,7 +149,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if (profileConfig == null) { - m_log.Debug("[PROFILES]: UserProfiles disabled, no configuration"); + //m_log.Debug("[PROFILES]: UserProfiles disabled, no configuration"); Enabled = false; return; } @@ -158,7 +162,9 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles Enabled = false; return; } - + + m_allowUserProfileWebURLs = profileConfig.GetBoolean("AllowUserProfileWebURLs", m_allowUserProfileWebURLs); + m_log.Debug("[PROFILES]: Full Profiles Enabled"); ReplaceableInterface = null; Enabled = true; @@ -181,22 +187,11 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles Scene = scene; Scene.RegisterModuleInterface(this); Scene.EventManager.OnNewClient += OnNewClient; - Scene.EventManager.OnMakeRootAgent += HandleOnMakeRootAgent; + Scene.EventManager.OnClientClosed += OnClientClosed; UserManagementModule = Scene.RequestModuleInterface(); } - void HandleOnMakeRootAgent (ScenePresence obj) - { - if(obj.PresenceType == PresenceType.Npc) - return; - - Util.FireAndForget(delegate - { - GetImageAssets(((IScenePresence)obj).UUID); - }, null, "UserProfileModule.GetImageAssets"); - } - /// /// Removes the region. /// @@ -207,13 +202,17 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { if(!Enabled) return; + + m_profilesCache.Clear(); + m_classifiedCache.Clear(); + m_classifiedInterest.Clear(); } /// /// This will be called once for every scene loaded. In a shared module this will be multiple times in one /// instance, while a nonshared module instance will only be called once. This method is called after AddRegion /// has been called in all modules for that scene, providing an opportunity to request another module's - /// interface, or hook an event from another module. + /// interface, or hook an event from another module. /// /// /// Scene. @@ -222,6 +221,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { if(!Enabled) return; + m_assetCache = Scene.RequestModuleInterface(); } /// @@ -230,7 +230,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles /// module has registered the interface by then, this module will be activated, else it will remain inactive, /// letting the other module take over. This should return non-null ONLY in modules that are intended to be /// easily replaceable, e.g. stub implementations that the developer expects to be replaced by third party - /// provided modules. + /// provided modules. /// /// /// The replaceable interface. @@ -248,7 +248,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles } /// - /// The name of the module + /// The name of the module /// /// /// Gets the module name. @@ -293,6 +293,40 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles client.OnUserInfoRequest += UserPreferencesRequest; client.OnUpdateUserInfo += UpdateUserPreferences; } + + void OnClientClosed(UUID AgentId, Scene scene) + { + ScenePresence sp = scene.GetScenePresence(AgentId); + IClientAPI client = sp.ControllingClient; + if (client == null) + return; + + //Profile + client.OnRequestAvatarProperties -= RequestAvatarProperties; + client.OnUpdateAvatarProperties -= AvatarPropertiesUpdate; + client.OnAvatarInterestUpdate -= AvatarInterestsUpdate; + + // Classifieds +// client.r GenericPacketHandler("avatarclassifiedsrequest", ClassifiedsRequest); + client.OnClassifiedInfoUpdate -= ClassifiedInfoUpdate; + client.OnClassifiedInfoRequest -= ClassifiedInfoRequest; + client.OnClassifiedDelete -= ClassifiedDelete; + + // Picks +// client.AddGenericPacketHandler("avatarpicksrequest", PicksRequest); +// client.AddGenericPacketHandler("pickinforequest", PickInfoRequest); + client.OnPickInfoUpdate -= PickInfoUpdate; + client.OnPickDelete -= PickDelete; + + // Notes +// client.AddGenericPacketHandler("avatarnotesrequest", NotesRequest); + client.OnAvatarNotesUpdate -= NotesUpdate; + + // Preferences + client.OnUserInfoRequest -= UserPreferencesRequest; + client.OnUpdateUserInfo -= UpdateUserPreferences; + } + #endregion Region Event Handlers #region Classified @@ -315,38 +349,74 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return; IClientAPI remoteClient = (IClientAPI)sender; + Dictionary classifieds = new Dictionary(); UUID targetID; - UUID.TryParse(args[0], out targetID); + if(!UUID.TryParse(args[0], out targetID) || targetID == UUID.Zero) + return; - // Can't handle NPC yet... ScenePresence p = FindPresence(targetID); + if (p != null && p.IsNPC) + { + remoteClient.SendAvatarClassifiedReply(targetID, classifieds); + return; + } - if (null != p) + UserProfileCacheEntry uce = null; + lock(m_profilesCache) { - if (p.PresenceType == PresenceType.Npc) - return; + if(m_profilesCache.TryGetValue(targetID, out uce) && uce != null) + { + if(uce.classifiedsLists != null) + { + foreach(KeyValuePair kvp in uce.classifiedsLists) + { + UUID kvpkey = kvp.Key; + classifieds[kvpkey] = kvp.Value; + lock (m_classifiedCache) + { + if (!m_classifiedCache.ContainsKey(kvpkey)) + { + m_classifiedCache.Add(kvpkey,targetID); + m_classifiedInterest.Add(kvpkey, 0); + } + + m_classifiedInterest[kvpkey]++; + } + } + remoteClient.SendAvatarClassifiedReply(targetID, uce.classifiedsLists); + return; + } + } } string serverURI = string.Empty; GetUserProfileServerURI(targetID, out serverURI); - UUID creatorId = UUID.Zero; - Dictionary classifieds = new Dictionary(); + if(string.IsNullOrWhiteSpace(serverURI)) + { + remoteClient.SendAvatarClassifiedReply(targetID, classifieds); + return; + } OSDMap parameters= new OSDMap(); - UUID.TryParse(args[0], out creatorId); - parameters.Add("creatorId", OSD.FromUUID(creatorId)); + + parameters.Add("creatorId", OSD.FromUUID(targetID)); OSD Params = (OSD)parameters; if(!rpc.JsonRpcRequest(ref Params, "avatarclassifiedsrequest", serverURI, UUID.Random().ToString())) { - remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), classifieds); + remoteClient.SendAvatarClassifiedReply(targetID, classifieds); return; } parameters = (OSDMap)Params; - OSDArray list = (OSDArray)parameters["result"]; + if(!parameters.ContainsKey("result") || parameters["result"] == null) + { + remoteClient.SendAvatarClassifiedReply(targetID, classifieds); + return; + } + OSDArray list = (OSDArray)parameters["result"]; foreach(OSD map in list) { @@ -360,7 +430,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { if (!m_classifiedCache.ContainsKey(cid)) { - m_classifiedCache.Add(cid,creatorId); + m_classifiedCache.Add(cid,targetID); m_classifiedInterest.Add(cid, 0); } @@ -368,11 +438,20 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles } } - remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), classifieds); + lock(m_profilesCache) + { + if(!m_profilesCache.TryGetValue(targetID, out uce) || uce == null) + uce = new UserProfileCacheEntry(); + uce.classifiedsLists = classifieds; + + m_profilesCache.AddOrUpdate(targetID, uce, PROFILECACHEEXPIRE); + } + + remoteClient.SendAvatarClassifiedReply(targetID, classifieds); } public void ClassifiedInfoRequest(UUID queryClassifiedID, IClientAPI remoteClient) - { + { UUID target = remoteClient.AgentId; UserClassifiedAdd ad = new UserClassifiedAdd(); ad.ClassifiedId = queryClassifiedID; @@ -380,7 +459,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles lock (m_classifiedCache) { if (m_classifiedCache.ContainsKey(queryClassifiedID)) - { + { target = m_classifiedCache[queryClassifiedID]; m_classifiedInterest[queryClassifiedID] --; @@ -392,9 +471,33 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles } } } - + + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(target, out uce) && uce != null) + { + if(uce.classifieds != null && uce.classifieds.ContainsKey(queryClassifiedID)) + { + ad = uce.classifieds[queryClassifiedID]; + Vector3 gPos = new Vector3(); + Vector3.TryParse(ad.GlobalPos, out gPos); + + remoteClient.SendClassifiedInfoReply(ad.ClassifiedId, ad.CreatorId, (uint)ad.CreationDate, + (uint)ad.ExpirationDate, (uint)ad.Category, ad.Name, ad.Description, + ad.ParcelId, (uint)ad.ParentEstate, ad.SnapshotId, ad.SimName, + gPos, ad.ParcelName, ad.Flags, ad.Price); + return; + } + } + } + string serverURI = string.Empty; - GetUserProfileServerURI(target, out serverURI); + bool foreign = GetUserProfileServerURI(target, out serverURI); + if(string.IsNullOrWhiteSpace(serverURI)) + { + return; + } object Ad = (object)ad; if(!rpc.JsonRpcRequest(ref Ad, "classifieds_info_query", serverURI, UUID.Random().ToString())) @@ -408,6 +511,20 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if(ad.CreatorId == UUID.Zero) return; + if(foreign) + cacheForeignImage(target, ad.SnapshotId); + + lock(m_profilesCache) + { + if(!m_profilesCache.TryGetValue(target, out uce) || uce == null) + uce = new UserProfileCacheEntry(); + if(uce.classifieds == null) + uce.classifieds = new Dictionary(); + uce.classifieds[ad.ClassifiedId] = ad; + + m_profilesCache.AddOrUpdate(target, uce, PROFILECACHEEXPIRE); + } + Vector3 globalPos = new Vector3(); Vector3.TryParse(ad.GlobalPos, out globalPos); @@ -458,36 +575,62 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles int queryclassifiedPrice, IClientAPI remoteClient) { Scene s = (Scene)remoteClient.Scene; - IMoneyModule money = s.RequestModuleInterface(); + Vector3 pos = remoteClient.SceneAgent.AbsolutePosition; + ILandObject land = s.LandChannel.GetLandObject(pos.X, pos.Y); + UUID creatorId = remoteClient.AgentId; + ScenePresence p = FindPresence(creatorId); - if (money != null) + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + m_profilesCache.TryGetValue(remoteClient.AgentId, out uce); + + string serverURI = string.Empty; + bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + if(string.IsNullOrWhiteSpace(serverURI)) { - if (!money.AmountCovered(remoteClient.AgentId, queryclassifiedPrice)) - { - remoteClient.SendAgentAlertMessage("You do not have enough money to create requested classified.", false); - return; - } - money.ApplyCharge(remoteClient.AgentId, queryclassifiedPrice, MoneyTransactionType.ClassifiedCharge); + return; } - UserClassifiedAdd ad = new UserClassifiedAdd(); - - Vector3 pos = remoteClient.SceneAgent.AbsolutePosition; - ILandObject land = s.LandChannel.GetLandObject(pos.X, pos.Y); - ScenePresence p = FindPresence(remoteClient.AgentId); - - string serverURI = string.Empty; - GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + if(foreign) + { + remoteClient.SendAgentAlertMessage("Please change classifieds on your home grid", true); + if(uce != null && uce.classifiedsLists != null) + remoteClient.SendAvatarClassifiedReply(remoteClient.AgentId, uce.classifiedsLists); + return; + } - if (land == null) + OSDMap parameters = new OSDMap {{"creatorId", OSD.FromUUID(creatorId)}}; + OSD Params = (OSD)parameters; + if (!rpc.JsonRpcRequest(ref Params, "avatarclassifiedsrequest", serverURI, UUID.Random().ToString())) { - ad.ParcelName = string.Empty; + remoteClient.SendAgentAlertMessage("Error fetching classifieds", false); + return; } - else + parameters = (OSDMap)Params; + OSDArray list = (OSDArray)parameters["result"]; + bool exists = list.Cast().Where(map => map.ContainsKey("classifieduuid")) + .Any(map => map["classifieduuid"].AsUUID().Equals(queryclassifiedID)); + + IMoneyModule money = null; + if (!exists) { - ad.ParcelName = land.LandData.Name; + money = s.RequestModuleInterface(); + if (money != null) + { + if (!money.AmountCovered(remoteClient.AgentId, queryclassifiedPrice)) + { + remoteClient.SendAgentAlertMessage("You do not have enough money to create this classified.", false); + if(uce != null && uce.classifiedsLists != null) + remoteClient.SendAvatarClassifiedReply(remoteClient.AgentId, uce.classifiedsLists); + return; + } +// money.ApplyCharge(remoteClient.AgentId, queryclassifiedPrice, MoneyTransactionType.ClassifiedCharge); + } } + UserClassifiedAdd ad = new UserClassifiedAdd(); + + ad.ParcelName = land == null ? string.Empty : land.LandData.Name; ad.CreatorId = remoteClient.AgentId; ad.ClassifiedId = queryclassifiedID; ad.Category = Convert.ToInt32(queryCategory); @@ -507,10 +650,26 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if(!rpc.JsonRpcRequest(ref Ad, "classified_update", serverURI, UUID.Random().ToString())) { - remoteClient.SendAgentAlertMessage( - "Error updating classified", false); + remoteClient.SendAgentAlertMessage("Error updating classified", false); + if(uce != null && uce.classifiedsLists != null) + remoteClient.SendAvatarClassifiedReply(remoteClient.AgentId, uce.classifiedsLists); return; } + + // only charge if it worked + if (money != null) + money.ApplyCharge(remoteClient.AgentId, queryclassifiedPrice, MoneyTransactionType.ClassifiedCharge); + + // just flush cache for now + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) + { + uce.classifieds = null; + uce.classifiedsLists = null; + } + } + } /// @@ -524,12 +683,23 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles /// public void ClassifiedDelete(UUID queryClassifiedID, IClientAPI remoteClient) { + string serverURI = string.Empty; - GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + if(string.IsNullOrWhiteSpace(serverURI)) + return; + + if(foreign) + { + remoteClient.SendAgentAlertMessage("Please change classifieds on your home grid", true); + return; + } UUID classifiedId; + if(!UUID.TryParse(queryClassifiedID.ToString(), out classifiedId)) + return; + OSDMap parameters= new OSDMap(); - UUID.TryParse(queryClassifiedID.ToString(), out classifiedId); parameters.Add("classifiedId", OSD.FromUUID(classifiedId)); OSD Params = (OSD)parameters; if(!rpc.JsonRpcRequest(ref Params, "classified_delete", serverURI, UUID.Random().ToString())) @@ -539,6 +709,17 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return; } + // flush cache + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) + { + uce.classifieds = null; + uce.classifiedsLists = null; + } + } + parameters = (OSDMap)Params; } #endregion Classified @@ -564,33 +745,54 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles IClientAPI remoteClient = (IClientAPI)sender; UUID targetId; - UUID.TryParse(args[0], out targetId); + if(!UUID.TryParse(args[0], out targetId)) + return; + + Dictionary picks = new Dictionary(); - // Can't handle NPC yet... ScenePresence p = FindPresence(targetId); + if (p != null && p.IsNPC) + { + remoteClient.SendAvatarPicksReply(targetId, picks); + return; + } - if (null != p) + UserProfileCacheEntry uce = null; + lock(m_profilesCache) { - if (p.PresenceType == PresenceType.Npc) - return; + if(m_profilesCache.TryGetValue(targetId, out uce) && uce != null) + { + if(uce != null && uce.picksList != null) + { + remoteClient.SendAvatarPicksReply(targetId, uce.picksList); + return; + } + } } string serverURI = string.Empty; GetUserProfileServerURI(targetId, out serverURI); - - Dictionary picks = new Dictionary(); + if(string.IsNullOrWhiteSpace(serverURI)) + { + remoteClient.SendAvatarPicksReply(targetId, picks); + return; + } OSDMap parameters= new OSDMap(); parameters.Add("creatorId", OSD.FromUUID(targetId)); OSD Params = (OSD)parameters; if(!rpc.JsonRpcRequest(ref Params, "avatarpicksrequest", serverURI, UUID.Random().ToString())) { - remoteClient.SendAvatarPicksReply(new UUID(args[0]), picks); + remoteClient.SendAvatarPicksReply(targetId, picks); return; } parameters = (OSDMap)Params; - + if(!parameters.ContainsKey("result") || parameters["result"] == null) + { + remoteClient.SendAvatarPicksReply(targetId, picks); + return; + } OSDArray list = (OSDArray)parameters["result"]; foreach(OSD map in list) @@ -598,12 +800,19 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles OSDMap m = (OSDMap)map; UUID cid = m["pickuuid"].AsUUID(); string name = m["name"].AsString(); - - m_log.DebugFormat("[PROFILES]: PicksRequest {0}", name); - picks[cid] = name; } - remoteClient.SendAvatarPicksReply(new UUID(args[0]), picks); + + lock(m_profilesCache) + { + if(!m_profilesCache.TryGetValue(targetId, out uce) || uce == null) + uce = new UserProfileCacheEntry(); + uce.picksList = picks; + + m_profilesCache.AddOrUpdate(targetId, uce, PROFILECACHEEXPIRE); + } + + remoteClient.SendAvatarPicksReply(targetId, picks); } /// @@ -623,21 +832,45 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if (!(sender is IClientAPI)) return; + UserProfilePick pick = new UserProfilePick (); UUID targetID; - UUID.TryParse (args [0], out targetID); - string serverURI = string.Empty; - GetUserProfileServerURI (targetID, out serverURI); + if(!UUID.TryParse(args [0], out targetID)) + return; - string theirGatekeeperURI; - GetUserGatekeeperURI (targetID, out theirGatekeeperURI); + pick.CreatorId = targetID; + + if(!UUID.TryParse (args [1], out pick.PickId)) + return; IClientAPI remoteClient = (IClientAPI)sender; + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(targetID, out uce) && uce != null) + { + if(uce != null && uce.picks != null && uce.picks.ContainsKey(pick.PickId)) + { + pick = uce.picks[pick.PickId]; + Vector3 gPos = new Vector3(Vector3.Zero); + Vector3.TryParse(pick.GlobalPos, out gPos); + remoteClient.SendPickInfoReply(pick.PickId,pick.CreatorId,pick.TopPick,pick.ParcelId,pick.Name, + pick.Desc,pick.SnapshotId,pick.ParcelName,pick.OriginalName,pick.SimName, + gPos,pick.SortOrder,pick.Enabled); + return; + } + } + } - UserProfilePick pick = new UserProfilePick (); - UUID.TryParse (args [0], out pick.CreatorId); - UUID.TryParse (args [1], out pick.PickId); + string serverURI = string.Empty; + bool foreign = GetUserProfileServerURI (targetID, out serverURI); + if(string.IsNullOrWhiteSpace(serverURI)) + { + return; + } + + string theirGatekeeperURI; + GetUserGatekeeperURI(targetID, out theirGatekeeperURI); - object Pick = (object)pick; if (!rpc.JsonRpcRequest (ref Pick, "pickinforequest", serverURI, UUID.Random ().ToString ())) { remoteClient.SendAgentAlertMessage ( @@ -645,15 +878,13 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return; } pick = (UserProfilePick)Pick; - + if(foreign) + cacheForeignImage(targetID, pick.SnapshotId); + Vector3 globalPos = new Vector3(Vector3.Zero); - - // Smoke and mirrors - if (pick.Gatekeeper == MyGatekeeper) - { - Vector3.TryParse(pick.GlobalPos,out globalPos); - } - else + Vector3.TryParse(pick.GlobalPos, out globalPos); + + if (!string.IsNullOrWhiteSpace(MyGatekeeper) && pick.Gatekeeper != MyGatekeeper) { // Setup the illusion string region = string.Format("{0} {1}",pick.Gatekeeper,pick.SimName); @@ -661,26 +892,52 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if(target == null) { - // This is a dead or unreachable region + // This is a unreachable region } else { - // Work our slight of hand - int x = target.RegionLocX; - int y = target.RegionLocY; + // we have a proxy on map + ulong oriHandle; + uint oriX; + uint oriY; + if(Util.ParseFakeParcelID(pick.ParcelId, out oriHandle, out oriX, out oriY)) + { + pick.ParcelId = Util.BuildFakeParcelID(target.RegionHandle, oriX, oriY); + globalPos.X = target.RegionLocX + oriX; + globalPos.Y = target.RegionLocY + oriY; + pick.GlobalPos = globalPos.ToString(); + } + else + { + // this is a fail on large regions + uint gtmp = (uint)globalPos.X >> 8; + globalPos.X -= (gtmp << 8); + + gtmp = (uint)globalPos.Y >> 8; + globalPos.Y -= (gtmp << 8); - dynamic synthX = globalPos.X - (globalPos.X/Constants.RegionSize) * Constants.RegionSize; - synthX += x; - globalPos.X = synthX; + pick.ParcelId = Util.BuildFakeParcelID(target.RegionHandle, (uint)globalPos.X, (uint)globalPos.Y); - dynamic synthY = globalPos.Y - (globalPos.Y/Constants.RegionSize) * Constants.RegionSize; - synthY += y; - globalPos.Y = synthY; + globalPos.X += target.RegionLocX; + globalPos.Y += target.RegionLocY; + pick.GlobalPos = globalPos.ToString(); + } } } m_log.DebugFormat("[PROFILES]: PickInfoRequest: {0} : {1}", pick.Name.ToString(), pick.SnapshotId.ToString()); + lock(m_profilesCache) + { + if(!m_profilesCache.TryGetValue(targetID, out uce) || uce == null) + uce = new UserProfileCacheEntry(); + if(uce.picks == null) + uce.picks = new Dictionary(); + uce.picks[pick.PickId] = pick; + + m_profilesCache.AddOrUpdate(targetID, uce, PROFILECACHEEXPIRE); + } + // Pull the rabbit out of the hat remoteClient.SendPickInfoReply(pick.PickId,pick.CreatorId,pick.TopPick,pick.ParcelId,pick.Name, pick.Desc,pick.SnapshotId,pick.ParcelName,pick.OriginalName,pick.SimName, @@ -718,13 +975,17 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles /// Enabled. /// public void PickInfoUpdate(IClientAPI remoteClient, UUID pickID, UUID creatorID, bool topPick, string name, string desc, UUID snapshotID, int sortOrder, bool enabled) - { - //TODO: See how this works with NPC, May need to test + { m_log.DebugFormat("[PROFILES]: Start PickInfoUpdate Name: {0} PickId: {1} SnapshotId: {2}", name, pickID.ToString(), snapshotID.ToString()); UserProfilePick pick = new UserProfilePick(); string serverURI = string.Empty; GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + if(string.IsNullOrWhiteSpace(serverURI)) + { + return; + } + ScenePresence p = FindPresence(remoteClient.AgentId); Vector3 avaPos = p.AbsolutePosition; @@ -734,24 +995,27 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles avaPos.Z); string landParcelName = "My Parcel"; - UUID landParcelID = p.currentParcelUUID; +// UUID landParcelID = p.currentParcelUUID; + // to locate parcels we use a fake id that encodes the region handle + // since we do not have a global locator + // this fails on HG + UUID landParcelID = Util.BuildFakeParcelID(remoteClient.Scene.RegionInfo.RegionHandle, (uint)avaPos.X, (uint)avaPos.Y); ILandObject land = p.Scene.LandChannel.GetLandObject(avaPos.X, avaPos.Y); if (land != null) { // If land found, use parcel uuid from here because the value from SP will be blank if the avatar hasnt moved landParcelName = land.LandData.Name; - landParcelID = land.LandData.GlobalID; +// landParcelID = land.LandData.GlobalID; } else { m_log.WarnFormat( - "[PROFILES]: PickInfoUpdate found no parcel info at {0},{1} in {2}", + "[PROFILES]: PickInfoUpdate found no parcel info at {0},{1} in {2}", avaPos.X, avaPos.Y, p.Scene.Name); } - pick.PickId = pickID; pick.CreatorId = creatorID; pick.TopPick = topPick; @@ -774,6 +1038,24 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return; } + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(!m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) || uce == null) + uce = new UserProfileCacheEntry(); + if(uce.picks == null) + uce.picks = new Dictionary(); + if(uce.picksList == null) + uce.picksList = new Dictionary(); + uce.picks[pick.PickId] = pick; + uce.picksList[pick.PickId] = pick.Name; + m_profilesCache.AddOrUpdate(remoteClient.AgentId, uce, PROFILECACHEEXPIRE); + } + remoteClient.SendAvatarPicksReply(remoteClient.AgentId, uce.picksList); + remoteClient.SendPickInfoReply(pick.PickId,pick.CreatorId,pick.TopPick,pick.ParcelId,pick.Name, + pick.Desc,pick.SnapshotId,pick.ParcelName,pick.OriginalName,pick.SimName, + posGlobal,pick.SortOrder,pick.Enabled); + m_log.DebugFormat("[PROFILES]: Finish PickInfoUpdate {0} {1}", pick.Name, pick.PickId.ToString()); } @@ -790,6 +1072,10 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { string serverURI = string.Empty; GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + if(string.IsNullOrWhiteSpace(serverURI)) + { + return; + } OSDMap parameters= new OSDMap(); parameters.Add("pickId", OSD.FromUUID(queryPickID)); @@ -800,6 +1086,23 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles "Error picks delete", false); return; } + + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) + { + if(uce.picks != null && uce.picks.ContainsKey(queryPickID)) + uce.picks.Remove(queryPickID); + if(uce.picksList != null && uce.picksList.ContainsKey(queryPickID)) + uce.picksList.Remove(queryPickID); + m_profilesCache.AddOrUpdate(remoteClient.AgentId, uce, PROFILECACHEEXPIRE); + } + } + if(uce != null && uce.picksList != null) + remoteClient.SendAvatarPicksReply(remoteClient.AgentId, uce.picksList); + else + remoteClient.SendAvatarPicksReply(remoteClient.AgentId, new Dictionary()); } #endregion Picks @@ -823,11 +1126,19 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if (!(sender is IClientAPI)) return; + if(!UUID.TryParse(args[0], out note.TargetId)) + return; + IClientAPI remoteClient = (IClientAPI)sender; + note.UserId = remoteClient.AgentId; + string serverURI = string.Empty; GetUserProfileServerURI(remoteClient.AgentId, out serverURI); - note.UserId = remoteClient.AgentId; - UUID.TryParse(args[0], out note.TargetId); + if(string.IsNullOrWhiteSpace(serverURI)) + { + remoteClient.SendAvatarNotesReply(note.TargetId, note.Notes); + return; + } object Note = (object)note; if(!rpc.JsonRpcRequest(ref Note, "avatarnotesrequest", serverURI, UUID.Random().ToString())) @@ -836,7 +1147,6 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return; } note = (UserProfileNotes) Note; - remoteClient.SendAvatarNotesReply(note.TargetId, note.Notes); } @@ -854,6 +1164,14 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles /// public void NotesUpdate(IClientAPI remoteClient, UUID queryTargetID, string queryNotes) { + ScenePresence p = FindPresence(queryTargetID); + if (p != null && p.IsNPC) + { + remoteClient.SendAgentAlertMessage( + "Notes for NPCs not available", false); + return; + } + UserProfileNotes note = new UserProfileNotes(); note.UserId = remoteClient.AgentId; @@ -862,6 +1180,8 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles string serverURI = string.Empty; GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + if(string.IsNullOrWhiteSpace(serverURI)) + return; object Note = note; if(!rpc.JsonRpcRequest(ref Note, "avatar_notes_update", serverURI, UUID.Random().ToString())) @@ -873,6 +1193,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles } #endregion Notes + #region User Preferences /// /// Updates the user preferences. @@ -896,16 +1217,18 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles string serverURI = string.Empty; bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + if(string.IsNullOrWhiteSpace(serverURI)) + return; object Pref = pref; if(!rpc.JsonRpcRequest(ref Pref, "user_preferences_update", serverURI, UUID.Random().ToString())) { m_log.InfoFormat("[PROFILES]: UserPreferences update error"); remoteClient.SendAgentAlertMessage("Error updating preferences", false); - return; + return; } } - + /// /// Users the preferences request. /// @@ -920,7 +1243,8 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles string serverURI = string.Empty; bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); - + if(string.IsNullOrWhiteSpace(serverURI)) + return; object Pref = (object)pref; if(!rpc.JsonRpcRequest(ref Pref, "user_preferences_request", serverURI, UUID.Random().ToString())) @@ -932,7 +1256,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles pref = (UserPreferences) Pref; remoteClient.SendUserInfoReply(pref.IMViaEmail, pref.Visible, pref.EMail); - + } #endregion User Preferences @@ -960,6 +1284,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles /// public void AvatarInterestsUpdate(IClientAPI remoteClient, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages) { + UserProfileProperties prop = new UserProfileProperties(); prop.UserId = remoteClient.AgentId; @@ -971,6 +1296,8 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles string serverURI = string.Empty; GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + if(string.IsNullOrWhiteSpace(serverURI)) + return; object Param = prop; if(!rpc.JsonRpcRequest(ref Param, "avatar_interests_update", serverURI, UUID.Random().ToString())) @@ -979,6 +1306,17 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles "Error updating interests", false); return; } + + // flush cache + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) + { + uce.props = null; + } + } + } public void RequestAvatarProperties(IClientAPI remoteClient, UUID avatarID) @@ -990,13 +1328,55 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return; } - // Can't handle NPC yet... ScenePresence p = FindPresence(avatarID); - - if (null != p) + if (p != null && p.IsNPC) { - if (p.PresenceType == PresenceType.Npc) - return; + remoteClient.SendAvatarProperties(avatarID, ((INPC)(p.ControllingClient)).profileAbout, ((INPC)(p.ControllingClient)).Born, + Utils.StringToBytes("Non Player Character (NPC)"), "NPCs have no life", 0x10, + UUID.Zero, ((INPC)(p.ControllingClient)).profileImage, "", UUID.Zero); + remoteClient.SendAvatarInterestsReply(avatarID, 0, "", + 0, "Getting into trouble", "Droidspeak"); + return; + } + UserProfileProperties props; + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(avatarID, out uce) && uce != null) + { + if(uce.props != null) + { + props = uce.props; + uint cflags = uce.flags; + // if on same region force online + if(p != null && !p.IsDeleted) + cflags |= 0x10; + + remoteClient.SendAvatarProperties(props.UserId, props.AboutText, + uce.born, uce.membershipType , props.FirstLifeText, cflags, + props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId); + + remoteClient.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, + props.WantToText, (uint)props.SkillsMask, + props.SkillsText, props.Language); + return; + } + else + { + if(uce.ClientsWaitingProps == null) + uce.ClientsWaitingProps = new HashSet(); + else if(uce.ClientsWaitingProps.Contains(remoteClient)) + return; + uce.ClientsWaitingProps.Add(remoteClient); + } + } + else + { + uce = new UserProfileCacheEntry(); + uce.ClientsWaitingProps = new HashSet(); + uce.ClientsWaitingProps.Add(remoteClient); + m_profilesCache.AddOrUpdate(avatarID, uce, PROFILECACHEEXPIRE); + } } string serverURI = string.Empty; @@ -1014,20 +1394,16 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles userInfo = new Dictionary(); } - Byte[] charterMember = new Byte[1]; - string born = String.Empty; + Byte[] membershipType = new Byte[1]; + string born = string.Empty; uint flags = 0x00; if (null != account) { if (account.UserTitle == "") - { - charterMember[0] = (Byte)((account.UserFlags & 0xf00) >> 8); - } + membershipType[0] = (Byte)((account.UserFlags & 0xf00) >> 8); else - { - charterMember = Utils.StringToBytes(account.UserTitle); - } + membershipType = Utils.StringToBytes(account.UserTitle); born = Util.ToDateTime(account.Created).ToString( "M/d/yyyy", CultureInfo.InvariantCulture); @@ -1038,16 +1414,13 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if (GetUserAccountData(avatarID, out userInfo) == true) { if ((string)userInfo["user_title"] == "") - { - charterMember[0] = (Byte)(((Byte)userInfo["user_flags"] & 0xf00) >> 8); - } + membershipType[0] = (Byte)(((Byte)userInfo["user_flags"] & 0xf00) >> 8); else - { - charterMember = Utils.StringToBytes((string)userInfo["user_title"]); - } + membershipType = Utils.StringToBytes((string)userInfo["user_title"]); int val_born = (int)userInfo["user_created"]; - born = Util.ToDateTime(val_born).ToString( + if(val_born != 0) + born = Util.ToDateTime(val_born).ToString( "M/d/yyyy", CultureInfo.InvariantCulture); // picky, picky @@ -1056,23 +1429,60 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles } } - UserProfileProperties props = new UserProfileProperties(); + props = new UserProfileProperties(); + props.UserId = avatarID; + string result = string.Empty; + if(!GetProfileData(ref props, foreign, serverURI, out result)) + { + props.AboutText ="Profile not available at this time. User may still be unknown to this grid"; + } - props.UserId = avatarID; + if(!m_allowUserProfileWebURLs) + props.WebUrl =""; - if (!GetProfileData(ref props, foreign, out result)) + HashSet clients; + lock(m_profilesCache) { -// m_log.DebugFormat("Error getting profile for {0}: {1}", avatarID, result); - return; + if(!m_profilesCache.TryGetValue(props.UserId, out uce) || uce == null) + uce = new UserProfileCacheEntry(); + uce.props = props; + uce.born = born; + uce.membershipType = membershipType; + uce.flags = flags; + clients = uce.ClientsWaitingProps; + uce.ClientsWaitingProps = null; + m_profilesCache.AddOrUpdate(props.UserId, uce, PROFILECACHEEXPIRE); } - remoteClient.SendAvatarProperties(props.UserId, props.AboutText, born, charterMember , props.FirstLifeText, flags, + // if on same region force online + if(p != null && !p.IsDeleted) + flags |= 0x10; + + if(clients == null) + { + remoteClient.SendAvatarProperties(props.UserId, props.AboutText, born, membershipType , props.FirstLifeText, flags, props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId); + remoteClient.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, props.WantToText, + (uint)props.SkillsMask, props.SkillsText, props.Language); + } + else + { + if(!clients.Contains(remoteClient)) + clients.Add(remoteClient); + foreach(IClientAPI cli in clients) + { + if(!cli.IsActive) + continue; + cli.SendAvatarProperties(props.UserId, props.AboutText, born, membershipType , props.FirstLifeText, flags, + props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId); + + cli.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, props.WantToText, + (uint)props.SkillsMask, props.SkillsText, props.Language); - remoteClient.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, props.WantToText, (uint)props.SkillsMask, - props.SkillsText, props.Language); + } + } } /// @@ -1088,6 +1498,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { if (remoteClient.AgentId == newProfile.ID) { + UserProfileProperties prop = new UserProfileProperties(); prop.UserId = remoteClient.AgentId; @@ -1097,6 +1508,9 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles prop.FirstLifeImageId = newProfile.FirstLifeImage; prop.FirstLifeText = newProfile.FirstLifeAboutText; + if(!m_allowUserProfileWebURLs) + prop.WebUrl =""; + string serverURI = string.Empty; GetUserProfileServerURI(remoteClient.AgentId, out serverURI); @@ -1109,6 +1523,16 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return; } + // flush cache + UserProfileCacheEntry uce = null; + lock(m_profilesCache) + { + if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce != null) + { + uce.props = null; + } + } + RequestAvatarProperties(remoteClient, newProfile.ID); } } @@ -1119,28 +1543,11 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles /// /// The profile data. /// - bool GetProfileData(ref UserProfileProperties properties, bool foreign, out string message) + bool GetProfileData(ref UserProfileProperties properties, bool foreign, string serverURI, out string message) { - // Can't handle NPC yet... - ScenePresence p = FindPresence(properties.UserId); - - if (null != p) - { - if (p.PresenceType == PresenceType.Npc) - { - message = "Id points to NPC"; - return false; - } - } - - string serverURI = string.Empty; - GetUserProfileServerURI(properties.UserId, out serverURI); - - // This is checking a friend on the home grid - // Not HG friend if (String.IsNullOrEmpty(serverURI)) { - message = "No Presence - foreign friend"; + message = "User profile service unknown at this time"; return false; } @@ -1161,7 +1568,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { m_log.Debug( string.Format( - "[PROFILES]: Request using the OpenProfile API for user {0} to {1} failed", + "[PROFILES]: Request using the OpenProfile API for user {0} to {1} failed", properties.UserId, serverURI), e); @@ -1178,10 +1585,14 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return false; } - // else, continue below } - + properties = (UserProfileProperties)Prop; + if(foreign) + { + cacheForeignImage(properties.UserId, properties.ImageId); + cacheForeignImage(properties.UserId, properties.FirstLifeImageId); + } message = "Success"; return true; @@ -1189,49 +1600,6 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles #endregion Avatar Properties #region Utils - bool GetImageAssets(UUID avatarId) - { - string profileServerURI = string.Empty; - string assetServerURI = string.Empty; - - bool foreign = GetUserProfileServerURI(avatarId, out profileServerURI); - - if(!foreign) - return true; - - assetServerURI = UserManagementModule.GetUserServerURL(avatarId, "AssetServerURI"); - - if(string.IsNullOrEmpty(profileServerURI) || string.IsNullOrEmpty(assetServerURI)) - return false; - - OSDMap parameters= new OSDMap(); - parameters.Add("avatarId", OSD.FromUUID(avatarId)); - OSD Params = (OSD)parameters; - if(!rpc.JsonRpcRequest(ref Params, "image_assets_request", profileServerURI, UUID.Random().ToString())) - { - return false; - } - - parameters = (OSDMap)Params; - - if (parameters.ContainsKey("result")) - { - OSDArray list = (OSDArray)parameters["result"]; - - foreach (OSD asset in list) - { - OSDString assetId = (OSDString)asset; - - Scene.AssetService.Get(string.Format("{0}/{1}", assetServerURI, assetId.AsString())); - } - return true; - } - else - { - m_log.ErrorFormat("[PROFILES]: Problematic response for image_assets_request from {0}", profileServerURI); - return false; - } - } /// /// Gets the user account data. @@ -1336,7 +1704,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { bool local; local = UserManagementModule.IsLocalGridUser(userID); - + if (!local) { serverURI = UserManagementModule.GetUserServerURL(userID, "GatekeeperURI"); @@ -1382,6 +1750,27 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles } } + void cacheForeignImage(UUID agent, UUID imageID) + { + if(imageID == null || imageID == UUID.Zero) + return; + + string assetServerURI = UserManagementModule.GetUserServerURL(agent, "AssetServerURI"); + if(string.IsNullOrWhiteSpace(assetServerURI)) + return; + + string imageIDstr = imageID.ToString(); + + + if(m_assetCache != null && m_assetCache.Check(imageIDstr)) + return; + + if(Scene.AssetService.Get(imageIDstr) != null) + return; + + Scene.AssetService.Get(string.Format("{0}/{1}", assetServerURI, imageIDstr)); + } + /// /// Finds the presence. /// @@ -1402,5 +1791,180 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return null; } #endregion Util + + #region Web Util + /// + /// 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. + /// + 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"); + + // Prep our payload + OSDMap json = new OSDMap(); + + json.Add("jsonrpc", OSD.FromString("2.0")); + json.Add("id", OSD.FromString(jsonId)); + json.Add("method", OSD.FromString(method)); + + json.Add("params", OSD.SerializeMembers(parameters)); + + string jsonRequestData = OSDParser.SerializeJsonString(json); + byte[] content = Encoding.UTF8.GetBytes(jsonRequestData); + + HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri); + + webRequest.ContentType = "application/json-rpc"; + webRequest.Method = "POST"; + + WebResponse webResponse = null; + try + { + using(Stream dataStream = webRequest.GetRequestStream()) + dataStream.Write(content,0,content.Length); + + webResponse = webRequest.GetResponse(); + } + catch (WebException e) + { + Console.WriteLine("Web Error" + e.Message); + Console.WriteLine ("Please check input"); + return false; + } + + OSDMap mret = new OSDMap(); + + using (Stream rstream = webResponse.GetResponseStream()) + { + try + { + mret = (OSDMap)OSDParser.DeserializeJson(rstream); + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES]: JsonRpcRequest Error {0} - remote user with legacy profiles?", e.Message); + if (webResponse != null) + webResponse.Close(); + return false; + } + } + + if (webResponse != null) + webResponse.Close(); + + if (mret.ContainsKey("error")) + return false; + + // get params... + OSD.DeserializeMembers(ref parameters, (OSDMap) mret["result"]); + return true; + } + + /// + /// Sends json-rpc request with OSD parameter. + /// + /// + /// The rpc request. + /// + /// + /// data - incoming as parameters, outgong as result/error + /// + /// + /// Json-rpc method to call. + /// + /// + /// URI of json-rpc service. + /// + /// + /// If set to true json identifier. + /// + bool JsonRpcRequest(ref OSD data, string method, string uri, string jsonId) + { + OSDMap map = new OSDMap(); + + map["jsonrpc"] = "2.0"; + if(string.IsNullOrEmpty(jsonId)) + map["id"] = UUID.Random().ToString(); + else + map["id"] = jsonId; + + map["method"] = method; + map["params"] = data; + + string jsonRequestData = OSDParser.SerializeJsonString(map); + byte[] content = Encoding.UTF8.GetBytes(jsonRequestData); + + HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri); + webRequest.ContentType = "application/json-rpc"; + webRequest.Method = "POST"; + + WebResponse webResponse = null; + try + { + using(Stream dataStream = webRequest.GetRequestStream()) + dataStream.Write(content,0,content.Length); + + webResponse = webRequest.GetResponse(); + } + catch (WebException e) + { + Console.WriteLine("Web Error" + e.Message); + Console.WriteLine ("Please check input"); + return false; + } + + OSDMap response = new OSDMap(); + + using (Stream rstream = webResponse.GetResponseStream()) + { + try + { + response = (OSDMap)OSDParser.DeserializeJson(rstream); + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES]: JsonRpcRequest Error {0} - remote user with legacy profiles?", e.Message); + if (webResponse != null) + webResponse.Close(); + return false; + } + } + + if (webResponse != null) + webResponse.Close(); + + if(response.ContainsKey("error")) + { + data = response["error"]; + return false; + } + + data = response; + + return true; + } + #endregion Web Util } } diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs index 817ef85..c0afe7c 100644 --- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs @@ -47,23 +47,23 @@ namespace OpenSim.Region.CoreModules.Framework { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "CapabilitiesModule")] public class CapabilitiesModule : INonSharedRegionModule, ICapabilitiesModule - { + { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private string m_showCapsCommandFormat = " {0,-38} {1,-60}\n"; - + protected Scene m_scene; - + /// /// Each agent has its own capabilities handler. /// - protected Dictionary m_capsObjects = new Dictionary(); - + protected Dictionary m_capsObjects = new Dictionary(); + protected Dictionary m_capsPaths = new Dictionary(); - protected Dictionary> m_childrenSeeds + protected Dictionary> m_childrenSeeds = new Dictionary>(); - + public void Initialise(IConfigSource source) { } @@ -101,16 +101,16 @@ namespace OpenSim.Region.CoreModules.Framework { m_scene.UnregisterModuleInterface(this); } - - public void PostInitialise() + + public void PostInitialise() { } public void Close() {} - public string Name - { - get { return "Capabilities Module"; } + public string Name + { + get { return "Capabilities Module"; } } public Type ReplaceableInterface @@ -118,23 +118,46 @@ namespace OpenSim.Region.CoreModules.Framework get { return null; } } - public void CreateCaps(UUID agentId) + public void CreateCaps(UUID agentId, uint circuitCode) { - if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId)) - return; + int ts = Util.EnvironmentTickCount(); +/* this as no business here... + * must be done elsewhere ( and is ) + int flags = m_scene.GetUserFlags(agentId); + + m_log.ErrorFormat("[CreateCaps]: banCheck {0} ", Util.EnvironmentTickCountSubtract(ts)); + if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId, flags)) + return; +*/ Caps caps; String capsObjectPath = GetCapsPath(agentId); lock (m_capsObjects) { - if (m_capsObjects.ContainsKey(agentId)) + if (m_capsObjects.ContainsKey(circuitCode)) { - Caps oldCaps = m_capsObjects[agentId]; - - //m_log.WarnFormat( - // "[CAPS]: Recreating caps for agent {0} in region {1}. Old caps path {2}, new caps path {3}. ", - // agentId, m_scene.RegionInfo.RegionName, oldCaps.CapsObjectPath, capsObjectPath); + Caps oldCaps = m_capsObjects[circuitCode]; + + + if (capsObjectPath == oldCaps.CapsObjectPath) + { +// m_log.WarnFormat( +// "[CAPS]: Reusing caps for agent {0} in region {1}. Old caps path {2}, new caps path {3}. ", +// agentId, m_scene.RegionInfo.RegionName, oldCaps.CapsObjectPath, capsObjectPath); + return; + } + else + { + // not reusing add extra melanie cleanup + // Remove tge handlers. They may conflict with the + // new object created below + oldCaps.DeregisterHandlers(); + + // Better safe ... should not be needed but also + // no big deal + m_capsObjects.Remove(circuitCode); + } } // m_log.DebugFormat( @@ -145,13 +168,17 @@ namespace OpenSim.Region.CoreModules.Framework (MainServer.Instance == null) ? 0: MainServer.Instance.Port, capsObjectPath, agentId, m_scene.RegionInfo.RegionName); - m_capsObjects[agentId] = caps; - } + m_log.DebugFormat("[CreateCaps]: new caps agent {0}, circuit {1}, path {2}, time {3} ",agentId, + circuitCode,caps.CapsObjectPath, Util.EnvironmentTickCountSubtract(ts)); + m_capsObjects[circuitCode] = caps; + } m_scene.EventManager.TriggerOnRegisterCaps(agentId, caps); +// m_log.ErrorFormat("[CreateCaps]: end {0} ", Util.EnvironmentTickCountSubtract(ts)); + } - public void RemoveCaps(UUID agentId) + public void RemoveCaps(UUID agentId, uint circuitCode) { m_log.DebugFormat("[CAPS]: Remove caps for agent {0} in region {1}", agentId, m_scene.RegionInfo.RegionName); lock (m_childrenSeeds) @@ -164,44 +191,65 @@ namespace OpenSim.Region.CoreModules.Framework lock (m_capsObjects) { - if (m_capsObjects.ContainsKey(agentId)) + if (m_capsObjects.ContainsKey(circuitCode)) { - m_capsObjects[agentId].DeregisterHandlers(); - m_scene.EventManager.TriggerOnDeregisterCaps(agentId, m_capsObjects[agentId]); - m_capsObjects.Remove(agentId); + m_capsObjects[circuitCode].DeregisterHandlers(); + m_scene.EventManager.TriggerOnDeregisterCaps(agentId, m_capsObjects[circuitCode]); + m_capsObjects.Remove(circuitCode); } else { + foreach (KeyValuePair kvp in m_capsObjects) + { + if (kvp.Value.AgentID == agentId) + { + kvp.Value.DeregisterHandlers(); + m_scene.EventManager.TriggerOnDeregisterCaps(agentId, kvp.Value); + m_capsObjects.Remove(kvp.Key); + return; + } + } m_log.WarnFormat( "[CAPS]: Received request to remove CAPS handler for root agent {0} in {1}, but no such CAPS handler found!", agentId, m_scene.RegionInfo.RegionName); } } } - - public Caps GetCapsForUser(UUID agentId) + + public Caps GetCapsForUser(uint circuitCode) { lock (m_capsObjects) { - if (m_capsObjects.ContainsKey(agentId)) + if (m_capsObjects.ContainsKey(circuitCode)) { - return m_capsObjects[agentId]; + return m_capsObjects[circuitCode]; } } - + return null; } - + + public void ActivateCaps(uint circuitCode) + { + lock (m_capsObjects) + { + if (m_capsObjects.ContainsKey(circuitCode)) + { + m_capsObjects[circuitCode].Activate(); + } + } + } + public void SetAgentCapsSeeds(AgentCircuitData agent) { lock (m_capsPaths) m_capsPaths[agent.AgentID] = agent.CapsPath; lock (m_childrenSeeds) - m_childrenSeeds[agent.AgentID] + m_childrenSeeds[agent.AgentID] = ((agent.ChildrenCapSeeds == null) ? new Dictionary() : agent.ChildrenCapSeeds); } - + public string GetCapsPath(UUID agentId) { lock (m_capsPaths) @@ -214,7 +262,7 @@ namespace OpenSim.Region.CoreModules.Framework return null; } - + public Dictionary GetChildrenSeeds(UUID agentID) { Dictionary seeds = null; @@ -289,9 +337,9 @@ namespace OpenSim.Region.CoreModules.Framework lock (m_capsObjects) { - foreach (KeyValuePair kvp in m_capsObjects) + foreach (KeyValuePair kvp in m_capsObjects) { - capsReport.AppendFormat("** User {0}:\n", kvp.Key); + capsReport.AppendFormat("** Circuit {0}:\n", kvp.Key); Caps caps = kvp.Value; for (IDictionaryEnumerator kvp2 = caps.CapsHandlers.GetCapsDetails(false, null).GetEnumerator(); kvp2.MoveNext(); ) @@ -339,6 +387,7 @@ namespace OpenSim.Region.CoreModules.Framework private void BuildDetailedStatsByCapReport(StringBuilder sb, string capName) { + /* sb.AppendFormat("Capability name {0}\n", capName); ConsoleDisplayTable cdt = new ConsoleDisplayTable(); @@ -365,8 +414,8 @@ namespace OpenSim.Region.CoreModules.Framework { receivedStats[sp.Name] = reqHandler.RequestsReceived; handledStats[sp.Name] = reqHandler.RequestsHandled; - } - else + } + else { PollServiceEventArgs pollHandler = null; if (caps.TryGetPollHandler(capName, out pollHandler)) @@ -384,10 +433,12 @@ namespace OpenSim.Region.CoreModules.Framework } sb.Append(cdt.ToString()); + */ } private void BuildSummaryStatsByCapReport(StringBuilder sb) { + /* ConsoleDisplayTable cdt = new ConsoleDisplayTable(); cdt.AddColumn("Name", 34); cdt.AddColumn("Req Received", 12); @@ -403,7 +454,7 @@ namespace OpenSim.Region.CoreModules.Framework Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID); if (caps == null) - return; + return; foreach (IRequestHandler reqHandler in caps.CapsHandlers.GetCapsHandlers().Values) { @@ -439,15 +490,17 @@ namespace OpenSim.Region.CoreModules.Framework } } ); - + foreach (KeyValuePair kvp in receivedStats.OrderByDescending(kp => kp.Value)) cdt.AddRow(kvp.Key, kvp.Value, handledStats[kvp.Key]); sb.Append(cdt.ToString()); + */ } private void HandleShowCapsStatsByUserCommand(string module, string[] cmdParams) { + /* if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) return; @@ -478,10 +531,12 @@ namespace OpenSim.Region.CoreModules.Framework } MainConsole.Instance.Output(sb.ToString()); + */ } private void BuildDetailedStatsByUserReport(StringBuilder sb, ScenePresence sp) { + /* sb.AppendFormat("Avatar name {0}, type {1}\n", sp.Name, sp.IsChildAgent ? "child" : "root"); ConsoleDisplayTable cdt = new ConsoleDisplayTable(); @@ -504,13 +559,15 @@ namespace OpenSim.Region.CoreModules.Framework capRows.Add(new CapTableRow(kvp.Key, kvp.Value.RequestsReceived, kvp.Value.RequestsHandled)); foreach (CapTableRow ctr in capRows.OrderByDescending(ctr => ctr.RequestsReceived)) - cdt.AddRow(ctr.Name, ctr.RequestsReceived, ctr.RequestsHandled); + cdt.AddRow(ctr.Name, ctr.RequestsReceived, ctr.RequestsHandled); sb.Append(cdt.ToString()); + */ } private void BuildSummaryStatsByUserReport(StringBuilder sb) { + /* ConsoleDisplayTable cdt = new ConsoleDisplayTable(); cdt.AddColumn("Name", 32); cdt.AddColumn("Type", 5); @@ -544,12 +601,13 @@ namespace OpenSim.Region.CoreModules.Framework totalRequestsReceived += handler.RequestsReceived; totalRequestsHandled += handler.RequestsHandled; } - + cdt.AddRow(sp.Name, sp.IsChildAgent ? "child" : "root", totalRequestsReceived, totalRequestsHandled); } ); sb.Append(cdt.ToString()); + */ } private class CapTableRow @@ -566,4 +624,4 @@ namespace OpenSim.Region.CoreModules.Framework } } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs index 0c632b1..d652f43 100644 --- a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs @@ -53,12 +53,12 @@ namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule protected Scene m_scene; protected IDialogModule m_dialogMod; - - public string Name { get { return "DAExample Module"; } } - public Type ReplaceableInterface { get { return null; } } + + public string Name { get { return "DAExample Module"; } } + public Type ReplaceableInterface { get { return null; } } public void Initialise(IConfigSource source) {} - + public void AddRegion(Scene scene) { if (ENABLED) @@ -70,22 +70,22 @@ namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule m_log.DebugFormat("[DA EXAMPLE MODULE]: Added region {0}", m_scene.Name); } } - - public void RemoveRegion(Scene scene) + + public void RemoveRegion(Scene scene) { if (ENABLED) { m_scene.EventManager.OnSceneGroupMove -= OnSceneGroupMove; } } - + public void RegionLoaded(Scene scene) {} - - public void Close() + + public void Close() { RemoveRegion(m_scene); } - + protected bool OnSceneGroupMove(UUID groupId, Vector3 delta) { OSDMap attrs = null; @@ -96,28 +96,28 @@ namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule if (!sop.DynAttrs.TryGetStore(Namespace, StoreName, out attrs)) attrs = new OSDMap(); - + OSDInteger newValue; // We have to lock on the entire dynamic attributes map to avoid race conditions with serialization code. - lock (sop.DynAttrs) + lock (sop.DynAttrs) { if (!attrs.ContainsKey("moves")) newValue = new OSDInteger(1); else newValue = new OSDInteger(attrs["moves"].AsInteger() + 1); - + attrs["moves"] = newValue; sop.DynAttrs.SetStore(Namespace, StoreName, attrs); } sop.ParentGroup.HasGroupChanged = true; - + string msg = string.Format("{0} {1} moved {2} times", sop.Name, sop.UUID, newValue); m_log.DebugFormat("[DA EXAMPLE MODULE]: {0}", msg); m_dialogMod.SendGeneralAlert(msg); - + return true; } } diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs index 166a994..3364cbc 100644 --- a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs @@ -65,11 +65,11 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule private Scene m_scene; private IDialogModule m_dialogMod; - public string Name { get { return "DO"; } } - public Type ReplaceableInterface { get { return null; } } + public string Name { get { return "DO"; } } + public Type ReplaceableInterface { get { return null; } } public void Initialise(IConfigSource source) {} - + public void AddRegion(Scene scene) { if (ENABLED) @@ -80,18 +80,18 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule m_dialogMod = m_scene.RequestModuleInterface(); } } - - public void RemoveRegion(Scene scene) + + public void RemoveRegion(Scene scene) { if (ENABLED) { m_scene.EventManager.OnSceneGroupMove -= OnSceneGroupMove; } } - + public void RegionLoaded(Scene scene) {} - - public void Close() + + public void Close() { RemoveRegion(m_scene); } @@ -116,7 +116,7 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule rootPart.DynObjs.Add(DAExampleModule.Namespace, Name, new MyObject(movesSoFar)); } - + private bool OnSceneGroupMove(UUID groupId, Vector3 delta) { SceneObjectGroup so = m_scene.GetSceneObjectGroup(groupId); @@ -129,11 +129,11 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule if (rawObj != null) { MyObject myObj = (MyObject)rawObj; - + m_dialogMod.SendGeneralAlert(string.Format("{0} {1} moved {2} times", so.Name, so.UUID, ++myObj.Moves)); } - + return true; - } + } } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 1b4b5e6..2334e0b 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -54,9 +54,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly string LogHeader = "[ENTITY TRANSFER MODULE]"; + public const int DefaultMaxTransferDistance = 4095; public const bool WaitForAgentArrivedAtDestinationDefault = true; /// + /// The maximum distance, in standard region units (256m) that an agent is allowed to transfer. + /// + public int MaxTransferDistance { get; set; } + + /// /// If true then on a teleport, the source region waits for a callback from the destination region. If /// a callback fails to arrive within a set time then the user is pulled back into the source region. /// @@ -66,9 +72,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// If true then we ask the viewer to disable teleport cancellation and ignore teleport requests. /// /// - /// This is useful in situations where teleport is very likely to always succeed and we want to avoid a + /// This is useful in situations where teleport is very likely to always succeed and we want to avoid a /// situation where avatars can be come 'stuck' due to a failed teleport cancellation. Unfortunately, the - /// nature of the teleport protocol makes it extremely difficult (maybe impossible) to make teleport + /// nature of the teleport protocol makes it extremely difficult (maybe impossible) to make teleport /// cancellation consistently suceed. /// public bool DisableInterRegionTeleportCancellation { get; set; } @@ -130,7 +136,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { if (m_idCache.TryGetValue(pRegionHandle, out m_banUntil)) { - if (DateTime.Now < m_banUntil) + if (DateTime.UtcNow < m_banUntil) { ret = true; } @@ -141,13 +147,19 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Add this agent in this region as a banned person public void Add(ulong pRegionHandle, UUID pAgentID) { + this.Add(pRegionHandle, pAgentID, 45, 15); + } + + public void Add(ulong pRegionHandle, UUID pAgentID, double newTime, double extendTime) + { if (!m_bannedRegions.TryGetValue(pAgentID, out m_idCache)) { m_idCache = new ExpiringCache(); - m_bannedRegions.Add(pAgentID, m_idCache, TimeSpan.FromSeconds(45)); + m_bannedRegions.Add(pAgentID, m_idCache, TimeSpan.FromSeconds(newTime)); } - m_idCache.Add(pRegionHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15)); + m_idCache.Add(pRegionHandle, DateTime.UtcNow + TimeSpan.FromSeconds(extendTime), extendTime); } + // Remove the agent from the region's banned list public void Remove(ulong pRegionHandle, UUID pAgentID) { @@ -157,10 +169,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } } } + private BannedRegionCache m_bannedRegionCache = new BannedRegionCache(); private IEventQueue m_eqModule; - private IRegionCombinerModule m_regionCombinerModule; #region ISharedRegionModule @@ -209,11 +221,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer IConfig transferConfig = source.Configs["EntityTransfer"]; if (transferConfig != null) { - DisableInterRegionTeleportCancellation + DisableInterRegionTeleportCancellation = transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false); WaitForAgentArrivedAtDestination = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault); + + MaxTransferDistance = transferConfig.GetInt("max_distance", DefaultMaxTransferDistance); + } + else + { + MaxTransferDistance = DefaultMaxTransferDistance; } m_entityTransferStateMachine = new EntityTransferStateMachine(this); @@ -232,7 +250,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer Scene = scene; - m_interRegionTeleportAttempts = + m_interRegionTeleportAttempts = new Stat( "InterRegionTeleportAttempts", "Number of inter-region teleports attempted.", @@ -245,7 +263,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer null, StatVerbosity.Debug); - m_interRegionTeleportAborts = + m_interRegionTeleportAborts = new Stat( "InterRegionTeleportAborts", "Number of inter-region teleports aborted due to client actions.", @@ -257,7 +275,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer null, StatVerbosity.Debug); - m_interRegionTeleportCancels = + m_interRegionTeleportCancels = new Stat( "InterRegionTeleportCancels", "Number of inter-region teleports cancelled by the client.", @@ -269,7 +287,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer null, StatVerbosity.Debug); - m_interRegionTeleportFailures = + m_interRegionTeleportFailures = new Stat( "InterRegionTeleportFailures", "Number of inter-region teleports that failed due to server/client/network issues.", @@ -303,7 +321,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer public virtual void Close() {} - public virtual void RemoveRegion(Scene scene) + public virtual void RemoveRegion(Scene scene) { if (m_Enabled) { @@ -320,7 +338,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return; m_eqModule = Scene.RequestModuleInterface(); - m_regionCombinerModule = Scene.RequestModuleInterface(); } #endregion @@ -332,7 +349,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (client.IsLoggingOut && m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting)) { m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout", + "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout", client.Name, Scene.Name); } } @@ -354,7 +371,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer teleportFlags |= (uint)TeleportFlags.Godlike; } - if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) + else if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) return; string destinationRegionName = "(not found)"; @@ -374,17 +391,27 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer try { - // Reset animations; the viewer does that in teleports. - sp.Animator.ResetAnimations(); if (regionHandle == sp.Scene.RegionInfo.RegionHandle) { + if(!sp.AllowMovement) + { + sp.ControllingClient.SendTeleportFailed("You are frozen"); + m_entityTransferStateMachine.ResetFromTransit(sp.UUID); + return; + } + + // Reset animations; the viewer does that in teleports. + sp.Animator.ResetAnimations(); destinationRegionName = sp.Scene.RegionInfo.RegionName; TeleportAgentWithinRegion(sp, position, lookAt, teleportFlags); } else // Another region possibly in another simulator { + // Reset animations; the viewer does that in teleports. + sp.Animator.ResetAnimations(); + GridRegion finalDestination = null; try { @@ -400,12 +427,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } catch (Exception e) { + m_log.ErrorFormat( "[ENTITY TRANSFER MODULE]: Exception on teleport of {0} from {1}@{2} to {3}@{4}: {5}{6}", sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName, e.Message, e.StackTrace); - - sp.ControllingClient.SendTeleportFailed("Internal error"); + if(sp != null && sp.ControllingClient != null && !sp.IsDeleted) + sp.ControllingClient.SendTeleportFailed("Internal error"); } finally { @@ -438,17 +466,25 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer position = emergencyPos; } + // Check Default Location (Also See ScenePresence.CompleteMovement) + if (position.X == 128f && position.Y == 128f && position.Z == 22.5f) + position = sp.Scene.RegionInfo.DefaultLandingPoint; + // TODO: Get proper AVG Height - float localAVHeight = 1.56f; + float localHalfAVHeight = 0.8f; + if (sp.Appearance != null) + localHalfAVHeight = sp.Appearance.AvatarHeight / 2; + float posZLimit = 22; // TODO: Check other Scene HeightField posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y]; - float newPosZ = posZLimit + localAVHeight; - if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) + posZLimit += localHalfAVHeight + 0.1f; + + if ((position.Z < posZLimit) && !(Single.IsInfinity(posZLimit) || Single.IsNaN(posZLimit))) { - position.Z = newPosZ; + position.Z = posZLimit; } if (sp.Flying) @@ -457,9 +493,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); sp.ControllingClient.SendTeleportStart(teleportFlags); + lookAt.Z = 0f; + + if(Math.Abs(lookAt.X) < 0.01f && Math.Abs(lookAt.Y) < 0.01f) + { + lookAt.X = 1.0f; + lookAt.Y = 0; + } sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); sp.TeleportFlags = (Constants.TeleportFlags)teleportFlags; + sp.RotateToLookAt(lookAt); sp.Velocity = Vector3.Zero; sp.Teleport(position); @@ -494,15 +538,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { string homeURI = Scene.GetAgentHomeURI(sp.ControllingClient.AgentId); - string message; - finalDestination = GetFinalDestination(reg, sp.ControllingClient.AgentId, homeURI, out message); + string reason = String.Empty; + finalDestination = GetFinalDestination(reg, sp.ControllingClient.AgentId, homeURI, out reason); if (finalDestination == null) { m_log.WarnFormat( "{0} Final destination is having problems. Unable to teleport {1} {2}: {3}", - LogHeader, sp.Name, sp.UUID, message); + LogHeader, sp.Name, sp.UUID, reason); - sp.ControllingClient.SendTeleportFailed(message); + sp.ControllingClient.SendTeleportFailed(reason); return; } @@ -515,17 +559,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return; } - // Validate assorted conditions - string reason = string.Empty; if (!ValidateGenericConditions(sp, reg, finalDestination, teleportFlags, out reason)) { sp.ControllingClient.SendTeleportFailed(reason); return; } - if (message != null) - sp.ControllingClient.SendAgentAlertMessage(message, true); - // // This is it // @@ -547,9 +586,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer Util.RegionHandleToRegionLoc(regionHandle, out regX, out regY); MapBlockData block = new MapBlockData(); - block.X = (ushort)regX; - block.Y = (ushort)regY; - block.Access = (byte)SimAccess.Down; + block.X = (ushort)(regX); + block.Y = (ushort)(regY); + block.Access = (byte)SimAccess.Down; // == not there List blocks = new List(); blocks.Add(block); @@ -565,12 +604,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer uint x = 0, y = 0; Util.RegionHandleToWorldLoc(regionHandle, out x, out y); + GridRegion reg; + + // handle legacy HG. linked regions are mapped into y = 0 and have no size information + // so we can only search by base handle + if( y == 0) + { + reg = gridService.GetRegionByPosition(scope, (int)x, (int)y); + return reg; + } + // Compute the world location we're teleporting to double worldX = (double)x + position.X; double worldY = (double)y + position.Y; // Find the region that contains the position - GridRegion reg = GetRegionContainingWorldLocation(gridService, scope, worldX, worldY); + reg = GetRegionContainingWorldLocation(gridService, scope, worldX, worldY); if (reg != null) { @@ -589,6 +638,28 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return true; } + /// + /// Determines whether this instance is within the max transfer distance. + /// + /// + /// + /// + /// true if this instance is within max transfer distance; otherwise, false. + /// + private bool IsWithinMaxTeleportDistance(RegionInfo sourceRegion, GridRegion destRegion) + { + if(MaxTransferDistance == 0) + return true; + +// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY); +// +// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}", +// destRegionX, destRegionY, finalDestination.RegionID, finalDestination.ServerURI); + + // Insanely, RegionLoc on RegionInfo is the 256m map co-ord whilst GridRegion.RegionLoc is the raw meters position. + return Math.Abs(sourceRegion.RegionLocX - destRegion.RegionCoordX) <= MaxTransferDistance + && Math.Abs(sourceRegion.RegionLocY - destRegion.RegionCoordY) <= MaxTransferDistance; + } /// /// Wraps DoTeleportInternal() and manages the transfer state. @@ -607,7 +678,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.ControllingClient.SendTeleportFailed("Agent is already in transit."); return; } - + try { DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags); @@ -650,10 +721,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer RegionInfo sourceRegion = sp.Scene.RegionInfo; + if (!IsWithinMaxTeleportDistance(sourceRegion, finalDestination)) + { + sp.ControllingClient.SendTeleportFailed( + string.Format( + "Can't teleport to {0} ({1},{2}) from {3} ({4},{5}), destination is more than {6} regions way", + finalDestination.RegionName, finalDestination.RegionCoordX, finalDestination.RegionCoordY, + sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY, + MaxTransferDistance)); - uint newRegionX, newRegionY, oldRegionX, oldRegionY; - Util.RegionHandleToRegionLoc(reg.RegionHandle, out newRegionX, out newRegionY); - Util.RegionHandleToRegionLoc(sp.Scene.RegionInfo.RegionHandle, out oldRegionX, out oldRegionY); + return; + } ulong destinationHandle = finalDestination.RegionHandle; @@ -663,8 +741,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer IPEndPoint endPoint = finalDestination.ExternalEndPoint; if (endPoint == null || endPoint.Address == null) { - sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); - + sp.ControllingClient.SendTeleportFailed("Could not resolve destination Address"); return; } @@ -694,7 +771,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_interRegionTeleportAttempts.Value++; m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: {0} transfer protocol version to {1} is {2} / {3}", + "[ENTITY TRANSFER MODULE]: {0} transfer protocol version to {1} is {2} / {3}", sp.Scene.Name, finalDestination.RegionName, ctx.OutboundVersion, ctx.InboundVersion); // Fixing a bug where teleporting while sitting results in the avatar ending up removed from @@ -704,27 +781,25 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer else if (sp.Flying) teleportFlags |= (uint)TeleportFlags.IsFlying; + sp.IsInLocalTransit = finalDestination.RegionLocY != 0; // HG + sp.IsInTransit = true; + + if (DisableInterRegionTeleportCancellation) teleportFlags |= (uint)TeleportFlags.DisableCancel; // At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to // the viewer. However, it might mean that the viewer does not see the black teleport screen (untested). sp.ControllingClient.SendTeleportStart(teleportFlags); - - // the avatar.Close below will clear the child region list. We need this below for (possibly) - // closing the child agents, so save it here (we need a copy as it is Clear()-ed). - //List childRegions = avatar.KnownRegionHandles; - // Compared to ScenePresence.CrossToNewRegion(), there's no obvious code to handle a teleport - // failure at this point (unlike a border crossing failure). So perhaps this can never fail - // once we reach here... - //avatar.Scene.RemoveCapsHandler(avatar.UUID); - + AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo(); agentCircuit.startpos = position; agentCircuit.child = true; + agentCircuit.Appearance = new AvatarAppearance(); - agentCircuit.Appearance.PackLegacyWearables = true; + agentCircuit.Appearance.AvatarHeight = sp.Appearance.AvatarHeight; + if (currentAgentCircuit != null) { agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs; @@ -735,36 +810,64 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer agentCircuit.Id0 = currentAgentCircuit.Id0; } - // if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) - float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance, - (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY)); - if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY)) + uint newRegionX, newRegionY, oldRegionX, oldRegionY; + Util.RegionHandleToRegionLoc(destinationHandle, out newRegionX, out newRegionY); + Util.RegionHandleToRegionLoc(sourceRegion.RegionHandle, out oldRegionX, out oldRegionY); + int oldSizeX = (int)sourceRegion.RegionSizeX; + int oldSizeY = (int)sourceRegion.RegionSizeY; + int newSizeX = finalDestination.RegionSizeX; + int newSizeY = finalDestination.RegionSizeY; + + bool OutSideViewRange = NeedsNewAgent(sp.RegionViewDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, + oldSizeX, oldSizeY, newSizeX, newSizeY); + + if (OutSideViewRange) { - // brand new agent, let's create a new caps seed + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} size {3},{4} needs new child agent for agent {5} from {6}", + finalDestination.RegionName, newRegionX, newRegionY,newSizeX, newSizeY, sp.Name, Scene.Name); + + //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); } + else + { + agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle); + if (agentCircuit.CapsPath == null) + agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); + } // We're going to fallback to V1 if the destination gives us anything smaller than 0.2 if (ctx.OutboundVersion >= 0.2f) - TransferAgent_V2(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, ctx, out reason); + TransferAgent_V2(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, OutSideViewRange , ctx, out reason); else - TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, ctx, out reason); + TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, OutSideViewRange, ctx, out reason); } private void TransferAgent_V1(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination, - IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, EntityTransferContext ctx, out string reason) + IPEndPoint endPoint, uint teleportFlags, bool OutSideViewRange, EntityTransferContext ctx, out string reason) { ulong destinationHandle = finalDestination.RegionHandle; AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Using TP V1 for {0} going from {1} to {2}", + "[ENTITY TRANSFER MODULE]: Using TP V1 for {0} going from {1} to {2}", sp.Name, Scene.Name, finalDestination.RegionName); - // Let's create an agent there if one doesn't exist yet. + string capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); + List childRegionsToClose = sp.GetChildAgentsToClose(destinationHandle, finalDestination.RegionSizeX, finalDestination.RegionSizeY); + if(agentCircuit.ChildrenCapSeeds != null) + { + foreach(ulong handler in childRegionsToClose) + { + agentCircuit.ChildrenCapSeeds.Remove(handler); + } + } + + // Let's create an agent there if one doesn't exist yet. // NOTE: logout will always be false for a non-HG teleport. bool logout = false; - if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) + if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, ctx, out reason, out logout)) { m_interRegionTeleportFailures.Value++; @@ -773,7 +876,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); sp.ControllingClient.SendTeleportFailed(reason); - + sp.IsInTransit = false; return; } @@ -784,7 +887,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", sp.Name, finalDestination.RegionName, sp.Scene.Name); - + sp.IsInTransit = false; return; } else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) @@ -794,7 +897,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.", sp.Name, finalDestination.RegionName, sp.Scene.Name); - + sp.IsInTransit = false; return; } @@ -802,28 +905,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); // OK, it got this agent. Let's close some child agents - sp.CloseChildAgents(newRegionX, newRegionY); - IClientIPEndpoint ipepClient; - string capsPath = String.Empty; - float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance, - (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY)); - if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY)) + if (OutSideViewRange) { - m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for incoming agent {3} from {4}", - finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name); - - //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); - #region IP Translation for NAT - // Uses ipepClient above - if (sp.ClientView.TryGet(out ipepClient)) - { - endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); - } - #endregion - capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); - if (m_eqModule != null) { // The EnableSimulator message makes the client establish a connection with the destination @@ -853,22 +937,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); } } - else - { - agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle); - capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); - } // Let's send a full update of the agent. This is a synchronous call. AgentData agent = new AgentData(); - sp.CopyTo(agent); - if (ctx.OutboundVersion < 0.5f) - agent.Appearance.PackLegacyWearables = true; + sp.CopyTo(agent,false); + + if ((teleportFlags & (uint)TeleportFlags.IsFlying) != 0) + agent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; + agent.Position = agentCircuit.startpos; SetCallbackURL(agent, sp.Scene.RegionInfo); - - // We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to + // We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to // establish th econnection to the destination which makes it return true. if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) { @@ -877,15 +957,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent", sp.Name, finalDestination.RegionName, sp.Scene.Name); - + sp.IsInTransit = false; return; } - // A common teleport failure occurs when we can send CreateAgent to the + // A common teleport failure occurs when we can send CreateAgent to the // destination region but the viewer cannot establish the connection (e.g. due to network issues between // the viewer and the destination). In this case, UpdateAgent timesout after 10 seconds, although then // there's a further 10 second wait whilst we attempt to tell the destination to delete the agent in Fail(). - if (!UpdateAgent(reg, finalDestination, agent, sp)) + if (!UpdateAgent(reg, finalDestination, agent, sp, ctx)) { if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) { @@ -894,7 +974,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.", sp.Name, finalDestination.RegionName, sp.Scene.Name); - + sp.IsInTransit = false; return; } @@ -903,6 +983,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Name, finalDestination.RegionName, sp.Scene.Name); Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); + sp.IsInTransit = false; return; } @@ -915,7 +996,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Name, finalDestination.RegionName, sp.Scene.Name); CleanupFailedInterRegionTeleport(sp, currentAgentCircuit.SessionID.ToString(), finalDestination); - + sp.IsInTransit = false; return; } @@ -924,7 +1005,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator, - // where that neighbour simulator could otherwise request a child agent create on the source which then + // where that neighbour simulator could otherwise request a child agent create on the source which then // closes our existing agent which is still signalled as root. sp.IsChildAgent = true; @@ -952,7 +1033,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.", sp.Name, finalDestination.RegionName, sp.Scene.Name); - + sp.IsInTransit = false; return; } @@ -961,12 +1042,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Destination region did not signal teleport completion."); - + sp.IsInTransit = false; return; } - m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); - /* // TODO: This may be 0.6. Check if still needed // For backwards compatibility @@ -978,18 +1057,26 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } */ - // May need to logout or other cleanup + m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); + + if(logout) + sp.closeAllChildAgents(); + else + sp.CloseChildAgents(childRegionsToClose); + + // call HG hook AgentHasMovedAway(sp, logout); - // Well, this is it. The agent is over there. - KillEntity(sp.Scene, sp.LocalId); + sp.HasMovedAway(!(OutSideViewRange || logout)); - // Now let's make it officially a child agent - sp.MakeChildAgent(); +// ulong sourceRegionHandle = sp.RegionHandle; + + // Now let's make it officially a child agent + sp.MakeChildAgent(destinationHandle); // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone - if (NeedsClosing(sp.Scene.DefaultDrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) + if (NeedsClosing(reg, OutSideViewRange)) { if (!sp.Scene.IncomingPreCloseClient(sp)) return; @@ -1001,26 +1088,32 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // This sleep can be increased if necessary. However, whilst it's active, // an agent cannot teleport back to this region if it has teleported away. Thread.Sleep(2000); - sp.Scene.CloseAgent(sp.UUID, false); } - else - { - // now we have a child agent in this region. - sp.Reset(); - } + sp.IsInTransit = false; } private void TransferAgent_V2(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination, - IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, EntityTransferContext ctx, out string reason) + IPEndPoint endPoint, uint teleportFlags, bool OutSideViewRange, EntityTransferContext ctx, out string reason) { ulong destinationHandle = finalDestination.RegionHandle; - AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); - // Let's create an agent there if one doesn't exist yet. + List childRegionsToClose = sp.GetChildAgentsToClose(destinationHandle, finalDestination.RegionSizeX, finalDestination.RegionSizeY); + + if(agentCircuit.ChildrenCapSeeds != null) + { + foreach(ulong handler in childRegionsToClose) + { + agentCircuit.ChildrenCapSeeds.Remove(handler); + } + } + + string capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);; + + // Let's create an agent there if one doesn't exist yet. // NOTE: logout will always be false for a non-HG teleport. bool logout = false; - if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) + if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, ctx, out reason, out logout)) { m_interRegionTeleportFailures.Value++; @@ -1029,7 +1122,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); sp.ControllingClient.SendTeleportFailed(reason); - + sp.IsInTransit = false; return; } @@ -1041,6 +1134,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", sp.Name, finalDestination.RegionName, sp.Scene.Name); + sp.IsInTransit = false; return; } else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) @@ -1051,40 +1145,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.", sp.Name, finalDestination.RegionName, sp.Scene.Name); + sp.IsInTransit = false; return; } // Past this point we have to attempt clean up if the teleport fails, so update transfer state. m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); - IClientIPEndpoint ipepClient; - string capsPath = String.Empty; - float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance, - (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY)); - if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY)) - { - m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for agent {3} from {4}", - finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name); - - //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); - #region IP Translation for NAT - // Uses ipepClient above - if (sp.ClientView.TryGet(out ipepClient)) - { - endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); - } - #endregion - capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); - } - else - { - agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle); - capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); - } - // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator, - // where that neighbour simulator could otherwise request a child agent create on the source which then + // where that neighbour simulator could otherwise request a child agent create on the source which then // closes our existing agent which is still signalled as root. //sp.IsChildAgent = true; @@ -1100,13 +1169,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); - // Let's send a full update of the agent. + // Let's send a full update of the agent. AgentData agent = new AgentData(); - sp.CopyTo(agent); - if (ctx.OutboundVersion < 0.5f) - agent.Appearance.PackLegacyWearables = true; + sp.CopyTo(agent,false); agent.Position = agentCircuit.startpos; + + if ((teleportFlags & (uint)TeleportFlags.IsFlying) != 0) + agent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; + agent.SenderWantsToWaitForRoot = true; + //SetCallbackURL(agent, sp.Scene.RegionInfo); // Reset the do not close flag. This must be done before the destination opens child connections (here @@ -1118,7 +1190,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Send the Update. If this returns true, we know the client has contacted the destination // via CompleteMovementIntoRegion, so we can let go. // If it returns false, something went wrong, and we need to abort. - if (!UpdateAgent(reg, finalDestination, agent, sp)) + if (!UpdateAgent(reg, finalDestination, agent, sp, ctx)) { if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) { @@ -1127,7 +1199,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.", sp.Name, finalDestination.RegionName, sp.Scene.Name); - + sp.IsInTransit = false; return; } @@ -1135,31 +1207,31 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}", sp.Name, finalDestination.RegionName, sp.Scene.Name); - Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); + Fail(sp, finalDestination, logout, agentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); + sp.IsInTransit = false; return; } - + m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); - // Need to signal neighbours whether child agents may need closing irrespective of whether this - // one needed closing. We also need to close child agents as quickly as possible to avoid complicated - // race conditions with rapid agent releporting (e.g. from A1 to a non-neighbour B, back - // to a neighbour A2 then off to a non-neighbour C). Closing child agents any later requires complex - // distributed checks to avoid problems in rapid reteleporting scenarios and where child agents are - // abandoned without proper close by viewer but then re-used by an incoming connection. - sp.CloseChildAgents(newRegionX, newRegionY); + if(logout) + sp.closeAllChildAgents(); + else + sp.CloseChildAgents(childRegionsToClose); + + sp.HasMovedAway(!(OutSideViewRange || logout)); - // May need to logout or other cleanup + //HG hook AgentHasMovedAway(sp, logout); - // Well, this is it. The agent is over there. - KillEntity(sp.Scene, sp.LocalId); +// ulong sourceRegionHandle = sp.RegionHandle; // Now let's make it officially a child agent - sp.MakeChildAgent(); + sp.MakeChildAgent(destinationHandle); // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone - if (NeedsClosing(sp.Scene.DefaultDrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) + // go by HG hook + if (NeedsClosing(reg, OutSideViewRange)) { if (!sp.Scene.IncomingPreCloseClient(sp)) return; @@ -1170,21 +1242,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // BEFORE THEY SETTLE IN THE NEW REGION. // DECREASING THE WAIT TIME HERE WILL EITHER RESULT IN A VIEWER CRASH OR // IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS. + Thread.Sleep(15000); - + // OK, it got this agent. Let's close everything - // If we shouldn't close the agent due to some other region renewing the connection + // If we shouldn't close the agent due to some other region renewing the connection // then this will be handled in IncomingCloseAgent under lock conditions m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Closing agent {0} in {1} after teleport", sp.Name, Scene.Name); sp.Scene.CloseAgent(sp.UUID, false); } - else - { - // now we have a child agent in this region. - sp.Reset(); - } + sp.IsInTransit = false; } /// @@ -1232,13 +1301,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); } - protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout) + protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, EntityTransferContext ctx, out string reason, out bool logout) { GridRegion source = new GridRegion(Scene.RegionInfo); source.RawServerURI = m_GatekeeperURI; logout = false; - bool success = Scene.SimulationService.CreateAgent(source, finalDestination, agentCircuit, teleportFlags, out reason); + bool success = Scene.SimulationService.CreateAgent(source, finalDestination, agentCircuit, teleportFlags, ctx, out reason); if (success) sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout); @@ -1246,9 +1315,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return success; } - protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent, ScenePresence sp) + protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent, ScenePresence sp, EntityTransferContext ctx) { - return Scene.SimulationService.UpdateAgent(finalDestination, agent); + return Scene.SimulationService.UpdateAgent(finalDestination, agent, ctx); } protected virtual void SetCallbackURL(AgentData agent, RegionInfo region) @@ -1265,10 +1334,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// /// /// + /// + /// now just a HG hook protected virtual void AgentHasMovedAway(ScenePresence sp, bool logout) { - if (sp.Scene.AttachmentsModule != null) - sp.Scene.AttachmentsModule.DeleteAttachmentsFromScene(sp, true); +// if (sp.Scene.AttachmentsModule != null) +// sp.Scene.AttachmentsModule.DeleteAttachmentsFromScene(sp, logout); } protected void KillEntity(Scene scene, uint localID) @@ -1276,6 +1347,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer scene.SendKillObject(new List { localID }); } + // HG hook protected virtual GridRegion GetFinalDestination(GridRegion region, UUID agentID, string agentHomeURI, out string message) { message = null; @@ -1285,28 +1357,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // This returns 'true' if the new region already has a child agent for our // incoming agent. The implication is that, if 'false', we have to create the // child and then teleport into the region. - protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY) + protected virtual bool NeedsNewAgent(float viewdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, + int oldsizeX, int oldsizeY, int newsizeX, int newsizeY) { - if (m_regionCombinerModule != null && m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID)) - { - Vector2 swCorner, neCorner; - GetMegaregionViewRange(out swCorner, out neCorner); - - m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Megaregion view of {0} is from {1} to {2} with new agent check for {3},{4}", - Scene.Name, swCorner, neCorner, newRegionX, newRegionY); - - return !(newRegionX >= swCorner.X && newRegionX <= neCorner.X && newRegionY >= swCorner.Y && newRegionY <= neCorner.Y); - } - else - { - return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY); - } + return Util.IsOutsideView(viewdist, oldRegionX, newRegionX, oldRegionY, newRegionY, + oldsizeX, oldsizeY, newsizeX, newsizeY); } - protected virtual bool NeedsClosing(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg) + // HG Hook + protected virtual bool NeedsClosing(GridRegion reg, bool OutViewRange) + { - return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY); + return OutViewRange; } #endregion @@ -1328,11 +1390,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer remoteClient.SendTeleportFailed("The teleport destination could not be found."); return; } - ((Scene)(remoteClient.Scene)).RequestTeleportLocation(remoteClient, info.RegionHandle, lm.Position, + ((Scene)(remoteClient.Scene)).RequestTeleportLocation(remoteClient, info.RegionHandle, lm.Position, Vector3.Zero, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark)); } - #endregion + #endregion #region Teleport Home @@ -1366,7 +1428,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer client.SendTeleportFailed("Your home region could not be found."); return false; } - + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Home region of {0} is {1} ({2}-{3})", client.Name, regionInfo.RegionName, regionInfo.RegionCoordX, regionInfo.RegionCoordY); @@ -1389,105 +1451,146 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer #region Agent Crossings - // Given a position relative to the current region (which has previously been tested to - // see that it is actually outside the current region), find the new region that the - // point is actually in. - // Returns the coordinates and information of the new region or 'null' of it doesn't exist. + public bool checkAgentAccessToRegion(ScenePresence agent, GridRegion destiny, Vector3 position, + EntityTransferContext ctx, out string reason) + { + reason = String.Empty; + + UUID agentID = agent.UUID; + ulong destinyHandle = destiny.RegionHandle; + + if (m_bannedRegionCache.IfBanned(destinyHandle, agentID)) + { + return false; + } + + Scene ascene = agent.Scene; + string homeURI = ascene.GetAgentHomeURI(agentID); + + + if (!ascene.SimulationService.QueryAccess(destiny, agentID, homeURI, false, position, + agent.Scene.GetFormatsOffered(), ctx, out reason)) + { + m_bannedRegionCache.Add(destinyHandle, agentID, 30.0, 30.0); + return false; + } + return true; + } + + + // Given a position relative to the current region and outside of it + // find the new region that the point is actually in. + // returns 'null' if new region not found or if information + // and new position relative to it + // now only works for crossings + public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, EntityTransferContext ctx, out Vector3 newpos, out string failureReason) { newpos = pos; failureReason = string.Empty; - string homeURI = scene.GetAgentHomeURI(agentID); // m_log.DebugFormat( // "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name); - // Compute world location of the object's position + // Compute world location of the agent's position double presenceWorldX = (double)scene.RegionInfo.WorldLocX + pos.X; double presenceWorldY = (double)scene.RegionInfo.WorldLocY + pos.Y; // Call the grid service to lookup the region containing the new position. - GridRegion neighbourRegion = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID, - presenceWorldX, presenceWorldY, - Math.Max(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY)); + GridRegion neighbourRegion = GetRegionContainingWorldLocation( + scene.GridService, scene.RegionInfo.ScopeID, + presenceWorldX, presenceWorldY, + Math.Max(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY)); + + if (neighbourRegion == null) + return null; - if (neighbourRegion != null) + if (m_bannedRegionCache.IfBanned(neighbourRegion.RegionHandle, agentID)) { - // Compute the entity's position relative to the new region - newpos = new Vector3((float)(presenceWorldX - (double)neighbourRegion.RegionLocX), + failureReason = "Access Denied or Temporary not possible"; + return null; + } + + m_bannedRegionCache.Remove(neighbourRegion.RegionHandle, agentID); + + // Compute the entity's position relative to the new region + newpos = new Vector3((float)(presenceWorldX - (double)neighbourRegion.RegionLocX), (float)(presenceWorldY - (double)neighbourRegion.RegionLocY), pos.Z); - if (m_bannedRegionCache.IfBanned(neighbourRegion.RegionHandle, agentID)) - { - failureReason = "Cannot region cross into banned parcel"; - neighbourRegion = null; - } - else - { - // If not banned, make sure this agent is not in the list. - m_bannedRegionCache.Remove(neighbourRegion.RegionHandle, agentID); - } - - // Check to see if we have access to the target region. - if (neighbourRegion != null - && !scene.SimulationService.QueryAccess(neighbourRegion, agentID, homeURI, false, newpos, scene.GetFormatsOffered(), ctx, out failureReason)) - { - // remember banned - m_bannedRegionCache.Add(neighbourRegion.RegionHandle, agentID); - neighbourRegion = null; - } + string homeURI = scene.GetAgentHomeURI(agentID); + + if (!scene.SimulationService.QueryAccess( + neighbourRegion, agentID, homeURI, false, newpos, + scene.GetFormatsOffered(), ctx, out failureReason)) + { + // remember the fail + m_bannedRegionCache.Add(neighbourRegion.RegionHandle, agentID); + if(String.IsNullOrWhiteSpace(failureReason)) + failureReason = "Access Denied"; + return null; } - else + + return neighbourRegion; + } + + public bool Cross(ScenePresence agent, bool isFlying) + { + agent.IsInLocalTransit = true; + agent.IsInTransit = true; + CrossAsyncDelegate d = CrossAsync; + d.BeginInvoke(agent, isFlying, CrossCompleted, d); + return true; + } + + private void CrossCompleted(IAsyncResult iar) + { + CrossAsyncDelegate icon = (CrossAsyncDelegate)iar.AsyncState; + ScenePresence agent = icon.EndInvoke(iar); + + if(agent == null || agent.IsDeleted) + return; + + if(!agent.IsChildAgent) { - // The destination region just doesn't exist - failureReason = "Cannot cross into non-existent region"; + // crossing failed + agent.CrossToNewRegionFail(); } - - if (neighbourRegion == null) - m_log.DebugFormat("{0} GetDestination: region not found. Old region name={1} at <{2},{3}> of size <{4},{5}>. Old pos={6}", - LogHeader, scene.RegionInfo.RegionName, - scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY, - scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY, - pos); else - m_log.DebugFormat("{0} GetDestination: new region={1} at <{2},{3}> of size <{4},{5}>, newpos=<{6},{7}>", - LogHeader, neighbourRegion.RegionName, - neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY, - newpos.X, newpos.Y); + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname); - return neighbourRegion; + agent.IsInTransit = false; } - public bool Cross(ScenePresence agent, bool isFlying) + public ScenePresence CrossAsync(ScenePresence agent, bool isFlying) { Vector3 newpos; EntityTransferContext ctx = new EntityTransferContext(); string failureReason; - GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, agent.AbsolutePosition, + // We need this because of decimal number parsing of the protocols. + Culture.SetCurrentCulture(); + + Vector3 pos = agent.AbsolutePosition + agent.Velocity * 0.2f; + + GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, pos, ctx, out newpos, out failureReason); if (neighbourRegion == null) { - agent.ControllingClient.SendAlertMessage(failureReason); - return false; + if (!agent.IsDeleted && failureReason != String.Empty && agent.ControllingClient != null) + agent.ControllingClient.SendAlertMessage(failureReason); + return agent; } - agent.IsInTransit = true; - - CrossAgentToNewRegionDelegate d = CrossAgentToNewRegionAsync; - d.BeginInvoke(agent, newpos, neighbourRegion, isFlying, ctx, CrossAgentToNewRegionCompleted, d); +// agent.IsInTransit = true; - Scene.EventManager.TriggerCrossAgentToNewRegion(agent, isFlying, neighbourRegion); - - return true; + CrossAgentToNewRegionAsync(agent, newpos, neighbourRegion, isFlying, ctx); + agent.IsInTransit = false; + return agent; } - - public delegate void InformClientToInitiateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY, - Vector3 position, - Scene initiatingScene); + public delegate void InformClientToInitiateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene); private void InformClientToInitiateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene) { @@ -1506,14 +1609,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer Thread.Sleep(10000); m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Auto-reteleporting {0} to correct megaregion location {1},{2},{3} from {4}", + "[ENTITY TRANSFER MODULE]: Auto-reteleporting {0} to correct megaregion location {1},{2},{3} from {4}", agent.Name, regionX, regionY, position, initiatingScene.Name); agent.Scene.RequestTeleportLocation( - agent.ControllingClient, - Util.RegionLocToHandle(regionX, regionY), - position, - agent.Lookat, + agent.ControllingClient, + Util.RegionGridLocToHandle(regionX, regionY), + position, + agent.Lookat, (uint)Constants.TeleportFlags.ViaLocation); /* @@ -1557,15 +1660,71 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer icon.EndInvoke(iar); } - public bool CrossAgentToNewRegionPrep(ScenePresence agent, GridRegion neighbourRegion) + public bool CrossAgentCreateFarChild(ScenePresence agent, GridRegion neighbourRegion, Vector3 pos, EntityTransferContext ctx) { - if (neighbourRegion == null) + ulong regionhandler = neighbourRegion.RegionHandle; + + if(agent.knowsNeighbourRegion(regionhandler)) + return true; + + string reason; + ulong currentRegionHandler = agent.Scene.RegionInfo.RegionHandle; + GridRegion source = new GridRegion(agent.Scene.RegionInfo); + + AgentCircuitData currentAgentCircuit = + agent.Scene.AuthenticateHandler.GetAgentCircuitData(agent.ControllingClient.CircuitCode); + AgentCircuitData agentCircuit = agent.ControllingClient.RequestClientInfo(); + agentCircuit.startpos = pos; + agentCircuit.child = true; + + agentCircuit.Appearance = new AvatarAppearance(); + agentCircuit.Appearance.AvatarHeight = agent.Appearance.AvatarHeight; + + if (currentAgentCircuit != null) + { + agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs; + agentCircuit.IPAddress = currentAgentCircuit.IPAddress; + agentCircuit.Viewer = currentAgentCircuit.Viewer; + agentCircuit.Channel = currentAgentCircuit.Channel; + agentCircuit.Mac = currentAgentCircuit.Mac; + agentCircuit.Id0 = currentAgentCircuit.Id0; + } + + agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); + agent.AddNeighbourRegion(neighbourRegion, agentCircuit.CapsPath); + + IPEndPoint endPoint = neighbourRegion.ExternalEndPoint; + if(endPoint == null) + { + m_log.DebugFormat("CrossAgentCreateFarChild failed to resolve neighbour address {0}", neighbourRegion.ExternalHostName); return false; - - m_entityTransferStateMachine.SetInTransit(agent.UUID); + } + if (!Scene.SimulationService.CreateAgent(source, neighbourRegion, agentCircuit, (int)TeleportFlags.Default, ctx, out reason)) + { + agent.RemoveNeighbourRegion(regionhandler); + return false; + } - agent.RemoveFromPhysicalScene(); + string capsPath = neighbourRegion.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); + int newSizeX = neighbourRegion.RegionSizeX; + int newSizeY = neighbourRegion.RegionSizeY; + if (m_eqModule != null) + { + m_log.DebugFormat("{0} {1} is sending {2} EnableSimulator for neighbour region {3}(loc=<{4},{5}>,siz=<{6},{7}>) " + + "and EstablishAgentCommunication with seed cap {8}", LogHeader, + source.RegionName, agent.Name, + neighbourRegion.RegionName, neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, newSizeX, newSizeY , capsPath); + + m_eqModule.EnableSimulator(regionhandler, + endPoint, agent.UUID, newSizeX, newSizeY); + m_eqModule.EstablishAgentCommunication(agent.UUID, endPoint, capsPath, + regionhandler, newSizeX, newSizeY); + } + else + { + agent.ControllingClient.InformClientOfNeighbour(regionhandler, endPoint); + } return true; } @@ -1582,37 +1741,56 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: new region={1} at <{2},{3}>. newpos={4}", LogHeader, neighbourRegion.RegionName, neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, pos); - if (!CrossAgentToNewRegionPrep(agent, neighbourRegion)) + if (neighbourRegion == null) { - m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: prep failed. Resetting transfer state", LogHeader); - m_entityTransferStateMachine.ResetFromTransit(agent.UUID); + m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: invalid destiny", LogHeader); + return agent; } - if (!CrossAgentIntoNewRegionMain(agent, pos, neighbourRegion, isFlying, ctx)) + IPEndPoint endpoint = neighbourRegion.ExternalEndPoint; + if(endpoint == null) + { + m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: failed to resolve neighbour address {0} ",neighbourRegion.ExternalHostName); + return agent; + } + + m_entityTransferStateMachine.SetInTransit(agent.UUID); + agent.RemoveFromPhysicalScene(); + + if (!CrossAgentIntoNewRegionMain(agent, pos, neighbourRegion, endpoint, isFlying, ctx)) { m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: cross main failed. Resetting transfer state", LogHeader); m_entityTransferStateMachine.ResetFromTransit(agent.UUID); } - - CrossAgentToNewRegionPost(agent, pos, neighbourRegion, isFlying, ctx); } catch (Exception e) { m_log.Error(string.Format("{0}: CrossAgentToNewRegionAsync: failed with exception ", LogHeader), e); } - return agent; } - public bool CrossAgentIntoNewRegionMain(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, bool isFlying, EntityTransferContext ctx) + public bool CrossAgentIntoNewRegionMain(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, + IPEndPoint endpoint, bool isFlying, EntityTransferContext ctx) { + int ts = Util.EnvironmentTickCount(); + bool sucess = true; + string reason = String.Empty; + List childRegionsToClose = null; try { - AgentData cAgent = new AgentData(); - agent.CopyTo(cAgent); - if (ctx.OutboundVersion < 0.5f) - cAgent.Appearance.PackLegacyWearables = true; + AgentData cAgent = new AgentData(); + agent.CopyTo(cAgent,true); + cAgent.Position = pos; + cAgent.ChildrenCapSeeds = agent.KnownRegions; + + childRegionsToClose = agent.GetChildAgentsToClose(neighbourRegion.RegionHandle, neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY); + if(cAgent.ChildrenCapSeeds != null) + { + foreach(ulong regh in childRegionsToClose) + cAgent.ChildrenCapSeeds.Remove(regh); + } if (isFlying) cAgent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; @@ -1623,21 +1801,31 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Beyond this point, extra cleanup is needed beyond removing transit state m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.Transferring); - if (!agent.Scene.SimulationService.UpdateAgent(neighbourRegion, cAgent)) + if (sucess && !agent.Scene.SimulationService.UpdateAgent(neighbourRegion, cAgent, ctx)) + { + sucess = false; + reason = "agent update failed"; + } + + if(!sucess) { // region doesn't take it m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); m_log.WarnFormat( - "[ENTITY TRANSFER MODULE]: Region {0} would not accept update for agent {1} on cross attempt. Returning to original region.", - neighbourRegion.RegionName, agent.Name); + "[ENTITY TRANSFER MODULE]: agent {0} crossing to {1} failed: {2}", + agent.Name, neighbourRegion.RegionName, reason); ReInstantiateScripts(agent); - agent.AddToPhysicalScene(isFlying); + if(agent.ParentID == 0 && agent.ParentUUID == UUID.Zero) + { + agent.AddToPhysicalScene(isFlying); + } return false; } + m_log.DebugFormat("[CrossAgentIntoNewRegionMain] ok, time {0}ms",Util.EnvironmentTickCountSubtract(ts)); } catch (Exception e) { @@ -1649,44 +1837,38 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return false; } - return true; - } - - public void CrossAgentToNewRegionPost(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, - bool isFlying, EntityTransferContext ctx) - { - agent.ControllingClient.RequestClientInfo(); - string agentcaps; if (!agent.KnownRegions.TryGetValue(neighbourRegion.RegionHandle, out agentcaps)) { m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: No ENTITY TRANSFER MODULE information for region handle {0}, exiting CrossToNewRegion.", neighbourRegion.RegionHandle); - return; + return false; } // No turning back + agent.IsChildAgent = true; string capsPath = neighbourRegion.ServerURI + CapsUtil.GetCapsSeedPath(agentcaps); m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID); - Vector3 vel2 = new Vector3(agent.Velocity.X, agent.Velocity.Y, 0); + Vector3 vel2 = Vector3.Zero; + if((agent.crossingFlags & 2) != 0) + vel2 = new Vector3(agent.Velocity.X, agent.Velocity.Y, 0); if (m_eqModule != null) { m_eqModule.CrossRegion( - neighbourRegion.RegionHandle, pos + agent.Velocity, vel2 /* agent.Velocity */, - neighbourRegion.ExternalEndPoint, - capsPath, agent.UUID, agent.ControllingClient.SessionId, + neighbourRegion.RegionHandle, pos, vel2 /* agent.Velocity */, + endpoint, capsPath, agent.UUID, agent.ControllingClient.SessionId, neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY); } else { m_log.ErrorFormat("{0} Using old CrossRegion packet. Varregion will not work!!", LogHeader); - agent.ControllingClient.CrossRegion(neighbourRegion.RegionHandle, pos + agent.Velocity, agent.Velocity, neighbourRegion.ExternalEndPoint, - capsPath); + agent.ControllingClient.CrossRegion(neighbourRegion.RegionHandle, pos, agent.Velocity, + endpoint,capsPath); } // SUCCESS! @@ -1695,51 +1877,23 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Unlike a teleport, here we do not wait for the destination region to confirm the receipt. m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); - agent.MakeChildAgent(); - - // FIXME: Possibly this should occur lower down after other commands to close other agents, - // but not sure yet what the side effects would be. - m_entityTransferStateMachine.ResetFromTransit(agent.UUID); - - // now we have a child agent in this region. Request all interesting data about other (root) agents - agent.SendOtherAgentsAvatarDataToClient(); - agent.SendOtherAgentsAppearanceToClient(); + if(childRegionsToClose != null) + agent.CloseChildAgents(childRegionsToClose); - // TODO: Check since what version this wasn't needed anymore. May be as old as 0.6 -/* - // Backwards compatibility. Best effort - if (version == 0f) - { - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: neighbor with old version, passing attachments one by one..."); - Thread.Sleep(3000); // wait a little now that we're not waiting for the callback - CrossAttachmentsIntoNewRegion(neighbourRegion, agent, true); - } -*/ - // Next, let's close the child agent connections that are too far away. - uint neighbourx; - uint neighboury; - Util.RegionHandleToRegionLoc(neighbourRegion.RegionHandle, out neighbourx, out neighboury); - - agent.CloseChildAgents(neighbourx, neighboury); + if((agent.crossingFlags & 8) == 0) + agent.ClearControls(); // don't let attachments delete (called in HasMovedAway) disturb taken controls on viewers - AgentHasMovedAway(agent, false); + agent.HasMovedAway((agent.crossingFlags & 8) == 0); - // the user may change their profile information in other region, - // so the userinfo in UserProfileCache is not reliable any more, delete it - // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! -// if (agent.Scene.NeedSceneCacheClear(agent.UUID)) -// { -// m_log.DebugFormat( -// "[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID); -// } + agent.MakeChildAgent(neighbourRegion.RegionHandle); - //m_log.Debug("AFTER CROSS"); - //Scene.DumpChildrenSeeds(UUID); - //DumpKnownRegions(); + // FIXME: Possibly this should occur lower down after other commands to close other agents, + // but not sure yet what the side effects would be. + m_entityTransferStateMachine.ResetFromTransit(agent.UUID); - return; + return true; } - + private void CrossAgentToNewRegionCompleted(IAsyncResult iar) { CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState; @@ -1754,7 +1908,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // In any case agent.IsInTransit = false; - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname); +// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname); } #endregion @@ -1762,7 +1916,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer #region Enable Child Agent /// - /// This informs a single neighbouring region about agent "avatar". + /// This informs a single neighbouring region about agent "avatar", and avatar about it /// Calls an asynchronous method to do so.. so it doesn't lag the sim. /// /// @@ -1771,42 +1925,46 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { m_log.DebugFormat("[ENTITY TRANSFER]: Enabling child agent in new neighbour {0}", region.RegionName); + ulong currentRegionHandler = sp.Scene.RegionInfo.RegionHandle; + ulong regionhandler = region.RegionHandle; + + Dictionary seeds = new Dictionary(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID)); + + if (seeds.ContainsKey(regionhandler)) + seeds.Remove(regionhandler); +/* + List oldregions = new List(seeds.Keys); + + if (oldregions.Contains(currentRegionHandler)) + oldregions.Remove(currentRegionHandler); +*/ + if (!seeds.ContainsKey(currentRegionHandler)) + seeds.Add(currentRegionHandler, sp.ControllingClient.RequestClientInfo().CapsPath); + AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); AgentCircuitData agent = sp.ControllingClient.RequestClientInfo(); agent.BaseFolder = UUID.Zero; agent.InventoryFolder = UUID.Zero; - agent.startpos = new Vector3(128, 128, 70); + agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, region); agent.child = true; agent.Appearance = new AvatarAppearance(); - agent.Appearance.PackLegacyWearables = true; - agent.CapsPath = CapsUtil.GetRandomCapsObjectPath(); - - agent.ChildrenCapSeeds = new Dictionary(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID)); - //m_log.DebugFormat("[XXX] Seeds 1 {0}", agent.ChildrenCapSeeds.Count); + agent.Appearance.AvatarHeight = sp.Appearance.AvatarHeight; - if (!agent.ChildrenCapSeeds.ContainsKey(sp.Scene.RegionInfo.RegionHandle)) - agent.ChildrenCapSeeds.Add(sp.Scene.RegionInfo.RegionHandle, sp.ControllingClient.RequestClientInfo().CapsPath); - //m_log.DebugFormat("[XXX] Seeds 2 {0}", agent.ChildrenCapSeeds.Count); + agent.CapsPath = CapsUtil.GetRandomCapsObjectPath(); - sp.AddNeighbourRegion(region.RegionHandle, agent.CapsPath); - //foreach (ulong h in agent.ChildrenCapSeeds.Keys) - // m_log.DebugFormat("[XXX] --> {0}", h); - //m_log.DebugFormat("[XXX] Adding {0}", region.RegionHandle); - if (agent.ChildrenCapSeeds.ContainsKey(region.RegionHandle)) - { - m_log.WarnFormat( - "[ENTITY TRANSFER]: Overwriting caps seed {0} with {1} for region {2} (handle {3}) for {4} in {5}", - agent.ChildrenCapSeeds[region.RegionHandle], agent.CapsPath, - region.RegionName, region.RegionHandle, sp.Name, Scene.Name); - } + seeds.Add(regionhandler, agent.CapsPath); - agent.ChildrenCapSeeds[region.RegionHandle] = agent.CapsPath; +// agent.ChildrenCapSeeds = new Dictionary(seeds); + agent.ChildrenCapSeeds = null; if (sp.Scene.CapsModule != null) { - sp.Scene.CapsModule.SetChildrenSeed(sp.UUID, agent.ChildrenCapSeeds); + sp.Scene.CapsModule.SetChildrenSeed(sp.UUID, seeds); } + sp.KnownRegions = seeds; + sp.AddNeighbourRegionSizeInfo(region); + if (currentAgentCircuit != null) { agent.ServiceURLs = currentAgentCircuit.ServiceURLs; @@ -1816,7 +1974,24 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer agent.Mac = currentAgentCircuit.Mac; agent.Id0 = currentAgentCircuit.Id0; } - +/* + AgentPosition agentpos = null; + + if (oldregions.Count > 0) + { + agentpos = new AgentPosition(); + agentpos.AgentID = new UUID(sp.UUID.Guid); + agentpos.SessionID = sp.ControllingClient.SessionId; + agentpos.Size = sp.Appearance.AvatarSize; + agentpos.Center = sp.CameraPosition; + agentpos.Far = sp.DrawDistance; + agentpos.Position = sp.AbsolutePosition; + agentpos.Velocity = sp.Velocity; + agentpos.RegionHandle = currentRegionHandler; + agentpos.Throttles = sp.ControllingClient.GetThrottlesPacked(1); + agentpos.ChildrenCapSeeds = seeds; + } +*/ IPEndPoint external = region.ExternalEndPoint; if (external != null) { @@ -1825,7 +2000,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer InformClientOfNeighbourCompleted, d); } +/* + if(oldregions.Count >0) + { + uint neighbourx; + uint neighboury; + UUID scope = sp.Scene.RegionInfo.ScopeID; + foreach (ulong handler in oldregions) + { + Utils.LongToUInts(handler, out neighbourx, out neighboury); + GridRegion neighbour = sp.Scene.GridService.GetRegionByPosition(scope, (int)neighbourx, (int)neighboury); + sp.Scene.SimulationService.UpdateAgent(neighbour, agentpos); + } + } + */ } + #endregion #region Enable Child Agents @@ -1835,167 +2025,175 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// /// This informs all neighbouring regions about agent "avatar". + /// and as important informs the avatar about then /// /// public void EnableChildAgents(ScenePresence sp) { + // assumes that out of view range regions are disconnected by the previus region + List neighbours = new List(); - RegionInfo m_regionInfo = sp.Scene.RegionInfo; + Scene spScene = sp.Scene; + RegionInfo m_regionInfo = spScene.RegionInfo; if (m_regionInfo != null) { - neighbours = GetNeighbours(sp, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY); + neighbours = GetNeighbors(sp, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY); } else { m_log.Debug("[ENTITY TRANSFER MODULE]: m_regionInfo was null in EnableChildAgents, is this a NPC?"); } - /// We need to find the difference between the new regions where there are no child agents - /// and the regions where there are already child agents. We only send notification to the former. - List neighbourHandles = NeighbourHandles(neighbours); // on this region - neighbourHandles.Add(sp.Scene.RegionInfo.RegionHandle); // add this region too - List previousRegionNeighbourHandles; + ulong currentRegionHandler = m_regionInfo.RegionHandle; - if (sp.Scene.CapsModule != null) + LinkedList previousRegionNeighbourHandles; + Dictionary seeds; + ICapabilitiesModule capsModule = spScene.CapsModule; + + if (capsModule != null) { - previousRegionNeighbourHandles = - new List(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID).Keys); + seeds = new Dictionary(capsModule.GetChildrenSeeds(sp.UUID)); + previousRegionNeighbourHandles = new LinkedList(seeds.Keys); } else { - previousRegionNeighbourHandles = new List(); + seeds = new Dictionary(); + previousRegionNeighbourHandles = new LinkedList(); } - List newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles); - List oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles); - -// Dump("Current Neighbors", neighbourHandles); -// Dump("Previous Neighbours", previousRegionNeighbourHandles); -// Dump("New Neighbours", newRegions); -// Dump("Old Neighbours", oldRegions); - - /// Update the scene presence's known regions here on this region - sp.DropOldNeighbours(oldRegions); + IClientAPI spClient = sp.ControllingClient; - /// Collect as many seeds as possible - Dictionary seeds; - if (sp.Scene.CapsModule != null) - seeds = new Dictionary(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID)); - else - seeds = new Dictionary(); + // This will fail if the user aborts login + try + { + if (!seeds.ContainsKey(currentRegionHandler)) + seeds.Add(currentRegionHandler, spClient.RequestClientInfo().CapsPath); + } + catch + { + return; + } - //m_log.Debug(" !!! No. of seeds: " + seeds.Count); - if (!seeds.ContainsKey(sp.Scene.RegionInfo.RegionHandle)) - seeds.Add(sp.Scene.RegionInfo.RegionHandle, sp.ControllingClient.RequestClientInfo().CapsPath); + AgentCircuitData currentAgentCircuit = + spScene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); - /// Create the necessary child agents List cagents = new List(); + List newneighbours = new List(); + foreach (GridRegion neighbour in neighbours) { - if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) + ulong handler = neighbour.RegionHandle; + + if (previousRegionNeighbourHandles.Contains(handler)) { - AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); - AgentCircuitData agent = sp.ControllingClient.RequestClientInfo(); - agent.BaseFolder = UUID.Zero; - agent.InventoryFolder = UUID.Zero; - agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, neighbour); - agent.child = true; - agent.Appearance = new AvatarAppearance(); - agent.Appearance.PackLegacyWearables = true; - if (currentAgentCircuit != null) - { - agent.ServiceURLs = currentAgentCircuit.ServiceURLs; - agent.IPAddress = currentAgentCircuit.IPAddress; - agent.Viewer = currentAgentCircuit.Viewer; - agent.Channel = currentAgentCircuit.Channel; - agent.Mac = currentAgentCircuit.Mac; - agent.Id0 = currentAgentCircuit.Id0; - } + // agent already knows this region + previousRegionNeighbourHandles.Remove(handler); + continue; + } - if (newRegions.Contains(neighbour.RegionHandle)) - { - agent.CapsPath = CapsUtil.GetRandomCapsObjectPath(); - sp.AddNeighbourRegion(neighbour.RegionHandle, agent.CapsPath); - seeds.Add(neighbour.RegionHandle, agent.CapsPath); - } - else - { - agent.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, neighbour.RegionHandle); - } + if (handler == currentRegionHandler) + continue; - cagents.Add(agent); + // a new region to add + AgentCircuitData agent = spClient.RequestClientInfo(); + agent.BaseFolder = UUID.Zero; + agent.InventoryFolder = UUID.Zero; + agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, neighbour); + agent.child = true; + agent.Appearance = new AvatarAppearance(); + agent.Appearance.AvatarHeight = sp.Appearance.AvatarHeight; + + if (currentAgentCircuit != null) + { + agent.ServiceURLs = currentAgentCircuit.ServiceURLs; + agent.IPAddress = currentAgentCircuit.IPAddress; + agent.Viewer = currentAgentCircuit.Viewer; + agent.Channel = currentAgentCircuit.Channel; + agent.Mac = currentAgentCircuit.Mac; + agent.Id0 = currentAgentCircuit.Id0; } - } - /// Update all child agent with everyone's seeds - foreach (AgentCircuitData a in cagents) - { - a.ChildrenCapSeeds = new Dictionary(seeds); - } + newneighbours.Add(handler); + agent.CapsPath = CapsUtil.GetRandomCapsObjectPath(); + seeds.Add(handler, agent.CapsPath); - if (sp.Scene.CapsModule != null) - { - sp.Scene.CapsModule.SetChildrenSeed(sp.UUID, seeds); + agent.ChildrenCapSeeds = null; + cagents.Add(agent); } - sp.KnownRegions = seeds; - //avatar.Scene.DumpChildrenSeeds(avatar.UUID); - //avatar.DumpKnownRegions(); - bool newAgent = false; - int count = 0; - foreach (GridRegion neighbour in neighbours) - { - //m_log.WarnFormat("--> Going to send child agent to {0}", neighbour.RegionName); - // Don't do it if there's already an agent in that region - if (newRegions.Contains(neighbour.RegionHandle)) - newAgent = true; - else - newAgent = false; -// continue; + if (previousRegionNeighbourHandles.Contains(currentRegionHandler)) + previousRegionNeighbourHandles.Remove(currentRegionHandler); - if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) - { - try - { - // Let's put this back at sync, so that it doesn't clog - // the network, especially for regions in the same physical server. - // We're really not in a hurry here. - InformClientOfNeighbourAsync(sp, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent); - //InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync; - //d.BeginInvoke(sp, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent, - // InformClientOfNeighbourCompleted, - // d); - } + // previousRegionNeighbourHandles now contains regions to forget + foreach (ulong handler in previousRegionNeighbourHandles) + seeds.Remove(handler); - catch (ArgumentOutOfRangeException) - { - m_log.ErrorFormat( - "[ENTITY TRANSFER MODULE]: Neighbour Regions response included the current region in the neighbour list. The following region will not display to the client: {0} for region {1} ({2}, {3}).", - neighbour.ExternalHostName, - neighbour.RegionHandle, - neighbour.RegionLocX, - neighbour.RegionLocY); - } - catch (Exception e) - { - m_log.ErrorFormat( - "[ENTITY TRANSFER MODULE]: Could not resolve external hostname {0} for region {1} ({2}, {3}). {4}", - neighbour.ExternalHostName, - neighbour.RegionHandle, - neighbour.RegionLocX, - neighbour.RegionLocY, - e); + /// Update all child agent with everyone's seeds + // foreach (AgentCircuitData a in cagents) + // a.ChildrenCapSeeds = new Dictionary(seeds); - // FIXME: Okay, even though we've failed, we're still going to throw the exception on, - // since I don't know what will happen if we just let the client continue + if (capsModule != null) + capsModule.SetChildrenSeed(sp.UUID, seeds); - // XXX: Well, decided to swallow the exception instead for now. Let us see how that goes. - // throw e; + sp.KnownRegions = seeds; + sp.SetNeighbourRegionSizeInfo(neighbours); + + if(newneighbours.Count > 0 || previousRegionNeighbourHandles.Count > 0) + { + AgentPosition agentpos = new AgentPosition(); + agentpos.AgentID = new UUID(sp.UUID.Guid); + agentpos.SessionID = spClient.SessionId; + agentpos.Size = sp.Appearance.AvatarSize; + agentpos.Center = sp.CameraPosition; + agentpos.Far = sp.DrawDistance; + agentpos.Position = sp.AbsolutePosition; + agentpos.Velocity = sp.Velocity; + agentpos.RegionHandle = currentRegionHandler; + //agentpos.GodLevel = sp.GodLevel; + agentpos.GodData = sp.GodController.State(); + agentpos.Throttles = spClient.GetThrottlesPacked(1); + // agentpos.ChildrenCapSeeds = seeds; + + Util.FireAndForget(delegate + { + Thread.Sleep(200); // the original delay that was at InformClientOfNeighbourAsync start + int count = 0; + IPEndPoint ipe; + foreach (GridRegion neighbour in neighbours) + { + ulong handler = neighbour.RegionHandle; + try + { + if (newneighbours.Contains(handler)) + { + ipe = neighbour.ExternalEndPoint; + if (ipe != null) + InformClientOfNeighbourAsync(sp, cagents[count], neighbour, ipe, true); + else + { + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: lost DNS resolution for neighbour {0}", neighbour.ExternalHostName); + } + count++; + } + else if (!previousRegionNeighbourHandles.Contains(handler)) + { + spScene.SimulationService.UpdateAgent(neighbour, agentpos); + } + } + catch (Exception e) + { + m_log.ErrorFormat( + "[ENTITY TRANSFER MODULE]: Error creating child agent at {0} ({1} ({2}, {3}). {4}", + neighbour.ExternalHostName, + neighbour.RegionHandle, + neighbour.RegionLocX, + neighbour.RegionLocY, + e); + } } - } - count++; + }); } } @@ -2004,26 +2202,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // The first region is the home region of the passed scene presence. Vector3 CalculateOffset(ScenePresence sp, GridRegion neighbour) { - /* - int rRegionX = (int)sp.Scene.RegionInfo.LegacyRegionLocX; - int rRegionY = (int)sp.Scene.RegionInfo.LegacyRegionLocY; - int tRegionX = neighbour.RegionLocX / (int)Constants.RegionSize; - int tRegionY = neighbour.RegionLocY / (int)Constants.RegionSize; - int shiftx = (rRegionX - tRegionX) * (int)Constants.RegionSize; - int shifty = (rRegionY - tRegionY) * (int)Constants.RegionSize; - return new Vector3(shiftx, shifty, 0f); - */ - return new Vector3( sp.Scene.RegionInfo.WorldLocX - neighbour.RegionLocX, + return new Vector3(sp.Scene.RegionInfo.WorldLocX - neighbour.RegionLocX, sp.Scene.RegionInfo.WorldLocY - neighbour.RegionLocY, 0f); } - - public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py) - { - // Since we don't know how big the regions could be, we have to search a very large area - // to find possible regions. - return GetRegionContainingWorldLocation(pGridService, pScopeID, px, py, Constants.MaximumRegionSize); - } + #endregion #region NotFoundLocationCache class // A collection of not found locations to make future lookups 'not found' lookups quick. @@ -2032,162 +2215,131 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // contains that point. A conservitive estimate. private class NotFoundLocationCache { - private struct NotFoundLocation - { - public double minX, maxX, minY, maxY; - public DateTime expireTime; - } - private List m_notFoundLocations = new List(); + private Dictionary m_notFoundLocations = new Dictionary(); public NotFoundLocationCache() { } - // Add an area to the list of 'not found' places. The area is the snapped region - // area around the added point. + // just use normal regions handlers and sizes public void Add(double pX, double pY) { + ulong psh = (ulong)pX & 0xffffff00ul; + psh <<= 32; + psh |= (ulong)pY & 0xffffff00ul; + lock (m_notFoundLocations) - { - if (!LockedContains(pX, pY)) - { - NotFoundLocation nfl = new NotFoundLocation(); - // A not found location is not found for at least a whole region sized area - nfl.minX = pX - (pX % (double)Constants.RegionSize); - nfl.minY = pY - (pY % (double)Constants.RegionSize); - nfl.maxX = nfl.minX + (double)Constants.RegionSize; - nfl.maxY = nfl.minY + (double)Constants.RegionSize; - nfl.expireTime = DateTime.Now + TimeSpan.FromSeconds(30); - m_notFoundLocations.Add(nfl); - } - } - + m_notFoundLocations[psh] = DateTime.UtcNow + TimeSpan.FromSeconds(30); } // Test to see of this point is in any of the 'not found' areas. // Return 'true' if the point is found inside the 'not found' areas. public bool Contains(double pX, double pY) { - bool ret = false; + ulong psh = (ulong)pX & 0xffffff00ul; + psh <<= 32; + psh |= (ulong)pY & 0xffffff00ul; + lock (m_notFoundLocations) - ret = LockedContains(pX, pY); - return ret; - } - private bool LockedContains(double pX, double pY) - { - bool ret = false; - this.DoExpiration(); - foreach (NotFoundLocation nfl in m_notFoundLocations) { - if (pX >= nfl.minX && pX < nfl.maxX && pY >= nfl.minY && pY < nfl.maxY) + if(m_notFoundLocations.ContainsKey(psh)) { - ret = true; - break; + if(m_notFoundLocations[psh] > DateTime.UtcNow) + return true; + m_notFoundLocations.Remove(psh); } + return false; } - return ret; } + private void DoExpiration() { - List m_toRemove = null; - DateTime now = DateTime.Now; - foreach (NotFoundLocation nfl in m_notFoundLocations) + List m_toRemove = new List();; + DateTime now = DateTime.UtcNow; + lock (m_notFoundLocations) { - if (nfl.expireTime < now) + foreach (KeyValuePair kvp in m_notFoundLocations) { - if (m_toRemove == null) - m_toRemove = new List(); - m_toRemove.Add(nfl); + if (kvp.Value < now) + m_toRemove.Add(kvp.Key); + } + + if (m_toRemove.Count > 0) + { + foreach (ulong u in m_toRemove) + m_notFoundLocations.Remove(u); + m_toRemove.Clear(); } - } - if (m_toRemove != null) - { - foreach (NotFoundLocation nfl in m_toRemove) - m_notFoundLocations.Remove(nfl); - m_toRemove.Clear(); } } } + #endregion // NotFoundLocationCache class + #region getregions private NotFoundLocationCache m_notFoundLocationCache = new NotFoundLocationCache(); - // Given a world position (fractional meter coordinate), get the GridRegion info for + protected GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py) + { + // Since we don't know how big the regions could be, we have to search a very large area + // to find possible regions. + return GetRegionContainingWorldLocation(pGridService, pScopeID, px, py, Constants.MaximumRegionSize); + } + + // Given a world position, get the GridRegion info for // the region containing that point. - // Someday this should be a method on GridService. - // 'pSizeHint' is the size of the source region but since the destination point can be anywhere - // the size of the target region is unknown thus the search area might have to be very large. - // Return 'null' if no such region exists. - public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, + // for compatibility with old grids it does a scan to find large regions + // 0.9 grids to that + + protected GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py, uint pSizeHint) { - m_log.DebugFormat("{0} GetRegionContainingWorldLocation: query, loc=<{1},{2}>", LogHeader, px, py); +// m_log.DebugFormat("{0} GetRegionContainingWorldLocation: call, XY=<{1},{2}>", LogHeader, px, py); GridRegion ret = null; - const double fudge = 2.0; - // One problem with this routine is negative results. That is, this can be called lots of times - // for regions that don't exist. m_notFoundLocationCache remembers 'not found' results so they - // will be quick 'not found's next time. - // NotFoundLocationCache is an expiring cache so it will eventually forget about 'not found' and - // thus re-ask the GridService about the location. if (m_notFoundLocationCache.Contains(px, py)) { - m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found via cache. loc=<{1},{2}>", LogHeader, px, py); +// m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found via cache. loc=<{1},{2}>", LogHeader, px, py); return null; } // As an optimization, since most regions will be legacy sized regions (256x256), first try to get // the region at the appropriate legacy region location. - uint possibleX = (uint)Math.Floor(px); - possibleX -= possibleX % Constants.RegionSize; - uint possibleY = (uint)Math.Floor(py); - possibleY -= possibleY % Constants.RegionSize; + // this is all that is needed on 0.9 grids + uint possibleX = (uint)px & 0xffffff00u; + uint possibleY = (uint)py & 0xffffff00u; ret = pGridService.GetRegionByPosition(pScopeID, (int)possibleX, (int)possibleY); if (ret != null) { - m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Found region using legacy size. rloc=<{1},{2}>. Rname={3}", - LogHeader, possibleX, possibleY, ret.RegionName); +// m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Found region using legacy size. rloc=<{1},{2}>. Rname={3}", +// LogHeader, possibleX, possibleY, ret.RegionName); + return ret; } - if (ret == null) + // for 0.8 regions just make a BIG area request. old code whould do it plus 4 more smaller on region open edges + // this is what 0.9 grids now do internally + List possibleRegions = pGridService.GetRegionRange(pScopeID, + (int)(px - Constants.MaximumRegionSize), (int)(px + 1), // +1 bc left mb not part of range + (int)(py - Constants.MaximumRegionSize), (int)(py + 1)); +// m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegions cnt={1}, range={2}", +// LogHeader, possibleRegions.Count, range); + if (possibleRegions != null && possibleRegions.Count > 0) { - // If the simple lookup failed, search the larger area for a region that contains this point - double range = (double)pSizeHint + fudge; - while (ret == null && range <= (Constants.MaximumRegionSize + Constants.RegionSize)) + // If we found some regions, check to see if the point is within + foreach (GridRegion gr in possibleRegions) { - // Get from the grid service a list of regions that might contain this point. - // The region origin will be in the zero direction so only subtract the range. - List possibleRegions = pGridService.GetRegionRange(pScopeID, - (int)(px - range), (int)(px), - (int)(py - range), (int)(py)); - m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegions cnt={1}, range={2}", - LogHeader, possibleRegions.Count, range); - if (possibleRegions != null && possibleRegions.Count > 0) - { - // If we found some regions, check to see if the point is within - foreach (GridRegion gr in possibleRegions) - { - m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegion nm={1}, regionLoc=<{2},{3}>, regionSize=<{4},{5}>", - LogHeader, gr.RegionName, gr.RegionLocX, gr.RegionLocY, gr.RegionSizeX, gr.RegionSizeY); - if (px >= (double)gr.RegionLocX && px < (double)(gr.RegionLocX + gr.RegionSizeX) +// m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegion nm={1}, regionLoc=<{2},{3}>, regionSize=<{4},{5}>", +// LogHeader, gr.RegionName, gr.RegionLocX, gr.RegionLocY, gr.RegionSizeX, gr.RegionSizeY); + if (px >= (double)gr.RegionLocX && px < (double)(gr.RegionLocX + gr.RegionSizeX) && py >= (double)gr.RegionLocY && py < (double)(gr.RegionLocY + gr.RegionSizeY)) - { - // Found a region that contains the point - ret = gr; - m_log.DebugFormat("{0} GetRegionContainingWorldLocation: found. RegionName={1}", LogHeader, ret.RegionName); - break; - } - } + { + // Found a region that contains the point + return gr; +// m_log.DebugFormat("{0} GetRegionContainingWorldLocation: found. RegionName={1}", LogHeader, ret.RegionName); } - // Larger search area for next time around if not found - range *= 2; } } - if (ret == null) - { - // remember this location was not found so we can quickly not find it next time - m_notFoundLocationCache.Add(px, py); - m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found. Remembering loc=<{1},{2}>", LogHeader, px, py); - } - - return ret; + // remember this location was not found so we can quickly not find it next time + m_notFoundLocationCache.Add(px, py); +// m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found. Remembering loc=<{1},{2}>", LogHeader, px, py); + return null; } private void InformClientOfNeighbourCompleted(IAsyncResult iar) @@ -2207,81 +2359,65 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// /// /// - private void InformClientOfNeighbourAsync(ScenePresence sp, AgentCircuitData a, GridRegion reg, + private void InformClientOfNeighbourAsync(ScenePresence sp, AgentCircuitData agentCircData, GridRegion reg, IPEndPoint endPoint, bool newAgent) { - // Let's wait just a little to give time to originating regions to catch up with closing child agents - // after a cross here - Thread.Sleep(500); - Scene scene = sp.Scene; - - m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Informing {0} {1} about neighbour {2} {3} at ({4},{5})", - sp.Name, sp.UUID, reg.RegionName, endPoint, reg.RegionCoordX, reg.RegionCoordY); + if (newAgent) + { + // we may already had lost this sp + if(sp == null || sp.IsDeleted || sp.ClientView == null) // something bad already happened + return; - string capsPath = reg.ServerURI + CapsUtil.GetCapsSeedPath(a.CapsPath); + Scene scene = sp.Scene; - string reason = String.Empty; + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Informing {0} {1} about neighbour {2} {3} at ({4},{5})", + sp.Name, sp.UUID, reg.RegionName, endPoint, reg.RegionCoordX, reg.RegionCoordY); - bool regionAccepted = scene.SimulationService.CreateAgent(null, reg, a, (uint)TeleportFlags.Default, out reason); + string capsPath = reg.ServerURI + CapsUtil.GetCapsSeedPath(agentCircData.CapsPath); - if (regionAccepted && newAgent) - { - if (m_eqModule != null) + string reason = String.Empty; + + EntityTransferContext ctx = new EntityTransferContext(); + bool regionAccepted = scene.SimulationService.CreateAgent(reg, reg, agentCircData, (uint)TeleportFlags.Default, ctx, out reason); + + if (regionAccepted) { - #region IP Translation for NAT - IClientIPEndpoint ipepClient; - if (sp.ClientView.TryGet(out ipepClient)) + // give time for createAgent to finish, since it is async and does grid services access + Thread.Sleep(500); + + if (m_eqModule != null) { - endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); - } - #endregion + if(sp == null || sp.IsDeleted || sp.ClientView == null) // something bad already happened + return; + + m_log.DebugFormat("{0} {1} is sending {2} EnableSimulator for neighbour region {3}(loc=<{4},{5}>,siz=<{6},{7}>) " + + "and EstablishAgentCommunication with seed cap {8}", LogHeader, + scene.RegionInfo.RegionName, sp.Name, + reg.RegionName, reg.RegionLocX, reg.RegionLocY, reg.RegionSizeX, reg.RegionSizeY, capsPath); - m_log.DebugFormat("{0} {1} is sending {2} EnableSimulator for neighbour region {3}(loc=<{4},{5}>,siz=<{6},{7}>) " + - "and EstablishAgentCommunication with seed cap {8}", LogHeader, - scene.RegionInfo.RegionName, sp.Name, - reg.RegionName, reg.RegionLocX, reg.RegionLocY, reg.RegionSizeX, reg.RegionSizeY , capsPath); + m_eqModule.EnableSimulator(reg.RegionHandle, endPoint, sp.UUID, reg.RegionSizeX, reg.RegionSizeY); + m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath, reg.RegionHandle, reg.RegionSizeX, reg.RegionSizeY); + } + else + { + sp.ControllingClient.InformClientOfNeighbour(reg.RegionHandle, endPoint); + // TODO: make Event Queue disablable! + } - m_eqModule.EnableSimulator(reg.RegionHandle, endPoint, sp.UUID, reg.RegionSizeX, reg.RegionSizeY); - m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath, reg.RegionHandle, reg.RegionSizeX, reg.RegionSizeY); + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Completed inform {0} {1} about neighbour {2}", sp.Name, sp.UUID, endPoint); } + else { - sp.ControllingClient.InformClientOfNeighbour(reg.RegionHandle, endPoint); - // TODO: make Event Queue disablable! + sp.RemoveNeighbourRegion(reg.RegionHandle); + m_log.WarnFormat( + "[ENTITY TRANSFER MODULE]: Region {0} did not accept {1} {2}: {3}", + reg.RegionName, sp.Name, sp.UUID, reason); } - - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Completed inform {0} {1} about neighbour {2}", sp.Name, sp.UUID, endPoint); } - if (!regionAccepted) - m_log.WarnFormat( - "[ENTITY TRANSFER MODULE]: Region {0} did not accept {1} {2}: {3}", - reg.RegionName, sp.Name, sp.UUID, reason); - } - - /// - /// Gets the range considered in view of this megaregion (assuming this is a megaregion). - /// - /// Expressed in 256m units - /// - /// - private void GetMegaregionViewRange(out Vector2 swCorner, out Vector2 neCorner) - { - Vector2 extent = Vector2.Zero; - - if (m_regionCombinerModule != null) - { - Vector2 megaRegionSize = m_regionCombinerModule.GetSizeOfMegaregion(Scene.RegionInfo.RegionID); - extent.X = (float)Util.WorldToRegionLoc((uint)megaRegionSize.X); - extent.Y = (float)Util.WorldToRegionLoc((uint)megaRegionSize.Y); - } - - swCorner.X = Scene.RegionInfo.RegionLocX - 1; - swCorner.Y = Scene.RegionInfo.RegionLocY - 1; - neCorner.X = Scene.RegionInfo.RegionLocX + extent.X; - neCorner.Y = Scene.RegionInfo.RegionLocY + extent.Y; } /// @@ -2290,98 +2426,42 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// /// /// - /// - protected List GetNeighbours(ScenePresence avatar, uint pRegionLocX, uint pRegionLocY) + /// + protected List GetNeighbors(ScenePresence avatar, uint pRegionLocX, uint pRegionLocY) { Scene pScene = avatar.Scene; RegionInfo m_regionInfo = pScene.RegionInfo; List neighbours; - // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't - // clear what should be done with a "far view" given that megaregions already extended the - // view to include everything in the megaregion - if (m_regionCombinerModule == null || !m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID)) - { - // The area to check is as big as the current region. - // We presume all adjacent regions are the same size as this region. - uint dd = Math.Max((uint)avatar.Scene.DefaultDrawDistance, - Math.Max(Scene.RegionInfo.RegionSizeX, Scene.RegionInfo.RegionSizeY)); + uint dd = (uint)avatar.RegionViewDistance; - uint startX = Util.RegionToWorldLoc(pRegionLocX) - dd + Constants.RegionSize/2; - uint startY = Util.RegionToWorldLoc(pRegionLocY) - dd + Constants.RegionSize/2; + // until avatar movement updates client connections, we need to seend at least this current region imediate neighbors + uint ddX = Math.Max(dd, Constants.RegionSize); + uint ddY = Math.Max(dd, Constants.RegionSize); - uint endX = Util.RegionToWorldLoc(pRegionLocX) + dd + Constants.RegionSize/2; - uint endY = Util.RegionToWorldLoc(pRegionLocY) + dd + Constants.RegionSize/2; + ddX--; + ddY--; - neighbours - = avatar.Scene.GridService.GetRegionRange( - m_regionInfo.ScopeID, (int)startX, (int)endX, (int)startY, (int)endY); - } - else - { - Vector2 swCorner, neCorner; - GetMegaregionViewRange(out swCorner, out neCorner); + // reference to region edges. Should be avatar position + uint startX = Util.RegionToWorldLoc(pRegionLocX); + uint endX = startX + m_regionInfo.RegionSizeX; + uint startY = Util.RegionToWorldLoc(pRegionLocY); + uint endY = startY + m_regionInfo.RegionSizeY; - neighbours - = pScene.GridService.GetRegionRange( - m_regionInfo.ScopeID, - (int)Util.RegionToWorldLoc((uint)swCorner.X), (int)Util.RegionToWorldLoc((uint)neCorner.X), - (int)Util.RegionToWorldLoc((uint)swCorner.Y), (int)Util.RegionToWorldLoc((uint)neCorner.Y)); - } + startX -= ddX; + startY -= ddY; + endX += ddX; + endY += ddY; -// neighbours.ForEach( -// n => -// m_log.DebugFormat( -// "[ENTITY TRANSFER MODULE]: Region flags for {0} as seen by {1} are {2}", -// n.RegionName, Scene.Name, n.RegionFlags != null ? n.RegionFlags.ToString() : "not present")); + neighbours + = avatar.Scene.GridService.GetRegionRange( + m_regionInfo.ScopeID, (int)startX, (int)endX, (int)startY, (int)endY); // The r.RegionFlags == null check only needs to be made for simulators before 2015-01-14 (pre 0.8.1). - neighbours.RemoveAll( - r => - r.RegionID == m_regionInfo.RegionID - || (r.RegionFlags != null && (r.RegionFlags & OpenSim.Framework.RegionFlags.RegionOnline) == 0)); + neighbours.RemoveAll( r => r.RegionID == m_regionInfo.RegionID ); return neighbours; } - - private List NewNeighbours(List currentNeighbours, List previousNeighbours) - { - return currentNeighbours.FindAll(delegate(ulong handle) { return !previousNeighbours.Contains(handle); }); - } - - // private List CommonNeighbours(List currentNeighbours, List previousNeighbours) - // { - // return currentNeighbours.FindAll(delegate(ulong handle) { return previousNeighbours.Contains(handle); }); - // } - - private List OldNeighbours(List currentNeighbours, List previousNeighbours) - { - return previousNeighbours.FindAll(delegate(ulong handle) { return !currentNeighbours.Contains(handle); }); - } - - private List NeighbourHandles(List neighbours) - { - List handles = new List(); - foreach (GridRegion reg in neighbours) - { - handles.Add(reg.RegionHandle); - } - return handles; - } - -// private void Dump(string msg, List handles) -// { -// m_log.InfoFormat("-------------- HANDLE DUMP ({0}) ---------", msg); -// foreach (ulong handle in handles) -// { -// uint x, y; -// Utils.LongToUInts(handle, out x, out y); -// x = x / Constants.RegionSize; -// y = y / Constants.RegionSize; -// m_log.InfoFormat("({0}, {1})", x, y); -// } -// } - #endregion #region Agent Arrived @@ -2395,83 +2475,47 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer #region Object Transfers - /// - /// Move the given scene object into a new region depending on which region its absolute position has moved - /// into. - /// - /// Using the objects new world location, ask the grid service for a the new region and adjust the prim - /// position to be relative to the new region. - /// - /// the scene object that we're crossing - /// the attempted out of region position of the scene object. This position is - /// relative to the region the object currently is in. - /// if 'true', the deletion of the client from the region is not broadcast to the clients - public void Cross(SceneObjectGroup grp, Vector3 attemptedPosition, bool silent) + public GridRegion GetObjectDestination(SceneObjectGroup grp, Vector3 targetPosition,out Vector3 newpos) { - if (grp == null) - return; - if (grp.IsDeleted) - return; + newpos = targetPosition; Scene scene = grp.Scene; if (scene == null) - return; - - if (grp.RootPart.DIE_AT_EDGE) - { - // We remove the object here - try - { - scene.DeleteSceneObject(grp, false); - } - catch (Exception) - { - m_log.Warn("[DATABASE]: exception when trying to remove the prim that crossed the border."); - } - return; - } - - // Remember the old group position in case the region lookup fails so position can be restored. - Vector3 oldGroupPosition = grp.RootPart.GroupPosition; + return null; - // Compute the absolute position of the object. - double objectWorldLocX = (double)scene.RegionInfo.WorldLocX + attemptedPosition.X; - double objectWorldLocY = (double)scene.RegionInfo.WorldLocY + attemptedPosition.Y; + int x = (int)targetPosition.X + (int)scene.RegionInfo.WorldLocX; + if (targetPosition.X >= 0) + x++; + else + x--; - // Ask the grid service for the region that contains the passed address - GridRegion destination = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID, - objectWorldLocX, objectWorldLocY); + int y = (int)targetPosition.Y + (int)scene.RegionInfo.WorldLocY; + if (targetPosition.Y >= 0) + y++; + else + y--; - Vector3 pos = Vector3.Zero; - if (destination != null) + GridRegion neighbourRegion = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID,x,y); + if (neighbourRegion == null) { - // Adjust the object's relative position from the old region (attemptedPosition) - // to be relative to the new region (pos). - pos = new Vector3( (float)(objectWorldLocX - (double)destination.RegionLocX), - (float)(objectWorldLocY - (double)destination.RegionLocY), - attemptedPosition.Z); + return null; } - if (destination == null || !CrossPrimGroupIntoNewRegion(destination, pos, grp, silent)) - { - m_log.InfoFormat("[ENTITY TRANSFER MODULE] cross region transfer failed for object {0}", grp.UUID); - - // We are going to move the object back to the old position so long as the old position - // is in the region - oldGroupPosition.X = Util.Clamp(oldGroupPosition.X, 1.0f, (float)(scene.RegionInfo.RegionSizeX - 1)); - oldGroupPosition.Y = Util.Clamp(oldGroupPosition.Y, 1.0f, (float)(scene.RegionInfo.RegionSizeY - 1)); - oldGroupPosition.Z = Util.Clamp(oldGroupPosition.Z, 1.0f, Constants.RegionHeight); + float newRegionSizeX = neighbourRegion.RegionSizeX; + float newRegionSizeY = neighbourRegion.RegionSizeY; + if (newRegionSizeX == 0) + newRegionSizeX = Constants.RegionSize; + if (newRegionSizeY == 0) + newRegionSizeY = Constants.RegionSize; - grp.AbsolutePosition = oldGroupPosition; - grp.Velocity = Vector3.Zero; - if (grp.RootPart.PhysActor != null) - grp.RootPart.PhysActor.CrossingFailure(); + newpos.X = targetPosition.X - (neighbourRegion.RegionLocX - (int)scene.RegionInfo.WorldLocX); + newpos.Y = targetPosition.Y - (neighbourRegion.RegionLocY - (int)scene.RegionInfo.WorldLocY); - if (grp.RootPart.KeyframeMotion != null) - grp.RootPart.KeyframeMotion.CrossingFailure(); + const float enterDistance = 0.2f; + newpos.X = Util.Clamp(newpos.X, enterDistance, newRegionSizeX - enterDistance); + newpos.Y = Util.Clamp(newpos.Y, enterDistance, newRegionSizeY - enterDistance); - grp.ScheduleGroupForFullUpdate(); - } + return neighbourRegion; } /// @@ -2483,10 +2527,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// true if the crossing itself was successful, false on failure /// FIMXE: we still return true if the crossing object was not successfully deleted from the originating region /// - protected bool CrossPrimGroupIntoNewRegion(GridRegion destination, Vector3 newPosition, SceneObjectGroup grp, bool silent) + public bool CrossPrimGroupIntoNewRegion(GridRegion destination, Vector3 newPosition, SceneObjectGroup grp, bool silent, bool removeScripts) { //m_log.Debug(" >>> CrossPrimGroupIntoNewRegion <<<"); + Culture.SetCurrentCulture(); + bool successYN = false; grp.RootPart.ClearUpdateSchedule(); //int primcrossingXMLmethod = 0; @@ -2515,7 +2561,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // We remove the object here try { - grp.Scene.DeleteSceneObject(grp, silent); + grp.Scene.DeleteSceneObject(grp, silent, removeScripts); } catch (Exception e) { @@ -2524,30 +2570,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer grp, e); } } -/* - * done on caller ( not in attachments crossing for now) - else - { - - if (!grp.IsDeleted) - { - PhysicsActor pa = grp.RootPart.PhysActor; - if (pa != null) - { - pa.CrossingFailure(); - if (grp.RootPart.KeyframeMotion != null) - { - // moved to KeyframeMotion.CrossingFailure -// grp.RootPart.Velocity = Vector3.Zero; - grp.RootPart.KeyframeMotion.CrossingFailure(); -// grp.SendGroupRootTerseUpdate(); - } - } - } - - m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: Prim crossing failed for {0}", grp); - } - */ } else { @@ -2589,7 +2611,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Sending attachment {0} to region {1}", clone.UUID, destination.RegionName); - CrossPrimGroupIntoNewRegion(destination, Vector3.Zero, clone, silent); + CrossPrimGroupIntoNewRegion(destination, Vector3.Zero, clone, silent,true); } } @@ -2639,7 +2661,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (Scene.RegionInfo.EstateSettings.IsBanned(so.OwnerID)) { m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Denied prim crossing of {0} {1} into {2} for banned avatar {3}", + "[ENTITY TRANSFER MODULE]: Denied prim crossing of {0} {1} into {2} for banned avatar {3}", so.Name, so.UUID, Scene.Name, so.OwnerID); return false; @@ -2651,7 +2673,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (!Scene.AddSceneObject(so)) { m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Problem adding scene object {0} {1} into {2} ", + "[ENTITY TRANSFER MODULE]: Problem adding scene object {0} {1} into {2} ", so.Name, so.UUID, Scene.Name); return false; @@ -2661,7 +2683,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { // FIXME: It would be better to never add the scene object at all rather than add it and then delete // it - if (!Scene.Permissions.CanObjectEntry(so.UUID, true, so.AbsolutePosition)) + if (!Scene.Permissions.CanObjectEntry(so, true, so.AbsolutePosition)) { // Deny non attachments based on parcel settings // @@ -2679,8 +2701,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer so.ResumeScripts(); - if (so.RootPart.KeyframeMotion != null) - so.RootPart.KeyframeMotion.UpdateSceneObject(so); + // AddSceneObject already does this and doing it again messes + //if (so.RootPart.KeyframeMotion != null) + // so.RootPart.KeyframeMotion.UpdateSceneObject(so); } return true; diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs index a3109e0..0a24555 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs @@ -101,7 +101,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// true if the agent was not already in transit, false if it was internal bool SetInTransit(UUID id) { - m_log.DebugFormat("{0} SetInTransit. agent={1}, newState=Preparing", LogHeader, id); +// m_log.DebugFormat("{0} SetInTransit. agent={1}, newState=Preparing", LogHeader, id); lock (m_agentsInTransit) { if (!m_agentsInTransit.ContainsKey(id)) @@ -123,7 +123,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// Illegal transitions will throw an Exception internal bool UpdateInTransit(UUID id, AgentTransferState newState) { - m_log.DebugFormat("{0} UpdateInTransit. agent={1}, newState={2}", LogHeader, id, newState); + // m_log.DebugFormat("{0} UpdateInTransit. agent={1}, newState={2}", LogHeader, id, newState); bool transitionOkay = false; @@ -169,7 +169,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } else { - if (newState == AgentTransferState.Cancelling + if (newState == AgentTransferState.Cancelling && (oldState == AgentTransferState.Preparing || oldState == AgentTransferState.Transferring)) { transitionOkay = true; @@ -181,7 +181,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } if (!transitionOkay) - failureMessage + failureMessage = string.Format( "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}", id, oldState, newState, m_mod.Scene.RegionInfo.RegionName); @@ -192,7 +192,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_agentsInTransit[id] = newState; // m_log.DebugFormat( -// "[ENTITY TRANSFER STATE MACHINE]: Changed agent with id {0} from state {1} to {2} in {3}", +// "[ENTITY TRANSFER STATE MACHINE]: Changed agent with id {0} from state {1} to {2} in {3}", // id, oldState, newState, m_mod.Scene.Name); } else if (failIfNotOkay) @@ -204,11 +204,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // { // if (oldState != null) // m_log.DebugFormat( -// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} from state {1} to {2} in {3}", +// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} from state {1} to {2} in {3}", // id, oldState, newState, m_mod.Scene.Name); // else // m_log.DebugFormat( -// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} to state {1} in {2} since agent not in transit", +// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} to state {1} in {2} since agent not in transit", // id, newState, m_mod.Scene.Name); // } } @@ -247,32 +247,32 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { AgentTransferState state = m_agentsInTransit[id]; - if (state == AgentTransferState.Transferring || state == AgentTransferState.ReceivedAtDestination) - { +// if (state == AgentTransferState.Transferring || state == AgentTransferState.ReceivedAtDestination) +// { // FIXME: For now, we allow exit from any state since a thrown exception in teleport is now guranteed // to be handled properly - ResetFromTransit() could be invoked at any step along the process - m_log.WarnFormat( - "[ENTITY TRANSFER STATE MACHINE]: Agent with ID {0} should not exit directly from state {1}, should go to {2} state first in {3}", - id, state, AgentTransferState.CleaningUp, m_mod.Scene.RegionInfo.RegionName); +// m_log.WarnFormat( +// "[ENTITY TRANSFER STATE MACHINE]: Agent with ID {0} should not exit directly from state {1}, should go to {2} state first in {3}", +// id, state, AgentTransferState.CleaningUp, m_mod.Scene.RegionInfo.RegionName); // throw new Exception( // "Agent with ID {0} cannot exit directly from state {1}, it must go to {2} state first", // state, AgentTransferState.CleaningUp); - } +// } m_agentsInTransit.Remove(id); - m_log.DebugFormat( - "[ENTITY TRANSFER STATE MACHINE]: Agent {0} cleared from transit in {1}", - id, m_mod.Scene.RegionInfo.RegionName); +// m_log.DebugFormat( +// "[ENTITY TRANSFER STATE MACHINE]: Agent {0} cleared from transit in {1}", +// id, m_mod.Scene.RegionInfo.RegionName); return true; } } - m_log.WarnFormat( - "[ENTITY TRANSFER STATE MACHINE]: Agent {0} requested to clear from transit in {1} but was already cleared", - id, m_mod.Scene.RegionInfo.RegionName); +// m_log.WarnFormat( +// "[ENTITY TRANSFER STATE MACHINE]: Agent {0} requested to clear from transit in {1} but was already cleared", +// id, m_mod.Scene.RegionInfo.RegionName); return false; } @@ -281,7 +281,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { if (!m_mod.WaitForAgentArrivedAtDestination) return true; - + lock (m_agentsInTransit) { AgentTransferState? currentState = GetAgentTransferState(id); @@ -299,7 +299,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer id, m_mod.Scene.RegionInfo.RegionName, currentState)); } - int count = 200; + int count = 400; // There should be no race condition here since no other code should be removing the agent transfer or // changing the state to another other than Transferring => ReceivedAtDestination. @@ -354,4 +354,4 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs index fa23590..56c654f 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs @@ -95,8 +95,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer foreach (AvatarAttachment att in a.GetAttachments()) { - InventoryItemBase item = new InventoryItemBase(att.ItemID, account.PrincipalID); - item = Scene.InventoryService.GetItem(item); + InventoryItemBase item = Scene.InventoryService.GetItem(account.PrincipalID, att.ItemID); if (item != null) a.SetAttachment(att.AttachPoint, att.ItemID, item.AssetID); else @@ -161,10 +160,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer scene.RegisterModuleInterface(this); //scene.EventManager.OnIncomingSceneObject += OnIncomingSceneObject; - m_incomingSceneObjectEngine + m_incomingSceneObjectEngine = new JobEngine( - string.Format("HG Incoming Scene Object Engine ({0})", scene.Name), - "HG INCOMING SCENE OBJECT ENGINE"); + string.Format("HG Incoming Scene Object Engine ({0})", scene.Name), + "HG INCOMING SCENE OBJECT ENGINE", 30000); StatsManager.RegisterStat( new Stat( @@ -239,13 +238,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return region; } - protected override bool NeedsClosing(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg) + protected override bool NeedsClosing(GridRegion reg, bool OutViewRange) { - if (base.NeedsClosing(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) + if (OutViewRange) return true; int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID); - if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0) + if (flags == -1 || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0) return true; return false; @@ -263,7 +262,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } } - protected override bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout) + protected override bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, EntityTransferContext ctx, out string reason, out bool logout) { m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: CreateAgent {0} {1}", reg.ServerURI, finalDestination.ServerURI); reason = string.Empty; @@ -273,7 +272,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { // this user is going to another grid // for local users, check if HyperGrid teleport is allowed, based on user level - if (Scene.UserManagementModule.IsLocalGridUser(sp.UUID) && sp.UserLevel < m_levelHGTeleport) + if (Scene.UserManagementModule.IsLocalGridUser(sp.UUID) && sp.GodController.UserLevel < m_levelHGTeleport) { m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: Unable to HG teleport agent due to insufficient UserLevel."); reason = "Hypergrid teleport not allowed"; @@ -292,7 +291,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer GridRegion source = new GridRegion(Scene.RegionInfo); source.RawServerURI = m_GatekeeperURI; - + bool success = connector.LoginAgentToGrid(source, agentCircuit, reg, finalDestination, false, out reason); logout = success; // flag for later logout from this grid; this is an HG TP @@ -308,7 +307,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } } - return base.CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout); + return base.CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, ctx, out reason, out logout); + } + + public override void TriggerTeleportHome(UUID id, IClientAPI client) + { + TeleportHome(id, client); } protected override bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason) @@ -328,7 +332,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: RestrictAppearanceAbroad is ON. Checking generic appearance"); // Check wearables - for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++) + for (int i = 0; i < sp.Appearance.Wearables.Length ; i++) { for (int j = 0; j < sp.Appearance.Wearables[i].Count; j++) { @@ -337,13 +341,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer bool found = false; foreach (AvatarAppearance a in ExportedAppearance) - if (a.Wearables[i] != null) + if (i < a.Wearables.Length && a.Wearables[i] != null) { found = true; break; } - if (!found) + if (!found) { m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Wearable not allowed to go outside {0}", i); return false; @@ -351,7 +355,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer found = false; foreach (AvatarAppearance a in ExportedAppearance) - if (sp.Appearance.Wearables[i][j].AssetID == a.Wearables[i][j].AssetID) + if (i < a.Wearables.Length && sp.Appearance.Wearables[i][j].AssetID == a.Wearables[i][j].AssetID) { found = true; break; @@ -412,7 +416,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // // Rez needed npc attachments // Scene.AttachmentsModule.RezAttachments(sp); - + // IAvatarFactoryModule module = Scene.RequestModuleInterface(); // //module.SendAppearance(sp.UUID); // module.RequestRebake(sp, false); @@ -429,11 +433,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // return base.UpdateAgent(reg, finalDestination, agentData, sp); //} - public override void TriggerTeleportHome(UUID id, IClientAPI client) - { - TeleportHome(id, client); - } - + public override bool TeleportHome(UUID id, IClientAPI client) { m_log.DebugFormat( @@ -449,7 +449,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } // Foreign user wants to go home - // + // AgentCircuitData aCircuit = ((Scene)(client.Scene)).AuthenticateHandler.GetAgentCircuitData(client.CircuitCode); if (aCircuit == null || (aCircuit != null && !aCircuit.ServiceURLs.ContainsKey("HomeURI"))) { @@ -470,7 +470,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { m_log.Debug("[HG ENTITY TRANSFER MODULE]: GetHomeRegion call failed ", e); } - + if (finalDestination == null) { client.SendTeleportFailed("Your home region could not be found"); @@ -487,13 +487,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } GridRegion homeGatekeeper = MakeRegion(aCircuit); - + m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: teleporting user {0} {1} home to {2} via {3}:{4}", aCircuit.firstname, aCircuit.lastname, finalDestination.RegionName, homeGatekeeper.ServerURI, homeGatekeeper.RegionName); - DoTeleport( - sp, homeGatekeeper, finalDestination, - position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); + DoTeleport(sp, homeGatekeeper, finalDestination, position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); return true; } @@ -505,7 +503,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// public override void RequestTeleportLandmark(IClientAPI remoteClient, AssetLandmark lm) { - m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Teleporting agent via landmark to {0} region {1} position {2}", + m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Teleporting agent via landmark to {0} region {1} position {2}", (lm.Gatekeeper == string.Empty) ? "local" : lm.Gatekeeper, lm.RegionID, lm.Position); if (lm.Gatekeeper == string.Empty) @@ -523,7 +521,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer remoteClient, info.RegionHandle, lm.Position, Vector3.Zero, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark)); } - else + else { // Foreign region GatekeeperServiceConnector gConn = new GatekeeperServiceConnector(); @@ -583,7 +581,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer jobsRemoved, commonIdToRemove, jobsToReinsert.Count); if (jobsToReinsert.Count > 0) - { + { foreach (JobEngine.Job jobToReinsert in jobsToReinsert) m_incomingSceneObjectEngine.QueueJob(jobToReinsert); } @@ -613,16 +611,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI")) { m_incomingSceneObjectEngine.QueueJob( - string.Format("HG UUID Gather for attachment {0} for {1}", so.Name, aCircuit.Name), - () => + string.Format("HG UUID Gather for attachment {0} for {1}", so.Name, aCircuit.Name), + () => { string url = aCircuit.ServiceURLs["AssetServerURI"].ToString(); // m_log.DebugFormat( - // "[HG ENTITY TRANSFER MODULE]: Incoming attachment {0} for HG user {1} with asset service {2}", + // "[HG ENTITY TRANSFER MODULE]: Incoming attachment {0} for HG user {1} with asset service {2}", // so.Name, so.AttachedAvatar, url); IDictionary ids = new Dictionary(); - HGUuidGatherer uuidGatherer + HGUuidGatherer uuidGatherer = new HGUuidGatherer(Scene.AssetService, url, ids); uuidGatherer.AddForInspection(so); @@ -648,7 +646,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer RemoveIncomingSceneObjectJobs(so.OwnerID.ToString()); return; - } + } } // m_log.DebugFormat( @@ -659,7 +657,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { int tickStart = Util.EnvironmentTickCount(); - uuidGatherer.FetchAsset(kvp.Key); + uuidGatherer.FetchAsset(kvp.Key); int ticksElapsed = Util.EnvironmentTickCountSubtract(tickStart); @@ -672,15 +670,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer RemoveIncomingSceneObjectJobs(so.OwnerID.ToString()); return; - } + } } base.HandleIncomingSceneObject(so, newPosition); // m_log.DebugFormat( - // "[HG ENTITY TRANSFER MODULE]: Completed incoming attachment {0} for HG user {1} with asset server {2}", + // "[HG ENTITY TRANSFER MODULE]: Completed incoming attachment {0} for HG user {1} with asset server {2}", // so.Name, so.OwnerID, url); - }, + }, so.OwnerID.ToString()); } } @@ -700,7 +698,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer string url = aCircuit.ServiceURLs["HomeURI"].ToString(); IUserAgentService security = new UserAgentServiceConnector(url); return security.VerifyClient(aCircuit.SessionID, token); - } + } else { m_log.DebugFormat( @@ -748,7 +746,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer GridRegion region = new GridRegion(); Uri uri = null; - if (!aCircuit.ServiceURLs.ContainsKey("HomeURI") || + if (!aCircuit.ServiceURLs.ContainsKey("HomeURI") || (aCircuit.ServiceURLs.ContainsKey("HomeURI") && !Uri.TryCreate(aCircuit.ServiceURLs["HomeURI"].ToString(), UriKind.Absolute, out uri))) return null; @@ -760,4 +758,4 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return region; } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/Framework/InterfaceCommander/Commander.cs b/OpenSim/Region/CoreModules/Framework/InterfaceCommander/Commander.cs index b5a4005..63dbb19 100644 --- a/OpenSim/Region/CoreModules/Framework/InterfaceCommander/Commander.cs +++ b/OpenSim/Region/CoreModules/Framework/InterfaceCommander/Commander.cs @@ -41,34 +41,34 @@ namespace OpenSim.Region.CoreModules.Framework.InterfaceCommander public class Commander : ICommander { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + /// /// Used in runtime class generation /// private string m_generatedApiClassName; - + public string Name { get { return m_name; } } private string m_name; - + public string Help { get { StringBuilder sb = new StringBuilder(); - + sb.AppendLine("=== " + m_name + " ==="); - + foreach (ICommand com in m_commands.Values) { sb.AppendLine("* " + Name + " " + com.Name + " - " + com.Help); } - + return sb.ToString(); } - } + } /// /// Constructor @@ -78,7 +78,7 @@ namespace OpenSim.Region.CoreModules.Framework.InterfaceCommander { m_name = name; m_generatedApiClassName = m_name[0].ToString().ToUpper(); - + if (m_name.Length > 1) m_generatedApiClassName += m_name.Substring(1); } @@ -87,7 +87,7 @@ namespace OpenSim.Region.CoreModules.Framework.InterfaceCommander { get { return m_commands; } } - private Dictionary m_commands = new Dictionary(); + private Dictionary m_commands = new Dictionary(); #region ICommander Members @@ -162,7 +162,7 @@ namespace OpenSim.Region.CoreModules.Framework.InterfaceCommander { if (function != "help") Console.WriteLine("ERROR: Invalid command - No such command exists"); - + Console.Write(Help); } } diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs index f54298c..51ae217 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs @@ -178,7 +178,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { UUID uuid = UUID.Zero; UUID.TryParse(meta.CreatorID, out uuid); - UserAccount creator = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid); + UserAccount creator = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid); if (creator != null) meta.CreatorID = m_HomeURI + ";" + creator.FirstName + " " + creator.LastName; } @@ -300,8 +300,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { m_log.Error( string.Format( - "[HG ASSET MAPPER]: Failed to post asset {0} (type {1}, length {2}) referenced from {3} to {4} with exception ", - asset.ID, asset.Type, asset.Data.Length, assetID, userAssetURL), + "[HG ASSET MAPPER]: Failed to post asset {0} (type {1}, length {2}) referenced from {3} to {4} with exception ", + asset.ID, asset.Type, asset.Data.Length, assetID, userAssetURL), e); // For debugging purposes for now we will continue to throw the exception up the stack as was already happening. However, after @@ -315,7 +315,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess else { m_log.DebugFormat( - "[HG ASSET MAPPER]: Didn't post asset {0} referenced from {1} because it already exists in asset server {2}", + "[HG ASSET MAPPER]: Didn't post asset {0} referenced from {1} because it already exists in asset server {2}", uuid, assetID, userAssetURL); } } diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs index 582b267..ba3a7c9 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs @@ -91,9 +91,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if (name == Name) { m_Enabled = true; - + InitialiseCommon(source); - + m_log.InfoFormat("[HG INVENTORY ACCESS MODULE]: {0} enabled.", Name); IConfig thisModuleConfig = source.Configs["HGInventoryAccessModule"]; @@ -117,7 +117,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess m_log.Warn("[HG INVENTORY ACCESS MODULE]: HGInventoryAccessModule configs not found. ProfileServerURI not set!"); m_bypassPermissions = !Util.GetConfigVarFromSections(source, "serverside_object_permissions", - new string[] { "Startup", "Permissions" }, true); + new string[] { "Startup", "Permissions" }, true); } } @@ -209,7 +209,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } } - public void PostInventoryAsset(UUID avatarID, AssetType type, UUID assetID, string name, int userlevel) + private void PostInventoryAsset(InventoryItemBase item, int userlevel) + { + InventoryFolderBase f = m_Scene.InventoryService.GetFolderForType(item.Owner, FolderType.Trash); + if (f == null || (f != null && item.Folder != f.ID)) + PostInventoryAsset(item.Owner, (AssetType)item.AssetType, item.AssetID, item.Name, userlevel); + } + + private void PostInventoryAsset(UUID avatarID, AssetType type, UUID assetID, string name, int userlevel) { if (type == AssetType.Link) return; @@ -241,26 +248,34 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } - /// + /// /// CapsUpdateInventoryItemAsset /// public override UUID CapsUpdateInventoryItemAsset(IClientAPI remoteClient, UUID itemID, byte[] data) { UUID newAssetID = base.CapsUpdateInventoryItemAsset(remoteClient, itemID, data); - PostInventoryAsset(remoteClient.AgentId, AssetType.Unknown, newAssetID, "", 0); + // We need to construct this here to satisfy the calling convention. + // Better this in two places than five formal params in all others. + InventoryItemBase item = new InventoryItemBase(); + item.Owner = remoteClient.AgentId; + item.AssetType = (int)AssetType.Unknown; + item.AssetID = newAssetID; + item.Name = String.Empty; + + PostInventoryAsset(item, 0); return newAssetID; } - /// + /// /// UpdateInventoryItemAsset /// public override bool UpdateInventoryItemAsset(UUID ownerID, InventoryItemBase item, AssetBase asset) { if (base.UpdateInventoryItemAsset(ownerID, item, asset)) { - PostInventoryAsset(ownerID, (AssetType)asset.Type, asset.FullID, asset.Name, 0); + PostInventoryAsset(item, 0); return true; } @@ -273,25 +288,45 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess protected override void ExportAsset(UUID agentID, UUID assetID) { if (!assetID.Equals(UUID.Zero)) - PostInventoryAsset(agentID, AssetType.Unknown, assetID, "", 0); + { + InventoryItemBase item = new InventoryItemBase(); + item.Owner = agentID; + item.AssetType = (int)AssetType.Unknown; + item.AssetID = assetID; + item.Name = String.Empty; + + PostInventoryAsset(item, 0); + } else + { m_log.Debug("[HGScene]: Scene.Inventory did not create asset"); + } } /// /// RezObject /// - public override SceneObjectGroup RezObject(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart, - UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, - bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) + // compatibility do not use + public override SceneObjectGroup RezObject( + IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart, + UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, + bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) + { + return RezObject(remoteClient, itemID, UUID.Zero, RayEnd, RayStart, + RayTargetID, BypassRayCast, RayEndIsIntersection, + RezSelected, RemoveItem, fromTaskID, attachment); + } + + public override SceneObjectGroup RezObject(IClientAPI remoteClient, UUID itemID, + UUID groupID, Vector3 RayEnd, Vector3 RayStart, + UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, + bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) { - m_log.DebugFormat("[HGScene]: RezObject itemID={0} fromTaskID={1}", itemID, fromTaskID); + //m_log.DebugFormat("[HGScene]: RezObject itemID={0} fromTaskID={1}", itemID, fromTaskID); //if (fromTaskID.Equals(UUID.Zero)) //{ - InventoryItemBase item = new InventoryItemBase(itemID); - item.Owner = remoteClient.AgentId; - item = m_Scene.InventoryService.GetItem(item); + InventoryItemBase item = m_Scene.InventoryService.GetItem(remoteClient.AgentId, itemID); //if (item == null) //{ // Fetch the item // item = new InventoryItemBase(); @@ -308,7 +343,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess //} // OK, we're done fetching. Pass it up to the default RezObject - SceneObjectGroup sog = base.RezObject(remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection, + SceneObjectGroup sog = base.RezObject(remoteClient, itemID, groupID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection, RezSelected, RemoveItem, fromTaskID, attachment); return sog; @@ -351,7 +386,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if (!m_CheckSeparateAssets) { if (!UserManagementModule.IsLocalGridUser(userID)) - { // foreign + { // foreign ScenePresence sp = null; if (m_Scene.TryGetScenePresence(userID, out sp)) { @@ -489,7 +524,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess foreach (InventoryItemBase it in content.Items) it.Name = it.Name + " (Unavailable)"; ; - // Send the new names + // Send the new names inv.SendBulkUpdateInventory(keep.ToArray(), content.Items.ToArray()); } @@ -506,16 +541,17 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess #region Permissions - private bool CanTakeObject(UUID objectID, UUID stealer, Scene scene) + private bool CanTakeObject(SceneObjectGroup sog, ScenePresence sp) { if (m_bypassPermissions) return true; - if (!m_OutboundPermission && !UserManagementModule.IsLocalGridUser(stealer)) + if(sp == null || sog == null) + return false; + + if (!m_OutboundPermission && !UserManagementModule.IsLocalGridUser(sp.UUID)) { - SceneObjectGroup sog = null; - if (m_Scene.TryGetSceneObjectGroup(objectID, out sog) && sog.OwnerID == stealer) + if (sog.OwnerID == sp.UUID) return true; - return false; } @@ -535,4 +571,4 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess #endregion } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 5a9efb8..788ed1c 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -68,7 +68,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess return m_UserManagement; } } - + public bool CoalesceMultipleObjectsToInventory { get; set; } #region INonSharedRegionModule @@ -92,14 +92,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if (name == Name) { m_Enabled = true; - + InitialiseCommon(source); - - m_log.InfoFormat("[INVENTORY ACCESS MODULE]: {0} enabled.", Name); + + m_log.InfoFormat("[INVENTORY ACCESS MODULE]: {0} enabled.", Name); } } } - + /// /// Common module config for both this and descendant classes. /// @@ -107,9 +107,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess protected virtual void InitialiseCommon(IConfigSource source) { IConfig inventoryConfig = source.Configs["Inventory"]; - + if (inventoryConfig != null) - CoalesceMultipleObjectsToInventory + CoalesceMultipleObjectsToInventory = inventoryConfig.GetBoolean("CoalesceMultipleObjectsToInventory", true); else CoalesceMultipleObjectsToInventory = true; @@ -175,53 +175,73 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess /// public void CreateNewInventoryItem(IClientAPI remoteClient, UUID transactionID, UUID folderID, uint callbackID, string description, string name, sbyte invType, - sbyte assetType, - byte wearableType, uint nextOwnerMask, int creationDate) + sbyte assetType, byte wearableType, + uint nextOwnerMask, int creationDate) { - m_log.DebugFormat("[INVENTORY ACCESS MODULE]: Received request to create inventory item {0} in folder {1}", name, folderID); + m_log.DebugFormat("[INVENTORY ACCESS MODULE]: Received request to create inventory item {0} in folder {1}, transactionID {2}", name, + folderID, transactionID); if (!m_Scene.Permissions.CanCreateUserInventory(invType, remoteClient.AgentId)) return; - if (transactionID == UUID.Zero) + InventoryFolderBase folder = m_Scene.InventoryService.GetFolder(remoteClient.AgentId, folderID); + + if (folder == null && Enum.IsDefined(typeof(FolderType), (sbyte)invType)) { - ScenePresence presence; - if (m_Scene.TryGetScenePresence(remoteClient.AgentId, out presence)) - { - byte[] data = null; + folder = m_Scene.InventoryService.GetFolderForType(remoteClient.AgentId, (FolderType)invType); + if (folder != null) + m_log.DebugFormat("[INVENTORY ACCESS MODULE]: Requested folder not found but found folder for type {0}", invType); + } - if (invType == (sbyte)InventoryType.Landmark && presence != null) - { - string suffix = string.Empty, prefix = string.Empty; - string strdata = GenerateLandmark(presence, out prefix, out suffix); - data = Encoding.ASCII.GetBytes(strdata); - name = prefix + name; - description += suffix; - } + if (folder == null || folder.Owner != remoteClient.AgentId) + return; - AssetBase asset = m_Scene.CreateAsset(name, description, assetType, data, remoteClient.AgentId); - m_Scene.AssetService.Store(asset); - m_Scene.CreateNewInventoryItem( - remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID, - name, description, 0, callbackID, asset.FullID, asset.Type, invType, nextOwnerMask, creationDate); - } - else - { - m_log.ErrorFormat( - "[INVENTORY ACCESS MODULE]: ScenePresence for agent uuid {0} unexpectedly not found in CreateNewInventoryItem", - remoteClient.AgentId); - } - } - else + if (transactionID != UUID.Zero) { IAgentAssetTransactions agentTransactions = m_Scene.AgentTransactionsModule; if (agentTransactions != null) { - agentTransactions.HandleItemCreationFromTransaction( + if (agentTransactions.HandleItemCreationFromTransaction( remoteClient, transactionID, folderID, callbackID, description, - name, invType, assetType, wearableType, nextOwnerMask); + name, invType, assetType, wearableType, nextOwnerMask)) + return; } } + + ScenePresence presence; + if (m_Scene.TryGetScenePresence(remoteClient.AgentId, out presence)) + { + byte[] data = null; + uint everyonemask = 0; + uint groupmask = 0; + + if (invType == (sbyte)InventoryType.Landmark && presence != null) + { + string suffix = string.Empty, prefix = string.Empty; + string strdata = GenerateLandmark(presence, out prefix, out suffix); + data = Encoding.ASCII.GetBytes(strdata); + name = prefix + name; + description += suffix; + groupmask = (uint)PermissionMask.AllAndExport; + everyonemask = (uint)(PermissionMask.AllAndExport & ~PermissionMask.Modify); + } + + AssetBase asset = m_Scene.CreateAsset(name, description, assetType, data, remoteClient.AgentId); + m_Scene.AssetService.Store(asset); + m_Scene.CreateNewInventoryItem( + remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID, + name, description, 0, callbackID, asset.FullID, asset.Type, invType, + (uint)PermissionMask.AllAndExport, // Base + (uint)PermissionMask.AllAndExport, // Current + everyonemask, + nextOwnerMask, groupmask, creationDate, false); // Data from viewer + } + else + { + m_log.ErrorFormat( + "[INVENTORY ACCESS MODULE]: ScenePresence for agent uuid {0} unexpectedly not found in CreateNewInventoryItem", + remoteClient.AgentId); + } } protected virtual string GenerateLandmark(ScenePresence presence, out string prefix, out string suffix) @@ -244,53 +264,65 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess /// public virtual UUID CapsUpdateInventoryItemAsset(IClientAPI remoteClient, UUID itemID, byte[] data) { - InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); - item = m_Scene.InventoryService.GetItem(item); + InventoryItemBase item = m_Scene.InventoryService.GetItem(remoteClient.AgentId, itemID); + + if (item == null) + { + m_log.ErrorFormat( + "[INVENTORY ACCESS MODULE]: Could not find item {0} for caps inventory update", itemID); + return UUID.Zero; + } if (item.Owner != remoteClient.AgentId) return UUID.Zero; - if (item != null) + if ((InventoryType)item.InvType == InventoryType.Notecard) { - if ((InventoryType)item.InvType == InventoryType.Notecard) + if (!m_Scene.Permissions.CanEditNotecard(itemID, UUID.Zero, remoteClient.AgentId)) { - if (!m_Scene.Permissions.CanEditNotecard(itemID, UUID.Zero, remoteClient.AgentId)) - { - remoteClient.SendAgentAlertMessage("Insufficient permissions to edit notecard", false); - return UUID.Zero; - } - - remoteClient.SendAlertMessage("Notecard saved"); + remoteClient.SendAgentAlertMessage("Insufficient permissions to edit notecard", false); + return UUID.Zero; } - else if ((InventoryType)item.InvType == InventoryType.LSL) - { - if (!m_Scene.Permissions.CanEditScript(itemID, UUID.Zero, remoteClient.AgentId)) - { - remoteClient.SendAgentAlertMessage("Insufficient permissions to edit script", false); - return UUID.Zero; - } - remoteClient.SendAlertMessage("Script saved"); + remoteClient.SendAlertMessage("Notecard saved"); + } + else if ((InventoryType)item.InvType == InventoryType.LSL) + { + if (!m_Scene.Permissions.CanEditScript(itemID, UUID.Zero, remoteClient.AgentId)) + { + remoteClient.SendAgentAlertMessage("Insufficient permissions to edit script", false); + return UUID.Zero; } - AssetBase asset = - CreateAsset(item.Name, item.Description, (sbyte)item.AssetType, data, remoteClient.AgentId.ToString()); - item.AssetID = asset.FullID; - m_Scene.AssetService.Store(asset); - - m_Scene.InventoryService.UpdateItem(item); - - // remoteClient.SendInventoryItemCreateUpdate(item); - return (asset.FullID); + remoteClient.SendAlertMessage("Script saved"); } - else + else if ((CustomInventoryType)item.InvType == CustomInventoryType.AnimationSet) { - m_log.ErrorFormat( - "[INVENTORY ACCESS MODULE]: Could not find item {0} for caps inventory update", - itemID); + AnimationSet animSet = new AnimationSet(data); + uint res = animSet.Validate(x => { + const int required = (int)(PermissionMask.Transfer | PermissionMask.Copy); + int perms = m_Scene.InventoryService.GetAssetPermissions(remoteClient.AgentId, x); + // enforce previus perm rule + if ((perms & required) != required) + return 0; + return (uint) perms; + }); + if(res == 0) + { + remoteClient.SendAgentAlertMessage("Not enought permissions on asset(s) referenced by animation set '{0}', update failed", false); + return UUID.Zero; + } } - return UUID.Zero; + AssetBase asset = + CreateAsset(item.Name, item.Description, (sbyte)item.AssetType, data, remoteClient.AgentId.ToString()); + item.AssetID = asset.FullID; + m_Scene.AssetService.Store(asset); + + m_Scene.InventoryService.UpdateItem(item); + + // remoteClient.SendInventoryItemCreateUpdate(item); + return (asset.FullID); } public virtual bool UpdateInventoryItemAsset(UUID ownerID, InventoryItemBase item, AssetBase asset) @@ -298,7 +330,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if (item != null && item.Owner == ownerID && asset != null) { // m_log.DebugFormat( -// "[INVENTORY ACCESS MODULE]: Updating item {0} {1} with new asset {2}", +// "[INVENTORY ACCESS MODULE]: Updating item {0} {1} with new asset {2}", // item.Name, item.ID, asset.ID); item.AssetID = asset.FullID; @@ -327,7 +359,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess List copiedItems = new List(); Dictionary> bundlesToCopy = new Dictionary>(); - + if (CoalesceMultipleObjectsToInventory) { // The following code groups the SOG's by owner. No objects @@ -337,7 +369,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { if (!bundlesToCopy.ContainsKey(g.OwnerID)) bundlesToCopy[g.OwnerID] = new List(); - + bundlesToCopy[g.OwnerID].Add(g); } } @@ -348,7 +380,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { List bundle = new List(); bundle.Add(g); - bundlesToCopy[g.UUID] = bundle; + bundlesToCopy[g.UUID] = bundle; } } @@ -360,10 +392,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // with distinct destinations as well. foreach (List bundle in bundlesToCopy.Values) copiedItems.Add(CopyBundleToInventory(action, folderID, bundle, remoteClient, asAttachment)); - + return copiedItems; } - + /// /// Copy a bundle of objects to inventory. If there is only one object, then this will create an object /// item. If there are multiple objects then these will be saved as a single coalesced item. @@ -379,33 +411,42 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess DeRezAction action, UUID folderID, List objlist, IClientAPI remoteClient, bool asAttachment) { - CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); -// Dictionary originalPositions = new Dictionary(); - - Dictionary group2Keyframe = new Dictionary(); + CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); + Dictionary originalPositions = new Dictionary(); + Dictionary originalRotations = new Dictionary(); + // this possible is not needed if keyframes are saved +// Dictionary originalKeyframes = new Dictionary(); foreach (SceneObjectGroup objectGroup in objlist) { if (objectGroup.RootPart.KeyframeMotion != null) { - objectGroup.RootPart.KeyframeMotion.Pause(); - group2Keyframe.Add(objectGroup, objectGroup.RootPart.KeyframeMotion); - objectGroup.RootPart.KeyframeMotion = null; + objectGroup.RootPart.KeyframeMotion.Suspend(); } + objectGroup.RootPart.SetForce(Vector3.Zero); + objectGroup.RootPart.SetAngularImpulse(Vector3.Zero, false); -// Vector3 inventoryStoredPosition = new Vector3 -// (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize) -// ? 250 -// : objectGroup.AbsolutePosition.X) -// , -// (objectGroup.AbsolutePosition.Y > (int)Constants.RegionSize) -// ? 250 -// : objectGroup.AbsolutePosition.Y, -// objectGroup.AbsolutePosition.Z); -// -// originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; -// -// objectGroup.AbsolutePosition = inventoryStoredPosition; +// originalKeyframes[objectGroup.UUID] = objectGroup.RootPart.KeyframeMotion; +// objectGroup.RootPart.KeyframeMotion = null; + + Vector3 inventoryStoredPosition = objectGroup.AbsolutePosition; + originalPositions[objectGroup.UUID] = inventoryStoredPosition; + Quaternion inventoryStoredRotation = objectGroup.GroupRotation; + originalRotations[objectGroup.UUID] = inventoryStoredRotation; + + // Restore attachment data after trip through the sim + if (objectGroup.AttachmentPoint > 0) + { + inventoryStoredPosition = objectGroup.RootPart.AttachedPos; + inventoryStoredRotation = objectGroup.RootPart.AttachRotation; + if (objectGroup.RootPart.Shape.PCode != (byte) PCode.Tree && + objectGroup.RootPart.Shape.PCode != (byte) PCode.NewTree) + objectGroup.RootPart.Shape.LastAttachPoint = (byte)objectGroup.AttachmentPoint; + + } + + objectGroup.AbsolutePosition = inventoryStoredPosition; + objectGroup.RootPart.RotationOffset = inventoryStoredRotation; // Make sure all bits but the ones we want are clear // on take. @@ -418,7 +459,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess (uint)PermissionMask.Export); objectGroup.RootPart.NextOwnerMask |= (uint)PermissionMask.Move; - + coa.Add(objectGroup); } @@ -432,10 +473,16 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess itemXml = CoalescedSceneObjectsSerializer.ToXml(coa, !asAttachment); else itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment); - -// // Restore the position of each group now that it has been stored to inventory. -// foreach (SceneObjectGroup objectGroup in objlist) -// objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; + + // Restore the position of each group now that it has been stored to inventory. + foreach (SceneObjectGroup objectGroup in objlist) + { + objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; + objectGroup.RootPart.RotationOffset = originalRotations[objectGroup.UUID]; +// objectGroup.RootPart.KeyframeMotion = originalKeyframes[objectGroup.UUID]; + if (objectGroup.RootPart.KeyframeMotion != null) + objectGroup.RootPart.KeyframeMotion.Resume(); + } InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); @@ -448,11 +495,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess item.CreatorId = objlist[0].RootPart.CreatorID.ToString(); item.CreatorData = objlist[0].RootPart.CreatorData; - + if (objlist.Count > 1) { item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems; - + // If the objects have different creators then don't specify a creator at all foreach (SceneObjectGroup objectGroup in objlist) { @@ -468,8 +515,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess else { item.SaleType = objlist[0].RootPart.ObjectSaleType; - item.SalePrice = objlist[0].RootPart.SalePrice; - } + item.SalePrice = objlist[0].RootPart.SalePrice; + } AssetBase asset = CreateAsset( objlist[0].GetPartName(objlist[0].RootPart.LocalId), @@ -478,7 +525,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess Utils.StringToBytes(itemXml), objlist[0].OwnerID.ToString()); m_Scene.AssetService.Store(asset); - + item.AssetID = asset.FullID; if (DeRezAction.SaveToExistingUserInventoryItem == action) @@ -487,13 +534,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } else { + AddPermissions(item, objlist[0], objlist, remoteClient); + item.CreationDate = Util.UnixTimeSinceEpoch(); item.Description = asset.Description; item.Name = asset.Name; item.AssetType = asset.Type; - AddPermissions(item, objlist[0], objlist, remoteClient); - m_Scene.AddInventoryItem(item); if (remoteClient != null && item.Owner == remoteClient.AgentId) @@ -510,17 +557,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } } - // Restore KeyframeMotion - foreach (SceneObjectGroup objectGroup in group2Keyframe.Keys) - { - objectGroup.RootPart.KeyframeMotion = group2Keyframe[objectGroup]; - objectGroup.RootPart.KeyframeMotion.Start(); - } - // This is a hook to do some per-asset post-processing for subclasses that need that - if (remoteClient != null) + if (remoteClient != null && action != DeRezAction.Delete) ExportAsset(remoteClient.AgentId, asset.FullID); - + return item; } @@ -538,56 +578,41 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess /// /// protected InventoryItemBase AddPermissions( - InventoryItemBase item, SceneObjectGroup so, List objsForEffectivePermissions, + InventoryItemBase item, SceneObjectGroup so, List objsForEffectivePermissions, IClientAPI remoteClient) { - uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move | PermissionMask.Export) | 7; - uint allObjectsNextOwnerPerms = 0x7fffffff; - uint allObjectsEveryOnePerms = 0x7fffffff; - uint allObjectsGroupPerms = 0x7fffffff; - + uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move | PermissionMask.Export | PermissionMask.FoldedMask); + foreach (SceneObjectGroup grp in objsForEffectivePermissions) { - effectivePerms &= grp.GetEffectivePermissions(); - allObjectsNextOwnerPerms &= grp.RootPart.NextOwnerMask; - allObjectsEveryOnePerms &= grp.RootPart.EveryoneMask; - allObjectsGroupPerms &= grp.RootPart.GroupMask; + effectivePerms &= grp.CurrentAndFoldedNextPermissions(); } - effectivePerms |= (uint)PermissionMask.Move; - - //PermissionsUtil.LogPermissions(item.Name, "Before AddPermissions", item.BasePermissions, item.CurrentPermissions, item.NextPermissions); - + if (remoteClient != null && (remoteClient.AgentId != so.RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions()) { - // Changing ownership, so apply the "Next Owner" permissions to all of the - // inventory item's permissions. - - uint perms = effectivePerms; - PermissionsUtil.ApplyFoldedPermissions(effectivePerms, ref perms); - - item.BasePermissions = perms & allObjectsNextOwnerPerms; - item.CurrentPermissions = item.BasePermissions; - item.NextPermissions = perms & allObjectsNextOwnerPerms; - item.EveryOnePermissions = allObjectsEveryOnePerms & allObjectsNextOwnerPerms; - item.GroupPermissions = allObjectsGroupPerms & allObjectsNextOwnerPerms; - + // apply parts inventory items next owner + PermissionsUtil.ApplyNoModFoldedPermissions(effectivePerms, ref effectivePerms); + // change to next owner + uint basePerms = effectivePerms & so.RootPart.NextOwnerMask; + // fix and update folded + basePerms = PermissionsUtil.FixAndFoldPermissions(basePerms); + + item.BasePermissions = basePerms; + item.CurrentPermissions = basePerms; + item.NextPermissions = basePerms & so.RootPart.NextOwnerMask; + item.EveryOnePermissions = basePerms & so.RootPart.EveryoneMask; + item.GroupPermissions = basePerms & so.RootPart.GroupMask; + // apply next owner perms on rez - item.CurrentPermissions |= SceneObjectGroup.SLAM; + item.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm; } else { - // Not changing ownership. - // In this case we apply the permissions in the object's items ONLY to the inventory - // item's "Next Owner" permissions, but NOT to its "Current", "Base", etc. permissions. - // E.g., if the object contains a No-Transfer item then the item's "Next Owner" - // permissions are also No-Transfer. - PermissionsUtil.ApplyFoldedPermissions(effectivePerms, ref allObjectsNextOwnerPerms); - item.BasePermissions = effectivePerms; item.CurrentPermissions = effectivePerms; - item.NextPermissions = allObjectsNextOwnerPerms & effectivePerms; - item.EveryOnePermissions = allObjectsEveryOnePerms & effectivePerms; - item.GroupPermissions = allObjectsGroupPerms & effectivePerms; + item.NextPermissions = so.RootPart.NextOwnerMask & effectivePerms; + item.EveryOnePermissions = so.RootPart.EveryoneMask & effectivePerms; + item.GroupPermissions = so.RootPart.GroupMask & effectivePerms; item.CurrentPermissions &= ((uint)PermissionMask.Copy | @@ -595,14 +620,12 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess (uint)PermissionMask.Modify | (uint)PermissionMask.Move | (uint)PermissionMask.Export | - 7); // Preserve folded permissions - } - - //PermissionsUtil.LogPermissions(item.Name, "After AddPermissions", item.BasePermissions, item.CurrentPermissions, item.NextPermissions); - + (uint)PermissionMask.FoldedMask); // Preserve folded permissions ?? + } + return item; } - + /// /// Create an item using details for the given scene object. /// @@ -615,7 +638,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess DeRezAction action, IClientAPI remoteClient, SceneObjectGroup so, UUID folderID) { // m_log.DebugFormat( -// "[BASIC INVENTORY ACCESS MODULE]: Creating item for object {0} {1} for folder {2}, action {3}", +// "[BASIC INVENTORY ACCESS MODULE]: Creating item for object {0} {1} for folder {2}, action {3}", // so.Name, so.UUID, folderID, action); // // Get the user info of the item destination @@ -663,14 +686,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // Delete is treated like return in this case // Deleting your own items makes them go to trash // - + InventoryFolderBase folder = null; InventoryItemBase item = null; if (DeRezAction.SaveToExistingUserInventoryItem == action) { - item = new InventoryItemBase(so.RootPart.FromUserInventoryItemID, userID); - item = m_Scene.InventoryService.GetItem(item); + item = m_Scene.InventoryService.GetItem(userID, so.RootPart.FromUserInventoryItemID); //item = userInfo.RootFolder.FindItem( // objectGroup.RootPart.FromUserInventoryItemID); @@ -680,7 +702,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess m_log.DebugFormat( "[INVENTORY ACCESS MODULE]: Object {0} {1} scheduled for save to inventory has already been deleted.", so.Name, so.UUID); - + return null; } } @@ -742,8 +764,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { if (so.FromFolderID != UUID.Zero && so.RootPart.OwnerID == remoteClient.AgentId) { - InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID); - folder = m_Scene.InventoryService.GetFolder(f); + folder = m_Scene.InventoryService.GetFolder(userID, so.FromFolderID); if(folder.Type == 14 || folder.Type == 16) { @@ -763,49 +784,65 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } } - item = new InventoryItemBase(); + item = new InventoryItemBase(); item.ID = UUID.Random(); item.InvType = (int)InventoryType.Object; item.Folder = folder.ID; item.Owner = userID; - } - + } + return item; } - + // compatibility do not use public virtual SceneObjectGroup RezObject( IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart, UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) { -// m_log.DebugFormat("[INVENTORY ACCESS MODULE]: RezObject for {0}, item {1}", remoteClient.Name, itemID); + return RezObject(remoteClient, itemID, UUID.Zero, RayEnd, RayStart, + RayTargetID, BypassRayCast, RayEndIsIntersection, + RezSelected, RemoveItem, fromTaskID, attachment); + } - InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); - item = m_Scene.InventoryService.GetItem(item); + public virtual SceneObjectGroup RezObject( + IClientAPI remoteClient, UUID itemID, UUID rezGroupID, Vector3 RayEnd, Vector3 RayStart, + UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, + bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) + { +// m_log.DebugFormat("[INVENTORY ACCESS MODULE]: RezObject for {0}, item {1}", remoteClient.Name, itemID); + InventoryItemBase item = m_Scene.InventoryService.GetItem(remoteClient.AgentId, itemID); if (item == null) { - m_log.WarnFormat( - "[INVENTORY ACCESS MODULE]: Could not find item {0} for {1} in RezObject()", - itemID, remoteClient.Name); - return null; } item.Owner = remoteClient.AgentId; return RezObject( - remoteClient, item, item.AssetID, + remoteClient, item, rezGroupID, item.AssetID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection, RezSelected, RemoveItem, fromTaskID, attachment); } - + // compatility public virtual SceneObjectGroup RezObject( IClientAPI remoteClient, InventoryItemBase item, UUID assetID, Vector3 RayEnd, Vector3 RayStart, UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) { - AssetBase rezAsset = m_Scene.AssetService.Get(assetID.ToString()); + return RezObject(remoteClient, item, UUID.Zero, assetID, + RayEnd, RayStart, RayTargetID, + BypassRayCast, RayEndIsIntersection, + RezSelected, RemoveItem, fromTaskID, attachment); + } + + public virtual SceneObjectGroup RezObject( + IClientAPI remoteClient, InventoryItemBase item, UUID groupID, UUID assetID, + Vector3 RayEnd, Vector3 RayStart, UUID RayTargetID, + byte BypassRayCast, bool RayEndIsIntersection, + bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) + { + AssetBase rezAsset = m_Scene.AssetService.Get(assetID.ToString()); if (rezAsset == null) { @@ -827,6 +864,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess return null; } + if(rezAsset.Data == null || rezAsset.Data.Length == 0) + { + m_log.WarnFormat( + "[INVENTORY ACCESS MODULE]: missing data in asset {0} to RezObject()", + assetID, remoteClient.Name); + remoteClient.SendAgentAlertMessage(string.Format("Unable to rez: missing data in asset {0} ", assetID), false); + return null; + } + SceneObjectGroup group = null; List objlist; @@ -836,7 +882,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0); Vector3 pos; - bool single + bool single = m_Scene.GetObjectsToRez( rezAsset.Data, attachment, out objlist, out veclist, out bbox, out offsetHeight); @@ -856,12 +902,35 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess pos -= bbox / 2; } + int primcount = 0; + foreach (SceneObjectGroup g in objlist) + primcount += g.PrimCount; + + if (!m_Scene.Permissions.CanRezObject( + primcount, remoteClient.AgentId, pos) + && !attachment) + { + // The client operates in no fail mode. It will + // have already removed the item from the folder + // if it's no copy. + // Put it back if it's not an attachment + // + if (item != null) + { + if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!attachment)) + remoteClient.SendBulkUpdateInventory(item); + } + + return null; + } + if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, veclist, attachment)) return null; for (int i = 0; i < objlist.Count; i++) { group = objlist[i]; + SceneObjectPart rootPart = group.RootPart; // m_log.DebugFormat( // "[INVENTORY ACCESS MODULE]: Preparing to rez {0} {1} {2} ownermask={3:X} nextownermask={4:X} groupmask={5:X} everyonemask={6:X} for {7}", @@ -891,9 +960,12 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // Make the rezzer the owner, as this is not necessarily set correctly in the serialized asset. part.LastOwnerID = part.OwnerID; part.OwnerID = remoteClient.AgentId; + part.RezzerID = remoteClient.AgentId; } } + group.ResetIDs(); + if (!attachment) { // If it's rezzed in world, select it. Much easier to @@ -903,48 +975,38 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { part.CreateSelected = true; } - } - group.ResetIDs(); - - if (attachment) + if (rootPart.Shape.PCode == (byte)PCode.Prim) + group.ClearPartAttachmentData(); + } + else { - group.RootPart.Flags |= PrimFlags.Phantom; group.IsAttachment = true; } + group.SetGroup(groupID, remoteClient); + // If we're rezzing an attachment then don't ask // AddNewSceneObject() to update the client since // we'll be doing that later on. Scheduling more than // one full update during the attachment // process causes some clients to fail to display the // attachment properly. - m_Scene.AddNewSceneObject(group, !attachment, false); - // if attachment we set it's asset id so object updates - // can reflect that, if not, we set it's position in world. if (!attachment) { - group.ScheduleGroupForFullUpdate(); - group.AbsolutePosition = pos + veclist[i]; - } - - group.SetGroup(remoteClient.ActiveGroupId, remoteClient); - - if (!attachment) - { - SceneObjectPart rootPart = group.RootPart; - - if (rootPart.Shape.PCode == (byte)PCode.Prim) - group.ClearPartAttachmentData(); + m_Scene.AddNewSceneObject(group, true, false); // Fire on_rez group.CreateScriptInstances(0, true, m_Scene.DefaultScriptEngine, 1); rootPart.ParentGroup.ResumeScripts(); - rootPart.ScheduleFullUpdate(); + group.ScheduleGroupForFullUpdate(); } + else + m_Scene.AddNewSceneObject(group, true, false); + // m_log.DebugFormat( // "[INVENTORY ACCESS MODULE]: Rezzed {0} {1} {2} ownermask={3:X} nextownermask={4:X} groupmask={5:X} everyonemask={6:X} for {7}", @@ -953,6 +1015,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // remoteClient.Name); } +// group.SetGroup(remoteClient.ActiveGroupId, remoteClient); + if (item != null) DoPostRezWhenFromItem(item, attachment); @@ -973,7 +1037,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess /// /// true if we can processed with rezzing, false if we need to abort private bool DoPreRezWhenFromItem( - IClientAPI remoteClient, InventoryItemBase item, List objlist, + IClientAPI remoteClient, InventoryItemBase item, List objlist, Vector3 pos, List veclist, bool isAttachment) { UUID fromUserInventoryItemId = UUID.Zero; @@ -1033,10 +1097,16 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // object itself before we rez. // // Only do these for the first object if we are rezzing a coalescence. - if (i == 0) + // nahh dont mess with coalescence objects, + // the name in inventory can be change for inventory purpuses only + if (objlist.Count == 1) { rootPart.Name = item.Name; rootPart.Description = item.Description; + } + + if ((item.Flags & (uint)InventoryItemFlags.ObjectSlamSale) != 0) + { rootPart.ObjectSaleType = item.SaleType; rootPart.SalePrice = item.SalePrice; } @@ -1047,20 +1117,78 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // "[INVENTORY ACCESS MODULE]: rootPart.OwnedID {0}, item.Owner {1}, item.CurrentPermissions {2:X}", // rootPart.OwnerID, item.Owner, item.CurrentPermissions); - if ((rootPart.OwnerID != item.Owner) || (item.CurrentPermissions & SceneObjectGroup.SLAM) != 0) + if ((rootPart.OwnerID != item.Owner) || + (item.CurrentPermissions & (uint)PermissionMask.Slam) != 0 || + (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0) { //Need to kill the for sale here rootPart.ObjectSaleType = 0; rootPart.SalePrice = 10; - } - foreach (SceneObjectPart part in so.Parts) + if (m_Scene.Permissions.PropagatePermissions()) + { + foreach (SceneObjectPart part in so.Parts) + { + part.GroupMask = 0; // DO NOT propagate here + if( part.OwnerID != part.GroupID) + part.LastOwnerID = part.OwnerID; + part.OwnerID = item.Owner; + part.RezzerID = item.Owner; + part.Inventory.ChangeInventoryOwner(item.Owner); + + // Reconstruct the original item's base permissions. They + // can be found in the lower (folded) bits. + if ((item.BasePermissions & (uint)PermissionMask.FoldedMask) != 0) + { + // We have permissions stored there so use them + part.NextOwnerMask = ((item.BasePermissions & (uint)PermissionMask.FoldedMask) << (int)PermissionMask.FoldingShift); + part.NextOwnerMask |= (uint)PermissionMask.Move; + } + else + { + // This is a legacy object and we can't avoid the issues that + // caused perms loss or escalation before, treat it the legacy + // way. + part.NextOwnerMask = item.NextPermissions; + } + } + + so.ApplyNextOwnerPermissions(); + + // In case the user has changed flags on a received item + // we have to apply those changes after the slam. Else we + // get a net loss of permissions. + // On legacy objects, this opts for a loss of permissions rather + // than the previous handling that allowed escalation. + foreach (SceneObjectPart part in so.Parts) + { + if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0) + { + part.GroupMask = item.GroupPermissions & part.BaseMask; + part.EveryoneMask = item.EveryOnePermissions & part.BaseMask; + part.NextOwnerMask = item.NextPermissions & part.BaseMask; + } + } + + } + } + else { - part.FromUserInventoryItemID = fromUserInventoryItemId; - part.ApplyPermissionsOnRez(item, true, m_Scene); + foreach (SceneObjectPart part in so.Parts) + { + part.FromUserInventoryItemID = fromUserInventoryItemId; + + if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0) + part.EveryoneMask = item.EveryOnePermissions; + if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0) + part.NextOwnerMask = item.NextPermissions; + if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0) + part.GroupMask = item.GroupPermissions; + } } rootPart.TrimPermissions(); + so.InvalidateDeepEffectivePerms(); if (isAttachment) so.FromItemID = item.ID; @@ -1184,9 +1312,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess protected virtual InventoryItemBase GetItem(UUID agentID, UUID itemID) { IInventoryService invService = m_Scene.RequestModuleInterface(); - InventoryItemBase item = new InventoryItemBase(itemID, agentID); - item = invService.GetItem(item); - + InventoryItemBase item = invService.GetItem(agentID, itemID); + if (item != null && item.CreatorData != null && item.CreatorData != string.Empty) UserManagementModule.AddUser(item.CreatorIdAsUuid, item.CreatorData); diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs index 007ff63..01c5d3b 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs @@ -77,7 +77,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests scene.StartScripts(); HGAssetMapper hgam = new HGAssetMapper(scene, homeUrl); - UserAccount ua + UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, userFirstName, userLastName, userId, "password"); SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, soPartsCount, ua.PrincipalID, "part", soIdTail); @@ -93,6 +93,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests Assert.AreEqual(foreignUrl, ncAssetGet.CreatorID); string xmlData = Utils.BytesToString(ncAssetGet.Data); XmlDocument ncAssetGetXmlDoc = new XmlDocument(); + ncAssetGetXmlDoc.XmlResolver=null; ncAssetGetXmlDoc.LoadXml(xmlData); // Console.WriteLine(ncAssetGetXmlDoc.OuterXml); @@ -116,7 +117,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests XmlNode uuidAttribute = savedScriptStateNodes[0].Attributes.GetNamedItem("UUID"); Assert.NotNull(uuidAttribute); // XXX: To check the actual UUID attribute we would have to do some work to retreive the UUID of the task - // item created earlier. + // item created earlier. } private void RezScript(Scene scene, UUID soId, string script, string itemName, UUID userId) @@ -131,9 +132,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests // immediately for tests rather than chunter through it's threaded mechanisms. AutoResetEvent chatEvent = new AutoResetEvent(false); - scene.EventManager.OnChatFromWorld += (s, c) => + scene.EventManager.OnChatFromWorld += (s, c) => { -// Console.WriteLine("Got chat [{0}]", c.Message); +// Console.WriteLine("Got chat [{0}]", c.Message); chatEvent.Set(); }; diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index 1d91165..de29ae9 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -48,12 +48,12 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests { [TestFixture] public class InventoryAccessModuleTests : OpenSimTestCase - { + { protected TestScene m_scene; protected BasicInventoryAccessModule m_iam; protected UUID m_userId = UUID.Parse("00000000-0000-0000-0000-000000000020"); protected TestClient m_tc; - + [SetUp] public override void SetUp() { @@ -68,31 +68,32 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests SceneHelpers sceneHelpers = new SceneHelpers(); m_scene = sceneHelpers.SetupScene(); SceneHelpers.SetupSceneModules(m_scene, config, m_iam); - + // Create user string userFirstName = "Jock"; string userLastName = "Stirrup"; string userPassword = "troll"; - UserAccountHelpers.CreateUserWithInventory(m_scene, userFirstName, userLastName, m_userId, userPassword); - + UserAccountHelpers.CreateUserWithInventory(m_scene, userFirstName, userLastName, m_userId, userPassword); + AgentCircuitData acd = new AgentCircuitData(); acd.AgentID = m_userId; m_tc = new TestClient(acd, m_scene); } - + [Test] public void TestRezCoalescedObject() { +/* TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - + // Create asset SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, m_userId, "Object1", 0x20); object1.AbsolutePosition = new Vector3(15, 30, 45); - + SceneObjectGroup object2 = SceneHelpers.CreateSceneObject(1, m_userId, "Object2", 0x40); - object2.AbsolutePosition = new Vector3(25, 50, 75); - + object2.AbsolutePosition = new Vector3(25, 50, 75); + CoalescedSceneObjects coa = new CoalescedSceneObjects(m_userId, object1, object2); UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); @@ -106,45 +107,46 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests item1.Name = item1Name; item1.AssetID = asset1.FullID; item1.ID = item1Id; - InventoryFolderBase objsFolder + InventoryFolderBase objsFolder = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, m_userId, "Objects")[0]; item1.Folder = objsFolder.ID; item1.Flags |= (uint)InventoryItemFlags.ObjectHasMultipleItems; m_scene.AddInventoryItem(item1); - - SceneObjectGroup so + + SceneObjectGroup so = m_iam.RezObject( - m_tc, item1Id, new Vector3(100, 100, 100), Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); - + m_tc, item1Id, new Vector3(100, 100, 100), Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); + Assert.That(so, Is.Not.Null); - + Assert.That(m_scene.SceneGraph.GetTotalObjectsCount(), Is.EqualTo(2)); - + SceneObjectPart retrievedObj1Part = m_scene.GetSceneObjectPart(object1.Name); Assert.That(retrievedObj1Part, Is.Null); - + retrievedObj1Part = m_scene.GetSceneObjectPart(item1.Name); Assert.That(retrievedObj1Part, Is.Not.Null); Assert.That(retrievedObj1Part.Name, Is.EqualTo(item1.Name)); - + // Bottom of coalescence is placed on ground, hence we end up with 100.5 rather than 85 since the bottom // object is unit square. Assert.That(retrievedObj1Part.AbsolutePosition, Is.EqualTo(new Vector3(95, 90, 100.5f))); - + SceneObjectPart retrievedObj2Part = m_scene.GetSceneObjectPart(object2.Name); - Assert.That(retrievedObj2Part, Is.Not.Null); + Assert.That(retrievedObj2Part, Is.Not.Null); Assert.That(retrievedObj2Part.Name, Is.EqualTo(object2.Name)); Assert.That(retrievedObj2Part.AbsolutePosition, Is.EqualTo(new Vector3(105, 110, 130.5f))); - } - +*/ + } + [Test] public void TestRezObject() { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - + // Create asset - SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, m_userId, "My Little Dog Object", 0x40); + SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, m_userId, "My Little Dog Object", 0x40); UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); @@ -157,17 +159,17 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests item1.Name = item1Name; item1.AssetID = asset1.FullID; item1.ID = item1Id; - InventoryFolderBase objsFolder + InventoryFolderBase objsFolder = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, m_userId, "Objects")[0]; item1.Folder = objsFolder.ID; m_scene.AddInventoryItem(item1); - - SceneObjectGroup so + + SceneObjectGroup so = m_iam.RezObject( - m_tc, item1Id, Vector3.Zero, Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); - + m_tc, item1Id, UUID.Zero, Vector3.Zero, Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); + Assert.That(so, Is.Not.Null); - + SceneObjectPart retrievedPart = m_scene.GetSceneObjectPart(so.UUID); Assert.That(retrievedPart, Is.Not.Null); } diff --git a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs index 862f0b7..5d77201 100644 --- a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs @@ -126,7 +126,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library return; // This will never run more than once, even if the region is restarted - if (!m_HasRunOnce) + if (!m_HasRunOnce) { LoadLibrariesFromArchives(); //DumpLibrary(); @@ -178,7 +178,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library InventoryArchiveReadRequest archread = new InventoryArchiveReadRequest(m_MockScene.InventoryService, m_MockScene.AssetService, m_MockScene.UserAccountService, uinfo, simpleName, iarFileName, false); try { - HashSet nodes = archread.Execute(); + Dictionary nodes = archread.Execute(); if (nodes != null && nodes.Count == 0) { // didn't find the subfolder with the given name; place it on the top @@ -188,7 +188,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library archread.Execute(); } - foreach (InventoryNodeBase node in nodes) + foreach (InventoryNodeBase node in nodes.Values) FixPerms(node); } catch (Exception e) diff --git a/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs b/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs index e1e1838..c1a9457 100644 --- a/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs +++ b/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs @@ -103,13 +103,8 @@ namespace OpenSim.Region.CoreModules.Framework.Library { InventoryItemBase[] itemColl = new InventoryItemBase[itemIDs.Length]; int i = 0; - InventoryItemBase item = new InventoryItemBase(); - item.Owner = principalID; foreach (UUID fid in itemIDs) - { - item.ID = fid; - itemColl[i++] = GetItem(item); - } + itemColl[i++] = GetItem(principalID, fid); return itemColl; } @@ -239,14 +234,14 @@ namespace OpenSim.Region.CoreModules.Framework.Library /// /// /// - public InventoryItemBase GetItem(InventoryItemBase item) { return null; } + public InventoryItemBase GetItem(UUID principalID, UUID itemID) { return null; } /// /// Get a folder, given by its UUID /// /// /// - public InventoryFolderBase GetFolder(InventoryFolderBase folder) { return null; } + public InventoryFolderBase GetFolder(UUID principalID, UUID folderID) { return null; } /// /// Does the given user have an inventory structure? @@ -264,11 +259,11 @@ namespace OpenSim.Region.CoreModules.Framework.Library /// /// Get the union of permissions of all inventory items - /// that hold the given assetID. + /// that hold the given assetID. /// /// /// - /// The permissions or 0 if no such asset is found in + /// The permissions or 0 if no such asset is found in /// the user's inventory public int GetAssetPermissions(UUID userID, UUID assetID) { return 0; } } diff --git a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs index 64feec1..fb3d31c 100644 --- a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs @@ -44,7 +44,7 @@ using Mono.Addins; namespace OpenSim.Region.CoreModules.Framework.Monitoring { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MonitorModule")] - public class MonitorModule : INonSharedRegionModule + public class MonitorModule : INonSharedRegionModule { /// /// Is this module enabled? @@ -78,7 +78,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring if (cnfg != null) Enabled = cnfg.GetBoolean("Enabled", true); - + if (!Enabled) return; @@ -205,7 +205,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m_scene, "ScriptEventsPerSecondMonitor", "Script Events", - m => m.Scene.StatsReporter.LastReportedSimStats[20], + m => m.Scene.StatsReporter.LastReportedSimStats[23], m => string.Format("{0} per second", m.GetValue()))); m_staticMonitors.Add( @@ -301,7 +301,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m_scene, "SpareFrameTimeMonitor", "Spare Frame Time", - m => m.Scene.StatsReporter.LastReportedSimStats[21], + m => m.Scene.StatsReporter.LastReportedSimStats[38], m => string.Format("{0} ms", m.GetValue()))); m_alerts.Add(new DeadlockAlert(m_staticMonitors.Find(x => x is LastFrameTimeMonitor) as LastFrameTimeMonitor)); @@ -433,7 +433,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring MakeStat("ScriptLines", "lines/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[20]; }); MakeStat("SimSpareMS", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[21]; }); } - + private void UnRegisterStatsManagerRegionStatistics() { foreach (Stat stat in registeredStats) @@ -443,6 +443,6 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring } registeredStats.Clear(); } - + } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs b/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs index 3849996..c04d856 100644 --- a/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs @@ -135,7 +135,7 @@ namespace OpenSim.Region.CoreModules.Framework.Search #endregion ISharedRegionModule - + #region Event Handlers void EventManager_OnMakeRootAgent(ScenePresence sp) diff --git a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs index 3abacbd..2c74c0e 100644 --- a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs @@ -48,31 +48,16 @@ namespace OpenSim.Region.CoreModules.Framework MethodBase.GetCurrentMethod().DeclaringType); private readonly List m_scenes = new List(); - private System.Timers.Timer m_timer = new System.Timers.Timer(); - - private Queue m_RequestQueue = new Queue(); - private Dictionary> m_Pending = new Dictionary>(); - private int m_Interval; + private JobEngine m_processorJobEngine; #region ISharedRegionModule public void Initialise(IConfigSource config) { - m_Interval = Util.GetConfigVarFromSections(config, "Interval", new string[] { "ServiceThrottle" }, 5000); - - m_timer = new System.Timers.Timer(); - m_timer.AutoReset = false; - m_timer.Enabled = true; - m_timer.Interval = 15000; // 15 secs at first - m_timer.Elapsed += ProcessQueue; - m_timer.Start(); - - //WorkManager.StartThread( - // ProcessQueue, - // "GridServiceRequestThread", - // ThreadPriority.BelowNormal, - // true, - // false); + m_processorJobEngine = new JobEngine( + "ServiceThrottle","ServiceThrottle"); + m_processorJobEngine.RequestProcessTimeoutOnStop = 31000; // many webrequests have 30s expire + m_processorJobEngine.Start(); } public void AddRegion(Scene scene) @@ -82,7 +67,6 @@ namespace OpenSim.Region.CoreModules.Framework m_scenes.Add(scene); scene.RegisterModuleInterface(this); scene.EventManager.OnNewClient += OnNewClient; - scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; } } @@ -105,6 +89,7 @@ namespace OpenSim.Region.CoreModules.Framework public void Close() { + m_processorJobEngine.Stop(); } public string Name @@ -126,38 +111,32 @@ namespace OpenSim.Region.CoreModules.Framework client.OnRegionHandleRequest += OnRegionHandleRequest; } - void OnMakeRootAgent(ScenePresence obj) - { - lock (m_timer) - { - if (!m_timer.Enabled) - { - m_timer.Interval = m_Interval; - m_timer.Enabled = true; - m_timer.Start(); - } - } - } - public void OnRegionHandleRequest(IClientAPI client, UUID regionID) { //m_log.DebugFormat("[SERVICE THROTTLE]: RegionHandleRequest {0}", regionID); - ulong handle = 0; - if (IsLocalRegionHandle(regionID, out handle)) - { - client.SendRegionHandle(regionID, handle); - return; - } - Action action = delegate { - GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, regionID); + if(!client.IsActive) + return; + + if(m_scenes.Count == 0) + return; + + Scene baseScene = m_scenes[0]; + + if(baseScene == null || baseScene.ShuttingDown) + return; + + GridRegion r = baseScene.GridService.GetRegionByUUID(UUID.Zero, regionID); + + if(!client.IsActive) + return; if (r != null && r.RegionHandle != 0) client.SendRegionHandle(regionID, r.RegionHandle); }; - Enqueue("region", regionID.ToString(), action); + m_processorJobEngine.QueueJob("regionHandle", action, regionID.ToString()); } #endregion Events @@ -166,91 +145,10 @@ namespace OpenSim.Region.CoreModules.Framework public void Enqueue(string category, string itemid, Action continuation) { - lock (m_RequestQueue) - { - if (m_Pending.ContainsKey(category)) - { - if (m_Pending[category].Contains(itemid)) - // Don't enqueue, it's already pending - return; - } - else - m_Pending.Add(category, new List()); - - m_Pending[category].Add(itemid); - - m_RequestQueue.Enqueue(delegate - { - lock (m_RequestQueue) - m_Pending[category].Remove(itemid); - - continuation(); - }); - } + m_processorJobEngine.QueueJob(category, continuation, itemid); } #endregion IServiceThrottleModule - - #region Process Continuation Queue - - private void ProcessQueue(object sender, System.Timers.ElapsedEventArgs e) - { - //m_log.DebugFormat("[YYY]: Process queue with {0} continuations", m_RequestQueue.Count); - - while (m_RequestQueue.Count > 0) - { - Action continuation = null; - lock (m_RequestQueue) - continuation = m_RequestQueue.Dequeue(); - - if (continuation != null) - continuation(); - } - - if (AreThereRootAgents()) - { - lock (m_timer) - { - m_timer.Interval = 1000; // 1 sec - m_timer.Enabled = true; - m_timer.Start(); - } - } - else - lock (m_timer) - m_timer.Enabled = false; - - } - - #endregion Process Continuation Queue - - #region Misc - - private bool IsLocalRegionHandle(UUID regionID, out ulong regionHandle) - { - regionHandle = 0; - foreach (Scene s in m_scenes) - if (s.RegionInfo.RegionID == regionID) - { - regionHandle = s.RegionInfo.RegionHandle; - return true; - } - return false; - } - - private bool AreThereRootAgents() - { - foreach (Scene s in m_scenes) - { - foreach (ScenePresence sp in s.GetScenePresences()) - if (!sp.IsChildAgent) - return true; - } - - return false; - } - - #endregion Misc } } diff --git a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs index f3436d1..3e6c8b5 100644 --- a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs @@ -45,14 +45,14 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging public class BinaryLoggingModule : INonSharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + protected bool m_collectStats; protected Scene m_scene = null; - + public string Name { get { return "Binary Statistics Logging Module"; } } public Type ReplaceableInterface { get { return null; } } - public void Initialise(IConfigSource source) + public void Initialise(IConfigSource source) { try { @@ -81,23 +81,23 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging // if it doesn't work, we don't collect anything } } - + public void AddRegion(Scene scene) { m_scene = scene; } - - public void RemoveRegion(Scene scene) + + public void RemoveRegion(Scene scene) { } - - public void RegionLoaded(Scene scene) + + public void RegionLoaded(Scene scene) { if (m_collectStats) m_scene.StatsReporter.OnSendStatsResult += LogSimStats; } - - public void Close() + + public void Close() { } @@ -107,12 +107,12 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging public string Path; public System.IO.BinaryWriter Log; } - + static StatLogger m_statLog = null; static TimeSpan m_statLogPeriod = TimeSpan.FromSeconds(300); static string m_statsDir = String.Empty; static Object m_statLockObject = new Object(); - + private void LogSimStats(SimStats stats) { SimStatsPacket pack = new SimStatsPacket(); diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs index 7b89c2c..3e0a610 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs @@ -52,7 +52,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement #region ISharedRegionModule - public new void Initialise(IConfigSource config) + public override void Initialise(IConfigSource config) { string umanmod = config.Configs["Modules"].GetString("UserManagementModule", null); if (umanmod == Name) @@ -111,7 +111,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } // This is it! Let's ask the other world - if (words[0].Contains(".")) + if (words[0].Contains(".")) { string[] names = words[0].Split(new char[] { '.' }); if (names.Length >= 2) @@ -130,7 +130,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } UserAgentServiceConnector uasConn = new UserAgentServiceConnector(uriStr); - + UUID userID = UUID.Zero; try { @@ -140,7 +140,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement { m_log.Debug("[USER MANAGEMENT MODULE]: GetUUID call failed ", e); } - + if (!userID.Equals(UUID.Zero)) { UserData ud = new UserData(); @@ -163,8 +163,8 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement //{ // foreach (UserData d in m_UserCache.Values) // { - // if (d.LastName.StartsWith("@") && - // (d.FirstName.ToLower().StartsWith(query.ToLower()) || + // if (d.LastName.StartsWith("@") && + // (d.FirstName.ToLower().StartsWith(query.ToLower()) || // d.LastName.ToLower().StartsWith(query.ToLower()))) // users.Add(d); // } @@ -172,4 +172,4 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs index 4e3b7e5..9d91aa3 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs @@ -37,7 +37,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement.Tests { [TestFixture] public class HGUserManagementModuleTests : OpenSimTestCase - { + { /// /// Test that a new HG agent (i.e. one without a user account) has their name cached in the UMM upon creation. /// diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 7ecbd26..2695464 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -66,7 +66,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement #region ISharedRegionModule - public void Initialise(IConfigSource config) + public virtual void Initialise(IConfigSource config) { string umanmod = config.Configs["Modules"].GetString("UserManagementModule", Name); if (umanmod == Name) @@ -88,7 +88,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement m_DisplayChangingHomeURI = userManagementConfig.GetBoolean("DisplayChangingHomeURI", false); } - public bool IsSharedModule + public virtual bool IsSharedModule { get { return true; } } @@ -98,12 +98,12 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement get { return "BasicUserManagementModule"; } } - public Type ReplaceableInterface + public virtual Type ReplaceableInterface { get { return null; } } - public void AddRegion(Scene scene) + public virtual void AddRegion(Scene scene) { if (m_Enabled) { @@ -119,7 +119,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } } - public void RemoveRegion(Scene scene) + public virtual void RemoveRegion(Scene scene) { if (m_Enabled) { @@ -131,17 +131,17 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } } - public void RegionLoaded(Scene s) + public virtual void RegionLoaded(Scene s) { if (m_Enabled && m_ServiceThrottle == null) m_ServiceThrottle = s.RequestModuleInterface(); } - public void PostInitialise() + public virtual void PostInitialise() { } - public void Close() + public virtual void Close() { lock (m_Scenes) { @@ -157,31 +157,34 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement #region Event Handlers - void EventManager_OnPrimsLoaded(Scene s) + protected virtual void EventManager_OnPrimsLoaded(Scene s) { // let's sniff all the user names referenced by objects in the scene m_log.DebugFormat("[USER MANAGEMENT MODULE]: Caching creators' data from {0} ({1} objects)...", s.RegionInfo.RegionName, s.GetEntities().Length); s.ForEachSOG(delegate(SceneObjectGroup sog) { CacheCreators(sog); }); } - void EventManager_OnNewClient(IClientAPI client) + protected virtual void EventManager_OnNewClient(IClientAPI client) { client.OnConnectionClosed += new Action(HandleConnectionClosed); client.OnNameFromUUIDRequest += new UUIDNameRequest(HandleUUIDNameRequest); client.OnAvatarPickerRequest += new AvatarPickerRequest(HandleAvatarPickerRequest); } - void HandleConnectionClosed(IClientAPI client) + protected virtual void HandleConnectionClosed(IClientAPI client) { client.OnNameFromUUIDRequest -= new UUIDNameRequest(HandleUUIDNameRequest); client.OnAvatarPickerRequest -= new AvatarPickerRequest(HandleAvatarPickerRequest); + client.OnConnectionClosed -= new Action(HandleConnectionClosed); } - void HandleUUIDNameRequest(UUID uuid, IClientAPI client) + protected virtual void HandleUUIDNameRequest(UUID uuid, IClientAPI client) { // m_log.DebugFormat( // "[USER MANAGEMENT MODULE]: Handling request for name binding of UUID {0} from {1}", // uuid, remote_client.Name); + if(m_Scenes.Count <= 0) + return; if (m_Scenes[0].LibraryService != null && (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid)) { @@ -204,7 +207,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } // Not found in cache, queue continuation - m_ServiceThrottle.Enqueue("name", uuid.ToString(), delegate + m_ServiceThrottle.Enqueue("uuidname", uuid.ToString(), delegate { //m_log.DebugFormat("[YYY]: Name request {0}", uuid); @@ -214,9 +217,12 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement // So to avoid clients // (particularly Hypergrid clients) permanently binding "Unknown User" to a given UUID, we will // instead drop the request entirely. + if(!client.IsActive) + return; if (GetUser(uuid, out user)) { - client.SendNameReply(uuid, user.FirstName, user.LastName); + if(client.IsActive) + client.SendNameReply(uuid, user.FirstName, user.LastName); } // else // m_log.DebugFormat( @@ -226,7 +232,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } } - public void HandleAvatarPickerRequest(IClientAPI client, UUID avatarID, UUID RequestID, string query) + public virtual void HandleAvatarPickerRequest(IClientAPI client, UUID avatarID, UUID RequestID, string query) { //EventManager.TriggerAvatarPickerRequest(); @@ -286,8 +292,11 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement #region IPeople - public List GetUserData(string query, int page_size, int page_number) + public virtual List GetUserData(string query, int page_size, int page_number) { + if(m_Scenes.Count <= 0) + return new List();; + // search the user accounts service List accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query); @@ -323,7 +332,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement #endregion IPeople - private void CacheCreators(SceneObjectGroup sog) + protected virtual void CacheCreators(SceneObjectGroup sog) { //m_log.DebugFormat("[USER MANAGEMENT MODULE]: processing {0} {1}; {2}", sog.RootPart.Name, sog.RootPart.CreatorData, sog.RootPart.CreatorIdentification); AddUser(sog.RootPart.CreatorID, sog.RootPart.CreatorData); @@ -336,9 +345,108 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } } + /// + /// + /// + /// + /// Caller please provide a properly instantiated array for names, string[2] + /// + protected virtual bool TryGetUserNames(UUID uuid, string[] names) + { + if (names == null) + names = new string[2]; + + if (TryGetUserNamesFromCache(uuid, names)) + return true; + + if (TryGetUserNamesFromServices(uuid, names)) + return true; + + return false; + } + + protected virtual bool TryGetUserNamesFromCache(UUID uuid, string[] names) + { + lock (m_UserCache) + { + if (m_UserCache.ContainsKey(uuid)) + { + names[0] = m_UserCache[uuid].FirstName; + names[1] = m_UserCache[uuid].LastName; + + return true; + } + } + + return false; + } + + /// + /// Try to get the names bound to the given uuid, from the services. + /// + /// True if the name was found, false if not. + /// + /// The array of names if found. If not found, then names[0] = "Unknown" and names[1] = "User" + protected virtual bool TryGetUserNamesFromServices(UUID uuid, string[] names) + { + if(m_Scenes.Count <= 0) + return false; + + UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(UUID.Zero, uuid); + + if (account != null) + { + names[0] = account.FirstName; + names[1] = account.LastName; + + UserData user = new UserData(); + user.FirstName = account.FirstName; + user.LastName = account.LastName; + + lock (m_UserCache) + m_UserCache[uuid] = user; + + return true; + } + else + { + // Let's try the GridUser service + GridUserInfo uInfo = m_Scenes[0].GridUserService.GetGridUserInfo(uuid.ToString()); + if (uInfo != null) + { + string url, first, last, tmp; + UUID u; + if (Util.ParseUniversalUserIdentifier(uInfo.UserID, out u, out url, out first, out last, out tmp)) + { + AddUser(uuid, first, last, url); + + if (m_UserCache.ContainsKey(uuid)) + { + names[0] = m_UserCache[uuid].FirstName; + names[1] = m_UserCache[uuid].LastName; + + return true; + } + } + else + m_log.DebugFormat("[USER MANAGEMENT MODULE]: Unable to parse UUI {0}", uInfo.UserID); + } +// else +// { +// m_log.DebugFormat("[USER MANAGEMENT MODULE]: No grid user found for {0}", uuid); +// } + + names[0] = "Unknown"; + names[1] = "UserUMMTGUN9"; + + return false; + } + } + + #region IUserManagement - public UUID GetUserIdByName(string name) + public virtual UUID GetUserIdByName(string name) { string[] parts = name.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length < 2) @@ -347,8 +455,11 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement return GetUserIdByName(parts[0], parts[1]); } - public UUID GetUserIdByName(string firstName, string lastName) + public virtual UUID GetUserIdByName(string firstName, string lastName) { + if(m_Scenes.Count <= 0) + return UUID.Zero; + // TODO: Optimize for reverse lookup if this gets used by non-console commands. lock (m_UserCache) { @@ -367,14 +478,159 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement return UUID.Zero; } - public string GetUserName(UUID uuid) + public virtual string GetUserName(UUID uuid) { UserData user; GetUser(uuid, out user); return user.FirstName + " " + user.LastName; } - public string GetUserHomeURL(UUID userID) + public virtual Dictionary GetUsersNames(string[] ids) + { + Dictionary ret = new Dictionary(); + if(m_Scenes.Count <= 0) + return ret; + + List missing = new List(); + Dictionary untried = new Dictionary(); + + // look in cache + UserData userdata = new UserData(); + + UUID uuid = UUID.Zero; + foreach(string id in ids) + { + if(UUID.TryParse(id, out uuid)) + { + lock (m_UserCache) + { + if (m_UserCache.TryGetValue(uuid, out userdata) && + userdata.FirstName != "Unknown" && userdata.FirstName != string.Empty) + { + string name = userdata.FirstName + " " + userdata.LastName; + + if(userdata.HasGridUserTried) + ret[uuid] = name; + else + { + untried[uuid] = name; + missing.Add(id); + } + } + else + missing.Add(id); + } + } + } + + if(missing.Count == 0) + return ret; + + // try user account service + List accounts = m_Scenes[0].UserAccountService.GetUserAccounts( + m_Scenes[0].RegionInfo.ScopeID, missing); + + if(accounts.Count != 0) + { + foreach(UserAccount uac in accounts) + { + if(uac != null) + { + string name = uac.FirstName + " " + uac.LastName; + ret[uac.PrincipalID] = name; + missing.Remove(uac.PrincipalID.ToString()); // slowww + untried.Remove(uac.PrincipalID); + + userdata = new UserData(); + userdata.Id = uac.PrincipalID; + userdata.FirstName = uac.FirstName; + userdata.LastName = uac.LastName; + userdata.HomeURL = string.Empty; + userdata.IsUnknownUser = false; + userdata.HasGridUserTried = true; + lock (m_UserCache) + m_UserCache[uac.PrincipalID] = userdata; + } + } + } + + if (missing.Count == 0 || m_Scenes[0].GridUserService == null) + return ret; + + // try grid user service + + GridUserInfo[] pinfos = m_Scenes[0].GridUserService.GetGridUserInfo(missing.ToArray()); + if(pinfos.Length > 0) + { + foreach(GridUserInfo uInfo in pinfos) + { + if (uInfo != null) + { + string url, first, last, tmp; + + if(uInfo.UserID.Length <= 36) + continue; + + if (Util.ParseUniversalUserIdentifier(uInfo.UserID, out uuid, out url, out first, out last, out tmp)) + { + if (url != string.Empty) + { + try + { + userdata = new UserData(); + userdata.FirstName = first.Replace(" ", ".") + "." + last.Replace(" ", "."); + userdata.LastName = "@" + new Uri(url).Authority; + userdata.Id = uuid; + userdata.HomeURL = url; + userdata.IsUnknownUser = false; + userdata.HasGridUserTried = true; + lock (m_UserCache) + m_UserCache[uuid] = userdata; + + string name = userdata.FirstName + " " + userdata.LastName; + ret[uuid] = name; + missing.Remove(uuid.ToString()); + untried.Remove(uuid); + } + catch + { + } + } + } + } + } + } + + // add the untried in cache that still failed + if(untried.Count > 0) + { + foreach(KeyValuePair kvp in untried) + { + ret[kvp.Key] = kvp.Value; + missing.Remove((kvp.Key).ToString()); + } + } + + // add the UMMthings ( not sure we should) + if(missing.Count > 0) + { + foreach(string id in missing) + { + if(UUID.TryParse(id, out uuid) && uuid != UUID.Zero) + { + if (m_Scenes[0].LibraryService != null && + (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid)) + ret[uuid] = "Mr OpenSim"; + else + ret[uuid] = "Unknown UserUMMAU43"; + } + } + } + + return ret; + } + + public virtual string GetUserHomeURL(UUID userID) { UserData user; if(GetUser(userID, out user)) @@ -384,7 +640,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement return string.Empty; } - public string GetUserServerURL(UUID userID, string serverType) + public virtual string GetUserServerURL(UUID userID, string serverType) { UserData userdata; if(!GetUser(userID, out userdata)) @@ -424,14 +680,14 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement return string.Empty; } - public string GetUserUUI(UUID userID) + public virtual string GetUserUUI(UUID userID) { string uui; GetUserUUI(userID, out uui); return uui; } - public bool GetUserUUI(UUID userID, out string uui) + public virtual bool GetUserUUI(UUID userID, out string uui) { UserData ud; bool result = GetUser(userID, out ud); @@ -449,6 +705,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement last = parts[1]; } uui = userID + ";" + homeURL + ";" + first + " " + last; + return result; } } @@ -457,8 +714,14 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } #region Cache Management - public bool GetUser(UUID uuid, out UserData userdata) + public virtual bool GetUser(UUID uuid, out UserData userdata) { + if(m_Scenes.Count <= 0) + { + userdata = new UserData(); + return false; + } + lock (m_UserCache) { if (m_UserCache.TryGetValue(uuid, out userdata)) @@ -471,7 +734,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement else { userdata = new UserData(); - userdata.HasGridUserTried = false; userdata.Id = uuid; userdata.FirstName = "Unknown"; userdata.LastName = "UserUMMAU42"; @@ -544,7 +806,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement return !userdata.IsUnknownUser; } - public void AddUser(UUID uuid, string first, string last) + public virtual void AddUser(UUID uuid, string first, string last, bool isNPC = false) { lock(m_UserCache) { @@ -555,13 +817,13 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement user.FirstName = first; user.LastName = last; user.IsUnknownUser = false; - user.HasGridUserTried = false; + user.HasGridUserTried = isNPC; m_UserCache.Add(uuid, user); } } } - public void AddUser(UUID uuid, string first, string last, string homeURL) + public virtual void AddUser(UUID uuid, string first, string last, string homeURL) { //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL); @@ -611,7 +873,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } } - public void AddUser(UUID id, string creatorData) + public virtual void AddUser(UUID id, string creatorData) { // m_log.InfoFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, creatorData {1}", id, creatorData); @@ -694,24 +956,29 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } #endregion - public bool IsLocalGridUser(UUID uuid) + public virtual bool IsLocalGridUser(UUID uuid) { - UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, uuid); - if (account == null || (account != null && !account.LocalToGrid)) - return false; + lock (m_Scenes) + { + if (m_Scenes.Count == 0) + return true; + UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, uuid); + if (account == null || (account != null && !account.LocalToGrid)) + return false; + } return true; } #endregion IUserManagement - protected void Init() + protected virtual void Init() { AddUser(UUID.Zero, "Unknown", "User"); RegisterConsoleCmds(); } - protected void RegisterConsoleCmds() + protected virtual void RegisterConsoleCmds() { MainConsole.Instance.Commands.AddCommand("Users", true, "show name", @@ -735,7 +1002,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement HandleResetUserCache); } - private void HandleResetUserCache(string module, string[] cmd) + protected virtual void HandleResetUserCache(string module, string[] cmd) { lock(m_UserCache) { @@ -743,7 +1010,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } } - private void HandleShowUser(string module, string[] cmd) + protected virtual void HandleShowUser(string module, string[] cmd) { if (cmd.Length < 3) { @@ -772,7 +1039,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement MainConsole.Instance.Output(cdt.ToString()); } - private void HandleShowUsers(string module, string[] cmd) + protected virtual void HandleShowUsers(string module, string[] cmd) { ConsoleDisplayTable cdt = new ConsoleDisplayTable(); cdt.AddColumn("UUID", 36); diff --git a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs index ea5b34e..8c44ee2 100644 --- a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs +++ b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs @@ -46,7 +46,7 @@ namespace OpenSim.Region.CoreModules.Hypergrid public class HGWorldMapModule : WorldMapModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + // Remember the map area that each client has been exposed to in this region private Dictionary> m_SeenMapBlocks = new Dictionary>(); @@ -106,6 +106,8 @@ namespace OpenSim.Region.CoreModules.Hypergrid if (!m_Enabled) return; + base.RemoveRegion(scene); + scene.EventManager.OnClientClosed -= EventManager_OnClientClosed; } @@ -138,9 +140,9 @@ namespace OpenSim.Region.CoreModules.Hypergrid } } - protected override List GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) + protected override List GetAndSendBlocksInternal(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) { - List mapBlocks = base.GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); + List mapBlocks = base.GetAndSendBlocksInternal(remoteClient, minX, minY, maxX, maxY, flag); lock (m_SeenMapBlocks) { if (!m_SeenMapBlocks.ContainsKey(remoteClient.AgentId)) diff --git a/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs b/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs index 63e3c92..2e3ac8e 100644 --- a/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs @@ -3,7 +3,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Mono.Addins; -// General Information about an assembly is controlled through the following +// 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.CoreModules")] @@ -15,8 +15,8 @@ using Mono.Addins; [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 +// 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)] @@ -26,11 +26,11 @@ using Mono.Addins; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // -[assembly: AssemblyVersion("0.8.3.*")] +[assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)] [assembly: Addin("OpenSim.Region.CoreModules", OpenSim.VersionInfo.VersionNumber)] diff --git a/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs index a686a4d..090cb7d 100644 --- a/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs @@ -135,17 +135,13 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture m_reuseableDynamicTextures.Store( GenerateReusableTextureKey(texture.InputCommands, texture.InputParams), newTextureID); } + updater.newTextureID = newTextureID; } - } - if (updater.UpdateTimer == 0) - { lock (Updaters) { - if (!Updaters.ContainsKey(updater.UpdaterID)) - { + if (Updaters.ContainsKey(updater.UpdaterID)) Updaters.Remove(updater.UpdaterID); - } } } } @@ -172,21 +168,20 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture } public UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, - string extraParams, int updateTimer) + string extraParams) { - return AddDynamicTextureURL(simID, primID, contentType, url, extraParams, updateTimer, false, 255); + return AddDynamicTextureURL(simID, primID, contentType, url, extraParams, false, 255); } public UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, - string extraParams, int updateTimer, bool SetBlending, byte AlphaValue) + string extraParams, bool SetBlending, byte AlphaValue) { - return AddDynamicTextureURL(simID, primID, contentType, url, - extraParams, updateTimer, SetBlending, - (int)(DISP_TEMP|DISP_EXPIRE), AlphaValue, ALL_SIDES); + return AddDynamicTextureURL(simID, primID, contentType, url, extraParams, SetBlending, + (DISP_TEMP|DISP_EXPIRE), AlphaValue, ALL_SIDES); } public UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, - string extraParams, int updateTimer, bool SetBlending, + string extraParams, bool SetBlending, int disp, byte AlphaValue, int face) { if (RenderPlugins.ContainsKey(contentType)) @@ -196,7 +191,6 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture updater.PrimID = primID; updater.ContentType = contentType; updater.Url = url; - updater.UpdateTimer = updateTimer; updater.UpdaterID = UUID.Random(); updater.Params = extraParams; updater.BlendWithOldTexture = SetBlending; @@ -213,26 +207,27 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture } RenderPlugins[contentType].AsyncConvertUrl(updater.UpdaterID, url, extraParams); - return updater.UpdaterID; + return updater.newTextureID; } return UUID.Zero; } public UUID AddDynamicTextureData(UUID simID, UUID primID, string contentType, string data, - string extraParams, int updateTimer) + string extraParams) { - return AddDynamicTextureData(simID, primID, contentType, data, extraParams, updateTimer, false, 255); + return AddDynamicTextureData(simID, primID, contentType, data, extraParams, false, + (DISP_TEMP|DISP_EXPIRE), 255, ALL_SIDES); } public UUID AddDynamicTextureData(UUID simID, UUID primID, string contentType, string data, - string extraParams, int updateTimer, bool SetBlending, byte AlphaValue) + string extraParams, bool SetBlending, byte AlphaValue) { - return AddDynamicTextureData(simID, primID, contentType, data, extraParams, updateTimer, SetBlending, - (int) (DISP_TEMP|DISP_EXPIRE), AlphaValue, ALL_SIDES); + return AddDynamicTextureData(simID, primID, contentType, data, extraParams, SetBlending, + (DISP_TEMP|DISP_EXPIRE), AlphaValue, ALL_SIDES); } public UUID AddDynamicTextureData(UUID simID, UUID primID, string contentType, string data, - string extraParams, int updateTimer, bool SetBlending, int disp, byte AlphaValue, int face) + string extraParams, bool SetBlending, int disp, byte AlphaValue, int face) { if (!RenderPlugins.ContainsKey(contentType)) return UUID.Zero; @@ -258,7 +253,6 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture updater.PrimID = primID; updater.ContentType = contentType; updater.BodyData = data; - updater.UpdateTimer = updateTimer; updater.UpdaterID = UUID.Random(); updater.Params = extraParams; updater.BlendWithOldTexture = SetBlending; @@ -314,7 +308,7 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture updater.UpdatePart(part, (UUID)objReusableTextureUUID); } - return updater.UpdaterID; + return updater.newTextureID; } private string GenerateReusableTextureKey(string data, string extraParams) @@ -404,17 +398,15 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture public byte FrontAlpha = 255; public string Params; public UUID PrimID; - public bool SetNewFrontAlpha = false; public UUID SimUUID; public UUID UpdaterID; - public int UpdateTimer; public int Face; public int Disp; public string Url; + public UUID newTextureID; public DynamicTextureUpdater() { - UpdateTimer = 0; BodyData = null; } @@ -436,16 +428,23 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture // FIXME: Need to return the appropriate ID if only a single face is replaced. oldID = tmptex.DefaultTexture.TextureID; + // not using parts number of faces because that fails on old meshs if (Face == ALL_SIDES) { oldID = tmptex.DefaultTexture.TextureID; tmptex.DefaultTexture.TextureID = textureID; + for(int i = 0; i < tmptex.FaceTextures.Length; i++) + { + if(tmptex.FaceTextures[i] != null) + tmptex.FaceTextures[i].TextureID = textureID; + } } else { try { Primitive.TextureEntryFace texface = tmptex.CreateFace((uint)Face); + oldID = texface.TextureID; texface.TextureID = textureID; tmptex.FaceTextures[Face] = texface; } @@ -455,10 +454,6 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture } } - // I'm pretty sure we always want to force this to true - // I'm pretty sure noone whats to set fullbright true if it wasn't true before. - // tmptex.DefaultTexture.Fullbright = true; - part.UpdateTextureEntry(tmptex.GetBytes()); } @@ -478,26 +473,39 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture if (part == null || data == null || data.Length <= 1) { - string msg = + string msg = String.Format("DynamicTextureModule: Error preparing image using URL {0}", Url); scene.SimChat(Utils.StringToBytes(msg), ChatTypeEnum.Say, 0, part.ParentGroup.RootPart.AbsolutePosition, part.Name, part.UUID, false); - + return UUID.Zero; } byte[] assetData = null; AssetBase oldAsset = null; - + if (BlendWithOldTexture) { - Primitive.TextureEntryFace defaultFace = part.Shape.Textures.DefaultTexture; - if (defaultFace != null) + Primitive.TextureEntryFace curFace; + if(Face == ALL_SIDES) + curFace = part.Shape.Textures.DefaultTexture; + else { - oldAsset = scene.AssetService.Get(defaultFace.TextureID.ToString()); + try + { + curFace = part.Shape.Textures.GetFace((uint)Face); + } + catch + { + curFace = null; + } + } + if (curFace != null) + { + oldAsset = scene.AssetService.Get(curFace.TextureID.ToString()); if (oldAsset != null) - assetData = BlendTextures(data, oldAsset.Data, SetNewFrontAlpha, FrontAlpha); + assetData = BlendTextures(data, oldAsset.Data, FrontAlpha); } } @@ -548,42 +556,49 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture return asset.FullID; } - private byte[] BlendTextures(byte[] frontImage, byte[] backImage, bool setNewAlpha, byte newAlpha) + private byte[] BlendTextures(byte[] frontImage, byte[] backImage, byte newAlpha) { ManagedImage managedImage; Image image; - if (OpenJPEG.DecodeToImage(frontImage, out managedImage, out image)) + if (!OpenJPEG.DecodeToImage(frontImage, out managedImage, out image) || image == null) + return null; + + Bitmap image1 = new Bitmap(image); + image.Dispose(); + + if (!OpenJPEG.DecodeToImage(backImage, out managedImage, out image) || image == null) { - Bitmap image1 = new Bitmap(image); + image1.Dispose(); + return null; + } - if (OpenJPEG.DecodeToImage(backImage, out managedImage, out image)) - { - Bitmap image2 = new Bitmap(image); + Bitmap image2 = new Bitmap(image); + image.Dispose(); - if (setNewAlpha) - SetAlpha(ref image1, newAlpha); + if (newAlpha < 255) + SetAlpha(ref image1, newAlpha); - Bitmap joint = MergeBitMaps(image1, image2); + using(Bitmap joint = MergeBitMaps(image1, image2)) + { + image1.Dispose(); + image2.Dispose(); - byte[] result = new byte[0]; + byte[] result = new byte[0]; - try - { - result = OpenJPEG.EncodeFromImage(joint, true); - } - catch (Exception e) - { - m_log.ErrorFormat( - "[DYNAMICTEXTUREMODULE]: OpenJpeg Encode Failed. Exception {0}{1}", + try + { + result = OpenJPEG.EncodeFromImage(joint, true); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[DYNAMICTEXTUREMODULE]: OpenJpeg Encode Failed. Exception {0}{1}", e.Message, e.StackTrace); - } - - return result; } - } - return null; + return result; + } } public Bitmap MergeBitMaps(Bitmap front, Bitmap back) @@ -592,12 +607,12 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture Graphics jG; joint = new Bitmap(back.Width, back.Height, PixelFormat.Format32bppArgb); - jG = Graphics.FromImage(joint); - - jG.DrawImage(back, 0, 0, back.Width, back.Height); - jG.DrawImage(front, 0, 0, back.Width, back.Height); - - return joint; + using(jG = Graphics.FromImage(joint)) + { + jG.DrawImage(back, 0, 0, back.Width, back.Height); + jG.DrawImage(front, 0, 0, back.Width, back.Height); + return joint; + } } private void SetAlpha(ref Bitmap b, byte alpha) diff --git a/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs b/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs index 4e7ad75..d59cfa9 100644 --- a/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs @@ -113,7 +113,7 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules } catch (Exception e) { - m_log.Error("[EMAIL] DefaultEmailModule not configured: " + e.Message); + m_log.Error("[EMAIL]: DefaultEmailModule not configured: " + e.Message); m_Enabled = false; return; } @@ -142,7 +142,7 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules } } - m_log.Info("[EMAIL] Activated DefaultEmailModule"); + m_log.Info("[EMAIL]: Activated DefaultEmailModule"); } public void RemoveRegion(Scene scene) @@ -224,8 +224,9 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules return null; } - private void resolveNamePositionRegionName(UUID objectID, out string ObjectName, out string ObjectAbsolutePosition, out string ObjectRegionName) + private bool resolveNamePositionRegionName(UUID objectID, out string ObjectName, out string ObjectAbsolutePosition, out string ObjectRegionName) { + ObjectName = ObjectAbsolutePosition = ObjectRegionName = String.Empty; string m_ObjectRegionName; int objectLocX; int objectLocY; @@ -239,15 +240,9 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules ObjectAbsolutePosition = "(" + objectLocX + ", " + objectLocY + ", " + objectLocZ + ")"; ObjectName = part.Name; ObjectRegionName = m_ObjectRegionName; - return; + return true; } - objectLocX = (int)part.AbsolutePosition.X; - objectLocY = (int)part.AbsolutePosition.Y; - objectLocZ = (int)part.AbsolutePosition.Z; - ObjectAbsolutePosition = "(" + objectLocX + ", " + objectLocY + ", " + objectLocZ + ")"; - ObjectName = part.Name; - ObjectRegionName = m_ObjectRegionName; - return; + return false; } /// @@ -273,12 +268,12 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules bool isEMailStrictMatch = EMailreStrict.IsMatch(address); if (!isEMailStrictMatch) { - m_log.Error("[EMAIL] REGEX Problem in EMail Address: "+address); + m_log.Error("[EMAIL]: REGEX Problem in EMail Address: "+address); return; } if ((subject.Length + body.Length) > m_MaxEmailSize) { - m_log.Error("[EMAIL] subject + body larger than limit of " + m_MaxEmailSize + " bytes"); + m_log.Error("[EMAIL]: subject + body larger than limit of " + m_MaxEmailSize + " bytes"); return; } @@ -286,7 +281,8 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules string LastObjectPosition = string.Empty; string LastObjectRegionName = string.Empty; - resolveNamePositionRegionName(objectID, out LastObjectName, out LastObjectPosition, out LastObjectRegionName); + if (!resolveNamePositionRegionName(objectID, out LastObjectName, out LastObjectPosition, out LastObjectRegionName)) + return; if (!address.EndsWith(m_InterObjectHostname)) { @@ -302,7 +298,8 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules //Subject emailMessage.Subject = subject; //TEXT Body - resolveNamePositionRegionName(objectID, out LastObjectName, out LastObjectPosition, out LastObjectRegionName); + if (!resolveNamePositionRegionName(objectID, out LastObjectName, out LastObjectPosition, out LastObjectRegionName)) + return; emailMessage.BodyText = "Object-Name: " + LastObjectName + "\nRegion: " + LastObjectRegionName + "\nLocal-Position: " + LastObjectPosition + "\n\n" + body; @@ -321,11 +318,11 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules emailMessage.Send(smtpServer); //Log - m_log.Info("[EMAIL] EMail sent to: " + address + " from object: " + objectID.ToString() + "@" + m_HostName); + m_log.Info("[EMAIL]: EMail sent to: " + address + " from object: " + objectID.ToString() + "@" + m_HostName); } catch (Exception e) { - m_log.Error("[EMAIL] DefaultEmailModule Exception: " + e.Message); + m_log.Error("[EMAIL]: DefaultEmailModule Exception: " + e.Message); } } else diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs index 9dfeb96..f5b575b 100644 --- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs @@ -28,15 +28,12 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Net; using System.Net.Mail; using System.Net.Security; -using System.Reflection; using System.Text; using System.Threading; using System.Security.Cryptography.X509Certificates; -using log4net; using Nini.Config; using OpenMetaverse; using OpenSim.Framework; @@ -45,6 +42,7 @@ using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using Mono.Addins; +using Amib.Threading; /***************************************************** * @@ -108,6 +106,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest private Dictionary m_pendingRequests; private Scene m_scene; // private Queue rpcQueue = new Queue(); + public static SmartThreadPool ThreadPool = null; public HttpRequestModule() { @@ -191,7 +190,15 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest case (int)HttpRequestConstants.HTTP_BODY_MAXLENGTH: - // TODO implement me + int len; + if(int.TryParse(parms[i + 1], out len)) + { + if(len > HttpRequestClass.HttpBodyMaxLenMAX) + len = HttpRequestClass.HttpBodyMaxLenMAX; + else if(len < 64) //??? + len = 64; + htc.HttpBodyMaxLen = len; + } break; case (int)HttpRequestConstants.HTTP_VERIFY_CERT: @@ -216,20 +223,16 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest if (parms.Length - i < 2) break; - //Have we reached the end of the list of headers? - //End is marked by a string with a single digit. - //We already know we have at least one parameter - //so it is safe to do this check at top of loop. - if (Char.IsDigit(parms[i][0])) - break; - if (htc.HttpCustomHeaders == null) htc.HttpCustomHeaders = new List(); htc.HttpCustomHeaders.Add(parms[i]); htc.HttpCustomHeaders.Add(parms[i+1]); + int nexti = i + 2; + if (nexti >= parms.Length || Char.IsDigit(parms[nexti][0])) + break; - i += 2; + i = nexti; } break; @@ -239,7 +242,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest } } } - + htc.RequestModule = this; htc.LocalID = localID; htc.ItemID = itemID; @@ -276,7 +279,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest } public bool StartHttpRequest(HttpRequestClass req) - { + { if (!CheckAllowed(new Uri(req.Url))) return false; @@ -290,29 +293,18 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest return true; } - public void StopHttpRequestsForScript(UUID id) + public void StopHttpRequest(uint m_localID, UUID m_itemID) { if (m_pendingRequests != null) { - List keysToRemove = null; - lock (HttpListLock) { - foreach (HttpRequestClass req in m_pendingRequests.Values) + HttpRequestClass tmpReq; + if (m_pendingRequests.TryGetValue(m_itemID, out tmpReq)) { - if (req.ItemID == id) - { - req.Stop(); - - if (keysToRemove == null) - keysToRemove = new List(); - - keysToRemove.Add(req.ReqID); - } + tmpReq.Stop(); + m_pendingRequests.Remove(m_itemID); } - - if (keysToRemove != null) - keysToRemove.ForEach(keyToRemove => m_pendingRequests.Remove(keyToRemove)); } } } @@ -330,13 +322,19 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest { lock (HttpListLock) { - foreach (HttpRequestClass req in m_pendingRequests.Values) + foreach (UUID luid in m_pendingRequests.Keys) { - if (req.Finished) - return req; + HttpRequestClass tmpReq; + + if (m_pendingRequests.TryGetValue(luid, out tmpReq)) + { + if (tmpReq.Finished) + { + return tmpReq; + } + } } } - return null; } @@ -363,9 +361,34 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest m_proxyurl = config.Configs["Startup"].GetString("HttpProxy"); m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions"); + HttpRequestClass.HttpBodyMaxLenMAX = config.Configs["Network"].GetInt("HttpBodyMaxLenMAX", 16384); + + m_outboundUrlFilter = new OutboundUrlFilter("Script HTTP request module", config); + int maxThreads = 15; + + IConfig httpConfig = config.Configs["HttpRequestModule"]; + if (httpConfig != null) + { + maxThreads = httpConfig.GetInt("MaxPoolThreads", maxThreads); + } m_pendingRequests = new Dictionary(); + + // First instance sets this up for all sims + if (ThreadPool == null) + { + STPStartInfo startInfo = new STPStartInfo(); + startInfo.IdleTimeout = 2000; + startInfo.MaxWorkerThreads = maxThreads; + startInfo.MinWorkerThreads = 0; + startInfo.ThreadPriority = ThreadPriority.BelowNormal; + startInfo.StartSuspended = true; + startInfo.ThreadPoolName = "ScriptsHttpReq"; + + ThreadPool = new SmartThreadPool(startInfo); + ThreadPool.Start(); + } } public void AddRegion(Scene scene) @@ -392,6 +415,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest public void Close() { + ThreadPool.Shutdown(); } public string Name @@ -409,8 +433,6 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest public class HttpRequestClass : IServiceRequest { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - // Constants for parameters // public const int HTTP_BODY_MAXLENGTH = 2; // public const int HTTP_METHOD = 0; @@ -430,13 +452,17 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest { get { return _finished; } } - // public int HttpBodyMaxLen = 2048; // not implemented + + public static int HttpBodyMaxLenMAX = 16384; // Parameter members and default values + public int HttpBodyMaxLen = 2048; public string HttpMethod = "GET"; public string HttpMIMEType = "text/plain;charset=utf-8"; public int HttpTimeout; public bool HttpVerifyCert = true; + public IWorkItemResult WorkItem = null; + //public bool HttpVerboseThrottle = true; // not implemented public List HttpCustomHeaders = null; public bool HttpPragmaNoCache = true; @@ -484,15 +510,40 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest public void Process() { + _finished = false; + + lock (HttpRequestModule.ThreadPool) + WorkItem = HttpRequestModule.ThreadPool.QueueWorkItem(new WorkItemCallback(StpSendWrapper), null); + } + + private object StpSendWrapper(object o) + { SendRequest(); + return null; } + /* + * TODO: More work on the response codes. Right now + * returning 200 for success or 499 for exception + */ + public void SendRequest() { + HttpWebResponse response = null; + Stream resStream = null; + byte[] buf = new byte[HttpBodyMaxLenMAX + 16]; + string tempString = null; + int count = 0; + try { Request = (HttpWebRequest)WebRequest.Create(Url); - Request.AllowAutoRedirect = false; + Request.AllowAutoRedirect = false; + Request.KeepAlive = false; + + //This works around some buggy HTTP Servers like Lighttpd + Request.ServicePoint.Expect100Continue = false; + Request.Method = HttpMethod; Request.ContentType = HttpMIMEType; @@ -500,7 +551,6 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest { // We could hijack Connection Group Name to identify // a desired security exception. But at the moment we'll use a dummy header instead. -// Request.ConnectionGroupName = "NoVerify"; Request.Headers.Add("NoVerifyCert", "true"); } // else @@ -533,14 +583,11 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest } } - if (ResponseHeaders != null) - { - foreach (KeyValuePair entry in ResponseHeaders) - if (entry.Key.ToLower().Equals("user-agent") && Request is HttpWebRequest) - ((HttpWebRequest)Request).UserAgent = entry.Value; - else - Request.Headers[entry.Key] = entry.Value; - } + foreach (KeyValuePair entry in ResponseHeaders) + if (entry.Key.ToLower().Equals("user-agent")) + Request.UserAgent = entry.Value; + else + Request.Headers[entry.Key] = entry.Value; // Encode outbound data if (!string.IsNullOrEmpty(OutboundBody)) @@ -552,12 +599,11 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest bstream.Write(data, 0, data.Length); } + Request.Timeout = HttpTimeout; try { - IAsyncResult result = (IAsyncResult)Request.BeginGetResponse(ResponseCallback, null); - - ThreadPool.RegisterWaitForSingleObject( - result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), null, HttpTimeout, true); + // execute the request + response = (HttpWebResponse) Request.GetResponse(); } catch (WebException e) { @@ -565,67 +611,74 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest { throw; } + response = (HttpWebResponse)e.Response; + } - HttpWebResponse response = (HttpWebResponse)e.Response; + Status = (int)response.StatusCode; - Status = (int)response.StatusCode; - ResponseBody = response.StatusDescription; - _finished = true; - } - } - catch (Exception e) - { -// m_log.Debug( -// string.Format("[SCRIPTS HTTP REQUESTS]: Exception on request to {0} for {1} ", Url, ItemID), e); + resStream = response.GetResponseStream(); + int totalBodyBytes = 0; + int maxBytes = HttpBodyMaxLen; + if(maxBytes > buf.Length) + maxBytes = buf.Length; - Status = (int)OSHttpStatusCode.ClientErrorJoker; - ResponseBody = e.Message; - _finished = true; - } - } + // we need to read all allowed or UFT8 conversion may fail + do + { + // fill the buffer with data + count = resStream.Read(buf, totalBodyBytes, maxBytes - totalBodyBytes); + totalBodyBytes += count; + if (totalBodyBytes >= maxBytes) + break; - private void ResponseCallback(IAsyncResult ar) - { - HttpWebResponse response = null; + } while (count > 0); // any more data to read? - try - { - try + if(totalBodyBytes > 0) { - response = (HttpWebResponse)Request.EndGetResponse(ar); + tempString = Util.UTF8.GetString(buf, 0, totalBodyBytes); + ResponseBody = tempString.Replace("\r", ""); } - catch (WebException e) + else + ResponseBody = ""; + } + catch (WebException e) + { + if (e.Status == WebExceptionStatus.ProtocolError) { - if (e.Status != WebExceptionStatus.ProtocolError) + HttpWebResponse webRsp = (HttpWebResponse)((WebException)e).Response; + Status = (int)webRsp.StatusCode; + try { - throw; + using (Stream responseStream = webRsp.GetResponseStream()) + { + using (StreamReader reader = new StreamReader(responseStream)) + ResponseBody = reader.ReadToEnd(); + } + } + catch + { + ResponseBody = webRsp.StatusDescription; } - - response = (HttpWebResponse)e.Response; } - - Status = (int)response.StatusCode; - - using (Stream stream = response.GetResponseStream()) + else { - StreamReader reader = new StreamReader(stream, Encoding.UTF8); - ResponseBody = reader.ReadToEnd(); - } + Status = (int)OSHttpStatusCode.ClientErrorJoker; + ResponseBody = e.Message; + } } catch (Exception e) { - Status = (int)OSHttpStatusCode.ClientErrorJoker; - ResponseBody = e.Message; - -// m_log.Debug( -// string.Format("[SCRIPTS HTTP REQUESTS]: Exception on response to {0} for {1} ", Url, ItemID), e); + // Don't crash on anything else } finally { + if (resStream != null) + resStream.Close(); if (response != null) response.Close(); - // We need to resubmit + + // We need to resubmit if ( (Status == (int)HttpStatusCode.MovedPermanently || Status == (int)HttpStatusCode.Found @@ -670,22 +723,24 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest else { _finished = true; + if (ResponseBody == null) + ResponseBody = String.Empty; } } } - private void TimeoutCallback(object state, bool timedOut) - { - if (timedOut) - Request.Abort(); - } - public void Stop() { -// m_log.DebugFormat("[SCRIPTS HTTP REQUESTS]: Stopping request to {0} for {1} ", Url, ItemID); - - if (Request != null) - Request.Abort(); + try + { + if (!WorkItem.Cancel()) + { + WorkItem.Cancel(true); + } + } + catch (Exception) + { + } } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs index d22487e..7e223d7 100644 --- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs @@ -45,7 +45,7 @@ using OpenSim.Tests.Common; namespace OpenSim.Region.CoreModules.Scripting.HttpRequest.Tests { class TestWebRequestCreate : IWebRequestCreate - { + { public TestWebRequest NextRequest { get; set; } public WebRequest Create(Uri uri) @@ -65,13 +65,13 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest.Tests public Func OnEndGetResponse { get; set; } - public TestWebRequest() : base() + public TestWebRequest() : base() { // Console.WriteLine("created"); } -// public TestWebRequest(SerializationInfo serializationInfo, StreamingContext streamingContext) -// : base(serializationInfo, streamingContext) +// public TestWebRequest(SerializationInfo serializationInfo, StreamingContext streamingContext) +// : base(serializationInfo, streamingContext) // { // Console.WriteLine("created"); // } @@ -97,7 +97,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest.Tests public string Response { get; set; } #pragma warning disable 0618 - public TestHttpWebResponse(SerializationInfo serializationInfo, StreamingContext streamingContext) + public TestHttpWebResponse(SerializationInfo serializationInfo, StreamingContext streamingContext) : base(serializationInfo, streamingContext) {} #pragma warning restore 0618 @@ -111,24 +111,24 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest.Tests { WaitHandle m_wh = new ManualResetEvent(true); - object IAsyncResult.AsyncState + object IAsyncResult.AsyncState { get { throw new System.NotImplementedException (); } } - WaitHandle IAsyncResult.AsyncWaitHandle + WaitHandle IAsyncResult.AsyncWaitHandle { get { return m_wh; } } - bool IAsyncResult.CompletedSynchronously + bool IAsyncResult.CompletedSynchronously { get { return false; } } - bool IAsyncResult.IsCompleted + bool IAsyncResult.IsCompleted { get { return true; } } @@ -155,7 +155,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest.Tests TestHelpers.EnableLogging(); if (!Util.IsPlatformMono) - Assert.Ignore("Ignoring test since can only currently run on Mono"); + Assert.Ignore("Ignoring test since can only currently run on Mono"); string rawResponse = "boom"; @@ -163,7 +163,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest.Tests TestWebRequest twr = new TestWebRequest(); //twr.OnEndGetResponse += ar => new TestHttpWebResponse(null, new StreamingContext()); - twr.OnEndGetResponse += ar => + twr.OnEndGetResponse += ar => { SerializationInfo si = new SerializationInfo(typeof(HttpWebResponse), new FormatterConverter()); StreamingContext sc = new StreamingContext(); diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs index 99a3122..11fc513 100644 --- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs @@ -26,10 +26,11 @@ */ using System; -using System.Threading; using System.Collections.Generic; using System.Collections; using System.Reflection; +using System.Net; +using System.Net.Sockets; using log4net; using Mono.Addins; using Nini.Config; @@ -42,40 +43,17 @@ using OpenSim.Region.Framework.Scenes; namespace OpenSim.Region.CoreModules.Scripting.LSLHttp { - /// - /// Data describing an external URL set up by a script. - /// public class UrlData { - /// - /// Scene object part hosting the script - /// public UUID hostID; - - /// - /// The item ID of the script that requested the URL. - /// public UUID itemID; - - /// - /// The script engine that runs the script. - /// public IScriptModule engine; - - /// - /// The generated URL. - /// public string url; - - /// - /// The random UUID component of the generated URL. - /// public UUID urlcode; - - /// - /// The external requests currently being processed or awaiting retrieval for this URL. - /// public Dictionary requests; + public bool isSsl; + public Scene scene; + public bool allowXss; } public class RequestData @@ -89,7 +67,11 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp //public ManualResetEvent ev; public bool requestDone; public int startTime; + public bool responseSent; public string uri; + public bool allowResponseType = false; + public UUID hostID; + public Scene scene; } /// @@ -102,40 +84,33 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); - /// - /// Indexs the URL request metadata (which script requested it, outstanding requests, etc.) by the request ID - /// randomly generated when a request is received for this URL. - /// - /// - /// Manipulation or retrieval from this dictionary must be locked on m_UrlMap to preserve consistency with - /// m_UrlMap - /// - private Dictionary m_RequestMap = new Dictionary(); + protected Dictionary m_RequestMap = + new Dictionary(); - /// - /// Indexs the URL request metadata (which script requested it, outstanding requests, etc.) by the full URL - /// - private Dictionary m_UrlMap = new Dictionary(); + protected Dictionary m_UrlMap = + new Dictionary(); - private uint m_HttpsPort = 0; - private IHttpServer m_HttpServer = null; - private IHttpServer m_HttpsServer = null; + protected bool m_enabled = false; + protected string m_ErrorStr; + protected uint m_HttpsPort = 0; + protected IHttpServer m_HttpServer = null; + protected IHttpServer m_HttpsServer = null; - public string ExternalHostNameForLSL { get; private set; } + public string ExternalHostNameForLSL { get; protected set; } /// /// The default maximum number of urls /// - public const int DefaultTotalUrls = 100; + public const int DefaultTotalUrls = 15000; /// /// Maximum number of external urls that can be set up by this module. /// public int TotalUrls { get; set; } - public Type ReplaceableInterface + public Type ReplaceableInterface { - get { return null; } + get { return typeof(IUrlModule); } } public string Name @@ -146,6 +121,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp public void Initialise(IConfigSource config) { IConfig networkConfig = config.Configs["Network"]; + m_enabled = false; if (networkConfig != null) { @@ -156,9 +132,31 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp if (ssl_enabled) m_HttpsPort = (uint)config.Configs["Network"].GetInt("https_port", (int)m_HttpsPort); } + else + { + m_ErrorStr = "[Network] configuration missing, HTTP listener for LSL disabled"; + m_log.Warn("[URL MODULE]: " + m_ErrorStr); + return; + } - if (ExternalHostNameForLSL == null) - ExternalHostNameForLSL = System.Environment.MachineName; + if (String.IsNullOrWhiteSpace(ExternalHostNameForLSL)) + { + m_ErrorStr = "ExternalHostNameForLSL not defined in configuration, HTTP listener for LSL disabled"; + m_log.Warn("[URL MODULE]: " + m_ErrorStr); + return; + } + + IPAddress ia = null; + ia = Util.GetHostFromDNS(ExternalHostNameForLSL); + if (ia == null) + { + m_ErrorStr = "Could not resolve ExternalHostNameForLSL, HTTP listener for LSL disabled"; + m_log.Warn("[URL MODULE]: " + m_ErrorStr); + return; + } + + m_enabled = true; + m_ErrorStr = String.Empty; IConfig llFunctionsConfig = config.Configs["LL-Functions"]; @@ -174,7 +172,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp public void AddRegion(Scene scene) { - if (m_HttpServer == null) + if (m_enabled && m_HttpServer == null) { // There can only be one // @@ -204,21 +202,39 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp public void RemoveRegion(Scene scene) { + // Drop references to that scene + foreach (KeyValuePair kvp in m_UrlMap) + { + if (kvp.Value.scene == scene) + kvp.Value.scene = null; + } + foreach (KeyValuePair kvp in m_RequestMap) + { + if (kvp.Value.scene == scene) + kvp.Value.scene = null; + } } public void Close() { } - public UUID RequestURL(IScriptModule engine, SceneObjectPart host, UUID itemID) + public UUID RequestURL(IScriptModule engine, SceneObjectPart host, UUID itemID, Hashtable options) { UUID urlcode = UUID.Random(); + if(!m_enabled) + { + engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", m_ErrorStr }); + return urlcode; + } + lock (m_UrlMap) { if (m_UrlMap.Count >= TotalUrls) { - engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" }); + engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", + "Too many URLs already open" }); return urlcode; } string url = "http://" + ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + "/lslhttp/" + urlcode.ToString() + "/"; @@ -229,20 +245,26 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp urlData.engine = engine; urlData.url = url; urlData.urlcode = urlcode; + urlData.isSsl = false; urlData.requests = new Dictionary(); - + urlData.scene = host.ParentGroup.Scene; + urlData.allowXss = false; + + if (options != null && options["allowXss"] != null) + urlData.allowXss = true; + m_UrlMap[url] = urlData; - + string uri = "/lslhttp/" + urlcode.ToString() + "/"; - - PollServiceEventArgs args + + PollServiceEventArgs args = new PollServiceEventArgs(HttpRequestHandler, uri, HasEvents, GetEvents, NoEvents, urlcode, 25000); args.Type = PollServiceEventArgs.EventType.LslHttp; m_HttpServer.AddPollServiceHTTPHandler(uri, args); - m_log.DebugFormat( - "[URL MODULE]: Set up incoming request url {0} for {1} in {2} {3}", - uri, itemID, host.Name, host.LocalId); +// m_log.DebugFormat( +// "[URL MODULE]: Set up incoming request url {0} for {1} in {2} {3}", +// uri, itemID, host.Name, host.LocalId); engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_GRANTED", url }); } @@ -250,10 +272,16 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp return urlcode; } - public UUID RequestSecureURL(IScriptModule engine, SceneObjectPart host, UUID itemID) + public UUID RequestSecureURL(IScriptModule engine, SceneObjectPart host, UUID itemID, Hashtable options) { UUID urlcode = UUID.Random(); + if(!m_enabled) + { + engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", m_ErrorStr }); + return urlcode; + } + if (m_HttpsServer == null) { engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" }); @@ -264,7 +292,8 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp { if (m_UrlMap.Count >= TotalUrls) { - engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" }); + engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", + "Too many URLs already open" }); return urlcode; } string url = "https://" + ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + "/lslhttps/" + urlcode.ToString() + "/"; @@ -275,20 +304,25 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp urlData.engine = engine; urlData.url = url; urlData.urlcode = urlcode; + urlData.isSsl = true; urlData.requests = new Dictionary(); + urlData.allowXss = false; + + if (options != null && options["allowXss"] != null) + urlData.allowXss = true; m_UrlMap[url] = urlData; - + string uri = "/lslhttps/" + urlcode.ToString() + "/"; - - PollServiceEventArgs args + + PollServiceEventArgs args = new PollServiceEventArgs(HttpRequestHandler, uri, HasEvents, GetEvents, NoEvents, urlcode, 25000); args.Type = PollServiceEventArgs.EventType.LslHttp; m_HttpsServer.AddPollServiceHTTPHandler(uri, args); - m_log.DebugFormat( - "[URL MODULE]: Set up incoming secure request url {0} for {1} in {2} {3}", - uri, itemID, host.Name, host.LocalId); +// m_log.DebugFormat( +// "[URL MODULE]: Set up incoming secure request url {0} for {1} in {2} {3}", +// uri, itemID, host.Name, host.LocalId); engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_GRANTED", url }); } @@ -307,18 +341,21 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp return; } - foreach (UUID req in data.requests.Keys) - m_RequestMap.Remove(req); + lock (m_RequestMap) + { + foreach (UUID req in data.requests.Keys) + m_RequestMap.Remove(req); + } - m_log.DebugFormat( - "[URL MODULE]: Releasing url {0} for {1} in {2}", - url, data.itemID, data.hostID); +// m_log.DebugFormat( +// "[URL MODULE]: Releasing url {0} for {1} in {2}", +// url, data.itemID, data.hostID); RemoveUrl(data); m_UrlMap.Remove(url); } } - + public void HttpContentType(UUID request, string type) { lock (m_UrlMap) @@ -334,32 +371,42 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp } } } - + public void HttpResponse(UUID request, int status, string body) { - lock (m_UrlMap) + lock (m_RequestMap) { if (m_RequestMap.ContainsKey(request)) { UrlData urlData = m_RequestMap[request]; - string responseBody = body; - if (urlData.requests[request].responseType.Equals("text/plain")) + if (!urlData.requests[request].responseSent) { - string value; - if (urlData.requests[request].headers.TryGetValue("user-agent", out value)) + string responseBody = body; + + // If we have no OpenID from built-in browser, disable this + if (!urlData.requests[request].allowResponseType) + urlData.requests[request].responseType = "text/plain"; + + if (urlData.requests[request].responseType.Equals("text/plain")) { - if (value != null && value.IndexOf("MSIE") >= 0) + string value; + if (urlData.requests[request].headers.TryGetValue("user-agent", out value)) { - // wrap the html escaped response if the target client is IE - // It ignores "text/plain" if the body is html - responseBody = "" + System.Web.HttpUtility.HtmlEncode(body) + ""; + if (value != null && value.IndexOf("MSIE") >= 0) + { + // wrap the html escaped response if the target client is IE + // It ignores "text/plain" if the body is html + responseBody = "" + System.Web.HttpUtility.HtmlEncode(body) + ""; + } } } + + urlData.requests[request].responseCode = status; + urlData.requests[request].responseBody = responseBody; + //urlData.requests[request].ev.Set(); + urlData.requests[request].requestDone = true; + urlData.requests[request].responseSent = true; } - urlData.requests[request].responseCode = status; - urlData.requests[request].responseBody = responseBody; - //urlData.requests[request].ev.Set(); - urlData.requests[request].requestDone =true; } else { @@ -370,7 +417,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp public string GetHttpHeader(UUID requestId, string header) { - lock (m_UrlMap) + lock (m_RequestMap) { if (m_RequestMap.ContainsKey(requestId)) { @@ -384,7 +431,6 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp m_log.Warn("[HttpRequestHandler] There was no http-in request with id " + requestId); } } - return String.Empty; } @@ -397,7 +443,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp public void ScriptRemoved(UUID itemID) { // m_log.DebugFormat("[URL MODULE]: Removing script {0}", itemID); - + lock (m_UrlMap) { List removeURLs = new List(); @@ -408,8 +454,11 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp { RemoveUrl(url.Value); removeURLs.Add(url.Key); - foreach (UUID req in url.Value.requests.Keys) - m_RequestMap.Remove(req); + lock (m_RequestMap) + { + foreach (UUID req in url.Value.requests.Keys) + m_RequestMap.Remove(req); + } } } @@ -430,9 +479,11 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp { RemoveUrl(url.Value); removeURLs.Add(url.Key); - - foreach (UUID req in url.Value.requests.Keys) - m_RequestMap.Remove(req); + lock (m_RequestMap) + { + foreach (UUID req in url.Value.requests.Keys) + m_RequestMap.Remove(req); + } } } @@ -441,123 +492,131 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp } } - private void RemoveUrl(UrlData data) + + protected void RemoveUrl(UrlData data) { - m_HttpServer.RemoveHTTPHandler("", "/lslhttp/" + data.urlcode.ToString() + "/"); + if (data.isSsl) + m_HttpsServer.RemoveHTTPHandler("", "/lslhttps/"+data.urlcode.ToString()+"/"); + else + m_HttpServer.RemoveHTTPHandler("", "/lslhttp/"+data.urlcode.ToString()+"/"); } - private Hashtable NoEvents(UUID requestID, UUID sessionID) + protected Hashtable NoEvents(UUID requestID, UUID sessionID) { Hashtable response = new Hashtable(); - UrlData urlData; - - lock (m_UrlMap) + UrlData url; + int startTime = 0; + lock (m_RequestMap) { - // We need to return a 404 here in case the request URL was removed at exactly the same time that a - // request was made. In this case, the request thread can outrace llRemoveURL() and still be polling - // for the request ID. if (!m_RequestMap.ContainsKey(requestID)) - { - response["int_response_code"] = 404; - response["str_response_string"] = ""; - response["keepalive"] = false; - response["reusecontext"] = false; - return response; - } + url = m_RequestMap[requestID]; + startTime = url.requests[requestID].startTime; + } - urlData = m_RequestMap[requestID]; + if (System.Environment.TickCount - startTime > 25000) + { + response["int_response_code"] = 500; + response["str_response_string"] = "Script timeout"; + response["content_type"] = "text/plain"; + response["keepalive"] = false; + response["reusecontext"] = false; - if (System.Environment.TickCount - urlData.requests[requestID].startTime > 25000) + //remove from map + lock (url.requests) + { + url.requests.Remove(requestID); + } + lock (m_RequestMap) { - response["int_response_code"] = 500; - response["str_response_string"] = "Script timeout"; - response["content_type"] = "text/plain"; - response["keepalive"] = false; - response["reusecontext"] = false; - - //remove from map - urlData.requests.Remove(requestID); m_RequestMap.Remove(requestID); - - return response; } + + return response; } + return response; } - private bool HasEvents(UUID requestID, UUID sessionID) + protected bool HasEvents(UUID requestID, UUID sessionID) { - lock (m_UrlMap) + UrlData url=null; + + lock (m_RequestMap) { - // We return true here because an external URL request that happened at the same time as an llRemoveURL() - // can still make it through to HttpRequestHandler(). That will return without setting up a request - // when it detects that the URL has been removed. The poller, however, will continue to ask for - // events for that request, so here we will signal that there are events and in GetEvents we will - // return a 404. if (!m_RequestMap.ContainsKey(requestID)) { - return true; + return false; } - - UrlData urlData = m_RequestMap[requestID]; - - if (!urlData.requests.ContainsKey(requestID)) + url = m_RequestMap[requestID]; + } + lock (url.requests) + { + if (!url.requests.ContainsKey(requestID)) { - return true; + return false; } - - // Trigger return of timeout response. - if (System.Environment.TickCount - urlData.requests[requestID].startTime > 25000) + else { - return true; + if (System.Environment.TickCount - url.requests[requestID].startTime > 25000) + { + return true; + } + if (url.requests[requestID].requestDone) + return true; + else + return false; } - - return urlData.requests[requestID].requestDone; } } - - private Hashtable GetEvents(UUID requestID, UUID sessionID) + protected Hashtable GetEvents(UUID requestID, UUID sessionID) { - Hashtable response; + UrlData url = null; + RequestData requestData = null; - lock (m_UrlMap) + lock (m_RequestMap) { - UrlData url = null; - RequestData requestData = null; - if (!m_RequestMap.ContainsKey(requestID)) - return NoEvents(requestID, sessionID); - + return NoEvents(requestID,sessionID); url = m_RequestMap[requestID]; + } + lock (url.requests) + { requestData = url.requests[requestID]; + } - if (!requestData.requestDone) - return NoEvents(requestID, sessionID); - - response = new Hashtable(); + if (!requestData.requestDone) + return NoEvents(requestID,sessionID); - if (System.Environment.TickCount - requestData.startTime > 25000) - { - response["int_response_code"] = 500; - response["str_response_string"] = "Script timeout"; - response["content_type"] = "text/plain"; - response["keepalive"] = false; - response["reusecontext"] = false; - return response; - } + Hashtable response = new Hashtable(); - //put response - response["int_response_code"] = requestData.responseCode; - response["str_response_string"] = requestData.responseBody; - response["content_type"] = requestData.responseType; - // response["content_type"] = "text/plain"; + if (System.Environment.TickCount - requestData.startTime > 25000) + { + response["int_response_code"] = 500; + response["str_response_string"] = "Script timeout"; + response["content_type"] = "text/plain"; response["keepalive"] = false; response["reusecontext"] = false; - - //remove from map + return response; + } + //put response + response["int_response_code"] = requestData.responseCode; + response["str_response_string"] = requestData.responseBody; + response["content_type"] = requestData.responseType; + response["keepalive"] = false; + response["reusecontext"] = false; + + if (url.allowXss) + response["access_control_allow_origin"] = "*"; + + //remove from map + lock (url.requests) + { url.requests.Remove(requestID); + } + lock (m_RequestMap) + { m_RequestMap.Remove(requestID); } @@ -566,44 +625,49 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp public void HttpRequestHandler(UUID requestID, Hashtable request) { - string uri = request["uri"].ToString(); - bool is_ssl = uri.Contains("lslhttps"); - - try + lock (request) { - Hashtable headers = (Hashtable)request["headers"]; + string uri = request["uri"].ToString(); + bool is_ssl = uri.Contains("lslhttps"); -// string uri_full = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri;// "/lslhttp/" + urlcode.ToString() + "/"; + try + { + Hashtable headers = (Hashtable)request["headers"]; - int pos1 = uri.IndexOf("/");// /lslhttp - int pos2 = uri.IndexOf("/", pos1 + 1);// /lslhttp/ - int pos3 = uri.IndexOf("/", pos2 + 1);// /lslhttp// - string uri_tmp = uri.Substring(0, pos3 + 1); - //HTTP server code doesn't provide us with QueryStrings - string pathInfo; - string queryString; - queryString = ""; +// string uri_full = "http://" + ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri;// "/lslhttp/" + urlcode.ToString() + "/"; - pathInfo = uri.Substring(pos3); + int pos1 = uri.IndexOf("/");// /lslhttp + int pos2 = uri.IndexOf("/", pos1 + 1);// /lslhttp/ + int pos3 = uri.IndexOf("/", pos2 + 1); // /lslhttp/urlcode - UrlData urlData = null; + string uri_tmp = uri.Substring(0, pos3 + 1); + //HTTP server code doesn't provide us with QueryStrings + string pathInfo; + string queryString; + queryString = ""; - lock (m_UrlMap) - { - string url; + pathInfo = uri.Substring(pos3); - if (is_ssl) - url = "https://" + ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp; + UrlData url = null; + string urlkey; + if (!is_ssl) + urlkey = "http://" + ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp; + //m_UrlMap[]; else - url = "http://" + ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp; + urlkey = "https://" + ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp; - // Avoid a race - the request URL may have been released via llRequestUrl() whilst this - // request was being processed. - if (!m_UrlMap.TryGetValue(url, out urlData)) + if (m_UrlMap.ContainsKey(urlkey)) + { + url = m_UrlMap[urlkey]; + } + else + { + //m_log.Warn("[HttpRequestHandler]: http-in request failed; no such url: "+urlkey.ToString()); return; + } //for llGetHttpHeader support we need to store original URI here - //to make x-path-info / x-query-string / x-script-url / x-remote-ip headers + //to make x-path-info / x-query-string / x-script-url / x-remote-ip headers //as per http://wiki.secondlife.com/wiki/LlGetHTTPHeader RequestData requestData = new RequestData(); @@ -611,6 +675,8 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp requestData.requestDone = false; requestData.startTime = System.Environment.TickCount; requestData.uri = uri; + requestData.hostID = url.hostID; + requestData.scene = url.scene; if (requestData.headers == null) requestData.headers = new Dictionary(); @@ -619,8 +685,33 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp string key = (string)header.Key; string value = (string)header.Value; requestData.headers.Add(key, value); + if (key == "cookie") + { + string[] parts = value.Split(new char[] {'='}); + if (parts[0] == "agni_sl_session_id" && parts.Length > 1) + { + string cookie = Uri.UnescapeDataString(parts[1]); + string[] crumbs = cookie.Split(new char[] {':'}); + UUID owner; + if (crumbs.Length == 2 && UUID.TryParse(crumbs[0], out owner)) + { + if (crumbs[1].Length == 32) + { + Scene scene = requestData.scene; + if (scene != null) + { + SceneObjectPart host = scene.GetSceneObjectPart(requestData.hostID); + if (host != null) + { + if (host.OwnerID == owner) + requestData.allowResponseType = true; + } + } + } + } + } + } } - foreach (DictionaryEntry de in request) { if (de.Key.ToString() == "querystringkeys") @@ -631,13 +722,21 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp if (request.ContainsKey(key)) { string val = (String)request[key]; - queryString = queryString + key + "=" + val + "&"; + if (key != "") + { + queryString = queryString + key + "=" + val + "&"; + } + else + { + queryString = queryString + val + "&"; + } } } - if (queryString.Length > 1) queryString = queryString.Substring(0, queryString.Length - 1); + } + } //if this machine is behind DNAT/port forwarding, currently this is being @@ -645,27 +744,38 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp requestData.headers["x-remote-ip"] = requestData.headers["remote_addr"]; requestData.headers["x-path-info"] = pathInfo; requestData.headers["x-query-string"] = queryString; - requestData.headers["x-script-url"] = urlData.url; + requestData.headers["x-script-url"] = url.url; - urlData.requests.Add(requestID, requestData); - m_RequestMap.Add(requestID, urlData); - } + //requestData.ev = new ManualResetEvent(false); + lock (url.requests) + { + url.requests.Add(requestID, requestData); + } + lock (m_RequestMap) + { + //add to request map + m_RequestMap.Add(requestID, url); + } - urlData.engine.PostScriptEvent( - urlData.itemID, - "http_request", - new Object[] { requestID.ToString(), request["http-method"].ToString(), request["body"].ToString() }); - } - catch (Exception we) - { - //Hashtable response = new Hashtable(); - m_log.Warn("[HttpRequestHandler]: http-in request failed"); - m_log.Warn(we.Message); - m_log.Warn(we.StackTrace); + url.engine.PostScriptEvent(url.itemID, "http_request", new Object[] { requestID.ToString(), request["http-method"].ToString(), request["body"].ToString() }); + + //send initial response? +// Hashtable response = new Hashtable(); + + return; + + } + catch (Exception we) + { + //Hashtable response = new Hashtable(); + m_log.Warn("[HttpRequestHandler]: http-in request failed"); + m_log.Warn(we.Message); + m_log.Warn(we.StackTrace); + } } } - private void OnScriptReset(uint localID, UUID itemID) + protected void OnScriptReset(uint localID, UUID itemID) { ScriptRemoved(itemID); } diff --git a/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs b/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs index d45962f..673a453 100644 --- a/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs @@ -98,7 +98,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL return false; } - public void GetDrawStringSize(string text, string fontName, int fontSize, + public void GetDrawStringSize(string text, string fontName, int fontSize, out double xSize, out double ySize) { xSize = 0; @@ -124,7 +124,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL { if (m_scene == null) m_scene = scene; - + } public void RemoveRegion(Scene scene) @@ -166,15 +166,15 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.AllowAutoRedirect = false; - - if (!string.IsNullOrEmpty(m_proxyurl)) + + if (!string.IsNullOrEmpty(m_proxyurl)) { - if (!string.IsNullOrEmpty(m_proxyexcepts)) + if (!string.IsNullOrEmpty(m_proxyexcepts)) { string[] elist = m_proxyexcepts.Split(';'); request.Proxy = new WebProxy(m_proxyurl, true, elist); - } - else + } + else { request.Proxy = new WebProxy(m_proxyurl, true); } @@ -253,7 +253,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL { imageJ2000 = OpenJPEG.EncodeFromImage(resize, true); } - } + } catch (Exception) { m_log.Error("[LOADIMAGEURLMODULE]: OpenJpeg Conversion Failed. Empty byte data returned!"); @@ -268,33 +268,37 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL catch (WebException) { } + catch (Exception e) + { + m_log.ErrorFormat("[LOADIMAGEURLMODULE]: unexpected exception {0}", e.Message); + } finally { if (stream != null) stream.Close(); if (response != null) - response.Close(); - - if ( - response.StatusCode == HttpStatusCode.MovedPermanently - || response.StatusCode == HttpStatusCode.Found - || response.StatusCode == HttpStatusCode.SeeOther - || response.StatusCode == HttpStatusCode.TemporaryRedirect) { - string redirectedUrl = response.Headers["Location"]; + if (response.StatusCode == HttpStatusCode.MovedPermanently + || response.StatusCode == HttpStatusCode.Found + || response.StatusCode == HttpStatusCode.SeeOther + || response.StatusCode == HttpStatusCode.TemporaryRedirect) + { + string redirectedUrl = response.Headers["Location"]; - MakeHttpRequest(redirectedUrl, state.RequestID); - } - else - { - m_log.DebugFormat("[LOADIMAGEURLMODULE]: Returning {0} bytes of image data for request {1}", - imageJ2000.Length, state.RequestID); + MakeHttpRequest(redirectedUrl, state.RequestID); + } + else + { + m_log.DebugFormat("[LOADIMAGEURLMODULE]: Returning {0} bytes of image data for request {1}", + imageJ2000.Length, state.RequestID); - m_textureManager.ReturnData( - state.RequestID, - new OpenSim.Region.CoreModules.Scripting.DynamicTexture.DynamicTexture( - request.RequestUri, null, imageJ2000, newSize, false)); + m_textureManager.ReturnData( + state.RequestID, + new OpenSim.Region.CoreModules.Scripting.DynamicTexture.DynamicTexture( + request.RequestUri, null, imageJ2000, newSize, false)); + } + response.Close(); } } } diff --git a/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs b/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs index 6da2222..9c3f08e 100644 --- a/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs @@ -89,7 +89,7 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms public void RegionLoaded(Scene scene) { m_scriptModule = scene.RequestModuleInterface(); - + if (m_scriptModule != null) m_log.Info("[MODULE COMMANDS]: Script engine found, module active"); } @@ -237,7 +237,7 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms } } } - + public Delegate[] GetScriptInvocationList() { List ret = new List(); @@ -271,6 +271,8 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms return "modInvokeR"; else if (sid.ReturnType == typeof(object[])) return "modInvokeL"; + else if (sid.ReturnType == typeof(void)) + return "modInvokeN"; m_log.WarnFormat("[MODULE COMMANDS] failed to find match for {0} with return type {1}",fname,sid.ReturnType.Name); } @@ -359,14 +361,14 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms public object LookupModConstant(string cname) { // m_log.DebugFormat("[MODULE COMMANDS] lookup constant <{0}>",cname); - + lock (m_constants) { object value = null; if (m_constants.TryGetValue(cname,out value)) return value; } - + return null; } diff --git a/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs b/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs index ed255bf..325f7f9 100644 --- a/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs +++ b/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs @@ -77,8 +77,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests so.UUID, m_vrm.GetContentType(), "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;", - "", - 0); + ""); Assert.That(originalTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); } @@ -98,8 +97,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests so.UUID, m_vrm.GetContentType(), dtText, - "", - 0); + ""); UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; @@ -108,8 +106,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests so.UUID, m_vrm.GetContentType(), dtText, - "", - 0); + ""); Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); } @@ -129,8 +126,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests so.UUID, m_vrm.GetContentType(), dtText, - "", - 0); + ""); UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; @@ -139,8 +135,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests so.UUID, m_vrm.GetContentType(), dtText, - "alpha:250", - 0); + "alpha:250"); Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); } @@ -161,8 +156,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests so.UUID, m_vrm.GetContentType(), dtText, - "", - 0); + ""); UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; @@ -171,8 +165,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests so.UUID, m_vrm.GetContentType(), dtText, - "", - 0); + ""); Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); } @@ -191,8 +184,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests so.UUID, m_vrm.GetContentType(), "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;", - "", - 0); + ""); Assert.That(originalTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); } @@ -213,8 +205,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests so.UUID, m_vrm.GetContentType(), dtText, - "", - 0); + ""); UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; @@ -223,8 +214,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests so.UUID, m_vrm.GetContentType(), dtText, - "", - 0); + ""); Assert.That(firstDynamicTextureID, Is.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); } @@ -253,8 +243,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests so.UUID, m_vrm.GetContentType(), dtText, - "1024", - 0); + "1024"); UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; @@ -263,8 +252,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests so.UUID, m_vrm.GetContentType(), dtText, - "1024", - 0); + "1024"); Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); } @@ -284,8 +272,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests so.UUID, m_vrm.GetContentType(), dtText, - "", - 0); + ""); UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; @@ -294,8 +281,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests so.UUID, m_vrm.GetContentType(), dtText, - "alpha:250", - 0); + "alpha:250"); Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); } @@ -316,8 +302,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests so.UUID, m_vrm.GetContentType(), dtText, - "", - 0); + ""); UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; @@ -326,8 +311,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests so.UUID, m_vrm.GetContentType(), dtText, - "", - 0); + ""); Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); } diff --git a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs index 4cecd85..8a26ab7 100644 --- a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs @@ -117,7 +117,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender return true; } - public void GetDrawStringSize(string text, string fontName, int fontSize, + public void GetDrawStringSize(string text, string fontName, int fontSize, out double xSize, out double ySize) { lock (this) @@ -209,32 +209,32 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender int alpha = 255; // 0 is transparent Color bgColor = Color.White; // Default background color char altDataDelim = ';'; - + char[] paramDelimiter = { ',' }; char[] nvpDelimiter = { ':' }; - + extraParams = extraParams.Trim(); extraParams = extraParams.ToLower(); - + string[] nvps = extraParams.Split(paramDelimiter); - + int temp = -1; foreach (string pair in nvps) { string[] nvp = pair.Split(nvpDelimiter); string name = ""; string value = ""; - + if (nvp[0] != null) { name = nvp[0].Trim(); } - + if (nvp.Length == 2) { value = nvp[1].Trim(); } - + switch (name) { case "width": @@ -301,7 +301,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender if (Int32.TryParse(value, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out hex)) { bgColor = Color.FromArgb(hex); - } + } else { bgColor = Color.FromName(value); @@ -321,7 +321,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender } else { - // this function used to accept an int on its own that represented both + // this function used to accept an int on its own that represented both // width and height, this is to maintain backwards compat, could be removed // but would break existing scripts temp = parseIntParam(name); @@ -329,10 +329,10 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender { if (temp > 1024) temp = 1024; - + if (temp < 128) temp = 128; - + width = temp; height = temp; } @@ -355,36 +355,28 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender lock (this) { if (alpha == 256) - bitmap = new Bitmap(width, height, PixelFormat.Format32bppRgb); - else - bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); - - graph = Graphics.FromImage(bitmap); - - // this is really just to save people filling the - // background color in their scripts, only do when fully opaque - if (alpha >= 255) { + bitmap = new Bitmap(width, height, PixelFormat.Format32bppRgb); + graph = Graphics.FromImage(bitmap); using (SolidBrush bgFillBrush = new SolidBrush(bgColor)) { graph.FillRectangle(bgFillBrush, 0, 0, width, height); } - } - - for (int w = 0; w < bitmap.Width; w++) + } + else { - if (alpha <= 255) + bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); + graph = Graphics.FromImage(bitmap); + Color newbg = Color.FromArgb(alpha,bgColor); + using (SolidBrush bgFillBrush = new SolidBrush(newbg)) { - for (int h = 0; h < bitmap.Height; h++) - { - bitmap.SetPixel(w, h, Color.FromArgb(alpha, bitmap.GetPixel(w, h))); - } + graph.FillRectangle(bgFillBrush, 0, 0, width, height); } } - + GDIDraw(data, graph, altDataDelim, out reuseable); } - + byte[] imageJ2000 = new byte[0]; // This code exists for testing purposes, please do not remove. @@ -394,7 +386,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender // imageJ2000 = s_asset2Data; // // s_flipper = !s_flipper; - + try { imageJ2000 = OpenJPEG.EncodeFromImage(bitmap, true); @@ -420,13 +412,13 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender { if (graph != null) graph.Dispose(); - + if (bitmap != null) bitmap.Dispose(); } } } - + private int parseIntParam(string strInt) { int parsed; @@ -440,7 +432,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender // m_log.Debug("Problem with Draw. Please verify parameters." + e.ToString()); parsed = -1; } - + return parsed; } @@ -519,8 +511,32 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender // m_log.DebugFormat("[VECTOR RENDER MODULE]: Processing line '{0}'", nextLine); + if (nextLine.StartsWith("ResetTransf")) + { + graph.ResetTransform(); + } + else if (nextLine.StartsWith("TransTransf")) + { + float x = 0; + float y = 0; + GetParams(partsDelimiter, ref nextLine, 11, ref x, ref y); + graph.TranslateTransform(x, y); + } + else if (nextLine.StartsWith("ScaleTransf")) + { + float x = 0; + float y = 0; + GetParams(partsDelimiter, ref nextLine, 11, ref x, ref y); + graph.ScaleTransform(x, y); + } + else if (nextLine.StartsWith("RotTransf")) + { + float x = 0; + GetParams(partsDelimiter, ref nextLine, 9, ref x); + graph.RotateTransform(x); + } //replace with switch, or even better, do some proper parsing - if (nextLine.StartsWith("MoveTo")) + else if (nextLine.StartsWith("MoveTo")) { float x = 0; float y = 0; @@ -572,7 +588,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender graph.DrawString("not an image. Please check URL.", errorFont, myBrush, new Point(startPoint.X, 12 + startPoint.Y)); } - + graph.DrawRectangle(drawPen, startPoint.X, startPoint.Y, endPoint.X, endPoint.Y); } } @@ -625,6 +641,17 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender startPoint.X += endPoint.X; startPoint.Y += endPoint.Y; } + else if (nextLine.StartsWith("FillEllipse")) + { + float x = 0; + float y = 0; + GetParams(partsDelimiter, ref nextLine, 11, ref x, ref y); + endPoint.X = (int)x; + endPoint.Y = (int)y; + graph.FillEllipse(myBrush, startPoint.X, startPoint.Y, endPoint.X, endPoint.Y); + startPoint.X += endPoint.X; + startPoint.Y += endPoint.Y; + } else if (nextLine.StartsWith("FontSize")) { nextLine = nextLine.Remove(0, 8); @@ -638,11 +665,11 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender { nextLine = nextLine.Remove(0, 8); nextLine = nextLine.Trim(); - + string[] fprops = nextLine.Split(partsDelimiter); foreach (string prop in fprops) { - + switch (prop) { case "B": @@ -717,7 +744,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender else if (cap[0].ToLower() != "both") return; string type = cap[1].ToLower(); - + if (end) { switch (type) @@ -760,7 +787,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender nextLine = nextLine.Remove(0, 9); nextLine = nextLine.Trim(); int hex = 0; - + Color newColor; if (Int32.TryParse(nextLine, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out hex)) { @@ -790,6 +817,17 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender } } + private static void GetParams(char[] partsDelimiter, ref string line, int startLength, ref float x) + { + line = line.Remove(0, startLength); + string[] parts = line.Split(partsDelimiter); + if (parts.Length > 0) + { + string xVal = parts[0].Trim(); + x = Convert.ToSingle(xVal, CultureInfo.InvariantCulture); + } + } + private static void GetParams(char[] partsDelimiter, ref string line, int startLength, ref float x, ref float y) { line = line.Remove(0, startLength); @@ -861,4 +899,4 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender return null; } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs b/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs index 3484387..a5203ea 100644 --- a/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs @@ -96,6 +96,8 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm // private static readonly ILog m_log = // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private const int DEBUG_CHANNEL = 2147483647; + private ListenerManager m_listenerManager; private Queue m_pending; private Queue m_pendingQ; @@ -111,7 +113,7 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm // wrap this in a try block so that defaults will work if // the config file doesn't specify otherwise. int maxlisteners = 1000; - int maxhandles = 64; + int maxhandles = 65; try { m_whisperdistance = config.Configs["Chat"].GetInt( @@ -128,8 +130,15 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm catch (Exception) { } - if (maxlisteners < 1) maxlisteners = int.MaxValue; - if (maxhandles < 1) maxhandles = int.MaxValue; + + if (maxlisteners < 1) + maxlisteners = int.MaxValue; + if (maxhandles < 1) + maxhandles = int.MaxValue; + + if (maxlisteners < maxhandles) + maxlisteners = maxhandles; + m_listenerManager = new ListenerManager(maxlisteners, maxhandles); m_pendingQ = new Queue(); m_pending = Queue.Synchronized(m_pendingQ); @@ -309,6 +318,7 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm // Determine which listen event filters match the given set of arguments, this results // in a limited set of listeners, each belonging a host. If the host is in range, add them // to the pending queue. + foreach (ListenerInfo li in m_listenerManager.GetListeners(UUID.Zero, channel, name, id, msg)) @@ -366,79 +376,82 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm /// /// Message. /// - public void DeliverMessageTo(UUID target, int channel, Vector3 pos, - string name, UUID id, string msg) + public void DeliverMessageTo(UUID target, int channel, Vector3 pos, string name, UUID id, string msg) { - // Is id an avatar? - ScenePresence sp = m_scene.GetScenePresence(target); + if (channel == DEBUG_CHANNEL) + return; + if(target == UUID.Zero) + return; + + // Is target an avatar? + ScenePresence sp = m_scene.GetScenePresence(target); if (sp != null) { - // ignore if a child agent this is restricted to inside one - // region - if (sp.IsChildAgent) + // Send message to avatar + if (channel == 0) + { + // Channel 0 goes to viewer ONLY + m_scene.SimChat(Utils.StringToBytes(msg), ChatTypeEnum.Broadcast, 0, pos, name, id, target, false, false); return; + } - // Channel zero only goes to the avatar - // non zero channel messages only go to the attachments of the avatar. - if (channel != 0) - { - List attachments = sp.GetAttachments(); - if (attachments.Count == 0) - return; + // for now messages to prims don't cross regions + if(sp.IsChildAgent) + return; - // Get uuid of attachments - List targets = new List(); - foreach (SceneObjectGroup sog in attachments) - { - if (!sog.IsDeleted) - targets.Add(sog.UUID); - } + List attachments = sp.GetAttachments(); + + if (attachments.Count == 0) + return; - // Need to check each attachment - foreach (ListenerInfo li - in m_listenerManager.GetListeners(UUID.Zero, - channel, name, id, msg)) + // Get uuid of attachments + List targets = new List(); + foreach (SceneObjectGroup sog in attachments) + { + if (!sog.IsDeleted) { - if (li.GetHostID().Equals(id)) - continue; + SceneObjectPart[] parts = sog.Parts; + foreach(SceneObjectPart p in parts) + targets.Add(p.UUID); + } + } - if (m_scene.GetSceneObjectPart( - li.GetHostID()) == null) - { - continue; - } + foreach (ListenerInfo li in m_listenerManager.GetListeners(UUID.Zero, channel, name, id, msg)) + { + UUID liHostID = li.GetHostID(); + if (liHostID.Equals(id)) + continue; + if (m_scene.GetSceneObjectPart(liHostID) == null) + continue; - if (targets.Contains(li.GetHostID())) - QueueMessage(new ListenerInfo(li, name, id, msg)); - } + if (targets.Contains(liHostID)) + QueueMessage(new ListenerInfo(li, name, id, msg)); } return; } - // No avatar found so look for an object - foreach (ListenerInfo li - in m_listenerManager.GetListeners(UUID.Zero, channel, - name, id, msg)) + SceneObjectPart part = m_scene.GetSceneObjectPart(target); + if (part == null) // Not even an object + return; // No error + + foreach (ListenerInfo li in m_listenerManager.GetListeners(UUID.Zero, channel, name, id, msg)) { + UUID liHostID = li.GetHostID(); // Dont process if this message is from yourself! - if (li.GetHostID().Equals(id)) + if (liHostID.Equals(id)) continue; - SceneObjectPart sPart = m_scene.GetSceneObjectPart( - li.GetHostID()); - if (sPart == null) + if (m_scene.GetSceneObjectPart(liHostID) == null) continue; - if (li.GetHostID().Equals(target)) + if (liHostID.Equals(target)) { QueueMessage(new ListenerInfo(li, name, id, msg)); break; } } - - return; } protected void QueueMessage(ListenerInfo li) @@ -557,9 +570,9 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm return coll[0].GetHandle(); } - if (m_curlisteners < m_maxlisteners) + lock (m_listeners) { - lock (m_listeners) + if (m_curlisteners < m_maxlisteners) { int newHandle = GetNewHandle(itemID); @@ -599,11 +612,9 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm li.GetHandle().Equals(handle)) { lis.Value.Remove(li); + m_curlisteners--; if (lis.Value.Count == 0) - { - m_listeners.Remove(lis.Key); - m_curlisteners--; - } + m_listeners.Remove(lis.Key); // bailing of loop so this does not smoke // there should be only one, so we bail out early return; } @@ -712,6 +723,9 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm } } + if(handles.Count >= m_maxhandles) + return -1; + // Note: 0 is NOT a valid handle for llListen() to return for (int i = 1; i <= m_maxhandles; i++) { diff --git a/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs b/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs index 87f4277..6028eef 100644 --- a/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs @@ -621,7 +621,7 @@ namespace OpenSim.Region.CoreModules.Scripting.XMLRPC private Thread httpThread; public int Idata; private UUID _itemID; - public UUID ItemID + public UUID ItemID { get { return _itemID; } set { _itemID = value; } @@ -633,7 +633,7 @@ namespace OpenSim.Region.CoreModules.Scripting.XMLRPC set { _localID = value; } } private UUID _reqID; - public UUID ReqID + public UUID ReqID { get { return _reqID; } set { _reqID = value; } @@ -658,7 +658,7 @@ namespace OpenSim.Region.CoreModules.Scripting.XMLRPC public void Process() { _finished = false; - httpThread = WorkManager.StartThread(SendRequest, "HttpRequestThread", ThreadPriority.BelowNormal, true, false); + httpThread = WorkManager.StartThread(SendRequest, "XMLRPCreqThread", ThreadPriority.BelowNormal, true, false, null, int.MaxValue); } /* diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Asset/AssetServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Asset/AssetServiceInConnectorModule.cs index 7b4668a..2c882e6 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Asset/AssetServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Asset/AssetServiceInConnectorModule.cs @@ -45,7 +45,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Asset { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static bool m_Enabled = false; - + private IConfigSource m_Config; bool m_Registered = false; @@ -74,7 +74,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Asset { } - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -95,7 +95,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Asset m_log.Info("[HGAssetService]: Starting..."); - + Object[] args = new Object[] { m_Config, MainServer.Instance, "HGAssetService" }; ServerUtils.LoadPlugin("OpenSim.Server.Handlers.dll:AssetServiceConnector", args); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Authentication/AuthenticationServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Authentication/AuthenticationServiceInConnectorModule.cs index 2cdffe6..a8c4e3c 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Authentication/AuthenticationServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Authentication/AuthenticationServiceInConnectorModule.cs @@ -47,7 +47,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Authentication { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static bool m_Enabled = false; - + private IConfigSource m_Config; bool m_Registered = false; @@ -77,7 +77,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Authentication { } - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Grid/GridInfoServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Grid/GridInfoServiceInConnectorModule.cs index 22857d0..834cbb7 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Grid/GridInfoServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Grid/GridInfoServiceInConnectorModule.cs @@ -47,7 +47,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Grid { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static bool m_Enabled = false; - + private IConfigSource m_Config; bool m_Registered = false; @@ -77,7 +77,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Grid { } - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs index f749295..4f87595 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs @@ -48,7 +48,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Hypergrid { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static bool m_Enabled = false; - + private IConfigSource m_Config; private bool m_Registered = false; private string m_LocalServiceDll = String.Empty; @@ -88,7 +88,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Hypergrid { } - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -130,7 +130,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Hypergrid m_HypergridHandler = new GatekeeperServiceInConnector(m_Config, MainServer.Instance, simService); m_UASHandler = new UserAgentServerConnector(m_Config, MainServer.Instance, friendsConn); - + new HeloServiceInConnector(m_Config, MainServer.Instance, "HeloService"); new HGFriendsServerConnector(m_Config, MainServer.Instance, "HGFriendsService", friendsConn); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Inventory/InventoryServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Inventory/InventoryServiceInConnectorModule.cs index 0a4e736..61e37a9 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Inventory/InventoryServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Inventory/InventoryServiceInConnectorModule.cs @@ -45,7 +45,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Inventory { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static bool m_Enabled = false; - + private IConfigSource m_Config; bool m_Registered = false; @@ -73,7 +73,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Inventory { } - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs index 2fd21be..fb8c306 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs @@ -84,7 +84,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Land { } - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -126,15 +126,36 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Land public LandData GetLandData(UUID scopeID, ulong regionHandle, uint x, uint y, out byte regionAccess) { - m_log.DebugFormat("[LAND IN CONNECTOR]: GetLandData for {0}. Count = {1}", - regionHandle, m_Scenes.Count); +// m_log.DebugFormat("[LAND IN CONNECTOR]: GetLandData for {0}. Count = {1}", +// regionHandle, m_Scenes.Count); + + uint rx = 0, ry = 0; + Util.RegionHandleToWorldLoc(regionHandle, out rx, out ry); + rx += x; + ry += y; foreach (Scene s in m_Scenes) { - if (s.RegionInfo.RegionHandle == regionHandle) + uint t = s.RegionInfo.WorldLocX; + if( rx < t) + continue; + t += s.RegionInfo.RegionSizeX; + if( rx >= t) + continue; + t = s.RegionInfo.WorldLocY; + if( ry < t) + continue; + t += s.RegionInfo.RegionSizeY; + if( ry < t) { - m_log.Debug("[LAND IN CONNECTOR]: Found region to GetLandData from"); +// m_log.Debug("[LAND IN CONNECTOR]: Found region to GetLandData from"); + x = rx - s.RegionInfo.WorldLocX; + y = ry - s.RegionInfo.WorldLocY; regionAccess = s.RegionInfo.AccessLevel; - return s.GetLandData(x, y); + LandData land = s.GetLandData(x, y); + IDwellModule dwellModule = s.RequestModuleInterface(); + if (dwellModule != null) + land.Dwell = dwellModule.GetDwell(land); + return land; } } m_log.DebugFormat("[LAND IN CONNECTOR]: region handle {0} not found", regionHandle); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Login/LLLoginServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Login/LLLoginServiceInConnectorModule.cs index 425febd..065dd94 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Login/LLLoginServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Login/LLLoginServiceInConnectorModule.cs @@ -84,7 +84,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Login { } - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -113,7 +113,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Login { if (!m_Enabled) return; - + if (!m_Registered) { m_Registered = true; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/MapImage/MapImageServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/MapImage/MapImageServiceInConnectorModule.cs index c14bce7..a75a156 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/MapImage/MapImageServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/MapImage/MapImageServiceInConnectorModule.cs @@ -47,7 +47,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.MapImage { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static bool m_Enabled = false; - + private IConfigSource m_Config; #region Region Module interface @@ -75,7 +75,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.MapImage { } - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Neighbour/NeighbourServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Neighbour/NeighbourServiceInConnectorModule.cs index 6bf47cb..09c545c 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Neighbour/NeighbourServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Neighbour/NeighbourServiceInConnectorModule.cs @@ -83,7 +83,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Neighbour { } - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Simulation/SimulationServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Simulation/SimulationServiceInConnectorModule.cs index 57d1132..7ba39d4 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Simulation/SimulationServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Simulation/SimulationServiceInConnectorModule.cs @@ -77,7 +77,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Simulation { } - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs index 4701ee6..2e6f472 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs @@ -77,65 +77,65 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Profile { get; private set; } - - public Type ReplaceableInterface + + public Type ReplaceableInterface { get { return null; } } public LocalUserProfilesServicesConnector() { - m_log.Debug("[LOCAL USERPROFILES SERVICE CONNECTOR]: LocalUserProfileServicesConnector no params"); + //m_log.Debug("[LOCAL USERPROFILES SERVICE CONNECTOR]: LocalUserProfileServicesConnector no params"); } - + public LocalUserProfilesServicesConnector(IConfigSource source) { - m_log.Debug("[LOCAL USERPROFILES SERVICE CONNECTOR]: LocalUserProfileServicesConnector instantiated directly."); + //m_log.Debug("[LOCAL USERPROFILES SERVICE CONNECTOR]: LocalUserProfileServicesConnector instantiated directly."); InitialiseService(source); } public void InitialiseService(IConfigSource source) { ConfigName = "UserProfilesService"; - + // Instantiate the request handler IHttpServer Server = MainServer.Instance; IConfig config = source.Configs[ConfigName]; if (config == null) { - m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: UserProfilesService missing from OpenSim.ini"); + //m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: UserProfilesService missing from OpenSim.ini"); return; } - + if(!config.GetBoolean("Enabled",false)) { Enabled = false; return; } - + Enabled = true; - + string serviceDll = config.GetString("LocalServiceModule", String.Empty); - + if (serviceDll == String.Empty) { m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: No LocalServiceModule named in section UserProfilesService"); return; } - + Object[] args = new Object[] { source, ConfigName }; ServiceModule = ServerUtils.LoadPlugin(serviceDll, args); - + if (ServiceModule == null) { m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: Can't load user profiles service"); return; } - + Enabled = true; JsonRpcProfileHandlers handler = new JsonRpcProfileHandlers(ServiceModule); @@ -196,7 +196,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Profile { if (!Enabled) return; - + lock (regions) { if (regions.ContainsKey(scene.RegionInfo.RegionID)) @@ -209,7 +209,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Profile void IRegionModuleBase.RemoveRegion(Scene scene) { if (!Enabled) - return; + return; lock (regions) { @@ -221,8 +221,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Profile void IRegionModuleBase.RegionLoaded(Scene scene) { if (!Enabled) - return; + return; } #endregion } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/LocalAgentPreferencesServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/LocalAgentPreferencesServiceConnector.cs index 41ae53f..5cd68d9 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/LocalAgentPreferencesServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/LocalAgentPreferencesServiceConnector.cs @@ -50,7 +50,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.AgentPreferences #region ISharedRegionModule - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/RemoteAgentPreferencesServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/RemoteAgentPreferencesServiceConnector.cs index ad9544a..d60236a 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/RemoteAgentPreferencesServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/RemoteAgentPreferencesServiceConnector.cs @@ -44,14 +44,14 @@ using Nini.Config; namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.AgentPreferences { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RemoteAgentPreferencesServicesConnector")] - public class RemoteAgentPreferencesServicesConnector : AgentPreferencesServicesConnector, + public class RemoteAgentPreferencesServicesConnector : AgentPreferencesServicesConnector, ISharedRegionModule, IAgentPreferencesService { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private bool m_Enabled = false; - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -61,7 +61,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.AgentPreferences get { return "RemoteAgentPreferencesServicesConnector"; } } - public override void Initialise(IConfigSource source) + public new void Initialise(IConfigSource source) { IConfig moduleConfig = source.Configs["Modules"]; if (moduleConfig != null) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs index 7fcfc74..92ae36f 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs @@ -48,7 +48,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); - private IImprovedAssetCache m_Cache = null; + private IAssetCache m_Cache = null; private IAssetService m_GridService; private IAssetService m_HGService; @@ -59,7 +59,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset private AssetPermissions m_AssetPerms; - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -159,7 +159,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset { if (!m_Enabled) return; - + m_aScene = scene; m_aScene.RegisterModuleInterface(this); @@ -176,10 +176,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset if (m_Cache == null) { - m_Cache = scene.RequestModuleInterface(); + m_Cache = scene.RequestModuleInterface(); if (!(m_Cache is ISharedRegionModule)) m_Cache = null; + } m_log.InfoFormat("[HG ASSET CONNECTOR]: Enabled hypergrid asset broker for region {0}", scene.RegionInfo.RegionName); @@ -205,10 +206,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset { //m_log.DebugFormat("[HG ASSET CONNECTOR]: Get {0}", id); AssetBase asset = null; - + if (m_Cache != null) { - asset = m_Cache.Get(id); + if (!m_Cache.Get(id, out asset)) + return null; if (asset != null) return asset; @@ -237,20 +239,21 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset public AssetBase GetCached(string id) { + AssetBase asset = null; if (m_Cache != null) - return m_Cache.Get(id); + m_Cache.Get(id, out asset); - return null; + return asset; } public AssetMetadata GetMetadata(string id) { AssetBase asset = null; - + if (m_Cache != null) { - if (m_Cache != null) - m_Cache.Get(id); + if (!m_Cache.Get(id, out asset)) + return null; if (asset != null) return asset.Metadata; @@ -269,11 +272,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset public byte[] GetData(string id) { AssetBase asset = null; - + if (m_Cache != null) { - if (m_Cache != null) - m_Cache.Get(id); + if (!m_Cache.Get(id, out asset)) + return null; if (asset != null) return asset.Data; @@ -289,9 +292,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset public bool Get(string id, Object sender, AssetRetrieved handler) { AssetBase asset = null; - + if (m_Cache != null) - asset = m_Cache.Get(id); + { + if (!m_Cache.Get(id, out asset)) + return false; + } if (asset != null) { @@ -338,23 +344,22 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset public string Store(AssetBase asset) { - bool isHG = IsHG(asset.ID); - - if ((m_Cache != null) && !isHG) - // Don't store it in the cache if the asset is to - // be sent to the other grid, because this is already - // a copy of the local asset. - m_Cache.Cache(asset); - - if (asset.Local) + if (asset.Local || asset.Temporary) { if (m_Cache != null) m_Cache.Cache(asset); return asset.ID; } + bool isHG = IsHG(asset.ID); + if ((m_Cache != null) && !isHG) + // Don't store it in the cache if the asset is to + // be sent to the other grid, because this is already + // a copy of the local asset. + m_Cache.Cache(asset); + string id; - if (IsHG(asset.ID)) + if (isHG) { if (m_AssetPerms.AllowedExport(asset.Type)) id = m_HGService.Store(asset); @@ -366,21 +371,23 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset if (String.IsNullOrEmpty(id)) return string.Empty; - - asset.ID = id; - if (m_Cache != null) - m_Cache.Cache(asset); + if(asset.ID != id) + { + asset.ID = id; + if (m_Cache != null) + m_Cache.Cache(asset); + } - return id; + return id; } public bool UpdateContent(string id, byte[] data) { AssetBase asset = null; - + if (m_Cache != null) - asset = m_Cache.Get(id); + m_Cache.Get(id, out asset); if (asset != null) { diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs index 5f34450..37a48bb 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs @@ -44,13 +44,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private IImprovedAssetCache m_Cache = null; + private IAssetCache m_Cache = null; private IAssetService m_AssetService; private bool m_Enabled = false; - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -128,7 +128,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset if (m_Cache == null) { - m_Cache = scene.RequestModuleInterface(); + m_Cache = scene.RequestModuleInterface(); if (!(m_Cache is ISharedRegionModule)) m_Cache = null; @@ -155,10 +155,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset public AssetBase Get(string id) { // m_log.DebugFormat("[LOCAL ASSET SERVICES CONNECTOR]: Synchronously requesting asset {0}", id); - + AssetBase asset = null; if (m_Cache != null) - asset = m_Cache.Get(id); + { + if (!m_Cache.Get(id, out asset)) + return null; + } if (asset == null) { @@ -169,7 +172,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset // if (null == asset) // m_log.WarnFormat("[LOCAL ASSET SERVICES CONNECTOR]: Could not synchronously find asset with id {0}", id); } - + return asset; } @@ -177,23 +180,27 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset { // m_log.DebugFormat("[LOCAL ASSET SERVICES CONNECTOR]: Cache request for {0}", id); + AssetBase asset = null; if (m_Cache != null) - return m_Cache.Get(id); + m_Cache.Get(id, out asset); - return null; + return asset; } public AssetMetadata GetMetadata(string id) { AssetBase asset = null; if (m_Cache != null) - asset = m_Cache.Get(id); + { + if (!m_Cache.Get(id, out asset)) + return null; + } if (asset != null) return asset.Metadata; asset = m_AssetService.Get(id); - if (asset != null) + if (asset != null) { if (m_Cache != null) m_Cache.Cache(asset); @@ -210,7 +217,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset AssetBase asset = null; if (m_Cache != null) - asset = m_Cache.Get(id); + { + if (!m_Cache.Get(id, out asset)) + return null; + } if (asset != null) return asset.Data; @@ -229,10 +239,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset public bool Get(string id, Object sender, AssetRetrieved handler) { // m_log.DebugFormat("[LOCAL ASSET SERVICES CONNECTOR]: Asynchronously requesting asset {0}", id); - + if (m_Cache != null) { - AssetBase asset = m_Cache.Get(id); + AssetBase asset; + if (!m_Cache.Get(id, out asset)) + return false; if (asset != null) { @@ -264,7 +276,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset { if (m_Cache != null) m_Cache.Cache(asset); - + if (asset.Local) { // m_log.DebugFormat( @@ -278,7 +290,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset // m_log.DebugFormat( // "[LOCAL ASSET SERVICE CONNECTOR]: Passing {0} {1} on to asset service for storage, status Temporary = {2}, Local = {3}", // asset.Name, asset.ID, asset.Temporary, asset.Local); - + return m_AssetService.Store(asset); } } @@ -287,7 +299,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset { AssetBase asset = null; if (m_Cache != null) - m_Cache.Get(id); + m_Cache.Get(id, out asset); if (asset != null) { asset.Data = data; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/RemoteAssetServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/RemoteAssetServiceConnector.cs index e6eeacf..1225ab5 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/RemoteAssetServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/RemoteAssetServiceConnector.cs @@ -48,9 +48,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset MethodBase.GetCurrentMethod().DeclaringType); private bool m_Enabled = false; - private IImprovedAssetCache m_Cache; + private IAssetCache m_Cache; - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -111,7 +111,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset if (m_Cache == null) { - m_Cache = scene.RequestModuleInterface(); + m_Cache = scene.RequestModuleInterface(); // Since we are a shared module and scene data is not // available for every method, the cache must be shared, too diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authentication/LocalAuthenticationServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authentication/LocalAuthenticationServiceConnector.cs index 16f42a7..8017245 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authentication/LocalAuthenticationServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authentication/LocalAuthenticationServiceConnector.cs @@ -53,7 +53,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authentication #region ISharedRegionModule - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -139,10 +139,17 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authentication #region IAuthenticationService + public string Authenticate(UUID principalID, string password, int lifetime, out UUID realID) + { + // Not implemented at the regions + realID = UUID.Zero; + return string.Empty; + } + public string Authenticate(UUID principalID, string password, int lifetime) { // Not implemented at the regions - return string.Empty; + return string.Empty; } public bool Verify(UUID principalID, string token, int lifetime) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authentication/RemoteAuthenticationServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authentication/RemoteAuthenticationServiceConnector.cs index 7cb8b22..fd1d802 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authentication/RemoteAuthenticationServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authentication/RemoteAuthenticationServiceConnector.cs @@ -47,7 +47,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authentication private bool m_Enabled = false; - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/LocalAuthorizationServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/LocalAuthorizationServiceConnector.cs index 1acb695..0be0676 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/LocalAuthorizationServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/LocalAuthorizationServiceConnector.cs @@ -53,7 +53,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization private bool m_Enabled = false; - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -66,7 +66,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization public void Initialise(IConfigSource source) { m_log.Info("[AUTHORIZATION CONNECTOR]: Initialise"); - + IConfig moduleConfig = source.Configs["Modules"]; if (moduleConfig != null) { diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/RemoteAuthorizationServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/RemoteAuthorizationServiceConnector.cs index b8d409d..f312b0d 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/RemoteAuthorizationServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/RemoteAuthorizationServiceConnector.cs @@ -51,7 +51,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization private bool m_Enabled = false; private List m_scenes = new List(); - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -103,7 +103,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization m_scenes.Add(scene); scene.RegisterModuleInterface(this); } - + } public void RemoveRegion(Scene scene) @@ -118,16 +118,16 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization m_log.InfoFormat("[REMOTE AUTHORIZATION CONNECTOR]: Enabled remote authorization for region {0}", scene.RegionInfo.RegionName); } - + public bool IsAuthorizedForRegion( string userID, string firstName, string lastName, string regionID, out string message) { m_log.InfoFormat( "[REMOTE AUTHORIZATION CONNECTOR]: IsAuthorizedForRegion checking {0} for region {1}", userID, regionID); - + bool isAuthorized = true; message = String.Empty; - + // get the scene this call is being made for Scene scene = null; lock (m_scenes) @@ -140,11 +140,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization } } } - + if (scene != null) { string mail = String.Empty; - + UserAccount account = scene.UserAccountService.GetUserAccount(UUID.Zero, new UUID(userID)); //if account not found, we assume its a foreign visitor from HG, else use account data... @@ -165,7 +165,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization "[REMOTE AUTHORIZATION CONNECTOR] IsAuthorizedForRegion, can't find scene to match region id of {0}", regionID); } - + return isAuthorized; } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Avatar/LocalAvatarServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Avatar/LocalAvatarServiceConnector.cs index c3ef588..42f6c3f 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Avatar/LocalAvatarServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Avatar/LocalAvatarServiceConnector.cs @@ -54,7 +54,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Avatar #region ISharedRegionModule - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -144,12 +144,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Avatar { return m_AvatarService.GetAppearance(userID); } - + public bool SetAppearance(UUID userID, AvatarAppearance appearance) { return m_AvatarService.SetAppearance(userID,appearance); } - + public AvatarData GetAvatar(UUID userID) { return m_AvatarService.GetAvatar(userID); @@ -174,7 +174,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Avatar { return m_AvatarService.RemoveItems(userID, names); } - + #endregion } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Avatar/RemoteAvatarServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Avatar/RemoteAvatarServiceConnector.cs index a087aea..37cfbbc 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Avatar/RemoteAvatarServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Avatar/RemoteAvatarServiceConnector.cs @@ -47,7 +47,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Avatar private bool m_Enabled = false; - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs index 1f782f5..d220568 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs @@ -51,7 +51,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid private static string LogHeader = "[LOCAL GRID SERVICE CONNECTOR]"; private IGridService m_GridService; - private Dictionary m_LocalCache = new Dictionary(); + private RegionInfoCache m_RegionInfoCache; + private HashSet m_scenes = new HashSet(); private bool m_Enabled; @@ -63,12 +64,18 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid public LocalGridServicesConnector(IConfigSource source) { m_log.DebugFormat("{0} LocalGridServicesConnector instantiated directly.", LogHeader); - InitialiseService(source); + InitialiseService(source, null); + } + + public LocalGridServicesConnector(IConfigSource source, RegionInfoCache regionInfoCache) + { + m_log.DebugFormat("{0} LocalGridServicesConnector instantiated directly with cache.", LogHeader); + InitialiseService(source, regionInfoCache); } #region ISharedRegionModule - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -86,19 +93,24 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid string name = moduleConfig.GetString("GridServices", ""); if (name == Name) { - InitialiseService(source); - m_log.Info("[LOCAL GRID SERVICE CONNECTOR]: Local grid connector enabled"); + if(InitialiseService(source, null)) + m_log.Info("[LOCAL GRID SERVICE CONNECTOR]: Local grid connector enabled"); } } } - private void InitialiseService(IConfigSource source) + private bool InitialiseService(IConfigSource source, RegionInfoCache ric) { + if(ric == null && m_RegionInfoCache == null) + m_RegionInfoCache = new RegionInfoCache(); + else + m_RegionInfoCache = ric; + IConfig config = source.Configs["GridService"]; if (config == null) { m_log.Error("[LOCAL GRID SERVICE CONNECTOR]: GridService missing from OpenSim.ini"); - return; + return false; } string serviceDll = config.GetString("LocalServiceModule", String.Empty); @@ -106,7 +118,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid if (serviceDll == String.Empty) { m_log.Error("[LOCAL GRID SERVICE CONNECTOR]: No LocalServiceModule named in section GridService"); - return; + return false; } Object[] args = new Object[] { source }; @@ -117,19 +129,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid if (m_GridService == null) { m_log.Error("[LOCAL GRID SERVICE CONNECTOR]: Can't load grid service"); - return; + return false; } m_Enabled = true; + return true; } public void PostInitialise() { - // FIXME: We will still add this command even if we aren't enabled since RemoteGridServiceConnector - // will have instantiated us directly. - MainConsole.Instance.Commands.AddCommand("Regions", false, "show neighbours", - "show neighbours", - "Shows the local regions' neighbours", HandleShowNeighboursCommand); } public void Close() @@ -141,15 +149,17 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid if (!m_Enabled) return; - scene.RegisterModuleInterface(this); - - lock (m_LocalCache) + lock(m_scenes) { - if (m_LocalCache.ContainsKey(scene.RegionInfo.RegionID)) - m_log.ErrorFormat("[LOCAL GRID SERVICE CONNECTOR]: simulator seems to have more than one region with the same UUID. Please correct this!"); - else - m_LocalCache.Add(scene.RegionInfo.RegionID, new RegionCache(scene)); + if(!m_scenes.Contains(scene)) + m_scenes.Add(scene); } + scene.RegisterModuleInterface(this); + + GridRegion r = new GridRegion(scene.RegionInfo); + m_RegionInfoCache.CacheLocal(r); + + scene.EventManager.OnRegionUp += OnRegionUp; } public void RemoveRegion(Scene scene) @@ -157,11 +167,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid if (!m_Enabled) return; - lock (m_LocalCache) + lock(m_scenes) { - m_LocalCache[scene.RegionInfo.RegionID].Clear(); - m_LocalCache.Remove(scene.RegionInfo.RegionID); + if(m_scenes.Contains(scene)) + m_scenes.Remove(scene); } + + m_RegionInfoCache.Remove(scene.RegionInfo.ScopeID, scene.RegionInfo.RegionHandle); + scene.EventManager.OnRegionUp -= OnRegionUp; } public void RegionLoaded(Scene scene) @@ -172,6 +185,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid #region IGridService + private void OnRegionUp(GridRegion region) + { + // This shouldn't happen + if (region == null) + return; + + m_RegionInfoCache.CacheNearNeighbour(region.ScopeID, region); + } + public string RegisterRegion(UUID scopeID, GridRegion regionInfo) { return m_GridService.RegisterRegion(scopeID, regionInfo); @@ -184,12 +206,20 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid public List GetNeighbours(UUID scopeID, UUID regionID) { - return m_GridService.GetNeighbours(scopeID, regionID); + return m_GridService.GetNeighbours(scopeID, regionID); } public GridRegion GetRegionByUUID(UUID scopeID, UUID regionID) { - return m_GridService.GetRegionByUUID(scopeID, regionID); + bool inCache = false; + GridRegion rinfo = m_RegionInfoCache.Get(scopeID,regionID,out inCache); + if (inCache) + return rinfo; + + rinfo = m_GridService.GetRegionByUUID(scopeID, regionID); + if(rinfo != null) + m_RegionInfoCache.Cache(scopeID, rinfo); + return rinfo; } // Get a region given its base coordinates. @@ -197,59 +227,30 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid // be the base coordinate of the region. public GridRegion GetRegionByPosition(UUID scopeID, int x, int y) { - GridRegion region = null; - uint regionX = Util.WorldToRegionLoc((uint)x); - uint regionY = Util.WorldToRegionLoc((uint)y); - // Sanity check - if ((Util.RegionToWorldLoc(regionX) != (uint)x) || (Util.RegionToWorldLoc(regionY) != (uint)y)) - { - m_log.WarnFormat("{0} GetRegionByPosition. Bad position requested: not the base of the region. Requested Pos=<{1},{2}>, Should Be=<{3},{4}>", - LogHeader, x, y, Util.RegionToWorldLoc(regionX), Util.RegionToWorldLoc(regionY)); - } - - // First see if it's a neighbour, even if it isn't on this sim. - // Neighbour data is cached in memory, so this is fast - - lock (m_LocalCache) - { - foreach (RegionCache rcache in m_LocalCache.Values) - { - region = rcache.GetRegionByPosition(x, y); - if (region != null) - { - m_log.DebugFormat("{0} GetRegionByPosition. Found region {1} in cache (of region {2}). Pos=<{3},{4}>", - LogHeader, region.RegionName, rcache.RegionName, - Util.WorldToRegionLoc((uint)region.RegionLocX), Util.WorldToRegionLoc((uint)region.RegionLocY)); - break; - } - } - } + bool inCache = false; + GridRegion rinfo = m_RegionInfoCache.Get(scopeID, (uint)x, (uint)y, out inCache); + if (inCache) + return rinfo; // Then try on this sim (may be a lookup in DB if this is using MySql). - if (region == null) - { - region = m_GridService.GetRegionByPosition(scopeID, x, y); - - if (region == null) - { - m_log.DebugFormat("{0} GetRegionByPosition. Region not found by grid service. Pos=<{1},{2}>", - LogHeader, regionX, regionY); - } - else - { - m_log.DebugFormat("{0} GetRegionByPosition. Got region {1} from grid service. Pos=<{2},{3}>", - LogHeader, region.RegionName, - Util.WorldToRegionLoc((uint)region.RegionLocX), Util.WorldToRegionLoc((uint)region.RegionLocY)); - } - } - - return region; + rinfo = m_GridService.GetRegionByPosition(scopeID, x, y); + if(rinfo != null) + m_RegionInfoCache.Cache(scopeID, rinfo); + return rinfo; } public GridRegion GetRegionByName(UUID scopeID, string regionName) { - return m_GridService.GetRegionByName(scopeID, regionName); + bool inCache = false; + GridRegion rinfo = m_RegionInfoCache.Get(scopeID, regionName, out inCache); + if (inCache) + return rinfo; + + rinfo = m_GridService.GetRegionByName(scopeID, regionName); + if(rinfo != null) + m_RegionInfoCache.Cache(scopeID, rinfo); + return rinfo; } public List GetRegionsByName(UUID scopeID, string name, int maxNumber) @@ -281,7 +282,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid { return m_GridService.GetHyperlinks(scopeID); } - + public int GetRegionFlags(UUID scopeID, UUID regionID) { return m_GridService.GetRegionFlags(scopeID, regionID); @@ -294,22 +295,5 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid #endregion - public void HandleShowNeighboursCommand(string module, string[] cmdparams) - { - System.Text.StringBuilder caps = new System.Text.StringBuilder(); - - lock (m_LocalCache) - { - foreach (KeyValuePair kvp in m_LocalCache) - { - caps.AppendFormat("*** Neighbours of {0} ({1}) ***\n", kvp.Value.RegionName, kvp.Key); - List regions = kvp.Value.GetNeighbours(); - foreach (GridRegion r in regions) - caps.AppendFormat(" {0} @ {1}-{2}\n", r.RegionName, Util.WorldToRegionLoc((uint)r.RegionLocX), Util.WorldToRegionLoc((uint)r.RegionLocY)); - } - } - - MainConsole.Instance.Output(caps.ToString()); - } } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs deleted file mode 100644 index ae76288..0000000 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs +++ /dev/null @@ -1,102 +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; -using OpenSim.Region.Framework.Scenes; -using OpenSim.Services.Interfaces; -using GridRegion = OpenSim.Services.Interfaces.GridRegion; - -using OpenMetaverse; -using log4net; - -namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid -{ - public class RegionCache - { - private static readonly ILog m_log = - LogManager.GetLogger( - MethodBase.GetCurrentMethod().DeclaringType); - - private Scene m_scene; - private Dictionary m_neighbours = new Dictionary(); - - public string RegionName - { - get { return m_scene.RegionInfo.RegionName; } - } - - public RegionCache(Scene s) - { - m_scene = s; - m_scene.EventManager.OnRegionUp += OnRegionUp; - } - - private void OnRegionUp(GridRegion otherRegion) - { - // This shouldn't happen - if (otherRegion == null) - return; - - m_log.DebugFormat("[REGION CACHE]: (on region {0}) Region {1} is up @ {2}-{3}", - m_scene.RegionInfo.RegionName, otherRegion.RegionName, Util.WorldToRegionLoc((uint)otherRegion.RegionLocX), Util.WorldToRegionLoc((uint)otherRegion.RegionLocY)); - - m_neighbours[otherRegion.RegionHandle] = otherRegion; - } - - public void Clear() - { - m_scene.EventManager.OnRegionUp -= OnRegionUp; - m_neighbours.Clear(); - } - - public List GetNeighbours() - { - return new List(m_neighbours.Values); - } - - // Get a region given its base coordinates (in meters). - // 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(int x, int y) - { - uint xsnap = (uint)(x / Constants.RegionSize) * Constants.RegionSize; - uint ysnap = (uint)(y / Constants.RegionSize) * Constants.RegionSize; - ulong handle = Util.RegionWorldLocToHandle(xsnap, ysnap); - - if (m_neighbours.ContainsKey(handle)) - return m_neighbours[handle]; - - return null; - } - } -} diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionInfoCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionInfoCache.cs index be8a9a2..f6fff58 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionInfoCache.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionInfoCache.cs @@ -26,6 +26,8 @@ */ using System; using System.Reflection; +using System.Threading; +using System.Runtime.InteropServices; using System.Collections.Generic; using OpenSim.Framework; using OpenSim.Services.Interfaces; @@ -37,82 +39,68 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid { public class RegionInfoCache { - private const double CACHE_EXPIRATION_SECONDS = 300.0; // 5 minutes + private const float CACHE_EXPIRATION_SECONDS = 120; // 2 minutes opensim regions change a lot // private static readonly ILog m_log = // LogManager.GetLogger( // MethodBase.GetCurrentMethod().DeclaringType); - - internal struct ScopedRegionUUID + + private static RegionsExpiringCache m_Cache; + private int numberInstances; + + public RegionInfoCache() { - public UUID m_scopeID; - public UUID m_regionID; - public ScopedRegionUUID(UUID scopeID, UUID regionID) - { - m_scopeID = scopeID; - m_regionID = regionID; - } + if(m_Cache == null) + m_Cache = new RegionsExpiringCache(); + numberInstances++; } - - internal struct ScopedRegionName + + public void Cache(GridRegion rinfo) { - public UUID m_scopeID; - public string m_name; - public ScopedRegionName(UUID scopeID, string name) - { - m_scopeID = scopeID; - m_name = name; - } + if (rinfo != null) + this.Cache(rinfo.ScopeID, rinfo); } - internal struct ScopedRegionPosition + public void Cache(UUID scopeID, GridRegion rinfo) { - public UUID m_scopeID; - public ulong m_regionHandle; - public ScopedRegionPosition(UUID scopeID, ulong handle) - { - m_scopeID = scopeID; - m_regionHandle = handle; - } - } + if (rinfo == null) + return; - private ExpiringCache m_UUIDCache; - private ExpiringCache m_NameCache; - private ExpiringCache m_PositionCache; + m_Cache.AddOrUpdate(scopeID, rinfo, CACHE_EXPIRATION_SECONDS); + } - public RegionInfoCache() + public void CacheLocal(GridRegion rinfo) { - m_UUIDCache = new ExpiringCache(); - m_NameCache = new ExpiringCache(); - m_PositionCache = new ExpiringCache(); + if (rinfo == null) + return; + + m_Cache.AddOrUpdate(rinfo.ScopeID, rinfo, 1e7f); } - public void Cache(GridRegion rinfo) + public void CacheNearNeighbour(UUID scopeID, GridRegion rinfo) { - if (rinfo != null) - this.Cache(rinfo.ScopeID,rinfo.RegionID,rinfo); + if (rinfo == null) + return; + + m_Cache.AddOrUpdate(scopeID, rinfo, CACHE_EXPIRATION_SECONDS); } - - public void Cache(UUID scopeID, UUID regionID, GridRegion rinfo) + + public void Cache(UUID scopeID, GridRegion rinfo, float expireSeconds) { - // for now, do not cache negative results; this is because - // we need to figure out how to handle regions coming online - // in a timely way if (rinfo == null) return; - - ScopedRegionUUID id = new ScopedRegionUUID(scopeID,regionID); - - // Cache even null accounts - m_UUIDCache.AddOrUpdate(id, rinfo, CACHE_EXPIRATION_SECONDS); - if (rinfo != null) - { - ScopedRegionName name = new ScopedRegionName(scopeID,rinfo.RegionName); - m_NameCache.AddOrUpdate(name, id, CACHE_EXPIRATION_SECONDS); - ScopedRegionPosition pos = new ScopedRegionPosition(scopeID, rinfo.RegionHandle); - m_PositionCache.AddOrUpdate(pos, rinfo, CACHE_EXPIRATION_SECONDS); - } + m_Cache.AddOrUpdate(scopeID, rinfo, expireSeconds); + } + + public void Remove(UUID scopeID, GridRegion rinfo) + { + m_Cache.Remove(scopeID, rinfo); + } + + public void Remove(UUID scopeID, ulong regionHandle) + { + m_Cache.Remove(scopeID, regionHandle); } public GridRegion Get(UUID scopeID, UUID regionID, out bool inCache) @@ -120,8 +108,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid inCache = false; GridRegion rinfo = null; - ScopedRegionUUID id = new ScopedRegionUUID(scopeID,regionID); - if (m_UUIDCache.TryGetValue(id, out rinfo)) + if (m_Cache.TryGetValue(scopeID, regionID, out rinfo)) { inCache = true; return rinfo; @@ -135,8 +122,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid inCache = false; GridRegion rinfo = null; - ScopedRegionPosition pos = new ScopedRegionPosition(scopeID, handle); - if (m_PositionCache.TryGetValue(pos, out rinfo)) + if (m_Cache.TryGetValue(scopeID, handle, out rinfo)) { inCache = true; return rinfo; @@ -145,25 +131,868 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid return null; } - public GridRegion Get(UUID scopeID, string name, out bool inCache) { inCache = false; - ScopedRegionName sname = new ScopedRegionName(scopeID,name); + GridRegion rinfo = null; + if (m_Cache.TryGetValue(scopeID, name, out rinfo)) + { + inCache = true; + return rinfo; + } + + return null; + } + + public GridRegion Get(UUID scopeID, uint x, uint y, out bool inCache) + { + inCache = false; + + GridRegion rinfo = null; + if (m_Cache.TryGetValue(scopeID, x, y, out rinfo)) + { + inCache = true; + return rinfo; + } + + return null; + } + } + + // dont care about endianess + [StructLayout(LayoutKind.Explicit, Size = 8, Pack = 8)] + public class fastRegionHandle + { + [FieldOffset(0)] public ulong handle; + [FieldOffset(0)] public uint y; + [FieldOffset(4)] public uint x; + + public fastRegionHandle(ulong h) + { + handle = h; + } + + public fastRegionHandle(uint px, uint py) + { + y = py & 0xffffff00; + x = px & 0xffffff00; + } + // actually do care + public ulong toHandle() + { + if(BitConverter.IsLittleEndian) + return handle; + return (ulong) x << 32 | (ulong)y ; + } + + public static bool operator ==(fastRegionHandle value1, fastRegionHandle value2) + { + return value1.handle == value2.handle; + } + public static bool operator !=(fastRegionHandle value1, fastRegionHandle value2) + { + return value1.handle != value2.handle; + } + public override int GetHashCode() + { + return handle.GetHashCode(); + } + public override bool Equals(Object obj) + { + if(obj == null) + return false; + fastRegionHandle p = obj as fastRegionHandle; + return p.handle == handle; + } + } + +/* + [StructLayout(LayoutKind.Explicit, Size = 8, Pack = 8)] + public class regionHandle + { + [FieldOffset(0)] private ulong handle; + [FieldOffset(0)] public uint a; + [FieldOffset(4)] public uint b; + + public regionHandle(ulong h) + { + handle = h; + } + + public regionHandle(uint px, uint py) + { + if(BitConverter.IsLittleEndian) + { + a = py & 0xffffff00; + b = px & 0xffffff00; + } + else + { + a = px & 0xffffff00; + b = py & 0xffffff00; + } + } + + public uint x + { + get + { + if(BitConverter.IsLittleEndian) + return b; + return a; + } + set + { + if(BitConverter.IsLittleEndian) + b = value & 0xffffff00; + else + a = value & 0xffffff00; + } + } + + public uint y + { + get + { + if(BitConverter.IsLittleEndian) + return a; + return b; + } + set + { + if(BitConverter.IsLittleEndian) + a = value; + else + b = value; + } + } + + public static bool operator ==(regionHandle value1, regionHandle value2) + { + return value1.handle == value2.handle; + } + public static bool operator !=(regionHandle value1, regionHandle value2) + { + return value1.handle != value2.handle; + } + public override int GetHashCode() + { + return handle.GetHashCode(); + } + public override bool Equals(Object obj) + { + if(obj == null) + return false; + regionHandle p = obj as regionHandle; + return p.handle == handle; + } + } +*/ + + public class RegionInfoForScope + { + public const ulong HANDLEMASK = 0xffffff00ffffff00ul; + public const ulong HANDLECOORDMASK = 0xffffff00ul; + + private Dictionary storage; + private Dictionary expires; + private Dictionary byname; + private Dictionary byuuid; + // includes handles to the inside of large regions + private Dictionary innerHandles = new Dictionary(); + + public RegionInfoForScope() + { + storage = new Dictionary(); + expires = new Dictionary(); + byname = new Dictionary(); + byuuid = new Dictionary(); + } + + public RegionInfoForScope(GridRegion region, DateTime expire) + { + storage = new Dictionary(); + expires = new Dictionary(); + byname = new Dictionary(); + byuuid = new Dictionary(); + + ulong handle = region.RegionHandle & HANDLEMASK; + storage[handle] = region; + expires[handle] = expire; + byname[region.RegionName] = handle; + byuuid[region.RegionID] = handle; + addToInner(region); + } + + public void Add(GridRegion region, DateTime expire) + { + ulong handle = region.RegionHandle & HANDLEMASK; + + if(storage != null && storage.ContainsKey(handle)) + return; + + if(storage == null) + storage = new Dictionary(); + if(expires == null) + expires = new Dictionary(); + if(byname == null) + byname = new Dictionary(); + if(byuuid == null) + byuuid = new Dictionary(); + + storage[handle] = region; + expires[handle] = expire; + byname[region.RegionName] = handle; + byuuid[region.RegionID] = handle; + + addToInner(region); + } + + public void AddUpdate(GridRegion region, DateTime expire) + { + if(storage == null) + storage = new Dictionary(); + if(expires == null) + expires = new Dictionary(); + if(byname == null) + byname = new Dictionary(); + if(byuuid == null) + byuuid = new Dictionary(); + + ulong handle = region.RegionHandle & HANDLEMASK; - ScopedRegionUUID id; - if (m_NameCache.TryGetValue(sname, out id)) + if(expires.ContainsKey(handle)) { - GridRegion rinfo = null; - if (m_UUIDCache.TryGetValue(id, out rinfo)) + if(expires[handle] < expire) + expires[handle] = expire; + if(storage.ContainsKey(handle)) { - inCache = true; - return rinfo; + GridRegion oldr = storage[handle]; + if (oldr.RegionSizeX != region.RegionSizeX + || oldr.RegionSizeY != region.RegionSizeY) + { + removeFromInner(oldr); + addToInner(region); + } } } - + else + { + expires[handle] = expire; + addToInner(region); + } + storage[handle] = region; + byname[region.RegionName] = handle; + byuuid[region.RegionID] = handle; + } + + public void Remove(GridRegion region) + { + if(region == null) + return; + + if(byname != null) + byname.Remove(region.RegionName); + if(byuuid != null) + byuuid.Remove(region.RegionID); + + ulong handle = region.RegionHandle & HANDLEMASK; + if(storage != null) + { + if(storage.ContainsKey(handle)) + { + storage[handle] = null; + storage.Remove(handle); + } + } + removeFromInner(region); + if(expires != null) + { + expires.Remove(handle); + if(expires.Count == 0) + Clear(); + } + } + + public void Remove(ulong handle) + { + handle &= HANDLEMASK; + + if(storage != null) + { + if(storage.ContainsKey(handle)) + { + GridRegion r = storage[handle]; + if(byname != null) + byname.Remove(r.RegionName); + if(byuuid != null) + byuuid.Remove(r.RegionID); + removeFromInner(r); + storage[handle] = null; + } + storage.Remove(handle); + } + if(expires != null) + { + expires.Remove(handle); + if(expires.Count == 0) + Clear(); + } + } + + public void Clear() + { + if(expires != null) + expires.Clear(); + if(storage != null) + storage.Clear(); + if(byname != null) + byname.Clear(); + if(byuuid != null) + byuuid.Clear(); + byname = null; + byuuid = null; + storage = null; + expires = null; + innerHandles.Clear(); + } + + public bool Contains(GridRegion region) + { + if(storage == null) + return false; + if(region == null) + return false; + + ulong handle = region.RegionHandle & HANDLEMASK; + return storage.ContainsKey(handle); + } + + public bool Contains(ulong handle) + { + if(storage == null) + return false; + + handle &= HANDLEMASK; + return storage.ContainsKey(handle); + } + + public GridRegion get(ulong handle) + { + if(storage == null) + return null; + + handle &= HANDLEMASK; + if(storage.ContainsKey(handle)) + return storage[handle]; + + if(!innerHandles.ContainsKey(handle)) + return null; + + ulong rhandle = innerHandles[handle]; + if(storage.ContainsKey(rhandle)) + return storage[rhandle]; + return null; } + + public GridRegion get(string name) + { + if(byname == null || !byname.ContainsKey(name)) + return null; + + ulong handle = byname[name]; + if(storage.ContainsKey(handle)) + return storage[handle]; + return null; + } + + public GridRegion get(UUID id) + { + if(byuuid == null || !byuuid.ContainsKey(id)) + return null; + + ulong handle = byuuid[id]; + if(storage.ContainsKey(handle)) + return storage[handle]; + return null; + } + + public GridRegion get(uint x, uint y) + { + if(storage == null) + return null; + + // look for a handle first this should find normal size regions + ulong handle = (ulong)x & HANDLECOORDMASK; + handle <<= 32; + handle |= ((ulong)y & HANDLECOORDMASK); + + if(storage.ContainsKey(handle)) + return storage[handle]; + + if(!innerHandles.ContainsKey(handle)) + return null; + + ulong rhandle = innerHandles[handle]; + if(!storage.ContainsKey(rhandle)) + return null; + + GridRegion r = storage[rhandle]; + if(r == null) + return null; + + // extra check, possible redundant + + int test = r.RegionLocX; + if(x < test) + return null; + test += r.RegionSizeX; + if(x >= test) + return null; + test = r.RegionLocY; + if (y < test) + return null; + test += r.RegionSizeY; + if (y < test) + return r; + +/* + // next do the harder work + foreach(KeyValuePair kvp in storage) + { + GridRegion r = kvp.Value; + if(r == null) // ?? + continue; + + int test = r.RegionLocX; + if(x < test) + continue; + test += r.RegionSizeX; + if(x >= test) + continue; + test = r.RegionLocY; + if (y < test) + continue; + test += r.RegionSizeY; + if (y < test) + return r; + } +*/ + return null; + } + + public int expire(DateTime now ) + { + if(expires == null || expires.Count == 0) + return 0; + + int expiresCount = expires.Count; + List toexpire = new List(); + + foreach(KeyValuePair kvp in expires) + { + if(kvp.Value < now) + toexpire.Add(kvp.Key); + } + + int toexpireCount = toexpire.Count; + if(toexpireCount == 0) + return expiresCount; + + if(toexpireCount == expiresCount) + { + Clear(); + return 0; + } + + if(storage != null) + { + ulong h; + for(int i = 0; i < toexpireCount; i++) + { + h = toexpire[i]; + if(storage.ContainsKey(h)) + { + GridRegion r = storage[h]; + if(byname != null) + byname.Remove(r.RegionName); + if(byuuid != null) + byuuid.Remove(r.RegionID); + removeFromInner(r); + + storage[h] = null; + storage.Remove(h); + } + if(expires != null) + expires.Remove(h); + } + } + else + { + Clear(); + return 0; + } + + expiresCount = expires.Count; + if(expiresCount == 0) + { + byname = null; + byuuid = null; + storage = null; + expires = null; + return 0; + } + + return expiresCount; + } + + public int Count() + { + if(byname == null) + return 0; + else + return byname.Count; + } + + private void addToInner(GridRegion region) + { + int rsx = region.RegionSizeX; + int rsy = region.RegionSizeY; + + if(rsx < 512 && rsy < 512) + return; + + rsx >>= 8; + rsy >>= 8; + + ulong handle = region.RegionHandle & HANDLEMASK; + fastRegionHandle fh = new fastRegionHandle(handle); + uint startY = fh.y; + for(int i = 0; i < rsx; i++) + { + for(int j = 0; j < rsy ; j++) + { + innerHandles[fh.toHandle()] = handle; + fh.y += 256; + } + + fh.y = startY; + fh.x += 256; + } + } + + private void removeFromInner(GridRegion region) + { + int rsx = region.RegionSizeX; + int rsy = region.RegionSizeY; + + if(rsx < 512 && rsy < 512) + return; + + rsx >>= 8; + rsy >>= 8; + ulong handle = region.RegionHandle & HANDLEMASK; + fastRegionHandle fh = new fastRegionHandle(handle); + uint startY = fh.y; + for(int i = 0; i < rsx; i++) + { + for(int j = 0; j < rsy ; j++) + { + innerHandles.Remove(fh.toHandle()); + fh.y += 256; + } + + fh.y = startY; + fh.x += 256; + } + } + } + + public class RegionsExpiringCache + { + const double CACHE_PURGE_TIME = 60000; // milliseconds + const int MAX_LOCK_WAIT = 10000; // milliseconds + + /// For thread safety + object syncRoot = new object(); + /// For thread safety + object isPurging = new object(); + + Dictionary InfobyScope = new Dictionary(); + private System.Timers.Timer timer = new System.Timers.Timer(CACHE_PURGE_TIME); + + public RegionsExpiringCache() + { + timer.Elapsed += PurgeCache; + timer.Start(); + } + + public bool AddOrUpdate(UUID scope, GridRegion region, float expirationSeconds) + { + if(region == null) + return false; + + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + + try + { + DateTime expire = DateTime.UtcNow + TimeSpan.FromSeconds(expirationSeconds); + + RegionInfoForScope ris = null; + if(!InfobyScope.TryGetValue(scope, out ris) || ris == null) + { + ris = new RegionInfoForScope(region, expire); + InfobyScope[scope] = ris; + } + else + ris.AddUpdate(region, expire); + + return true; + } + finally { Monitor.Exit(syncRoot); } + } + + public void Clear() + { + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + try + { + foreach(RegionInfoForScope ris in InfobyScope.Values) + ris.Clear(); + InfobyScope.Clear(); + } + finally { Monitor.Exit(syncRoot); } + } + + public bool Contains(UUID scope, GridRegion region) + { + if(region == null) + return false; + + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + + try + { + RegionInfoForScope ris = null; + if(!InfobyScope.TryGetValue(scope, out ris) || ris == null) + return false; + + return ris.Contains(region); + } + finally { Monitor.Exit(syncRoot); } + } + + public bool Contains(UUID scope, ulong handle) + { + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + + try + { + RegionInfoForScope ris = null; + if(!InfobyScope.TryGetValue(scope, out ris) || ris == null) + return false; + + return ris.Contains(handle); + } + finally { Monitor.Exit(syncRoot); } + } + + public int Count() + { + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + + try + { + int count = 0; + foreach(RegionInfoForScope ris in InfobyScope.Values) + count += ris.Count(); + return count; + } + finally { Monitor.Exit(syncRoot); } + } + + public bool Remove(UUID scope, ulong handle) + { + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + try + { + RegionInfoForScope ris = null; + if(!InfobyScope.TryGetValue(scope, out ris) || ris == null) + return false; + + ris.Remove(handle); + if(ris.Count() == 0) + InfobyScope.Remove(scope); + return true; + } + finally { Monitor.Exit(syncRoot); } + } + + public bool Remove(UUID scope, GridRegion region) + { + if(region == null) + return false; + + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + try + { + RegionInfoForScope ris = null; + if(!InfobyScope.TryGetValue(scope, out ris) || ris == null) + return false; + + ris.Remove(region); + if(ris.Count() == 0) + InfobyScope.Remove(scope); + return true; + } + finally { Monitor.Exit(syncRoot); } + } + + public bool TryGetValue(UUID scope, ulong handle, out GridRegion value) + { + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + + value = null; + try + { + RegionInfoForScope ris = null; + if(!InfobyScope.TryGetValue(scope, out ris) || ris == null) + return false; + value = ris.get(handle); + } + finally { Monitor.Exit(syncRoot); } + + return value != null; + } + + public bool TryGetValue(UUID scope, string name, out GridRegion value) + { + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + + value = null; + try + { + RegionInfoForScope ris = null; + if(!InfobyScope.TryGetValue(scope, out ris) || ris == null) + return false; + value = ris.get(name); + } + finally { Monitor.Exit(syncRoot); } + + return value != null; + } + + public bool TryGetValue(UUID scope, UUID id, out GridRegion value) + { + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + + value = null; + try + { + RegionInfoForScope ris = null; + if(!InfobyScope.TryGetValue(scope, out ris) || ris == null) + return false; + value = ris.get(id); + } + finally { Monitor.Exit(syncRoot); } + + return value != null; + } + + // gets a region that contains world position (x,y) + // hopefull will not take ages + public bool TryGetValue(UUID scope, uint x, uint y, out GridRegion value) + { + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + + value = null; + try + { + RegionInfoForScope ris = null; + if(!InfobyScope.TryGetValue(scope, out ris) || ris == null) + return false; + + value = ris.get(x, y); + } + finally { Monitor.Exit(syncRoot); } + + return value != null; + } + + public bool Update(UUID scope, GridRegion region, double expirationSeconds) + { + if(region == null) + return false; + + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + throw new ApplicationException("Lock could not be acquired after " + MAX_LOCK_WAIT + "ms"); + + try + { + RegionInfoForScope ris = null; + if(!InfobyScope.TryGetValue(scope, out ris) || ris == null) + return false; + + DateTime expire = DateTime.UtcNow + TimeSpan.FromSeconds(expirationSeconds); + ris.AddUpdate(region,expire); + return true; + } + finally { Monitor.Exit(syncRoot); } + } + + /// + /// Purges expired objects from the cache. Called automatically by the purge timer. + /// + private void PurgeCache(object sender, System.Timers.ElapsedEventArgs e) + { + // Only let one thread purge at once - a buildup could cause a crash + // This could cause the purge to be delayed while there are lots of read/write ops + // happening on the cache + if (!Monitor.TryEnter(isPurging)) + return; + + DateTime now = DateTime.UtcNow; + + try + { + // If we fail to acquire a lock on the synchronization root after MAX_LOCK_WAIT, skip this purge cycle + if (!Monitor.TryEnter(syncRoot, MAX_LOCK_WAIT)) + return; + try + { + List expiredscopes = new List(); + + foreach (KeyValuePair kvp in InfobyScope) + { + if (kvp.Value.expire(now) == 0) + expiredscopes.Add(kvp.Key); + } + + if (expiredscopes.Count > 0) + { + foreach (UUID sid in expiredscopes) + { + InfobyScope[sid] = null; + InfobyScope.Remove(sid); + } + } + } + finally { Monitor.Exit(syncRoot); } + } + finally { Monitor.Exit(isPurging); } + } } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs index 85073fc..ee17093 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs @@ -52,12 +52,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid MethodBase.GetCurrentMethod().DeclaringType); private bool m_Enabled = false; + private string m_ThisGatekeeper = string.Empty; private IGridService m_LocalGridService; private IGridService m_RemoteGridService; - private RegionInfoCache m_RegionInfoCache = new RegionInfoCache(); - + private RegionInfoCache m_RegionInfoCache; + public RemoteGridServicesConnector() { } @@ -69,7 +70,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid #region ISharedRegionmodule - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -87,38 +88,57 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid string name = moduleConfig.GetString("GridServices", ""); if (name == Name) { - InitialiseServices(source); - m_Enabled = true; - m_log.Info("[REMOTE GRID CONNECTOR]: Remote grid enabled"); + if(InitialiseServices(source)) + { + m_Enabled = true; + m_log.Info("[REMOTE GRID CONNECTOR]: Remote grid enabled"); + } } } } - private void InitialiseServices(IConfigSource source) + private bool InitialiseServices(IConfigSource source) { IConfig gridConfig = source.Configs["GridService"]; if (gridConfig == null) { m_log.Error("[REMOTE GRID CONNECTOR]: GridService missing from OpenSim.ini"); - return; + return false; } string networkConnector = gridConfig.GetString("NetworkConnector", string.Empty); if (networkConnector == string.Empty) { m_log.Error("[REMOTE GRID CONNECTOR]: Please specify a network connector under [GridService]"); - return; + return false; } - Object[] args = new Object[] { source }; + Object[] args = new Object[] { source }; m_RemoteGridService = ServerUtils.LoadPlugin(networkConnector, args); - m_LocalGridService = new LocalGridServicesConnector(source); - } + m_LocalGridService = new LocalGridServicesConnector(source, m_RegionInfoCache); + if (m_LocalGridService == null) + { + m_log.Error("[REMOTE GRID CONNECTOR]: failed to load local connector"); + return false; + } + + if(m_RegionInfoCache == null) + m_RegionInfoCache = new RegionInfoCache(); + + m_ThisGatekeeper = Util.GetConfigVarFromSections(source, "GatekeeperURI", + new string[] { "Startup", "Hypergrid", "GridService" }, String.Empty); + // Legacy. Remove soon! + m_ThisGatekeeper = gridConfig.GetString("Gatekeeper", m_ThisGatekeeper); + + Util.checkServiceURI(m_ThisGatekeeper, out m_ThisGatekeeper); + + return true; + } public void PostInitialise() { - if (m_LocalGridService != null) + if (m_Enabled) ((ISharedRegionModule)m_LocalGridService).PostInitialise(); } @@ -129,15 +149,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid public void AddRegion(Scene scene) { if (m_Enabled) + { scene.RegisterModuleInterface(this); - - if (m_LocalGridService != null) ((ISharedRegionModule)m_LocalGridService).AddRegion(scene); + } } public void RemoveRegion(Scene scene) { - if (m_LocalGridService != null) + if (m_Enabled) ((ISharedRegionModule)m_LocalGridService).RemoveRegion(scene); } @@ -174,16 +194,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid public GridRegion GetRegionByUUID(UUID scopeID, UUID regionID) { - bool inCache = false; - GridRegion rinfo = m_RegionInfoCache.Get(scopeID,regionID,out inCache); - if (inCache) + GridRegion rinfo = m_LocalGridService.GetRegionByUUID(scopeID, regionID); + if (rinfo != null) return rinfo; - - rinfo = m_LocalGridService.GetRegionByUUID(scopeID, regionID); - if (rinfo == null) - rinfo = m_RemoteGridService.GetRegionByUUID(scopeID, regionID); - m_RegionInfoCache.Cache(scopeID,regionID,rinfo); + rinfo = m_RemoteGridService.GetRegionByUUID(scopeID, regionID); + m_RegionInfoCache.Cache(scopeID, rinfo); return rinfo; } @@ -193,51 +209,56 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid // The coordinates are world coords (meters), NOT region units. public GridRegion GetRegionByPosition(UUID scopeID, int x, int y) { - ulong regionHandle = Util.RegionWorldLocToHandle((uint)x, (uint)y); - uint regionX = Util.WorldToRegionLoc((uint)x); - uint regionY = Util.WorldToRegionLoc((uint)y); - - // Sanity check - if ((Util.RegionToWorldLoc(regionX) != (uint)x) || (Util.RegionToWorldLoc(regionY) != (uint)y)) + GridRegion rinfo = m_LocalGridService.GetRegionByPosition(scopeID, x, y); + if (rinfo != null) { - m_log.WarnFormat("[REMOTE GRID CONNECTOR]: GetRegionByPosition. Bad position requested: not the base of the region. Requested Pos=<{0},{1}>, Should Be=<{2},{3}>", - x, y, Util.RegionToWorldLoc(regionX), Util.RegionToWorldLoc(regionY)); - } - - bool inCache = false; - GridRegion rinfo = m_RegionInfoCache.Get(scopeID, regionHandle, out inCache); - if (inCache) - { - //m_log.DebugFormat("[REMOTE GRID CONNECTOR]: GetRegionByPosition. Found region {0} in cache. Pos=<{1},{2}>, RegionHandle={3}", - // (rinfo == null) ? "" : rinfo.RegionName, regionX, regionY, (rinfo == null) ? regionHandle : rinfo.RegionHandle); +// m_log.DebugFormat("[REMOTE GRID CONNECTOR]: GetRegionByPosition. Found region {0} on local. Pos=<{1},{2}>, RegionHandle={3}", +// rinfo.RegionName, rinfo.RegionCoordX, rinfo.RegionCoordY, rinfo.RegionHandle); return rinfo; } - rinfo = m_LocalGridService.GetRegionByPosition(scopeID, x, y); - if (rinfo == null) - rinfo = m_RemoteGridService.GetRegionByPosition(scopeID, x, y); + rinfo = m_RemoteGridService.GetRegionByPosition(scopeID, x, y); - m_RegionInfoCache.Cache(rinfo); - - //m_log.DebugFormat("[REMOTE GRID CONNECTOR]: GetRegionByPosition. Added region {0} to the cache. Pos=<{1},{2}>, RegionHandle={3}", - // (rinfo == null) ? "" : rinfo.RegionName, regionX, regionY, (rinfo == null) ? regionHandle : rinfo.RegionHandle); + if (rinfo == null) + { +// uint regionX = Util.WorldToRegionLoc((uint)x); +// uint regionY = Util.WorldToRegionLoc((uint)y); +// m_log.WarnFormat("[REMOTE GRID CONNECTOR]: Requested region {0}-{1} not found", regionX, regionY); + } + else + { + m_RegionInfoCache.Cache(scopeID, rinfo); +// m_log.DebugFormat("[REMOTE GRID CONNECTOR]: GetRegionByPosition. Added region {0} to the cache. Pos=<{1},{2}>, RegionHandle={3}", +// rinfo.RegionName, rinfo.RegionCoordX, rinfo.RegionCoordY, rinfo.RegionHandle); + } return rinfo; } - public GridRegion GetRegionByName(UUID scopeID, string regionName) + public GridRegion GetRegionByName(UUID scopeID, string name) { - bool inCache = false; - GridRegion rinfo = m_RegionInfoCache.Get(scopeID,regionName, out inCache); - if (inCache) + GridRegion rinfo = m_LocalGridService.GetRegionByName(scopeID, name); + if (rinfo != null) return rinfo; - - rinfo = m_LocalGridService.GetRegionByName(scopeID, regionName); - if (rinfo == null) - rinfo = m_RemoteGridService.GetRegionByName(scopeID, regionName); - // can't cache negative results for name lookups - m_RegionInfoCache.Cache(rinfo); + // HG urls should not get here, strip them + // side effect is that local regions with same name as HG may also be found + // this mb good or bad + string regionName = name; + if(name.Contains(".")) + { + if(string.IsNullOrWhiteSpace(m_ThisGatekeeper)) + return rinfo; // no HG + + string regionURI = ""; + if(!Util.buildHGRegionURI(name, out regionURI, out regionName) || string.IsNullOrWhiteSpace(regionName)) + return rinfo; // invalid + if(m_ThisGatekeeper != regionURI) + return rinfo; // not local grid + } + + rinfo = m_RemoteGridService.GetRegionByName(scopeID, regionName); + m_RegionInfoCache.Cache(scopeID, rinfo); return rinfo; } @@ -245,7 +266,24 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid { List rinfo = m_LocalGridService.GetRegionsByName(scopeID, name, maxNumber); //m_log.DebugFormat("[REMOTE GRID CONNECTOR]: Local GetRegionsByName {0} found {1} regions", name, rinfo.Count); - List grinfo = m_RemoteGridService.GetRegionsByName(scopeID, name, maxNumber); + + // HG urls should not get here, strip them + // side effect is that local regions with same name as HG may also be found + // this mb good or bad + string regionName = name; + if(name.Contains(".")) + { + if(string.IsNullOrWhiteSpace(m_ThisGatekeeper)) + return rinfo; // no HG + + string regionURI = ""; + if(!Util.buildHGRegionURI(name, out regionURI, out regionName) || string.IsNullOrWhiteSpace(regionName)) + return rinfo; // invalid + if(m_ThisGatekeeper != regionURI) + return rinfo; // not local grid + } + + List grinfo = m_RemoteGridService.GetRegionsByName(scopeID, regionName, maxNumber); if (grinfo != null) { diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs index 25ae689..1378368 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs @@ -64,7 +64,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests config.Configs["GridService"].Set("Region_Test_Region_3", "FallbackRegion"); config.Configs["GridService"].Set("Region_Other_Region_4", "FallbackRegion"); - m_LocalConnector = new LocalGridServicesConnector(config); + m_LocalConnector = new LocalGridServicesConnector(config, null); } /// @@ -88,7 +88,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests Scene s = new Scene(new RegionInfo()); s.RegionInfo.RegionID = r1.RegionID; m_LocalConnector.AddRegion(s); - + GridRegion r2 = new GridRegion(); r2.RegionName = "Test Region 2"; r2.RegionID = new UUID(2); @@ -198,4 +198,4 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests Assert.That(results.Count, Is.EqualTo(0), "Retrieved linked regions collection is not the number expected"); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs index 2238c90..1529fc2 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs @@ -37,7 +37,7 @@ using log4net; namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser { - public class ActivityDetector + public class ActivityDetector { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -63,18 +63,31 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser scene.EventManager.OnNewClient -= OnNewClient; } - public void OnMakeRootAgent(ScenePresence sp) - { - if (sp.PresenceType != PresenceType.Npc) + public void OnMakeRootAgent(ScenePresence sp) + { + if (sp.IsNPC) + return; + + if(sp.gotCrossUpdate) { - string userid; - //m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected root presence {0} in {1}", userid, sp.Scene.RegionInfo.RegionName); - if (sp.Scene.UserManagementModule.GetUserUUI(sp.UUID, out userid)) + Util.FireAndForget(delegate { - /* we only setposition on known agents that have a valid lookup */ - m_GridUserService.SetLastPosition( - userid, UUID.Zero, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); - } + DoOnMakeRootAgent(sp); + }, null, "ActivityDetector_MakeRoot"); + } + else + DoOnMakeRootAgent(sp); + } + + public void DoOnMakeRootAgent(ScenePresence sp) + { + string userid; + //m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected root presence {0} in {1}", userid, sp.Scene.RegionInfo.RegionName); + if (sp.Scene.UserManagementModule.GetUserUUI(sp.UUID, out userid)) + { + /* we only setposition on known agents that have a valid lookup */ + m_GridUserService.SetLastPosition( + userid, UUID.Zero, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs index 48f228a..7a4f981 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs @@ -86,7 +86,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory } } - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -203,21 +203,22 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory void OnClientClosed(UUID clientID, Scene scene) { - if (m_InventoryURLs.ContainsKey(clientID)) // if it's in cache + ScenePresence sp = null; + foreach (Scene s in m_Scenes) { - ScenePresence sp = null; - foreach (Scene s in m_Scenes) + s.TryGetScenePresence(clientID, out sp); + if ((sp != null) && !sp.IsChildAgent && (s != scene)) { - s.TryGetScenePresence(clientID, out sp); - if ((sp != null) && !sp.IsChildAgent && (s != scene)) - { - m_log.DebugFormat("[INVENTORY CACHE]: OnClientClosed in {0}, but user {1} still in sim. Keeping inventoryURL in cache", + m_log.DebugFormat("[INVENTORY CACHE]: OnClientClosed in {0}, but user {1} still in sim. Keeping inventoryURL in cache", scene.RegionInfo.RegionName, clientID); return; - } } - DropInventoryServiceURL(clientID); } + + if (m_InventoryURLs.ContainsKey(clientID)) // if it's in cache + DropInventoryServiceURL(clientID); + + m_Cache.RemoveAll(clientID); } /// @@ -249,7 +250,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory if (inventoryURL != null && inventoryURL != string.Empty) { inventoryURL = inventoryURL.Trim(new char[] { '/' }); - m_InventoryURLs[userID] = inventoryURL; + lock (m_InventoryURLs) + m_InventoryURLs[userID] = inventoryURL; m_log.DebugFormat("[HG INVENTORY CONNECTOR]: Added {0} to the cache of inventory URLs", inventoryURL); return; } @@ -267,38 +269,45 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory if (!string.IsNullOrEmpty(inventoryURL)) { inventoryURL = inventoryURL.Trim(new char[] { '/' }); - m_InventoryURLs.Add(userID, inventoryURL); + lock (m_InventoryURLs) + m_InventoryURLs[userID] = inventoryURL; m_log.DebugFormat("[HG INVENTORY CONNECTOR]: Added {0} to the cache of inventory URLs", inventoryURL); } - } - } } private void DropInventoryServiceURL(UUID userID) { lock (m_InventoryURLs) + { if (m_InventoryURLs.ContainsKey(userID)) { string url = m_InventoryURLs[userID]; m_InventoryURLs.Remove(userID); m_log.DebugFormat("[HG INVENTORY CONNECTOR]: Removed {0} from the cache of inventory URLs", url); } + } } public string GetInventoryServiceURL(UUID userID) { - if (m_InventoryURLs.ContainsKey(userID)) - return m_InventoryURLs[userID]; + lock (m_InventoryURLs) + { + if (m_InventoryURLs.ContainsKey(userID)) + return m_InventoryURLs[userID]; + } CacheInventoryServiceURL(userID); - if (m_InventoryURLs.ContainsKey(userID)) - return m_InventoryURLs[userID]; + lock (m_InventoryURLs) + { + if (m_InventoryURLs.ContainsKey(userID)) + return m_InventoryURLs[userID]; + } return null; //it means that the methods should forward to local grid's inventory - + } #endregion @@ -598,21 +607,19 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return connector.DeleteItems(ownerID, itemIDs); } - public InventoryItemBase GetItem(InventoryItemBase item) + public InventoryItemBase GetItem(UUID principalID, UUID itemID) { - if (item == null) - return null; //m_log.Debug("[HG INVENTORY CONNECTOR]: GetItem " + item.ID); - string invURL = GetInventoryServiceURL(item.Owner); + string invURL = GetInventoryServiceURL(principalID); if (invURL == null) // not there, forward to local inventory connector to resolve lock (m_Lock) - return m_LocalGridInventoryService.GetItem(item); + return m_LocalGridInventoryService.GetItem(principalID, itemID); IInventoryService connector = GetConnector(invURL); - return connector.GetItem(item); + return connector.GetItem(principalID, itemID); } public InventoryItemBase[] GetMultipleItems(UUID userID, UUID[] itemIDs) @@ -632,22 +639,19 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return connector.GetMultipleItems(userID, itemIDs); } - public InventoryFolderBase GetFolder(InventoryFolderBase folder) + public InventoryFolderBase GetFolder(UUID principalID, UUID folderID) { - if (folder == null) - return null; - //m_log.Debug("[HG INVENTORY CONNECTOR]: GetFolder " + folder.ID); - string invURL = GetInventoryServiceURL(folder.Owner); + string invURL = GetInventoryServiceURL(principalID); if (invURL == null) // not there, forward to local inventory connector to resolve lock (m_Lock) - return m_LocalGridInventoryService.GetFolder(folder); + return m_LocalGridInventoryService.GetFolder(principalID, folderID); IInventoryService connector = GetConnector(invURL); - return connector.GetFolder(folder); + return connector.GetFolder(principalID, folderID); } public bool HasInventoryForUser(UUID userID) @@ -710,4 +714,4 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return connector; } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs index 3195e6b..f7ef2ea 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs @@ -38,12 +38,23 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory /// public class InventoryCache { - private const double CACHE_EXPIRATION_SECONDS = 3600.0; // 1 hour + private const double CACHE_EXPIRATION_SECONDS = 60.0; // 1 minute private static ExpiringCache m_RootFolders = new ExpiringCache(); private static ExpiringCache> m_FolderTypes = new ExpiringCache>(); private static ExpiringCache m_Inventories = new ExpiringCache(); + + public void RemoveAll(UUID userID) + { + if(m_RootFolders.Contains(userID)) + m_RootFolders.Remove(userID); + if(m_FolderTypes.Contains(userID)) + m_FolderTypes.Remove(userID); + if(m_Inventories.Contains(userID)) + m_Inventories.Remove(userID); + } + public void Cache(UUID userID, InventoryFolderBase root) { m_RootFolders.AddOrUpdate(userID, root, CACHE_EXPIRATION_SECONDS); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs index 20d4e02..fa36b66 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs @@ -72,7 +72,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory private bool m_Enabled = false; - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -134,7 +134,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory { if (!m_Enabled) return; - + scene.RegisterModuleInterface(this); if (Scene == null) @@ -261,9 +261,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory public bool AddItem(InventoryItemBase item) { // m_log.DebugFormat( -// "[LOCAL INVENTORY SERVICES CONNECTOR]: Adding inventory item {0} to user {1} folder {2}", +// "[LOCAL INVENTORY SERVICES CONNECTOR]: Adding inventory item {0} to user {1} folder {2}", // item.Name, item.Owner, item.Folder); - + return m_InventoryService.AddItem(item); } @@ -292,13 +292,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return m_InventoryService.DeleteItems(ownerID, itemIDs); } - public InventoryItemBase GetItem(InventoryItemBase item) + public InventoryItemBase GetItem(UUID principalID, UUID itemID) { // m_log.DebugFormat("[LOCAL INVENTORY SERVICES CONNECTOR]: Requesting inventory item {0}", item.ID); // UUID requestedItemId = item.ID; - - item = m_InventoryService.GetItem(item); + + InventoryItemBase item = m_InventoryService.GetItem(principalID, itemID); // if (null == item) // m_log.ErrorFormat( @@ -312,9 +312,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return m_InventoryService.GetMultipleItems(userID, itemIDs); } - public InventoryFolderBase GetFolder(InventoryFolderBase folder) + public InventoryFolderBase GetFolder(UUID principalID, UUID folderID) { - return m_InventoryService.GetFolder(folder); + return m_InventoryService.GetFolder(principalID, folderID); } /// diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs index 978b9d9..d8ae2c4 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs @@ -74,7 +74,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory } } - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -292,15 +292,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return m_RemoteConnector.DeleteItems(ownerID, itemIDs); } - public InventoryItemBase GetItem(InventoryItemBase item) + public InventoryItemBase GetItem(UUID userID, UUID itemID) { //m_log.DebugFormat("[XINVENTORY CONNECTOR]: GetItem {0}", item.ID); - if (item == null) - return null; if (m_RemoteConnector == null) m_log.DebugFormat("[XINVENTORY CONNECTOR]: connector stub is null!!!"); - return m_RemoteConnector.GetItem(item); + return m_RemoteConnector.GetItem(userID, itemID); } public InventoryItemBase[] GetMultipleItems(UUID userID, UUID[] itemIDs) @@ -311,13 +309,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return m_RemoteConnector.GetMultipleItems(userID, itemIDs); } - public InventoryFolderBase GetFolder(InventoryFolderBase folder) + public InventoryFolderBase GetFolder(UUID userID, UUID folderID) { //m_log.DebugFormat("[XINVENTORY CONNECTOR]: GetFolder {0}", folder.ID); - if (folder == null) - return null; - return m_RemoteConnector.GetFolder(folder); + return m_RemoteConnector.GetFolder(userID, folderID); } public bool HasInventoryForUser(UUID userID) @@ -337,4 +333,4 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory #endregion } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Land/LocalLandServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Land/LocalLandServiceConnector.cs index 5329933..8baf41a 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Land/LocalLandServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Land/LocalLandServiceConnector.cs @@ -62,7 +62,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Land #region ISharedRegionModule - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -121,15 +121,32 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Land public LandData GetLandData(UUID scopeID, ulong regionHandle, uint x, uint y, out byte regionAccess) { regionAccess = 2; - m_log.DebugFormat("[LAND CONNECTOR]: request for land data in {0} at {1}, {2}", - regionHandle, x, y); +// m_log.DebugFormat("[LAND CONNECTOR]: request for land data in {0} at {1}, {2}", +// regionHandle, x, y); + + uint rx = 0, ry = 0; + Util.RegionHandleToWorldLoc(regionHandle, out rx, out ry); foreach (Scene s in m_Scenes) { - if (s.RegionInfo.RegionHandle == regionHandle) + uint t = s.RegionInfo.WorldLocX; + if( rx < t) + continue; + t += s.RegionInfo.RegionSizeX; + if( rx >= t) + continue; + t = s.RegionInfo.WorldLocY; + if( ry < t) + continue; + t += s.RegionInfo.RegionSizeY; + if( ry < t) { LandData land = s.GetLandData(x, y); regionAccess = s.RegionInfo.AccessLevel; + IDwellModule dwellModule = s.RequestModuleInterface(); + if (dwellModule != null) + land.Dwell = dwellModule.GetDwell(land); + return land; } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Land/RemoteLandServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Land/RemoteLandServiceConnector.cs index 77dfa4a..68c5b64 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Land/RemoteLandServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Land/RemoteLandServiceConnector.cs @@ -53,7 +53,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Land private bool m_Enabled = false; private LocalLandServicesConnector m_LocalService; - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs index 08d6bdd..9888c3b 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs @@ -53,6 +53,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage /// [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MapImageServiceModule")] + public class MapImageServiceModule : IMapImageUploadModule, ISharedRegionModule { private static readonly ILog m_log = @@ -67,11 +68,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage private int m_refreshtime = 0; private int m_lastrefresh = 0; private System.Timers.Timer m_refreshTimer; - + #region ISharedRegionModule - + public Type ReplaceableInterface { get { return null; } } - public string Name { get { return "MapImageServiceModule"; } } + public string Name { get { return "MapImageServiceModule"; } } public void RegionLoaded(Scene scene) { } public void Close() { } public void PostInitialise() { } @@ -94,8 +95,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage return; int refreshminutes = Convert.ToInt32(config.GetString("RefreshTime")); - - // if refresh is less than zero, disable the module if (refreshminutes < 0) { m_log.WarnFormat("[MAP IMAGE SERVICE MODULE]: Negative refresh time given in config. Module disabled."); @@ -116,22 +115,23 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage m_log.WarnFormat("[MAP IMAGE SERVICE MODULE]: Unable to load LocalServiceModule from {0}. MapService module disabled. Please fix the configuration.", service); return; } - + // we don't want the timer if the interval is zero, but we still want this module enables if(refreshminutes > 0) { m_refreshtime = refreshminutes * 60 * 1000; // convert from minutes to ms - + m_refreshTimer = new System.Timers.Timer(); m_refreshTimer.Enabled = true; m_refreshTimer.AutoReset = true; m_refreshTimer.Interval = m_refreshtime; m_refreshTimer.Elapsed += new ElapsedEventHandler(HandleMaptileRefresh); + m_log.InfoFormat("[MAP IMAGE SERVICE MODULE]: enabled with refresh time {0} min and service object {1}", refreshminutes, service); } - else + else { m_log.InfoFormat("[MAP IMAGE SERVICE MODULE]: enabled with no refresh and service object {0}", service); } @@ -171,7 +171,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage } #endregion ISharedRegionModule - + /// /// /// @@ -210,7 +210,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage return; } - m_log.DebugFormat("{0} Upload maptile for {1}", LogHeader, scene.Name); // mapTile.Save( // DEBUG DEBUG // String.Format("maptiles/raw-{0}-{1}-{2}.jpg", regionName, scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY), @@ -218,12 +217,17 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage // 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) { - ConvertAndUploadMaptile(mapTile, + m_log.DebugFormat("{0} Upload maptile for {1}", LogHeader, scene.Name); + ConvertAndUploadMaptile(scene, mapTile, scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY, scene.RegionInfo.RegionName); } else { + m_log.DebugFormat("{0} Upload {1} maptiles for {2}", LogHeader, + (mapTile.Width * mapTile.Height) / (Constants.RegionSize * Constants.RegionSize), + scene.Name); + // 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. @@ -240,7 +244,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage (int)Constants.RegionSize, (int)Constants.RegionSize); using (Bitmap subMapTile = mapTile.Clone(rect, mapTile.PixelFormat)) { - ConvertAndUploadMaptile(subMapTile, + ConvertAndUploadMaptile(scene, subMapTile, scene.RegionInfo.RegionLocX + (xx / Constants.RegionSize), scene.RegionInfo.RegionLocY + (yy / Constants.RegionSize), scene.Name); @@ -253,8 +257,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage /// /// /// - private void UploadMapTile(IScene scene) + public void UploadMapTile(IScene scene) { + m_log.DebugFormat("{0}: upload maptile for {1}", LogHeader, scene.RegionInfo.RegionName); + // Create a JPG map tile and upload it to the AddMapTile API IMapImageGenerator tileGenerator = scene.RequestModuleInterface(); if (tileGenerator == null) @@ -265,18 +271,16 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage using (Bitmap mapTile = tileGenerator.CreateMapTile()) { - if (mapTile != null) - { - UploadMapTile(scene, mapTile); - } - else - { - m_log.WarnFormat("{0} Tile image generation failed", LogHeader); - } + // XXX: The MapImageModule will return a null if the user has chosen not to create map tiles and there + // is no static map tile. + if (mapTile == null) + return; + + UploadMapTile(scene, mapTile); } } - private void ConvertAndUploadMaptile(Image tileImage, uint locX, uint locY, string regionName) + private void ConvertAndUploadMaptile(IScene scene, Image tileImage, uint locX, uint locY, string regionName) { byte[] jpgData = Utils.EmptyBytes; @@ -288,7 +292,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage if (jpgData != Utils.EmptyBytes) { string reason = string.Empty; - if (!m_MapService.AddMapTile((int)locX, (int)locY, jpgData, out reason)) + if (!m_MapService.AddMapTile((int)locX, (int)locY, jpgData, scene.RegionInfo.ScopeID, out reason)) { m_log.DebugFormat("{0} Unable to upload tile image for {1} at {2}-{3}: {4}", LogHeader, regionName, locX, locY, reason); @@ -300,4 +304,4 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage } } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MuteList/LocalMuteListServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MuteList/LocalMuteListServiceConnector.cs new file mode 100644 index 0000000..37b30aa --- /dev/null +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MuteList/LocalMuteListServiceConnector.cs @@ -0,0 +1,188 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING 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 Mono.Addins; +using Nini.Config; +using System; +using System.Collections.Generic; +using System.Reflection; +using OpenSim.Framework; +using OpenSim.Server.Base; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using OpenMetaverse; + +namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MuteList +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LocalMuteListServicesConnector")] + public class LocalMuteListServicesConnector : ISharedRegionModule, IMuteListService + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + private List m_Scenes = new List(); + protected IMuteListService m_service = null; + + private bool m_Enabled = false; + + #region ISharedRegionModule + + public Type ReplaceableInterface + { + get { return null; } + } + + public string Name + { + get { return "LocalMuteListServicesConnector"; } + } + + public void Initialise(IConfigSource source) + { + // only active for core mute lists module + IConfig moduleConfig = source.Configs["Messaging"]; + if (moduleConfig == null) + return; + + if (moduleConfig.GetString("MuteListModule", "None") != "MuteListModuleTst") + return; + + moduleConfig = source.Configs["Modules"]; + + if (moduleConfig == null) + return; + + string name = moduleConfig.GetString("MuteListService", ""); + if(name != Name) + return; + + IConfig userConfig = source.Configs["MuteListService"]; + if (userConfig == null) + { + m_log.Error("[MuteList LOCALCONNECTOR]: MuteListService missing from configuration"); + return; + } + + string serviceDll = userConfig.GetString("LocalServiceModule", + String.Empty); + + if (serviceDll == String.Empty) + { + m_log.Error("[MuteList LOCALCONNECTOR]: No LocalServiceModule named in section MuteListService"); + return; + } + + Object[] args = new Object[] { source }; + try + { + m_service = ServerUtils.LoadPlugin(serviceDll, args); + } + catch + { + m_log.Error("[MuteList LOCALCONNECTOR]: Failed to load mute service"); + return; + } + + if (m_service == null) + { + m_log.Error("[MuteList LOCALCONNECTOR]: Can't load MuteList service"); + return; + } + + m_Enabled = true; + m_log.Info("[MuteList LOCALCONNECTOR]: enabled"); + } + + public void Close() + { + } + + public void AddRegion(Scene scene) + { + if (!m_Enabled) + return; + + lock(m_Scenes) + { + m_Scenes.Add(scene); + scene.RegisterModuleInterface(this); + } + } + + public void RegionLoaded(Scene scene) + { + } + + public void PostInitialise() + { + } + + public void RemoveRegion(Scene scene) + { + if (!m_Enabled) + return; + + lock(m_Scenes) + { + if (m_Scenes.Contains(scene)) + { + m_Scenes.Remove(scene); + scene.UnregisterModuleInterface(this); + } + } + } + + #endregion ISharedRegionModule + + #region IMuteListService + public Byte[] MuteListRequest(UUID agentID, uint crc) + { + if (!m_Enabled) + return null; + return m_service.MuteListRequest(agentID, crc); + } + + public bool UpdateMute(MuteData mute) + { + if (!m_Enabled) + return false; + return m_service.UpdateMute(mute); + } + + public bool RemoveMute(UUID agentID, UUID muteID, string muteName) + { + if (!m_Enabled) + return false; + return m_service.RemoveMute(agentID, muteID, muteName); + } + + #endregion IMuteListService + } +} diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MuteList/RemoteMuteListServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MuteList/RemoteMuteListServiceConnector.cs new file mode 100644 index 0000000..a5dec64 --- /dev/null +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MuteList/RemoteMuteListServiceConnector.cs @@ -0,0 +1,143 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 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; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Services.Connectors; + +using OpenMetaverse; +using log4net; +using Mono.Addins; +using Nini.Config; + +namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MuteList +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RemoteMuteListServicesConnector")] + public class RemoteMuteListServicesConnector : ISharedRegionModule, IMuteListService + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + #region ISharedRegionModule + + private bool m_Enabled = false; + + private IMuteListService m_remoteConnector; + + public Type ReplaceableInterface + { + get { return null; } + } + + public string Name + { + get { return "RemoteMuteListServicesConnector"; } + } + + public void Initialise(IConfigSource source) + { + // only active for core mute lists module + IConfig moduleConfig = source.Configs["Messaging"]; + if (moduleConfig == null) + return; + + if (moduleConfig.GetString("MuteListModule", "None") != "MuteListModuleTst") + return; + + moduleConfig = source.Configs["Modules"]; + if (moduleConfig != null) + { + string name = moduleConfig.GetString("MuteListService", ""); + if (name == Name) + { + m_remoteConnector = new MuteListServicesConnector(source); + m_Enabled = true; + } + } + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public void AddRegion(Scene scene) + { + if (!m_Enabled) + return; + + scene.RegisterModuleInterface(this); + m_log.InfoFormat("[MUTELIST CONNECTOR]: Enabled for region {0}", scene.RegionInfo.RegionName); + } + + public void RemoveRegion(Scene scene) + { + if (!m_Enabled) + return; + } + + public void RegionLoaded(Scene scene) + { + if (!m_Enabled) + return; + } + + #endregion + + #region IMuteListService + public Byte[] MuteListRequest(UUID agentID, uint crc) + { + if (!m_Enabled) + return null; + return m_remoteConnector.MuteListRequest(agentID, crc); + } + + public bool UpdateMute(MuteData mute) + { + if (!m_Enabled) + return false; + return m_remoteConnector.UpdateMute(mute); + } + + public bool RemoveMute(UUID agentID, UUID muteID, string muteName) + { + if (!m_Enabled) + return false; + return m_remoteConnector.RemoveMute(agentID, muteID, muteName); + } + + #endregion IMuteListService + + } +} diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs deleted file mode 100644 index bda354f..0000000 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs +++ /dev/null @@ -1,147 +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 Mono.Addins; -using Nini.Config; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Server.Base; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; -using OpenSim.Services.Interfaces; - -namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Neighbour -{ - [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LocalNeighbourServicesConnector")] - public class LocalNeighbourServicesConnector : - ISharedRegionModule, INeighbourService - { - private static readonly ILog m_log = - LogManager.GetLogger( - MethodBase.GetCurrentMethod().DeclaringType); - - private List m_Scenes = new List(); - - private bool m_Enabled = false; - - public LocalNeighbourServicesConnector() - { - } - - public LocalNeighbourServicesConnector(List scenes) - { - m_Scenes = scenes; - } - - #region ISharedRegionModule - - public Type ReplaceableInterface - { - get { return null; } - } - - public string Name - { - get { return "LocalNeighbourServicesConnector"; } - } - - public void Initialise(IConfigSource source) - { - IConfig moduleConfig = source.Configs["Modules"]; - if (moduleConfig != null) - { - string name = moduleConfig.GetString("NeighbourServices", this.Name); - if (name == Name) - { - // m_Enabled rules whether this module registers as INeighbourService or not - m_Enabled = true; - m_log.Info("[NEIGHBOUR CONNECTOR]: Local neighbour connector enabled"); - } - } - } - - public void Close() - { - } - - public void AddRegion(Scene scene) - { - m_Scenes.Add(scene); - - if (!m_Enabled) - return; - - scene.RegisterModuleInterface(this); - } - - public void RegionLoaded(Scene scene) - { - m_log.Info("[NEIGHBOUR CONNECTOR]: Local neighbour connector enabled for region " + scene.RegionInfo.RegionName); - } - - public void PostInitialise() - { - } - - public void RemoveRegion(Scene scene) - { - // Always remove - if (m_Scenes.Contains(scene)) - m_Scenes.Remove(scene); - } - - #endregion ISharedRegionModule - - #region INeighbourService - - public OpenSim.Services.Interfaces.GridRegion HelloNeighbour(ulong regionHandle, RegionInfo thisRegion) - { - uint x, y; - Util.RegionHandleToRegionLoc(regionHandle, out x, out y); - - foreach (Scene s in m_Scenes) - { - if (s.RegionInfo.RegionHandle == regionHandle) - { - m_log.DebugFormat("[LOCAL NEIGHBOUR SERVICE CONNECTOR]: HelloNeighbour from region {0} to neighbour {1} at {2}-{3}", - thisRegion.RegionName, s.Name, x, y ); - - //m_log.Debug("[NEIGHBOUR CONNECTOR]: Found region to SendHelloNeighbour"); - return s.IncomingHelloNeighbour(thisRegion); - } - } - //m_log.DebugFormat("[NEIGHBOUR CONNECTOR]: region handle {0} not found", regionHandle); - return null; - } - - #endregion INeighbourService - } -} diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/NeighbourServiceOutConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/NeighbourServiceOutConnector.cs new file mode 100644 index 0000000..60addec --- /dev/null +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/NeighbourServiceOutConnector.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 log4net; +using Mono.Addins; +using System; +using System.Reflection; +using System.Collections.Generic; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Services.Connectors; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; + + +namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Neighbour +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "NeighbourServicesOutConnector")] + public class NeighbourServicesOutConnector : + NeighbourServicesConnector, ISharedRegionModule, INeighbourService + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + private List m_Scenes = new List(); + private bool m_Enabled = false; + + public Type ReplaceableInterface + { + get { return null; } + } + + public string Name + { + get { return "NeighbourServicesOutConnector"; } + } + + public void Initialise(IConfigSource source) + { + IConfig moduleConfig = source.Configs["Modules"]; + if (moduleConfig != null) + { + string name = moduleConfig.GetString("NeighbourServices"); + if (name == Name) + { + m_Enabled = true; + m_log.Info("[NEIGHBOUR CONNECTOR]: Neighbour out connector enabled"); + } + } + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public void AddRegion(Scene scene) + { + if (!m_Enabled) + return; + + m_Scenes.Add(scene); + scene.RegisterModuleInterface(this); + } + + public void RemoveRegion(Scene scene) + { + // Always remove + if (m_Scenes.Contains(scene)) + m_Scenes.Remove(scene); + } + + public void RegionLoaded(Scene scene) + { + if (!m_Enabled) + return; + + m_GridService = scene.GridService; + m_log.InfoFormat("[NEIGHBOUR CONNECTOR]: Enabled out neighbours for region {0}", scene.RegionInfo.RegionName); + + } + + #region INeighbourService + + public override GridRegion HelloNeighbour(ulong regionHandle, RegionInfo thisRegion) + { + if (!m_Enabled) + return null; + + foreach (Scene s in m_Scenes) + { + if (s.RegionInfo.RegionHandle == regionHandle) + { +// uint x, y; +// Util.RegionHandleToRegionLoc(regionHandle, out x, out y); +// m_log.DebugFormat("[NEIGHBOUR SERVICE OUT CONNECTOR]: HelloNeighbour from region {0} to neighbour {1} at {2}-{3}", +// thisRegion.RegionName, s.Name, x, y ); + return s.IncomingHelloNeighbour(thisRegion); + } + } + + return base.HelloNeighbour(regionHandle, thisRegion); + } + + #endregion INeighbourService + } +} diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/RemoteNeighourServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/RemoteNeighourServiceConnector.cs deleted file mode 100644 index e6772f3..0000000 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/RemoteNeighourServiceConnector.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 log4net; -using Mono.Addins; -using System; -using System.Collections.Generic; -using System.Reflection; -using Nini.Config; -using OpenSim.Framework; -using OpenSim.Services.Connectors; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; -using OpenSim.Services.Interfaces; -using OpenSim.Server.Base; - -namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Neighbour -{ - [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RemoteNeighbourServicesConnector")] - public class RemoteNeighbourServicesConnector : - NeighbourServicesConnector, ISharedRegionModule, INeighbourService - { - private static readonly ILog m_log = - LogManager.GetLogger( - MethodBase.GetCurrentMethod().DeclaringType); - - private bool m_Enabled = false; - private LocalNeighbourServicesConnector m_LocalService; - //private string serviceDll; - //private List m_Scenes = new List(); - - public Type ReplaceableInterface - { - get { return null; } - } - - public string Name - { - get { return "RemoteNeighbourServicesConnector"; } - } - - public void Initialise(IConfigSource source) - { - IConfig moduleConfig = source.Configs["Modules"]; - if (moduleConfig != null) - { - string name = moduleConfig.GetString("NeighbourServices"); - if (name == Name) - { - m_LocalService = new LocalNeighbourServicesConnector(); - - //IConfig neighbourConfig = source.Configs["NeighbourService"]; - //if (neighbourConfig == null) - //{ - // m_log.Error("[NEIGHBOUR CONNECTOR]: NeighbourService missing from OpenSim.ini"); - // return; - //} - //serviceDll = neighbourConfig.GetString("LocalServiceModule", String.Empty); - //if (serviceDll == String.Empty) - //{ - // m_log.Error("[NEIGHBOUR CONNECTOR]: No LocalServiceModule named in section NeighbourService"); - // return; - //} - - m_Enabled = true; - - m_log.Info("[NEIGHBOUR CONNECTOR]: Remote Neighbour connector enabled"); - } - } - } - - public void PostInitialise() - { - //if (m_Enabled) - //{ - // Object[] args = new Object[] { m_Scenes }; - // m_LocalService = - // ServerUtils.LoadPlugin(serviceDll, - // args); - - // if (m_LocalService == null) - // { - // m_log.Error("[NEIGHBOUR CONNECTOR]: Can't load neighbour service"); - // Unregister(); - // return; - // } - //} - } - - public void Close() - { - } - - public void AddRegion(Scene scene) - { - if (!m_Enabled) - return; - - m_LocalService.AddRegion(scene); - scene.RegisterModuleInterface(this); - } - - public void RemoveRegion(Scene scene) - { - if (m_Enabled) - m_LocalService.RemoveRegion(scene); - } - - public void RegionLoaded(Scene scene) - { - if (!m_Enabled) - return; - - m_GridService = scene.GridService; - - m_log.InfoFormat("[NEIGHBOUR CONNECTOR]: Enabled remote neighbours for region {0}", scene.RegionInfo.RegionName); - - } - - #region INeighbourService - - public override GridRegion HelloNeighbour(ulong regionHandle, RegionInfo thisRegion) - { - GridRegion region = m_LocalService.HelloNeighbour(regionHandle, thisRegion); - if (region != null) - return region; - - return base.HelloNeighbour(regionHandle, thisRegion); - } - - #endregion INeighbourService - } -} diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs index 50c252c..a7e62eb 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs @@ -35,7 +35,7 @@ using OpenSim.Services.Interfaces; namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence { - public class PresenceDetector + public class PresenceDetector { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -68,6 +68,22 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence public void OnMakeRootAgent(ScenePresence sp) { + if (sp.IsNPC) + return; + + if(sp.gotCrossUpdate) + { + Util.FireAndForget(delegate + { + DoOnMakeRootAgent(sp); + }, null, "PresenceDetector_MakeRoot"); + } + else + DoOnMakeRootAgent(sp); + } + + public void DoOnMakeRootAgent(ScenePresence sp) + { // m_log.DebugFormat("[PRESENCE DETECTOR]: Detected root presence {0} in {1}", sp.UUID, sp.Scene.RegionInfo.RegionName); if (sp.PresenceType != PresenceType.Npc) m_PresenceService.ReportAgent(sp.ControllingClient.SessionId, sp.Scene.RegionInfo.RegionID); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs index 69bac82..7838d12 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs @@ -72,7 +72,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.Tests public void TestPresenceV0_1() { SetUp(); - + // Let's stick in a test presence /* PresenceData p = new PresenceData(); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs index cc8203e..57aba05 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs @@ -185,7 +185,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation * Agent-related communications */ - public bool CreateAgent(GridRegion source, GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, out string reason) + public bool CreateAgent(GridRegion source, GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, EntityTransferContext ctx, out string reason) { if (destination == null) { @@ -204,7 +204,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation return false; } - public bool UpdateAgent(GridRegion destination, AgentData cAgentData) + public bool UpdateAgent(GridRegion destination, AgentData cAgentData, EntityTransferContext ctx) { if (destination == null) return false; @@ -219,7 +219,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation } // m_log.DebugFormat( -// "[LOCAL COMMS]: Did not find region {0} {1} for ChildAgentUpdate", +// "[LOCAL COMMS]: Did not find region {0} {1} for ChildAgentUpdate", // destination.RegionName, destination.RegionID); return false; @@ -265,9 +265,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation reason = "Destination is a variable-sized region, and source is an old simulator. Consider upgrading."; m_log.DebugFormat("[LOCAL SIMULATION CONNECTOR]: Request to access this variable-sized region from older simulator was denied"); return false; - + } + return m_scenes[destination.RegionID].QueryAccess(agentID, agentHomeURI, viaTeleport, position, features, out reason); } @@ -305,7 +306,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation m_scenes[destination.RegionID].CloseAgent(id, false, auth_token); return true; } - //m_log.Debug("[LOCAL COMMS]: region not found in SendCloseAgent"); return false; } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs index 1e095ca..b402d2a 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs @@ -137,7 +137,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation } protected virtual void InitOnce(Scene scene) - { + { m_aScene = scene; //m_regionClient = new RegionToRegionClient(m_aScene, m_hyperlinkService); } @@ -160,7 +160,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation * Agent-related communications */ - public bool CreateAgent(GridRegion source, GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, out string reason) + public bool CreateAgent(GridRegion source, GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, EntityTransferContext ctx, out string reason) { if (destination == null) { @@ -170,27 +170,27 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation } // Try local first - if (m_localBackend.CreateAgent(source, destination, aCircuit, teleportFlags, out reason)) + if (m_localBackend.CreateAgent(source, destination, aCircuit, teleportFlags, ctx, out reason)) return true; // else do the remote thing if (!m_localBackend.IsLocalRegion(destination.RegionID)) { - return m_remoteConnector.CreateAgent(source, destination, aCircuit, teleportFlags, out reason); + return m_remoteConnector.CreateAgent(source, destination, aCircuit, teleportFlags, ctx, out reason); } return false; } - public bool UpdateAgent(GridRegion destination, AgentData cAgentData) + public bool UpdateAgent(GridRegion destination, AgentData cAgentData, EntityTransferContext ctx) { if (destination == null) return false; // Try local first if (m_localBackend.IsLocalRegion(destination.RegionID)) - return m_localBackend.UpdateAgent(destination, cAgentData); + return m_localBackend.UpdateAgent(destination, cAgentData, ctx); - return m_remoteConnector.UpdateAgent(destination, cAgentData); + return m_remoteConnector.UpdateAgent(destination, cAgentData, ctx); } public bool UpdateAgent(GridRegion destination, AgentPosition cAgentData) @@ -236,7 +236,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation return false; } - public bool CloseAgent(GridRegion destination, UUID id, string auth_token) { if (destination == null) @@ -249,7 +248,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation // else do the remote thing if (!m_localBackend.IsLocalRegion(destination.RegionID)) return m_remoteConnector.CloseAgent(destination, id, auth_token); - + return false; } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs index 6d4ac39..77fd70b 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs @@ -59,7 +59,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts #region ISharedRegionModule - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -129,6 +129,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts // FIXME: Why do we bother setting this module and caching up if we just end up registering the inner // user account service?! scene.RegisterModuleInterface(UserAccountService); + scene.RegisterModuleInterface(m_Cache); } public void RemoveRegion(Scene scene) @@ -152,7 +153,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts public UserAccount GetUserAccount(UUID scopeID, UUID userID) { bool inCache = false; - UserAccount account = m_Cache.Get(userID, out inCache); + UserAccount account; + account = m_Cache.Get(userID, out inCache); if (inCache) return account; @@ -165,7 +167,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts public UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName) { bool inCache = false; - UserAccount account = m_Cache.Get(firstName + " " + lastName, out inCache); + UserAccount account; + account = m_Cache.Get(firstName + " " + lastName, out inCache); if (inCache) return account; @@ -181,6 +184,50 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts return UserAccountService.GetUserAccount(scopeID, Email); } + public List GetUserAccounts(UUID scopeID, List IDs) + { + List ret = new List(); + List missing = new List(); + + // still another cache.. + bool inCache = false; + UUID uuid = UUID.Zero; + UserAccount account; + foreach(string id in IDs) + { + if(UUID.TryParse(id, out uuid)) + { + account = m_Cache.Get(uuid, out inCache); + if (inCache) + ret.Add(account); + else + missing.Add(id); + } + } + + if(missing.Count == 0) + return ret; + + List ext = UserAccountService.GetUserAccounts(scopeID, missing); + if(ext != null && ext.Count > 0) + { + foreach(UserAccount acc in ext) + { + if(acc != null) + { + ret.Add(acc); + m_Cache.Cache(acc.PrincipalID, acc); + } + } + } + return ret; + } + + public List GetUserAccountsWhere(UUID scopeID, string query) + { + return null; + } + public List GetUserAccounts(UUID scopeID, string query) { return UserAccountService.GetUserAccounts(scopeID, query); @@ -203,4 +250,4 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts #endregion } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs index 5aa87d3..b510d0a 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs @@ -26,6 +26,8 @@ */ using System; +using System.Collections; +using System.Collections.Generic; using Nini.Config; using log4net; using Mono.Addins; @@ -34,6 +36,7 @@ using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Services.Interfaces; using OpenSim.Services.Connectors; +using OpenSim.Framework; using OpenMetaverse; @@ -50,7 +53,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts private bool m_Enabled = false; private UserAccountCache m_Cache; - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -103,6 +106,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts return; scene.RegisterModuleInterface(this); + scene.RegisterModuleInterface(m_Cache); + + scene.EventManager.OnNewClient += OnNewClient; } public void RemoveRegion(Scene scene) @@ -117,12 +123,21 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts return; } + // When a user actually enters the sim, clear them from + // cache so the sim will have the current values for + // flags, title, etc. And country, don't forget country! + private void OnNewClient(IClientAPI client) + { + m_Cache.Remove(client.Name); + } + #region Overwritten methods from IUserAccountService public override UserAccount GetUserAccount(UUID scopeID, UUID userID) { bool inCache = false; - UserAccount account = m_Cache.Get(userID, out inCache); + UserAccount account; + account = m_Cache.Get(userID, out inCache); if (inCache) return account; @@ -135,7 +150,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts public override UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName) { bool inCache = false; - UserAccount account = m_Cache.Get(firstName + " " + lastName, out inCache); + UserAccount account; + account = m_Cache.Get(firstName + " " + lastName, out inCache); if (inCache) return account; @@ -146,6 +162,45 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts return account; } + public override List GetUserAccounts(UUID scopeID, List IDs) + { + List accs = new List(); + List missing = new List(); + + UUID uuid = UUID.Zero; + UserAccount account; + bool inCache = false; + + foreach(string id in IDs) + { + if(UUID.TryParse(id, out uuid)) + { + account = m_Cache.Get(uuid, out inCache); + if (inCache) + accs.Add(account); + else + missing.Add(id); + } + } + + if(missing.Count > 0) + { + List ext = base.GetUserAccounts(scopeID, missing); + if(ext != null && ext.Count >0 ) + { + foreach(UserAccount acc in ext) + { + if(acc != null) + { + accs.Add(acc); + m_Cache.Cache(acc.PrincipalID, acc); + } + } + } + } + return accs; + } + public override bool StoreUserAccount(UserAccount data) { // This remote connector refuses to serve this method diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs index ed52e48..f3572a2 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs @@ -34,68 +34,119 @@ using log4net; namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts { - public class UserAccountCache + public class UserAccountCache : IUserAccountCacheModule { - private const double CACHE_EXPIRATION_SECONDS = 120000.0; // 33 hours! + private const double CACHE_ALIEN_EXPIRATION_SECONDS = 172800; // 48 hours + private const double CACHE_EXPIRATION_SECONDS = 3600.0; // 1 hour! + private const double CACHE_NULL_EXPIRATION_SECONDS = 600; // 10minutes // private static readonly ILog m_log = // LogManager.GetLogger( // MethodBase.GetCurrentMethod().DeclaringType); - + private ExpiringCache m_UUIDCache; private ExpiringCache m_NameCache; + private object accessLock = new object(); public UserAccountCache() { m_UUIDCache = new ExpiringCache(); - m_NameCache = new ExpiringCache(); + m_NameCache = new ExpiringCache(); } public void Cache(UUID userID, UserAccount account) { // Cache even null accounts - m_UUIDCache.AddOrUpdate(userID, account, CACHE_EXPIRATION_SECONDS); - if (account != null) - m_NameCache.AddOrUpdate(account.Name, account.PrincipalID, CACHE_EXPIRATION_SECONDS); - + lock(accessLock) + { + if (account == null) + m_UUIDCache.AddOrUpdate(userID, null, CACHE_NULL_EXPIRATION_SECONDS); + else if(account.LocalToGrid) + { + m_UUIDCache.AddOrUpdate(userID, account, CACHE_EXPIRATION_SECONDS); + m_NameCache.AddOrUpdate(account.Name, account.PrincipalID, CACHE_EXPIRATION_SECONDS); + } + else + { + m_UUIDCache.AddOrUpdate(userID, account, CACHE_ALIEN_EXPIRATION_SECONDS); + m_NameCache.AddOrUpdate(account.Name, account.PrincipalID, CACHE_ALIEN_EXPIRATION_SECONDS); + } //m_log.DebugFormat("[USER CACHE]: cached user {0}", userID); + } } - public void Invalidate(UUID userID) - { - m_UUIDCache.Remove(userID); - } public UserAccount Get(UUID userID, out bool inCache) { UserAccount account = null; inCache = false; - if (m_UUIDCache.TryGetValue(userID, out account)) + lock(accessLock) { - //m_log.DebugFormat("[USER CACHE]: Account {0} {1} found in cache", account.FirstName, account.LastName); - inCache = true; - return account; + if (m_UUIDCache.TryGetValue(userID, out account)) + { + //m_log.DebugFormat("[USER CACHE]: Account {0} {1} found in cache", account.FirstName, account.LastName); + inCache = true; + return account; + } } - return null; } public UserAccount Get(string name, out bool inCache) { inCache = false; - if (!m_NameCache.Contains(name)) - return null; + lock(accessLock) + { + if (!m_NameCache.Contains(name)) + return null; - UserAccount account = null; - UUID uuid = UUID.Zero; - if (m_NameCache.TryGetValue(name, out uuid)) - if (m_UUIDCache.TryGetValue(uuid, out account)) + UserAccount account = null; + UUID uuid = UUID.Zero; + if (m_NameCache.TryGetValue(name, out uuid)) { - inCache = true; - return account; + if (m_UUIDCache.TryGetValue(uuid, out account)) + { + inCache = true; + return account; + } } - + } return null; } + + public void Invalidate(UUID userID) + { + m_UUIDCache.Remove(userID); + } + + public void Remove(UUID id) + { + lock(accessLock) + { + if (!m_UUIDCache.Contains(id)) + return; + + UserAccount account = null; + if (m_UUIDCache.TryGetValue(id, out account) && account != null) + m_NameCache.Remove(account.Name); + m_UUIDCache.Remove(id); + } + } + + public void Remove(string name) + { + lock(accessLock) + { + if (!m_NameCache.Contains(name)) + return; + + UUID uuid = UUID.Zero; + if (m_NameCache.TryGetValue(name, out uuid)) + { + m_NameCache.Remove(name); + m_UUIDCache.Remove(uuid); + } + } + } } } diff --git a/OpenSim/Region/CoreModules/World/Access/AccessModule.cs b/OpenSim/Region/CoreModules/World/Access/AccessModule.cs index f567cab..081439a 100644 --- a/OpenSim/Region/CoreModules/World/Access/AccessModule.cs +++ b/OpenSim/Region/CoreModules/World/Access/AccessModule.cs @@ -44,7 +44,7 @@ namespace OpenSim.Region.CoreModules.World public class AccessModule : ISharedRegionModule { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + private List m_SceneList = new List(); public void Initialise(IConfigSource config) diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs index 9c6706f..41515c0 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs @@ -40,6 +40,7 @@ using OpenSim.Framework.Monitoring; using OpenSim.Framework.Serialization; using OpenSim.Framework.Serialization.External; using OpenSim.Region.CoreModules.World.Terrain; +using OpenSim.Region.CoreModules.World.Land; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes.Serialization; @@ -76,14 +77,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver SceneObjects = new List(); } } - + /// /// The maximum major version of OAR that we can read. Minor versions shouldn't need a max number since version /// bumps here should be compatible. /// public static int MAX_MAJOR_VERSION = 1; - + /// /// Has the control file been loaded for this archive? /// @@ -126,12 +127,29 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// protected float m_rotation = 0f; + /// + /// original oar region size. not using Constants.RegionSize + /// + protected Vector3 m_incomingRegionSize = new Vector3(256f, 256f, float.MaxValue); + + /// + /// Center around which to apply the rotation relative to the original oar position + /// + protected Vector3 m_rotationCenter = new Vector3(128f, 128f, 0f); + + /// + /// Corner 1 of a bounding cuboid which specifies which objects we load from the oar + /// + protected Vector3 m_boundingOrigin = Vector3.Zero; + /// - /// Center around which to apply the rotation relative to the origional oar position + /// Size of a bounding cuboid which specifies which objects we load from the oar /// - protected Vector3 m_rotationCenter = new Vector3(Constants.RegionSize / 2f, Constants.RegionSize / 2f, 0f); + protected Vector3 m_boundingSize = new Vector3(Constants.MaximumRegionSize, Constants.MaximumRegionSize, float.MaxValue); protected bool m_noObjects = false; + protected bool m_boundingBox = false; + protected bool m_debug = false; /// /// Used to cache lookups for valid uuids. @@ -160,10 +178,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver private IAssetService m_assetService = null; - private UUID m_defaultUser; - public ArchiveReadRequest(Scene scene, string loadPath, Guid requestId, Dictionaryoptions) + public ArchiveReadRequest(Scene scene, string loadPath, Guid requestId, Dictionary options) { m_rootScene = scene; @@ -172,7 +189,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver m_defaultUser = (UUID)options["default-user"]; m_log.InfoFormat("Using User {0} as default user", m_defaultUser.ToString()); } - else + else { m_defaultUser = scene.RegionInfo.EstateSettings.EstateOwner; } @@ -189,8 +206,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver + "If you've manually installed Mono, have you appropriately updated zlib1g as well?"); m_log.Error(e); } - + m_errorMessage = String.Empty; + m_merge = options.ContainsKey("merge"); m_forceTerrain = options.ContainsKey("force-terrain"); m_forceParcels = options.ContainsKey("force-parcels"); @@ -199,10 +217,45 @@ namespace OpenSim.Region.CoreModules.World.Archiver m_requestId = requestId; m_displacement = options.ContainsKey("displacement") ? (Vector3)options["displacement"] : Vector3.Zero; m_rotation = options.ContainsKey("rotation") ? (float)options["rotation"] : 0f; - m_rotationCenter = options.ContainsKey("rotation-center") ? (Vector3)options["rotation-center"] - : new Vector3(scene.RegionInfo.RegionSizeX / 2f, scene.RegionInfo.RegionSizeY / 2f, 0f); - // Zero can never be a valid user or group id + m_boundingOrigin = Vector3.Zero; + m_boundingSize = new Vector3(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY, float.MaxValue); + + if (options.ContainsKey("bounding-origin")) + { + Vector3 boOption = (Vector3)options["bounding-origin"]; + if (boOption != m_boundingOrigin) + { + m_boundingOrigin = boOption; + } + m_boundingBox = true; + } + + if (options.ContainsKey("bounding-size")) + { + Vector3 bsOption = (Vector3)options["bounding-size"]; + bool clip = false; + if (bsOption.X <= 0 || bsOption.X > m_boundingSize.X) + { + bsOption.X = m_boundingSize.X; + clip = true; + } + if (bsOption.Y <= 0 || bsOption.Y > m_boundingSize.Y) + { + bsOption.Y = m_boundingSize.Y; + clip = true; + } + if (bsOption != m_boundingSize) + { + m_boundingSize = bsOption; + m_boundingBox = true; + } + if (clip) m_log.InfoFormat("[ARCHIVER]: The bounding cube specified is larger than the destination region! Clipping to {0}.", m_boundingSize.ToString()); + } + + m_debug = options.ContainsKey("debug"); + + // Zero can never be a valid user id (or group) m_validUserUuids[UUID.Zero] = false; m_validGroupUuids[UUID.Zero] = false; @@ -210,7 +263,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver m_assetService = m_rootScene.AssetService; } - public ArchiveReadRequest(Scene scene, Stream loadStream, Guid requestId, Dictionaryoptions) + public ArchiveReadRequest(Scene scene, Stream loadStream, Guid requestId, Dictionary options) { m_rootScene = scene; m_loadPath = null; @@ -220,7 +273,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver m_requestId = requestId; m_defaultUser = scene.RegionInfo.EstateSettings.EstateOwner; - + // Zero can never be a valid user id m_validUserUuids[UUID.Zero] = false; @@ -233,6 +286,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// public void DearchiveRegion() { + DearchiveRegion(true); + } + + public void DearchiveRegion(bool shouldStartScripts) + { int successfulAssetRestores = 0; int failedAssetRestores = 0; @@ -255,7 +313,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver { //m_log.DebugFormat( // "[ARCHIVER]: Successfully read {0} ({1} bytes)", filePath, data.Length); - + if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType) continue; @@ -301,11 +359,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver else if (!m_merge && filePath.StartsWith(ArchiveConstants.SETTINGS_PATH)) { LoadRegionSettings(scene, filePath, data, dearchivedScenes); - } + } else if (filePath.StartsWith(ArchiveConstants.LANDDATA_PATH) && (!m_merge || m_forceParcels)) { sceneContext.SerialisedParcels.Add(Encoding.UTF8.GetString(data)); - } + } else if (filePath == ArchiveConstants.CONTROL_FILE_PATH) { // Ignore, because we already read the control file @@ -353,7 +411,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver { LoadParcels(sceneContext.Scene, sceneContext.SerialisedParcels); LoadObjects(sceneContext.Scene, sceneContext.SerialisedSceneObjects, sceneContext.SceneObjects); - + // Inform any interested parties that the region has changed. We waited until now so that all // of the region's objects will be loaded when we send this notification. IEstateModule estateModule = sceneContext.Scene.RequestModuleInterface(); @@ -372,22 +430,25 @@ namespace OpenSim.Region.CoreModules.World.Archiver // Start the scripts. We delayed this because we want the OAR to finish loading ASAP, so // that users can enter the scene. If we allow the scripts to start in the loop above // then they significantly increase the time until the OAR finishes loading. - WorkManager.RunInThread(o => + if (shouldStartScripts) { - Thread.Sleep(15000); - m_log.Info("[ARCHIVER]: Starting scripts in scene objects"); - - foreach (DearchiveContext sceneContext in sceneContexts.Values) + WorkManager.RunInThread(o => { - foreach (SceneObjectGroup sceneObject in sceneContext.SceneObjects) + Thread.Sleep(15000); + m_log.Info("[ARCHIVER]: Starting scripts in scene objects"); + + foreach (DearchiveContext sceneContext in sceneContexts.Values) { - sceneObject.CreateScriptInstances(0, false, sceneContext.Scene.DefaultScriptEngine, 0); // StateSource.RegionStart - sceneObject.ResumeScripts(); - } + foreach (SceneObjectGroup sceneObject in sceneContext.SceneObjects) + { + sceneObject.CreateScriptInstances(0, false, sceneContext.Scene.DefaultScriptEngine, 0); // StateSource.RegionStart + sceneObject.ResumeScripts(); + } - sceneContext.SceneObjects.Clear(); - } - }, null, string.Format("ReadArchiveStartScripts (request {0})", m_requestId)); + sceneContext.SceneObjects.Clear(); + } + }, null, string.Format("ReadArchiveStartScripts (request {0})", m_requestId)); + } m_log.InfoFormat("[ARCHIVER]: Successfully loaded archive"); @@ -418,7 +479,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver { if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType) continue; - + if (filePath == ArchiveConstants.CONTROL_FILE_PATH) { LoadControlFile(filePath, data, dearchivedScenes); @@ -435,7 +496,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver // If the control file wasn't the first file then reset the read pointer if (!firstFile) { - m_log.Warn("Control file wasn't the first file in the archive"); + m_log.Warn("[ARCHIVER]: Control file wasn't the first file in the archive"); if (m_loadStream.CanSeek) { m_loadStream.Seek(0, SeekOrigin.Begin); @@ -452,7 +513,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver else { // There isn't currently a scenario where this happens, but it's best to add a check just in case - throw new Exception("Error reading archive: control file wasn't the first file, and the input stream doesn't allow seeking"); + throw new Exception("[ARCHIVER]: Error reading archive: control file wasn't the first file, and the input stream doesn't allow seeking"); } } @@ -462,9 +523,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver firstFile = false; } - throw new Exception("Control file not found"); + throw new Exception("[ARCHIVER]: Control file not found"); } - + /// /// Load serialized scene objects. /// @@ -473,12 +534,16 @@ namespace OpenSim.Region.CoreModules.World.Archiver // Reload serialized prims m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count); - OpenMetaverse.Quaternion rot = OpenMetaverse.Quaternion.CreateFromAxisAngle(0, 0, 1, m_rotation); + // Convert rotation to radians + double rotation = Math.PI * m_rotation / 180f; + + OpenMetaverse.Quaternion rot = OpenMetaverse.Quaternion.CreateFromAxisAngle(0, 0, 1, (float)rotation); UUID oldTelehubUUID = scene.RegionInfo.RegionSettings.TelehubObject; IRegionSerialiserModule serialiser = scene.RequestModuleInterface(); int sceneObjectsLoadedCount = 0; + Vector3 boundingExtent = new Vector3(m_boundingOrigin.X + m_boundingSize.X, m_boundingOrigin.Y + m_boundingSize.Y, m_boundingOrigin.Z + m_boundingSize.Z); foreach (string serialisedSceneObject in serialisedSceneObjects) { @@ -488,7 +553,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver // Really large xml files (multi megabyte) appear to cause // memory problems // when loading the xml. But don't enable this check yet - + if (serialisedSceneObject.Length > 5000000) { m_log.Error("[ARCHIVER]: Ignoring xml since size > 5000000);"); @@ -498,31 +563,52 @@ namespace OpenSim.Region.CoreModules.World.Archiver SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject); + Vector3 pos = sceneObject.AbsolutePosition; + if (m_debug) + m_log.DebugFormat("[ARCHIVER]: Loading object from OAR with original scene position {0}.", pos.ToString()); + // Happily this does not do much to the object since it hasn't been added to the scene yet if (!sceneObject.IsAttachment) { - if (m_displacement != Vector3.Zero || m_rotation != 0f) + if (m_rotation != 0f) { - Vector3 pos = sceneObject.AbsolutePosition; - if (m_rotation != 0f) - { - // Rotate the object - sceneObject.RootPart.RotationOffset = rot * sceneObject.GroupRotation; - // Get object position relative to rotation axis - Vector3 offset = pos - m_rotationCenter; - // Rotate the object position - offset *= rot; - // Restore the object position back to relative to the region - pos = m_rotationCenter + offset; - } - if (m_displacement != Vector3.Zero) + //fix the rotation center to the middle of the incoming region now as it's otherwise hopelessly confusing on varRegions + //as it only works with objects and terrain (using old Merge method) and not parcels + m_rotationCenter.X = m_incomingRegionSize.X / 2; + m_rotationCenter.Y = m_incomingRegionSize.Y / 2; + + // Rotate the object + sceneObject.RootPart.RotationOffset = rot * sceneObject.GroupRotation; + // Get object position relative to rotation axis + Vector3 offset = pos - m_rotationCenter; + // Rotate the object position + offset *= rot; + // Restore the object position back to relative to the region + pos = m_rotationCenter + offset; + if (m_debug) m_log.DebugFormat("[ARCHIVER]: After rotation, object from OAR is at scene position {0}.", pos.ToString()); + } + if (m_boundingBox) + { + if (pos.X < m_boundingOrigin.X || pos.X >= boundingExtent.X + || pos.Y < m_boundingOrigin.Y || pos.Y >= boundingExtent.Y + || pos.Z < m_boundingOrigin.Z || pos.Z >= boundingExtent.Z) { - pos += m_displacement; + if (m_debug) m_log.DebugFormat("[ARCHIVER]: Skipping object from OAR in scene because it's position {0} is outside of bounding cube.", pos.ToString()); + continue; } - sceneObject.AbsolutePosition = pos; + //adjust object position to be relative to <0,0> so we can apply the displacement + pos.X -= m_boundingOrigin.X; + pos.Y -= m_boundingOrigin.Y; + } + if (m_displacement != Vector3.Zero) + { + pos += m_displacement; + if (m_debug) m_log.DebugFormat("[ARCHIVER]: After displacement, object from OAR is at scene position {0}.", pos.ToString()); } + sceneObject.AbsolutePosition = pos; } - + if (m_debug) + m_log.DebugFormat("[ARCHIVER]: Placing object from OAR in scene at position {0}. ", pos.ToString()); bool isTelehub = (sceneObject.UUID == oldTelehubUUID) && (oldTelehubUUID != UUID.Zero); @@ -554,11 +640,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver int ignoredObjects = serialisedSceneObjects.Count - sceneObjectsLoadedCount; if (ignoredObjects > 0) - m_log.WarnFormat("[ARCHIVER]: Ignored {0} scene objects that already existed in the scene", ignoredObjects); + m_log.WarnFormat("[ARCHIVER]: Ignored {0} scene objects that already existed in the scene or were out of bounds", ignoredObjects); if (oldTelehubUUID != UUID.Zero) { - m_log.WarnFormat("Telehub object not found: {0}", oldTelehubUUID); + m_log.WarnFormat("[ARCHIVER]: Telehub object not found: {0}", oldTelehubUUID); scene.RegionInfo.RegionSettings.TelehubObject = UUID.Zero; scene.RegionInfo.RegionSettings.ClearSpawnPoints(); } @@ -600,6 +686,16 @@ namespace OpenSim.Region.CoreModules.World.Archiver // being no copy/no mod for everyone lock (part.TaskInventory) { +/* avination code disabled for opensim + // And zap any troublesome sit target information + part.SitTargetOrientation = new Quaternion(0, 0, 0, 1); + part.SitTargetPosition = new Vector3(0, 0, 0); +*/ + // Fix ownership/creator of inventory items + // Not doing so results in inventory items + // being no copy/no mod for everyone + part.TaskInventory.LockItemsForRead(true); + TaskInventoryDictionary inv = part.TaskInventory; foreach (KeyValuePair kvp in inv) { @@ -620,11 +716,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver if (!ResolveGroupUuid(kvp.Value.GroupID)) kvp.Value.GroupID = UUID.Zero; } + part.TaskInventory.LockItemsForRead(false); + } } } - /// /// Load serialized parcels. /// @@ -635,17 +732,88 @@ namespace OpenSim.Region.CoreModules.World.Archiver // Reload serialized parcels m_log.InfoFormat("[ARCHIVER]: Loading {0} parcels. Please wait.", serialisedParcels.Count); List landData = new List(); + ILandObject landObject = scene.RequestModuleInterface(); + List parcels; + Vector3 parcelDisp = new Vector3(m_displacement.X, m_displacement.Y, 0f); + Vector2 displacement = new Vector2(m_displacement.X, m_displacement.Y); + Vector2 boundingOrigin = new Vector2(m_boundingOrigin.X, m_boundingOrigin.Y); + Vector2 boundingSize = new Vector2(m_boundingSize.X, m_boundingSize.Y); + Vector2 regionSize = new Vector2(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY); + + // Gather any existing parcels before we add any more. Later as we add parcels we can check if the new parcel + // data overlays any of the old data, and we can modify and remove (if empty) the old parcel so that there's no conflict + parcels = scene.LandChannel.AllParcels(); + foreach (string serialisedParcel in serialisedParcels) { LandData parcel = LandDataSerializer.Deserialize(serialisedParcel); + bool overrideRegionSize = true; //use the src land parcel data size not the dst region size + bool isEmptyNow; + Vector3 AABBMin; + Vector3 AABBMax; + + // create a new LandObject that we can use to manipulate the incoming source parcel data + // this is ok, but just beware that some of the LandObject functions (that we haven't used here) still + // assume we're always using the destination region size + LandData ld = new LandData(); + landObject = new LandObject(ld, scene); + landObject.LandData = parcel; + + bool[,] srcLandBitmap = landObject.ConvertBytesToLandBitmap(overrideRegionSize); + if (landObject.IsLandBitmapEmpty(srcLandBitmap)) + { + m_log.InfoFormat("[ARCHIVER]: Skipping source parcel {0} with GlobalID: {1} LocalID: {2} that has no claimed land.", + parcel.Name, parcel.GlobalID, parcel.LocalID); + continue; + } + //m_log.DebugFormat("[ARCHIVER]: Showing claimed land for source parcel: {0} with GlobalID: {1} LocalID: {2}.", + // parcel.Name, parcel.GlobalID, parcel.LocalID); + //landObject.DebugLandBitmap(srcLandBitmap); + + bool[,] dstLandBitmap = landObject.RemapLandBitmap(srcLandBitmap, displacement, m_rotation, boundingOrigin, boundingSize, regionSize, out isEmptyNow, out AABBMin, out AABBMax); + if (isEmptyNow) + { + m_log.WarnFormat("[ARCHIVER]: Not adding destination parcel {0} with GlobalID: {1} LocalID: {2} because, after applying rotation, bounding and displacement, it has no claimed land.", + parcel.Name, parcel.GlobalID, parcel.LocalID); + continue; + } + //m_log.DebugFormat("[ARCHIVER]: Showing claimed land for destination parcel: {0} with GlobalID: {1} LocalID: {2} after applying rotation, bounding and displacement.", + // parcel.Name, parcel.GlobalID, parcel.LocalID); + //landObject.DebugLandBitmap(dstLandBitmap); + + landObject.LandBitmap = dstLandBitmap; + parcel.Bitmap = landObject.ConvertLandBitmapToBytes(); + parcel.AABBMin = AABBMin; + parcel.AABBMax = AABBMax; - if (m_displacement != Vector3.Zero) + if (m_merge) { - Vector3 parcelDisp = new Vector3(m_displacement.X, m_displacement.Y, 0f); - parcel.AABBMin += parcelDisp; - parcel.AABBMax += parcelDisp; + // give the remapped parcel a new GlobalID, in case we're using the same OAR twice and a bounding cube, displacement and --merge + parcel.GlobalID = UUID.Random(); + + //now check if the area of this new incoming parcel overlays an area in any existing parcels + //and if so modify or lose the existing parcels + for (int i = 0; i < parcels.Count; i++) + { + if (parcels[i] != null) + { + bool[,] modLandBitmap = parcels[i].ConvertBytesToLandBitmap(overrideRegionSize); + modLandBitmap = parcels[i].RemoveFromLandBitmap(modLandBitmap, dstLandBitmap, out isEmptyNow, out AABBMin, out AABBMax); + if (isEmptyNow) + { + parcels[i] = null; + } + else + { + parcels[i].LandBitmap = modLandBitmap; + parcels[i].LandData.Bitmap = parcels[i].ConvertLandBitmapToBytes(); + parcels[i].LandData.AABBMin = AABBMin; + parcels[i].LandData.AABBMax = AABBMax; + } + } + } } - + // Validate User and Group UUID's if (!ResolveGroupUuid(parcel.GroupID)) @@ -679,19 +847,23 @@ namespace OpenSim.Region.CoreModules.World.Archiver } parcel.ParcelAccessList = accessList; -// m_log.DebugFormat( -// "[ARCHIVER]: Adding parcel {0}, local id {1}, owner {2}, group {3}, isGroupOwned {4}, area {5}", -// parcel.Name, parcel.LocalID, parcel.OwnerID, parcel.GroupID, parcel.IsGroupOwned, parcel.Area); - + if (m_debug) m_log.DebugFormat("[ARCHIVER]: Adding parcel {0}, local id {1}, owner {2}, group {3}, isGroupOwned {4}, area {5}", + parcel.Name, parcel.LocalID, parcel.OwnerID, parcel.GroupID, parcel.IsGroupOwned, parcel.Area); + landData.Add(parcel); } - if (!m_merge) + if (m_merge) { - bool setupDefaultParcel = (landData.Count == 0); - scene.LandChannel.Clear(setupDefaultParcel); + for (int i = 0; i < parcels.Count; i++) //if merging then we need to also add back in any existing parcels + { + if (parcels[i] != null) landData.Add(parcels[i].LandData); + } } - + + m_log.InfoFormat("[ARCHIVER]: Clearing {0} parcels.", parcels.Count); + bool setupDefaultParcel = (landData.Count == 0); + scene.LandChannel.Clear(setupDefaultParcel); scene.EventManager.TriggerIncomingLandDataFromStorage(landData); m_log.InfoFormat("[ARCHIVER]: Restored {0} parcels.", landData.Count); } @@ -772,6 +944,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver if (m_assetService.GetMetadata(uuid) != null) { + sbyte asype = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension]; + if(asype == -2) + { + + } + // m_log.DebugFormat("[ARCHIVER]: found existing asset {0}",uuid); return true; } @@ -780,6 +958,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver { sbyte assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension]; + if(assetType == -2) + { + + } if (assetType == (sbyte)AssetType.Unknown) { m_log.WarnFormat("[ARCHIVER]: Importing {0} byte asset {1} with unknown type", data.Length, uuid); @@ -792,7 +974,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver ModifySceneObject(m_rootScene, sog); return true; }); - + if (data == null) return false; } @@ -898,7 +1080,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver currentRegionSettings.Save(); scene.TriggerEstateSunUpdate(); - + IEstateModule estateModule = scene.RequestModuleInterface(); if (estateModule != null) estateModule.sendRegionHandshakeToAll(); @@ -918,13 +1100,13 @@ namespace OpenSim.Region.CoreModules.World.Archiver private bool LoadTerrain(Scene scene, string terrainPath, byte[] data) { ITerrainModule terrainModule = scene.RequestModuleInterface(); - using (MemoryStream ms = new MemoryStream(data)) { - if (m_displacement != Vector3.Zero || m_rotation != 0f) + if (m_displacement != Vector3.Zero || m_rotation != 0f || m_boundingBox) { - Vector2 rotationCenter = new Vector2(m_rotationCenter.X, m_rotationCenter.Y); - terrainModule.LoadFromStream(terrainPath, m_displacement, m_rotation, rotationCenter, ms); + Vector2 boundingOrigin = new Vector2(m_boundingOrigin.X, m_boundingOrigin.Y); + Vector2 boundingSize = new Vector2(m_boundingSize.X, m_boundingSize.Y); + terrainModule.LoadFromStream(terrainPath, m_displacement, m_rotation, boundingOrigin, boundingSize, ms); ; } else { @@ -948,6 +1130,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable()); XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.None); XmlTextReader xtr = new XmlTextReader(Encoding.ASCII.GetString(data), XmlNodeType.Document, context); + xtr.ProhibitDtd = true; // Loaded metadata will be empty if no information exists in the archive dearchivedScenes.LoadedCreationDateTime = 0; @@ -955,16 +1138,16 @@ namespace OpenSim.Region.CoreModules.World.Archiver bool multiRegion = false; - while (xtr.Read()) + while (xtr.Read()) { - if (xtr.NodeType == XmlNodeType.Element) + if (xtr.NodeType == XmlNodeType.Element) { if (xtr.Name.ToString() == "archive") { int majorVersion = int.Parse(xtr["major_version"]); int minorVersion = int.Parse(xtr["minor_version"]); string version = string.Format("{0}.{1}", majorVersion, minorVersion); - + if (majorVersion > MAX_MAJOR_VERSION) { throw new Exception( @@ -972,15 +1155,15 @@ namespace OpenSim.Region.CoreModules.World.Archiver "The OAR you are trying to load has major version number of {0} but this version of OpenSim can only load OARs with major version number {1} and below", majorVersion, MAX_MAJOR_VERSION)); } - + m_log.InfoFormat("[ARCHIVER]: Loading OAR with version {0}", version); } - if (xtr.Name.ToString() == "datetime") + else if (xtr.Name.ToString() == "datetime") { int value; if (Int32.TryParse(xtr.ReadElementContentAsString(), out value)) dearchivedScenes.LoadedCreationDateTime = value; - } + } else if (xtr.Name.ToString() == "row") { multiRegion = true; @@ -994,13 +1177,26 @@ namespace OpenSim.Region.CoreModules.World.Archiver { string id = xtr.ReadElementContentAsString(); dearchivedScenes.DefaultOriginalID = id; - if (multiRegion) + if(multiRegion) dearchivedScenes.SetRegionOriginalID(id); } else if (xtr.Name.ToString() == "dir") { dearchivedScenes.SetRegionDirectory(xtr.ReadElementContentAsString()); } + else if (xtr.Name.ToString() == "size_in_meters") + { + Vector3 value; + string size = "<" + xtr.ReadElementContentAsString() + ",0>"; + if (Vector3.TryParse(size, out value)) + { + m_incomingRegionSize = value; + if(multiRegion) + dearchivedScenes.SetRegionSize(m_incomingRegionSize); + m_log.DebugFormat("[ARCHIVER]: Found region_size info {0}", + m_incomingRegionSize.ToString()); + } + } } } @@ -1012,9 +1208,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver dearchivedScenes.StartRegion(); dearchivedScenes.SetRegionOriginalID(dearchivedScenes.DefaultOriginalID); dearchivedScenes.SetRegionDirectory(""); + dearchivedScenes.SetRegionSize(m_incomingRegionSize); } ControlFileLoaded = true; + if(xtr != null) + xtr.Close(); return dearchivedScenes; } diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs index d8dace2..2fb4426 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs @@ -50,7 +50,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// The inner dictionaries contain each row's regions (key: X coordinate). /// public SortedDictionary> Regions { get; set; } - + /// /// The subdirectory where each region is stored in the archive. /// @@ -152,7 +152,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver } } } - + /// /// Returns the scene at position 'location'. /// diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs index cb2c7f1..11c53d7 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs @@ -60,8 +60,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// /// The minimum major version of OAR that we can write. /// - public static int MIN_MAJOR_VERSION = 0; - + public static int MIN_MAJOR_VERSION = 0; + /// /// The maximum major version of OAR that we can write. /// @@ -112,7 +112,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver m_log.ErrorFormat("{0} {1}", e.Message, e.StackTrace); } } - + /// /// Constructor. /// @@ -181,11 +181,13 @@ namespace OpenSim.Region.CoreModules.World.Archiver // Archive the regions Dictionary assetUuids = new Dictionary(); + HashSet failedIDs = new HashSet(); + HashSet uncertainAssetsUUIDs = new HashSet(); scenesGroup.ForEachScene(delegate(Scene scene) { string regionDir = MultiRegionFormat ? scenesGroup.GetRegionDir(scene.RegionInfo.RegionID) : ""; - ArchiveOneRegion(scene, regionDir, assetUuids); + ArchiveOneRegion(scene, regionDir, assetUuids, failedIDs, uncertainAssetsUUIDs); }); // Archive the assets @@ -193,23 +195,21 @@ namespace OpenSim.Region.CoreModules.World.Archiver if (SaveAssets) { m_log.DebugFormat("[ARCHIVER]: Saving {0} assets", assetUuids.Count); - - // Asynchronously request all the assets required to perform this archive operation - AssetsRequest ar - = new AssetsRequest( + + AssetsRequest ar = new AssetsRequest( new AssetsArchiver(m_archiveWriter), assetUuids, + failedIDs.Count, m_rootScene.AssetService, m_rootScene.UserAccountService, - m_rootScene.RegionInfo.ScopeID, options, ReceivedAllAssets); - - WorkManager.RunInThread(o => ar.Execute(), null, "Archive Assets Request"); - - // CloseArchive() will be called from ReceivedAllAssets() + m_rootScene.RegionInfo.ScopeID, options, null); + ar.Execute(); + assetUuids = null; } else { m_log.DebugFormat("[ARCHIVER]: Not saving assets since --noassets was specified"); - CloseArchive(string.Empty); +// CloseArchive(string.Empty); } + CloseArchive(string.Empty); } catch (Exception e) { @@ -218,7 +218,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver } } - private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary assetUuids) + private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary assetUuids, + HashSet failedIDs, HashSet uncertainAssetsUUIDs) { m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.Name); @@ -226,7 +227,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver List sceneObjects = new List(); int numObjectsSkippedPermissions = 0; - + // Filter entities so that we only have scene objects. // FIXME: Would be nicer to have this as a proper list in SceneGraph, since lots of methods // end up having to do this @@ -237,7 +238,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver { SceneObjectGroup sceneObject = (SceneObjectGroup)entity; - if (!sceneObject.IsDeleted && !sceneObject.IsAttachment) + if (!sceneObject.IsDeleted && !sceneObject.IsAttachment && !sceneObject.IsTemporary && !sceneObject.inTransit) { if (!CanUserArchiveObject(scene.RegionInfo.EstateSettings.EstateOwner, sceneObject, FilterContent, permissionsModule)) { @@ -254,17 +255,39 @@ namespace OpenSim.Region.CoreModules.World.Archiver if (SaveAssets) { - UuidGatherer assetGatherer = new UuidGatherer(scene.AssetService, assetUuids); + UuidGatherer assetGatherer = new UuidGatherer(scene.AssetService, assetUuids, failedIDs, uncertainAssetsUUIDs); int prevAssets = assetUuids.Count; - + foreach (SceneObjectGroup sceneObject in sceneObjects) + { + int curErrorCntr = assetGatherer.ErrorCount; + int possible = assetGatherer.possibleNotAssetCount; assetGatherer.AddForInspection(sceneObject); + assetGatherer.GatherAll(); + curErrorCntr = assetGatherer.ErrorCount - curErrorCntr; + possible = assetGatherer.possibleNotAssetCount - possible; + if(curErrorCntr > 0) + { + m_log.ErrorFormat("[ARCHIVER]: object {0} '{1}', at {2}, contains {3} references to missing or damaged assets", + sceneObject.UUID, sceneObject.Name ,sceneObject.AbsolutePosition.ToString(), curErrorCntr); + if(possible > 0) + m_log.WarnFormat("[ARCHIVER Warning]: object also contains {0} references that may be to missing or damaged assets or not a problem", possible); + } + else if(possible > 0) + { + m_log.WarnFormat("[ARCHIVER Warning]: object {0} '{1}', at {2}, contains {3} references that may be to missing or damaged assets or not a problem", + sceneObject.UUID, sceneObject.Name ,sceneObject.AbsolutePosition.ToString(), possible); + } + } assetGatherer.GatherAll(); + int errors = assetGatherer.FailedUUIDs.Count; m_log.DebugFormat( - "[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets", - sceneObjects.Count, assetUuids.Count - prevAssets); + "[ARCHIVER]: {0} region scene objects to save reference {1} possible assets", + sceneObjects.Count, assetUuids.Count - prevAssets + errors); + if(errors > 0) + m_log.DebugFormat("[ARCHIVER]: {0} of these have problems or are not assets and will be ignored", errors); } if (numObjectsSkippedPermissions > 0) @@ -276,16 +299,16 @@ namespace OpenSim.Region.CoreModules.World.Archiver // Make sure that we also request terrain texture assets RegionSettings regionSettings = scene.RegionInfo.RegionSettings; - + if (regionSettings.TerrainTexture1 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_1) assetUuids[regionSettings.TerrainTexture1] = (sbyte)AssetType.Texture; - + if (regionSettings.TerrainTexture2 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_2) assetUuids[regionSettings.TerrainTexture2] = (sbyte)AssetType.Texture; - + if (regionSettings.TerrainTexture3 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_3) assetUuids[regionSettings.TerrainTexture3] = (sbyte)AssetType.Texture; - + if (regionSettings.TerrainTexture4 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_4) assetUuids[regionSettings.TerrainTexture4] = (sbyte)AssetType.Texture; @@ -398,18 +421,18 @@ namespace OpenSim.Region.CoreModules.World.Archiver // string[] parts = m_options["version"].ToString().Split('.'); // if (parts.Length >= 1) // { -// majorVersion = Int32.Parse(parts[0]); -// +// majorVersion = Int32.Parse(parts[0]); +// // if (parts.Length >= 2) // minorVersion = Int32.Parse(parts[1]); // } // } -// +// // if (majorVersion < MIN_MAJOR_VERSION || majorVersion > MAX_MAJOR_VERSION) // { // throw new Exception( // string.Format( -// "OAR version number for save must be between {0} and {1}", +// "OAR version number for save must be between {0} and {1}", // MIN_MAJOR_VERSION, MAX_MAJOR_VERSION)); // } // else if (majorVersion == MAX_MAJOR_VERSION) @@ -420,9 +443,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver // else if (majorVersion == MIN_MAJOR_VERSION) // { // // Force 0.4 -// minorVersion = 4; +// minorVersion = 4; // } - + m_log.InfoFormat("[ARCHIVER]: Creating version {0}.{1} OAR", majorVersion, minorVersion); if (majorVersion == 1) { @@ -430,7 +453,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver } String s; - + using (StringWriter sw = new StringWriter()) { using (XmlTextWriter xtw = new XmlTextWriter(sw)) @@ -440,7 +463,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver xtw.WriteStartElement("archive"); xtw.WriteAttributeString("major_version", majorVersion.ToString()); xtw.WriteAttributeString("minor_version", minorVersion.ToString()); - + xtw.WriteStartElement("creation_info"); DateTime now = DateTime.UtcNow; TimeSpan t = now - new DateTime(1970, 1, 1); @@ -448,7 +471,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver if (!MultiRegionFormat) xtw.WriteElementString("id", m_rootScene.RegionInfo.RegionID.ToString()); xtw.WriteEndElement(); - + xtw.WriteElementString("assets_included", SaveAssets.ToString()); if (MultiRegionFormat) @@ -463,7 +486,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver } xtw.WriteEndElement(); - + xtw.Flush(); } @@ -522,22 +545,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver protected static void WriteRegionInfo(Scene scene, XmlTextWriter xtw) { - bool isMegaregion; Vector2 size; - IRegionCombinerModule rcMod = scene.RequestModuleInterface(); + size = new Vector2((float)scene.RegionInfo.RegionSizeX, (float)scene.RegionInfo.RegionSizeY); - if (rcMod != null) - isMegaregion = rcMod.IsRootForMegaregion(scene.RegionInfo.RegionID); - else - isMegaregion = false; - - if (isMegaregion) - size = rcMod.GetSizeOfMegaregion(scene.RegionInfo.RegionID); - else - size = new Vector2((float)scene.RegionInfo.RegionSizeX, (float)scene.RegionInfo.RegionSizeY); - - xtw.WriteElementString("is_megaregion", isMegaregion.ToString()); xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y)); } @@ -560,7 +571,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver foreach (ILandObject lo in landObjects) { LandData landData = lo.LandData; - string landDataPath + string landDataPath = String.Format("{0}{1}", regionDir, ArchiveConstants.CreateOarLandDataPath(landData)); m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options)); } @@ -584,17 +595,18 @@ namespace OpenSim.Region.CoreModules.World.Archiver foreach (SceneObjectGroup sceneObject in sceneObjects) { //m_log.DebugFormat("[ARCHIVER]: Saving {0} {1}, {2}", entity.Name, entity.UUID, entity.GetType()); - + if(sceneObject.IsDeleted || sceneObject.inTransit) + continue; string serializedObject = serializer.SerializeGroupToXml2(sceneObject, m_options); string objectPath = string.Format("{0}{1}", regionDir, ArchiveHelpers.CreateObjectPath(sceneObject)); m_archiveWriter.WriteFile(objectPath, serializedObject); } } - + protected void ReceivedAllAssets(ICollection assetsFoundUuids, ICollection assetsNotFoundUuids, bool timedOut) { string errorMessage; - + if (timedOut) { errorMessage = "Loading assets timed out"; @@ -612,10 +624,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver errorMessage = String.Empty; } - + CloseArchive(errorMessage); } - + /// /// Closes the archive and notifies that we're done. /// @@ -634,7 +646,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver if (errorMessage == string.Empty) errorMessage = e.Message; } - + m_log.InfoFormat("[ARCHIVER]: Finished writing out OAR for {0}", m_rootScene.RegionInfo.RegionName); m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage); diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs index 6a09caf..1305545 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs @@ -49,24 +49,23 @@ namespace OpenSim.Region.CoreModules.World.Archiver [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ArchiverModule")] public class ArchiverModule : INonSharedRegionModule, IRegionArchiverModule { - private static readonly ILog m_log = + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); public Scene Scene { get; private set; } - public IRegionCombinerModule RegionCombinerModule { get; private set; } /// /// The file used to load and save an opensimulator archive if no filename has been specified /// protected const string DEFAULT_OAR_BACKUP_FILENAME = "region.oar"; - public string Name - { - get { return "RegionArchiverModule"; } + public string Name + { + get { return "RegionArchiverModule"; } } - public Type ReplaceableInterface - { + public Type ReplaceableInterface + { get { return null; } } @@ -85,7 +84,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver public void RegionLoaded(Scene scene) { - RegionCombinerModule = scene.RequestModuleInterface(); } public void RemoveRegion(Scene scene) @@ -110,18 +108,22 @@ namespace OpenSim.Region.CoreModules.World.Archiver Vector3 displacement = new Vector3(0f, 0f, 0f); String defaultUser = ""; float rotation = 0f; - Vector3 rotationCenter = new Vector3(Constants.RegionSize / 2f, Constants.RegionSize / 2f, 0); - + Vector3 rotationCenter = new Vector3(Scene.RegionInfo.RegionSizeX / 2f, Scene.RegionInfo.RegionSizeY / 2f, 0); + Vector3 boundingOrigin = new Vector3(0f, 0f, 0f); + Vector3 boundingSize = new Vector3(Scene.RegionInfo.RegionSizeX, Scene.RegionInfo.RegionSizeY, float.MaxValue); + bool debug = false; + OptionSet options = new OptionSet(); - options.Add("m|merge", delegate (string v) { mergeOar = (v != null); }); - options.Add("s|skip-assets", delegate (string v) { skipAssets = (v != null); }); - options.Add("force-terrain", delegate (string v) { forceTerrain = (v != null); }); - options.Add("forceterrain", delegate (string v) { forceTerrain = (v != null); }); // downward compatibility - options.Add("force-parcels", delegate (string v) { forceParcels = (v != null); }); - options.Add("forceparcels", delegate (string v) { forceParcels = (v != null); }); // downward compatibility - options.Add("no-objects", delegate (string v) { noObjects = (v != null); }); + options.Add("m|merge", delegate(string v) { mergeOar = (v != null); }); + options.Add("s|skip-assets", delegate(string v) { skipAssets = (v != null); }); + options.Add("force-terrain", delegate(string v) { forceTerrain = (v != null); }); + options.Add("forceterrain", delegate(string v) { forceTerrain = (v != null); }); // downward compatibility + options.Add("force-parcels", delegate(string v) { forceParcels = (v != null); }); + options.Add("forceparcels", delegate(string v) { forceParcels = (v != null); }); // downward compatibility + options.Add("no-objects", delegate(string v) { noObjects = (v != null); }); options.Add("default-user=", delegate(string v) { defaultUser = (v == null) ? "" : v; }); - options.Add("displacement=", delegate (string v) { + options.Add("displacement=", delegate(string v) + { try { displacement = v == null ? Vector3.Zero : Vector3.Parse(v); @@ -145,12 +147,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver m_log.ErrorFormat("[ARCHIVER MODULE] Must be an angle in degrees between -360 and +360: --rotation 45"); return; } - // Convert to radians for internals - rotation = Util.Clamp(rotation, -359f, 359f) / 180f * (float)Math.PI; + //pass this in as degrees now, convert to radians later during actual work phase + rotation = Util.Clamp(rotation, -359f, 359f); }); - options.Add("rotation-center=", delegate (string v) { + options.Add("rotation-center=", delegate(string v) + { try { + m_log.Info("[ARCHIVER MODULE] Warning: --rotation-center no longer does anything and will be removed soon!"); rotationCenter = v == null ? Vector3.Zero : Vector3.Parse(v); } catch @@ -160,6 +164,33 @@ namespace OpenSim.Region.CoreModules.World.Archiver return; } }); + options.Add("bounding-origin=", delegate(string v) + { + try + { + boundingOrigin = v == null ? Vector3.Zero : Vector3.Parse(v); + } + catch + { + m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing bounding cube origin"); + m_log.ErrorFormat("[ARCHIVER MODULE] Must be represented as vector3: --bounding-origin \"<128,128,0>\""); + return; + } + }); + options.Add("bounding-size=", delegate(string v) + { + try + { + boundingSize = v == null ? new Vector3(Scene.RegionInfo.RegionSizeX, Scene.RegionInfo.RegionSizeY, float.MaxValue) : Vector3.Parse(v); + } + catch + { + m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing bounding cube size"); + m_log.ErrorFormat("[ARCHIVER MODULE] Must be represented as a positive vector3: --bounding-size \"<256,256,4096>\""); + return; + } + }); + options.Add("d|debug", delegate(string v) { debug = (v != null); }); // Send a message to the region ready module /* bluewall* Disable this for the time being @@ -170,9 +201,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver rready.OarLoadingAlert("load"); } */ - + List mainParams = options.Parse(cmdparams); - + // m_log.DebugFormat("MERGE OAR IS [{0}]", mergeOar); // // foreach (string param in mainParams) @@ -208,6 +239,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver archiveOptions.Add("displacement", displacement); archiveOptions.Add("rotation", rotation); archiveOptions.Add("rotation-center", rotationCenter); + archiveOptions.Add("bounding-origin", boundingOrigin); + archiveOptions.Add("bounding-size", boundingSize); + if (debug) archiveOptions.Add("debug", null); if (mainParams.Count > 2) { @@ -254,7 +288,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver ArchiveRegion(path, options); } - + public void ArchiveRegion(string savePath, Dictionary options) { ArchiveRegion(savePath, Guid.Empty, options); @@ -264,7 +298,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver { m_log.InfoFormat( "[ARCHIVER]: Writing archive for region {0} to {1}", Scene.RegionInfo.RegionName, savePath); - + new ArchiveWriteRequest(Scene, savePath, requestId).ArchiveRegion(options); } @@ -288,21 +322,20 @@ namespace OpenSim.Region.CoreModules.World.Archiver Dictionary archiveOptions = new Dictionary(); DearchiveRegion(loadPath, Guid.Empty, archiveOptions); } - - public void DearchiveRegion(string loadPath, Guid requestId, Dictionary options) + + public void DearchiveRegion(string loadPath, Guid requestId, Dictionary options) { m_log.InfoFormat( "[ARCHIVER]: Loading archive to region {0} from {1}", Scene.RegionInfo.RegionName, loadPath); - + new ArchiveReadRequest(Scene, loadPath, requestId, options).DearchiveRegion(); } - + public void DearchiveRegion(Stream loadStream) { Dictionary archiveOptions = new Dictionary(); DearchiveRegion(loadStream, Guid.Empty, archiveOptions); } - public void DearchiveRegion(Stream loadStream, Guid requestId, Dictionary options) { new ArchiveReadRequest(Scene, loadStream, requestId, options).DearchiveRegion(); diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs index bc6a97d..3092fe0 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs @@ -46,13 +46,13 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// /// Post a message to the log every x assets as a progress bar /// - protected static int LOG_ASSET_LOAD_NOTIFICATION_INTERVAL = 50; + protected static int LOG_ASSET_LOAD_NOTIFICATION_INTERVAL = 100; /// /// Keep a count of the number of assets written so that we can provide status updates /// - protected int m_assetsWritten; - + protected int m_assetsWritten; + protected TarArchiveWriter m_archiveWriter; public AssetsArchiver(TarArchiveWriter archiveWriter) @@ -143,6 +143,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver asset.Data); m_assetsWritten++; + + //m_log.DebugFormat("[ARCHIVER]: Added asset {0}", m_assetsWritten); + + if (m_assetsWritten % LOG_ASSET_LOAD_NOTIFICATION_INTERVAL == 0) + m_log.InfoFormat("[ARCHIVER]: Added {0} assets to archive", m_assetsWritten); } } diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsDearchiver.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsDearchiver.cs index 8c0ef88..5d3be62 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/AssetsDearchiver.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsDearchiver.cs @@ -93,6 +93,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver StringReader sr = new StringReader(xml); XmlTextReader reader = new XmlTextReader(sr); + reader.ProhibitDtd = true; reader.ReadStartElement("assets"); reader.Read(); diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs index db66c83..91f4dc3 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs @@ -60,29 +60,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver Completed, Aborted }; - - /// - /// Timeout threshold if we still need assets or missing asset notifications but have stopped receiving them - /// from the asset service - /// - protected const int TIMEOUT = 60 * 1000; - - /// - /// If a timeout does occur, limit the amount of UUID information put to the console. - /// - protected const int MAX_UUID_DISPLAY_ON_TIMEOUT = 3; - - protected System.Timers.Timer m_requestCallbackTimer; /// - /// State of this request - /// - private RequestState m_requestState = RequestState.Initial; - - /// /// uuids to request /// protected IDictionary m_uuids; + private int m_previousErrorsCount; /// /// Callback used when all the assets requested have been received. @@ -93,7 +76,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// List of assets that were found. This will be passed back to the requester. /// protected List m_foundAssetUuids = new List(); - + /// /// Maintain a list of assets that could not be found. This will be passed back to the requester. /// @@ -104,217 +87,114 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// private int m_repliesRequired; + private System.Timers.Timer m_timeOutTimer; + private bool m_timeout; + /// /// Asset service used to request the assets /// protected IAssetService m_assetService; protected IUserAccountService m_userAccountService; - protected UUID m_scopeID; // the grid ID + protected UUID m_scopeID; // the grid ID protected AssetsArchiver m_assetsArchiver; protected Dictionary m_options; protected internal AssetsRequest( - AssetsArchiver assetsArchiver, IDictionary uuids, - IAssetService assetService, IUserAccountService userService, - UUID scope, Dictionary options, + AssetsArchiver assetsArchiver, IDictionary uuids, + int previousErrorsCount, + IAssetService assetService, IUserAccountService userService, + UUID scope, Dictionary options, AssetsRequestCallback assetsRequestCallback) { m_assetsArchiver = assetsArchiver; m_uuids = uuids; + m_previousErrorsCount = previousErrorsCount; m_assetsRequestCallback = assetsRequestCallback; m_assetService = assetService; m_userAccountService = userService; m_scopeID = scope; m_options = options; m_repliesRequired = uuids.Count; - - // FIXME: This is a really poor way of handling the timeout since it will always leave the original requesting thread - // hanging. Need to restructure so an original request thread waits for a ManualResetEvent on asset received - // so we can properly abort that thread. Or request all assets synchronously, though that would be a more - // radical change - m_requestCallbackTimer = new System.Timers.Timer(TIMEOUT); - m_requestCallbackTimer.AutoReset = false; - m_requestCallbackTimer.Elapsed += new ElapsedEventHandler(OnRequestCallbackTimeout); } protected internal void Execute() { - m_requestState = RequestState.Running; - - m_log.DebugFormat("[ARCHIVER]: AssetsRequest executed looking for {0} possible assets", m_repliesRequired); - + Culture.SetCurrentCulture(); // We can stop here if there are no assets to fetch if (m_repliesRequired == 0) { - m_requestState = RequestState.Completed; PerformAssetsRequestCallback(false); return; } - m_requestCallbackTimer.Enabled = true; + m_timeOutTimer = new System.Timers.Timer(60000); + m_timeOutTimer .AutoReset = false; + m_timeOutTimer.Elapsed += OnTimeout; + m_timeout = false; foreach (KeyValuePair kvp in m_uuids) { -// m_log.DebugFormat("[ARCHIVER]: Requesting asset {0}", kvp.Key); - -// m_assetService.Get(kvp.Key.ToString(), kvp.Value, PreAssetRequestCallback); - AssetBase asset = m_assetService.Get(kvp.Key.ToString()); - PreAssetRequestCallback(kvp.Key.ToString(), kvp.Value, asset); - } - } + string thiskey = kvp.Key.ToString(); + try + { + m_timeOutTimer.Enabled = true; + AssetBase asset = m_assetService.Get(thiskey); + if(m_timeout) + break; + + m_timeOutTimer.Enabled = false; - protected void OnRequestCallbackTimeout(object source, ElapsedEventArgs args) - { - bool timedOut = true; + if(asset == null) + { + m_notFoundAssetUuids.Add(new UUID(thiskey)); + continue; + } - try - { - lock (this) - { - // Take care of the possibilty that this thread started but was paused just outside the lock before - // the final request came in (assuming that such a thing is possible) - if (m_requestState == RequestState.Completed) + sbyte assetType = kvp.Value; + if (asset != null && assetType == (sbyte)AssetType.Unknown) { - timedOut = false; - return; + m_log.InfoFormat("[ARCHIVER]: Rewriting broken asset type for {0} to {1}", thiskey, SLUtil.AssetTypeFromCode(assetType)); + asset.Type = assetType; } - - m_requestState = RequestState.Aborted; - } - // Calculate which uuids were not found. This is an expensive way of doing it, but this is a failure - // case anyway. - List uuids = new List(); - foreach (UUID uuid in m_uuids.Keys) - { - uuids.Add(uuid); + m_foundAssetUuids.Add(asset.FullID); + m_assetsArchiver.WriteAsset(PostProcess(asset)); } - foreach (UUID uuid in m_foundAssetUuids) - { - uuids.Remove(uuid); - } - - foreach (UUID uuid in m_notFoundAssetUuids) + catch (Exception e) { - uuids.Remove(uuid); - } - - m_log.ErrorFormat( - "[ARCHIVER]: Asset service failed to return information about {0} requested assets", uuids.Count); - - int i = 0; - foreach (UUID uuid in uuids) - { - m_log.ErrorFormat("[ARCHIVER]: No information about asset {0} received", uuid); - - if (++i >= MAX_UUID_DISPLAY_ON_TIMEOUT) - break; + m_log.ErrorFormat("[ARCHIVER]: Execute failed with {0}", e); } - - if (uuids.Count > MAX_UUID_DISPLAY_ON_TIMEOUT) - m_log.ErrorFormat( - "[ARCHIVER]: (... {0} more not shown)", uuids.Count - MAX_UUID_DISPLAY_ON_TIMEOUT); - - m_log.Error("[ARCHIVER]: Archive save aborted. PLEASE DO NOT USE THIS ARCHIVE, IT WILL BE INCOMPLETE."); - } - catch (Exception e) - { - m_log.ErrorFormat("[ARCHIVER]: Timeout handler exception {0}{1}", e.Message, e.StackTrace); } - finally - { - if (timedOut) - WorkManager.RunInThread(PerformAssetsRequestCallback, true, "Archive Assets Request Callback"); - } - } - protected void PreAssetRequestCallback(string fetchedAssetID, object assetType, AssetBase fetchedAsset) - { - // Check for broken asset types and fix them with the AssetType gleaned by UuidGatherer - if (fetchedAsset != null && fetchedAsset.Type == (sbyte)AssetType.Unknown) - { - m_log.InfoFormat("[ARCHIVER]: Rewriting broken asset type for {0} to {1}", fetchedAsset.ID, SLUtil.AssetTypeFromCode((sbyte)assetType)); - fetchedAsset.Type = (sbyte)assetType; - } + m_timeOutTimer.Dispose(); + int totalerrors = m_notFoundAssetUuids.Count + m_previousErrorsCount; - AssetRequestCallback(fetchedAssetID, this, fetchedAsset); - } + if(m_timeout) + m_log.DebugFormat("[ARCHIVER]: Aborted because AssetService request timeout. Successfully added {0} assets", m_foundAssetUuids.Count); + else if(totalerrors == 0) + m_log.DebugFormat("[ARCHIVER]: Successfully added all {0} assets", m_foundAssetUuids.Count); + else + m_log.DebugFormat("[ARCHIVER]: Successfully added {0} assets ({1} of total possible assets requested were not found, were damaged or were not assets)", + m_foundAssetUuids.Count, totalerrors); - /// - /// Called back by the asset cache when it has the asset - /// - /// - /// - public void AssetRequestCallback(string id, object sender, AssetBase asset) + PerformAssetsRequestCallback(m_timeout); + } + + private void OnTimeout(object source, ElapsedEventArgs args) { - Culture.SetCurrentCulture(); - - try - { - lock (this) - { - //m_log.DebugFormat("[ARCHIVER]: Received callback for asset {0}", id); - - m_requestCallbackTimer.Stop(); - - if ((m_requestState == RequestState.Aborted) || (m_requestState == RequestState.Completed)) - { - m_log.WarnFormat( - "[ARCHIVER]: Received information about asset {0} while in state {1}. Ignoring.", - id, m_requestState); - - return; - } - - if (asset != null) - { - if (m_options.ContainsKey("verbose")) - m_log.InfoFormat("[ARCHIVER]: Writing asset {0}", id); - - m_foundAssetUuids.Add(asset.FullID); - - m_assetsArchiver.WriteAsset(PostProcess(asset)); - } - else - { - if (m_options.ContainsKey("verbose")) - m_log.InfoFormat("[ARCHIVER]: Recording asset {0} as not found", id); - - m_notFoundAssetUuids.Add(new UUID(id)); - } - - if (m_foundAssetUuids.Count + m_notFoundAssetUuids.Count >= m_repliesRequired) - { - m_requestState = RequestState.Completed; - - m_log.DebugFormat( - "[ARCHIVER]: Successfully added {0} assets ({1} assets not found but these may be expected invalid references)", - m_foundAssetUuids.Count, m_notFoundAssetUuids.Count); - - // We want to stop using the asset cache thread asap - // as we now need to do the work of producing the rest of the archive - WorkManager.RunInThread(PerformAssetsRequestCallback, false, "Archive Assets Request Callback"); - } - else - { - m_requestCallbackTimer.Start(); - } - } - } - catch (Exception e) - { - m_log.ErrorFormat("[ARCHIVER]: AssetRequestCallback failed with {0}", e); - } + m_timeout = true; } /// /// Perform the callback on the original requester of the assets /// - protected void PerformAssetsRequestCallback(object o) + private void PerformAssetsRequestCallback(object o) { + if(m_assetsRequestCallback == null) + return; Culture.SetCurrentCulture(); Boolean timedOut = (Boolean)o; @@ -330,7 +210,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver } } - protected AssetBase PostProcess(AssetBase asset) + private AssetBase PostProcess(AssetBase asset) { if (asset.Type == (sbyte)AssetType.Object && asset.Data != null && m_options.ContainsKey("home")) { diff --git a/OpenSim/Region/CoreModules/World/Archiver/DearchiveScenesGroup.cs b/OpenSim/Region/CoreModules/World/Archiver/DearchiveScenesGroup.cs index 3dcc020..809d863 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/DearchiveScenesGroup.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/DearchiveScenesGroup.cs @@ -70,6 +70,16 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// If null then the region doesn't have a corresponding scene, and it won't be loaded. /// public Scene Scene { get; set; } + + /// + /// The size of the region being loaded. + /// + public Vector3 RegionSize { get; set; } + + public RegionInfo() + { + RegionSize = new Vector3(256f,256f,float.MaxValue); + } } /// @@ -113,23 +123,34 @@ namespace OpenSim.Region.CoreModules.World.Archiver public void StartRegion() { m_curX = (m_curX == null) ? 0 : m_curX + 1; - // Note: this doesn't mean we have a real region in this location; this could just be a "hole" + // Note: this doesn't mean we have a real region in this location; this could just be a "hole" } public void SetRegionOriginalID(string id) { m_curRegion = new RegionInfo(); - m_curRegion.Location = new Point((int)m_curX, (int)m_curY); + int x = (int)((m_curX == null) ? 0 : m_curX); + int y = (int)((m_curY == null) ? 0 : m_curY); + + m_curRegion.Location = new Point(x, y); m_curRegion.OriginalID = id; // 'curRegion' will be saved in 'm_directory2region' when SetRegionDir() is called } public void SetRegionDirectory(string directory) { - m_curRegion.Directory = directory; - m_directory2region[directory] = m_curRegion; + if(m_curRegion != null) + { + m_curRegion.Directory = directory; + m_directory2region[directory] = m_curRegion; + } } + public void SetRegionSize(Vector3 size) + { + if(m_curRegion != null) + m_curRegion.RegionSize = size; + } /// /// Sets all the scenes present in the simulator. @@ -145,7 +166,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver { foreach (RegionInfo archivedRegion in m_directory2region.Values) { - Point location = new Point((int)rootScene.RegionInfo.RegionLocX, (int)rootScene.RegionInfo.RegionLocY); + Point location = new Point((int)rootScene.RegionInfo.RegionLocX, + (int)rootScene.RegionInfo.RegionLocY); + location.Offset(archivedRegion.Location); Scene scene; @@ -191,7 +214,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver return false; string regionDirectory = parts[1]; relativePath = parts[2]; - + RegionInfo region; if (m_directory2region.TryGetValue(regionDirectory, out region)) { @@ -228,5 +251,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver return m_newId2region.Keys.ToList(); } + public int GetScenesCount() + { + return m_directory2region.Count; + } } } diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs index 9f197f5..6885299 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs @@ -65,7 +65,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests protected SerialiserModule m_serialiserModule; protected TaskInventoryItem m_soundItem; - + + private AutoResetEvent m_oarEvent = new AutoResetEvent(false); + [SetUp] public override void SetUp() { @@ -87,11 +89,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests m_lastRequestId = requestId; m_lastErrorMessage = errorMessage; Console.WriteLine("About to pulse ArchiverTests on LoadCompleted"); - - Monitor.PulseAll(this); + m_oarEvent.Set(); } } - + private void SaveCompleted(Guid requestId, string errorMessage) { lock (this) @@ -99,7 +100,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests m_lastRequestId = requestId; m_lastErrorMessage = errorMessage; Console.WriteLine("About to pulse ArchiverTests on SaveCompleted"); - Monitor.PulseAll(this); + m_oarEvent.Set(); } } @@ -110,6 +111,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); Vector3 groupPosition = new Vector3(10, 20, 30); Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); + rotationOffset.Normalize(); // Vector3 offsetPosition = new Vector3(5, 10, 15); return new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, Vector3.Zero) { Name = partName }; @@ -122,11 +124,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests PrimitiveBaseShape shape = PrimitiveBaseShape.CreateCylinder(); Vector3 groupPosition = new Vector3(90, 80, 70); Quaternion rotationOffset = new Quaternion(60, 70, 80, 90); + rotationOffset.Normalize(); Vector3 offsetPosition = new Vector3(20, 25, 30); return new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, offsetPosition) { Name = partName }; } - + private void CreateTestObjects(Scene scene, out SceneObjectGroup sog1, out SceneObjectGroup sog2, out UUID ncAssetUuid) { SceneObjectPart part1 = CreateSceneObjectPart1(); @@ -192,17 +195,15 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests m_scene.EventManager.OnOarFileSaved += SaveCompleted; Guid requestId = new Guid("00000000-0000-0000-0000-808080808080"); - - lock (this) - { - m_archiverModule.ArchiveRegion(archiveWriteStream, requestId); - //AssetServerBase assetServer = (AssetServerBase)scene.CommsManager.AssetCache.AssetServer; - //while (assetServer.HasWaitingRequests()) - // assetServer.ProcessNextRequest(); - - Monitor.Wait(this, 60000); - } - + + m_oarEvent.Reset(); + m_archiverModule.ArchiveRegion(archiveWriteStream, requestId); + //AssetServerBase assetServer = (AssetServerBase)scene.CommsManager.AssetCache.AssetServer; + //while (assetServer.HasWaitingRequests()) + // assetServer.ProcessNextRequest(); + + m_oarEvent.WaitOne(60000); + Assert.That(m_lastRequestId, Is.EqualTo(requestId)); byte[] archive = archiveWriteStream.ToArray(); @@ -210,7 +211,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests TarArchiveReader tar = new TarArchiveReader(archiveReadStream); bool gotNcAssetFile = false; - + string expectedNcAssetFileName = string.Format("{0}_{1}", ncAssetUuid, "notecard.txt"); List foundPaths = new List(); @@ -219,7 +220,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests expectedPaths.Add(ArchiveHelpers.CreateObjectPath(sog2)); string filePath; - TarArchiveReader.TarEntryType tarEntryType; + TarArchiveReader.TarEntryType tarEntryType; byte[] data = tar.ReadEntry(out filePath, out tarEntryType); Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); @@ -227,9 +228,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests Dictionary archiveOptions = new Dictionary(); ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions); arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); - - Assert.That(arr.ControlFileLoaded, Is.True); - + + Assert.That(arr.ControlFileLoaded, Is.True); + while (tar.ReadEntry(out filePath, out tarEntryType) != null) { if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH)) @@ -265,7 +266,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests m_scene.AddNewSceneObject(sog1, false); SceneObjectPart part2 = CreateSceneObjectPart2(); - + AssetNotecard nc = new AssetNotecard(); nc.BodyText = "Hello World!"; nc.Encode(); @@ -275,10 +276,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests = AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero); m_scene.AssetService.Store(ncAsset); SceneObjectGroup sog2 = new SceneObjectGroup(part2); - TaskInventoryItem ncItem + TaskInventoryItem ncItem = new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid }; part2.Inventory.AddInventoryItem(ncItem, true); - + m_scene.AddNewSceneObject(sog2, false); MemoryStream archiveWriteStream = new MemoryStream(); @@ -287,6 +288,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests Dictionary options = new Dictionary(); options.Add("noassets", true); + m_archiverModule.ArchiveRegion(archiveWriteStream, requestId, options); // Don't wait for completion - with --noassets save oar happens synchronously @@ -304,7 +306,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests expectedPaths.Add(ArchiveHelpers.CreateObjectPath(sog2)); string filePath; - TarArchiveReader.TarEntryType tarEntryType; + TarArchiveReader.TarEntryType tarEntryType; byte[] data = tar.ReadEntry(out filePath, out tarEntryType); Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); @@ -312,9 +314,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests Dictionary archiveOptions = new Dictionary(); ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions); arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); - - Assert.That(arr.ControlFileLoaded, Is.True); - + + Assert.That(arr.ControlFileLoaded, Is.True); + while (tar.ReadEntry(out filePath, out tarEntryType) != null) { if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH)) @@ -343,11 +345,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests MemoryStream archiveWriteStream = new MemoryStream(); TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream); - + // Put in a random blank directory to check that this doesn't upset the load process tar.WriteDir("ignoreme"); - - // Also check that direct entries which will also have a file entry containing that directory doesn't + + // Also check that direct entries which will also have a file entry containing that directory doesn't // upset load tar.WriteDir(ArchiveConstants.TERRAINS_PATH); @@ -390,17 +392,17 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests Math.Round(part1.GroupPosition.X), Math.Round(part1.GroupPosition.Y), Math.Round(part1.GroupPosition.Z), part1.UUID); tar.WriteFile(ArchiveConstants.OBJECTS_PATH + object1FileName, SceneObjectSerializer.ToXml2Format(object1)); - + tar.Close(); MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); - lock (this) - { - m_scene.EventManager.OnOarFileLoaded += LoadCompleted; - m_archiverModule.DearchiveRegion(archiveReadStream); - } - + m_scene.EventManager.OnOarFileLoaded += LoadCompleted; + m_oarEvent.Reset(); + m_archiverModule.DearchiveRegion(archiveReadStream); + + m_oarEvent.WaitOne(60000); + Assert.That(m_lastErrorMessage, Is.Null); TestLoadedRegion(part1, soundItemName, soundData); @@ -444,11 +446,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); - lock (this) - { - m_scene.EventManager.OnOarFileLoaded += LoadCompleted; - m_archiverModule.DearchiveRegion(archiveReadStream); - } + m_scene.EventManager.OnOarFileLoaded += LoadCompleted; + m_oarEvent.Reset(); + m_archiverModule.DearchiveRegion(archiveReadStream); + + m_oarEvent.WaitOne(60000); Assert.That(m_lastErrorMessage, Is.Null); @@ -473,35 +475,33 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests m_scene.AddNewSceneObject(sog1, false); SceneObjectPart part2 = CreateSceneObjectPart2(); - + AssetNotecard nc = new AssetNotecard(); nc.BodyText = "Hello World!"; nc.Encode(); UUID ncAssetUuid = new UUID("00000000-0000-0000-1000-000000000000"); UUID ncItemUuid = new UUID("00000000-0000-0000-1100-000000000000"); - AssetBase ncAsset + AssetBase ncAsset = AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero); m_scene.AssetService.Store(ncAsset); SceneObjectGroup sog2 = new SceneObjectGroup(part2); - TaskInventoryItem ncItem + TaskInventoryItem ncItem = new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid }; part2.Inventory.AddInventoryItem(ncItem, true); - + m_scene.AddNewSceneObject(sog2, false); MemoryStream archiveWriteStream = new MemoryStream(); m_scene.EventManager.OnOarFileSaved += SaveCompleted; Guid requestId = new Guid("00000000-0000-0000-0000-808080808080"); - - lock (this) - { - m_archiverModule.ArchiveRegion( + + m_oarEvent.Reset(); + m_archiverModule.ArchiveRegion( archiveWriteStream, requestId, new Dictionary() { { "wipe-owners", Boolean.TrueString } }); - - Monitor.Wait(this, 60000); - } - + + m_oarEvent.WaitOne(60000); + Assert.That(m_lastRequestId, Is.EqualTo(requestId)); byte[] archive = archiveWriteStream.ToArray(); @@ -526,11 +526,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests scene2.RegionInfo.EstateSettings.EstateOwner = estateOwner; - lock (this) - { - scene2.EventManager.OnOarFileLoaded += LoadCompleted; - archiverModule.DearchiveRegion(archiveReadStream); - } + scene2.EventManager.OnOarFileLoaded += LoadCompleted; + m_oarEvent.Reset(); + archiverModule.DearchiveRegion(archiveReadStream); + + m_oarEvent.WaitOne(60000); Assert.That(m_lastErrorMessage, Is.Null); @@ -557,16 +557,16 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests MockGroupsServicesConnector groupsService = new MockGroupsServicesConnector(); IConfigSource configSource = new IniConfigSource(); - IConfig config = configSource.AddConfig("Groups"); + IConfig config = configSource.AddConfig("Groups"); config.Set("Enabled", true); - config.Set("Module", "GroupsModule"); + config.Set("Module", "GroupsModule"); config.Set("DebugEnabled", true); SceneHelpers.SetupSceneModules( m_scene, configSource, new object[] { new GroupsModule(), groupsService, new LandManagementModule() }); // Create group in scene for loading // FIXME: For now we'll put up with the issue that we'll get a group ID that varies across tests. - UUID groupID + UUID groupID = groupsService.CreateGroup(UUID.Zero, "group1", "", true, UUID.Zero, 3, true, true, true, UUID.Zero); // Construct OAR @@ -591,11 +591,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests oarStream = new MemoryStream(oarStream.ToArray()); // Load OAR - lock (this) - { - m_scene.EventManager.OnOarFileLoaded += LoadCompleted; - m_archiverModule.DearchiveRegion(oarStream); - } + m_scene.EventManager.OnOarFileLoaded += LoadCompleted; + m_oarEvent.Reset(); + m_archiverModule.DearchiveRegion(oarStream); + + m_oarEvent.WaitOne(60000); ILandObject rLo = m_scene.LandChannel.GetLandObject(16, 16); LandData rLd = rLo.LandData; @@ -617,7 +617,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests MemoryStream archiveWriteStream = new MemoryStream(); TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream); - + tar.WriteDir(ArchiveConstants.TERRAINS_PATH); tar.WriteFile( ArchiveConstants.CONTROL_FILE_PATH, @@ -658,17 +658,17 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests rs.AddSpawnPoint(SpawnPoint.Parse("1,-2,0.33")); tar.WriteFile(ArchiveConstants.SETTINGS_PATH + "region1.xml", RegionSettingsSerializer.Serialize(rs)); - + tar.Close(); MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); - lock (this) - { - m_scene.EventManager.OnOarFileLoaded += LoadCompleted; - m_archiverModule.DearchiveRegion(archiveReadStream); - } - + m_scene.EventManager.OnOarFileLoaded += LoadCompleted; + m_oarEvent.Reset(); + m_archiverModule.DearchiveRegion(archiveReadStream); + + m_oarEvent.WaitOne(60000); + Assert.That(m_lastErrorMessage, Is.Null); RegionSettings loadedRs = m_scene.RegionInfo.RegionSettings; @@ -705,7 +705,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests Assert.AreEqual(UUID.Zero, loadedRs.TelehubObject); // because no object was found with the original UUID Assert.AreEqual(0, loadedRs.SpawnPoints().Count); } - + /// /// Test merging an OpenSim Region Archive into an existing scene /// @@ -737,13 +737,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests m_scene.AddNewSceneObject(new SceneObjectGroup(part2), false); // Write out this scene + scene.EventManager.OnOarFileSaved += SaveCompleted; + m_oarEvent.Reset(); + m_archiverModule.ArchiveRegion(archiveWriteStream); - lock (this) - { - m_archiverModule.ArchiveRegion(archiveWriteStream); - Monitor.Wait(this, 60000); - } + m_oarEvent.WaitOne(60000); } { @@ -754,10 +753,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests byte[] archive = archiveWriteStream.ToArray(); MemoryStream archiveReadStream = new MemoryStream(archive); + m_scene.EventManager.OnOarFileLoaded += LoadCompleted; Dictionary archiveOptions = new Dictionary(); archiveOptions.Add("merge", null); + m_oarEvent.Reset(); m_archiverModule.DearchiveRegion(archiveReadStream, Guid.Empty, archiveOptions); + m_oarEvent.WaitOne(60000); + SceneObjectPart object1Existing = m_scene.GetSceneObjectPart(part1.Name); Assert.That(object1Existing, Is.Not.Null, "object1 was not present after merge"); Assert.That(object1Existing.Name, Is.EqualTo(part1.Name), "object1 names not identical after merge"); @@ -816,7 +819,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests SceneObjectGroup sog1; SceneObjectGroup sog2; UUID ncAssetUuid; - + CreateTestObjects(scene, out sog1, out sog2, out ncAssetUuid); expectedPaths[scene.RegionInfo.RegionID] = new List(); @@ -829,18 +832,17 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests // Save OAR MemoryStream archiveWriteStream = new MemoryStream(); - m_scene.EventManager.OnOarFileSaved += SaveCompleted; Guid requestId = new Guid("00000000-0000-0000-0000-808080808080"); Dictionary options = new Dictionary(); options.Add("all", true); - lock (this) - { - m_archiverModule.ArchiveRegion(archiveWriteStream, requestId, options); - Monitor.Wait(this, 60000); - } + m_scene.EventManager.OnOarFileSaved += SaveCompleted; + m_oarEvent.Reset(); + m_archiverModule.ArchiveRegion(archiveWriteStream, requestId, options); + + m_oarEvent.WaitOne(60000); // Check that the OAR contains the expected data @@ -991,7 +993,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests tar.Close(); - + // Delete the current objects, to test that they're loaded from the OAR and didn't // just remain in the scene. m_sceneHelpers.SceneManager.ForEachScene(delegate(Scene scene) @@ -1007,11 +1009,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); - lock (this) - { - m_scene.EventManager.OnOarFileLoaded += LoadCompleted; - m_archiverModule.DearchiveRegion(archiveReadStream); - } + m_scene.EventManager.OnOarFileLoaded += LoadCompleted; + m_oarEvent.Reset(); + m_archiverModule.DearchiveRegion(archiveReadStream); + + m_oarEvent.WaitOne(60000); Assert.That(m_lastErrorMessage, Is.Null); @@ -1027,8 +1029,19 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests Assert.That(object1PartLoaded, Is.Not.Null, "object1 was not loaded"); Assert.That(object1PartLoaded.Name, Is.EqualTo(part1.Name), "object1 names not identical"); Assert.That(object1PartLoaded.GroupPosition, Is.EqualTo(part1.GroupPosition), "object1 group position not equal"); - Assert.That( - object1PartLoaded.RotationOffset, Is.EqualTo(part1.RotationOffset), "object1 rotation offset not equal"); + + Quaternion qtmp1 = new Quaternion ( + (float)Math.Round(object1PartLoaded.RotationOffset.X,5), + (float)Math.Round(object1PartLoaded.RotationOffset.Y,5), + (float)Math.Round(object1PartLoaded.RotationOffset.Z,5), + (float)Math.Round(object1PartLoaded.RotationOffset.W,5)); + Quaternion qtmp2 = new Quaternion ( + (float)Math.Round(part1.RotationOffset.X,5), + (float)Math.Round(part1.RotationOffset.Y,5), + (float)Math.Round(part1.RotationOffset.Z,5), + (float)Math.Round(part1.RotationOffset.W,5)); + + Assert.That(qtmp1, Is.EqualTo(qtmp2), "object1 rotation offset not equal"); Assert.That( object1PartLoaded.OffsetPosition, Is.EqualTo(part1.OffsetPosition), "object1 offset position not equal"); Assert.That(object1PartLoaded.SitTargetOrientation, Is.EqualTo(part1.SitTargetOrientation)); diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/Resources/test-sound.wav b/OpenSim/Region/CoreModules/World/Archiver/Tests/Resources/test-sound.wav old mode 100644 new mode 100755 diff --git a/OpenSim/Region/CoreModules/World/Cloud/CloudModule.cs b/OpenSim/Region/CoreModules/World/Cloud/CloudModule.cs index d217f36..a450dd6 100644 --- a/OpenSim/Region/CoreModules/World/Cloud/CloudModule.cs +++ b/OpenSim/Region/CoreModules/World/Cloud/CloudModule.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.Threading; using Mono.Addins; using Nini.Config; using OpenMetaverse; @@ -39,16 +40,20 @@ namespace OpenSim.Region.CoreModules.World [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "CloudModule")] public class CloudModule : ICloudModule, INonSharedRegionModule { -// private static readonly log4net.ILog m_log +// private static readonly log4net.ILog m_log // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private uint m_frame = 0; private int m_frameUpdateRate = 1000; - private Random m_rndnums = new Random(Environment.TickCount); + private Random m_rndnums; private Scene m_scene = null; private bool m_ready = false; private bool m_enabled = false; private float m_cloudDensity = 1.0F; private float[] cloudCover = new float[16 * 16]; + private int m_dataVersion; + private bool m_busy; + private object cloudlock = new object(); + public void Initialise(IConfigSource config) { @@ -70,11 +75,17 @@ namespace OpenSim.Region.CoreModules.World m_scene = scene; - scene.EventManager.OnNewClient += CloudsToClient; scene.RegisterModuleInterface(this); - scene.EventManager.OnFrame += CloudUpdate; + int seed = Environment.TickCount; + seed += (int)(scene.RegionInfo.RegionLocX << 16); + seed += (int)(scene.RegionInfo.RegionLocY); + m_rndnums = new Random(seed); GenerateCloudCover(); + m_dataVersion = (int)m_scene.AllocateLocalId(); + + scene.EventManager.OnNewClient += CloudsToClient; + scene.EventManager.OnFrame += CloudUpdate; m_ready = true; } @@ -89,7 +100,6 @@ namespace OpenSim.Region.CoreModules.World m_scene.EventManager.OnNewClient -= CloudsToClient; m_scene.EventManager.OnFrame -= CloudUpdate; m_scene.UnregisterModuleInterface(this); - m_scene = null; } @@ -127,7 +137,8 @@ namespace OpenSim.Region.CoreModules.World if (cloudCover != null) { - cover = cloudCover[y * 16 + x]; + lock(cloudlock) + cover = cloudCover[y * 16 + x]; } return cover; @@ -152,7 +163,7 @@ namespace OpenSim.Region.CoreModules.World columnRight = 0; columnLeft = x - 1; } - else + else { columnRight = x + 1; columnLeft = x - 1; @@ -174,40 +185,65 @@ namespace OpenSim.Region.CoreModules.World rowAbove = y + 1; rowBelow = y - 1; } - float neighborAverage = (cloudCover[rowBelow * 16 + columnLeft] + - cloudCover[y * 16 + columnLeft] + - cloudCover[rowAbove * 16 + columnLeft] + - cloudCover[rowBelow * 16 + x] + - cloudCover[rowAbove * 16 + x] + - cloudCover[rowBelow * 16 + columnRight] + - cloudCover[y * 16 + columnRight] + - cloudCover[rowAbove * 16 + columnRight] + + float neighborAverage = (cloudCover[rowBelow * 16 + columnLeft] + + cloudCover[y * 16 + columnLeft] + + cloudCover[rowAbove * 16 + columnLeft] + + cloudCover[rowBelow * 16 + x] + + cloudCover[rowAbove * 16 + x] + + cloudCover[rowBelow * 16 + columnRight] + + cloudCover[y * 16 + columnRight] + + cloudCover[rowAbove * 16 + columnRight] + cloudCover[y * 16 + x]) / 9; newCover[y * 16 + x] = ((neighborAverage / m_cloudDensity) + 0.175f) % 1.0f; newCover[y * 16 + x] *= m_cloudDensity; } } Array.Copy(newCover, cloudCover, 16 * 16); + m_dataVersion++; } - - private void CloudUpdate() - { - if (((m_frame++ % m_frameUpdateRate) != 0) || !m_ready || (m_cloudDensity == 0)) - { - return; - } - UpdateCloudCover(); + + private void CloudUpdate() + { + if ((!m_ready || m_busy || m_cloudDensity == 0 || + (m_frame++ % m_frameUpdateRate) != 0)) + return; + + if(Monitor.TryEnter(cloudlock)) + { + m_busy = true; + Util.FireAndForget(delegate + { + try + { + lock(cloudlock) + { + UpdateCloudCover(); + m_scene.ForEachClient(delegate(IClientAPI client) + { + client.SendCloudData(m_dataVersion, cloudCover); + }); + } + } + finally + { + m_busy = false; + } + }, + null, "CloudModuleUpdate"); + Monitor.Exit(cloudlock); + } } public void CloudsToClient(IClientAPI client) { if (m_ready) { - client.SendCloudData(cloudCover); + lock(cloudlock) + client.SendCloudData(m_dataVersion, cloudCover); } } - + /// /// Calculate the cloud cover over the region. /// diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateConnector.cs b/OpenSim/Region/CoreModules/World/Estate/EstateConnector.cs new file mode 100644 index 0000000..8001c3c --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Estate/EstateConnector.cs @@ -0,0 +1,228 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 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.Services.Interfaces; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; +using OpenSim.Server.Base; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; + +using OpenMetaverse; +using log4net; + +namespace OpenSim.Region.CoreModules.World.Estate +{ + public class EstateConnector + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected EstateModule m_EstateModule; + private string token; + uint port = 0; + + public EstateConnector(EstateModule module, string _token, uint _port) + { + m_EstateModule = module; + token = _token; + port = _port; + } + + public void SendTeleportHomeOneUser(uint EstateID, UUID PreyID) + { + Dictionary sendData = new Dictionary(); + sendData["METHOD"] = "teleport_home_one_user"; + sendData["TOKEN"] = token; + + sendData["EstateID"] = EstateID.ToString(); + sendData["PreyID"] = PreyID.ToString(); + + SendToEstate(EstateID, sendData); + } + + public void SendTeleportHomeAllUsers(uint EstateID) + { + Dictionary sendData = new Dictionary(); + sendData["METHOD"] = "teleport_home_all_users"; + sendData["TOKEN"] = token; + + sendData["EstateID"] = EstateID.ToString(); + + SendToEstate(EstateID, sendData); + } + + public bool SendUpdateCovenant(uint EstateID, UUID CovenantID) + { + Dictionary sendData = new Dictionary(); + sendData["METHOD"] = "update_covenant"; + sendData["TOKEN"] = token; + + sendData["CovenantID"] = CovenantID.ToString(); + sendData["EstateID"] = EstateID.ToString(); + + // Handle local regions locally + // + foreach (Scene s in m_EstateModule.Scenes) + { + if (s.RegionInfo.EstateSettings.EstateID == EstateID) + s.RegionInfo.RegionSettings.Covenant = CovenantID; +// s.ReloadEstateData(); + } + + SendToEstate(EstateID, sendData); + + return true; + } + + public bool SendUpdateEstate(uint EstateID) + { + Dictionary sendData = new Dictionary(); + sendData["METHOD"] = "update_estate"; + sendData["TOKEN"] = token; + + sendData["EstateID"] = EstateID.ToString(); + + // Handle local regions locally + // + foreach (Scene s in m_EstateModule.Scenes) + { + if (s.RegionInfo.EstateSettings.EstateID == EstateID) + s.ReloadEstateData(); + } + + SendToEstate(EstateID, sendData); + + return true; + } + + public void SendEstateMessage(uint EstateID, UUID FromID, string FromName, string Message) + { + Dictionary sendData = new Dictionary(); + sendData["METHOD"] = "estate_message"; + sendData["TOKEN"] = token; + + sendData["EstateID"] = EstateID.ToString(); + sendData["FromID"] = FromID.ToString(); + sendData["FromName"] = FromName; + sendData["Message"] = Message; + + SendToEstate(EstateID, sendData); + } + + private void SendToEstate(uint EstateID, Dictionary sendData) + { + List regions = m_EstateModule.Scenes[0].GetEstateRegions((int)EstateID); + + // Don't send to the same instance twice + List done = new List(); + + // Handle local regions locally + lock (m_EstateModule.Scenes) + { + foreach (Scene s in m_EstateModule.Scenes) + { + RegionInfo sreg = s.RegionInfo; + if (regions.Contains(sreg.RegionID)) + { + string url = sreg.ExternalHostName + ":" + sreg.HttpPort; + regions.Remove(sreg.RegionID); + if(!done.Contains(url)) // we may have older regs with same url lost in dbs + done.Add(url); + } + } + } + + if(regions.Count == 0) + return; + + Scene baseScene = m_EstateModule.Scenes[0]; + UUID ScopeID = baseScene.RegionInfo.ScopeID; + IGridService gridService = baseScene.GridService; + if(gridService == null) + return; + + // Send to remote regions + foreach (UUID regionID in regions) + { + GridRegion region = gridService.GetRegionByUUID(ScopeID, regionID); + if (region != null) + { + string url = region.ExternalHostName + ":" + region.HttpPort; + if(done.Contains(url)) + continue; + Call(region, sendData); + done.Add(url); + } + } + } + + private bool Call(GridRegion region, Dictionary sendData) + { + string reqString = ServerUtils.BuildQueryString(sendData); + // m_log.DebugFormat("[XESTATE CONNECTOR]: queryString = {0}", reqString); + try + { + string url = ""; + if(port != 0) + url = "http://" + region.ExternalHostName + ":" + port + "/"; + else + url = region.ServerURI; + + string reply = SynchronousRestFormsRequester.MakeRequest("POST", + url + "estate", + reqString); + if (reply != string.Empty) + { + Dictionary replyData = ServerUtils.ParseXmlResponse(reply); + + if (replyData.ContainsKey("RESULT")) + { + if (replyData["RESULT"].ToString().ToLower() == "true") + return true; + else + return false; + } + else + m_log.DebugFormat("[XESTATE CONNECTOR]: reply data does not contain result field"); + + } + else + m_log.DebugFormat("[XESTATE CONNECTOR]: received empty reply"); + } + catch (Exception e) + { + m_log.DebugFormat("[XESTATE CONNECTOR]: Exception when contacting remote sim: {0}", e.Message); + } + + return false; + } + } +} diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs index 702b503..7879f83 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs @@ -49,18 +49,18 @@ namespace OpenSim.Region.CoreModules.World.Estate public class EstateManagementCommands { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + protected EstateManagementModule m_module; public EstateManagementCommands(EstateManagementModule module) { m_module = module; } - + public void Initialise() - { + { // m_log.DebugFormat("[ESTATE MODULE]: Setting up estate commands for region {0}", m_module.Scene.RegionInfo.RegionName); - + m_module.Scene.AddCommand("Regions", m_module, "set terrain texture", "set terrain texture [] []", "Sets the terrain to , if or are specified, it will only " + @@ -77,14 +77,14 @@ namespace OpenSim.Region.CoreModules.World.Estate m_module.Scene.AddCommand("Regions", m_module, "set water height", "set water height [] []", - "Sets the water height in meters. If and are specified, it will only set it on regions with a matching coordinate. " + + "Sets the water height in meters. If and are specified, it will only set it on regions with a matching coordinate. " + "Specify -1 in or to wildcard that coordinate.", consoleSetWaterHeight); m_module.Scene.AddCommand( "Estates", m_module, "estate show", "estate show", "Shows all estates on the simulator.", ShowEstatesCommand); } - + public void Close() {} #region CommandHandlers @@ -120,7 +120,7 @@ namespace OpenSim.Region.CoreModules.World.Estate m_module.Scene.RegionInfo.RegionSettings.TerrainTexture4 = texture; break; } - + m_module.Scene.RegionInfo.RegionSettings.Save(); m_module.TriggerRegionInfoChange(); m_module.sendRegionHandshakeToAll(); @@ -130,7 +130,7 @@ namespace OpenSim.Region.CoreModules.World.Estate protected void consoleSetWaterHeight(string module, string[] args) { string heightstring = args[3]; - + int x = (args.Length > 4 ? int.Parse(args[4]) : -1); int y = (args.Length > 5 ? int.Parse(args[5]) : -1); @@ -143,13 +143,13 @@ namespace OpenSim.Region.CoreModules.World.Estate m_log.Debug("[ESTATEMODULE]: Setting water height in " + m_module.Scene.RegionInfo.RegionName + " to " + string.Format(" {0}", selectedheight)); m_module.Scene.RegionInfo.RegionSettings.WaterHeight = selectedheight; - + m_module.Scene.RegionInfo.RegionSettings.Save(); m_module.TriggerRegionInfoChange(); m_module.sendRegionHandshakeToAll(); } } - } + } protected void consoleSetTerrainHeights(string module, string[] args) { string num = args[3]; @@ -198,31 +198,31 @@ namespace OpenSim.Region.CoreModules.World.Estate m_module.Scene.RegionInfo.RegionSettings.Elevation2NE = highValue; break; } - + m_module.Scene.RegionInfo.RegionSettings.Save(); m_module.TriggerRegionInfoChange(); m_module.sendRegionHandshakeToAll(); } } - } - + } + protected void ShowEstatesCommand(string module, string[] cmd) { - StringBuilder report = new StringBuilder(); + StringBuilder report = new StringBuilder(); RegionInfo ri = m_module.Scene.RegionInfo; EstateSettings es = ri.EstateSettings; - - report.AppendFormat("Estate information for region {0}\n", ri.RegionName); + + report.AppendFormat("Estate information for region {0}\n", ri.RegionName); report.AppendFormat( "{0,-20} {1,-7} {2,-20}\n", "Estate Name", "ID", "Owner"); - + report.AppendFormat( - "{0,-20} {1,-7} {2,-20}\n", + "{0,-20} {1,-7} {2,-20}\n", es.EstateName, es.EstateID, m_module.UserManager.GetUserName(es.EstateOwner)); - + MainConsole.Instance.Output(report.ToString()); } #endregion diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index 80fa08a..3c45b68 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -33,15 +33,19 @@ using System.Linq; using System.Reflection; using System.Security; using System.Timers; +using System.Threading; using log4net; using Mono.Addins; using Nini.Config; using OpenMetaverse; using OpenSim.Framework; +using OpenSim.Framework.Monitoring; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Services.Interfaces; using RegionFlags = OpenMetaverse.RegionFlags; +using Timer = System.Timers.Timer; + namespace OpenSim.Region.CoreModules.World.Estate { @@ -53,8 +57,8 @@ namespace OpenSim.Region.CoreModules.World.Estate private Timer m_regionChangeTimer = new Timer(); public Scene Scene { get; private set; } public IUserManagement UserManager { get; private set; } - - protected EstateManagementCommands m_commands; + + protected EstateManagementCommands m_commands; /// /// If false, region restart requests from the client are blocked even if they are otherwise legitimate. @@ -67,14 +71,18 @@ namespace OpenSim.Region.CoreModules.World.Estate public event ChangeDelegate OnRegionInfoChange; public event ChangeDelegate OnEstateInfoChange; public event MessageDelegate OnEstateMessage; + public event EstateTeleportOneUserHomeRequest OnEstateTeleportOneUserHomeRequest; + public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest; + + private int m_delayCount = 0; #region Region Module interface - + public string Name { get { return "EstateManagementModule"; } } - - public Type ReplaceableInterface { get { return null; } } - public void Initialise(IConfigSource source) + public Type ReplaceableInterface { get { return null; } } + + public void Initialise(IConfigSource source) { AllowRegionRestartFromClient = true; @@ -83,7 +91,7 @@ namespace OpenSim.Region.CoreModules.World.Estate if (config != null) AllowRegionRestartFromClient = config.GetBoolean("AllowRegionRestartFromClient", true); } - + public void AddRegion(Scene scene) { Scene = scene; @@ -95,20 +103,24 @@ namespace OpenSim.Region.CoreModules.World.Estate m_commands = new EstateManagementCommands(this); m_commands.Initialise(); + + m_regionChangeTimer.Interval = 10000; + m_regionChangeTimer.Elapsed += RaiseRegionInfoChange; + m_regionChangeTimer.AutoReset = false; } - - public void RemoveRegion(Scene scene) {} - + + public void RemoveRegion(Scene scene) {} + public void RegionLoaded(Scene scene) { // Sets up the sun module based no the saved Estate and Region Settings // DO NOT REMOVE or the sun will stop working scene.TriggerEstateSunUpdate(); - - UserManager = scene.RequestModuleInterface(); + + UserManager = scene.RequestModuleInterface(); } - public void Close() + public void Close() { m_commands.Close(); } @@ -142,6 +154,10 @@ namespace OpenSim.Region.CoreModules.World.Estate flags |= RegionFlags.AllowParcelChanges; if (Scene.RegionInfo.RegionSettings.BlockShowInSearch) flags |= RegionFlags.BlockParcelSearch; + if (Scene.RegionInfo.RegionSettings.GodBlockSearch) + flags |= (RegionFlags)(1 << 11); + if (Scene.RegionInfo.RegionSettings.Casino) + flags |= (RegionFlags)(1 << 10); if (Scene.RegionInfo.RegionSettings.FixedSun) flags |= RegionFlags.SunFixed; @@ -194,6 +210,14 @@ namespace OpenSim.Region.CoreModules.World.Estate change(Scene.RegionInfo.RegionID); } + protected void RaiseRegionInfoChange(object sender, ElapsedEventArgs e) + { + ChangeDelegate change = OnRegionInfoChange; + + if (change != null) + change(Scene.RegionInfo.RegionID); + } + public void TriggerRegionInfoChange() { m_regionChangeTimer.Stop(); @@ -423,7 +447,7 @@ namespace OpenSim.Region.CoreModules.World.Estate Scene.RegionInfo.EstateSettings.EstateID); remote_client.SendEstateList(invoice, - (int)Constants.EstateAccessCodex.AccessOptions, + (int)Constants.EstateAccessCodex.AllowedAccess, Scene.RegionInfo.EstateSettings.EstateAccess, Scene.RegionInfo.EstateSettings.EstateID); @@ -462,7 +486,7 @@ namespace OpenSim.Region.CoreModules.World.Estate if((byte)maxAgents <= Scene.RegionInfo.AgentCapacity) Scene.RegionInfo.RegionSettings.AgentLimit = (byte) maxAgents; - else + else Scene.RegionInfo.RegionSettings.AgentLimit = Scene.RegionInfo.AgentCapacity; Scene.RegionInfo.RegionSettings.ObjectBonus = objectBonusFactor; @@ -554,6 +578,7 @@ namespace OpenSim.Region.CoreModules.World.Estate bool UseEstateSun, bool UseFixedSun, float SunHour, bool UseGlobal, bool EstateFixedSun, float EstateSunHour) { + double lastwaterlevel = Scene.RegionInfo.RegionSettings.WaterHeight; // Water Height Scene.RegionInfo.RegionSettings.WaterHeight = WaterHeight; @@ -566,6 +591,9 @@ namespace OpenSim.Region.CoreModules.World.Estate Scene.RegionInfo.RegionSettings.FixedSun = UseFixedSun; Scene.RegionInfo.RegionSettings.SunPosition = SunHour; + if(Scene.PhysicsEnabled && Scene.PhysicsScene != null && lastwaterlevel != WaterHeight) + Scene.PhysicsScene.SetWaterLevel(WaterHeight); + Scene.TriggerEstateSunUpdate(); //m_log.Debug("[ESTATE]: UFS: " + UseFixedSun.ToString()); @@ -587,6 +615,16 @@ namespace OpenSim.Region.CoreModules.World.Estate IRestartModule restartModule = Scene.RequestModuleInterface(); if (restartModule != null) { + if (timeInSeconds == -1) + { + m_delayCount++; + if (m_delayCount > 3) + return; + + restartModule.DelayRestart(3600, "Restart delayed by region manager"); + return; + } + List times = new List(); while (timeInSeconds > 0) { @@ -602,7 +640,7 @@ namespace OpenSim.Region.CoreModules.World.Estate restartModule.ScheduleRestart(UUID.Zero, "Region will restart in {0}", times.ToArray(), false); m_log.InfoFormat( - "User {0} requested restart of region {1} in {2} seconds", + "User {0} requested restart of region {1} in {2} seconds", remoteClient.Name, Scene.Name, times.Count != 0 ? times[0] : 0); } } @@ -610,236 +648,363 @@ namespace OpenSim.Region.CoreModules.World.Estate private void handleChangeEstateCovenantRequest(IClientAPI remoteClient, UUID estateCovenantID) { // m_log.DebugFormat( -// "[ESTATE MANAGEMENT MODULE]: Handling request from {0} to change estate covenant to {1}", +// "[ESTATE MANAGEMENT MODULE]: Handling request from {0} to change estate covenant to {1}", // remoteClient.Name, estateCovenantID); - + Scene.RegionInfo.RegionSettings.Covenant = estateCovenantID; Scene.RegionInfo.RegionSettings.CovenantChangedDateTime = Util.UnixTimeSinceEpoch(); Scene.RegionInfo.RegionSettings.Save(); TriggerRegionInfoChange(); } - private void handleEstateAccessDeltaRequest(IClientAPI remote_client, UUID invoice, int estateAccessType, UUID user) + private object deltareqLock = new object(); + private bool runnigDeltaExec = false; + + private class EstateAccessDeltaRequest + { + public IClientAPI remote_client; + public UUID invoice; + public int estateAccessType; + public UUID user; + } + + private OpenSim.Framework.BlockingQueue deltaRequests = new OpenSim.Framework.BlockingQueue(); + + private void handleEstateAccessDeltaRequest(IClientAPI _remote_client, UUID _invoice, int _estateAccessType, UUID _user) { // EstateAccessDelta handles Estate Managers, Sim Access, Sim Banlist, allowed Groups.. etc. - if (user == Scene.RegionInfo.EstateSettings.EstateOwner) + if (_user == Scene.RegionInfo.EstateSettings.EstateOwner) return; // never process EO - if ((estateAccessType & 4) != 0) // User add + EstateAccessDeltaRequest newreq = new EstateAccessDeltaRequest(); + newreq.remote_client = _remote_client; + newreq.invoice = _invoice; + newreq.estateAccessType = _estateAccessType; + newreq.user = _user; + + deltaRequests.Enqueue(newreq); + + lock(deltareqLock) { - if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true)) + if(!runnigDeltaExec) { - if ((estateAccessType & 1) != 0) // All estates + runnigDeltaExec = true; + WorkManager.RunInThreadPool(execDeltaRequests,null,"execDeltaRequests"); + } + } + } + + private void execDeltaRequests(object o) + { + IClientAPI remote_client; + UUID invoice; + int estateAccessType; + UUID user; + Dictionary changed = new Dictionary(); + Dictionary sendAllowedOrBanList = new Dictionary(); + Dictionary sendManagers = new Dictionary(); + Dictionary sendGroups = new Dictionary(); + + List otherEstates = new List(); + + bool sentAllowedFull = false; + bool sentBansFull = false; + bool sentGroupsFull = false; + bool sentManagersFull = false; + + while(Scene.IsRunning) + { + EstateAccessDeltaRequest req = deltaRequests.Dequeue(500); + + if(!Scene.IsRunning) + break; + + if(req == null) + { + if(changed.Count > 0) { - List estateIDs = Scene.EstateDataService.GetEstatesByOwner(Scene.RegionInfo.EstateSettings.EstateOwner); - EstateSettings estateSettings; + foreach(EstateSettings est in changed.Values) + Scene.EstateDataService.StoreEstateSettings(est); - foreach (int estateID in estateIDs) - { - if (estateID != Scene.RegionInfo.EstateSettings.EstateID) - { - estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); - estateSettings.AddEstateUser(user); - Scene.EstateDataService.StoreEstateSettings(estateSettings); - } - } + TriggerEstateInfoChange(); } - Scene.RegionInfo.EstateSettings.AddEstateUser(user); - Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings); + EstateSettings es = Scene.RegionInfo.EstateSettings; + foreach(KeyValuePair kvp in sendAllowedOrBanList) + { + IClientAPI cli = kvp.Key; + UUID invoive = kvp.Value; + cli.SendEstateList(invoive, (int)Constants.EstateAccessCodex.AllowedAccess, es.EstateAccess, es.EstateID); + cli.SendBannedUserList(invoive, es.EstateBans, es.EstateID); + } + sendAllowedOrBanList.Clear(); - TriggerEstateInfoChange(); - remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AccessOptions, Scene.RegionInfo.EstateSettings.EstateAccess, Scene.RegionInfo.EstateSettings.EstateID); + foreach(KeyValuePair kvp in sendManagers) + { + IClientAPI cli = kvp.Key; + cli.SendEstateList(kvp.Value, (int)Constants.EstateAccessCodex.EstateManagers, es.EstateManagers, es.EstateID); + } + foreach(KeyValuePair kvp in sendGroups) + { + IClientAPI cli = kvp.Key; + cli.SendEstateList(kvp.Value, (int)Constants.EstateAccessCodex.AllowedGroups, es.EstateGroups, es.EstateID); + } + otherEstates.Clear(); + sendAllowedOrBanList.Clear(); + sendManagers.Clear(); + sendGroups.Clear(); + changed.Clear(); + lock(deltareqLock) + { + if(deltaRequests.Count() != 0) + continue; + runnigDeltaExec = false; + return; + } } - else + + remote_client = req.remote_client; + if(!remote_client.IsActive) + continue; + + invoice = req.invoice; + user = req.user; + + estateAccessType = req.estateAccessType; + + bool needReply = ((estateAccessType & 1024) == 0); + bool doOtherEstates = ((estateAccessType & 3) != 0); + + EstateSettings thisSettings = Scene.RegionInfo.EstateSettings; + int thisEstateID =(int)thisSettings.EstateID; + + UUID agentID = remote_client.AgentId; + + bool isadmin = Scene.Permissions.IsAdministrator(agentID); + // just i case recheck rights + if (!isadmin && !Scene.Permissions.IsEstateManager(agentID)) { - remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions"); + remote_client.SendAlertMessage("Method EstateAccess Failed, you don't have permissions"); + continue; } - } - - if ((estateAccessType & 8) != 0) // User remove - { - if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true)) + otherEstates.Clear(); + if(doOtherEstates) { - if ((estateAccessType & 1) != 0) // All estates + UUID thisOwner = Scene.RegionInfo.EstateSettings.EstateOwner; + List estateIDs = Scene.EstateDataService.GetEstatesByOwner(thisOwner); + foreach (int estateID in estateIDs) { - List estateIDs = Scene.EstateDataService.GetEstatesByOwner(Scene.RegionInfo.EstateSettings.EstateOwner); + if (estateID == thisEstateID) + continue; + EstateSettings estateSettings; + if(changed.ContainsKey(estateID)) + estateSettings = changed[estateID]; + else + estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); + + if(!isadmin && !estateSettings.IsEstateManagerOrOwner(agentID)) + continue; + otherEstates.Add(estateSettings); + } + estateIDs.Clear(); + } - foreach (int estateID in estateIDs) + // the commands + // first the ones allowed for estate managers on this region + if ((estateAccessType & 4) != 0) // User add + { + if(thisSettings.EstateUsersCount() >= (int)Constants.EstateAccessLimits.AllowedAccess) + { + if(!sentAllowedFull) { - if (estateID != Scene.RegionInfo.EstateSettings.EstateID) + sentAllowedFull = true; + remote_client.SendAlertMessage("Estate Allowed users list is full"); + } + } + else + { + if (doOtherEstates) + { + foreach (EstateSettings estateSettings in otherEstates) { - estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); - estateSettings.RemoveEstateUser(user); - Scene.EstateDataService.StoreEstateSettings(estateSettings); + if(!isadmin && !estateSettings.IsEstateManagerOrOwner(agentID)) + continue; + if(estateSettings.EstateUsersCount() >= (int)Constants.EstateAccessLimits.AllowedAccess) + continue; + estateSettings.AddEstateUser(user); + estateSettings.RemoveBan(user); + changed[(int)estateSettings.EstateID] = estateSettings; } } - } - Scene.RegionInfo.EstateSettings.RemoveEstateUser(user); - Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings); + thisSettings.AddEstateUser(user); + thisSettings.RemoveBan(user); + changed[thisEstateID] = thisSettings;; - TriggerEstateInfoChange(); - remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AccessOptions, Scene.RegionInfo.EstateSettings.EstateAccess, Scene.RegionInfo.EstateSettings.EstateID); + if(needReply) + sendAllowedOrBanList[remote_client] = invoice; + } } - else + + if ((estateAccessType & 8) != 0) // User remove { - remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions"); + if (doOtherEstates) // All estates + { + foreach (EstateSettings estateSettings in otherEstates) + { + if(!isadmin && !estateSettings.IsEstateManagerOrOwner(agentID)) + continue; + estateSettings.RemoveEstateUser(user); + changed[(int)estateSettings.EstateID] = estateSettings; + } + } + + thisSettings.RemoveEstateUser(user); + changed[thisEstateID] = thisSettings;; + + if(needReply) + sendAllowedOrBanList[remote_client] = invoice; } - } - if ((estateAccessType & 16) != 0) // Group add - { - if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true)) + if ((estateAccessType & 16) != 0) // Group add { - if ((estateAccessType & 1) != 0) // All estates + if(thisSettings.EstateGroupsCount() >= (int)Constants.EstateAccessLimits.AllowedGroups) { - List estateIDs = Scene.EstateDataService.GetEstatesByOwner(Scene.RegionInfo.EstateSettings.EstateOwner); - EstateSettings estateSettings; - - foreach (int estateID in estateIDs) + if(!sentGroupsFull) + { + sentGroupsFull = true; + remote_client.SendAlertMessage("Estate Allowed groups list is full"); + } + } + else + { + if (doOtherEstates) // All estates { - if (estateID != Scene.RegionInfo.EstateSettings.EstateID) + foreach (EstateSettings estateSettings in otherEstates) { - estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); + if(!isadmin && !estateSettings.IsEstateManagerOrOwner(agentID)) + continue; + if(estateSettings.EstateGroupsCount() >= (int)Constants.EstateAccessLimits.AllowedGroups) + continue; estateSettings.AddEstateGroup(user); - Scene.EstateDataService.StoreEstateSettings(estateSettings); + changed[(int)estateSettings.EstateID] = estateSettings; } } - } - Scene.RegionInfo.EstateSettings.AddEstateGroup(user); - Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings); + thisSettings.AddEstateGroup(user); + changed[thisEstateID] = thisSettings; - TriggerEstateInfoChange(); - remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AllowedGroups, Scene.RegionInfo.EstateSettings.EstateGroups, Scene.RegionInfo.EstateSettings.EstateID); - } - else - { - remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions"); + sendGroups[remote_client] = invoice; + } } - } - if ((estateAccessType & 32) != 0) // Group remove - { - if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true)) + if ((estateAccessType & 32) != 0) // Group remove { - if ((estateAccessType & 1) != 0) // All estates + if (doOtherEstates) // All estates { - List estateIDs = Scene.EstateDataService.GetEstatesByOwner(Scene.RegionInfo.EstateSettings.EstateOwner); - EstateSettings estateSettings; - - foreach (int estateID in estateIDs) + foreach (EstateSettings estateSettings in otherEstates) { - if (estateID != Scene.RegionInfo.EstateSettings.EstateID) - { - estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); - estateSettings.RemoveEstateGroup(user); - Scene.EstateDataService.StoreEstateSettings(estateSettings); - } + if(!isadmin && !estateSettings.IsEstateManagerOrOwner(agentID)) + continue; + estateSettings.RemoveEstateGroup(user); + changed[(int)estateSettings.EstateID] = estateSettings; } } - Scene.RegionInfo.EstateSettings.RemoveEstateGroup(user); - Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings); + thisSettings.RemoveEstateGroup(user); + changed[thisEstateID] = thisSettings; - TriggerEstateInfoChange(); - remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AllowedGroups, Scene.RegionInfo.EstateSettings.EstateGroups, Scene.RegionInfo.EstateSettings.EstateID); + sendGroups[remote_client] = invoice; } - else - { - remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions"); - } - } - if ((estateAccessType & 64) != 0) // Ban add - { - if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, false)) + if ((estateAccessType & 64) != 0) // Ban add { - EstateBan[] banlistcheck = Scene.RegionInfo.EstateSettings.EstateBans; - bool alreadyInList = false; - - for (int i = 0; i < banlistcheck.Length; i++) + if(thisSettings.EstateBansCount() >= (int)Constants.EstateAccessLimits.EstateBans) { - if (user == banlistcheck[i].BannedUserID) + if(!sentBansFull) { - alreadyInList = true; - break; + sentBansFull = true; + remote_client.SendAlertMessage("Estate Ban list is full"); } - } - if (!alreadyInList) + else { + EstateBan[] banlistcheck = Scene.RegionInfo.EstateSettings.EstateBans; - if ((estateAccessType & 1) != 0) // All estates - { - List estateIDs = Scene.EstateDataService.GetEstatesByOwner(Scene.RegionInfo.EstateSettings.EstateOwner); - EstateSettings estateSettings; + bool alreadyInList = false; - foreach (int estateID in estateIDs) + for (int i = 0; i < banlistcheck.Length; i++) + { + if (user == banlistcheck[i].BannedUserID) + { + alreadyInList = true; + break; + } + } + if (!alreadyInList) + { + if (doOtherEstates) // All estates { - if (estateID != Scene.RegionInfo.EstateSettings.EstateID) + foreach (EstateSettings estateSettings in otherEstates) { + if(!isadmin && !estateSettings.IsEstateManagerOrOwner(agentID)) + continue; + + if(estateSettings.EstateBansCount() >= (int)Constants.EstateAccessLimits.EstateBans) + continue; + EstateBan bitem = new EstateBan(); bitem.BannedUserID = user; - bitem.EstateID = (uint)estateID; + bitem.EstateID = estateSettings.EstateID; bitem.BannedHostAddress = "0.0.0.0"; bitem.BannedHostIPMask = "0.0.0.0"; - estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); estateSettings.AddBan(bitem); - Scene.EstateDataService.StoreEstateSettings(estateSettings); + estateSettings.RemoveEstateUser(user); + changed[(int)estateSettings.EstateID] = estateSettings; } } - } - EstateBan item = new EstateBan(); + EstateBan item = new EstateBan(); - item.BannedUserID = user; - item.EstateID = Scene.RegionInfo.EstateSettings.EstateID; - item.BannedHostAddress = "0.0.0.0"; - item.BannedHostIPMask = "0.0.0.0"; + item.BannedUserID = user; + item.EstateID = Scene.RegionInfo.EstateSettings.EstateID; + item.BannedHostAddress = "0.0.0.0"; + item.BannedHostIPMask = "0.0.0.0"; - Scene.RegionInfo.EstateSettings.AddBan(item); - Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings); + thisSettings.AddBan(item); + thisSettings.RemoveEstateUser(user); + changed[thisEstateID] = thisSettings; - TriggerEstateInfoChange(); - - ScenePresence s = Scene.GetScenePresence(user); - if (s != null) - { - if (!s.IsChildAgent) + ScenePresence s = Scene.GetScenePresence(user); + if (s != null) { - if (!Scene.TeleportClientHome(user, s.ControllingClient)) + if (!s.IsChildAgent) { - s.ControllingClient.Kick("Your access to the region was revoked and TP home failed - you have been logged out."); - Scene.CloseAgent(s.UUID, false); + if (!Scene.TeleportClientHome(user, s.ControllingClient)) + { + s.ControllingClient.Kick("Your access to the region was revoked and TP home failed - you have been logged out."); + Scene.CloseAgent(s.UUID, false); + } } } } - - } - else - { - remote_client.SendAlertMessage("User is already on the region ban list"); + else + { + remote_client.SendAlertMessage("User is already on the region ban list"); + } + //Scene.RegionInfo.regionBanlist.Add(Manager(user); + if(needReply) + sendAllowedOrBanList[remote_client] = invoice; } - //Scene.RegionInfo.regionBanlist.Add(Manager(user); - remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID); - } - else - { - remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions"); } - } - if ((estateAccessType & 128) != 0) // Ban remove - { - if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, false)) + if ((estateAccessType & 128) != 0) // Ban remove { EstateBan[] banlistcheck = Scene.RegionInfo.EstateSettings.EstateBans; @@ -855,107 +1020,93 @@ namespace OpenSim.Region.CoreModules.World.Estate break; } } - + if (alreadyInList && listitem != null) { - if ((estateAccessType & 1) != 0) // All estates + if (doOtherEstates) // All estates { - List estateIDs = Scene.EstateDataService.GetEstatesByOwner(Scene.RegionInfo.EstateSettings.EstateOwner); - EstateSettings estateSettings; - - foreach (int estateID in estateIDs) + foreach (EstateSettings estateSettings in otherEstates) { - if (estateID != Scene.RegionInfo.EstateSettings.EstateID) - { - estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); - estateSettings.RemoveBan(user); - Scene.EstateDataService.StoreEstateSettings(estateSettings); - } + if(!isadmin && !estateSettings.IsEstateManagerOrOwner(agentID)) + continue; + estateSettings.RemoveBan(user); + changed[(int)estateSettings.EstateID] = estateSettings; } } - Scene.RegionInfo.EstateSettings.RemoveBan(listitem.BannedUserID); - Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings); - - TriggerEstateInfoChange(); + thisSettings.RemoveBan(listitem.BannedUserID); + changed[thisEstateID] = thisSettings; } else { remote_client.SendAlertMessage("User is not on the region ban list"); } - - //Scene.RegionInfo.regionBanlist.Add(Manager(user); - remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID); + + if(needReply) + sendAllowedOrBanList[remote_client] = invoice; } - else + + // last the ones only for owners of this region + if (!Scene.Permissions.CanIssueEstateCommand(agentID, true)) { - remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions"); + remote_client.SendAlertMessage("Method EstateAccess Failed, you don't have permissions"); + continue; } - } - if ((estateAccessType & 256) != 0) // Manager add - { - if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true)) + if ((estateAccessType & 256) != 0) // Manager add { - if ((estateAccessType & 1) != 0) // All estates + if(thisSettings.EstateManagersCount() >= (int)Constants.EstateAccessLimits.EstateManagers) { - List estateIDs = Scene.EstateDataService.GetEstatesByOwner(Scene.RegionInfo.EstateSettings.EstateOwner); - EstateSettings estateSettings; - - foreach (int estateID in estateIDs) + if(!sentManagersFull) + { + sentManagersFull = true; + remote_client.SendAlertMessage("Estate Managers list is full"); + } + } + else + { + if (doOtherEstates) // All estates { - if (estateID != Scene.RegionInfo.EstateSettings.EstateID) + foreach (EstateSettings estateSettings in otherEstates) { - estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); + if(!isadmin && !estateSettings.IsEstateOwner(agentID)) // redundante check? + continue; + if(estateSettings.EstateManagersCount() >= (int)Constants.EstateAccessLimits.EstateManagers) + continue; estateSettings.AddEstateManager(user); - Scene.EstateDataService.StoreEstateSettings(estateSettings); + changed[(int)estateSettings.EstateID] = estateSettings; } } - } - Scene.RegionInfo.EstateSettings.AddEstateManager(user); - Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings); + thisSettings.AddEstateManager(user); + changed[thisEstateID] = thisSettings; - TriggerEstateInfoChange(); - remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.EstateManagers, Scene.RegionInfo.EstateSettings.EstateManagers, Scene.RegionInfo.EstateSettings.EstateID); - } - else - { - remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions"); + sendManagers[remote_client] = invoice; + } } - } - if ((estateAccessType & 512) != 0) // Manager remove - { - if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true)) + if ((estateAccessType & 512) != 0) // Manager remove { - if ((estateAccessType & 1) != 0) // All estates + if (doOtherEstates) // All estates { - List estateIDs = Scene.EstateDataService.GetEstatesByOwner(Scene.RegionInfo.EstateSettings.EstateOwner); - EstateSettings estateSettings; - - foreach (int estateID in estateIDs) + foreach (EstateSettings estateSettings in otherEstates) { - if (estateID != Scene.RegionInfo.EstateSettings.EstateID) - { - estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); - estateSettings.RemoveEstateManager(user); - Scene.EstateDataService.StoreEstateSettings(estateSettings); - } + if(!isadmin && !estateSettings.IsEstateOwner(agentID)) + continue; + + estateSettings.RemoveEstateManager(user); + changed[(int)estateSettings.EstateID] = estateSettings; } } - Scene.RegionInfo.EstateSettings.RemoveEstateManager(user); - Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings); + thisSettings.RemoveEstateManager(user); + changed[thisEstateID] = thisSettings; - TriggerEstateInfoChange(); - remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.EstateManagers, Scene.RegionInfo.EstateSettings.EstateManagers, Scene.RegionInfo.EstateSettings.EstateID); - } - else - { - remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions"); + sendManagers[remote_client] = invoice; } } + lock(deltareqLock) + runnigDeltaExec = false; } public void HandleOnEstateManageTelehub(IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1) @@ -1007,7 +1158,7 @@ namespace OpenSim.Region.CoreModules.World.Estate IClientAPI remote_client, UUID invoice, UUID senderID, UUID sessionID, string senderName, string message) { IDialogModule dm = Scene.RequestModuleInterface(); - + if (dm != null) dm.SendNotificationToUsersInRegion(senderID, senderName, message); } @@ -1044,13 +1195,20 @@ namespace OpenSim.Region.CoreModules.World.Estate private void handleEstateTeleportOneUserHomeRequest(IClientAPI remover_client, UUID invoice, UUID senderID, UUID prey) { + EstateTeleportOneUserHomeRequest evOverride = OnEstateTeleportOneUserHomeRequest; + if(evOverride != null) + { + evOverride(remover_client, invoice, senderID, prey); + return; + } + if (!Scene.Permissions.CanIssueEstateCommand(remover_client.AgentId, false)) return; if (prey != UUID.Zero) { ScenePresence s = Scene.GetScenePresence(prey); - if (s != null) + if (s != null && !s.IsDeleted && !s.IsInTransit) { if (!Scene.TeleportClientHome(prey, s.ControllingClient)) { @@ -1063,6 +1221,13 @@ namespace OpenSim.Region.CoreModules.World.Estate private void handleEstateTeleportAllUsersHomeRequest(IClientAPI remover_client, UUID invoice, UUID senderID) { + EstateTeleportAllUsersHomeRequest evOverride = OnEstateTeleportAllUsersHomeRequest; + if(evOverride != null) + { + evOverride(remover_client, invoice, senderID); + return; + } + if (!Scene.Permissions.CanIssueEstateCommand(remover_client.AgentId, false)) return; @@ -1084,7 +1249,7 @@ namespace OpenSim.Region.CoreModules.World.Estate } }); } - + private void AbortTerrainXferHandler(IClientAPI remoteClient, ulong XferID) { lock (this) @@ -1167,7 +1332,7 @@ namespace OpenSim.Region.CoreModules.World.Estate if (TerrainUploader == null) { m_log.DebugFormat( - "[TERRAIN]: Started receiving terrain upload for region {0} from {1}", + "[TERRAIN]: Started receiving terrain upload for region {0} from {1}", Scene.Name, remote_client.Name); TerrainUploader = new EstateTerrainXferHandler(remote_client, clientFileName); @@ -1187,7 +1352,7 @@ namespace OpenSim.Region.CoreModules.World.Estate { // Save terrain here ITerrainModule terr = Scene.RequestModuleInterface(); - + if (terr != null) { // m_log.Warn("[CLIENT]: Got Request to Send Terrain in region " + Scene.RegionInfo.RegionName); @@ -1197,15 +1362,24 @@ namespace OpenSim.Region.CoreModules.World.Estate } terr.SaveToFile(Util.dataDir() + "/terrain.raw"); - FileStream input = new FileStream(Util.dataDir() + "/terrain.raw", FileMode.Open); - byte[] bdata = new byte[input.Length]; - input.Read(bdata, 0, (int)input.Length); + byte[] bdata; + using(FileStream input = new FileStream(Util.dataDir() + "/terrain.raw",FileMode.Open)) + { + bdata = new byte[input.Length]; + input.Read(bdata, 0, (int)input.Length); + } + if(bdata == null || bdata.Length == 0) + { + remote_client.SendAlertMessage("Terrain error"); + return; + } + remote_client.SendAlertMessage("Terrain file written, starting download..."); - Scene.XferManager.AddNewFile("terrain.raw", bdata); + string xfername = (UUID.Random()).ToString(); + Scene.XferManager.AddNewFile(xfername, bdata); m_log.DebugFormat("[CLIENT]: Sending terrain for region {0} to {1}", Scene.Name, remote_client.Name); - - remote_client.SendInitiateDownload("terrain.raw", clientFileName); + remote_client.SendInitiateDownload(xfername, clientFileName); } } @@ -1319,7 +1493,8 @@ namespace OpenSim.Region.CoreModules.World.Estate public void sendRegionInfoPacketToAll() { - Scene.ForEachRootClient(delegate(IClientAPI client) +// Scene.ForEachRootClient(delegate(IClientAPI client) + Scene.ForEachClient(delegate(IClientAPI client) { HandleRegionInfoRequest(client); }); @@ -1443,7 +1618,7 @@ namespace OpenSim.Region.CoreModules.World.Estate Scene.RegionInfo.EstateSettings.FixedSun, (float)Scene.RegionInfo.EstateSettings.SunPosition); - sendRegionInfoPacketToAll(); +// sendRegionInfoPacketToAll(); already done by setRegionTerrainSettings } @@ -1477,7 +1652,8 @@ namespace OpenSim.Region.CoreModules.World.Estate sendRegionHandshake(client); } - private uint GetEstateFlags() + + public uint GetEstateFlags() { RegionFlags flags = RegionFlags.None; diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateModule.cs new file mode 100644 index 0000000..f3c8aa8 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Estate/EstateModule.cs @@ -0,0 +1,271 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 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 Nwc.XmlRpc; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using OpenSim.Server.Base; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using Mono.Addins; + +namespace OpenSim.Region.CoreModules.World.Estate +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XEstate")] + public class EstateModule : ISharedRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected List m_Scenes = new List(); + protected bool m_InInfoUpdate = false; + private string token = "7db8eh2gvgg45jj"; + protected bool m_enabled = false; + + public bool InInfoUpdate + { + get { return m_InInfoUpdate; } + set { m_InInfoUpdate = value; } + } + + public List Scenes + { + get { return m_Scenes; } + } + + protected EstateConnector m_EstateConnector; + + public void Initialise(IConfigSource config) + { + uint port = MainServer.Instance.Port; + + IConfig estateConfig = config.Configs["Estates"]; + if (estateConfig != null) + { + if (estateConfig.GetString("EstateCommunicationsHandler", Name) == Name) + m_enabled = true; + else + return; + + port = (uint)estateConfig.GetInt("Port", 0); + // this will need to came from somewhere else + token = estateConfig.GetString("Token", token); + } + else + { + m_enabled = true; + } + + m_EstateConnector = new EstateConnector(this, token, port); + + if(port == 0) + port = MainServer.Instance.Port; + + // Instantiate the request handler + IHttpServer server = MainServer.GetHttpServer(port); + server.AddStreamHandler(new EstateRequestHandler(this, token)); + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public void AddRegion(Scene scene) + { + if (!m_enabled) + return; + + lock (m_Scenes) + m_Scenes.Add(scene); + } + + public void RegionLoaded(Scene scene) + { + if (!m_enabled) + return; + + IEstateModule em = scene.RequestModuleInterface(); + + em.OnRegionInfoChange += OnRegionInfoChange; + em.OnEstateInfoChange += OnEstateInfoChange; + em.OnEstateMessage += OnEstateMessage; + em.OnEstateTeleportOneUserHomeRequest += OnEstateTeleportOneUserHomeRequest; + em.OnEstateTeleportAllUsersHomeRequest += OnEstateTeleportAllUsersHomeRequest; + } + + public void RemoveRegion(Scene scene) + { + if (!m_enabled) + return; + + lock (m_Scenes) + m_Scenes.Remove(scene); + } + + public string Name + { + get { return "EstateModule"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + private Scene FindScene(UUID RegionID) + { + foreach (Scene s in Scenes) + { + if (s.RegionInfo.RegionID == RegionID) + return s; + } + + return null; + } + + private void OnRegionInfoChange(UUID RegionID) + { + Scene s = FindScene(RegionID); + if (s == null) + return; + + if (!m_InInfoUpdate) + m_EstateConnector.SendUpdateCovenant(s.RegionInfo.EstateSettings.EstateID, s.RegionInfo.RegionSettings.Covenant); + } + + private void OnEstateInfoChange(UUID RegionID) + { + Scene s = FindScene(RegionID); + if (s == null) + return; + + if (!m_InInfoUpdate) + m_EstateConnector.SendUpdateEstate(s.RegionInfo.EstateSettings.EstateID); + } + + private void OnEstateMessage(UUID RegionID, UUID FromID, string FromName, string Message) + { + Scene senderScenes = FindScene(RegionID); + if (senderScenes == null) + return; + + uint estateID = senderScenes.RegionInfo.EstateSettings.EstateID; + + foreach (Scene s in Scenes) + { + if (s.RegionInfo.EstateSettings.EstateID == estateID) + { + IDialogModule dm = s.RequestModuleInterface(); + + if (dm != null) + { + dm.SendNotificationToUsersInRegion(FromID, FromName, + Message); + } + } + } + if (!m_InInfoUpdate) + m_EstateConnector.SendEstateMessage(estateID, FromID, FromName, Message); + } + + private void OnEstateTeleportOneUserHomeRequest(IClientAPI client, UUID invoice, UUID senderID, UUID prey) + { + if (prey == UUID.Zero) + return; + + if (!(client.Scene is Scene)) + return; + + Scene scene = (Scene)client.Scene; + + uint estateID = scene.RegionInfo.EstateSettings.EstateID; + + if (!scene.Permissions.CanIssueEstateCommand(client.AgentId, false)) + return; + + foreach (Scene s in Scenes) + { + if (s.RegionInfo.EstateSettings.EstateID != estateID) + continue; + + ScenePresence p = scene.GetScenePresence(prey); + if (p != null && !p.IsChildAgent ) + { + if(!p.IsDeleted && !p.IsInTransit) + { + p.ControllingClient.SendTeleportStart(16); + scene.TeleportClientHome(prey, p.ControllingClient); + } + return; + } + } + + m_EstateConnector.SendTeleportHomeOneUser(estateID, prey); + } + + private void OnEstateTeleportAllUsersHomeRequest(IClientAPI client, UUID invoice, UUID senderID) + { + if (!(client.Scene is Scene)) + return; + + Scene scene = (Scene)client.Scene; + + uint estateID = scene.RegionInfo.EstateSettings.EstateID; + + if (!scene.Permissions.CanIssueEstateCommand(client.AgentId, false)) + return; + + foreach (Scene s in Scenes) + { + if (s.RegionInfo.EstateSettings.EstateID != estateID) + continue; + + scene.ForEachScenePresence(delegate(ScenePresence p) { + if (p != null && !p.IsChildAgent) + { + p.ControllingClient.SendTeleportStart(16); + scene.TeleportClientHome(p.ControllingClient.AgentId, p.ControllingClient); + } + }); + } + + m_EstateConnector.SendTeleportHomeAllUsers(estateID); + } + } +} diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateRequestHandler.cs b/OpenSim/Region/CoreModules/World/Estate/EstateRequestHandler.cs new file mode 100644 index 0000000..5eda8ab --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Estate/EstateRequestHandler.cs @@ -0,0 +1,300 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 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 OpenSim.Framework; +using OpenSim.Server.Base; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; + +using OpenMetaverse; +using log4net; + +namespace OpenSim.Region.CoreModules.World.Estate +{ + public class EstateRequestHandler : BaseStreamHandler + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected EstateModule m_EstateModule; + protected Object m_RequestLock = new Object(); + private string token; + + public EstateRequestHandler(EstateModule fmodule, string _token) + : base("POST", "/estate") + { + m_EstateModule = fmodule; + token = _token; + } + + protected override byte[] ProcessRequest(string path, Stream requestData, + IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + string body; + using(StreamReader sr = new StreamReader(requestData)) + body = sr.ReadToEnd(); + + body = body.Trim(); + + // m_log.DebugFormat("[XESTATE HANDLER]: query String: {0}", body); + + try + { + lock (m_RequestLock) + { + Dictionary request = + ServerUtils.ParseQueryString(body); + + if (!request.ContainsKey("METHOD")) + return FailureResult(); + + if (!request.ContainsKey("TOKEN")) + return FailureResult(); + + string reqToken = request["TOKEN"].ToString(); + request.Remove("TOKEN"); + + if(token != reqToken) + return FailureResult(); + + string method = request["METHOD"].ToString(); + request.Remove("METHOD"); + + try + { + m_EstateModule.InInfoUpdate = false; + + switch (method) + { + case "update_covenant": + return UpdateCovenant(request); + case "update_estate": + return UpdateEstate(request); + case "estate_message": + return EstateMessage(request); + case "teleport_home_one_user": + return TeleportHomeOneUser(request); + case "teleport_home_all_users": + return TeleportHomeAllUsers(request); + } + } + finally + { + m_EstateModule.InInfoUpdate = false; + } + } + } + catch (Exception e) + { + m_log.Debug("[XESTATE]: Exception {0}" + e.ToString()); + } + + return FailureResult(); + } + + byte[] TeleportHomeAllUsers(Dictionary request) + { + UUID PreyID = UUID.Zero; + int EstateID = 0; + + if (!request.ContainsKey("EstateID")) + return FailureResult(); + + if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) + return FailureResult(); + + foreach (Scene s in m_EstateModule.Scenes) + { + if (s.RegionInfo.EstateSettings.EstateID == EstateID) + { + s.ForEachScenePresence(delegate(ScenePresence p) { + if (p != null && !p.IsChildAgent) + { + p.ControllingClient.SendTeleportStart(16); + s.TeleportClientHome(p.ControllingClient.AgentId, p.ControllingClient); + } + }); + } + } + + return SuccessResult(); + } + + byte[] TeleportHomeOneUser(Dictionary request) + { + UUID PreyID = UUID.Zero; + int EstateID = 0; + + if (!request.ContainsKey("PreyID") || + !request.ContainsKey("EstateID")) + { + return FailureResult(); + } + + if (!UUID.TryParse(request["PreyID"].ToString(), out PreyID)) + return FailureResult(); + + if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) + return FailureResult(); + + foreach (Scene s in m_EstateModule.Scenes) + { + if (s.RegionInfo.EstateSettings.EstateID == EstateID) + { + ScenePresence p = s.GetScenePresence(PreyID); + if (p != null && !p.IsChildAgent) + { + p.ControllingClient.SendTeleportStart(16); + s.TeleportClientHome(PreyID, p.ControllingClient); + } + } + } + + return SuccessResult(); + } + + byte[] EstateMessage(Dictionary request) + { + UUID FromID = UUID.Zero; + string FromName = String.Empty; + string Message = String.Empty; + int EstateID = 0; + + if (!request.ContainsKey("FromID") || + !request.ContainsKey("FromName") || + !request.ContainsKey("Message") || + !request.ContainsKey("EstateID")) + { + return FailureResult(); + } + + if (!UUID.TryParse(request["FromID"].ToString(), out FromID)) + return FailureResult(); + + if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) + return FailureResult(); + + FromName = request["FromName"].ToString(); + Message = request["Message"].ToString(); + + foreach (Scene s in m_EstateModule.Scenes) + { + if (s.RegionInfo.EstateSettings.EstateID == EstateID) + { + IDialogModule dm = s.RequestModuleInterface(); + + if (dm != null) + { + dm.SendNotificationToUsersInRegion(FromID, FromName, + Message); + } + } + } + + return SuccessResult(); + } + + byte[] UpdateCovenant(Dictionary request) + { + UUID CovenantID = UUID.Zero; + int EstateID = 0; + + if (!request.ContainsKey("CovenantID") || !request.ContainsKey("EstateID")) + return FailureResult(); + + if (!UUID.TryParse(request["CovenantID"].ToString(), out CovenantID)) + return FailureResult(); + + if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) + return FailureResult(); + + foreach (Scene s in m_EstateModule.Scenes) + { + if (s.RegionInfo.EstateSettings.EstateID == (uint)EstateID) + s.RegionInfo.RegionSettings.Covenant = CovenantID; + } + + return SuccessResult(); + } + + byte[] UpdateEstate(Dictionary request) + { + int EstateID = 0; + + if (!request.ContainsKey("EstateID")) + return FailureResult(); + if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) + return FailureResult(); + + foreach (Scene s in m_EstateModule.Scenes) + { + if (s.RegionInfo.EstateSettings.EstateID == (uint)EstateID) + s.ReloadEstateData(); + } + return SuccessResult(); + } + + 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); + } + + } +} diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs deleted file mode 100644 index 73e706c..0000000 --- a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs +++ /dev/null @@ -1,218 +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.Services.Interfaces; -using GridRegion = OpenSim.Services.Interfaces.GridRegion; -using OpenSim.Server.Base; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Framework; -using OpenSim.Region.Framework.Scenes; - -using OpenMetaverse; -using log4net; - -namespace OpenSim.Region.CoreModules.World.Estate -{ - public class EstateConnector - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - protected XEstateModule m_EstateModule; - - public EstateConnector(XEstateModule module) - { - m_EstateModule = module; - } - - public void SendTeleportHomeOneUser(uint EstateID, UUID PreyID) - { - Dictionary sendData = new Dictionary(); - sendData["METHOD"] = "teleport_home_one_user"; - - sendData["EstateID"] = EstateID.ToString(); - sendData["PreyID"] = PreyID.ToString(); - - SendToEstate(EstateID, sendData); - } - - public void SendTeleportHomeAllUsers(uint EstateID) - { - Dictionary sendData = new Dictionary(); - sendData["METHOD"] = "teleport_home_all_users"; - - sendData["EstateID"] = EstateID.ToString(); - - SendToEstate(EstateID, sendData); - } - - public bool SendUpdateCovenant(uint EstateID, UUID CovenantID) - { - Dictionary sendData = new Dictionary(); - sendData["METHOD"] = "update_covenant"; - - sendData["CovenantID"] = CovenantID.ToString(); - sendData["EstateID"] = EstateID.ToString(); - - // Handle local regions locally - // - foreach (Scene s in m_EstateModule.Scenes) - { - if (s.RegionInfo.EstateSettings.EstateID == EstateID) - s.RegionInfo.RegionSettings.Covenant = CovenantID; -// s.ReloadEstateData(); - } - - SendToEstate(EstateID, sendData); - - return true; - } - - public bool SendUpdateEstate(uint EstateID) - { - Dictionary sendData = new Dictionary(); - sendData["METHOD"] = "update_estate"; - - sendData["EstateID"] = EstateID.ToString(); - - // Handle local regions locally - // - foreach (Scene s in m_EstateModule.Scenes) - { - if (s.RegionInfo.EstateSettings.EstateID == EstateID) - s.ReloadEstateData(); - } - - SendToEstate(EstateID, sendData); - - return true; - } - - public void SendEstateMessage(uint EstateID, UUID FromID, string FromName, string Message) - { - Dictionary sendData = new Dictionary(); - sendData["METHOD"] = "estate_message"; - - sendData["EstateID"] = EstateID.ToString(); - sendData["FromID"] = FromID.ToString(); - sendData["FromName"] = FromName; - sendData["Message"] = Message; - - SendToEstate(EstateID, sendData); - } - - private void SendToEstate(uint EstateID, Dictionary sendData) - { - List regions = m_EstateModule.Scenes[0].GetEstateRegions((int)EstateID); - - UUID ScopeID = UUID.Zero; - - // Handle local regions locally - // - lock (m_EstateModule.Scenes) - { - foreach (Scene s in m_EstateModule.Scenes) - { - if (regions.Contains(s.RegionInfo.RegionID)) - { - // All regions in one estate are in the same scope. - // Use that scope. - // - ScopeID = s.RegionInfo.ScopeID; - regions.Remove(s.RegionInfo.RegionID); - } - } - } - - // Our own region should always be in the above list. - // In a standalone this would not be true. But then, - // Scope ID is not relevat there. Use first scope. - // - if (ScopeID == UUID.Zero) - ScopeID = m_EstateModule.Scenes[0].RegionInfo.ScopeID; - - // Don't send to the same instance twice - // - List done = new List(); - - // Send to remote regions - // - foreach (UUID regionID in regions) - { - GridRegion region = m_EstateModule.Scenes[0].GridService.GetRegionByUUID(ScopeID, regionID); - if (region != null) - { - string url = "http://" + region.ExternalHostName + ":" + region.HttpPort; - if (done.Contains(url)) - continue; - - Call(region, sendData); - done.Add(url); - } - } - } - - private bool Call(GridRegion region, Dictionary sendData) - { - string reqString = ServerUtils.BuildQueryString(sendData); - // m_log.DebugFormat("[XESTATE CONNECTOR]: queryString = {0}", reqString); - try - { - string url = "http://" + region.ExternalHostName + ":" + region.HttpPort; - string reply = SynchronousRestFormsRequester.MakeRequest("POST", - url + "/estate", - reqString); - if (reply != string.Empty) - { - Dictionary replyData = ServerUtils.ParseXmlResponse(reply); - - if (replyData.ContainsKey("RESULT")) - { - if (replyData["RESULT"].ToString().ToLower() == "true") - return true; - else - return false; - } - else - m_log.DebugFormat("[XESTATE CONNECTOR]: reply data does not contain result field"); - - } - else - m_log.DebugFormat("[XESTATE CONNECTOR]: received empty reply"); - } - catch (Exception e) - { - m_log.DebugFormat("[XESTATE CONNECTOR]: Exception when contacting remote sim: {0}", e.Message); - } - - return false; - } - } -} diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs deleted file mode 100644 index 4bb3799..0000000 --- a/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs +++ /dev/null @@ -1,255 +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 Nwc.XmlRpc; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; -using OpenSim.Services.Interfaces; -using OpenSim.Server.Base; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; -using Mono.Addins; - -namespace OpenSim.Region.CoreModules.World.Estate -{ - [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XEstate")] - public class XEstateModule : ISharedRegionModule - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - protected List m_Scenes = new List(); - protected bool m_InInfoUpdate = false; - - public bool InInfoUpdate - { - get { return m_InInfoUpdate; } - set { m_InInfoUpdate = value; } - } - - public List Scenes - { - get { return m_Scenes; } - } - - protected EstateConnector m_EstateConnector; - - public void Initialise(IConfigSource config) - { - int port = 0; - - IConfig estateConfig = config.Configs["Estate"]; - if (estateConfig != null) - { - port = estateConfig.GetInt("Port", 0); - } - - m_EstateConnector = new EstateConnector(this); - - // Instantiate the request handler - IHttpServer server = MainServer.GetHttpServer((uint)port); - server.AddStreamHandler(new EstateRequestHandler(this)); - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public void AddRegion(Scene scene) - { - lock (m_Scenes) - m_Scenes.Add(scene); - - scene.EventManager.OnNewClient += OnNewClient; - } - - public void RegionLoaded(Scene scene) - { - IEstateModule em = scene.RequestModuleInterface(); - - em.OnRegionInfoChange += OnRegionInfoChange; - em.OnEstateInfoChange += OnEstateInfoChange; - em.OnEstateMessage += OnEstateMessage; - } - - public void RemoveRegion(Scene scene) - { - scene.EventManager.OnNewClient -= OnNewClient; - - lock (m_Scenes) - m_Scenes.Remove(scene); - } - - public string Name - { - get { return "EstateModule"; } - } - - public Type ReplaceableInterface - { - get { return null; } - } - - private Scene FindScene(UUID RegionID) - { - foreach (Scene s in Scenes) - { - if (s.RegionInfo.RegionID == RegionID) - return s; - } - - return null; - } - - private void OnRegionInfoChange(UUID RegionID) - { - Scene s = FindScene(RegionID); - if (s == null) - return; - - if (!m_InInfoUpdate) - m_EstateConnector.SendUpdateCovenant(s.RegionInfo.EstateSettings.EstateID, s.RegionInfo.RegionSettings.Covenant); - } - - private void OnEstateInfoChange(UUID RegionID) - { - Scene s = FindScene(RegionID); - if (s == null) - return; - - if (!m_InInfoUpdate) - m_EstateConnector.SendUpdateEstate(s.RegionInfo.EstateSettings.EstateID); - } - - private void OnEstateMessage(UUID RegionID, UUID FromID, string FromName, string Message) - { - Scene senderScenes = FindScene(RegionID); - if (senderScenes == null) - return; - - uint estateID = senderScenes.RegionInfo.EstateSettings.EstateID; - - foreach (Scene s in Scenes) - { - if (s.RegionInfo.EstateSettings.EstateID == estateID) - { - IDialogModule dm = s.RequestModuleInterface(); - - if (dm != null) - { - dm.SendNotificationToUsersInRegion(FromID, FromName, - Message); - } - } - } - if (!m_InInfoUpdate) - m_EstateConnector.SendEstateMessage(estateID, FromID, FromName, Message); - } - - private void OnNewClient(IClientAPI client) - { - client.OnEstateTeleportOneUserHomeRequest += OnEstateTeleportOneUserHomeRequest; - client.OnEstateTeleportAllUsersHomeRequest += OnEstateTeleportAllUsersHomeRequest; - - } - - private void OnEstateTeleportOneUserHomeRequest(IClientAPI client, UUID invoice, UUID senderID, UUID prey) - { - if (prey == UUID.Zero) - return; - - if (!(client.Scene is Scene)) - return; - - Scene scene = (Scene)client.Scene; - - uint estateID = scene.RegionInfo.EstateSettings.EstateID; - - if (!scene.Permissions.CanIssueEstateCommand(client.AgentId, false)) - return; - - foreach (Scene s in Scenes) - { - if (s == scene) - continue; // Already handles by estate module - if (s.RegionInfo.EstateSettings.EstateID != estateID) - continue; - - ScenePresence p = scene.GetScenePresence(prey); - if (p != null && !p.IsChildAgent) - { - p.ControllingClient.SendTeleportStart(16); - scene.TeleportClientHome(prey, p.ControllingClient); - } - } - - m_EstateConnector.SendTeleportHomeOneUser(estateID, prey); - } - - private void OnEstateTeleportAllUsersHomeRequest(IClientAPI client, UUID invoice, UUID senderID) - { - if (!(client.Scene is Scene)) - return; - - Scene scene = (Scene)client.Scene; - - uint estateID = scene.RegionInfo.EstateSettings.EstateID; - - if (!scene.Permissions.CanIssueEstateCommand(client.AgentId, false)) - return; - - foreach (Scene s in Scenes) - { - if (s == scene) - continue; // Already handles by estate module - if (s.RegionInfo.EstateSettings.EstateID != estateID) - continue; - - scene.ForEachScenePresence(delegate(ScenePresence p) { - if (p != null && !p.IsChildAgent) - { - p.ControllingClient.SendTeleportStart(16); - scene.TeleportClientHome(p.ControllingClient.AgentId, p.ControllingClient); - } - }); - } - - m_EstateConnector.SendTeleportHomeAllUsers(estateID); - } - } -} diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs deleted file mode 100644 index ec5af2b..0000000 --- a/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs +++ /dev/null @@ -1,288 +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 OpenSim.Framework; -using OpenSim.Server.Base; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Region.Framework.Scenes; -using OpenSim.Region.Framework.Interfaces; - -using OpenMetaverse; -using log4net; - -namespace OpenSim.Region.CoreModules.World.Estate -{ - public class EstateRequestHandler : BaseStreamHandler - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - protected XEstateModule m_EstateModule; - protected Object m_RequestLock = new Object(); - - public EstateRequestHandler(XEstateModule fmodule) - : base("POST", "/estate") - { - m_EstateModule = fmodule; - } - - 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("[XESTATE HANDLER]: query String: {0}", body); - - try - { - lock (m_RequestLock) - { - Dictionary request = - ServerUtils.ParseQueryString(body); - - if (!request.ContainsKey("METHOD")) - return FailureResult(); - - string method = request["METHOD"].ToString(); - request.Remove("METHOD"); - - try - { - m_EstateModule.InInfoUpdate = false; - - switch (method) - { - case "update_covenant": - return UpdateCovenant(request); - case "update_estate": - return UpdateEstate(request); - case "estate_message": - return EstateMessage(request); - case "teleport_home_one_user": - return TeleportHomeOneUser(request); - case "teleport_home_all_users": - return TeleportHomeAllUsers(request); - } - } - finally - { - m_EstateModule.InInfoUpdate = false; - } - } - } - catch (Exception e) - { - m_log.Debug("[XESTATE]: Exception {0}" + e.ToString()); - } - - return FailureResult(); - } - - byte[] TeleportHomeAllUsers(Dictionary request) - { - UUID PreyID = UUID.Zero; - int EstateID = 0; - - if (!request.ContainsKey("EstateID")) - return FailureResult(); - - if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) - return FailureResult(); - - foreach (Scene s in m_EstateModule.Scenes) - { - if (s.RegionInfo.EstateSettings.EstateID == EstateID) - { - s.ForEachScenePresence(delegate(ScenePresence p) { - if (p != null && !p.IsChildAgent) - { - p.ControllingClient.SendTeleportStart(16); - s.TeleportClientHome(p.ControllingClient.AgentId, p.ControllingClient); - } - }); - } - } - - return SuccessResult(); - } - - byte[] TeleportHomeOneUser(Dictionary request) - { - UUID PreyID = UUID.Zero; - int EstateID = 0; - - if (!request.ContainsKey("PreyID") || - !request.ContainsKey("EstateID")) - { - return FailureResult(); - } - - if (!UUID.TryParse(request["PreyID"].ToString(), out PreyID)) - return FailureResult(); - - if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) - return FailureResult(); - - foreach (Scene s in m_EstateModule.Scenes) - { - if (s.RegionInfo.EstateSettings.EstateID == EstateID) - { - ScenePresence p = s.GetScenePresence(PreyID); - if (p != null && !p.IsChildAgent) - { - p.ControllingClient.SendTeleportStart(16); - s.TeleportClientHome(PreyID, p.ControllingClient); - } - } - } - - return SuccessResult(); - } - - byte[] EstateMessage(Dictionary request) - { - UUID FromID = UUID.Zero; - string FromName = String.Empty; - string Message = String.Empty; - int EstateID = 0; - - if (!request.ContainsKey("FromID") || - !request.ContainsKey("FromName") || - !request.ContainsKey("Message") || - !request.ContainsKey("EstateID")) - { - return FailureResult(); - } - - if (!UUID.TryParse(request["FromID"].ToString(), out FromID)) - return FailureResult(); - - if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) - return FailureResult(); - - FromName = request["FromName"].ToString(); - Message = request["Message"].ToString(); - - foreach (Scene s in m_EstateModule.Scenes) - { - if (s.RegionInfo.EstateSettings.EstateID == EstateID) - { - IDialogModule dm = s.RequestModuleInterface(); - - if (dm != null) - { - dm.SendNotificationToUsersInRegion(FromID, FromName, - Message); - } - } - } - - return SuccessResult(); - } - - byte[] UpdateCovenant(Dictionary request) - { - UUID CovenantID = UUID.Zero; - int EstateID = 0; - - if (!request.ContainsKey("CovenantID") || !request.ContainsKey("EstateID")) - return FailureResult(); - - if (!UUID.TryParse(request["CovenantID"].ToString(), out CovenantID)) - return FailureResult(); - - if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) - return FailureResult(); - - foreach (Scene s in m_EstateModule.Scenes) - { - if (s.RegionInfo.EstateSettings.EstateID == (uint)EstateID) - s.RegionInfo.RegionSettings.Covenant = CovenantID; - } - - return SuccessResult(); - } - - byte[] UpdateEstate(Dictionary request) - { - int EstateID = 0; - - if (!request.ContainsKey("EstateID")) - return FailureResult(); - if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) - return FailureResult(); - - foreach (Scene s in m_EstateModule.Scenes) - { - if (s.RegionInfo.EstateSettings.EstateID == (uint)EstateID) - s.ReloadEstateData(); - } - return SuccessResult(); - } - - 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); - } - - } -} diff --git a/OpenSim/Region/CoreModules/World/Land/DwellModule.cs b/OpenSim/Region/CoreModules/World/Land/DwellModule.cs index 70c6028..22480e6 100644 --- a/OpenSim/Region/CoreModules/World/Land/DwellModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/DwellModule.cs @@ -53,7 +53,7 @@ using GridRegion = OpenSim.Services.Interfaces.GridRegion; namespace OpenSim.Region.CoreModules.World.Land { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DefaultDwellModule")] - public class DefaultDwellModule : IDwellModule, INonSharedRegionModule + public class DefaultDwellModule : INonSharedRegionModule, IDwellModule { private Scene m_scene; private IConfigSource m_Config; @@ -88,16 +88,21 @@ namespace OpenSim.Region.CoreModules.World.Land return; m_scene = scene; - - m_scene.EventManager.OnNewClient += OnNewClient; + m_scene.RegisterModuleInterface(this); } public void RegionLoaded(Scene scene) { + if (!m_Enabled) + return; + m_scene.EventManager.OnNewClient += OnNewClient; } public void RemoveRegion(Scene scene) { + if (!m_Enabled) + return; + m_scene.EventManager.OnNewClient -= OnNewClient; } public void Close() @@ -115,12 +120,26 @@ namespace OpenSim.Region.CoreModules.World.Land if (parcel == null) return; - client.SendParcelDwellReply(localID, parcel.LandData.GlobalID, parcel.LandData.Dwell); + LandData land = parcel.LandData; + if(land!= null) + client.SendParcelDwellReply(localID, land.GlobalID, land.Dwell); } + public int GetDwell(UUID parcelID) { + ILandObject parcel = m_scene.LandChannel.GetLandObject(parcelID); + if (parcel != null && parcel.LandData != null) + return (int)(parcel.LandData.Dwell); + return 0; + } + + public int GetDwell(LandData land) + { + if (land != null) + return (int)(land.Dwell); return 0; } + } } diff --git a/OpenSim/Region/CoreModules/World/Land/LandChannel.cs b/OpenSim/Region/CoreModules/World/Land/LandChannel.cs index 73c592d..5ff063b 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandChannel.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandChannel.cs @@ -37,26 +37,37 @@ namespace OpenSim.Region.CoreModules.World.Land { #region Constants + public const float BAN_LINE_SAFETY_HEIGHT = 100; //Land types set with flags in ParcelOverlay. //Only one of these can be used. - public const float BAN_LINE_SAFETY_HIEGHT = 100; - public const byte LAND_FLAG_PROPERTY_BORDER_SOUTH = 128; //Equals 10000000 - public const byte LAND_FLAG_PROPERTY_BORDER_WEST = 64; //Equals 01000000 + //RequestResults (I think these are right, they seem to work): public const int LAND_RESULT_MULTIPLE = 1; // The request they made contained more than a single peice of land public const int LAND_RESULT_SINGLE = 0; // The request they made contained only a single piece of land //ParcelSelectObjects + public const int LAND_SELECT_OBJECTS_OWNER = 2; public const int LAND_SELECT_OBJECTS_GROUP = 4; public const int LAND_SELECT_OBJECTS_OTHER = 8; - public const int LAND_SELECT_OBJECTS_OWNER = 2; - public const byte LAND_TYPE_IS_BEING_AUCTIONED = 5; //Equals 00000101 - public const byte LAND_TYPE_IS_FOR_SALE = 4; //Equals 00000100 - public const byte LAND_TYPE_OWNED_BY_GROUP = 2; //Equals 00000010 + + + public const byte LAND_TYPE_PUBLIC = 0; //Equals 00000000 + // types 1 to 7 are exclusive public const byte LAND_TYPE_OWNED_BY_OTHER = 1; //Equals 00000001 + public const byte LAND_TYPE_OWNED_BY_GROUP = 2; //Equals 00000010 public const byte LAND_TYPE_OWNED_BY_REQUESTER = 3; //Equals 00000011 - public const byte LAND_TYPE_PUBLIC = 0; //Equals 00000000 + public const byte LAND_TYPE_IS_FOR_SALE = 4; //Equals 00000100 + public const byte LAND_TYPE_IS_BEING_AUCTIONED = 5; //Equals 00000101 + public const byte LAND_TYPE_unused6 = 6; + public const byte LAND_TYPE_unused7 = 7; + // next are flags + public const byte LAND_FLAG_unused8 = 0x08; // this may become excluside in future + public const byte LAND_FLAG_HIDEAVATARS = 0x10; + public const byte LAND_FLAG_LOCALSOUND = 0x20; + public const byte LAND_FLAG_PROPERTY_BORDER_WEST = 0x40; //Equals 01000000 + public const byte LAND_FLAG_PROPERTY_BORDER_SOUTH = 0x80; //Equals 10000000 + //These are other constants. Yay! public const int START_LAND_LOCAL_ID = 1; @@ -64,7 +75,7 @@ namespace OpenSim.Region.CoreModules.World.Land #endregion private readonly Scene m_scene; - private readonly LandManagementModule m_landManagementModule; + private readonly LandManagementModule m_landManagementModule; public LandChannel(Scene scene, LandManagementModule landManagementMod) { @@ -80,7 +91,7 @@ namespace OpenSim.Region.CoreModules.World.Land { return m_landManagementModule.GetLandObject(x_float, y_float); } - + ILandObject obj = new LandObject(UUID.Zero, false, m_scene); obj.LandData.Name = "NO LAND"; return obj; @@ -95,6 +106,15 @@ namespace OpenSim.Region.CoreModules.World.Land return null; } + public ILandObject GetLandObject(UUID GlobalID) + { + if (m_landManagementModule != null) + { + return m_landManagementModule.GetLandObject(GlobalID); + } + return null; + } + public ILandObject GetLandObject(Vector3 position) { return GetLandObject(position.X, position.Y); @@ -106,7 +126,7 @@ namespace OpenSim.Region.CoreModules.World.Land { return m_landManagementModule.GetLandObject(x, y); } - + ILandObject obj = new LandObject(UUID.Zero, false, m_scene); obj.LandData.Name = "NO LAND"; return obj; @@ -121,7 +141,7 @@ namespace OpenSim.Region.CoreModules.World.Land return new List(); } - + public void Clear(bool setupDefaultParcel) { if (m_landManagementModule != null) @@ -156,6 +176,14 @@ namespace OpenSim.Region.CoreModules.World.Land } } + public void SendParcelsOverlay(IClientAPI client) + { + if (m_landManagementModule != null) + { + m_landManagementModule.SendParcelOverlay(client); + } + } + public void Join(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id) { if (m_landManagementModule != null) @@ -171,7 +199,7 @@ namespace OpenSim.Region.CoreModules.World.Land m_landManagementModule.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) { if (m_landManagementModule != null) @@ -203,7 +231,13 @@ namespace OpenSim.Region.CoreModules.World.Land m_landManagementModule.setParcelOtherCleanTime(remoteClient, localID, otherCleanTime); } } - + public void sendClientInitialLandInfo(IClientAPI remoteClient) + { + if (m_landManagementModule != null) + { + m_landManagementModule.sendClientInitialLandInfo(remoteClient); + } + } #endregion } } diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index 92f6c1b..b1f5122 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs @@ -41,6 +41,7 @@ using OpenSim.Framework; using OpenSim.Framework.Capabilities; using OpenSim.Framework.Console; using OpenSim.Framework.Servers; +using OpenSim.Framework.Monitoring; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; @@ -52,7 +53,7 @@ using GridRegion = OpenSim.Services.Interfaces.GridRegion; namespace OpenSim.Region.CoreModules.World.Land { // used for caching - internal class ExtendedLandData + internal class ExtendedLandData { public LandData LandData; public ulong RegionHandle; @@ -69,9 +70,8 @@ namespace OpenSim.Region.CoreModules.World.Land /// /// Minimum land unit size in region co-ordinates. /// - public const int LandUnit = 4; - private static readonly string remoteParcelRequestPath = "0009/"; + public const int LandUnit = 4; private LandChannel landChannel; private Scene m_scene; @@ -89,20 +89,27 @@ namespace OpenSim.Region.CoreModules.World.Land /// /// Land objects keyed by local id /// - private readonly Dictionary m_landList = new Dictionary(); +// private readonly Dictionary m_landList = new Dictionary(); + + //ubit: removed the readonly so i can move it around + private Dictionary m_landList = new Dictionary(); + private Dictionary m_landUUIDList = new Dictionary(); private int m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1; private bool m_allowedForcefulBans = true; + private bool m_showBansLines = true; + private UUID DefaultGodParcelGroup; + private string DefaultGodParcelName; // caches ExtendedLandData private Cache parcelInfoCache; - /// /// Record positions that avatar's are currently being forced to move to due to parcel entry restrictions. /// - private Dictionary forcedPosition = new Dictionary(); + private HashSet forcedPosition = new HashSet(); + // Enables limiting parcel layer info transmission when doing simple updates private bool shouldLimitParcelLayerInfoToViewDistance { get; set; } @@ -125,6 +132,11 @@ namespace OpenSim.Region.CoreModules.World.Land { shouldLimitParcelLayerInfoToViewDistance = landManagementConfig.GetBoolean("LimitParcelLayerUpdateDistance", shouldLimitParcelLayerInfoToViewDistance); parcelLayerViewDistance = landManagementConfig.GetInt("ParcelLayerViewDistance", parcelLayerViewDistance); + DefaultGodParcelGroup = new UUID(landManagementConfig.GetString("DefaultAdministratorGroupUUID", UUID.Zero.ToString())); + DefaultGodParcelName = landManagementConfig.GetString("DefaultAdministratorParcelName", "Default Parcel"); + bool disablebans = landManagementConfig.GetBoolean("DisableParcelBans", !m_allowedForcefulBans); + m_allowedForcefulBans = !disablebans; + m_showBansLines = landManagementConfig.GetBoolean("ShowParcelBansLines", m_showBansLines); } } @@ -132,17 +144,20 @@ namespace OpenSim.Region.CoreModules.World.Land { m_scene = scene; m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / LandUnit, m_scene.RegionInfo.RegionSizeY / LandUnit]; + landChannel = new LandChannel(scene, this); parcelInfoCache = new Cache(); parcelInfoCache.Size = 30; // the number of different parcel requests in this region to cache parcelInfoCache.DefaultTTL = new TimeSpan(0, 5, 0); + m_scene.EventManager.OnObjectAddedToScene += EventManagerOnParcelPrimCountAdd; m_scene.EventManager.OnParcelPrimCountAdd += EventManagerOnParcelPrimCountAdd; + + m_scene.EventManager.OnObjectBeingRemovedFromScene += EventManagerOnObjectBeingRemovedFromScene; m_scene.EventManager.OnParcelPrimCountUpdate += EventManagerOnParcelPrimCountUpdate; - m_scene.EventManager.OnObjectBeingRemovedFromScene += EventManagerOnObjectBeingRemovedFromScene; m_scene.EventManager.OnRequestParcelPrimCountUpdate += EventManagerOnRequestParcelPrimCountUpdate; - + m_scene.EventManager.OnAvatarEnteringNewParcel += EventManagerOnAvatarEnteringNewParcel; m_scene.EventManager.OnClientMovement += EventManagerOnClientMovement; m_scene.EventManager.OnValidateLandBuy += EventManagerOnValidateLandBuy; @@ -152,14 +167,14 @@ namespace OpenSim.Region.CoreModules.World.Land m_scene.EventManager.OnSignificantClientMovement += EventManagerOnSignificantClientMovement; m_scene.EventManager.OnNoticeNoLandDataFromStorage += EventManagerOnNoLandDataFromStorage; m_scene.EventManager.OnIncomingLandDataFromStorage += EventManagerOnIncomingLandDataFromStorage; - m_scene.EventManager.OnSetAllowForcefulBan += EventManagerOnSetAllowedForcefulBan; + m_scene.EventManager.OnSetAllowForcefulBan += EventManagerOnSetAllowedForcefulBan; m_scene.EventManager.OnRegisterCaps += EventManagerOnRegisterCaps; lock (m_scene) { m_scene.LandChannel = (ILandChannel)landChannel; } - + RegisterCommands(); } @@ -172,8 +187,8 @@ namespace OpenSim.Region.CoreModules.World.Land } public void RemoveRegion(Scene scene) - { - // TODO: Release event manager listeners here + { + // TODO: Release event manager listeners here } // private bool OnVerifyUserConnection(ScenePresence scenePresence, out string reason) @@ -181,7 +196,7 @@ namespace OpenSim.Region.CoreModules.World.Land // ILandObject nearestParcel = m_scene.GetNearestAllowedParcel(scenePresence.UUID, scenePresence.AbsolutePosition.X, scenePresence.AbsolutePosition.Y); // reason = "You are not allowed to enter this sim."; // return nearestParcel != null; -// } +// } void EventManagerOnNewClient(IClientAPI client) { @@ -199,18 +214,10 @@ namespace OpenSim.Region.CoreModules.World.Land client.OnParcelReclaim += ClientOnParcelReclaim; client.OnParcelInfoRequest += ClientOnParcelInfoRequest; client.OnParcelDeedToGroup += ClientOnParcelDeedToGroup; - client.OnPreAgentUpdate += ClientOnPreAgentUpdate; client.OnParcelEjectUser += ClientOnParcelEjectUser; client.OnParcelFreezeUser += ClientOnParcelFreezeUser; client.OnSetStartLocationRequest += ClientOnSetHome; - - - EntityBase presenceEntity; - if (m_scene.Entities.TryGetValue(client.AgentId, out presenceEntity) && presenceEntity is ScenePresence) - { - SendLandUpdate((ScenePresence)presenceEntity, true); - SendParcelOverlay(client); - } + client.OnParcelBuyPass += ClientParcelBuyPass; } public void EventMakeChildAgent(ScenePresence avatar) @@ -218,52 +225,6 @@ namespace OpenSim.Region.CoreModules.World.Land avatar.currentParcelUUID = UUID.Zero; } - void ClientOnPreAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) - { - //If we are forcing a position for them to go - if (forcedPosition.ContainsKey(remoteClient.AgentId)) - { - ScenePresence clientAvatar = m_scene.GetScenePresence(remoteClient.AgentId); - - //Putting the user into flying, both keeps the avatar in fligth when it bumps into something and stopped from going another direction AND - //When the avatar walks into a ban line on the ground, it prevents getting stuck - agentData.ControlFlags = (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; - - //Make sure we stop if they get about to the right place to prevent yoyo and prevents getting stuck on banlines - if (Vector3.Distance(clientAvatar.AbsolutePosition, forcedPosition[remoteClient.AgentId]) < .2) - { -// m_log.DebugFormat( -// "[LAND MANAGEMENT MODULE]: Stopping force position of {0} because {1} is close enough to {2}", -// clientAvatar.Name, clientAvatar.AbsolutePosition, forcedPosition[remoteClient.AgentId]); - - forcedPosition.Remove(remoteClient.AgentId); - } - //if we are far away, teleport - else if (Vector3.Distance(clientAvatar.AbsolutePosition, forcedPosition[remoteClient.AgentId]) > 3) - { - Vector3 forcePosition = forcedPosition[remoteClient.AgentId]; -// m_log.DebugFormat( -// "[LAND MANAGEMENT MODULE]: Teleporting out {0} because {1} is too far from avatar position {2}", -// clientAvatar.Name, clientAvatar.AbsolutePosition, forcePosition); - - m_scene.RequestTeleportLocation(remoteClient, m_scene.RegionInfo.RegionHandle, - forcePosition, clientAvatar.Lookat, (uint)Constants.TeleportFlags.ForceRedirect); - - forcedPosition.Remove(remoteClient.AgentId); - } - else - { -// m_log.DebugFormat( -// "[LAND MANAGEMENT MODULE]: Forcing {0} from {1} to {2}", -// clientAvatar.Name, clientAvatar.AbsolutePosition, forcedPosition[remoteClient.AgentId]); - - //Forces them toward the forced position we want if they aren't there yet - agentData.UseClientAgentPosition = true; - agentData.ClientAgentPosition = forcedPosition[remoteClient.AgentId]; - } - } - } - public void Close() { } @@ -291,7 +252,10 @@ namespace OpenSim.Region.CoreModules.World.Land lock (m_landList) { if (m_landList.TryGetValue(local_id, out land)) + { land.LandData = newData; + m_landUUIDList[newData.GlobalID] = local_id; + } } if (land != null) @@ -312,28 +276,35 @@ namespace OpenSim.Region.CoreModules.World.Land //Remove all the land objects in the sim and add a blank, full sim land object set to public lock (m_landList) { + foreach(ILandObject parcel in m_landList.Values) + parcel.Clear(); + m_landList.Clear(); + m_landUUIDList.Clear(); m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1; + m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / LandUnit, m_scene.RegionInfo.RegionSizeY / LandUnit]; } } - + /// /// Create a default parcel that spans the entire region and is owned by the estate owner. /// /// The parcel created. protected ILandObject CreateDefaultParcel() { - m_log.DebugFormat( - "[LAND MANAGEMENT MODULE]: Creating default parcel for region {0}", m_scene.RegionInfo.RegionName); - - ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene); + m_log.DebugFormat("{0} Creating default parcel for region {1}", LogHeader, m_scene.RegionInfo.RegionName); + + ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene); + fullSimParcel.SetLandBitmap(fullSimParcel.GetSquareLandBitmap(0, 0, (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY)); - fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; - fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch(); - - return AddLandObject(fullSimParcel); + LandData ldata = fullSimParcel.LandData; + ldata.SimwideArea = ldata.Area; + ldata.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; + ldata.ClaimDate = Util.UnixTimeSinceEpoch(); + + return AddLandObject(fullSimParcel); } public List AllParcels() @@ -347,9 +318,9 @@ namespace OpenSim.Region.CoreModules.World.Land public List ParcelsNearPoint(Vector3 position) { List parcelsNear = new List(); - for (int x = -4; x <= 4; x += 4) + for (int x = -8; x <= 8; x += 4) { - for (int y = -4; y <= 4; y += 4) + for (int y = -8; y <= 8; y += 4) { ILandObject check = GetLandObject(position.X + x, position.Y + y); if (check != null) @@ -365,33 +336,99 @@ namespace OpenSim.Region.CoreModules.World.Land return parcelsNear; } - public void SendYouAreBannedNotice(ScenePresence avatar) + // checks and enforces bans or restrictions + // returns true if enforced + public bool EnforceBans(ILandObject land, ScenePresence avatar) { - if (AllowedForcefulBans) + Vector3 agentpos = avatar.AbsolutePosition; + float h = m_scene.GetGroundHeight(agentpos.X, agentpos.Y) + LandChannel.BAN_LINE_SAFETY_HEIGHT; + float zdif = avatar.AbsolutePosition.Z - h; + if (zdif > 0 ) + { + forcedPosition.Remove(avatar.UUID); + avatar.lastKnownAllowedPosition = agentpos; + return false; + } + + bool ban = false; + string reason = ""; + if (land.IsRestrictedFromLand(avatar.UUID)) { - avatar.ControllingClient.SendAlertMessage( - "You are not allowed on this parcel because you are banned. Please go away."); + reason = "You do not have access to the parcel"; + ban = true; + } + + if (land.IsBannedFromLand(avatar.UUID)) + { + if ( m_allowedForcefulBans) + { + reason ="You are banned from parcel"; + ban = true; + } + else if(!ban) + { + if (forcedPosition.Contains(avatar.UUID)) + avatar.ControllingClient.SendAlertMessage("You are banned from parcel, please leave by your own will"); + forcedPosition.Remove(avatar.UUID); + avatar.lastKnownAllowedPosition = agentpos; + return false; + } + } + + if(ban) + { + if (!forcedPosition.Contains(avatar.UUID)) + avatar.ControllingClient.SendAlertMessage(reason); + + if(zdif > -4f) + { + + agentpos.Z = h + 4.0f; + ForceAvatarToPosition(avatar, agentpos); + return true; + } + + if (land.ContainsPoint((int)avatar.lastKnownAllowedPosition.X, + (int) avatar.lastKnownAllowedPosition.Y)) + { + Vector3? pos = m_scene.GetNearestAllowedPosition(avatar); + if (pos == null) + { + forcedPosition.Remove(avatar.UUID); + m_scene.TeleportClientHome(avatar.UUID, avatar.ControllingClient); + } + else + ForceAvatarToPosition(avatar, (Vector3)pos); + } + else + { + ForceAvatarToPosition(avatar, avatar.lastKnownAllowedPosition); + } + return true; } else { - avatar.ControllingClient.SendAlertMessage( - "You are not allowed on this parcel because you are banned; however, the grid administrator has disabled ban lines globally. Please obey the land owner's requests or you can be banned from the entire sim!"); + forcedPosition.Remove(avatar.UUID); + avatar.lastKnownAllowedPosition = agentpos; + return false; } } private void ForceAvatarToPosition(ScenePresence avatar, Vector3? position) { if (m_scene.Permissions.IsGod(avatar.UUID)) return; - if (position.HasValue) - { - forcedPosition[avatar.ControllingClient.AgentId] = (Vector3)position; - } - } - public void SendYouAreRestrictedNotice(ScenePresence avatar) - { - avatar.ControllingClient.SendAlertMessage( - "You are not allowed on this parcel because the land owner has restricted access."); + if (!position.HasValue) + return; + + if(avatar.MovingToTarget) + avatar.ResetMoveToTarget(); + avatar.AbsolutePosition = position.Value; + avatar.lastKnownAllowedPosition = position.Value; + avatar.Velocity = Vector3.Zero; + if(avatar.IsSatOnObject) + avatar.StandUp(); + forcedPosition.Add(avatar.UUID); } public void EventManagerOnAvatarEnteringNewParcel(ScenePresence avatar, int localLandID, UUID regionID) @@ -404,29 +441,12 @@ namespace OpenSim.Region.CoreModules.World.Land parcelAvatarIsEntering = m_landList[localLandID]; } - if (parcelAvatarIsEntering != null) + if (parcelAvatarIsEntering != null && + avatar.currentParcelUUID != parcelAvatarIsEntering.LandData.GlobalID) { - if (avatar.AbsolutePosition.Z < LandChannel.BAN_LINE_SAFETY_HIEGHT) - { - if (parcelAvatarIsEntering.IsBannedFromLand(avatar.UUID)) - { - SendYouAreBannedNotice(avatar); - ForceAvatarToPosition(avatar, m_scene.GetNearestAllowedPosition(avatar)); - } - else if (parcelAvatarIsEntering.IsRestrictedFromLand(avatar.UUID)) - { - SendYouAreRestrictedNotice(avatar); - ForceAvatarToPosition(avatar, m_scene.GetNearestAllowedPosition(avatar)); - } - else - { - avatar.sentMessageAboutRestrictedParcelFlyingDown = true; - } - } - else - { - avatar.sentMessageAboutRestrictedParcelFlyingDown = true; - } + SendLandUpdate(avatar, parcelAvatarIsEntering); + avatar.currentParcelUUID = parcelAvatarIsEntering.LandData.GlobalID; + EnforceBans(parcelAvatarIsEntering, avatar); } } } @@ -434,7 +454,7 @@ namespace OpenSim.Region.CoreModules.World.Land public void SendOutNearestBanLine(IClientAPI client) { ScenePresence sp = m_scene.GetScenePresence(client.AgentId); - if (sp == null || sp.IsChildAgent) + if (sp == null || sp.IsDeleted) return; List checkLandParcels = ParcelsNearPoint(sp.AbsolutePosition); @@ -454,98 +474,180 @@ namespace OpenSim.Region.CoreModules.World.Land return; } - public void SendLandUpdate(ScenePresence avatar, bool force) + public void sendClientInitialLandInfo(IClientAPI remoteClient) { - ILandObject over = GetLandObject((int)Math.Min(((int)m_scene.RegionInfo.RegionSizeX - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.X))), - (int)Math.Min(((int)m_scene.RegionInfo.RegionSizeY - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.Y)))); + ScenePresence avatar; - if (over != null) + if (!m_scene.TryGetScenePresence(remoteClient.AgentId, out avatar)) + return; + + if (!avatar.IsChildAgent) { - if (force) - { - if (!avatar.IsChildAgent) - { - over.SendLandUpdateToClient(avatar.ControllingClient); - m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar, over.LandData.LocalID, - m_scene.RegionInfo.RegionID); - } - } + ILandObject over = GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); + if (over == null) + return; - if (avatar.currentParcelUUID != over.LandData.GlobalID) - { - if (!avatar.IsChildAgent) - { - over.SendLandUpdateToClient(avatar.ControllingClient); - avatar.currentParcelUUID = over.LandData.GlobalID; - m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar, over.LandData.LocalID, - m_scene.RegionInfo.RegionID); - } - } + avatar.currentParcelUUID = over.LandData.GlobalID; + over.SendLandUpdateToClient(avatar.ControllingClient); } + SendParcelOverlay(remoteClient); } - public void SendLandUpdate(ScenePresence avatar) + public void SendLandUpdate(ScenePresence avatar, ILandObject over) { - SendLandUpdate(avatar, false); - } + if (avatar.IsChildAgent) + return; - public void EventManagerOnSignificantClientMovement(ScenePresence clientAvatar) - { - SendLandUpdate(clientAvatar); - SendOutNearestBanLine(clientAvatar.ControllingClient); - ILandObject parcel = GetLandObject(clientAvatar.AbsolutePosition.X, clientAvatar.AbsolutePosition.Y); - if (parcel != null) + if (over != null) { - if (clientAvatar.AbsolutePosition.Z < LandChannel.BAN_LINE_SAFETY_HIEGHT && - clientAvatar.sentMessageAboutRestrictedParcelFlyingDown) - { - EventManagerOnAvatarEnteringNewParcel(clientAvatar, parcel.LandData.LocalID, - m_scene.RegionInfo.RegionID); - //They are going under the safety line! - if (!parcel.IsBannedFromLand(clientAvatar.UUID)) - { - clientAvatar.sentMessageAboutRestrictedParcelFlyingDown = false; - } - } - else if (clientAvatar.AbsolutePosition.Z < LandChannel.BAN_LINE_SAFETY_HIEGHT && - parcel.IsBannedFromLand(clientAvatar.UUID)) - { - //once we've sent the message once, keep going toward the target until we are done - if (forcedPosition.ContainsKey(clientAvatar.ControllingClient.AgentId)) - { - SendYouAreBannedNotice(clientAvatar); - ForceAvatarToPosition(clientAvatar, m_scene.GetNearestAllowedPosition(clientAvatar)); - } - } - else if (parcel.IsRestrictedFromLand(clientAvatar.UUID)) - { - //once we've sent the message once, keep going toward the target until we are done - if (forcedPosition.ContainsKey(clientAvatar.ControllingClient.AgentId)) - { - SendYouAreRestrictedNotice(clientAvatar); - ForceAvatarToPosition(clientAvatar, m_scene.GetNearestAllowedPosition(clientAvatar)); - } - } - else - { - //when we are finally in a safe place, lets release the forced position lock - forcedPosition.Remove(clientAvatar.ControllingClient.AgentId); - } + over.SendLandUpdateToClient(avatar.ControllingClient); +// sl doesnt seem to send this now, as it used 2 +// SendParcelOverlay(avatar.ControllingClient); } } + public void EventManagerOnSignificantClientMovement(ScenePresence avatar) + { + if (avatar.IsChildAgent) + return; + + if ( m_allowedForcefulBans && m_showBansLines) + SendOutNearestBanLine(avatar.ControllingClient); + } + /// /// Like handleEventManagerOnSignificantClientMovement, but called with an AgentUpdate regardless of distance. /// /// public void EventManagerOnClientMovement(ScenePresence avatar) { + if (avatar.IsChildAgent) + return; + Vector3 pos = avatar.AbsolutePosition; ILandObject over = GetLandObject(pos.X, pos.Y); if (over != null) { - if (!over.IsRestrictedFromLand(avatar.UUID) && (!over.IsBannedFromLand(avatar.UUID) || pos.Z >= LandChannel.BAN_LINE_SAFETY_HIEGHT)) - avatar.lastKnownAllowedPosition = pos; + EnforceBans(over, avatar); + pos = avatar.AbsolutePosition; + ILandObject newover = GetLandObject(pos.X, pos.Y); + if(over != newover || avatar.currentParcelUUID != newover.LandData.GlobalID) + { + m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar, + newover.LandData.LocalID, m_scene.RegionInfo.RegionID); + } + } + } + + public void ClientParcelBuyPass(IClientAPI remote_client, UUID targetID, int landLocalID) + { + ILandObject land; + lock (m_landList) + { + m_landList.TryGetValue(landLocalID, out land); + } + // trivial checks + if(land == null) + return; + + LandData ldata = land.LandData; + + if(ldata == null) + return; + + if(ldata.OwnerID == targetID) + return; + + if(ldata.PassHours == 0) + return; + + // don't allow passes on group owned until we can give money to groups + if(ldata.IsGroupOwned) + { + remote_client.SendAgentAlertMessage("pass to group owned parcel not suported", false); + return; + } + + if((ldata.Flags & (uint)ParcelFlags.UsePassList) == 0) + return; + + int cost = ldata.PassPrice; + + int idx = land.LandData.ParcelAccessList.FindIndex( + delegate(LandAccessEntry e) + { + if (e.AgentID == targetID && e.Flags == AccessList.Access) + return true; + return false; + }); + int now = Util.UnixTimeSinceEpoch(); + int expires = (int)(3600.0 * ldata.PassHours + 0.5f); + int currenttime = -1; + if (idx != -1) + { + if(ldata.ParcelAccessList[idx].Expires == 0) + { + remote_client.SendAgentAlertMessage("You already have access to parcel", false); + return; + } + + currenttime = ldata.ParcelAccessList[idx].Expires - now; + if(currenttime > (int)(0.25f * expires + 0.5f)) + { + if(currenttime > 3600) + remote_client.SendAgentAlertMessage(string.Format("You already have a pass valid for {0:0.###} hours", + currenttime/3600f), false); + else if(currenttime > 60) + remote_client.SendAgentAlertMessage(string.Format("You already have a pass valid for {0:0.##} minutes", + currenttime/60f), false); + else + remote_client.SendAgentAlertMessage(string.Format("You already have a pass valid for {0:0.#} seconds", + currenttime), false); + return; + } + } + + LandAccessEntry entry = new LandAccessEntry(); + entry.AgentID = targetID; + entry.Flags = AccessList.Access; + entry.Expires = now + expires; + if(currenttime > 0) + entry.Expires += currenttime; + IMoneyModule mm = m_scene.RequestModuleInterface(); + if(cost != 0 && mm != null) + { + WorkManager.RunInThreadPool( + delegate + { + string regionName = m_scene.RegionInfo.RegionName; + + if (!mm.AmountCovered(remote_client.AgentId, cost)) + { + remote_client.SendAgentAlertMessage(String.Format("Insufficient funds in region '{0}' money system", regionName), true); + return; + } + + string payDescription = String.Format("Parcel '{0}' at region '{1} {2:0.###} hours access pass", ldata.Name, regionName, ldata.PassHours); + + if(!mm.MoveMoney(remote_client.AgentId, ldata.OwnerID, cost,MoneyTransactionType.LandPassSale, payDescription)) + { + remote_client.SendAgentAlertMessage("Sorry pass payment processing failed, please try again later", true); + return; + } + + if (idx != -1) + ldata.ParcelAccessList.RemoveAt(idx); + ldata.ParcelAccessList.Add(entry); + m_scene.EventManager.TriggerLandObjectUpdated((uint)land.LandData.LocalID, land); + return; + }, null, "ParcelBuyPass"); + } + else + { + if (idx != -1) + ldata.ParcelAccessList.RemoveAt(idx); + ldata.ParcelAccessList.Add(entry); + m_scene.EventManager.TriggerLandObjectUpdated((uint)land.LandData.LocalID, land); } } @@ -589,7 +691,7 @@ namespace OpenSim.Region.CoreModules.World.Land requiredPowers = GroupPowers.LandManageBanned; if (m_scene.Permissions.CanEditParcelProperties(agentID, - land, requiredPowers)) + land, requiredPowers, false)) { land.UpdateAccessList(flags, transactionID, sequenceID, sections, entries, remote_client); @@ -605,13 +707,11 @@ namespace OpenSim.Region.CoreModules.World.Land /// Adds a land object to the stored list and adds them to the landIDList to what they own /// /// - /// The land object being added. + /// The land object being added. /// Will return null if this overlaps with an existing parcel that has not had its bitmap adjusted. /// - public ILandObject AddLandObject(ILandObject land) + public ILandObject AddLandObject(ILandObject new_land) { - ILandObject new_land = land.Copy(); - // Only now can we add the prim counts to the land object - we rely on the global ID which is generated // as a random UUID inside LandData initialization if (m_primCountModule != null) @@ -623,18 +723,15 @@ namespace OpenSim.Region.CoreModules.World.Land new_land.LandData.LocalID = newLandLocalID; bool[,] landBitmap = new_land.GetLandBitmap(); - // m_log.DebugFormat("{0} AddLandObject. new_land.bitmapSize=({1},{2}). newLocalID={3}", - // LogHeader, landBitmap.GetLength(0), landBitmap.GetLength(1), newLandLocalID); - if (landBitmap.GetLength(0) != m_landIDList.GetLength(0) || landBitmap.GetLength(1) != m_landIDList.GetLength(1)) { // Going to variable sized regions can cause mismatches m_log.ErrorFormat("{0} AddLandObject. Added land bitmap different size than region ID map. bitmapSize=({1},{2}), landIDSize=({3},{4})", - LogHeader, landBitmap.GetLength(0), landBitmap.GetLength(1), m_landIDList.GetLength(0), m_landIDList.GetLength(1) ); + LogHeader, landBitmap.GetLength(0), landBitmap.GetLength(1), m_landIDList.GetLength(0), m_landIDList.GetLength(1)); } else { - // If other land objects still believe that they occupy any parts of the same space, + // If other land objects still believe that they occupy any parts of the same space, // then do not allow the add to proceed. for (int x = 0; x < landBitmap.GetLength(0); x++) { @@ -652,7 +749,7 @@ namespace OpenSim.Region.CoreModules.World.Land { m_log.ErrorFormat( "{0}: Cannot add parcel \"{1}\", local ID {2} at tile {3},{4} because this is still occupied by parcel \"{5}\", local ID {6} in {7}", - LogHeader, new_land.LandData.Name, new_land.LandData.LocalID, x, y, + LogHeader, new_land.LandData.Name, new_land.LandData.LocalID, x, y, lastRecordedLo.LandData.Name, lastRecordedLo.LandData.LocalID, m_scene.Name); return null; @@ -668,10 +765,10 @@ namespace OpenSim.Region.CoreModules.World.Land { if (landBitmap[x, y]) { - // m_log.DebugFormat( - // "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}", - // new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName); - + // m_log.DebugFormat( + // "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}", + // new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName); + m_landIDList[x, y] = newLandLocalID; } } @@ -679,6 +776,7 @@ namespace OpenSim.Region.CoreModules.World.Land } m_landList.Add(newLandLocalID, new_land); + m_landUUIDList[new_land.LandData.GlobalID] = newLandLocalID; m_lastLandLocalID++; } @@ -695,6 +793,7 @@ namespace OpenSim.Region.CoreModules.World.Land public void removeLandObject(int local_id) { ILandObject land; + UUID landGlobalID = UUID.Zero; lock (m_landList) { for (int x = 0; x < m_landIDList.GetLength(0); x++) @@ -713,37 +812,47 @@ namespace OpenSim.Region.CoreModules.World.Land land = m_landList[local_id]; m_landList.Remove(local_id); + if(land != null && land.LandData != null) + { + landGlobalID = land.LandData.GlobalID; + m_landUUIDList.Remove(landGlobalID); + } } - m_scene.EventManager.TriggerLandObjectRemoved(land.LandData.GlobalID); + if(landGlobalID != UUID.Zero) + { + m_scene.EventManager.TriggerLandObjectRemoved(landGlobalID); + land.Clear(); + } } - + /// /// Clear the scene of all parcels - /// + /// public void Clear(bool setupDefaultParcel) { - List parcels; + Dictionary landworkList; + // move to work pointer since we are deleting it all lock (m_landList) { - parcels = new List(m_landList.Values); + landworkList = m_landList; + m_landList = new Dictionary(); } - foreach (ILandObject lo in parcels) + // this 2 methods have locks (now) + ResetSimLandObjects(); + + if (setupDefaultParcel) + CreateDefaultParcel(); + + // fire outside events unlocked + foreach (ILandObject lo in landworkList.Values) { //m_scene.SimulationDataService.RemoveLandObject(lo.LandData.GlobalID); m_scene.EventManager.TriggerLandObjectRemoved(lo.LandData.GlobalID); } + landworkList.Clear(); - lock (m_landList) - { - m_landList.Clear(); - - ResetSimLandObjects(); - } - - if (setupDefaultParcel) - CreateDefaultParcel(); } private void performFinalLandJoin(ILandObject master, ILandObject slave) @@ -762,11 +871,29 @@ namespace OpenSim.Region.CoreModules.World.Land } } } - + master.LandData.Dwell += slave.LandData.Dwell; removeLandObject(slave.LandData.LocalID); UpdateLandObject(master.LandData.LocalID, master.LandData); } + public ILandObject GetLandObject(UUID globalID) + { + lock (m_landList) + { + int lid = -1; + if(m_landUUIDList.TryGetValue(globalID, out lid) && lid >= 0) + { + if (m_landList.ContainsKey(lid)) + { + return m_landList[lid]; + } + else + m_landUUIDList.Remove(globalID); // auto heal + } + } + return null; + } + public ILandObject GetLandObject(int parcelLocalID) { lock (m_landList) @@ -787,58 +914,37 @@ namespace OpenSim.Region.CoreModules.World.Land /// Land object at the point supplied public ILandObject GetLandObject(float x_float, float y_float) { - return GetLandObject((int)x_float, (int)y_float, true /* returnNullIfLandObjectNotFound */); - /* - int x; - int y; - - if (x_float >= m_scene.RegionInfo.RegionSizeX || x_float < 0 || y_float >= m_scene.RegionInfo.RegionSizeX || y_float < 0) - return null; + return GetLandObject((int)x_float, (int)y_float, true); + } - try - { - x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / (float)landUnit)); - y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / (float)landUnit)); - } - catch (OverflowException) - { - return null; - } + // if x,y is off region this will return the parcel at cliped x,y + // as did code it replaces + public ILandObject GetLandObjectClipedXY(float x, float y) + { + //do clip inline + int avx = (int)x; + if (avx < 0) + avx = 0; + else if (avx >= m_scene.RegionInfo.RegionSizeX) + avx = (int)Constants.RegionSize - 1; - if (x >= (m_scene.RegionInfo.RegionSizeX / landUnit) - || y >= (m_scene.RegionInfo.RegionSizeY / landUnit) - || x < 0 - || y < 0) - { - return null; - } + int avy = (int)y; + if (avy < 0) + avy = 0; + else if (avy >= m_scene.RegionInfo.RegionSizeY) + avy = (int)Constants.RegionSize - 1; - lock (m_landList) + lock (m_landIDList) { - // Corner case. If an autoreturn happens during sim startup - // we will come here with the list uninitialized - // -// int landId = m_landIDList[x, y]; - -// if (landId == 0) -// m_log.DebugFormat( -// "[LAND MANAGEMENT MODULE]: No land object found at ({0}, {1}) on {2}", -// x, y, m_scene.RegionInfo.RegionName); - try { - if (m_landList.ContainsKey(m_landIDList[x, y])) - return m_landList[m_landIDList[x, y]]; + return m_landList[m_landIDList[avx / LandUnit, avy / LandUnit]]; } - catch (Exception e) + catch (IndexOutOfRangeException) { - m_log.DebugFormat("{0} GetLandObject exception. x={1}, y={2}, m_landIDList.len=({3},{4})", - LogHeader, x, y, m_landIDList.GetLength(0), m_landIDList.GetLength(1)); + return null; } - - return null; } - */ } // Public entry. @@ -848,33 +954,32 @@ namespace OpenSim.Region.CoreModules.World.Land return GetLandObject(x, y, false /* returnNullIfLandObjectNotFound */); } - /// - /// Given a region position, return the parcel land object for that location - /// - /// - /// The land object. - /// - /// - /// - /// - /// Return null if the land object requested is not within the region's bounds. - /// - private ILandObject GetLandObject(int x, int y, bool returnNullIfLandObjectOutsideBounds) + public ILandObject GetLandObject(int x, int y, bool returnNullIfLandObjectOutsideBounds) { - if (x >= m_scene.RegionInfo.RegionSizeX || y >= m_scene.RegionInfo.RegionSizeY || x < 0 || y < 0) + if (x >= m_scene.RegionInfo.RegionSizeX || y >= m_scene.RegionInfo.RegionSizeY || x < 0 || y < 0) { // These exceptions here will cause a lot of complaints from the users specifically because // they happen every time at border crossings if (returnNullIfLandObjectOutsideBounds) return null; else - throw new Exception( - String.Format("{0} GetLandObject for non-existent position. Region={1}, pos=<{2},{3}", - LogHeader, m_scene.RegionInfo.RegionName, x, y) - ); + throw new Exception("Error: Parcel not found at point " + x + ", " + y); } - return m_landList[m_landIDList[x / 4, y / 4]]; + if(m_landList.Count == 0 || m_landIDList == null) + return null; + + lock (m_landIDList) + { + try + { + return m_landList[m_landIDList[x / 4, y / 4]]; + } + catch (IndexOutOfRangeException) + { + return null; + } + } } // Create a 'parcel is here' bitmap for the parcel identified by the passed landID @@ -926,7 +1031,7 @@ namespace OpenSim.Region.CoreModules.World.Land } } - public void FinalizeLandPrimCountUpdate() + private void FinalizeLandPrimCountUpdate() { //Get Simwide prim count for owner Dictionary> landOwnersAndParcels = new Dictionary>(); @@ -967,10 +1072,10 @@ namespace OpenSim.Region.CoreModules.World.Land public void EventManagerOnParcelPrimCountUpdate() { -// m_log.DebugFormat( -// "[LAND MANAGEMENT MODULE]: Triggered EventManagerOnParcelPrimCountUpdate() for {0}", -// m_scene.RegionInfo.RegionName); - + //m_log.DebugFormat( + // "[land management module]: triggered eventmanageronparcelprimcountupdate() for {0}", + // m_scene.RegionInfo.RegionName); + ResetOverMeRecords(); EntityBase[] entities = m_scene.Entities.GetEntities(); foreach (EntityBase obj in entities) @@ -1002,27 +1107,33 @@ namespace OpenSim.Region.CoreModules.World.Land /// North Point /// UUID of user who is trying to subdivide /// Returns true if successful - private void subdivide(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id) + public void Subdivide(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id) { //First, lets loop through the points and make sure they are all in the same peice of land //Get the land object at start ILandObject startLandObject = GetLandObject(start_x, start_y); - if (startLandObject == null) return; + if (startLandObject == null) + return; + + if (!m_scene.Permissions.CanEditParcelProperties(attempting_user_id, startLandObject, GroupPowers.LandDivideJoin, true)) + { + return; + } //Loop through the points try { - int totalX = end_x - start_x; - int totalY = end_y - start_y; - for (int y = 0; y < totalY; y++) + for (int y = start_y; y < end_y; y++) { - for (int x = 0; x < totalX; x++) + for (int x = start_x; x < end_x; x++) { - ILandObject tempLandObject = GetLandObject(start_x + x, start_y + y); - if (tempLandObject == null) return; - if (tempLandObject != startLandObject) return; + ILandObject tempLandObject = GetLandObject(x, y); + if (tempLandObject == null) + return; + if (tempLandObject != startLandObject) + return; } } } @@ -1031,22 +1142,22 @@ namespace OpenSim.Region.CoreModules.World.Land return; } - //If we are still here, then they are subdividing within one piece of land - //Check owner - if (!m_scene.Permissions.CanEditParcelProperties(attempting_user_id, startLandObject, GroupPowers.LandDivideJoin)) - { - return; - } - - //Lets create a new land object with bitmap activated at that point (keeping the old land objects info) + //Lets create a new land object with bitmap activated at that point (keeping the old land objects info) ILandObject newLand = startLandObject.Copy(); + newLand.LandData.Name = newLand.LandData.Name; newLand.LandData.GlobalID = UUID.Random(); newLand.LandData.Dwell = 0; + // Clear "Show in search" on the cut out parcel to prevent double-charging + newLand.LandData.Flags &= ~(uint)ParcelFlags.ShowDirectory; + // invalidate landing point + newLand.LandData.LandingType = (byte)LandingType.Direct; + newLand.LandData.UserLocation = Vector3.Zero; + newLand.LandData.UserLookAt = Vector3.Zero; newLand.SetLandBitmap(newLand.GetSquareLandBitmap(start_x, start_y, end_x, end_y)); - //Now, lets set the subdivision area of the original to false + //lets set the subdivision area of the original to false int startLandObjectIndex = startLandObject.LandData.LocalID; lock (m_landList) { @@ -1055,65 +1166,85 @@ namespace OpenSim.Region.CoreModules.World.Land m_landList[startLandObjectIndex].ForceUpdateLandInfo(); } - //Now add the new land object + //add the new land object ILandObject result = AddLandObject(newLand); - if (result != null) + UpdateLandObject(startLandObject.LandData.LocalID, startLandObject.LandData); + + if(startLandObject.LandData.LandingType == (byte)LandingType.LandingPoint) { - UpdateLandObject(startLandObject.LandData.LocalID, startLandObject.LandData); - result.SendLandUpdateToAvatarsOverMe(); - } + int x = (int)startLandObject.LandData.UserLocation.X; + int y = (int)startLandObject.LandData.UserLocation.Y; + if(!startLandObject.ContainsPoint(x, y)) + { + startLandObject.LandData.LandingType = (byte)LandingType.Direct; + startLandObject.LandData.UserLocation = Vector3.Zero; + startLandObject.LandData.UserLookAt = Vector3.Zero; + } + } + + m_scene.EventManager.TriggerParcelPrimCountTainted(); + + result.SendLandUpdateToAvatarsOverMe(); + startLandObject.SendLandUpdateToAvatarsOverMe(); + m_scene.ForEachClient(SendParcelOverlay); + } /// /// Join 2 land objects together /// - /// x value in first piece of land - /// y value in first piece of land - /// x value in second peice of land - /// y value in second peice of land + /// start x of selection area + /// start y of selection area + /// end x of selection area + /// end y of selection area /// UUID of the avatar trying to join the land objects /// Returns true if successful - private void join(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id) + public void Join(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id) { - end_x -= 4; - end_y -= 4; + int index = 0; + int maxindex = -1; + int maxArea = 0; List selectedLandObjects = new List(); - int stepYSelected; - for (stepYSelected = start_y; stepYSelected <= end_y; stepYSelected += 4) + for (int x = start_x; x < end_x; x += 4) { - int stepXSelected; - for (stepXSelected = start_x; stepXSelected <= end_x; stepXSelected += 4) + for (int y = start_y; y < end_y; y += 4) { - ILandObject p = GetLandObject(stepXSelected, stepYSelected); + ILandObject p = GetLandObject(x, y); if (p != null) { if (!selectedLandObjects.Contains(p)) { selectedLandObjects.Add(p); + if(p.LandData.Area > maxArea) + { + maxArea = p.LandData.Area; + maxindex = index; + } + index++; } } } } - ILandObject masterLandObject = selectedLandObjects[0]; - selectedLandObjects.RemoveAt(0); - if (selectedLandObjects.Count < 1) - { + if(maxindex < 0 || selectedLandObjects.Count < 2) return; - } - if (!m_scene.Permissions.CanEditParcelProperties(attempting_user_id, masterLandObject, GroupPowers.LandDivideJoin)) + + ILandObject masterLandObject = selectedLandObjects[maxindex]; + selectedLandObjects.RemoveAt(maxindex); + + if (!m_scene.Permissions.CanEditParcelProperties(attempting_user_id, masterLandObject, GroupPowers.LandDivideJoin, true)) { return; } + + UUID masterOwner = masterLandObject.LandData.OwnerID; foreach (ILandObject p in selectedLandObjects) { - if (p.LandData.OwnerID != masterLandObject.LandData.OwnerID) - { + if (p.LandData.OwnerID != masterOwner) return; - } } lock (m_landList) @@ -1126,29 +1257,14 @@ namespace OpenSim.Region.CoreModules.World.Land } } + m_scene.EventManager.TriggerParcelPrimCountTainted(); masterLandObject.SendLandUpdateToAvatarsOverMe(); + m_scene.ForEachClient(SendParcelOverlay); } - - public void Join(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id) - { - 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) - { - subdivide(start_x, start_y, end_x, end_y, attempting_user_id); - } - #endregion #region Parcel Updating - // Send parcel layer info for the whole region - public void SendParcelOverlay(IClientAPI remote_client) - { - SendParcelOverlay(remote_client, 0, 0, (int)Constants.MaximumRegionSize); - } - /// /// Send the parcel overlay blocks to the client. We send the overlay packets /// around a location and limited by the 'parcelLayerViewDistance'. This number @@ -1162,145 +1278,115 @@ namespace OpenSim.Region.CoreModules.World.Land /// X position in the region to send surrounding parcel layer info /// y position in the region to send surrounding parcel layer info /// Distance from x,y position to send parcel layer info - private void SendParcelOverlay(IClientAPI remote_client, int xPlace, int yPlace, int layerViewDistance) + public void SendParcelOverlay(IClientAPI remote_client) { + if (remote_client.SceneAgent.PresenceType == PresenceType.Npc) + return; + const int LAND_BLOCKS_PER_PACKET = 1024; byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET]; int byteArrayCount = 0; int sequenceID = 0; - int xLow = 0; - int xHigh = (int)m_scene.RegionInfo.RegionSizeX; - int yLow = 0; - int yHigh = (int)m_scene.RegionInfo.RegionSizeY; - - if (shouldLimitParcelLayerInfoToViewDistance) + // Layer data is in LandUnit (4m) chunks + for (int y = 0; y < m_scene.RegionInfo.RegionSizeY; y += LandUnit) { - // Compute view distance around the given point - int txLow = xPlace - layerViewDistance; - int txHigh = xPlace + layerViewDistance; - // If the distance is outside the region area, move the view distance to ba all in the region - if (txLow < xLow) + for (int x = 0; x < m_scene.RegionInfo.RegionSizeX; x += LandUnit) { - txLow = xLow; - txHigh = Math.Min(yLow + (layerViewDistance * 2), xHigh); - } - if (txHigh > xHigh) - { - txLow = Math.Max(xLow, xHigh - (layerViewDistance * 2)); - txHigh = xHigh; - } - xLow = txLow; - xHigh = txHigh; + byte tempByte = 0; //This represents the byte for the current 4x4 - int tyLow = yPlace - layerViewDistance; - int tyHigh = yPlace + layerViewDistance; - if (tyLow < yLow) - { - tyLow = yLow; - tyHigh = Math.Min(yLow + (layerViewDistance * 2), yHigh); - } - if (tyHigh > yHigh) - { - tyLow = Math.Max(yLow, yHigh - (layerViewDistance * 2)); - tyHigh = yHigh; - } - yLow = tyLow; - yHigh = tyHigh; - } - // m_log.DebugFormat("{0} SendParcelOverlay: place=<{1},{2}>, vDist={3}, xLH=<{4},{5}, yLH=<{6},{7}>", - // LogHeader, xPlace, yPlace, layerViewDistance, xLow, xHigh, yLow, yHigh); + ILandObject currentParcelBlock = GetLandObject(x, y); - // Layer data is in landUnit (4m) chunks - for (int y = yLow; y < yHigh / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); y++) - { - for (int x = xLow; x < xHigh / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); x++) - { - byteArray[byteArrayCount] = BuildLayerByte(GetLandObject(x * LandUnit, y * LandUnit), x, y, remote_client); - byteArrayCount++; - if (byteArrayCount >= LAND_BLOCKS_PER_PACKET) + if (currentParcelBlock != null) { - // m_log.DebugFormat("{0} SendParcelOverlay, sending packet, bytes={1}", LogHeader, byteArray.Length); - remote_client.SendLandParcelOverlay(byteArray, sequenceID); - byteArrayCount = 0; - sequenceID++; - byteArray = new byte[LAND_BLOCKS_PER_PACKET]; - } + // types + if (currentParcelBlock.LandData.OwnerID == remote_client.AgentId) + { + //Owner Flag + tempByte = (byte)LandChannel.LAND_TYPE_OWNED_BY_REQUESTER; + } + else if (currentParcelBlock.LandData.IsGroupOwned && remote_client.IsGroupMember(currentParcelBlock.LandData.GroupID)) + { + tempByte = (byte)LandChannel.LAND_TYPE_OWNED_BY_GROUP; + } + else if (currentParcelBlock.LandData.SalePrice > 0 && + (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero || + currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId)) + { + //Sale type + tempByte = (byte)LandChannel.LAND_TYPE_IS_FOR_SALE; + } + else if (currentParcelBlock.LandData.OwnerID == UUID.Zero) + { + //Public type + tempByte = (byte)LandChannel.LAND_TYPE_PUBLIC; // this does nothing, its zero + } + // LAND_TYPE_IS_BEING_AUCTIONED still unsuported + else + { + //Other Flag + tempByte = (byte)LandChannel.LAND_TYPE_OWNED_BY_OTHER; + } - } - } + // now flags + // border control - if (byteArrayCount != 0) - { - remote_client.SendLandParcelOverlay(byteArray, sequenceID); - // m_log.DebugFormat("{0} SendParcelOverlay, complete sending packet, bytes={1}", LogHeader, byteArray.Length); - } - } + ILandObject westParcel = null; + ILandObject southParcel = null; + if (x > 0) + { + westParcel = GetLandObject((x - 1), y); + } + if (y > 0) + { + southParcel = GetLandObject(x, (y - 1)); + } - private byte BuildLayerByte(ILandObject currentParcelBlock, int x, int y, IClientAPI remote_client) - { - byte tempByte = 0; //This represents the byte for the current 4x4 + if (x == 0) + { + tempByte |= (byte)LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST; + } + else if (westParcel != null && westParcel != currentParcelBlock) + { + tempByte |= (byte)LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST; + } - if (currentParcelBlock != null) - { - if (currentParcelBlock.LandData.OwnerID == remote_client.AgentId) - { - //Owner Flag - tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER); - } - else if (currentParcelBlock.LandData.SalePrice > 0 && - (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero || - currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId)) - { - //Sale Flag - tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_IS_FOR_SALE); - } - else if (currentParcelBlock.LandData.OwnerID == UUID.Zero) - { - //Public Flag - tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_PUBLIC); - } - else - { - //Other Flag - tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_OTHER); - } + if (y == 0) + { + tempByte |= (byte)LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH; + } + else if (southParcel != null && southParcel != currentParcelBlock) + { + tempByte |= (byte)LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH; + } - //Now for border control + // local sound + if ((currentParcelBlock.LandData.Flags & (uint)ParcelFlags.SoundLocal) != 0) + tempByte |= (byte)LandChannel.LAND_FLAG_LOCALSOUND; - ILandObject westParcel = null; - ILandObject southParcel = null; - if (x > 0) - { - westParcel = GetLandObject((x - 1) * LandUnit, y * LandUnit); - } - if (y > 0) - { - southParcel = GetLandObject(x * LandUnit, (y - 1) * LandUnit); - } + // hide avatars + if (!currentParcelBlock.LandData.SeeAVs) + tempByte |= (byte)LandChannel.LAND_FLAG_HIDEAVATARS; - if (x == 0) - { - tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST); - } - else if (westParcel != null && westParcel != currentParcelBlock) - { - tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST); - } - if (y == 0) - { - tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH); - } - else if (southParcel != null && southParcel != currentParcelBlock) - { - tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH); + byteArray[byteArrayCount] = tempByte; + byteArrayCount++; + if (byteArrayCount >= LAND_BLOCKS_PER_PACKET) + { + remote_client.SendLandParcelOverlay(byteArray, sequenceID); + byteArrayCount = 0; + sequenceID++; + byteArray = new byte[LAND_BLOCKS_PER_PACKET]; + } + } } - } - return tempByte; + if (byteArrayCount > 0) + { + remote_client.SendLandParcelOverlay(byteArray, sequenceID); + } } public void ClientOnParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id, @@ -1320,8 +1406,11 @@ namespace OpenSim.Region.CoreModules.World.Land { if (!temp.Contains(currentParcel)) { - currentParcel.ForceUpdateLandInfo(); - temp.Add(currentParcel); + if (!currentParcel.IsBannedFromLand(remote_client.AgentId)) + { + currentParcel.ForceUpdateLandInfo(); + temp.Add(currentParcel); + } } } } @@ -1338,8 +1427,44 @@ namespace OpenSim.Region.CoreModules.World.Land temp[i].SendLandProperties(sequence_id, snap_selection, requestResult, remote_client); } - // Also send the layer data around the point of interest - SendParcelOverlay(remote_client, (start_x + end_x) / 2, (start_y + end_y) / 2, parcelLayerViewDistance); +// SendParcelOverlay(remote_client); + } + + public void UpdateLandProperties(ILandObject land, LandUpdateArgs args, IClientAPI remote_client) + { + bool snap_selection = false; + bool needOverlay = false; + if (land.UpdateLandProperties(args, remote_client, out snap_selection, out needOverlay)) + { + UUID parcelID = land.LandData.GlobalID; + m_scene.ForEachScenePresence(delegate(ScenePresence avatar) + { + if (avatar.IsDeleted || avatar.IsNPC) + return; + + IClientAPI client = avatar.ControllingClient; + if (needOverlay) + SendParcelOverlay(client); + + if (avatar.IsChildAgent) + { + if(client == remote_client) + land.SendLandProperties(-10000, false, LandChannel.LAND_RESULT_SINGLE, client); + return; + } + + ILandObject aland = GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); + if (aland != null) + { + if(client == remote_client && land != aland) + land.SendLandProperties(-10000, false, LandChannel.LAND_RESULT_SINGLE, client); + else if (land == aland) + aland.SendLandProperties(0, false, LandChannel.LAND_RESULT_SINGLE, client); + } + if (avatar.currentParcelUUID == parcelID) + avatar.currentParcelUUID = parcelID; // force parcel flags review + }); + } } public void ClientOnParcelPropertiesUpdateRequest(LandUpdateArgs args, int localID, IClientAPI remote_client) @@ -1352,19 +1477,19 @@ namespace OpenSim.Region.CoreModules.World.Land if (land != null) { - land.UpdateLandProperties(args, remote_client); + UpdateLandProperties(land, args, remote_client); m_scene.EventManager.TriggerOnParcelPropertiesUpdateRequest(args, localID, remote_client); } } public void ClientOnParcelDivideRequest(int west, int south, int east, int north, IClientAPI remote_client) { - subdivide(west, south, east, north, remote_client.AgentId); + Subdivide(west, south, east, north, remote_client.AgentId); } public void ClientOnParcelJoinRequest(int west, int south, int east, int north, IClientAPI remote_client) { - join(west, south, east, north, remote_client.AgentId); + Join(west, south, east, north, remote_client.AgentId); } public void ClientOnParcelSelectObjects(int local_id, int request_type, @@ -1375,7 +1500,7 @@ namespace OpenSim.Region.CoreModules.World.Land public void ClientOnParcelObjectOwnerRequest(int local_id, IClientAPI remote_client) { - ILandObject land; + ILandObject land = null; lock (m_landList) { m_landList.TryGetValue(local_id, out land); @@ -1384,7 +1509,7 @@ namespace OpenSim.Region.CoreModules.World.Land if (land != null) { m_scene.EventManager.TriggerParcelPrimCountUpdate(); - m_landList[local_id].SendLandObjectOwners(remote_client); + land.SendLandObjectOwners(remote_client); } else { @@ -1394,7 +1519,7 @@ namespace OpenSim.Region.CoreModules.World.Land public void ClientOnParcelGodForceOwner(int local_id, UUID ownerID, IClientAPI remote_client) { - ILandObject land; + ILandObject land = null; lock (m_landList) { m_landList.TryGetValue(local_id, out land); @@ -1408,7 +1533,6 @@ namespace OpenSim.Region.CoreModules.World.Land land.LandData.GroupID = UUID.Zero; land.LandData.IsGroupOwned = false; land.LandData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory); - m_scene.ForEachClient(SendParcelOverlay); land.SendLandUpdateToClient(true, remote_client); UpdateLandObject(land.LandData.LocalID, land.LandData); @@ -1418,7 +1542,7 @@ namespace OpenSim.Region.CoreModules.World.Land public void ClientOnParcelAbandonRequest(int local_id, IClientAPI remote_client) { - ILandObject land; + ILandObject land = null; lock (m_landList) { m_landList.TryGetValue(local_id, out land); @@ -1432,7 +1556,7 @@ namespace OpenSim.Region.CoreModules.World.Land land.LandData.GroupID = UUID.Zero; land.LandData.IsGroupOwned = false; land.LandData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory); - + m_scene.ForEachClient(SendParcelOverlay); land.SendLandUpdateToClient(true, remote_client); UpdateLandObject(land.LandData.LocalID, land.LandData); @@ -1442,7 +1566,7 @@ namespace OpenSim.Region.CoreModules.World.Land public void ClientOnParcelReclaim(int local_id, IClientAPI remote_client) { - ILandObject land; + ILandObject land = null; lock (m_landList) { m_landList.TryGetValue(local_id, out land); @@ -1458,8 +1582,10 @@ namespace OpenSim.Region.CoreModules.World.Land land.LandData.IsGroupOwned = false; land.LandData.SalePrice = 0; land.LandData.AuthBuyerID = UUID.Zero; + land.LandData.SeeAVs = true; + land.LandData.AnyAVSounds = true; + land.LandData.GroupAVSounds = true; land.LandData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory); - m_scene.ForEachClient(SendParcelOverlay); land.SendLandUpdateToClient(true, remote_client); UpdateLandObject(land.LandData.LocalID, land.LandData); @@ -1526,17 +1652,16 @@ namespace OpenSim.Region.CoreModules.World.Land void ClientOnParcelDeedToGroup(int parcelLocalID, UUID groupID, IClientAPI remote_client) { - ILandObject land; + ILandObject land = null; lock (m_landList) { m_landList.TryGetValue(parcelLocalID, out land); } - if (!m_scene.Permissions.CanDeedParcel(remote_client.AgentId, land)) - return; - if (land != null) { + if (!m_scene.Permissions.CanDeedParcel(remote_client.AgentId, land)) + return; land.DeedToGroup(groupID); } } @@ -1545,17 +1670,12 @@ namespace OpenSim.Region.CoreModules.World.Land private void EventManagerOnIncomingLandDataFromStorage(List data) { -// m_log.DebugFormat( -// "[LAND MANAGMENT MODULE]: Processing {0} incoming parcels on {1}", data.Count, m_scene.Name); - - // Prevent race conditions from any auto-creation of new parcels for varregions whilst we are still loading - // the existing parcels. lock (m_landList) { for (int i = 0; i < data.Count; i++) IncomingLandObjectFromStorage(data[i]); - // Layer data is in landUnit (4m) chunks + // Layer data is in LandUnit (4m) chunks for (int y = 0; y < m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); y++) { for (int x = 0; x < m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); x++) @@ -1565,7 +1685,7 @@ namespace OpenSim.Region.CoreModules.World.Land if (m_landList.Count == 1) { m_log.DebugFormat( - "[{0}]: Auto-extending land parcel as landID at {1},{2} is 0 and only one land parcel is present in {3}", + "[{0}]: Auto-extending land parcel as landID at {1},{2} is 0 and only one land parcel is present in {3}", LogHeader, x, y, m_scene.Name); int onlyParcelID = 0; @@ -1588,11 +1708,11 @@ namespace OpenSim.Region.CoreModules.World.Land else if (m_landList.Count > 1) { m_log.DebugFormat( - "{0}: Auto-creating land parcel as landID at {1},{2} is 0 and more than one land parcel is present in {3}", + "{0}: Auto-creating land parcel as landID at {1},{2} is 0 and more than one land parcel is present in {3}", LogHeader, x, y, m_scene.Name); // There are several other parcels so we must create a new one for the unassigned space - ILandObject newLand = new LandObject(UUID.Zero, false, m_scene); + ILandObject newLand = new LandObject(UUID.Zero, false, m_scene); // Claim all the unclaimed "0" ids newLand.SetLandBitmap(CreateBitmapForID(0)); newLand.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; @@ -1603,20 +1723,23 @@ namespace OpenSim.Region.CoreModules.World.Land { // We should never reach this point as the separate code path when no land data exists should have fired instead. m_log.WarnFormat( - "{0}: Ignoring request to auto-create parcel in {1} as there are no other parcels present", + "{0}: Ignoring request to auto-create parcel in {1} as there are no other parcels present", LogHeader, m_scene.Name); } } } } + FinalizeLandPrimCountUpdate(); // update simarea information } } private void IncomingLandObjectFromStorage(LandData data) { - ILandObject new_land = new LandObject(data, m_scene); - new_land.SetLandBitmapFromByteArray(); + ILandObject new_land = new LandObject(data.OwnerID, data.IsGroupOwned, m_scene, data); + + new_land.SetLandBitmapFromByteArray(); AddLandObject(new_land); +// new_land.SendLandUpdateToAvatarsOverMe(); } public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient) @@ -1629,7 +1752,7 @@ namespace OpenSim.Region.CoreModules.World.Land m_landList.TryGetValue(localID, out selectedParcel); } - if (selectedParcel == null) + if (selectedParcel == null) return; selectedParcel.ReturnLandObjects(returnType, agentIDs, taskIDs, remoteClient); @@ -1670,9 +1793,9 @@ namespace OpenSim.Region.CoreModules.World.Land foreach (HashSet objs in returns.Values) { List objs2 = new List(objs); - if (m_scene.Permissions.CanReturnObjects(null, remoteClient.AgentId, objs2)) + if (m_scene.Permissions.CanReturnObjects(null, remoteClient, objs2)) { - m_scene.returnObjects(objs2.ToArray(), remoteClient.AgentId); + m_scene.returnObjects(objs2.ToArray(), remoteClient); } else { @@ -1710,12 +1833,13 @@ namespace OpenSim.Region.CoreModules.World.Land private void EventManagerOnRegisterCaps(UUID agentID, Caps caps) { + //string capsBase = "/CAPS/" + UUID.Random(); string capsBase = "/CAPS/" + caps.CapsObjectPath; caps.RegisterHandler( "RemoteParcelRequest", new RestStreamHandler( "POST", - capsBase + remoteParcelRequestPath, + capsBase, (request, path, param, httpRequest, httpResponse) => RemoteParcelRequest(request, path, param, agentID, caps), "RemoteParcelRequest", @@ -1735,7 +1859,7 @@ namespace OpenSim.Region.CoreModules.World.Land private string ProcessPropertiesUpdate(string request, string path, string param, UUID agentID, Caps caps) { IClientAPI client; - if (!m_scene.TryGetClient(agentID, out client)) + if (!m_scene.TryGetClient(agentID, out client)) { m_log.WarnFormat("[LAND MANAGEMENT MODULE]: Unable to retrieve IClientAPI for {0}", agentID); return LLSDHelpers.SerialiseLLSDReply(new LLSDEmpty()); @@ -1759,7 +1883,7 @@ namespace OpenSim.Region.CoreModules.World.Land land_update.MusicURL = properties.MusicURL; land_update.Name = properties.Name; land_update.ParcelFlags = (uint) properties.ParcelFlags; - land_update.PassHours = (int) properties.PassHours; + land_update.PassHours = properties.PassHours; land_update.PassPrice = (int) properties.PassPrice; land_update.SalePrice = (int) properties.SalePrice; land_update.SnapshotID = properties.SnapshotID; @@ -1773,7 +1897,20 @@ namespace OpenSim.Region.CoreModules.World.Land land_update.ObscureMusic = properties.ObscureMusic; land_update.ObscureMedia = properties.ObscureMedia; - ILandObject land; + if (args.ContainsKey("see_avs")) + { + land_update.SeeAVs = args["see_avs"].AsBoolean(); + land_update.AnyAVSounds = args["any_av_sounds"].AsBoolean(); + land_update.GroupAVSounds = args["group_av_sounds"].AsBoolean(); + } + else + { + land_update.SeeAVs = true; + land_update.AnyAVSounds = true; + land_update.GroupAVSounds = true; + } + + ILandObject land = null; lock (m_landList) { m_landList.TryGetValue(parcelID, out land); @@ -1781,13 +1918,14 @@ namespace OpenSim.Region.CoreModules.World.Land if (land != null) { - land.UpdateLandProperties(land_update, client); + UpdateLandProperties(land,land_update, client); m_scene.EventManager.TriggerOnParcelPropertiesUpdateRequest(land_update, parcelID, client); } else { m_log.WarnFormat("[LAND MANAGEMENT MODULE]: Unable to find parcelID {0}", parcelID); } + return LLSDHelpers.SerialiseLLSDReply(new LLSDEmpty()); } // we cheat here: As we don't have (and want) a grid-global parcel-store, we can't return the @@ -1815,9 +1953,9 @@ namespace OpenSim.Region.CoreModules.World.Land { Hashtable hash = new Hashtable(); hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); - if (hash.ContainsKey("region_id") && hash.ContainsKey("location")) + if (hash.ContainsKey("location")) { - UUID regionID = (UUID)hash["region_id"]; + UUID scope = m_scene.RegionInfo.ScopeID; ArrayList list = (ArrayList)hash["location"]; uint x = (uint)(double)list[0]; uint y = (uint)(double)list[1]; @@ -1826,19 +1964,46 @@ namespace OpenSim.Region.CoreModules.World.Land // if you do a "About Landmark" on a landmark a second time, the viewer sends the // region_handle it got earlier via RegionHandleRequest ulong regionHandle = Util.BytesToUInt64Big((byte[])hash["region_handle"]); - parcelID = Util.BuildFakeParcelID(regionHandle, x, y); + if(regionHandle == m_scene.RegionInfo.RegionHandle) + parcelID = Util.BuildFakeParcelID(regionHandle, x, y); + else + { + uint wx; + uint wy; + Util.RegionHandleToWorldLoc(regionHandle, out wx, out wy); + GridRegion info = m_scene.GridService.GetRegionByPosition(scope, (int)wx, (int)wy); + if(info != null) + { + wx -= (uint)info.RegionLocX; + wy -= (uint)info.RegionLocY; + wx += x; + wy += y; + // Firestorm devs have no ideia how to do handlers math + // on all cases + if(wx > info.RegionSizeX || wy > info.RegionSizeY) + { + wx = x; + wy = y; + } + parcelID = Util.BuildFakeParcelID(info.RegionHandle, wx, wy); + } + } } - else if (regionID == m_scene.RegionInfo.RegionID) + else if(hash.ContainsKey("region_id")) { + UUID regionID = (UUID)hash["region_id"]; + if (regionID == m_scene.RegionInfo.RegionID) + { // a parcel request for a local parcel => no need to query the grid - parcelID = Util.BuildFakeParcelID(m_scene.RegionInfo.RegionHandle, x, y); - } - else - { - // a parcel request for a parcel in another region. Ask the grid about the region - GridRegion info = m_scene.GridService.GetRegionByUUID(UUID.Zero, regionID); - if (info != null) - parcelID = Util.BuildFakeParcelID(info.RegionHandle, x, y); + parcelID = Util.BuildFakeParcelID(m_scene.RegionInfo.RegionHandle, x, y); + } + else + { + // a parcel request for a parcel in another region. Ask the grid about the region + GridRegion info = m_scene.GridService.GetRegionByUUID(scope, regionID); + if (info != null) + parcelID = Util.BuildFakeParcelID(info.RegionHandle, x, y); + } } } } @@ -1854,7 +2019,7 @@ namespace OpenSim.Region.CoreModules.World.Land LLSDRemoteParcelResponse response = new LLSDRemoteParcelResponse(); response.parcel_id = parcelID; - m_log.DebugFormat("[LAND MANAGEMENT MODULE]: Got parcelID {0}", parcelID); + //m_log.DebugFormat("[LAND MANAGEMENT MODULE]: Got parcelID {0}", parcelID); return LLSDHelpers.SerialiseLLSDReply(response); } @@ -1871,17 +2036,25 @@ namespace OpenSim.Region.CoreModules.World.Land { UUID parcel = UUID.Zero; UUID.TryParse(id, out parcel); + // assume we've got the parcelID we just computed in RemoteParcelRequest ExtendedLandData extLandData = new ExtendedLandData(); - Util.ParseFakeParcelID(parcel, out extLandData.RegionHandle, - out extLandData.X, out extLandData.Y); - m_log.DebugFormat("[LAND MANAGEMENT MODULE]: Got parcelinfo request for regionHandle {0}, x/y {1}/{2}", + if(!Util.ParseFakeParcelID(parcel, out extLandData.RegionHandle, + out extLandData.X, out extLandData.Y)) + return null; + m_log.DebugFormat("[LAND MANAGEMENT MODULE] : Got parcelinfo request for regionHandle {0}, x/y {1}/{2}", extLandData.RegionHandle, extLandData.X, extLandData.Y); // for this region or for somewhere else? if (extLandData.RegionHandle == m_scene.RegionInfo.RegionHandle) { - extLandData.LandData = this.GetLandObject(extLandData.X, extLandData.Y).LandData; + ILandObject extLandObject = this.GetLandObject(extLandData.X, extLandData.Y); + if(extLandObject == null) + { + m_log.DebugFormat("[LAND MANAGEMENT MODULE]: ParcelInfoRequest: a FakeParcelID points to outside the region"); + return null; + } + extLandData.LandData = extLandObject.LandData; extLandData.RegionAccess = m_scene.RegionInfo.AccessLevel; } else @@ -1907,6 +2080,9 @@ namespace OpenSim.Region.CoreModules.World.Land if (data.RegionHandle == m_scene.RegionInfo.RegionHandle) { info = new GridRegion(m_scene.RegionInfo); + IDwellModule dwellModule = m_scene.RequestModuleInterface(); + if (dwellModule != null) + data.LandData.Dwell = dwellModule.GetDwell(data.LandData); } else { @@ -1932,7 +2108,7 @@ namespace OpenSim.Region.CoreModules.World.Land public void setParcelOtherCleanTime(IClientAPI remoteClient, int localID, int otherCleanTime) { - ILandObject land; + ILandObject land = null; lock (m_landList) { m_landList.TryGetValue(localID, out land); @@ -1940,14 +2116,91 @@ namespace OpenSim.Region.CoreModules.World.Land if (land == null) return; - if (!m_scene.Permissions.CanEditParcelProperties(remoteClient.AgentId, land, GroupPowers.LandOptions)) + if (!m_scene.Permissions.CanEditParcelProperties(remoteClient.AgentId, land, GroupPowers.LandOptions, false)) return; land.LandData.OtherCleanTime = otherCleanTime; UpdateLandObject(localID, land.LandData); } - + + public void ClientOnParcelGodMark(IClientAPI client, UUID god, int landID) + { + ILandObject land = null; + List Land = ((Scene)client.Scene).LandChannel.AllParcels(); + foreach (ILandObject landObject in Land) + { + if (landObject.LandData.LocalID == landID) + { + land = landObject; + } + } + land.DeedToGroup(DefaultGodParcelGroup); + land.LandData.Name = DefaultGodParcelName; + land.SendLandUpdateToAvatarsOverMe(); + } + + private void ClientOnSimWideDeletes(IClientAPI client, UUID agentID, int flags, UUID targetID) + { + ScenePresence SP; + ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out SP); + List returns = new List(); + if (SP.GodController.UserLevel != 0) + { + if (flags == 0) //All parcels, scripted or not + { + ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e) + { + if (e.OwnerID == targetID) + { + returns.Add(e); + } + } + ); + } + if (flags == 4) //All parcels, scripted object + { + ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e) + { + if (e.OwnerID == targetID) + { + if (e.ContainsScripts()) + { + returns.Add(e); + } + } + }); + } + if (flags == 4) //not target parcel, scripted object + { + ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e) + { + if (e.OwnerID == targetID) + { + ILandObject landobject = ((Scene)client.Scene).LandChannel.GetLandObject(e.AbsolutePosition.X, e.AbsolutePosition.Y); + if (landobject.LandData.OwnerID != e.OwnerID) + { + if (e.ContainsScripts()) + { + returns.Add(e); + } + } + } + }); + } + foreach (SceneObjectGroup ol in returns) + { + ReturnObject(ol, client); + } + } + } + public void ReturnObject(SceneObjectGroup obj, IClientAPI client) + { + SceneObjectGroup[] objs = new SceneObjectGroup[1]; + objs[0] = obj; + ((Scene)client.Scene).returnObjects(objs, client); + } + Dictionary Timers = new Dictionary(); public void ClientOnParcelFreezeUser(IClientAPI client, UUID parcelowner, uint flags, UUID target) @@ -1958,12 +2211,12 @@ namespace OpenSim.Region.CoreModules.World.Land ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out parcelManager); System.Threading.Timer Timer; - if (targetAvatar.UserLevel == 0) + if (targetAvatar.GodController.UserLevel < 200) { ILandObject land = ((Scene)client.Scene).LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y); - if (!((Scene)client.Scene).Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze)) + if (!((Scene)client.Scene).Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze, true)) return; - if (flags == 0) + if ((flags & 1) == 0) // only lowest bit has meaning for now { targetAvatar.AllowMovement = false; targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has frozen you for 30 seconds. You cannot move or interact with the world."); @@ -1983,7 +2236,6 @@ namespace OpenSim.Region.CoreModules.World.Land } } } - private void OnEndParcelFrozen(object avatar) { ScenePresence targetAvatar = (ScenePresence)avatar; @@ -2010,12 +2262,13 @@ namespace OpenSim.Region.CoreModules.World.Land // Check if you even have permission to do this ILandObject land = m_scene.LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y); - if (!m_scene.Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze) && + if (!m_scene.Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze, true) && !m_scene.Permissions.IsAdministrator(client.AgentId)) return; + Vector3 pos = m_scene.GetNearestAllowedPosition(targetAvatar, land); - targetAvatar.TeleportWithMomentum(pos, null); + targetAvatar.TeleportOnEject(pos); targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname); parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected."); @@ -2059,7 +2312,7 @@ namespace OpenSim.Region.CoreModules.World.Land if (// Required: local user; foreign users cannot set home m_scene.UserManagementModule.IsLocalGridUser(remoteClient.AgentId) && (// (a) gods and land managers can set home - m_scene.Permissions.IsAdministrator(remoteClient.AgentId) || + m_scene.Permissions.IsAdministrator(remoteClient.AgentId) || m_scene.Permissions.IsGod(remoteClient.AgentId) || // (b) land owners can set home remoteClient.AgentId == land.LandData.OwnerID || @@ -2111,8 +2364,8 @@ namespace OpenSim.Region.CoreModules.World.Land "If no local land ID is given, then summary information about all the parcels is shown.\n" + "If a local land ID is given then full information about that parcel is shown.", HandleShowCommand); - } - + } + protected void HandleClearCommand(string module, string[] args) { if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene)) @@ -2120,9 +2373,9 @@ namespace OpenSim.Region.CoreModules.World.Land string response = MainConsole.Instance.CmdPrompt( string.Format( - "Are you sure that you want to clear all land parcels from {0} (y or n)", m_scene.Name), + "Are you sure that you want to clear all land parcels from {0} (y or n)", m_scene.Name), "n"); - + if (response.ToLower() == "y") { Clear(true); @@ -2132,14 +2385,14 @@ namespace OpenSim.Region.CoreModules.World.Land { MainConsole.Instance.OutputFormat("Aborting clear of all parcels from {0}", m_scene.Name); } - } - + } + protected void HandleShowCommand(string module, string[] args) { if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene)) return; - StringBuilder report = new StringBuilder(); + StringBuilder report = new StringBuilder(); if (args.Length <= 2) { @@ -2152,10 +2405,10 @@ namespace OpenSim.Region.CoreModules.World.Land if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[2], out landLocalId)) return; - ILandObject lo; + ILandObject lo = null; lock (m_landList) - { + { if (!m_landList.TryGetValue(landLocalId, out lo)) { MainConsole.Instance.OutputFormat("No parcel found with local ID {0}", landLocalId); @@ -2170,7 +2423,7 @@ namespace OpenSim.Region.CoreModules.World.Land } private void AppendParcelsSummaryReport(StringBuilder report) - { + { report.AppendFormat("Land information for {0}\n", m_scene.Name); ConsoleDisplayTable cdt = new ConsoleDisplayTable(); @@ -2180,7 +2433,7 @@ namespace OpenSim.Region.CoreModules.World.Land cdt.AddColumn("Starts", ConsoleDisplayUtil.VectorSize); cdt.AddColumn("Ends", ConsoleDisplayUtil.VectorSize); cdt.AddColumn("Owner", ConsoleDisplayUtil.UserNameSize); - + lock (m_landList) { foreach (ILandObject lo in m_landList.Values) @@ -2202,7 +2455,7 @@ namespace OpenSim.Region.CoreModules.World.Land } report.Append(cdt.ToString()); - } + } private void AppendParcelReport(StringBuilder report, ILandObject lo) { @@ -2214,8 +2467,6 @@ namespace OpenSim.Region.CoreModules.World.Land cdl.AddRow("Description", ld.Description); cdl.AddRow("Snapshot ID", ld.SnapshotID); cdl.AddRow("Area", ld.Area); - cdl.AddRow("Starts", lo.StartPoint); - cdl.AddRow("Ends", lo.EndPoint); cdl.AddRow("AABB Min", ld.AABBMin); cdl.AddRow("AABB Max", ld.AABBMax); string ownerName; @@ -2233,7 +2484,7 @@ namespace OpenSim.Region.CoreModules.World.Land cdl.AddRow("GroupID", ld.GroupID); cdl.AddRow("Status", ld.Status); - cdl.AddRow("Flags", (ParcelFlags)ld.Flags); + cdl.AddRow("Flags", (ParcelFlags)ld.Flags); cdl.AddRow("Landing Type", (LandingType)ld.LandingType); cdl.AddRow("User Location", ld.UserLocation); @@ -2242,12 +2493,14 @@ namespace OpenSim.Region.CoreModules.World.Land cdl.AddRow("Other clean time", ld.OtherCleanTime); cdl.AddRow("Max Prims", lo.GetParcelMaxPrimCount()); + cdl.AddRow("Simwide Max Prims (owner)", lo.GetSimulatorMaxPrimCount()); IPrimCounts pc = lo.PrimCounts; cdl.AddRow("Owner Prims", pc.Owner); cdl.AddRow("Group Prims", pc.Group); cdl.AddRow("Other Prims", pc.Others); cdl.AddRow("Selected Prims", pc.Selected); cdl.AddRow("Total Prims", pc.Total); + cdl.AddRow("SimWide Prims (owner)", pc.Simulator); cdl.AddRow("Music URL", ld.MusicURL); cdl.AddRow("Obscure Music", ld.ObscureMusic); diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index a0c1b9d..4471432 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs @@ -50,15 +50,22 @@ namespace OpenSim.Region.CoreModules.World.Land private readonly int landUnit = 4; private int m_lastSeqId = 0; - + private int m_expiryCounter = 0; + protected Scene m_scene; protected List primsOverMe = new List(); protected Dictionary m_listTransactions = new Dictionary(); protected ExpiringCache m_groupMemberCache = new ExpiringCache(); protected TimeSpan m_groupMemberCacheTimeout = TimeSpan.FromSeconds(30); // cache invalidation after 30 seconds + IDwellModule m_dwellModule; - public bool[,] LandBitmap { get; set; } + private bool[,] m_landBitmap; + public bool[,] LandBitmap + { + get { return m_landBitmap; } + set { m_landBitmap = value; } + } #endregion @@ -69,7 +76,13 @@ namespace OpenSim.Region.CoreModules.World.Land return free; } - public LandData LandData { get; set; } + protected LandData m_landData; + public LandData LandData + { + get { return m_landData; } + + set { m_landData = value; } + } public IPrimCounts PrimCounts { get; set; } @@ -78,77 +91,230 @@ namespace OpenSim.Region.CoreModules.World.Land get { return m_scene.RegionInfo.RegionID; } } - public Vector3 StartPoint + private Vector2 m_startPoint = Vector2.Zero; + private Vector2 m_endPoint = Vector2.Zero; + private Vector2 m_centerPoint = Vector2.Zero; + private Vector2 m_AABBmin = Vector2.Zero; + private Vector2 m_AABBmax = Vector2.Zero; + + public Vector2 StartPoint { get { - for (int y = 0; y < LandBitmap.GetLength(1); y++) - { - for (int x = 0; x < LandBitmap.GetLength(0); x++) - { - if (LandBitmap[x, y]) - return new Vector3(x * landUnit, y * landUnit, 0); - } - } + return m_startPoint; + } + } - m_log.ErrorFormat("{0} StartPoint. No start point found. bitmapSize=<{1},{2}>", - LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1)); - return new Vector3(-1, -1, -1); + public Vector2 EndPoint + { + get + { + return m_endPoint; } } - public Vector3 EndPoint + //estimate a center point of a parcel + public Vector2 CenterPoint { get { - for (int y = LandBitmap.GetLength(1) - 1; y >= 0; y--) + return m_centerPoint; + } + } + + public Vector2? GetNearestPoint(Vector3 pos) + { + Vector3 direction = new Vector3(m_centerPoint.X - pos.X, m_centerPoint.Y - pos.Y, 0f ); + return GetNearestPointAlongDirection(pos, direction); + } + + public Vector2? GetNearestPointAlongDirection(Vector3 pos, Vector3 pdirection) + { + Vector2 testpos; + Vector2 direction; + + testpos.X = pos.X / landUnit; + testpos.Y = pos.Y / landUnit; + + if(LandBitmap[(int)testpos.X, (int)testpos.Y]) + return new Vector2(pos.X, pos.Y); // we are already here + + direction.X = pdirection.X; + direction.Y = pdirection.Y; + + if(direction.X == 0f && direction.Y == 0f) + return null; // we can't look anywhere + + direction.Normalize(); + + int minx = (int)(m_AABBmin.X / landUnit); + int maxx = (int)(m_AABBmax.X / landUnit); + + // check against AABB + if(direction.X > 0f) + { + if(testpos.X >= maxx) + return null; // will never get there + if(testpos.X < minx) + testpos.X = minx; + } + else if(direction.X < 0f) + { + if(testpos.X < minx) + return null; // will never get there + if(testpos.X >= maxx) + testpos.X = maxx - 1; + } + else + { + if(testpos.X < minx) + return null; // will never get there + else if(testpos.X >= maxx) + return null; // will never get there + } + + int miny = (int)(m_AABBmin.Y / landUnit); + int maxy = (int)(m_AABBmax.Y / landUnit); + + if(direction.Y > 0f) + { + if(testpos.Y >= maxy) + return null; // will never get there + if(testpos.Y < miny) + testpos.Y = miny; + } + else if(direction.Y < 0f) + { + if(testpos.Y < miny) + return null; // will never get there + if(testpos.Y >= maxy) + testpos.Y = maxy - 1; + } + else + { + if(testpos.Y < miny) + return null; // will never get there + else if(testpos.Y >= maxy) + return null; // will never get there + } + + while(!LandBitmap[(int)testpos.X, (int)testpos.Y]) + { + testpos += direction; + + if(testpos.X < minx) + return null; + if (testpos.X >= maxx) + return null; + if(testpos.Y < miny) + return null; + if (testpos.Y >= maxy) + return null; + } + + testpos *= landUnit; + float ftmp; + + if(Math.Abs(direction.X) > Math.Abs(direction.Y)) + { + if(direction.X < 0) + testpos.X += landUnit - 0.5f; + else + testpos.X += 0.5f; + ftmp = testpos.X - pos.X; + ftmp /= direction.X; + ftmp = Math.Abs(ftmp); + ftmp *= direction.Y; + ftmp += pos.Y; + + if(ftmp < testpos.Y + .5f) + ftmp = testpos.Y + .5f; + else { - for (int x = LandBitmap.GetLength(0) - 1; x >= 0; x--) - { - if (LandBitmap[x, y]) - { - return new Vector3(x * landUnit + landUnit, y * landUnit + landUnit, 0); - } - } + testpos.Y += landUnit - 0.5f; + if(ftmp > testpos.Y) + ftmp = testpos.Y; } - - m_log.ErrorFormat("{0} EndPoint. No end point found. bitmapSize=<{1},{2}>", - LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1)); - return new Vector3(-1, -1, -1); + testpos.Y = ftmp; + } + else + { + if(direction.Y < 0) + testpos.Y += landUnit - 0.5f; + else + testpos.Y += 0.5f; + ftmp = testpos.Y - pos.Y; + ftmp /= direction.Y; + ftmp = Math.Abs(ftmp); + ftmp *= direction.X; + ftmp += pos.X; + + if(ftmp < testpos.X + .5f) + ftmp = testpos.X + .5f; + else + { + testpos.X += landUnit - 0.5f; + if(ftmp > testpos.X) + ftmp = testpos.X; + } + testpos.X = ftmp; } + return testpos; } + #region Constructors public LandObject(LandData landData, Scene scene) { LandData = landData.Copy(); m_scene = scene; + m_scene.EventManager.OnFrame += OnFrame; + m_dwellModule = m_scene.RequestModuleInterface(); } - public LandObject(UUID owner_id, bool is_group_owned, Scene scene) + public LandObject(UUID owner_id, bool is_group_owned, Scene scene, LandData data = null) { m_scene = scene; if (m_scene == null) LandBitmap = new bool[Constants.RegionSize / landUnit, Constants.RegionSize / landUnit]; else + { LandBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; + m_dwellModule = m_scene.RequestModuleInterface(); + } + + if(data == null) + LandData = new LandData(); + else + LandData = data; - LandData = new LandData(); LandData.OwnerID = owner_id; if (is_group_owned) LandData.GroupID = owner_id; - else - LandData.GroupID = UUID.Zero; + LandData.IsGroupOwned = is_group_owned; + + if(m_dwellModule == null) + LandData.Dwell = 0; + + m_scene.EventManager.OnFrame += OnFrame; + } + + public void Clear() + { + if(m_scene != null) + m_scene.EventManager.OnFrame -= OnFrame; + LandData = null; } + #endregion #region Member Functions #region General Functions - + /// /// Checks to see if this land object contains a point /// @@ -195,14 +361,22 @@ namespace OpenSim.Region.CoreModules.World.Land else { // Normal Calculations - int parcelMax = (int)(((float)LandData.Area / (m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY)) - * (float)m_scene.RegionInfo.ObjectCapacity - * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); - // TODO: The calculation of ObjectBonus should be refactored. It does still not work in the same manner as SL! + int parcelMax = (int)( + (double)LandData.Area + * (double)m_scene.RegionInfo.ObjectCapacity + * (double)m_scene.RegionInfo.RegionSettings.ObjectBonus + / (double)(m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY) + + 0.5 ); + + if(parcelMax > m_scene.RegionInfo.ObjectCapacity) + parcelMax = m_scene.RegionInfo.ObjectCapacity; + + //m_log.DebugFormat("Area: {0}, Capacity {1}, Bonus {2}, Parcel {3}", LandData.Area, m_scene.RegionInfo.ObjectCapacity, m_scene.RegionInfo.RegionSettings.ObjectBonus, parcelMax); return parcelMax; } } + // the total prims a parcel owner can have on a region public int GetSimulatorMaxPrimCount() { if (overrideSimulatorMaxPrimCount != null) @@ -212,18 +386,34 @@ namespace OpenSim.Region.CoreModules.World.Land else { //Normal Calculations - int simMax = (int)(((float)LandData.SimwideArea / (m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY)) - * (float)m_scene.RegionInfo.ObjectCapacity); + int simMax = (int)( (double)LandData.SimwideArea + * (double)m_scene.RegionInfo.ObjectCapacity + * (double)m_scene.RegionInfo.RegionSettings.ObjectBonus + / (long)(m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY) + +0.5 ); + // sanity check + if(simMax > m_scene.RegionInfo.ObjectCapacity) + simMax = m_scene.RegionInfo.ObjectCapacity; + //m_log.DebugFormat("Simwide Area: {0}, Capacity {1}, SimMax {2}, SimWidePrims {3}", + // LandData.SimwideArea, m_scene.RegionInfo.ObjectCapacity, simMax, LandData.SimwidePrims); return simMax; } } - + #endregion #region Packet Request Handling public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client) { + if(m_scene.RegionInfo.RegionSettings.AllowDamage) + remote_client.SceneAgent.Invulnerable = false; + else + remote_client.SceneAgent.Invulnerable = (m_landData.Flags & (uint)ParcelFlags.AllowDamage) == 0; + + if (remote_client.SceneAgent.PresenceType == PresenceType.Npc) + return; + IEstateModule estateModule = m_scene.RequestModuleInterface(); // uint regionFlags = 336723974 & ~((uint)(RegionFlags.AllowLandmark | RegionFlags.AllowSetHome)); uint regionFlags = (uint)(RegionFlags.PublicAllowed @@ -252,10 +442,11 @@ namespace OpenSim.Region.CoreModules.World.Land GetSimulatorMaxPrimCount(), regionFlags); } - public void UpdateLandProperties(LandUpdateArgs args, IClientAPI remote_client) + public bool UpdateLandProperties(LandUpdateArgs args, IClientAPI remote_client, out bool snap_selection, out bool needOverlay) { //Needs later group support - bool snap_selection = false; + snap_selection = false; + needOverlay = false; LandData newData = LandData.Copy(); uint allowedDelta = 0; @@ -264,7 +455,7 @@ namespace OpenSim.Region.CoreModules.World.Land // ParcelFlags.ForSaleObjects // ParcelFlags.LindenHome - if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions)) + if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions, false)) { allowedDelta |= (uint)(ParcelFlags.AllowLandmark | ParcelFlags.AllowTerraform | @@ -277,9 +468,12 @@ namespace OpenSim.Region.CoreModules.World.Land ParcelFlags.AllowAPrimitiveEntry | ParcelFlags.AllowGroupObjectEntry | ParcelFlags.AllowFly); + newData.SeeAVs = args.SeeAVs; + newData.AnyAVSounds = args.AnyAVSounds; + newData.GroupAVSounds = args.GroupAVSounds; } - if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandSetSale)) + if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandSetSale, true)) { if (args.AuthBuyerID != newData.AuthBuyerID || args.SalePrice != newData.SalePrice) @@ -302,30 +496,30 @@ namespace OpenSim.Region.CoreModules.World.Land allowedDelta |= (uint)ParcelFlags.ForSale; } - if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.FindPlaces)) + if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.FindPlaces, false)) { newData.Category = args.Category; allowedDelta |= (uint)(ParcelFlags.ShowDirectory | ParcelFlags.AllowPublish | - ParcelFlags.MaturePublish); + ParcelFlags.MaturePublish) | (uint)(1 << 23); } - if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.LandChangeIdentity)) + if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.LandChangeIdentity, false)) { newData.Description = args.Desc; newData.Name = args.Name; newData.SnapshotID = args.SnapshotID; } - if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.SetLandingPoint)) + if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.SetLandingPoint, false)) { newData.LandingType = args.LandingType; newData.UserLocation = args.UserLocation; newData.UserLookAt = args.UserLookAt; } - if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.ChangeMedia)) + if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.ChangeMedia, false)) { newData.MediaAutoScale = args.MediaAutoScale; newData.MediaID = args.MediaID; @@ -346,7 +540,8 @@ namespace OpenSim.Region.CoreModules.World.Land ParcelFlags.UseEstateVoiceChan); } - if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.LandManagePasses)) + // don't allow passes on group owned until we can give money to groups + if (!newData.IsGroupOwned && m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.LandManagePasses, false)) { newData.PassHours = args.PassHours; newData.PassPrice = args.PassPrice; @@ -354,13 +549,13 @@ namespace OpenSim.Region.CoreModules.World.Land allowedDelta |= (uint)ParcelFlags.UsePassList; } - if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandManageAllowed)) + if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandManageAllowed, false)) { allowedDelta |= (uint)(ParcelFlags.UseAccessGroup | ParcelFlags.UseAccessList); } - if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandManageBanned)) + if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandManageBanned, false)) { allowedDelta |= (uint)(ParcelFlags.UseBanList | ParcelFlags.DenyAnonymous | @@ -372,9 +567,16 @@ namespace OpenSim.Region.CoreModules.World.Land uint preserve = LandData.Flags & ~allowedDelta; newData.Flags = preserve | (args.ParcelFlags & allowedDelta); + uint curdelta = LandData.Flags ^ newData.Flags; + curdelta &= (uint)(ParcelFlags.SoundLocal); + + if(curdelta != 0 || newData.SeeAVs != LandData.SeeAVs) + needOverlay = true; + m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData); - SendLandUpdateToAvatarsOverMe(snap_selection); + return true; } + return false; } public void UpdateLandSold(UUID avatarID, UUID groupID, bool groupOwned, uint AuctionID, int claimprice, int area) @@ -395,7 +597,7 @@ namespace OpenSim.Region.CoreModules.World.Land UUID previousOwner = LandData.OwnerID; m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData); - m_scene.EventManager.TriggerParcelPrimCountUpdate(); +// m_scene.EventManager.TriggerParcelPrimCountUpdate(); SendLandUpdateToAvatarsOverMe(true); if (sellObjects) SellLandObjects(previousOwner); @@ -431,7 +633,7 @@ namespace OpenSim.Region.CoreModules.World.Land public bool CanBeOnThisLand(UUID avatar, float posHeight) { - if (posHeight < LandChannel.BAN_LINE_SAFETY_HIEGHT && IsBannedFromLand(avatar)) + if (posHeight < LandChannel.BAN_LINE_SAFETY_HEIGHT && IsBannedFromLand(avatar)) { return false; } @@ -530,7 +732,30 @@ namespace OpenSim.Region.CoreModules.World.Land if (HasGroupAccess(avatar)) return false; - return !IsInLandAccessList(avatar); + if(IsInLandAccessList(avatar)) + return false; + + // check for a NPC + ScenePresence sp; + if (!m_scene.TryGetScenePresence(avatar, out sp)) + return true; + + if(sp==null || !sp.IsNPC) + return true; + + INPC npccli = (INPC)sp.ControllingClient; + if(npccli== null) + return true; + + UUID owner = npccli.Owner; + + if(owner == UUID.Zero) + return true; + + if (owner == LandData.OwnerID) + return false; + + return !IsInLandAccessList(owner); } public bool IsInLandAccessList(UUID avatar) @@ -568,6 +793,7 @@ namespace OpenSim.Region.CoreModules.World.Land public void SendLandUpdateToAvatarsOverMe(bool snap_selection) { + m_scene.EventManager.TriggerParcelPrimCountUpdate(); m_scene.ForEachRootScenePresence(delegate(ScenePresence avatar) { ILandObject over = null; @@ -587,13 +813,13 @@ namespace OpenSim.Region.CoreModules.World.Land { if (over.LandData.LocalID == LandData.LocalID) { - if (((over.LandData.Flags & (uint)ParcelFlags.AllowDamage) != 0) && - m_scene.RegionInfo.RegionSettings.AllowDamage) + if(m_scene.RegionInfo.RegionSettings.AllowDamage) avatar.Invulnerable = false; else - avatar.Invulnerable = true; + avatar.Invulnerable = (over.LandData.Flags & (uint)ParcelFlags.AllowDamage) == 0; SendLandUpdateToClient(snap_selection, avatar.ControllingClient); + avatar.currentParcelUUID = LandData.GlobalID; } } }); @@ -630,13 +856,13 @@ namespace OpenSim.Region.CoreModules.World.Land IClientAPI remote_client) { - if (flags == (uint) AccessList.Access || flags == (uint) AccessList.Both) + if ((flags & (uint) AccessList.Access) != 0) { List accessEntries = CreateAccessListArrayByFlag(AccessList.Access); remote_client.SendLandAccessListData(accessEntries,(uint) AccessList.Access,LandData.LocalID); } - if (flags == (uint) AccessList.Ban || flags == (uint) AccessList.Both) + if ((flags & (uint) AccessList.Ban) != 0) { List accessEntries = CreateAccessListArrayByFlag(AccessList.Ban); remote_client.SendLandAccessListData(accessEntries, (uint)AccessList.Ban, LandData.LocalID); @@ -691,6 +917,17 @@ namespace OpenSim.Region.CoreModules.World.Land newData.ParcelAccessList.Add(temp); } + // update use lists flags + // rights already checked or we wont be here + uint parcelflags = newData.Flags; + + if((flags & (uint)AccessList.Access) != 0) + parcelflags |= (uint)ParcelFlags.UseAccessList; + if((flags & (uint)AccessList.Ban) != 0) + parcelflags |= (uint)ParcelFlags.UseBanList; + + newData.Flags = parcelflags; + m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData); } @@ -708,7 +945,7 @@ namespace OpenSim.Region.CoreModules.World.Land /// public void ForceUpdateLandInfo() { - UpdateAABBAndAreaValues(); + UpdateGeometryValues(); UpdateLandBitmapByteArray(); } @@ -718,52 +955,117 @@ namespace OpenSim.Region.CoreModules.World.Land } /// - /// Updates the AABBMin and AABBMax values after area/shape modification of the land object + /// Updates geomtric values after area/shape modification of the land object /// - private void UpdateAABBAndAreaValues() + private void UpdateGeometryValues() { - int min_x = 10000; - int min_y = 10000; - int max_x = 0; - int max_y = 0; + int min_x = Int32.MaxValue; + int min_y = Int32.MaxValue; + int max_x = Int32.MinValue; + int max_y = Int32.MinValue; int tempArea = 0; int x, y; + + int lastX = 0; + int lastY = 0; + float avgx = 0f; + float avgy = 0f; + + bool needFirst = true; + for (x = 0; x < LandBitmap.GetLength(0); x++) { for (y = 0; y < LandBitmap.GetLength(1); y++) { - if (LandBitmap[x, y] == true) + if (LandBitmap[x, y]) { - if (min_x > x) min_x = x; - if (min_y > y) min_y = y; - if (max_x < x) max_x = x; - if (max_y < y) max_y = y; - tempArea += landUnit * landUnit; //16sqm peice of land + if (min_x > x) + min_x = x; + if (min_y > y) + min_y = y; + if (max_x < x) + max_x = x; + if (max_y < y) + max_y = y; + + if(needFirst) + { + avgx = x; + avgy = y; + m_startPoint.X = x * landUnit; + m_startPoint.Y = y * landUnit; + needFirst = false; + } + else + { + // keeping previus odd average + avgx = (avgx * tempArea + x) / (tempArea + 1); + avgy = (avgy * tempArea + y) / (tempArea + 1); + } + + tempArea++; + + lastX = x; + lastY = y; } } } + + int halfunit = landUnit/2; + + m_centerPoint.X = avgx * landUnit + halfunit; + m_centerPoint.Y = avgy * landUnit + halfunit; + + m_endPoint.X = lastX * landUnit + landUnit; + m_endPoint.Y = lastY * landUnit + landUnit; + + // next tests should not be needed + // if they fail, something is wrong + + int regionSizeX = (int)Constants.RegionSize; + int regionSizeY = (int)Constants.RegionSize; + + if(m_scene != null) + { + regionSizeX = (int)m_scene.RegionInfo.RegionSizeX; + regionSizeY = (int)m_scene.RegionInfo.RegionSizeX; + } + int tx = min_x * landUnit; - if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1)) - tx = ((int)m_scene.RegionInfo.RegionSizeX - 1); + if (tx >= regionSizeX) + tx = regionSizeX - 1; + int ty = min_y * landUnit; - if (ty > ((int)m_scene.RegionInfo.RegionSizeY - 1)) - ty = ((int)m_scene.RegionInfo.RegionSizeY - 1); + if (ty >= regionSizeY) + ty = regionSizeY - 1; - LandData.AABBMin = - new Vector3( - (float)(min_x * landUnit), (float)(min_y * landUnit), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0); + m_AABBmin.X = tx; + m_AABBmin.Y = ty; + + if(m_scene == null || m_scene.Heightmap == null) + LandData.AABBMin = new Vector3(tx, ty, 0f); + else + LandData.AABBMin = new Vector3(tx, ty, (float)m_scene.Heightmap[tx, ty]); + max_x++; tx = max_x * landUnit; - if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1)) - tx = ((int)m_scene.RegionInfo.RegionSizeX - 1); + if (tx > regionSizeX) + tx = regionSizeX; + + max_y++; ty = max_y * landUnit; - if (ty > ((int)m_scene.RegionInfo.RegionSizeY - 1)) - ty = ((int)m_scene.RegionInfo.RegionSizeY - 1); + if (ty > regionSizeY) + ty = regionSizeY; + + m_AABBmax.X = tx; + m_AABBmax.Y = ty; - LandData.AABBMax - = new Vector3( - (float)(max_x * landUnit), (float)(max_y * landUnit), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0); + if(m_scene == null || m_scene.Heightmap == null) + LandData.AABBMax = new Vector3(tx, ty, 0f); + else + LandData.AABBMax = new Vector3(tx, ty, (float)m_scene.Heightmap[tx - 1, ty - 1]); + tempArea *= landUnit * landUnit; LandData.Area = tempArea; } @@ -778,7 +1080,6 @@ namespace OpenSim.Region.CoreModules.World.Land public void SetLandBitmap(bool[,] bitmap) { LandBitmap = bitmap; - // m_log.DebugFormat("{0} SetLandBitmap. BitmapSize=<{1},{2}>", LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1)); ForceUpdateLandInfo(); } @@ -793,17 +1094,17 @@ namespace OpenSim.Region.CoreModules.World.Land public bool[,] BasicFullRegionLandBitmap() { - return GetSquareLandBitmap(0, 0, (int)m_scene.RegionInfo.RegionSizeX, (int) m_scene.RegionInfo.RegionSizeY); + return GetSquareLandBitmap(0, 0, (int)m_scene.RegionInfo.RegionSizeX, (int) m_scene.RegionInfo.RegionSizeY, true); } - - public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y) + + public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y, bool set_value = true) { // Empty bitmap for the whole region bool[,] tempBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; tempBitmap.Initialize(); // Fill the bitmap square area specified by state and end - tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true); + tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, set_value); // m_log.DebugFormat("{0} GetSquareLandBitmap. tempBitmapSize=<{1},{2}>", // LogHeader, tempBitmap.GetLength(0), tempBitmap.GetLength(1)); return tempBitmap; @@ -873,51 +1174,288 @@ namespace OpenSim.Region.CoreModules.World.Land } /// + /// Remap a land bitmap. Takes the supplied land bitmap and rotates it, crops it and finally offsets it into + /// a final land bitmap of the target region size. + /// + /// The original parcel bitmap + /// + /// <x,y,?> + /// <x,y,?> + /// <x,y,?> + /// <x,y,?> + /// out: This is set if the resultant bitmap is now empty + /// out: parcel.AABBMin <x,y,0> + /// out: parcel.AABBMax <x,y,0> + /// New parcel bitmap + public bool[,] RemapLandBitmap(bool[,] bitmap_base, Vector2 displacement, float rotationDegrees, Vector2 boundingOrigin, Vector2 boundingSize, Vector2 regionSize, out bool isEmptyNow, out Vector3 AABBMin, out Vector3 AABBMax) + { + // get the size of the incoming bitmap + int baseX = bitmap_base.GetLength(0); + int baseY = bitmap_base.GetLength(1); + + // create an intermediate bitmap that is 25% bigger on each side that we can work with to handle rotations + int offsetX = baseX / 4; // the original origin will now be at these coordinates so now we can have imaginary negative coordinates ;) + int offsetY = baseY / 4; + int tmpX = baseX + baseX / 2; + int tmpY = baseY + baseY / 2; + int centreX = tmpX / 2; + int centreY = tmpY / 2; + bool[,] bitmap_tmp = new bool[tmpX, tmpY]; + + double radianRotation = Math.PI * rotationDegrees / 180f; + double cosR = Math.Cos(radianRotation); + double sinR = Math.Sin(radianRotation); + if (rotationDegrees < 0f) rotationDegrees += 360f; //-90=270 -180=180 -270=90 + + // So first we apply the rotation to the incoming bitmap, storing the result in bitmap_tmp + // We special case orthogonal rotations for accuracy because even using double precision math, Math.Cos(90 degrees) is never fully 0 + // and we can never rotate around a centre pixel because the bitmap size is always even + int x, y, sx, sy; + for (y = 0; y <= tmpY; y++) + { + for (x = 0; x <= tmpX; x++) + { + if (rotationDegrees == 0f) + { + sx = x - offsetX; + sy = y - offsetY; + } + else if (rotationDegrees == 90f) + { + sx = y - offsetX; + sy = tmpY - 1 - x - offsetY; + } + else if (rotationDegrees == 180f) + { + sx = tmpX - 1 - x - offsetX; + sy = tmpY - 1 - y - offsetY; + } + else if (rotationDegrees == 270f) + { + sx = tmpX - 1 - y - offsetX; + sy = x - offsetY; + } + else + { + // arbitary rotation: hmmm should I be using (centreX - 0.5) and (centreY - 0.5) and round cosR and sinR to say only 5 decimal places? + sx = centreX + (int)Math.Round((((double)x - centreX) * cosR) + (((double)y - centreY) * sinR)) - offsetX; + sy = centreY + (int)Math.Round((((double)y - centreY) * cosR) - (((double)x - centreX) * sinR)) - offsetY; + } + if (sx >= 0 && sx < baseX && sy >= 0 && sy < baseY) + { + try + { + if (bitmap_base[sx, sy]) bitmap_tmp[x, y] = true; + } + catch (Exception) //just in case we've still not taken care of every way the arrays might go out of bounds! ;) + { + m_log.DebugFormat("{0} RemapLandBitmap Rotate: Out of Bounds sx={1} sy={2} dx={3} dy={4}", LogHeader, sx, sy, x, y); + } + } + } + } + + // We could also incorporate the next steps, bounding-rectangle and displacement in the loop above, but it's simpler to visualise if done separately + // and will also make it much easier when later I want the option for maybe a circular or oval bounding shape too ;). + // So... our output land bitmap must be the size of the current region but rememeber, parcel landbitmaps are landUnit metres (4x4 metres) per point, + // and region sizes, boundaries and displacements are in metres so we need to scale down + + int newX = (int)(regionSize.X / landUnit); + int newY = (int)(regionSize.Y / landUnit); + bool[,] bitmap_new = new bool[newX, newY]; + // displacement is relative to <0,0> in the destination region and defines where the origin of the data selected by the bounding-rectangle is placed + int dispX = (int)Math.Floor(displacement.X / landUnit); + int dispY = (int)Math.Floor(displacement.Y / landUnit); + + // startX/Y and endX/Y are coordinates in bitmap_tmp + int startX = (int)Math.Floor(boundingOrigin.X / landUnit) + offsetX; + if (startX > tmpX) startX = tmpX; + if (startX < 0) startX = 0; + int startY = (int)Math.Floor(boundingOrigin.Y / landUnit) + offsetY; + if (startY > tmpY) startY = tmpY; + if (startY < 0) startY = 0; + + int endX = (int)Math.Floor((boundingOrigin.X + boundingSize.X) / landUnit) + offsetX; + if (endX > tmpX) endX = tmpX; + if (endX < 0) endX = 0; + int endY = (int)Math.Floor((boundingOrigin.Y + boundingSize.Y) / landUnit) + offsetY; + if (endY > tmpY) endY = tmpY; + if (endY < 0) endY = 0; + + //m_log.DebugFormat("{0} RemapLandBitmap: inSize=<{1},{2}>, disp=<{3},{4}> rot={5}, offset=<{6},{7}>, boundingStart=<{8},{9}>, boundingEnd=<{10},{11}>, cosR={12}, sinR={13}, outSize=<{14},{15}>", LogHeader, + // baseX, baseY, dispX, dispY, radianRotation, offsetX, offsetY, startX, startY, endX, endY, cosR, sinR, newX, newY); + + isEmptyNow = true; + int minX = newX; + int minY = newY; + int maxX = 0; + int maxY = 0; + + int dx, dy; + for (y = startY; y < endY; y++) + { + for (x = startX; x < endX; x++) + { + dx = x - startX + dispX; + dy = y - startY + dispY; + if (dx >= 0 && dx < newX && dy >= 0 && dy < newY) + { + try + { + if (bitmap_tmp[x, y]) + { + bitmap_new[dx, dy] = true; + isEmptyNow = false; + if (dx < minX) minX = dx; + if (dy < minY) minY = dy; + if (dx > maxX) maxX = dx; + if (dy > maxY) maxY = dy; + } + } + catch (Exception) //just in case we've still not taken care of every way the arrays might go out of bounds! ;) + { + m_log.DebugFormat("{0} RemapLandBitmap - Bound & Displace: Out of Bounds sx={1} sy={2} dx={3} dy={4}", LogHeader, x, y, dx, dy); + } + } + } + } + if (isEmptyNow) + { + //m_log.DebugFormat("{0} RemapLandBitmap: Land bitmap is marked as Empty", LogHeader); + minX = 0; + minY = 0; + } + + AABBMin = new Vector3(minX * landUnit, minY * landUnit, 0); + AABBMax = new Vector3(maxX * landUnit, maxY * landUnit, 0); + return bitmap_new; + } + + /// + /// Clears any parcel data in bitmap_base where there exists parcel data in bitmap_new. In other words the parcel data + /// in bitmap_new takes over the space of the parcel data in bitmap_base. + /// + /// + /// + /// out: This is set if the resultant bitmap is now empty + /// out: parcel.AABBMin <x,y,0> + /// out: parcel.AABBMax <x,y,0> + /// New parcel bitmap + public bool[,] RemoveFromLandBitmap(bool[,] bitmap_base, bool[,] bitmap_new, out bool isEmptyNow, out Vector3 AABBMin, out Vector3 AABBMax) + { + // get the size of the incoming bitmaps + int baseX = bitmap_base.GetLength(0); + int baseY = bitmap_base.GetLength(1); + int newX = bitmap_new.GetLength(0); + int newY = bitmap_new.GetLength(1); + + if (baseX != newX || baseY != newY) + { + throw new Exception( + String.Format("{0} RemoveFromLandBitmap: Land bitmaps are not the same size! baseX={1} baseY={2} newX={3} newY={4}", LogHeader, baseX, baseY, newX, newY)); + } + + isEmptyNow = true; + int minX = baseX; + int minY = baseY; + int maxX = 0; + int maxY = 0; + + for (int y = 0; y < baseY; y++) + { + for (int x = 0; x < baseX; x++) + { + if (bitmap_new[x, y]) bitmap_base[x, y] = false; + if (bitmap_base[x, y]) + { + isEmptyNow = false; + if (x < minX) minX = x; + if (y < minY) minY = y; + if (x > maxX) maxX = x; + if (y > maxY) maxY = y; + } + } + } + if (isEmptyNow) + { + //m_log.DebugFormat("{0} RemoveFromLandBitmap: Land bitmap is marked as Empty", LogHeader); + minX = 0; + minY = 0; + } + AABBMin = new Vector3(minX * landUnit, minY * landUnit, 0); + AABBMax = new Vector3(maxX * landUnit, maxY * landUnit, 0); + return bitmap_base; + } + + /// /// Converts the land bitmap to a packet friendly byte array /// /// - private byte[] ConvertLandBitmapToBytes() + public byte[] ConvertLandBitmapToBytes() { byte[] tempConvertArr = new byte[LandBitmap.GetLength(0) * LandBitmap.GetLength(1) / 8]; - byte tempByte = 0; - int byteNum = 0; - int i = 0; + + int tempByte = 0; + int i, byteNum = 0; + int mask = 1; + i = 0; for (int y = 0; y < LandBitmap.GetLength(1); y++) { for (int x = 0; x < LandBitmap.GetLength(0); x++) { - tempByte = Convert.ToByte(tempByte | Convert.ToByte(LandBitmap[x, y]) << (i++ % 8)); - if (i % 8 == 0) + if (LandBitmap[x, y]) + tempByte |= mask; + mask = mask << 1; + if (mask == 0x100) { - tempConvertArr[byteNum] = tempByte; - tempByte = (byte) 0; - i = 0; - byteNum++; + mask = 1; + tempConvertArr[byteNum++] = (byte)tempByte; + tempByte = 0; } } } - // m_log.DebugFormat("{0} ConvertLandBitmapToBytes. BitmapSize=<{1},{2}>", - // LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1)); + + if(tempByte != 0 && byteNum < 512) + tempConvertArr[byteNum] = (byte)tempByte; + return tempConvertArr; } - private bool[,] ConvertBytesToLandBitmap() + public bool[,] ConvertBytesToLandBitmap(bool overrideRegionSize = false) { - bool[,] tempConvertMap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; - tempConvertMap.Initialize(); - byte tempByte = 0; - // Math.Min overcomes an old bug that might have made it into the database. Only use the bytes that fit into convertMap. - int bitmapLen = Math.Min(LandData.Bitmap.Length, tempConvertMap.GetLength(0) * tempConvertMap.GetLength(1) / 8); - int xLen = (int)(m_scene.RegionInfo.RegionSizeX / landUnit); + int bitmapLen; + int xLen; + bool[,] tempConvertMap; - if (bitmapLen == 512) + if (overrideRegionSize) + { + // Importing land parcel data from an OAR where the source region is a different size to the dest region requires us + // to make a LandBitmap that's not derived from the current region's size. We use the LandData.Bitmap size in bytes + // to figure out what the OAR's region dimensions are. (Is there a better way to get the src region x and y from the OAR?) + // This method assumes we always will have square regions + + bitmapLen = LandData.Bitmap.Length; + xLen = (int)Math.Abs(Math.Sqrt(bitmapLen * 8)); + tempConvertMap = new bool[xLen, xLen]; + tempConvertMap.Initialize(); + } + else { - // Legacy bitmap being passed in. Use the legacy region size - // and only set the lower area of the larger region. - xLen = (int)(Constants.RegionSize / landUnit); + tempConvertMap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; + tempConvertMap.Initialize(); + // Math.Min overcomes an old bug that might have made it into the database. Only use the bytes that fit into convertMap. + bitmapLen = Math.Min(LandData.Bitmap.Length, tempConvertMap.GetLength(0) * tempConvertMap.GetLength(1) / 8); + xLen = (int)(m_scene.RegionInfo.RegionSizeX / landUnit); + if (bitmapLen == 512) + { + // Legacy bitmap being passed in. Use the legacy region size + // and only set the lower area of the larger region. + xLen = (int)(Constants.RegionSize / landUnit); + } } // m_log.DebugFormat("{0} ConvertBytesToLandBitmap: bitmapLen={1}, xLen={2}", LogHeader, bitmapLen, xLen); + byte tempByte; int x = 0, y = 0; for (int i = 0; i < bitmapLen; i++) { @@ -945,13 +1483,39 @@ namespace OpenSim.Region.CoreModules.World.Land return tempConvertMap; } + public bool IsLandBitmapEmpty(bool[,] landBitmap) + { + for (int y = 0; y < landBitmap.GetLength(1); y++) + { + for (int x = 0; x < landBitmap.GetLength(0); x++) + { + if (landBitmap[x, y]) return false; + } + } + return true; + } + + public void DebugLandBitmap(bool[,] landBitmap) + { + m_log.InfoFormat("{0}: Map Key: #=claimed land .=unclaimed land.", LogHeader); + for (int y = landBitmap.GetLength(1) - 1; y >= 0; y--) + { + string row = ""; + for (int x = 0; x < landBitmap.GetLength(0); x++) + { + row += landBitmap[x, y] ? "#" : "."; + } + m_log.InfoFormat("{0}: {1}", LogHeader, row); + } + } + #endregion #region Object Select and Object Owner Listing public void SendForceObjectSelect(int local_id, int request_type, List returnIDs, IClientAPI remote_client) { - if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions)) + if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions, true)) { List resultLocalIDs = new List(); try @@ -1001,7 +1565,7 @@ namespace OpenSim.Region.CoreModules.World.Land /// public void SendLandObjectOwners(IClientAPI remote_client) { - if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions)) + if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions, true)) { Dictionary primCount = new Dictionary(); List groups = new List(); @@ -1009,9 +1573,9 @@ namespace OpenSim.Region.CoreModules.World.Land lock (primsOverMe) { // m_log.DebugFormat( -// "[LAND OBJECT]: Request for SendLandObjectOwners() from {0} with {1} known prims on region", +// "[LAND OBJECT]: Request for SendLandObjectOwners() from {0} with {1} known prims on region", // remote_client.Name, primsOverMe.Count); - + try { foreach (SceneObjectGroup obj in primsOverMe) @@ -1052,7 +1616,7 @@ namespace OpenSim.Region.CoreModules.World.Land public Dictionary GetLandObjectOwners() { Dictionary ownersAndCount = new Dictionary(); - + lock (primsOverMe) { try @@ -1106,8 +1670,7 @@ namespace OpenSim.Region.CoreModules.World.Land { foreach (SceneObjectGroup obj in primsOverMe) { - if (obj.OwnerID == previousOwner && obj.GroupID == UUID.Zero && - (obj.GetEffectivePermissions() & (uint)(OpenSim.Framework.PermissionMask.Transfer)) != 0) + if(m_scene.Permissions.CanSellObject(previousOwner,obj, (byte)SaleType.Original)) m_BuySellModule.BuyObject(sp.ControllingClient, UUID.Zero, obj.LocalId, 1, 0); } } @@ -1121,14 +1684,14 @@ namespace OpenSim.Region.CoreModules.World.Land { SceneObjectGroup[] objs = new SceneObjectGroup[1]; objs[0] = obj; - m_scene.returnObjects(objs, obj.OwnerID); + m_scene.returnObjects(objs, null); } public void ReturnLandObjects(uint type, UUID[] owners, UUID[] tasks, IClientAPI remote_client) { // m_log.DebugFormat( // "[LAND OBJECT]: Request to return objects in {0} from {1}", LandData.Name, remote_client.Name); - + Dictionary> returns = new Dictionary>(); lock (primsOverMe) @@ -1152,6 +1715,8 @@ namespace OpenSim.Region.CoreModules.World.Land { if (obj.GroupID == LandData.GroupID) { + if (obj.OwnerID == LandData.OwnerID) + continue; if (!returns.ContainsKey(obj.OwnerID)) returns[obj.OwnerID] = new List(); @@ -1193,8 +1758,8 @@ namespace OpenSim.Region.CoreModules.World.Land foreach (List ol in returns.Values) { - if (m_scene.Permissions.CanReturnObjects(this, remote_client.AgentId, ol)) - m_scene.returnObjects(ol.ToArray(), remote_client.AgentId); + if (m_scene.Permissions.CanReturnObjects(this, remote_client, ol)) + m_scene.returnObjects(ol.ToArray(), remote_client); } } @@ -1211,7 +1776,7 @@ namespace OpenSim.Region.CoreModules.World.Land public void AddPrimOverMe(SceneObjectGroup obj) { // m_log.DebugFormat("[LAND OBJECT]: Adding scene object {0} {1} over {2}", obj.Name, obj.LocalId, LandData.Name); - + lock (primsOverMe) primsOverMe.Add(obj); } @@ -1219,13 +1784,13 @@ namespace OpenSim.Region.CoreModules.World.Land public void RemovePrimFromOverMe(SceneObjectGroup obj) { // m_log.DebugFormat("[LAND OBJECT]: Removing scene object {0} {1} from over {2}", obj.Name, obj.LocalId, LandData.Name); - + lock (primsOverMe) primsOverMe.Remove(obj); } #endregion - + /// /// Set the media url for this land parcel /// @@ -1233,9 +1798,10 @@ namespace OpenSim.Region.CoreModules.World.Land public void SetMediaUrl(string url) { LandData.MediaURL = url; + m_scene.LandChannel.UpdateLandObject(LandData.LocalID, LandData); SendLandUpdateToAvatarsOverMe(); } - + /// /// Set the music url for this land parcel /// @@ -1243,6 +1809,7 @@ namespace OpenSim.Region.CoreModules.World.Land public void SetMusicUrl(string url) { LandData.MusicURL = url; + m_scene.LandChannel.UpdateLandObject(LandData.LocalID, LandData); SendLandUpdateToAvatarsOverMe(); } @@ -1257,6 +1824,48 @@ namespace OpenSim.Region.CoreModules.World.Land #endregion + private void OnFrame() + { + m_expiryCounter++; + + if (m_expiryCounter >= 50) + { + ExpireAccessList(); + m_expiryCounter = 0; + } + + // need to update dwell here bc landdata has no parent info + if(LandData != null && m_dwellModule != null) + { + double now = Util.GetTimeStampMS(); + double elapsed = now - LandData.LastDwellTimeMS; + if(elapsed > 150000) //2.5 minutes resolution / throttle + { + float dwell = LandData.Dwell; + double cur = dwell * 60000.0; + double decay = 1.5e-8 * cur * elapsed; + cur -= decay; + if(cur < 0) + cur = 0; + + UUID lgid = LandData.GlobalID; + m_scene.ForEachRootScenePresence(delegate(ScenePresence sp) + { + if(sp.IsNPC || sp.IsLoggingIn || sp.IsDeleted || sp.currentParcelUUID != lgid) + return; + cur += (now - sp.ParcelDwellTickMS); + sp.ParcelDwellTickMS = now; + }); + + float newdwell = (float)(cur * 1.666666666667e-5); + LandData.Dwell = newdwell; + + if(Math.Abs(newdwell - dwell) >= 0.9) + m_scene.EventManager.TriggerLandObjectAdded(this); + } + } + } + private void ExpireAccessList() { List delete = new List(); @@ -1267,7 +1876,22 @@ namespace OpenSim.Region.CoreModules.World.Land delete.Add(entry); } foreach (LandAccessEntry entry in delete) + { LandData.ParcelAccessList.Remove(entry); + ScenePresence presence; + + if (m_scene.TryGetScenePresence(entry.AgentID, out presence) && (!presence.IsChildAgent)) + { + ILandObject land = m_scene.LandChannel.GetLandObject(presence.AbsolutePosition.X, presence.AbsolutePosition.Y); + if (land.LandData.LocalID == LandData.LocalID) + { + Vector3 pos = m_scene.GetNearestAllowedPosition(presence, land); + presence.TeleportOnEject(pos); + presence.ControllingClient.SendAlertMessage("You have been ejected from this land"); + } + } + m_log.DebugFormat("[LAND]: Removing entry {0} because it has expired", entry.AgentID); + } if (delete.Count > 0) m_scene.EventManager.TriggerLandObjectUpdated((uint)LandData.LocalID, this); diff --git a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs index 9b51cc8..2a720db 100644 --- a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs @@ -69,11 +69,11 @@ namespace OpenSim.Region.CoreModules.World.Land /// For now, a simple simwide taint to get this up. Later parcel based /// taint to allow recounting a parcel if only ownership has changed /// without recounting the whole sim. - /// + /// /// We start out tainted so that the first get call resets the various prim counts. /// private bool m_Tainted = true; - + private Object m_TaintLock = new Object(); public Type ReplaceableInterface @@ -88,14 +88,12 @@ namespace OpenSim.Region.CoreModules.World.Land public void AddRegion(Scene scene) { m_Scene = scene; - + m_Scene.RegisterModuleInterface(this); - m_Scene.EventManager.OnObjectAddedToScene += OnParcelPrimCountAdd; - m_Scene.EventManager.OnObjectBeingRemovedFromScene += - OnObjectBeingRemovedFromScene; - m_Scene.EventManager.OnParcelPrimCountTainted += - OnParcelPrimCountTainted; + m_Scene.EventManager.OnObjectAddedToScene += OnParcelPrimCountAdd; + m_Scene.EventManager.OnObjectBeingRemovedFromScene += OnObjectBeingRemovedFromScene; + m_Scene.EventManager.OnParcelPrimCountTainted += OnParcelPrimCountTainted; m_Scene.EventManager.OnLandObjectAdded += delegate(ILandObject lo) { OnParcelPrimCountTainted(); }; } @@ -104,7 +102,7 @@ namespace OpenSim.Region.CoreModules.World.Land } public void RemoveRegion(Scene scene) - { + { } public void Close() @@ -126,7 +124,7 @@ namespace OpenSim.Region.CoreModules.World.Land AddObject(obj); // else // m_log.DebugFormat( -// "[PRIM COUNT MODULE]: Ignoring OnParcelPrimCountAdd() for {0} on {1} since count is tainted", +// "[PRIM COUNT MODULE]: Ignoring OnParcelPrimCountAdd() for {0} on {1} since count is tainted", // obj.Name, m_Scene.RegionInfo.RegionName); } } @@ -140,16 +138,16 @@ namespace OpenSim.Region.CoreModules.World.Land RemoveObject(obj); // else // m_log.DebugFormat( -// "[PRIM COUNT MODULE]: Ignoring OnObjectBeingRemovedFromScene() for {0} on {1} since count is tainted", -// obj.Name, m_Scene.RegionInfo.RegionName); +// "[PRIM COUNT MODULE]: Ignoring OnObjectBeingRemovedFromScene() for {0} on {1} since count is tainted", +// obj.Name, m_Scene.RegionInfo.RegionName); } } private void OnParcelPrimCountTainted() { // m_log.DebugFormat( -// "[PRIM COUNT MODULE]: OnParcelPrimCountTainted() called on {0}", m_Scene.RegionInfo.RegionName); - +// "[PRIM COUNT MODULE]: OnParcelPrimCountTainted() called on {0}", m_Scene.RegionInfo.RegionName); + lock (m_TaintLock) m_Tainted = true; } @@ -174,40 +172,40 @@ namespace OpenSim.Region.CoreModules.World.Land // NOTE: Call under Taint Lock private void AddObject(SceneObjectGroup obj) - { + { if (obj.IsAttachment) return; if (((obj.RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)) - return; + return; Vector3 pos = obj.AbsolutePosition; ILandObject landObject = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y); - + // If for some reason there is no land object (perhaps the object is out of bounds) then we can't count it if (landObject == null) { // m_log.WarnFormat( -// "[PRIM COUNT MODULE]: Found no land object for {0} at position ({1}, {2}) on {3}", +// "[PRIM COUNT MODULE]: Found no land object for {0} at position ({1}, {2}) on {3}", // obj.Name, pos.X, pos.Y, m_Scene.RegionInfo.RegionName); - + return; } - + LandData landData = landObject.LandData; - + // m_log.DebugFormat( -// "[PRIM COUNT MODULE]: Adding object {0} with {1} parts to prim count for parcel {2} on {3}", -// obj.Name, obj.Parts.Length, landData.Name, m_Scene.RegionInfo.RegionName); - +// "[PRIM COUNT MODULE]: Adding object {0} with {1} parts to prim count for parcel {2} on {3}", +// obj.Name, obj.Parts.Length, landData.Name, m_Scene.RegionInfo.RegionName); + // m_log.DebugFormat( -// "[PRIM COUNT MODULE]: Object {0} is owned by {1} over land owned by {2}", +// "[PRIM COUNT MODULE]: Object {0} is owned by {1} over land owned by {2}", // obj.Name, obj.OwnerID, landData.OwnerID); ParcelCounts parcelCounts; if (m_ParcelCounts.TryGetValue(landData.GlobalID, out parcelCounts)) { UUID landOwner = landData.OwnerID; - int partCount = obj.Parts.Length; + int partCount = obj.GetPartCount(); m_SimwideCounts[landOwner] += partCount; if (parcelCounts.Users.ContainsKey(obj.OwnerID)) @@ -215,37 +213,23 @@ namespace OpenSim.Region.CoreModules.World.Land else parcelCounts.Users[obj.OwnerID] = partCount; - if (obj.IsSelected) - { - parcelCounts.Selected += partCount; - } + if (obj.IsSelected || obj.GetSittingAvatarsCount() > 0) + parcelCounts.Selected += partCount; + + if (obj.OwnerID == landData.OwnerID) + parcelCounts.Owner += partCount; + else if (landData.GroupID != UUID.Zero && obj.GroupID == landData.GroupID) + parcelCounts.Group += partCount; else - { - if (landData.IsGroupOwned) - { - if (obj.OwnerID == landData.GroupID) - parcelCounts.Owner += partCount; - else if (landData.GroupID != UUID.Zero && obj.GroupID == landData.GroupID) - parcelCounts.Group += partCount; - else - parcelCounts.Others += partCount; - } - else - { - if (obj.OwnerID == landData.OwnerID) - parcelCounts.Owner += partCount; - else - parcelCounts.Others += partCount; - } - } + parcelCounts.Others += partCount; } } // NOTE: Call under Taint Lock private void RemoveObject(SceneObjectGroup obj) { -// m_log.DebugFormat("[PRIM COUNT MODULE]: Removing object {0} {1} from prim count", obj.Name, obj.UUID); - +// m_log.DebugFormat("[PRIM COUNT MODULE]: Removing object {0} {1} from prim count", obj.Name, obj.UUID); + // Currently this is being done by tainting the count instead. } @@ -253,7 +237,7 @@ namespace OpenSim.Region.CoreModules.World.Land { // m_log.DebugFormat( // "[PRIM COUNT MODULE]: GetPrimCounts for parcel {0} in {1}", parcelID, m_Scene.RegionInfo.RegionName); - + PrimCounts primCounts; lock (m_PrimCounts) @@ -267,7 +251,7 @@ namespace OpenSim.Region.CoreModules.World.Land return primCounts; } - + /// /// Get the number of prims on the parcel that are owned by the parcel owner. /// @@ -276,7 +260,7 @@ namespace OpenSim.Region.CoreModules.World.Land public int GetOwnerCount(UUID parcelID) { int count = 0; - + lock (m_TaintLock) { if (m_Tainted) @@ -286,11 +270,11 @@ namespace OpenSim.Region.CoreModules.World.Land if (m_ParcelCounts.TryGetValue(parcelID, out counts)) count = counts.Owner; } - + // m_log.DebugFormat( -// "[PRIM COUNT MODULE]: GetOwnerCount for parcel {0} in {1} returning {2}", +// "[PRIM COUNT MODULE]: GetOwnerCount for parcel {0} in {1} returning {2}", // parcelID, m_Scene.RegionInfo.RegionName, count); - + return count; } @@ -298,11 +282,11 @@ namespace OpenSim.Region.CoreModules.World.Land /// Get the number of prims on the parcel that have been set to the group that owns the parcel. /// /// - /// + /// public int GetGroupCount(UUID parcelID) { int count = 0; - + lock (m_TaintLock) { if (m_Tainted) @@ -312,11 +296,11 @@ namespace OpenSim.Region.CoreModules.World.Land if (m_ParcelCounts.TryGetValue(parcelID, out counts)) count = counts.Group; } - + // m_log.DebugFormat( -// "[PRIM COUNT MODULE]: GetGroupCount for parcel {0} in {1} returning {2}", +// "[PRIM COUNT MODULE]: GetGroupCount for parcel {0} in {1} returning {2}", // parcelID, m_Scene.RegionInfo.RegionName, count); - + return count; } @@ -324,11 +308,11 @@ namespace OpenSim.Region.CoreModules.World.Land /// Get the number of prims on the parcel that are not owned by the parcel owner or set to the parcel group. /// /// - /// + /// public int GetOthersCount(UUID parcelID) { int count = 0; - + lock (m_TaintLock) { if (m_Tainted) @@ -338,23 +322,23 @@ namespace OpenSim.Region.CoreModules.World.Land if (m_ParcelCounts.TryGetValue(parcelID, out counts)) count = counts.Others; } - + // m_log.DebugFormat( -// "[PRIM COUNT MODULE]: GetOthersCount for parcel {0} in {1} returning {2}", +// "[PRIM COUNT MODULE]: GetOthersCount for parcel {0} in {1} returning {2}", // parcelID, m_Scene.RegionInfo.RegionName, count); - + return count; } - + /// /// Get the number of selected prims. /// /// - /// + /// public int GetSelectedCount(UUID parcelID) { int count = 0; - + lock (m_TaintLock) { if (m_Tainted) @@ -364,24 +348,24 @@ namespace OpenSim.Region.CoreModules.World.Land if (m_ParcelCounts.TryGetValue(parcelID, out counts)) count = counts.Selected; } - + // m_log.DebugFormat( -// "[PRIM COUNT MODULE]: GetSelectedCount for parcel {0} in {1} returning {2}", +// "[PRIM COUNT MODULE]: GetSelectedCount for parcel {0} in {1} returning {2}", // parcelID, m_Scene.RegionInfo.RegionName, count); - + return count; } - + /// /// Get the total count of owner, group and others prims on the parcel. - /// FIXME: Need to do selected prims once this is reimplemented. + /// FIXME: Need to do selected prims once this is reimplemented. /// /// /// public int GetTotalCount(UUID parcelID) { int count = 0; - + lock (m_TaintLock) { if (m_Tainted) @@ -393,31 +377,30 @@ namespace OpenSim.Region.CoreModules.World.Land count = counts.Owner; count += counts.Group; count += counts.Others; - count += counts.Selected; } } - + // m_log.DebugFormat( -// "[PRIM COUNT MODULE]: GetTotalCount for parcel {0} in {1} returning {2}", +// "[PRIM COUNT MODULE]: GetTotalCount for parcel {0} in {1} returning {2}", // parcelID, m_Scene.RegionInfo.RegionName, count); - - return count; + + return count; } /// /// Get the number of prims that are in the entire simulator for the owner of this parcel. /// /// - /// + /// public int GetSimulatorCount(UUID parcelID) { int count = 0; - + lock (m_TaintLock) { if (m_Tainted) Recount(); - + UUID owner; if (m_OwnerMap.TryGetValue(parcelID, out owner)) { @@ -426,11 +409,11 @@ namespace OpenSim.Region.CoreModules.World.Land count = val; } } - + // m_log.DebugFormat( -// "[PRIM COUNT MODULE]: GetOthersCount for parcel {0} in {1} returning {2}", +// "[PRIM COUNT MODULE]: GetOthersCount for parcel {0} in {1} returning {2}", // parcelID, m_Scene.RegionInfo.RegionName, count); - + return count; } @@ -439,11 +422,11 @@ namespace OpenSim.Region.CoreModules.World.Land /// /// /// - /// + /// public int GetUserCount(UUID parcelID, UUID userID) { int count = 0; - + lock (m_TaintLock) { if (m_Tainted) @@ -459,9 +442,9 @@ namespace OpenSim.Region.CoreModules.World.Land } // m_log.DebugFormat( -// "[PRIM COUNT MODULE]: GetUserCount for user {0} in parcel {1} in region {2} returning {3}", +// "[PRIM COUNT MODULE]: GetUserCount for user {0} in parcel {1} in region {2} returning {3}", // userID, parcelID, m_Scene.RegionInfo.RegionName, count); - + return count; } @@ -469,13 +452,13 @@ namespace OpenSim.Region.CoreModules.World.Land private void Recount() { // m_log.DebugFormat("[PRIM COUNT MODULE]: Recounting prims on {0}", m_Scene.RegionInfo.RegionName); - + m_OwnerMap.Clear(); m_SimwideCounts.Clear(); m_ParcelCounts.Clear(); List land = m_Scene.LandChannel.AllParcels(); - + foreach (ILandObject l in land) { LandData landData = l.LandData; @@ -483,7 +466,7 @@ namespace OpenSim.Region.CoreModules.World.Land m_OwnerMap[landData.GlobalID] = landData.OwnerID; m_SimwideCounts[landData.OwnerID] = 0; // m_log.DebugFormat( -// "[PRIM COUNT MODULE]: Initializing parcel count for {0} on {1}", +// "[PRIM COUNT MODULE]: Initializing parcel count for {0} on {1}", // landData.Name, m_Scene.RegionInfo.RegionName); m_ParcelCounts[landData.GlobalID] = new ParcelCounts(); } @@ -499,7 +482,7 @@ namespace OpenSim.Region.CoreModules.World.Land m_PrimCounts.Remove(k); } } - + m_Tainted = false; } } @@ -541,7 +524,7 @@ namespace OpenSim.Region.CoreModules.World.Land return m_Parent.GetOthersCount(m_ParcelID); } } - + public int Selected { get @@ -549,7 +532,7 @@ namespace OpenSim.Region.CoreModules.World.Land return m_Parent.GetSelectedCount(m_ParcelID); } } - + public int Total { get @@ -597,4 +580,4 @@ namespace OpenSim.Region.CoreModules.World.Land } } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/World/Land/Tests/LandManagementModuleTests.cs b/OpenSim/Region/CoreModules/World/Land/Tests/LandManagementModuleTests.cs index 4ed67f3..d6a3ded 100644 --- a/OpenSim/Region/CoreModules/World/Land/Tests/LandManagementModuleTests.cs +++ b/OpenSim/Region/CoreModules/World/Land/Tests/LandManagementModuleTests.cs @@ -45,14 +45,14 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests UUID userId = TestHelpers.ParseTail(0x1); LandManagementModule lmm = new LandManagementModule(); - Scene scene = new SceneHelpers().SetupScene(); - SceneHelpers.SetupSceneModules(scene, lmm); - + Scene scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(scene, lmm); + ILandObject lo = new LandObject(userId, false, scene); lo.LandData.Name = "lo1"; lo.SetLandBitmap( lo.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize)); - lo = lmm.AddLandObject(lo); + lo = lmm.AddLandObject(lo); // TODO: Should add asserts to check that land object was added properly. @@ -67,7 +67,7 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests { ILandObject loAtCoord = lmm.GetLandObject(0, 0); Assert.That(loAtCoord.LandData.LocalID, Is.EqualTo(lo.LandData.LocalID)); - Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(lo.LandData.GlobalID)); + Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(lo.LandData.GlobalID)); } { @@ -88,8 +88,8 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests SceneHelpers sh = new SceneHelpers(); LandManagementModule lmm = new LandManagementModule(); - Scene scene = sh.SetupScene(); - SceneHelpers.SetupSceneModules(scene, lmm); + Scene scene = sh.SetupScene(); + SceneHelpers.SetupSceneModules(scene, lmm); scene.loadAllLandObjectsFromStorage(scene.RegionInfo.RegionID); @@ -115,8 +115,8 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests SceneHelpers sh = new SceneHelpers(); LandManagementModule lmm = new LandManagementModule(); - Scene scene = sh.SetupScene(); - SceneHelpers.SetupSceneModules(scene, lmm); + Scene scene = sh.SetupScene(); + SceneHelpers.SetupSceneModules(scene, lmm); ILandObject originalLo1 = new LandObject(userId, false, scene); originalLo1.LandData.Name = "lo1"; @@ -149,8 +149,8 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests SceneHelpers sh = new SceneHelpers(); LandManagementModule lmm = new LandManagementModule(); - Scene scene = sh.SetupScene(); - SceneHelpers.SetupSceneModules(scene, lmm); + Scene scene = sh.SetupScene(); + SceneHelpers.SetupSceneModules(scene, lmm); ILandObject originalLo1 = new LandObject(userId, false, scene); originalLo1.LandData.Name = "lo1"; @@ -173,7 +173,7 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests Assert.That(loAtCoord1.LandData.Name, Is.EqualTo(originalLo1.LandData.Name)); Assert.That(loAtCoord1.LandData.GlobalID, Is.EqualTo(originalLo1.LandData.GlobalID)); - ILandObject loAtCoord2 + ILandObject loAtCoord2 = lmm.GetLandObject((int)Constants.RegionSize - 1, (((int)Constants.RegionSize / 4) * 3) - 1); Assert.That(loAtCoord2.LandData.Name, Is.EqualTo(originalLo2.LandData.Name)); Assert.That(loAtCoord2.LandData.GlobalID, Is.EqualTo(originalLo2.LandData.GlobalID)); @@ -198,8 +198,8 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests SceneHelpers sh = new SceneHelpers(); LandManagementModule lmm = new LandManagementModule(); - Scene scene = sh.SetupScene(); - SceneHelpers.SetupSceneModules(scene, lmm); + Scene scene = sh.SetupScene(); + SceneHelpers.SetupSceneModules(scene, lmm); ILandObject originalLo1 = new LandObject(userId, false, scene); originalLo1.LandData.Name = "lo1"; @@ -220,7 +220,7 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests { ILandObject loAtCoord = lmm.GetLandObject(0, 0); Assert.That(loAtCoord.LandData.Name, Is.EqualTo(originalLo1.LandData.Name)); - Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(originalLo1.LandData.GlobalID)); + Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(originalLo1.LandData.GlobalID)); } { @@ -239,21 +239,21 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests UUID userId = TestHelpers.ParseTail(0x1); LandManagementModule lmm = new LandManagementModule(); - Scene scene = new SceneHelpers().SetupScene(); - SceneHelpers.SetupSceneModules(scene, lmm); - + Scene scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(scene, lmm); + ILandObject lo = new LandObject(userId, false, scene); lo.LandData.Name = "lo1"; lo.SetLandBitmap( lo.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize)); - lo = lmm.AddLandObject(lo); + lo = lmm.AddLandObject(lo); lmm.Subdivide(0, 0, LandManagementModule.LandUnit, LandManagementModule.LandUnit, userId); { ILandObject loAtCoord = lmm.GetLandObject(0, 0); Assert.That(loAtCoord.LandData.LocalID, Is.Not.EqualTo(lo.LandData.LocalID)); - Assert.That(loAtCoord.LandData.GlobalID, Is.Not.EqualTo(lo.LandData.GlobalID)); + Assert.That(loAtCoord.LandData.GlobalID, Is.Not.EqualTo(lo.LandData.GlobalID)); } { diff --git a/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs b/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs index 949acb6..a349aa1 100644 --- a/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs +++ b/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs @@ -43,21 +43,21 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests public class PrimCountModuleTests : OpenSimTestCase { protected UUID m_userId = new UUID("00000000-0000-0000-0000-100000000000"); - protected UUID m_groupId = new UUID("00000000-0000-0000-8888-000000000000"); - protected UUID m_otherUserId = new UUID("99999999-9999-9999-9999-999999999999"); + protected UUID m_groupId = new UUID("00000000-0000-0000-8888-000000000000"); + protected UUID m_otherUserId = new UUID("99999999-9999-9999-9999-999999999999"); protected TestScene m_scene; protected PrimCountModule m_pcm; - + /// /// A parcel that covers the entire sim except for a 1 unit wide strip on the eastern side. /// protected ILandObject m_lo; - + /// /// A parcel that covers just the eastern strip of the sim. /// - protected ILandObject m_lo2; - + protected ILandObject m_lo2; + [SetUp] public override void SetUp() { @@ -65,24 +65,24 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests m_pcm = new PrimCountModule(); LandManagementModule lmm = new LandManagementModule(); - m_scene = new SceneHelpers().SetupScene(); - SceneHelpers.SetupSceneModules(m_scene, lmm, m_pcm); - + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, lmm, m_pcm); + int xParcelDivider = (int)Constants.RegionSize - 1; - + ILandObject lo = new LandObject(m_userId, false, m_scene); lo.LandData.Name = "m_lo"; lo.SetLandBitmap( lo.GetSquareLandBitmap(0, 0, xParcelDivider, (int)Constants.RegionSize)); - m_lo = lmm.AddLandObject(lo); - + m_lo = lmm.AddLandObject(lo); + ILandObject lo2 = new LandObject(m_userId, false, m_scene); lo2.SetLandBitmap( lo2.GetSquareLandBitmap(xParcelDivider, 0, (int)Constants.RegionSize, (int)Constants.RegionSize)); lo2.LandData.Name = "m_lo2"; m_lo2 = lmm.AddLandObject(lo2); - } - + } + /// /// Test that counts before we do anything are correct. /// @@ -90,7 +90,7 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests public void TestInitialCounts() { IPrimCounts pc = m_lo.PrimCounts; - + Assert.That(pc.Owner, Is.EqualTo(0)); Assert.That(pc.Group, Is.EqualTo(0)); Assert.That(pc.Others, Is.EqualTo(0)); @@ -98,9 +98,9 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests Assert.That(pc.Selected, Is.EqualTo(0)); Assert.That(pc.Users[m_userId], Is.EqualTo(0)); Assert.That(pc.Users[m_otherUserId], Is.EqualTo(0)); - Assert.That(pc.Simulator, Is.EqualTo(0)); - } - + Assert.That(pc.Simulator, Is.EqualTo(0)); + } + /// /// Test count after a parcel owner owned object is added. /// @@ -108,13 +108,13 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests public void TestAddOwnerObject() { TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); - - IPrimCounts pc = m_lo.PrimCounts; - - SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_userId, "a", 0x01); +// log4net.Config.XmlConfigurator.Configure(); + + IPrimCounts pc = m_lo.PrimCounts; + + SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_userId, "a", 0x01); m_scene.AddNewSceneObject(sog, false); - + Assert.That(pc.Owner, Is.EqualTo(3)); Assert.That(pc.Group, Is.EqualTo(0)); Assert.That(pc.Others, Is.EqualTo(0)); @@ -122,12 +122,12 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests Assert.That(pc.Selected, Is.EqualTo(0)); Assert.That(pc.Users[m_userId], Is.EqualTo(3)); Assert.That(pc.Users[m_otherUserId], Is.EqualTo(0)); - Assert.That(pc.Simulator, Is.EqualTo(3)); - + Assert.That(pc.Simulator, Is.EqualTo(3)); + // Add a second object and retest - SceneObjectGroup sog2 = SceneHelpers.CreateSceneObject(2, m_userId, "b", 0x10); - m_scene.AddNewSceneObject(sog2, false); - + SceneObjectGroup sog2 = SceneHelpers.CreateSceneObject(2, m_userId, "b", 0x10); + m_scene.AddNewSceneObject(sog2, false); + Assert.That(pc.Owner, Is.EqualTo(5)); Assert.That(pc.Group, Is.EqualTo(0)); Assert.That(pc.Others, Is.EqualTo(0)); @@ -135,9 +135,9 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests Assert.That(pc.Selected, Is.EqualTo(0)); Assert.That(pc.Users[m_userId], Is.EqualTo(5)); Assert.That(pc.Users[m_otherUserId], Is.EqualTo(0)); - Assert.That(pc.Simulator, Is.EqualTo(5)); + Assert.That(pc.Simulator, Is.EqualTo(5)); } - + /// /// Test count after a parcel owner owned copied object is added. /// @@ -145,14 +145,14 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests public void TestCopyOwnerObject() { TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); - +// log4net.Config.XmlConfigurator.Configure(); + IPrimCounts pc = m_lo.PrimCounts; - - SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_userId, "a", 0x01); + + SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_userId, "a", 0x01); m_scene.AddNewSceneObject(sog, false); - m_scene.SceneGraph.DuplicateObject(sog.LocalId, Vector3.Zero, 0, m_userId, UUID.Zero, Quaternion.Identity); - + m_scene.SceneGraph.DuplicateObject(sog.LocalId, Vector3.Zero, m_userId, UUID.Zero, Quaternion.Identity, false); + Assert.That(pc.Owner, Is.EqualTo(6)); Assert.That(pc.Group, Is.EqualTo(0)); Assert.That(pc.Others, Is.EqualTo(0)); @@ -160,9 +160,9 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests Assert.That(pc.Selected, Is.EqualTo(0)); Assert.That(pc.Users[m_userId], Is.EqualTo(6)); Assert.That(pc.Users[m_otherUserId], Is.EqualTo(0)); - Assert.That(pc.Simulator, Is.EqualTo(6)); - } - + Assert.That(pc.Simulator, Is.EqualTo(6)); + } + /// /// Test that parcel counts update correctly when an object is moved between parcels, where that movement /// is not done directly by the user/ @@ -171,18 +171,18 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests public void TestMoveOwnerObject() { TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); - - SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_userId, "a", 0x01); +// log4net.Config.XmlConfigurator.Configure(); + + SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_userId, "a", 0x01); m_scene.AddNewSceneObject(sog, false); - SceneObjectGroup sog2 = SceneHelpers.CreateSceneObject(2, m_userId, "b", 0x10); - m_scene.AddNewSceneObject(sog2, false); - - // Move the first scene object to the eastern strip parcel + SceneObjectGroup sog2 = SceneHelpers.CreateSceneObject(2, m_userId, "b", 0x10); + m_scene.AddNewSceneObject(sog2, false); + + // Move the first scene object to the eastern strip parcel sog.AbsolutePosition = new Vector3(254, 2, 2); - - IPrimCounts pclo1 = m_lo.PrimCounts; - + + IPrimCounts pclo1 = m_lo.PrimCounts; + Assert.That(pclo1.Owner, Is.EqualTo(2)); Assert.That(pclo1.Group, Is.EqualTo(0)); Assert.That(pclo1.Others, Is.EqualTo(0)); @@ -190,10 +190,10 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests Assert.That(pclo1.Selected, Is.EqualTo(0)); Assert.That(pclo1.Users[m_userId], Is.EqualTo(2)); Assert.That(pclo1.Users[m_otherUserId], Is.EqualTo(0)); - Assert.That(pclo1.Simulator, Is.EqualTo(5)); - - IPrimCounts pclo2 = m_lo2.PrimCounts; - + Assert.That(pclo1.Simulator, Is.EqualTo(5)); + + IPrimCounts pclo2 = m_lo2.PrimCounts; + Assert.That(pclo2.Owner, Is.EqualTo(3)); Assert.That(pclo2.Group, Is.EqualTo(0)); Assert.That(pclo2.Others, Is.EqualTo(0)); @@ -201,11 +201,11 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests Assert.That(pclo2.Selected, Is.EqualTo(0)); Assert.That(pclo2.Users[m_userId], Is.EqualTo(3)); Assert.That(pclo2.Users[m_otherUserId], Is.EqualTo(0)); - Assert.That(pclo2.Simulator, Is.EqualTo(5)); - + Assert.That(pclo2.Simulator, Is.EqualTo(5)); + // Now move it back again - sog.AbsolutePosition = new Vector3(2, 2, 2); - + sog.AbsolutePosition = new Vector3(2, 2, 2); + Assert.That(pclo1.Owner, Is.EqualTo(5)); Assert.That(pclo1.Group, Is.EqualTo(0)); Assert.That(pclo1.Others, Is.EqualTo(0)); @@ -213,8 +213,8 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests Assert.That(pclo1.Selected, Is.EqualTo(0)); Assert.That(pclo1.Users[m_userId], Is.EqualTo(5)); Assert.That(pclo1.Users[m_otherUserId], Is.EqualTo(0)); - Assert.That(pclo1.Simulator, Is.EqualTo(5)); - + Assert.That(pclo1.Simulator, Is.EqualTo(5)); + Assert.That(pclo2.Owner, Is.EqualTo(0)); Assert.That(pclo2.Group, Is.EqualTo(0)); Assert.That(pclo2.Others, Is.EqualTo(0)); @@ -222,9 +222,9 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests Assert.That(pclo2.Selected, Is.EqualTo(0)); Assert.That(pclo2.Users[m_userId], Is.EqualTo(0)); Assert.That(pclo2.Users[m_otherUserId], Is.EqualTo(0)); - Assert.That(pclo2.Simulator, Is.EqualTo(5)); + Assert.That(pclo2.Simulator, Is.EqualTo(5)); } - + /// /// Test count after a parcel owner owned object is removed. /// @@ -233,14 +233,14 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - + IPrimCounts pc = m_lo.PrimCounts; - + m_scene.AddNewSceneObject(SceneHelpers.CreateSceneObject(1, m_userId, "a", 0x1), false); SceneObjectGroup sogToDelete = SceneHelpers.CreateSceneObject(3, m_userId, "b", 0x10); - m_scene.AddNewSceneObject(sogToDelete, false); + m_scene.AddNewSceneObject(sogToDelete, false); m_scene.DeleteSceneObject(sogToDelete, false); - + Assert.That(pc.Owner, Is.EqualTo(1)); Assert.That(pc.Group, Is.EqualTo(0)); Assert.That(pc.Others, Is.EqualTo(0)); @@ -248,37 +248,37 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests Assert.That(pc.Selected, Is.EqualTo(0)); Assert.That(pc.Users[m_userId], Is.EqualTo(1)); Assert.That(pc.Users[m_otherUserId], Is.EqualTo(0)); - Assert.That(pc.Simulator, Is.EqualTo(1)); - } - + Assert.That(pc.Simulator, Is.EqualTo(1)); + } + [Test] public void TestAddGroupObject() { TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); - +// log4net.Config.XmlConfigurator.Configure(); + m_lo.DeedToGroup(m_groupId); - - IPrimCounts pc = m_lo.PrimCounts; - - SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_otherUserId, "a", 0x01); + + IPrimCounts pc = m_lo.PrimCounts; + + SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_otherUserId, "a", 0x01); sog.GroupID = m_groupId; m_scene.AddNewSceneObject(sog, false); - + Assert.That(pc.Owner, Is.EqualTo(0)); Assert.That(pc.Group, Is.EqualTo(3)); Assert.That(pc.Others, Is.EqualTo(0)); Assert.That(pc.Total, Is.EqualTo(3)); Assert.That(pc.Selected, Is.EqualTo(0)); - + // Is this desired behaviour? Not totally sure. Assert.That(pc.Users[m_userId], Is.EqualTo(0)); Assert.That(pc.Users[m_groupId], Is.EqualTo(0)); Assert.That(pc.Users[m_otherUserId], Is.EqualTo(3)); - - Assert.That(pc.Simulator, Is.EqualTo(3)); + + Assert.That(pc.Simulator, Is.EqualTo(3)); } - + /// /// Test count after a parcel owner owned object is removed. /// @@ -287,19 +287,19 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - + m_lo.DeedToGroup(m_groupId); - + IPrimCounts pc = m_lo.PrimCounts; - + SceneObjectGroup sogToKeep = SceneHelpers.CreateSceneObject(1, m_userId, "a", 0x1); - sogToKeep.GroupID = m_groupId; + sogToKeep.GroupID = m_groupId; m_scene.AddNewSceneObject(sogToKeep, false); - + SceneObjectGroup sogToDelete = SceneHelpers.CreateSceneObject(3, m_userId, "b", 0x10); - m_scene.AddNewSceneObject(sogToDelete, false); + m_scene.AddNewSceneObject(sogToDelete, false); m_scene.DeleteSceneObject(sogToDelete, false); - + Assert.That(pc.Owner, Is.EqualTo(0)); Assert.That(pc.Group, Is.EqualTo(1)); Assert.That(pc.Others, Is.EqualTo(0)); @@ -308,20 +308,20 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests Assert.That(pc.Users[m_userId], Is.EqualTo(1)); Assert.That(pc.Users[m_groupId], Is.EqualTo(0)); Assert.That(pc.Users[m_otherUserId], Is.EqualTo(0)); - Assert.That(pc.Simulator, Is.EqualTo(1)); - } - - [Test] + Assert.That(pc.Simulator, Is.EqualTo(1)); + } + + [Test] public void TestAddOthersObject() { TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); - - IPrimCounts pc = m_lo.PrimCounts; - - SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_otherUserId, "a", 0x01); +// log4net.Config.XmlConfigurator.Configure(); + + IPrimCounts pc = m_lo.PrimCounts; + + SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_otherUserId, "a", 0x01); m_scene.AddNewSceneObject(sog, false); - + Assert.That(pc.Owner, Is.EqualTo(0)); Assert.That(pc.Group, Is.EqualTo(0)); Assert.That(pc.Others, Is.EqualTo(3)); @@ -329,22 +329,22 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests Assert.That(pc.Selected, Is.EqualTo(0)); Assert.That(pc.Users[m_userId], Is.EqualTo(0)); Assert.That(pc.Users[m_otherUserId], Is.EqualTo(3)); - Assert.That(pc.Simulator, Is.EqualTo(3)); + Assert.That(pc.Simulator, Is.EqualTo(3)); } - + [Test] public void TestRemoveOthersObject() { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - + IPrimCounts pc = m_lo.PrimCounts; - + m_scene.AddNewSceneObject(SceneHelpers.CreateSceneObject(1, m_otherUserId, "a", 0x1), false); SceneObjectGroup sogToDelete = SceneHelpers.CreateSceneObject(3, m_otherUserId, "b", 0x10); - m_scene.AddNewSceneObject(sogToDelete, false); + m_scene.AddNewSceneObject(sogToDelete, false); m_scene.DeleteSceneObject(sogToDelete, false); - + Assert.That(pc.Owner, Is.EqualTo(0)); Assert.That(pc.Group, Is.EqualTo(0)); Assert.That(pc.Others, Is.EqualTo(1)); @@ -352,9 +352,9 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests Assert.That(pc.Selected, Is.EqualTo(0)); Assert.That(pc.Users[m_userId], Is.EqualTo(0)); Assert.That(pc.Users[m_otherUserId], Is.EqualTo(1)); - Assert.That(pc.Simulator, Is.EqualTo(1)); - } - + Assert.That(pc.Simulator, Is.EqualTo(1)); + } + /// /// Test the count is correct after is has been tainted. /// @@ -363,12 +363,12 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests { TestHelpers.InMethod(); IPrimCounts pc = m_lo.PrimCounts; - - SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_userId, "a", 0x01); - m_scene.AddNewSceneObject(sog, false); - + + SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_userId, "a", 0x01); + m_scene.AddNewSceneObject(sog, false); + m_pcm.TaintPrimCount(); - + Assert.That(pc.Owner, Is.EqualTo(3)); Assert.That(pc.Group, Is.EqualTo(0)); Assert.That(pc.Others, Is.EqualTo(0)); @@ -376,7 +376,7 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests Assert.That(pc.Selected, Is.EqualTo(0)); Assert.That(pc.Users[m_userId], Is.EqualTo(3)); Assert.That(pc.Users[m_otherUserId], Is.EqualTo(0)); - Assert.That(pc.Simulator, Is.EqualTo(3)); + Assert.That(pc.Simulator, Is.EqualTo(3)); } } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs index 796a15f..b927cfa 100644 --- a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs +++ b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs @@ -82,11 +82,11 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap string[] configSections = new string[] { "Map", "Startup" }; - drawPrimVolume + drawPrimVolume = Util.GetConfigVarFromSections(m_config, "DrawPrimOnMapTile", configSections, drawPrimVolume); - textureTerrain + textureTerrain = Util.GetConfigVarFromSections(m_config, "TextureOnMapTile", configSections, textureTerrain); - generateMaptiles + generateMaptiles = Util.GetConfigVarFromSections(m_config, "GenerateMaptiles", configSections, generateMaptiles); if (generateMaptiles) @@ -112,7 +112,6 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap //} //t = System.Environment.TickCount - t; //m_log.InfoFormat("[MAPTILE] generation of 10 maptiles needed {0} ms", t); - if (drawPrimVolume) { DrawObjectVolume(m_scene, mapbmp); @@ -127,15 +126,15 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap catch (Exception) { m_log.ErrorFormat( - "[MAPTILE]: Failed to load Static map image texture file: {0} for {1}", + "[MAPTILE]: Failed to load Static map image texture file: {0} for {1}", m_scene.RegionInfo.MaptileStaticFile, m_scene.Name); //mapbmp = new Bitmap((int)m_scene.Heightmap.Width, (int)m_scene.Heightmap.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb); mapbmp = null; } - if (mapbmp != null) + if (mapbmp != null) m_log.DebugFormat( - "[MAPTILE]: Static map image texture file {0} found for {1}", + "[MAPTILE]: Static map image texture file {0} found for {1}", m_scene.RegionInfo.MaptileStaticFile, m_scene.Name); } } @@ -309,7 +308,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap List z_localIDs = new List(); Dictionary z_sort = new Dictionary(); - try + try { lock (objs) { @@ -383,7 +382,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap Vector3 pos = part.GetWorldPosition(); - // skip prim outside of retion + // skip prim outside of region if (!m_scene.PositionIsInCurrentRegion(pos)) continue; @@ -407,12 +406,13 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap { // Translate scale by rotation so scale is represented properly when object is rotated Vector3 lscale = new Vector3(part.Shape.Scale.X, part.Shape.Scale.Y, part.Shape.Scale.Z); + lscale *= 0.5f; + Vector3 scale = new Vector3(); Vector3 tScale = new Vector3(); Vector3 axPos = new Vector3(pos.X, pos.Y, pos.Z); - Quaternion llrot = part.GetWorldRotation(); - Quaternion rot = new Quaternion(llrot.W, llrot.X, llrot.Y, llrot.Z); + Quaternion rot = part.GetWorldRotation(); scale = lscale * rot; // negative scales don't work in this situation @@ -471,7 +471,6 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap tScale = new Vector3(lscale.X, -lscale.Y, -lscale.Z); scale = ((tScale * rot)); - vertexes[2] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z))); //vertexes[2].x = pos.X + vertexes[2].x; diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs b/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs index 708286c..0b37179 100644 --- a/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs +++ b/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs @@ -38,18 +38,20 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap { public class ShadedMapTileRenderer : IMapTileTerrainRenderer { - private static readonly Color WATER_COLOR = Color.FromArgb(29, 71, 95); - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly string LogHeader = "[SHADED MAPTILE RENDERER]"; private Scene m_scene; - //private IConfigSource m_config; // not used currently + private IConfigSource m_config; + private Color m_color_water; public void Initialise(Scene scene, IConfigSource config) { m_scene = scene; - // m_config = config; // not used currently + m_config = config; + + string[] configSections = new string[] { "Map", "Startup" }; + m_color_water = System.Drawing.ColorTranslator.FromHtml(Util.GetConfigVarFromSections(m_config, "MapColorWater", configSections, "#1D475F")); } public void TerrainToBitmap(Bitmap mapbmp) @@ -231,7 +233,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap try { - mapbmp.SetPixel(x, yr, WATER_COLOR); + mapbmp.SetPixel(x, yr, m_color_water); } catch (ArgumentException) { diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs b/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs index 9f23141..c71f5c0 100644 --- a/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs +++ b/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs @@ -130,21 +130,19 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap // some hardcoded terrain UUIDs that work with SL 1.20 (the four default textures and "Blank"). // The color-values were choosen because they "look right" (at least to me) ;-) private static readonly UUID defaultTerrainTexture1 = new UUID("0bc58228-74a0-7e83-89bc-5c23464bcec5"); - private static readonly Color defaultColor1 = Color.FromArgb(165, 137, 118); private static readonly UUID defaultTerrainTexture2 = new UUID("63338ede-0037-c4fd-855b-015d77112fc8"); - private static readonly Color defaultColor2 = Color.FromArgb(69, 89, 49); private static readonly UUID defaultTerrainTexture3 = new UUID("303cd381-8560-7579-23f1-f0a880799740"); - private static readonly Color defaultColor3 = Color.FromArgb(162, 154, 141); private static readonly UUID defaultTerrainTexture4 = new UUID("53a2f406-4895-1d13-d541-d2e3b86bc19c"); - private static readonly Color defaultColor4 = Color.FromArgb(200, 200, 200); - - private static readonly Color WATER_COLOR = Color.FromArgb(29, 71, 95); #endregion - private Scene m_scene; - // private IConfigSource m_config; // not used currently + private IConfigSource m_config; + private Color m_color_water; + private Color m_color_1; + private Color m_color_2; + private Color m_color_3; + private Color m_color_4; // mapping from texture UUIDs to averaged color. This will contain 5-9 values, in general; new values are only // added when the terrain textures are changed in the estate dialog and a new map is generated (and will stay in @@ -156,12 +154,21 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap public void Initialise(Scene scene, IConfigSource source) { m_scene = scene; - // m_config = source; // not used currently + m_config = source; + + string[] configSections = new string[] { "Map", "Startup" }; + + m_color_water = System.Drawing.ColorTranslator.FromHtml(Util.GetConfigVarFromSections(m_config, "MapColorWater", configSections, "#1D475F")); + m_color_1 = System.Drawing.ColorTranslator.FromHtml(Util.GetConfigVarFromSections(m_config, "MapColor1", configSections, "#A58976")); + m_color_2 = System.Drawing.ColorTranslator.FromHtml(Util.GetConfigVarFromSections(m_config, "MapColor2", configSections, "#455931")); + m_color_3 = System.Drawing.ColorTranslator.FromHtml(Util.GetConfigVarFromSections(m_config, "MapColor3", configSections, "#A29A8D")); + m_color_4 = System.Drawing.ColorTranslator.FromHtml(Util.GetConfigVarFromSections(m_config, "MapColor4", configSections, "#C8C8C8")); + m_mapping = new Dictionary(); - m_mapping.Add(defaultTerrainTexture1, defaultColor1); - m_mapping.Add(defaultTerrainTexture2, defaultColor2); - m_mapping.Add(defaultTerrainTexture3, defaultColor3); - m_mapping.Add(defaultTerrainTexture4, defaultColor4); + m_mapping.Add(defaultTerrainTexture1, m_color_1); + m_mapping.Add(defaultTerrainTexture2, m_color_2); + m_mapping.Add(defaultTerrainTexture3, m_color_3); + m_mapping.Add(defaultTerrainTexture4, m_color_4); m_mapping.Add(Util.BLANK_TEXTURE_UUID, Color.White); } @@ -180,7 +187,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap ManagedImage managedImage; Image image; - + try { if (OpenJPEG.DecodeToImage(asset.Data, out managedImage, out image)) @@ -201,7 +208,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap m_log.ErrorFormat("{0} OpenJpeg was unable to encode this. Asset Data is empty for {1}", LogHeader, id); } return null; - + } // Compute the average color of a texture. @@ -288,7 +295,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap if (mapbmp.Width != hm.Width || mapbmp.Height != hm.Height) { m_log.ErrorFormat("{0} TerrainToBitmap. Passed bitmap wrong dimensions. passed=<{1},{2}>, size=<{3},{4}>", - LogHeader, mapbmp.Width, mapbmp.Height, hm.Width, hm.Height); + "[TEXTURED MAP TILE RENDERER]", mapbmp.Width, mapbmp.Height, hm.Width, hm.Height); } // These textures should be in the AssetCache anyway, as every client conneting to this @@ -298,10 +305,10 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap RegionSettings settings = m_scene.RegionInfo.RegionSettings; // the four terrain colors as HSVs for interpolation - HSV hsv1 = new HSV(computeAverageColor(settings.TerrainTexture1, defaultColor1)); - HSV hsv2 = new HSV(computeAverageColor(settings.TerrainTexture2, defaultColor2)); - HSV hsv3 = new HSV(computeAverageColor(settings.TerrainTexture3, defaultColor3)); - HSV hsv4 = new HSV(computeAverageColor(settings.TerrainTexture4, defaultColor4)); + HSV hsv1 = new HSV(computeAverageColor(settings.TerrainTexture1, m_color_1)); + HSV hsv2 = new HSV(computeAverageColor(settings.TerrainTexture2, m_color_2)); + HSV hsv3 = new HSV(computeAverageColor(settings.TerrainTexture3, m_color_3)); + HSV hsv4 = new HSV(computeAverageColor(settings.TerrainTexture4, m_color_4)); float levelNElow = (float)settings.Elevation1NE; float levelNEhigh = (float)settings.Elevation2NE; @@ -371,8 +378,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap // first, rescale h to 0.0 - 1.0 hmod = (hmod - low) / (high - low); // now we have to split: 0.00 => color1, 0.33 => color2, 0.67 => color3, 1.00 => color4 - if (hmod < 1f/3f) hsv = interpolateHSV(ref hsv1, ref hsv2, hmod * 3f); - else if (hmod < 2f/3f) hsv = interpolateHSV(ref hsv2, ref hsv3, (hmod * 3f) - 1f); + if (hmod < 1f / 3f) hsv = interpolateHSV(ref hsv1, ref hsv2, hmod * 3f); + else if (hmod < 2f / 3f) hsv = interpolateHSV(ref hsv2, ref hsv3, (hmod * 3f) - 1f); else hsv = interpolateHSV(ref hsv3, ref hsv4, (hmod * 3f) - 2f); } @@ -417,7 +424,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap heightvalue = 100f - (heightvalue * 100f) / 19f; // 0 - 19 => 100 - 0 - mapbmp.SetPixel(x, yr, WATER_COLOR); + mapbmp.SetPixel(x, yr, m_color_water); } } } diff --git a/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs b/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs index 0a4e83e..f13d648 100644 --- a/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs +++ b/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs @@ -190,6 +190,9 @@ namespace OpenSim.Region.CoreModules.World.LightShare public void SendProfileToClient(IClientAPI client, RegionLightShareData wl) { + if (client == null) + return; + if (m_enableWindlight) { if (m_scene.RegionInfo.WindlightSettings.valid) @@ -207,8 +210,8 @@ namespace OpenSim.Region.CoreModules.World.LightShare private void EventManager_OnMakeRootAgent(ScenePresence presence) { -// m_log.Debug("[WINDLIGHT]: Sending windlight scene to new client {0}", presence.Name); - + if (m_enableWindlight && m_scene.RegionInfo.WindlightSettings.valid) + m_log.Debug("[WINDLIGHT]: Sending windlight scene to new client"); SendProfileToClient(presence.ControllingClient); } diff --git a/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs b/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs index 46b0470..f5aa40a 100644 --- a/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs +++ b/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs @@ -56,7 +56,7 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap public class MoapModule : INonSharedRegionModule, IMoapModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + public string Name { get { return "MoapModule"; } } public Type ReplaceableInterface { get { return null; } } @@ -64,33 +64,33 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap /// Is this module enabled? /// protected bool m_isEnabled = true; - + /// /// The scene to which this module is attached /// protected Scene m_scene; - + /// /// Track the ObjectMedia capabilities given to users keyed by path /// protected Dictionary m_omCapUsers = new Dictionary(); - + /// /// Track the ObjectMedia capabilities given to users keyed by agent. Lock m_omCapUsers to manipulate. /// protected Dictionary m_omCapUrls = new Dictionary(); - + /// /// Track the ObjectMediaUpdate capabilities given to users keyed by path /// protected Dictionary m_omuCapUsers = new Dictionary(); - + /// /// Track the ObjectMediaUpdate capabilities given to users keyed by agent. Lock m_omuCapUsers to manipulate /// protected Dictionary m_omuCapUrls = new Dictionary(); - - public void Initialise(IConfigSource configSource) + + public void Initialise(IConfigSource configSource) { IConfig config = configSource.Configs["MediaOnAPrim"]; @@ -100,63 +100,63 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap // m_log.Debug("[MOAP]: Initialised module.")l } - public void AddRegion(Scene scene) - { + public void AddRegion(Scene scene) + { if (!m_isEnabled) return; - + m_scene = scene; m_scene.RegisterModuleInterface(this); } public void RemoveRegion(Scene scene) {} - public void RegionLoaded(Scene scene) + public void RegionLoaded(Scene scene) { if (!m_isEnabled) return; - + m_scene.EventManager.OnRegisterCaps += OnRegisterCaps; m_scene.EventManager.OnDeregisterCaps += OnDeregisterCaps; m_scene.EventManager.OnSceneObjectPartCopy += OnSceneObjectPartCopy; } - - public void Close() + + public void Close() { if (!m_isEnabled) return; - + m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps; m_scene.EventManager.OnDeregisterCaps -= OnDeregisterCaps; m_scene.EventManager.OnSceneObjectPartCopy -= OnSceneObjectPartCopy; } - + public void OnRegisterCaps(UUID agentID, Caps caps) { // m_log.DebugFormat( // "[MOAP]: Registering ObjectMedia and ObjectMediaNavigate capabilities for agent {0}", agentID); - + string omCapUrl = "/CAPS/" + UUID.Random(); - + lock (m_omCapUsers) { m_omCapUsers[omCapUrl] = agentID; m_omCapUrls[agentID] = omCapUrl; - + // Even though we're registering for POST we're going to get GETS and UPDATES too caps.RegisterHandler( "ObjectMedia", new RestStreamHandler( "POST", omCapUrl, HandleObjectMediaMessage, "ObjectMedia", agentID.ToString())); } - + string omuCapUrl = "/CAPS/" + UUID.Random(); - + lock (m_omuCapUsers) { m_omuCapUsers[omuCapUrl] = agentID; m_omuCapUrls[agentID] = omuCapUrl; - + // Even though we're registering for POST we're going to get GETS and UPDATES too caps.RegisterHandler( "ObjectMediaNavigate", @@ -164,7 +164,7 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap "POST", omuCapUrl, HandleObjectMediaNavigateMessage, "ObjectMediaNavigate", agentID.ToString())); } } - + public void OnDeregisterCaps(UUID agentID, Caps caps) { lock (m_omCapUsers) @@ -173,7 +173,7 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap m_omCapUrls.Remove(agentID); m_omCapUsers.Remove(path); } - + lock (m_omuCapUsers) { string path = m_omuCapUrls[agentID]; @@ -181,7 +181,7 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap m_omuCapUsers.Remove(path); } } - + protected void OnSceneObjectPartCopy(SceneObjectPart copy, SceneObjectPart original, bool userExposed) { if (original.Shape.Media != null) @@ -197,19 +197,19 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap dupeMedia.Add(null); } } - + copy.Shape.Media = dupeMedia; } } - + public MediaEntry GetMediaEntry(SceneObjectPart part, int face) { MediaEntry me = null; - + CheckFaceParam(part, face); - + List media = part.Shape.Media; - + if (null == media) { me = null; @@ -218,17 +218,17 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap { lock (media) me = media[face]; - + // TODO: Really need a proper copy constructor down in libopenmetaverse if (me != null) me = MediaEntry.FromOSD(me.GetOSD()); } - + // m_log.DebugFormat("[MOAP]: GetMediaEntry for {0} face {1} found {2}", part.Name, face, me); - + return me; } - + /// /// Set the media entry on the face of the given part. /// @@ -238,28 +238,29 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap public void SetMediaEntry(SceneObjectPart part, int face, MediaEntry me) { // m_log.DebugFormat("[MOAP]: SetMediaEntry for {0}, face {1}", part.Name, face); - + CheckFaceParam(part, face); - + if (null == part.Shape.Media) { if (me == null) return; - else + else part.Shape.Media = new PrimitiveBaseShape.MediaList(new MediaEntry[part.GetNumberOfSides()]); } lock (part.Shape.Media) - part.Shape.Media[face] = me; - + part.Shape.Media[face] = me; + UpdateMediaUrl(part, UUID.Zero); - + SetPartMediaFlags(part, face, me != null); - + + part.ParentGroup.HasGroupChanged = true; part.ScheduleFullUpdate(); part.TriggerScriptChangedEvent(Changed.MEDIA); } - + /// /// Clear the media entry from the face of the given part. /// @@ -267,9 +268,9 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap /// public void ClearMediaEntry(SceneObjectPart part, int face) { - SetMediaEntry(part, face, null); + SetMediaEntry(part, face, null); } - + /// /// Set the media flags on the texture face of the given part. /// @@ -284,9 +285,9 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap Primitive.TextureEntry te = part.Shape.Textures; Primitive.TextureEntryFace teFace = te.CreateFace((uint)face); teFace.MediaFlags = flag; - part.Shape.Textures = te; + part.Shape.Textures = te; } - + /// /// Sets or gets per face media textures. /// @@ -300,11 +301,11 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { // m_log.DebugFormat("[MOAP]: Got ObjectMedia path [{0}], raw request [{1}]", path, request); - + OSDMap osd = (OSDMap)OSDParser.DeserializeLLSDXml(request); ObjectMediaMessage omm = new ObjectMediaMessage(); omm.Deserialize(osd); - + if (omm.Request is ObjectMediaRequest) return HandleObjectMediaRequest(omm.Request as ObjectMediaRequest); else if (omm.Request is ObjectMediaUpdate) @@ -312,10 +313,10 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap throw new Exception( string.Format( - "[MOAP]: ObjectMediaMessage has unrecognized ObjectMediaBlock of {0}", + "[MOAP]: ObjectMediaMessage has unrecognized ObjectMediaBlock of {0}", omm.Request.GetType())); } - + /// /// Handle a fetch request for media textures /// @@ -324,36 +325,36 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap protected string HandleObjectMediaRequest(ObjectMediaRequest omr) { UUID primId = omr.PrimID; - + SceneObjectPart part = m_scene.GetSceneObjectPart(primId); - + if (null == part) { m_log.WarnFormat( - "[MOAP]: Received a GET ObjectMediaRequest for prim {0} but this doesn't exist in region {1}", + "[MOAP]: Received a GET ObjectMediaRequest for prim {0} but this doesn't exist in region {1}", primId, m_scene.RegionInfo.RegionName); return string.Empty; } - + if (null == part.Shape.Media) return string.Empty; - + ObjectMediaResponse resp = new ObjectMediaResponse(); - + resp.PrimID = primId; - + lock (part.Shape.Media) resp.FaceMedia = part.Shape.Media.ToArray(); - + resp.Version = part.MediaUrl; - + string rawResp = OSDParser.SerializeLLSDXmlString(resp.Serialize()); - + // m_log.DebugFormat("[MOAP]: Got HandleObjectMediaRequestGet raw response is [{0}]", rawResp); - + return rawResp; } - + /// /// Handle an update of media textures. /// @@ -363,46 +364,46 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap protected string HandleObjectMediaUpdate(string path, ObjectMediaUpdate omu) { UUID primId = omu.PrimID; - + SceneObjectPart part = m_scene.GetSceneObjectPart(primId); - + if (null == part) { m_log.WarnFormat( - "[MOAP]: Received an UPDATE ObjectMediaRequest for prim {0} but this doesn't exist in region {1}", + "[MOAP]: Received an UPDATE ObjectMediaRequest for prim {0} but this doesn't exist in region {1}", primId, m_scene.RegionInfo.RegionName); return string.Empty; } - + // m_log.DebugFormat("[MOAP]: Received {0} media entries for prim {1}", omu.FaceMedia.Length, primId); -// +// // for (int i = 0; i < omu.FaceMedia.Length; i++) // { // MediaEntry me = omu.FaceMedia[i]; // string v = (null == me ? "null": OSDParser.SerializeLLSDXmlString(me.GetOSD())); // m_log.DebugFormat("[MOAP]: Face {0} [{1}]", i, v); // } - + if (omu.FaceMedia.Length > part.GetNumberOfSides()) { m_log.WarnFormat( - "[MOAP]: Received {0} media entries from client for prim {1} {2} but this prim has only {3} faces. Dropping request.", + "[MOAP]: Received {0} media entries from client for prim {1} {2} but this prim has only {3} faces. Dropping request.", omu.FaceMedia.Length, part.Name, part.UUID, part.GetNumberOfSides()); return string.Empty; } - + UUID agentId = default(UUID); - + lock (m_omCapUsers) - agentId = m_omCapUsers[path]; - + agentId = m_omCapUsers[path]; + List media = part.Shape.Media; - + if (null == media) { // m_log.DebugFormat("[MOAP]: Setting all new media list for {0}", part.Name); part.Shape.Media = new PrimitiveBaseShape.MediaList(omu.FaceMedia); - + for (int i = 0; i < omu.FaceMedia.Length; i++) { if (omu.FaceMedia[i] != null) @@ -412,7 +413,7 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap // directly. SetPartMediaFlags(part, i, true); // m_log.DebugFormat( -// "[MOAP]: Media flags for face {0} is {1}", +// "[MOAP]: Media flags for face {0} is {1}", // i, part.Shape.Textures.FaceTextures[i].MediaFlags); } } @@ -420,15 +421,15 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap else { // m_log.DebugFormat("[MOAP]: Setting existing media list for {0}", part.Name); - - // We need to go through the media textures one at a time to make sure that we have permission + + // We need to go through the media textures one at a time to make sure that we have permission // to change them - + // FIXME: Race condition here since some other texture entry manipulator may overwrite/get // overwritten. Unfortunately, PrimitiveBaseShape does not allow us to change texture entry // directly. Primitive.TextureEntry te = part.Shape.Textures; - + lock (media) { for (int i = 0; i < media.Count; i++) @@ -436,38 +437,39 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap if (m_scene.Permissions.CanControlPrimMedia(agentId, part.UUID, i)) { media[i] = omu.FaceMedia[i]; - + // When a face is cleared this is done by setting the MediaFlags in the TextureEntry via a normal // texture update, so we don't need to worry about clearing MediaFlags here. if (null == media[i]) continue; - + SetPartMediaFlags(part, i, true); - + // m_log.DebugFormat( - // "[MOAP]: Media flags for face {0} is {1}", + // "[MOAP]: Media flags for face {0} is {1}", // i, face.MediaFlags); // m_log.DebugFormat("[MOAP]: Set media entry for face {0} on {1}", i, part.Name); } } } - + part.Shape.Textures = te; - + // for (int i2 = 0; i2 < part.Shape.Textures.FaceTextures.Length; i2++) // m_log.DebugFormat("[MOAP]: FaceTexture[{0}] is {1}", i2, part.Shape.Textures.FaceTextures[i2]); } - + UpdateMediaUrl(part, agentId); - + // Arguably, we could avoid sending a full update to the avatar that just changed the texture. + part.ParentGroup.HasGroupChanged = true; part.ScheduleFullUpdate(); - + part.TriggerScriptChangedEvent(Changed.MEDIA); - + return string.Empty; } - + /// /// Received from the viewer if a user has changed the url of a media texture. /// @@ -481,71 +483,72 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { // m_log.DebugFormat("[MOAP]: Got ObjectMediaNavigate request [{0}]", request); - + OSDMap osd = (OSDMap)OSDParser.DeserializeLLSDXml(request); ObjectMediaNavigateMessage omn = new ObjectMediaNavigateMessage(); omn.Deserialize(osd); - + UUID primId = omn.PrimID; - + SceneObjectPart part = m_scene.GetSceneObjectPart(primId); - + if (null == part) { m_log.WarnFormat( - "[MOAP]: Received an ObjectMediaNavigateMessage for prim {0} but this doesn't exist in region {1}", + "[MOAP]: Received an ObjectMediaNavigateMessage for prim {0} but this doesn't exist in region {1}", primId, m_scene.RegionInfo.RegionName); return string.Empty; } - + UUID agentId = default(UUID); - + lock (m_omuCapUsers) agentId = m_omuCapUsers[path]; - + if (!m_scene.Permissions.CanInteractWithPrimMedia(agentId, part.UUID, omn.Face)) return string.Empty; - + // m_log.DebugFormat( -// "[MOAP]: Received request to update media entry for face {0} on prim {1} {2} to {3}", +// "[MOAP]: Received request to update media entry for face {0} on prim {1} {2} to {3}", // omn.Face, part.Name, part.UUID, omn.URL); - + // If media has never been set for this prim, then just return. if (null == part.Shape.Media) return string.Empty; - + MediaEntry me = null; - + lock (part.Shape.Media) me = part.Shape.Media[omn.Face]; - + // Do the same if media has not been set up for a specific face if (null == me) return string.Empty; - + if (me.EnableWhiteList) { if (!CheckUrlAgainstWhitelist(omn.URL, me.WhiteList)) { // m_log.DebugFormat( -// "[MOAP]: Blocking change of face {0} on prim {1} {2} to {3} since it's not on the enabled whitelist", +// "[MOAP]: Blocking change of face {0} on prim {1} {2} to {3} since it's not on the enabled whitelist", // omn.Face, part.Name, part.UUID, omn.URL); - + return string.Empty; } } - + me.CurrentURL = omn.URL; - + UpdateMediaUrl(part, agentId); - + + part.ParentGroup.HasGroupChanged = true; part.ScheduleFullUpdate(); - + part.TriggerScriptChangedEvent(Changed.MEDIA); - + return OSDParser.SerializeLLSDXmlString(new OSD()); } - + /// /// Check that the face number is valid for the given prim. /// @@ -555,13 +558,13 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap { if (face < 0) throw new ArgumentException("Face cannot be less than zero"); - + int maxFaces = part.GetNumberOfSides() - 1; if (face > maxFaces) throw new ArgumentException( string.Format("Face argument was {0} but max is {1}", face, maxFaces)); } - + /// /// Update the media url of the given part /// @@ -583,10 +586,10 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap int version = int.Parse(rawVersion); part.MediaUrl = string.Format("x-mv:{0:D10}/{1}", ++version, updateId); } - + // m_log.DebugFormat("[MOAP]: Storing media url [{0}] in prim {1} {2}", part.MediaUrl, part.Name, part.UUID); } - + /// /// Check the given url against the given whitelist. /// @@ -599,22 +602,22 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap return false; Uri url = new Uri(rawUrl); - + foreach (string origWlUrl in whitelist) { string wlUrl = origWlUrl; - + // Deal with a line-ending wildcard if (wlUrl.EndsWith("*")) wlUrl = wlUrl.Remove(wlUrl.Length - 1); - + // m_log.DebugFormat("[MOAP]: Checking whitelist URL pattern {0}", origWlUrl); - + // Handle a line starting wildcard slightly differently since this can only match the domain, not the path if (wlUrl.StartsWith("*")) { wlUrl = wlUrl.Substring(1); - + if (url.Host.Contains(wlUrl)) { // m_log.DebugFormat("[MOAP]: Whitelist URL {0} matches {1}", origWlUrl, rawUrl); @@ -624,7 +627,7 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap else { string urlToMatch = url.Authority + url.AbsolutePath; - + if (urlToMatch.StartsWith(wlUrl)) { // m_log.DebugFormat("[MOAP]: Whitelist URL {0} matches {1}", origWlUrl, rawUrl); @@ -632,7 +635,7 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap } } } - + return false; } } diff --git a/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs b/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs index ee57aed..7080705 100644 --- a/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs +++ b/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs @@ -47,7 +47,7 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests { protected TestScene m_scene; protected MoapModule m_module; - + [SetUp] public override void SetUp() { @@ -55,45 +55,45 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests m_module = new MoapModule(); m_scene = new SceneHelpers().SetupScene(); - SceneHelpers.SetupSceneModules(m_scene, m_module); - } - + SceneHelpers.SetupSceneModules(m_scene, m_module); + } + [Test] public void TestClearMediaUrl() { - TestHelpers.InMethod(); + TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; - MediaEntry me = new MediaEntry(); - + MediaEntry me = new MediaEntry(); + m_module.SetMediaEntry(part, 1, me); m_module.ClearMediaEntry(part, 1); - + Assert.That(part.Shape.Media[1], Is.EqualTo(null)); - + // Although we've cleared one face, other faces may still be present. So we need to check for an // update media url version Assert.That(part.MediaUrl, Is.EqualTo("x-mv:0000000001/" + UUID.Zero)); - + // By changing media flag to false, the face texture once again becomes identical to the DefaultTexture. // Therefore, when libOMV reserializes it, it disappears and we are left with no face texture in this slot. // Not at all confusing, eh? Assert.That(part.Shape.Textures.FaceTextures[1], Is.Null); } - + [Test] public void TestSetMediaUrl() { TestHelpers.InMethod(); - - string homeUrl = "opensimulator.org"; - + + string homeUrl = "opensimulator.org"; + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; - MediaEntry me = new MediaEntry() { HomeURL = homeUrl }; - + MediaEntry me = new MediaEntry() { HomeURL = homeUrl }; + m_module.SetMediaEntry(part, 1, me); - + Assert.That(part.Shape.Media[1].HomeURL, Is.EqualTo(homeUrl)); Assert.That(part.MediaUrl, Is.EqualTo("x-mv:0000000000/" + UUID.Zero)); Assert.That(part.Shape.Textures.FaceTextures[1].MediaFlags, Is.True); diff --git a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs index 2abc910..6a8f4c0 100644 --- a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs +++ b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs @@ -45,38 +45,38 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "BuySellModule")] public class BuySellModule : IBuySellModule, INonSharedRegionModule { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + protected Scene m_scene = null; protected IDialogModule m_dialogModule; - + public string Name { get { return "Object BuySell Module"; } } public Type ReplaceableInterface { get { return null; } } public void Initialise(IConfigSource source) {} - + public void AddRegion(Scene scene) { m_scene = scene; m_scene.RegisterModuleInterface(this); m_scene.EventManager.OnNewClient += SubscribeToClientEvents; } - - public void RemoveRegion(Scene scene) + + public void RemoveRegion(Scene scene) { m_scene.EventManager.OnNewClient -= SubscribeToClientEvents; } - - public void RegionLoaded(Scene scene) + + public void RegionLoaded(Scene scene) { m_dialogModule = scene.RequestModuleInterface(); } - - public void Close() + + public void Close() { RemoveRegion(m_scene); } - + public void SubscribeToClientEvents(IClientAPI client) { client.OnObjectSaleInfo += ObjectSaleInfo; @@ -89,18 +89,23 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell if (part == null) return; - if (part.ParentGroup.IsDeleted) + SceneObjectGroup sog = part.ParentGroup; + if (sog == null || sog.IsDeleted) return; - if (part.OwnerID != client.AgentId && (!m_scene.Permissions.IsGod(client.AgentId))) + // Does the user have the power to put the object on sale? + if (!m_scene.Permissions.CanSellObject(client, sog, saleType)) + { + client.SendAgentAlertMessage("You don't have permission to set object on sale", false); return; + } - part = part.ParentGroup.RootPart; + part = sog.RootPart; part.ObjectSaleType = saleType; part.SalePrice = salePrice; - part.ParentGroup.HasGroupChanged = true; + sog.HasGroupChanged = true; part.SendPropertiesToClient(client); } @@ -113,11 +118,16 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell return false; SceneObjectGroup group = part.ParentGroup; + if(group == null || group.IsDeleted || group.inTransit) + return false; + + // make sure we are not buying a child part + part = group.RootPart; switch (saleType) { case 1: // Sell as original (in-place sale) - uint effectivePerms = group.GetEffectivePermissions(); + uint effectivePerms = group.EffectiveOwnerPerms; if ((effectivePerms & (uint)PermissionMask.Transfer) == 0) { @@ -126,8 +136,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell return false; } - group.SetOwnerId(remoteClient.AgentId); - group.SetRootPartOwner(part, remoteClient.AgentId, remoteClient.ActiveGroupId); + group.SetOwner(remoteClient.AgentId, remoteClient.ActiveGroupId); if (m_scene.Permissions.PropagatePermissions()) { @@ -137,6 +146,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell child.TriggerScriptChangedEvent(Changed.OWNER); child.ApplyNextOwnerPermissions(); } + group.InvalidateDeepEffectivePerms(); } part.ObjectSaleType = 0; @@ -152,19 +162,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell break; case 2: // Sell a copy - Vector3 inventoryStoredPosition = new Vector3( - Math.Min(group.AbsolutePosition.X, m_scene.RegionInfo.RegionSizeX - 6), - Math.Min(group.AbsolutePosition.Y, m_scene.RegionInfo.RegionSizeY - 6), - group.AbsolutePosition.Z); - - Vector3 originalPosition = group.AbsolutePosition; - - group.AbsolutePosition = inventoryStoredPosition; - - string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(group); - group.AbsolutePosition = originalPosition; - - uint perms = group.GetEffectivePermissions(); + uint perms = group.EffectiveOwnerPerms; if ((perms & (uint)PermissionMask.Transfer) == 0) { @@ -173,6 +171,15 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell return false; } + if ((perms & (uint)PermissionMask.Copy) == 0) + { + if (m_dialogModule != null) + m_dialogModule.SendAlertToUser(remoteClient, "This sale has been blocked by the permissions system"); + return false; + } + + string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(group); + AssetBase asset = m_scene.CreateAsset( group.GetPartName(localID), group.GetPartDescription(localID), @@ -193,16 +200,21 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell item.AssetType = asset.Type; item.InvType = (int)InventoryType.Object; item.Folder = categoryID; + + perms = group.CurrentAndFoldedNextPermissions(); + // apply parts inventory next perms + PermissionsUtil.ApplyNoModFoldedPermissions(perms, ref perms); + // change to next owner perms + perms &= part.NextOwnerMask; + // update folded + perms = PermissionsUtil.FixAndFoldPermissions(perms); + + item.BasePermissions = perms; + item.CurrentPermissions = perms; + item.NextPermissions = part.NextOwnerMask & perms; + item.EveryOnePermissions = part.EveryoneMask & perms; + item.GroupPermissions = part.GroupMask & perms; - PermissionsUtil.ApplyFoldedPermissions(perms, ref perms); - - item.BasePermissions = perms & part.NextOwnerMask; - item.CurrentPermissions = perms & part.NextOwnerMask; - item.NextPermissions = part.NextOwnerMask; - item.EveryOnePermissions = part.EveryoneMask & - part.NextOwnerMask; - item.GroupPermissions = part.GroupMask & - part.NextOwnerMask; item.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm; item.CreationDate = Util.UnixTimeSinceEpoch(); diff --git a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs index e77f0aa..3d786dd 100644 --- a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs +++ b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs @@ -53,30 +53,30 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ObjectCommandsModule")] public class ObjectCommandsModule : 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; private ICommandConsole m_console; public string Name { get { return "Object Commands Module"; } } - + public Type ReplaceableInterface { get { return null; } } - + public void Initialise(IConfigSource source) { // m_log.DebugFormat("[OBJECT COMMANDS MODULE]: INITIALIZED MODULE"); } - + public void PostInitialise() { // m_log.DebugFormat("[OBJECT COMMANDS MODULE]: POST INITIALIZED MODULE"); } - + public void Close() { // m_log.DebugFormat("[OBJECT COMMANDS MODULE]: CLOSED MODULE"); } - + public void AddRegion(Scene scene) { // m_log.DebugFormat("[OBJECT COMMANDS MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName); @@ -123,8 +123,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands "Objects", false, "delete object pos", - "delete object pos to ", - "Delete scene objects within the given area.", + "delete object pos ", + "Delete scene objects within the given volume.", ConsoleUtil.CoordHelp, HandleDeleteObject); @@ -152,9 +152,18 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands m_console.Commands.AddCommand( "Objects", false, + "show object owner", + "show object owner [--full] ", + "Show details of scene objects with given owner.", + "The --full option will print out information on all the parts of the object.\n", + HandleShowObjectByOwnerID); + + m_console.Commands.AddCommand( + "Objects", + false, "show object pos", - "show object pos [--full] to ", - "Show details of scene objects within the given area.", + "show object pos [--full] ", + "Show details of scene objects within give volume", "The --full option will print out information on all the parts of the object.\n" + "For yet more detailed part information, use the \"show part\" commands.\n" + ConsoleUtil.CoordHelp, @@ -180,8 +189,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands "Objects", false, "show part pos", - "show part pos to ", - "Show details of scene object parts within the given area.", + "show part pos ", + "Show details of scene object parts within the given volume.", ConsoleUtil.CoordHelp, HandleShowPartByPos); @@ -325,6 +334,32 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands OutputSogsToConsole(searchPredicate, showFull); } + private void HandleShowObjectByOwnerID(string module, string[] cmdparams) + { + if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene)) + return; + + bool showFull = false; + OptionSet options = new OptionSet().Add("full", v => showFull = v != null); + + List mainParams = options.Parse(cmdparams); + + if (mainParams.Count < 4) + { + m_console.OutputFormat("Usage: show object owner "); + return; + } + + UUID ownerID; + if (!ConsoleUtil.TryParseConsoleUuid(m_console, mainParams[3], out ownerID)) + return; + + Predicate searchPredicate + = so => so.OwnerID == ownerID && !so.IsAttachment; + + OutputSogsToConsole(searchPredicate, showFull); + } + private void HandleShowObjectByPos(string module, string[] cmdparams) { if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene)) @@ -504,13 +539,13 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands if (!ConsoleUtil.CheckFileDoesNotExist(m_console, fileName)) return; - + using (XmlTextWriter xtw = new XmlTextWriter(fileName, Encoding.UTF8)) { xtw.Formatting = Formatting.Indented; SceneObjectSerializer.ToOriginalXmlFormat(so, xtw, true); } - + m_console.OutputFormat("Object dumped to file {0}", fileName); } @@ -590,7 +625,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands cdl.AddRow("FlexiSoftness", s.FlexiSoftness); cdl.AddRow("HollowShape", s.HollowShape); cdl.AddRow( - "LightColor", + "LightColor", string.Format("<{0},{1},{2},{3}>", s.LightColorR, s.LightColorB, s.LightColorG, s.LightColorA)); cdl.AddRow("LightCutoff", s.LightCutoff); cdl.AddRow("LightEntry", s.LightEntry); @@ -624,7 +659,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands cdl.AddRow("Rotation (World)", sop.GetWorldRotation()); cdl.AddRow("Scale", s.Scale); cdl.AddRow( - "SculptData", + "SculptData", string.Format("{0} bytes", s.SculptData != null ? s.SculptData.Length.ToString() : "n/a")); cdl.AddRow("SculptEntry", s.SculptEntry); cdl.AddRow("SculptTexture", s.SculptTexture); @@ -633,7 +668,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands // TODO, need to display more information about textures but in a compact format // to stop output becoming huge. - for (int i = 0; i < sop.GetNumberOfSides(); i++) + for (int i = 0; i < sop.GetNumberOfSides(); i++) { Primitive.TextureEntryFace teFace = s.Textures.FaceTextures[i]; @@ -730,12 +765,12 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands if (g.OwnerID == match && !g.IsAttachment) deletes.Add(g); }); - + // if (deletes.Count == 0) // m_console.OutputFormat("No objects were found with owner {0}", match); - + break; - + case "creator": if (!UUID.TryParse(o, out match)) return; @@ -747,12 +782,12 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands if (g.RootPart.CreatorID == match && !g.IsAttachment) deletes.Add(g); }); - + // if (deletes.Count == 0) // m_console.OutputFormat("No objects were found with creator {0}", match); - + break; - + case "id": UUID uuid; uint localId; @@ -768,18 +803,21 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands else so = m_scene.GetSceneObjectGroup(localId); - if (!so.IsAttachment) - deletes.Add(so); - - // if (deletes.Count == 0) - // m_console.OutputFormat("No objects were found with uuid {0}", match); - + if (so!= null) + { + deletes.Add(so); + if(so.IsAttachment) + { + requireConfirmation = true; + m_console.OutputFormat("Warning: object with uuid {0} is a attachment", uuid); + } + } break; - + case "name": deletes = GetDeleteCandidatesByName(module, cmd); break; - + case "outside": deletes = new List(); @@ -787,7 +825,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands { SceneObjectPart rootPart = g.RootPart; bool delete = false; - + if (rootPart.GroupPosition.Z < 0.0 || rootPart.GroupPosition.Z > 10000.0) { delete = true; @@ -796,18 +834,18 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands { ILandObject parcel = m_scene.LandChannel.GetLandObject(rootPart.GroupPosition.X, rootPart.GroupPosition.Y); - + if (parcel == null || parcel.LandData.Name == "NO LAND") delete = true; } - + if (delete && !g.IsAttachment && !deletes.Contains(g)) deletes.Add(g); }); - + if (deletes.Count == 0) m_console.OutputFormat("No objects were found outside region bounds"); - + break; case "pos": @@ -829,7 +867,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands "Are you sure that you want to delete {0} objects from {1}", deletes.Count, m_scene.RegionInfo.RegionName), "y/N"); - + if (response.ToLower() != "y") { MainConsole.Instance.OutputFormat( @@ -869,11 +907,11 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands if (useRegex) { Regex nameRegex = new Regex(name); - searchAction = so => { if (nameRegex.IsMatch(so.Name)) { sceneObjects.Add(so); }}; + searchAction = so => { if (nameRegex.IsMatch(so.Name)) {if(!so.IsAttachment) sceneObjects.Add(so);}}; } else { - searchAction = so => { if (so.Name == name) { sceneObjects.Add(so); }}; + searchAction = so => { if (so.Name == name) {if(!so.IsAttachment) sceneObjects.Add(so);}}; } m_scene.ForEachSOG(searchAction); @@ -916,11 +954,11 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands { m_console.OutputFormat("Error: Start vector '{0}' does not have a valid format", rawConsoleStartVector); endVector = Vector3.Zero; - + return false; } - string rawConsoleEndVector = rawComponents.Skip(2).Take(1).Single(); + string rawConsoleEndVector = rawComponents.Skip(1).Take(1).Single(); if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector)) { diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs index 780ec69..45c1c56 100644 --- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs +++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs @@ -43,12 +43,13 @@ using PermissionMask = OpenSim.Framework.PermissionMask; namespace OpenSim.Region.CoreModules.World.Permissions { - [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "PermissionsModule")] - public class PermissionsModule : INonSharedRegionModule, IPermissionsModule + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DefaultPermissionsModule")] + public class DefaultPermissionsModule : INonSharedRegionModule, IPermissionsModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + protected Scene m_scene; + protected ScenePermissions scenePermissions; protected bool m_Enabled; private InventoryFolderImpl m_libraryRootFolder; @@ -69,15 +70,6 @@ namespace OpenSim.Region.CoreModules.World.Permissions } #region Constants - // These are here for testing. They will be taken out - - //private uint PERM_ALL = (uint)2147483647; - private uint PERM_COPY = (uint)32768; - //private uint PERM_MODIFY = (uint)16384; - private uint PERM_MOVE = (uint)524288; - private uint PERM_TRANS = (uint)8192; - private uint PERM_LOCKED = (uint)540672; - /// /// Different user set names that come in from the configuration file. /// @@ -96,12 +88,12 @@ namespace OpenSim.Region.CoreModules.World.Permissions private bool m_bypassPermissionsValue = true; private bool m_propagatePermissions = false; private bool m_debugPermissions = false; - private bool m_allowGridGods = false; - private bool m_RegionOwnerIsGod = false; - private bool m_RegionManagerIsGod = false; - private bool m_ParcelOwnerIsGod = false; - - private bool m_SimpleBuildPermissions = false; + private bool m_allowGridAdmins = false; + private bool m_RegionOwnerIsAdmin = false; + private bool m_RegionManagerIsAdmin = false; + private bool m_forceGridAdminsOnly; + private bool m_forceAdminModeAlwaysOn; + private bool m_allowAdminActionsWithoutGodMode; /// /// The set of users that are allowed to create scripts. This is only active if permissions are not being @@ -110,17 +102,17 @@ namespace OpenSim.Region.CoreModules.World.Permissions private UserSet m_allowedScriptCreators = UserSet.All; /// - /// The set of users that are allowed to edit (save) scripts. This is only active if + /// The set of users that are allowed to edit (save) scripts. This is only active if /// permissions are not being bypassed. This overrides normal permissions.- /// private UserSet m_allowedScriptEditors = UserSet.All; - + private Dictionary GrantLSL = new Dictionary(); private Dictionary GrantCS = new Dictionary(); private Dictionary GrantVB = new Dictionary(); private Dictionary GrantJS = new Dictionary(); private Dictionary GrantYP = new Dictionary(); - + private IFriendsModule m_friendsModule; private IFriendsModule FriendsModule { @@ -168,21 +160,25 @@ namespace OpenSim.Region.CoreModules.World.Permissions m_Enabled = true; - m_allowGridGods = Util.GetConfigVarFromSections(config, "allow_grid_gods", - new string[] { "Startup", "Permissions" }, false); - m_bypassPermissions = !Util.GetConfigVarFromSections(config, "serverside_object_permissions", - new string[] { "Startup", "Permissions" }, true); - m_propagatePermissions = Util.GetConfigVarFromSections(config, "propagate_permissions", - new string[] { "Startup", "Permissions" }, true); - m_RegionOwnerIsGod = Util.GetConfigVarFromSections(config, "region_owner_is_god", - new string[] { "Startup", "Permissions" }, true); - m_RegionManagerIsGod = Util.GetConfigVarFromSections(config, "region_manager_is_god", - new string[] { "Startup", "Permissions" }, false); - m_ParcelOwnerIsGod = Util.GetConfigVarFromSections(config, "parcel_owner_is_god", - new string[] { "Startup", "Permissions" }, true); - - m_SimpleBuildPermissions = Util.GetConfigVarFromSections(config, "simple_build_permissions", - new string[] { "Startup", "Permissions" }, false); + string[] sections = new string[] { "Startup", "Permissions" }; + + m_allowGridAdmins = Util.GetConfigVarFromSections(config, "allow_grid_gods", sections, false); + m_bypassPermissions = !Util.GetConfigVarFromSections(config, "serverside_object_permissions", sections, true); + m_propagatePermissions = Util.GetConfigVarFromSections(config, "propagate_permissions", sections, true); + + m_forceGridAdminsOnly = Util.GetConfigVarFromSections(config, "force_grid_gods_only", sections, false); + if(!m_forceGridAdminsOnly) + { + m_RegionOwnerIsAdmin = Util.GetConfigVarFromSections(config, "region_owner_is_god",sections, true); + m_RegionManagerIsAdmin = Util.GetConfigVarFromSections(config, "region_manager_is_god",sections, false); + } + else + m_allowGridAdmins = true; + + m_forceAdminModeAlwaysOn = Util.GetConfigVarFromSections(config, "automatic_gods", sections, false); + m_allowAdminActionsWithoutGodMode = Util.GetConfigVarFromSections(config, "implicit_gods", sections, false); + if(m_allowAdminActionsWithoutGodMode) + m_forceAdminModeAlwaysOn = false; m_allowedScriptCreators = ParseUserSetConfigSetting(config, "allowed_script_creators", m_allowedScriptCreators); @@ -206,7 +202,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions } grant = Util.GetConfigVarFromSections(config, "GrantCS", - new string[] { "Startup", "Permissions" }, string.Empty); + new string[] { "Startup", "Permissions" }, string.Empty); if (grant.Length > 0) { foreach (string uuidl in grant.Split(',')) @@ -258,61 +254,79 @@ namespace OpenSim.Region.CoreModules.World.Permissions m_scene = scene; scene.RegisterModuleInterface(this); + scenePermissions = m_scene.Permissions; //Register functions with Scene External Checks! - m_scene.Permissions.OnBypassPermissions += BypassPermissions; - m_scene.Permissions.OnSetBypassPermissions += SetBypassPermissions; - m_scene.Permissions.OnPropagatePermissions += PropagatePermissions; - m_scene.Permissions.OnGenerateClientFlags += GenerateClientFlags; - m_scene.Permissions.OnAbandonParcel += CanAbandonParcel; - m_scene.Permissions.OnReclaimParcel += CanReclaimParcel; - m_scene.Permissions.OnDeedParcel += CanDeedParcel; - m_scene.Permissions.OnDeedObject += CanDeedObject; - m_scene.Permissions.OnIsGod += IsGod; - m_scene.Permissions.OnIsGridGod += IsGridGod; - m_scene.Permissions.OnIsAdministrator += IsAdministrator; - m_scene.Permissions.OnDuplicateObject += CanDuplicateObject; - m_scene.Permissions.OnDeleteObject += CanDeleteObject; - m_scene.Permissions.OnEditObject += CanEditObject; - m_scene.Permissions.OnEditParcelProperties += CanEditParcelProperties; - m_scene.Permissions.OnInstantMessage += CanInstantMessage; - m_scene.Permissions.OnInventoryTransfer += CanInventoryTransfer; - m_scene.Permissions.OnIssueEstateCommand += CanIssueEstateCommand; - m_scene.Permissions.OnMoveObject += CanMoveObject; - m_scene.Permissions.OnObjectEntry += CanObjectEntry; - m_scene.Permissions.OnReturnObjects += CanReturnObjects; - m_scene.Permissions.OnRezObject += CanRezObject; - m_scene.Permissions.OnRunConsoleCommand += CanRunConsoleCommand; - m_scene.Permissions.OnRunScript += CanRunScript; - m_scene.Permissions.OnCompileScript += CanCompileScript; - m_scene.Permissions.OnSellParcel += CanSellParcel; - m_scene.Permissions.OnTakeObject += CanTakeObject; - m_scene.Permissions.OnTakeCopyObject += CanTakeCopyObject; - m_scene.Permissions.OnTerraformLand += CanTerraformLand; - m_scene.Permissions.OnLinkObject += CanLinkObject; - m_scene.Permissions.OnDelinkObject += CanDelinkObject; - m_scene.Permissions.OnBuyLand += CanBuyLand; - - m_scene.Permissions.OnViewNotecard += CanViewNotecard; - m_scene.Permissions.OnViewScript += CanViewScript; - m_scene.Permissions.OnEditNotecard += CanEditNotecard; - m_scene.Permissions.OnEditScript += CanEditScript; - - m_scene.Permissions.OnCreateObjectInventory += CanCreateObjectInventory; - m_scene.Permissions.OnEditObjectInventory += CanEditObjectInventory; - m_scene.Permissions.OnCopyObjectInventory += CanCopyObjectInventory; - m_scene.Permissions.OnDeleteObjectInventory += CanDeleteObjectInventory; - m_scene.Permissions.OnResetScript += CanResetScript; + scenePermissions.OnBypassPermissions += BypassPermissions; + scenePermissions.OnSetBypassPermissions += SetBypassPermissions; + scenePermissions.OnPropagatePermissions += PropagatePermissions; + + scenePermissions.OnIsGridGod += IsGridAdministrator; + scenePermissions.OnIsAdministrator += IsAdministrator; + scenePermissions.OnIsEstateManager += IsEstateManager; + + scenePermissions.OnGenerateClientFlags += GenerateClientFlags; + + scenePermissions.OnIssueEstateCommand += CanIssueEstateCommand; + scenePermissions.OnRunConsoleCommand += CanRunConsoleCommand; + + scenePermissions.OnTeleport += CanTeleport; + + scenePermissions.OnInstantMessage += CanInstantMessage; + + scenePermissions.OnAbandonParcel += CanAbandonParcel; + scenePermissions.OnReclaimParcel += CanReclaimParcel; + scenePermissions.OnDeedParcel += CanDeedParcel; + scenePermissions.OnSellParcel += CanSellParcel; + scenePermissions.OnEditParcelProperties += CanEditParcelProperties; + scenePermissions.OnTerraformLand += CanTerraformLand; + scenePermissions.OnBuyLand += CanBuyLand; + + scenePermissions.OnReturnObjects += CanReturnObjects; + + scenePermissions.OnRezObject += CanRezObject; + scenePermissions.OnObjectEntry += CanObjectEntry; + scenePermissions.OnObjectEnterWithScripts += OnObjectEnterWithScripts; + + scenePermissions.OnDuplicateObject += CanDuplicateObject; + scenePermissions.OnDeleteObjectByIDs += CanDeleteObjectByIDs; + scenePermissions.OnDeleteObject += CanDeleteObject; + scenePermissions.OnEditObjectByIDs += CanEditObjectByIDs; + scenePermissions.OnEditObject += CanEditObject; + scenePermissions.OnEditObjectPerms += CanEditObjectPerms; + scenePermissions.OnInventoryTransfer += CanInventoryTransfer; + scenePermissions.OnMoveObject += CanMoveObject; + scenePermissions.OnTakeObject += CanTakeObject; + scenePermissions.OnTakeCopyObject += CanTakeCopyObject; + scenePermissions.OnLinkObject += CanLinkObject; + scenePermissions.OnDelinkObject += CanDelinkObject; + scenePermissions.OnDeedObject += CanDeedObject; + scenePermissions.OnSellGroupObject += CanSellGroupObject; + scenePermissions.OnSellObjectByUserID += CanSellObjectByUserID; + scenePermissions.OnSellObject += CanSellObject; - m_scene.Permissions.OnCreateUserInventory += CanCreateUserInventory; - m_scene.Permissions.OnCopyUserInventory += CanCopyUserInventory; - m_scene.Permissions.OnEditUserInventory += CanEditUserInventory; - m_scene.Permissions.OnDeleteUserInventory += CanDeleteUserInventory; + scenePermissions.OnCreateObjectInventory += CanCreateObjectInventory; + scenePermissions.OnEditObjectInventory += CanEditObjectInventory; + scenePermissions.OnCopyObjectInventory += CanCopyObjectInventory; + scenePermissions.OnDeleteObjectInventory += CanDeleteObjectInventory; + scenePermissions.OnDoObjectInvToObjectInv += CanDoObjectInvToObjectInv; + scenePermissions.OnDropInObjectInv += CanDropInObjectInv; + + scenePermissions.OnViewNotecard += CanViewNotecard; + scenePermissions.OnViewScript += CanViewScript; + scenePermissions.OnEditNotecard += CanEditNotecard; + scenePermissions.OnEditScript += CanEditScript; + scenePermissions.OnResetScript += CanResetScript; + scenePermissions.OnRunScript += CanRunScript; + scenePermissions.OnCompileScript += CanCompileScript; - m_scene.Permissions.OnTeleport += CanTeleport; - - m_scene.Permissions.OnControlPrimMedia += CanControlPrimMedia; - m_scene.Permissions.OnInteractWithPrimMedia += CanInteractWithPrimMedia; + scenePermissions.OnCreateUserInventory += CanCreateUserInventory; + scenePermissions.OnCopyUserInventory += CanCopyUserInventory; + scenePermissions.OnEditUserInventory += CanEditUserInventory; + scenePermissions.OnDeleteUserInventory += CanDeleteUserInventory; + + scenePermissions.OnControlPrimMedia += CanControlPrimMedia; + scenePermissions.OnInteractWithPrimMedia += CanInteractWithPrimMedia; m_scene.AddCommand("Users", this, "bypass permissions", "bypass permissions ", @@ -327,8 +341,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions m_scene.AddCommand("Debug", this, "debug permissions", "debug permissions ", "Turn on permissions debugging", - HandleDebugPermissions); - + HandleDebugPermissions); + } public void RegionLoaded(Scene scene) @@ -341,6 +355,79 @@ namespace OpenSim.Region.CoreModules.World.Permissions return; m_scene.UnregisterModuleInterface(this); + + scenePermissions.OnBypassPermissions -= BypassPermissions; + scenePermissions.OnSetBypassPermissions -= SetBypassPermissions; + scenePermissions.OnPropagatePermissions -= PropagatePermissions; + + scenePermissions.OnIsGridGod -= IsGridAdministrator; + scenePermissions.OnIsAdministrator -= IsAdministrator; + scenePermissions.OnIsEstateManager -= IsEstateManager; + + scenePermissions.OnGenerateClientFlags -= GenerateClientFlags; + + scenePermissions.OnIssueEstateCommand -= CanIssueEstateCommand; + scenePermissions.OnRunConsoleCommand -= CanRunConsoleCommand; + + scenePermissions.OnTeleport -= CanTeleport; + + scenePermissions.OnInstantMessage -= CanInstantMessage; + + scenePermissions.OnAbandonParcel -= CanAbandonParcel; + scenePermissions.OnReclaimParcel -= CanReclaimParcel; + scenePermissions.OnDeedParcel -= CanDeedParcel; + scenePermissions.OnSellParcel -= CanSellParcel; + scenePermissions.OnEditParcelProperties -= CanEditParcelProperties; + scenePermissions.OnTerraformLand -= CanTerraformLand; + scenePermissions.OnBuyLand -= CanBuyLand; + + scenePermissions.OnRezObject -= CanRezObject; + scenePermissions.OnObjectEntry -= CanObjectEntry; + scenePermissions.OnObjectEnterWithScripts -= OnObjectEnterWithScripts; + + scenePermissions.OnReturnObjects -= CanReturnObjects; + + scenePermissions.OnDuplicateObject -= CanDuplicateObject; + scenePermissions.OnDeleteObjectByIDs -= CanDeleteObjectByIDs; + scenePermissions.OnDeleteObject -= CanDeleteObject; + scenePermissions.OnEditObjectByIDs -= CanEditObjectByIDs; + scenePermissions.OnEditObject -= CanEditObject; + scenePermissions.OnEditObjectPerms -= CanEditObjectPerms; + scenePermissions.OnInventoryTransfer -= CanInventoryTransfer; + scenePermissions.OnMoveObject -= CanMoveObject; + scenePermissions.OnTakeObject -= CanTakeObject; + scenePermissions.OnTakeCopyObject -= CanTakeCopyObject; + scenePermissions.OnLinkObject -= CanLinkObject; + scenePermissions.OnDelinkObject -= CanDelinkObject; + scenePermissions.OnDeedObject -= CanDeedObject; + + scenePermissions.OnSellGroupObject -= CanSellGroupObject; + scenePermissions.OnSellObjectByUserID -= CanSellObjectByUserID; + scenePermissions.OnSellObject -= CanSellObject; + + scenePermissions.OnCreateObjectInventory -= CanCreateObjectInventory; + scenePermissions.OnEditObjectInventory -= CanEditObjectInventory; + scenePermissions.OnCopyObjectInventory -= CanCopyObjectInventory; + scenePermissions.OnDeleteObjectInventory -= CanDeleteObjectInventory; + scenePermissions.OnDoObjectInvToObjectInv -= CanDoObjectInvToObjectInv; + scenePermissions.OnDropInObjectInv -= CanDropInObjectInv; + + scenePermissions.OnViewNotecard -= CanViewNotecard; + scenePermissions.OnViewScript -= CanViewScript; + scenePermissions.OnEditNotecard -= CanEditNotecard; + scenePermissions.OnEditScript -= CanEditScript; + scenePermissions.OnResetScript -= CanResetScript; + scenePermissions.OnRunScript -= CanRunScript; + scenePermissions.OnCompileScript -= CanCompileScript; + + scenePermissions.OnCreateUserInventory -= CanCreateUserInventory; + scenePermissions.OnCopyUserInventory -= CanCopyUserInventory; + scenePermissions.OnEditUserInventory -= CanEditUserInventory; + scenePermissions.OnDeleteUserInventory -= CanDeleteUserInventory; + + scenePermissions.OnControlPrimMedia -= CanControlPrimMedia; + scenePermissions.OnInteractWithPrimMedia -= CanInteractWithPrimMedia; + } public void Close() @@ -349,7 +436,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions public string Name { - get { return "PermissionsModule"; } + get { return "DefaultPermissionsModule"; } } public Type ReplaceableInterface @@ -439,7 +526,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions { m_scene.EventManager.TriggerPermissionError(user, reason); } - + protected void DebugPermissionInformation(string permissionCalled) { if (m_debugPermissions) @@ -469,7 +556,37 @@ namespace OpenSim.Region.CoreModules.World.Permissions return false; } - + + protected bool GroupMemberPowers(UUID groupID, UUID userID, ref ulong powers) + { + powers = 0; + if (null == GroupsModule) + return false; + + GroupMembershipData gmd = GroupsModule.GetMembershipData(groupID, userID); + + if (gmd != null) + { + powers = gmd.GroupPowers; + return true; + } + return false; + } + + protected bool GroupMemberPowers(UUID groupID, ScenePresence sp, ref ulong powers) + { + powers = 0; + IClientAPI client = sp.ControllingClient; + if (client == null) + return false; + + if(!client.IsGroupMember(groupID)) + return false; + + powers = client.GetGroupPowers(groupID); + return true; + } + /// /// Parse a user set configuration setting /// @@ -481,28 +598,28 @@ namespace OpenSim.Region.CoreModules.World.Permissions { UserSet userSet = defaultValue; - string rawSetting = Util.GetConfigVarFromSections(config, settingName, - new string[] {"Startup", "Permissions"}, defaultValue.ToString()); - + string rawSetting = Util.GetConfigVarFromSections(config, settingName, + new string[] {"Startup", "Permissions"}, defaultValue.ToString()); + // Temporary measure to allow 'gods' to be specified in config for consistency's sake. In the long term // this should disappear. if ("gods" == rawSetting.ToLower()) rawSetting = UserSet.Administrators.ToString(); - + // Doing it this was so that we can do a case insensitive conversion try { userSet = (UserSet)Enum.Parse(typeof(UserSet), rawSetting, true); } - catch + catch { m_log.ErrorFormat( "[PERMISSIONS]: {0} is not a valid {1} value, setting to {2}", rawSetting, settingName, userSet); } - + m_log.DebugFormat("[PERMISSIONS]: {0} {1}", settingName, userSet); - + return userSet; } @@ -516,13 +633,13 @@ namespace OpenSim.Region.CoreModules.World.Permissions if (user == UUID.Zero) return false; - if (m_scene.RegionInfo.EstateSettings.EstateOwner == user && m_RegionOwnerIsGod) + if (m_RegionOwnerIsAdmin && m_scene.RegionInfo.EstateSettings.EstateOwner == user) return true; - - if (IsEstateManager(user) && m_RegionManagerIsGod) + + if (m_RegionManagerIsAdmin && IsEstateManager(user)) return true; - if (IsGridGod(user, null)) + if (IsGridAdministrator(user)) return true; return false; @@ -534,18 +651,19 @@ namespace OpenSim.Region.CoreModules.World.Permissions /// The user /// Unused, can be null /// - protected bool IsGridGod(UUID user, Scene scene) + protected bool IsGridAdministrator(UUID user) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; - if (user == UUID.Zero) return false; + if (user == UUID.Zero) + return false; - if (m_allowGridGods) + if (m_allowGridAdmins) { ScenePresence sp = m_scene.GetScenePresence(user); if (sp != null) - return (sp.UserLevel >= 200); + return (sp.GodController.UserLevel >= 200); UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, user); if (account != null) @@ -556,11 +674,11 @@ namespace OpenSim.Region.CoreModules.World.Permissions } protected bool IsFriendWithPerms(UUID user, UUID objectOwner) - { - if (user == UUID.Zero) + { + if (FriendsModule == null) return false; - if (FriendsModule == null) + if (user == UUID.Zero) return false; int friendPerms = FriendsModule.GetRightsGrantedByFriend(user, objectOwner); @@ -570,7 +688,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions protected bool IsEstateManager(UUID user) { if (user == UUID.Zero) return false; - + return m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(user); } @@ -596,75 +714,178 @@ namespace OpenSim.Region.CoreModules.World.Permissions #region Object Permissions - public uint GenerateClientFlags(UUID user, UUID objID) - { - // Here's the way this works, - // ObjectFlags and Permission flags are two different enumerations - // ObjectFlags, however, tells the client to change what it will allow the user to do. - // So, that means that all of the permissions type ObjectFlags are /temporary/ and only - // supposed to be set when customizing the objectflags for the client. + const uint DEFAULT_FLAGS = (uint)( + PrimFlags.ObjectCopy | // Tells client you can copy the object + PrimFlags.ObjectModify | // tells client you can modify the object + PrimFlags.ObjectMove | // tells client that you can move the object (only, no mod) + PrimFlags.ObjectTransfer | // tells the client that you can /take/ the object if you don't own it + PrimFlags.ObjectYouOwner | // Tells client that you're the owner of the object + PrimFlags.ObjectAnyOwner | // Tells client that someone owns the object + PrimFlags.ObjectOwnerModify // Tells client that you're the owner of the object + ); + + const uint NOT_DEFAULT_FLAGS = (uint)~( + PrimFlags.ObjectCopy | // Tells client you can copy the object + PrimFlags.ObjectModify | // tells client you can modify the object + PrimFlags.ObjectMove | // tells client that you can move the object (only, no mod) + PrimFlags.ObjectTransfer | // tells the client that you can /take/ the object if you don't own it + PrimFlags.ObjectYouOwner | // Tells client that you're the owner of the object + PrimFlags.ObjectAnyOwner | // Tells client that someone owns the object + PrimFlags.ObjectOwnerModify // Tells client that you're the owner of the object + ); + + const uint EXTRAOWNERMASK = (uint)( + PrimFlags.ObjectYouOwner | + PrimFlags.ObjectAnyOwner + ); + + const uint EXTRAGODMASK = (uint)( + PrimFlags.ObjectYouOwner | + PrimFlags.ObjectAnyOwner | + PrimFlags.ObjectOwnerModify | + PrimFlags.ObjectModify | + PrimFlags.ObjectMove + ); + + const uint GOD_FLAGS = (uint)( + PrimFlags.ObjectCopy | // Tells client you can copy the object + PrimFlags.ObjectModify | // tells client you can modify the object + PrimFlags.ObjectMove | // tells client that you can move the object (only, no mod) + PrimFlags.ObjectTransfer | // tells the client that you can /take/ the object if you don't own it + PrimFlags.ObjectYouOwner | // Tells client that you're the owner of the object + PrimFlags.ObjectAnyOwner | // Tells client that someone owns the object + PrimFlags.ObjectOwnerModify // Tells client that you're the owner of the object + ); + + const uint LOCKED_GOD_FLAGS = (uint)( + PrimFlags.ObjectCopy | // Tells client you can copy the object + PrimFlags.ObjectTransfer | // tells the client that you can /take/ the object if you don't own it + PrimFlags.ObjectYouOwner | // Tells client that you're the owner of the object + PrimFlags.ObjectAnyOwner // Tells client that someone owns the object + ); + + const uint SHAREDMASK = (uint)( + PermissionMask.Move | + PermissionMask.Modify | + PermissionMask.Copy + ); + + public uint GenerateClientFlags(SceneObjectPart task, ScenePresence sp, uint curEffectivePerms) + { + if(sp == null || task == null || curEffectivePerms == 0) + return 0; - // These temporary objectflags get computed and added in this function based on the - // Permission mask that's appropriate! - // Outside of this method, they should never be added to objectflags! - // -teravus + // Remove any of the objectFlags that are temporary. These will get added back if appropriate + uint objflags = curEffectivePerms & NOT_DEFAULT_FLAGS ; - SceneObjectPart task = m_scene.GetSceneObjectPart(objID); + uint returnMask; - // this shouldn't ever happen.. return no permissions/objectflags. - if (task == null) - return (uint)0; + SceneObjectGroup grp = task.ParentGroup; + if(grp == null) + return 0; - uint objflags = task.GetEffectiveObjectFlags(); - UUID objectOwner = task.OwnerID; + UUID taskOwnerID = task.OwnerID; + UUID spID = sp.UUID; + bool unlocked = (grp.RootPart.OwnerMask & (uint)PermissionMask.Move) != 0; - // Remove any of the objectFlags that are temporary. These will get added back if appropriate - // in the next bit of code - - // libomv will moan about PrimFlags.ObjectYouOfficer being - // deprecated -#pragma warning disable 0612 - objflags &= (uint) - ~(PrimFlags.ObjectCopy | // Tells client you can copy the object - PrimFlags.ObjectModify | // tells client you can modify the object - PrimFlags.ObjectMove | // tells client that you can move the object (only, no mod) - PrimFlags.ObjectTransfer | // tells the client that you can /take/ the object if you don't own it - PrimFlags.ObjectYouOwner | // Tells client that you're the owner of the object - PrimFlags.ObjectAnyOwner | // Tells client that someone owns the object - PrimFlags.ObjectOwnerModify | // Tells client that you're the owner of the object - PrimFlags.ObjectYouOfficer // Tells client that you've got group object editing permission. Used when ObjectGroupOwned is set - ); -#pragma warning restore 0612 - - // Creating the three ObjectFlags options for this method to choose from. - // Customize the OwnerMask - uint objectOwnerMask = ApplyObjectModifyMasks(task.OwnerMask, objflags); - objectOwnerMask |= (uint)PrimFlags.ObjectYouOwner | (uint)PrimFlags.ObjectAnyOwner | (uint)PrimFlags.ObjectOwnerModify; - - // Customize the GroupMask - uint objectGroupMask = ApplyObjectModifyMasks(task.GroupMask, objflags); - - // Customize the EveryoneMask - uint objectEveryoneMask = ApplyObjectModifyMasks(task.EveryoneMask, objflags); - if (objectOwner != UUID.Zero) - objectEveryoneMask |= (uint)PrimFlags.ObjectAnyOwner; - - PermissionClass permissionClass = GetPermissionClass(user, task); - - switch (permissionClass) + if(sp.IsGod) + { + // do locked on objects owned by admin + if(!unlocked && spID == taskOwnerID) + return objflags | LOCKED_GOD_FLAGS; + else + return objflags | GOD_FLAGS; + } + + //bypass option == owner rights + if (m_bypassPermissions) + { + returnMask = ApplyObjectModifyMasks(task.OwnerMask, objflags, true); //?? + returnMask |= EXTRAOWNERMASK; + if((returnMask & (uint)PrimFlags.ObjectModify) != 0) + returnMask |= (uint)PrimFlags.ObjectOwnerModify; + return returnMask; + } + + // owner + if (spID == taskOwnerID) + { + returnMask = ApplyObjectModifyMasks(grp.EffectiveOwnerPerms, objflags, unlocked); + returnMask |= EXTRAOWNERMASK; + if((returnMask & (uint)PrimFlags.ObjectModify) != 0) + returnMask |= (uint)PrimFlags.ObjectOwnerModify; + return returnMask; + } + + // if not god or owner, do attachments as everyone + if(task.ParentGroup.IsAttachment) + { + returnMask = ApplyObjectModifyMasks(grp.EffectiveEveryOnePerms, objflags, unlocked); + if (taskOwnerID != UUID.Zero) + returnMask |= (uint)PrimFlags.ObjectAnyOwner; + return returnMask; + } + + UUID taskGroupID = task.GroupID; + bool notGroupdOwned = taskOwnerID != taskGroupID; + + // if friends with rights then owner + if (notGroupdOwned && IsFriendWithPerms(spID, taskOwnerID)) + { + returnMask = ApplyObjectModifyMasks(grp.EffectiveOwnerPerms, objflags, unlocked); + returnMask |= EXTRAOWNERMASK; + if((returnMask & (uint)PrimFlags.ObjectModify) != 0) + returnMask |= (uint)PrimFlags.ObjectOwnerModify; + return returnMask; + } + + // group owned or shared ? + IClientAPI client = sp.ControllingClient; + ulong powers = 0; + if(taskGroupID != UUID.Zero && GroupMemberPowers(taskGroupID, sp, ref powers)) { - case PermissionClass.Owner: - return objectOwnerMask; - case PermissionClass.Group: - return objectGroupMask | objectEveryoneMask; - case PermissionClass.Everyone: - default: - return objectEveryoneMask; + if(notGroupdOwned) + { + // group sharing or everyone + returnMask = ApplyObjectModifyMasks(grp.EffectiveGroupOrEveryOnePerms, objflags, unlocked); + if (taskOwnerID != UUID.Zero) + returnMask |= (uint)PrimFlags.ObjectAnyOwner; + return returnMask; + } + + // object is owned by group, check role powers + if((powers & (ulong)GroupPowers.ObjectManipulate) == 0) + { + // group sharing or everyone + returnMask = ApplyObjectModifyMasks(grp.EffectiveGroupOrEveryOnePerms, objflags, unlocked); + returnMask |= + (uint)PrimFlags.ObjectGroupOwned | + (uint)PrimFlags.ObjectAnyOwner; + return returnMask; + } + + // we may have copy without transfer + uint grpEffectiveOwnerPerms = grp.EffectiveOwnerPerms; + if((grpEffectiveOwnerPerms & (uint)PermissionMask.Transfer) == 0) + grpEffectiveOwnerPerms &= ~(uint)PermissionMask.Copy; + returnMask = ApplyObjectModifyMasks(grpEffectiveOwnerPerms, objflags, unlocked); + returnMask |= + (uint)PrimFlags.ObjectGroupOwned | + (uint)PrimFlags.ObjectYouOwner; + if((returnMask & (uint)PrimFlags.ObjectModify) != 0) + returnMask |= (uint)PrimFlags.ObjectOwnerModify; + return returnMask; } + + // fallback is everyone rights + returnMask = ApplyObjectModifyMasks(grp.EffectiveEveryOnePerms, objflags, unlocked); + if (taskOwnerID != UUID.Zero) + returnMask |= (uint)PrimFlags.ObjectAnyOwner; + return returnMask; } - private uint ApplyObjectModifyMasks(uint setPermissionMask, uint objectFlagsMask) + private uint ApplyObjectModifyMasks(uint setPermissionMask, uint objectFlagsMask, bool unlocked) { // We are adding the temporary objectflags to the object's objectflags based on the // permission flag given. These change the F flags on the client. @@ -674,14 +895,17 @@ namespace OpenSim.Region.CoreModules.World.Permissions objectFlagsMask |= (uint)PrimFlags.ObjectCopy; } - if ((setPermissionMask & (uint)PermissionMask.Move) != 0) + if (unlocked) { - objectFlagsMask |= (uint)PrimFlags.ObjectMove; - } + if ((setPermissionMask & (uint)PermissionMask.Move) != 0) + { + objectFlagsMask |= (uint)PrimFlags.ObjectMove; + } - if ((setPermissionMask & (uint)PermissionMask.Modify) != 0) - { - objectFlagsMask |= (uint)PrimFlags.ObjectModify; + if ((setPermissionMask & (uint)PermissionMask.Modify) != 0) + { + objectFlagsMask |= (uint)PrimFlags.ObjectModify; + } } if ((setPermissionMask & (uint)PermissionMask.Transfer) != 0) @@ -692,6 +916,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions return objectFlagsMask; } + // OARs still need this method that handles offline users public PermissionClass GetPermissionClass(UUID user, SceneObjectPart obj) { if (obj == null) @@ -705,135 +930,199 @@ namespace OpenSim.Region.CoreModules.World.Permissions if (user == objectOwner) return PermissionClass.Owner; - if (IsFriendWithPerms(user, objectOwner)) - return PermissionClass.Owner; - - // Estate users should be able to edit anything in the sim if RegionOwnerIsGod is set - if (m_RegionOwnerIsGod && IsEstateManager(user) && !IsAdministrator(objectOwner)) - return PermissionClass.Owner; - // Admin should be able to edit anything in the sim (including admin objects) if (IsAdministrator(user)) return PermissionClass.Owner; - // Users should be able to edit what is over their land. - Vector3 taskPos = obj.AbsolutePosition; - ILandObject parcel = m_scene.LandChannel.GetLandObject(taskPos.X, taskPos.Y); - if (parcel != null && parcel.LandData.OwnerID == user && m_ParcelOwnerIsGod) + if(!obj.ParentGroup.IsAttachment) { - // Admin objects should not be editable by the above - if (!IsAdministrator(objectOwner)) + if (IsFriendWithPerms(user, objectOwner) ) return PermissionClass.Owner; - } - // Group permissions - if ((obj.GroupID != UUID.Zero) && IsGroupMember(obj.GroupID, user, 0)) - return PermissionClass.Group; + // Group permissions + if (obj.GroupID != UUID.Zero && IsGroupMember(obj.GroupID, user, 0)) + return PermissionClass.Group; + } return PermissionClass.Everyone; } - /// - /// General permissions checks for any operation involving an object. These supplement more specific checks - /// implemented by callers. - /// - /// - /// This is a scene object group UUID - /// - /// - protected bool GenericObjectPermission(UUID currentUser, UUID objId, bool denyOnLocked) + // get effective object permissions using user UUID. User rights will be fixed + protected uint GetObjectPermissions(UUID currentUser, SceneObjectGroup group, bool denyOnLocked) { - // Default: deny - bool permission = false; - bool locked = false; - - SceneObjectPart part = m_scene.GetSceneObjectPart(objId); + if (group == null) + return 0; - if (part == null) - return false; - - SceneObjectGroup group = part.ParentGroup; + SceneObjectPart root = group.RootPart; + if (root == null) + return 0; UUID objectOwner = group.OwnerID; - locked = ((group.RootPart.OwnerMask & PERM_LOCKED) == 0); + bool locked = denyOnLocked && ((root.OwnerMask & (uint)PermissionMask.Move) == 0); - // People shouldn't be able to do anything with locked objects, except the Administrator - // The 'set permissions' runs through a different permission check, so when an object owner - // sets an object locked, the only thing that they can do is unlock it. - // - // Nobody but the object owner can set permissions on an object - // - if (locked && (!IsAdministrator(currentUser)) && denyOnLocked) + if (IsAdministrator(currentUser)) { - return false; + // do lock on admin owned objects + if(locked && currentUser == objectOwner) + return (uint)(PermissionMask.AllEffective & ~(PermissionMask.Modify | PermissionMask.Move)); + return (uint)PermissionMask.AllEffective; } - // Object owners should be able to edit their own content + uint lockmask = (uint)PermissionMask.AllEffective; + if(locked) + lockmask &= ~(uint)(PermissionMask.Modify | PermissionMask.Move); + if (currentUser == objectOwner) + return group.EffectiveOwnerPerms & lockmask; + + if (group.IsAttachment) + return 0; + + UUID sogGroupID = group.GroupID; + bool notgroudOwned = sogGroupID != objectOwner; + + if (notgroudOwned && IsFriendWithPerms(currentUser, objectOwner)) + return group.EffectiveOwnerPerms & lockmask; + + ulong powers = 0; + if (sogGroupID != UUID.Zero && GroupMemberPowers(sogGroupID, currentUser, ref powers)) { - // there is no way that later code can change this back to false - // so just return true immediately and short circuit the more - // expensive group checks - return true; - - //permission = true; + if(notgroudOwned) + return group.EffectiveGroupOrEveryOnePerms & lockmask; + + if((powers & (ulong)GroupPowers.ObjectManipulate) == 0) + return group.EffectiveGroupOrEveryOnePerms & lockmask; + + uint grpEffectiveOwnerPerms = group.EffectiveOwnerPerms & lockmask; + if((grpEffectiveOwnerPerms & (uint)PermissionMask.Transfer) == 0) + grpEffectiveOwnerPerms &= ~(uint)PermissionMask.Copy; + return grpEffectiveOwnerPerms; } - else if (group.IsAttachment) + + return group.EffectiveEveryOnePerms & lockmask; + } + + // get effective object permissions using present presence. So some may depend on requested rights (ie God) + protected uint GetObjectPermissions(ScenePresence sp, SceneObjectGroup group, bool denyOnLocked) + { + if (sp == null || sp.IsDeleted || group == null || group.IsDeleted) + return 0; + + SceneObjectPart root = group.RootPart; + if (root == null) + return 0; + + UUID spID = sp.UUID; + UUID objectOwner = group.OwnerID; + + bool locked = denyOnLocked && ((root.OwnerMask & (uint)PermissionMask.Move) == 0); + + if (sp.IsGod) { - permission = false; + if(locked && spID == objectOwner) + return (uint)(PermissionMask.AllEffective & ~(PermissionMask.Modify | PermissionMask.Move)); + return (uint)PermissionMask.AllEffective; } -// m_log.DebugFormat( -// "[PERMISSIONS]: group.GroupID = {0}, part.GroupMask = {1}, isGroupMember = {2} for {3}", -// group.GroupID, -// m_scene.GetSceneObjectPart(objId).GroupMask, -// IsGroupMember(group.GroupID, currentUser, 0), -// currentUser); + uint lockmask = (uint)PermissionMask.AllEffective; + if(locked) + lockmask &= ~(uint)(PermissionMask.Modify | PermissionMask.Move); + + if (spID == objectOwner) + return group.EffectiveOwnerPerms & lockmask; - // Group members should be able to edit group objects - if ((group.GroupID != UUID.Zero) - && ((m_scene.GetSceneObjectPart(objId).GroupMask & (uint)PermissionMask.Modify) != 0) - && IsGroupMember(group.GroupID, currentUser, 0)) - { - // Return immediately, so that the administrator can shares group objects - return true; - } + if (group.IsAttachment) + return 0; + + UUID sogGroupID = group.GroupID; + bool notgroudOwned = sogGroupID != objectOwner; - // Friends with benefits should be able to edit the objects too - if (IsFriendWithPerms(currentUser, objectOwner)) - { - // Return immediately, so that the administrator can share objects with friends - return true; - } - - // Users should be able to edit what is over their land. - ILandObject parcel = m_scene.LandChannel.GetLandObject(group.AbsolutePosition.X, group.AbsolutePosition.Y); - if ((parcel != null) && (parcel.LandData.OwnerID == currentUser)) - { - permission = true; - } + if (notgroudOwned && IsFriendWithPerms(spID, objectOwner)) + return group.EffectiveOwnerPerms & lockmask; - // Estate users should be able to edit anything in the sim - if (IsEstateManager(currentUser)) + ulong powers = 0; + if (sogGroupID != UUID.Zero && GroupMemberPowers(sogGroupID, sp, ref powers)) { - permission = true; + if(notgroudOwned) + return group.EffectiveGroupOrEveryOnePerms & lockmask; + + if((powers & (ulong)GroupPowers.ObjectManipulate) == 0) + return group.EffectiveGroupOrEveryOnePerms & lockmask; + + uint grpEffectiveOwnerPerms = group.EffectiveOwnerPerms & lockmask; + if((grpEffectiveOwnerPerms & (uint)PermissionMask.Transfer) == 0) + grpEffectiveOwnerPerms &= ~(uint)PermissionMask.Copy; + return grpEffectiveOwnerPerms; } - // Admin objects should not be editable by the above - if (IsAdministrator(objectOwner)) + return group.EffectiveEveryOnePerms & lockmask; + } + + private uint GetObjectItemPermissions(UUID userID, TaskInventoryItem ti) + { + UUID tiOwnerID = ti.OwnerID; + if(tiOwnerID == userID) + return ti.CurrentPermissions; + + if(IsAdministrator(userID)) + return (uint)PermissionMask.AllEffective; + // ?? + if (IsFriendWithPerms(userID, tiOwnerID)) + return ti.CurrentPermissions; + + UUID tiGroupID = ti.GroupID; + if(tiGroupID != UUID.Zero) { - permission = false; + ulong powers = 0; + if(GroupMemberPowers(tiGroupID, userID, ref powers)) + { + if(tiGroupID == ti.OwnerID) + { + if((powers & (ulong)GroupPowers.ObjectManipulate) != 0) + return ti.CurrentPermissions; + } + return ti.GroupPermissions; + } } - // Admin should be able to edit anything in the sim (including admin objects) - if (IsAdministrator(currentUser)) + return 0; + } + + private uint GetObjectItemPermissions(ScenePresence sp, TaskInventoryItem ti, bool notEveryone) + { + UUID tiOwnerID = ti.OwnerID; + UUID spID = sp.UUID; + + if(tiOwnerID == spID) + return ti.CurrentPermissions; + + // ?? + if (IsFriendWithPerms(spID, tiOwnerID)) + return ti.CurrentPermissions; + + UUID tiGroupID = ti.GroupID; + if(tiGroupID != UUID.Zero) { - permission = true; + ulong powers = 0; + if(GroupMemberPowers(tiGroupID, spID, ref powers)) + { + if(tiGroupID == ti.OwnerID) + { + if((powers & (ulong)GroupPowers.ObjectManipulate) != 0) + return ti.CurrentPermissions; + } + uint p = ti.GroupPermissions; + if(!notEveryone) + p |= ti.EveryonePermissions; + return p; + } } - return permission; - } + if(notEveryone) + return 0; + return ti.EveryonePermissions; + } #endregion #region Generic Permissions @@ -858,97 +1147,45 @@ namespace OpenSim.Region.CoreModules.World.Permissions public bool GenericEstatePermission(UUID user) { - // Default: deny - bool permission = false; - // Estate admins should be able to use estate tools if (IsEstateManager(user)) - permission = true; + return true; // Administrators always have permission if (IsAdministrator(user)) - permission = true; + return true; - return permission; + return false; } - protected bool GenericParcelPermission(UUID user, ILandObject parcel, ulong groupPowers) - { - bool permission = false; - - if (parcel.LandData.OwnerID == user) - { - permission = true; - } - - if ((parcel.LandData.GroupID != UUID.Zero) && IsGroupMember(parcel.LandData.GroupID, user, groupPowers)) - { - permission = true; - } - - if (IsEstateManager(user)) - { - permission = true; - } - - if (IsAdministrator(user)) - { - permission = true; - } - - if (m_SimpleBuildPermissions && - (parcel.LandData.Flags & (uint)ParcelFlags.UseAccessList) == 0 && parcel.IsInLandAccessList(user)) - permission = true; - - return permission; - } - protected bool GenericParcelOwnerPermission(UUID user, ILandObject parcel, ulong groupPowers, bool allowEstateManager) { if (parcel.LandData.OwnerID == user) - { - // Returning immediately so that group deeded objects on group deeded land don't trigger a NRE on - // the subsequent redundant checks when using lParcelMediaCommandList() - // See http://opensimulator.org/mantis/view.php?id=3999 for more details return true; - } if (parcel.LandData.IsGroupOwned && IsGroupMember(parcel.LandData.GroupID, user, groupPowers)) - { return true; - } - + if (allowEstateManager && IsEstateManager(user)) - { return true; - } if (IsAdministrator(user)) - { return true; - } return false; } - - protected bool GenericParcelPermission(UUID user, Vector3 pos, ulong groupPowers) - { - ILandObject parcel = m_scene.LandChannel.GetLandObject(pos.X, pos.Y); - if (parcel == null) return false; - return GenericParcelPermission(user, parcel, groupPowers); - } #endregion #region Permission Checks - private bool CanAbandonParcel(UUID user, ILandObject parcel, Scene scene) + private bool CanAbandonParcel(UUID user, ILandObject parcel) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; - + return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandRelease, false); } - private bool CanReclaimParcel(UUID user, ILandObject parcel, Scene scene) + private bool CanReclaimParcel(UUID user, ILandObject parcel) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; @@ -956,108 +1193,252 @@ namespace OpenSim.Region.CoreModules.World.Permissions return GenericParcelOwnerPermission(user, parcel, 0,true); } - private bool CanDeedParcel(UUID user, ILandObject parcel, Scene scene) + private bool CanDeedParcel(UUID user, ILandObject parcel) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; + if(parcel.LandData.GroupID == UUID.Zero) + return false; + + if (IsAdministrator(user)) + return true; + if (parcel.LandData.OwnerID != user) // Only the owner can deed! return false; - ScenePresence sp = scene.GetScenePresence(user); - IClientAPI client = sp.ControllingClient; + ScenePresence sp = m_scene.GetScenePresence(user); + if(sp == null) + return false; + IClientAPI client = sp.ControllingClient; if ((client.GetGroupPowers(parcel.LandData.GroupID) & (ulong)GroupPowers.LandDeed) == 0) return false; - return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandDeed, false); + return true; } - private bool CanDeedObject(UUID user, UUID group, Scene scene) + private bool CanDeedObject(ScenePresence sp, SceneObjectGroup sog, UUID targetGroupID) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; - ScenePresence sp = scene.GetScenePresence(user); - IClientAPI client = sp.ControllingClient; + if(sog == null || sog.IsDeleted || sp == null || sp.IsDeleted || targetGroupID == UUID.Zero) + return false; - if ((client.GetGroupPowers(group) & (ulong)GroupPowers.DeedObject) == 0) + // object has group already? + if(sog.GroupID != targetGroupID) return false; - return true; - } + // is effectivelly shared? + if(sog.EffectiveGroupPerms == 0) + return false; - private bool IsGod(UUID user, Scene scene) - { - DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); - if (m_bypassPermissions) return m_bypassPermissionsValue; + if(sp.IsGod) + return true; - return IsAdministrator(user); + // owned by requester? + if(sog.OwnerID != sp.UUID) + return false; + + // owner can transfer? + if((sog.EffectiveOwnerPerms & (uint)PermissionMask.Transfer) == 0) + return false; + + // group member ? + ulong powers = 0; + if(!GroupMemberPowers(targetGroupID, sp, ref powers)) + return false; + + // has group rights? + if ((powers & (ulong)GroupPowers.DeedObject) == 0) + return false; + + return true; } - private bool CanDuplicateObject(int objectCount, UUID objectID, UUID owner, Scene scene, Vector3 objectPosition) + private bool CanDuplicateObject(SceneObjectGroup sog, ScenePresence sp) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; - if (!GenericObjectPermission(owner, objectID, true)) - { - //They can't even edit the object + if (sog == null || sog.IsDeleted || sp == null || sp.IsDeleted) return false; - } - - SceneObjectPart part = scene.GetSceneObjectPart(objectID); - if (part == null) + + uint perms = GetObjectPermissions(sp, sog, false); + if((perms & (uint)PermissionMask.Copy) == 0) return false; - if (part.OwnerID == owner) - { - if ((part.OwnerMask & PERM_COPY) == 0) - return false; - } - else if (part.GroupID != UUID.Zero) - { - if ((part.OwnerID == part.GroupID) && ((owner != part.LastOwnerID) || ((part.GroupMask & PERM_TRANS) == 0))) - return false; + if(sog.OwnerID != sp.UUID && (perms & (uint)PermissionMask.Transfer) == 0) + return false; - if ((part.GroupMask & PERM_COPY) == 0) - return false; - } - //If they can rez, they can duplicate - return CanRezObject(objectCount, owner, objectPosition, scene); + return CanRezObject(0, sp.UUID, sog.AbsolutePosition); } - private bool CanDeleteObject(UUID objectID, UUID deleter, Scene scene) + private bool CanDeleteObject(SceneObjectGroup sog, ScenePresence sp) { + // ignoring locked. viewers should warn and ask for confirmation + DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; - return GenericObjectPermission(deleter, objectID, false); + if (sog == null || sog.IsDeleted || sp == null || sp.IsDeleted) + return false; + + if(sog.IsAttachment) + return false; + + UUID sogOwnerID = sog.OwnerID; + UUID spID = sp.UUID; + + if(sogOwnerID == spID) + return true; + + if (sp.IsGod) + return true; + + if (IsFriendWithPerms(sog.UUID, sogOwnerID)) + return true; + + UUID sogGroupID = sog.GroupID; + if (sogGroupID != UUID.Zero) + { + ulong powers = 0; + if(GroupMemberPowers(sogGroupID, sp, ref powers)) + { + if(sogGroupID == sogOwnerID) + { + if((powers & (ulong)GroupPowers.ObjectManipulate) != 0) + return true; + } + return (sog.EffectiveGroupPerms & (uint)PermissionMask.Modify) != 0; + } + } + return false; + } + + private bool CanDeleteObjectByIDs(UUID objectID, UUID userID) + { + // ignoring locked. viewers should warn and ask for confirmation + + DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); + if (m_bypassPermissions) return m_bypassPermissionsValue; + + SceneObjectGroup sog = m_scene.GetGroupByPrim(objectID); + if (sog == null) + return false; + + if(sog.IsAttachment) + return false; + + UUID sogOwnerID = sog.OwnerID; + + if(sogOwnerID == userID) + return true; + + if (IsAdministrator(userID)) + return true; + + if (IsFriendWithPerms(objectID, sogOwnerID)) + return true; + + UUID sogGroupID = sog.GroupID; + if (sogGroupID != UUID.Zero) + { + ulong powers = 0; + if(GroupMemberPowers(sogGroupID, userID, ref powers)) + { + if(sogGroupID == sogOwnerID) + { + if((powers & (ulong)GroupPowers.ObjectManipulate) != 0) + return true; + } + return (sog.EffectiveGroupPerms & (uint)PermissionMask.Modify) != 0; + } + } + return false; } - private bool CanEditObject(UUID objectID, UUID editorID, Scene scene) + private bool CanEditObjectByIDs(UUID objectID, UUID userID) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; - return GenericObjectPermission(editorID, objectID, false); + SceneObjectGroup sog = m_scene.GetGroupByPrim(objectID); + if (sog == null) + return false; + + uint perms = GetObjectPermissions(userID, sog, true); + if((perms & (uint)PermissionMask.Modify) == 0) + return false; + return true; } - private bool CanEditObjectInventory(UUID objectID, UUID editorID, Scene scene) + private bool CanEditObject(SceneObjectGroup sog, ScenePresence sp) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; - return GenericObjectPermission(editorID, objectID, false); + if(sog == null || sog.IsDeleted || sp == null || sp.IsDeleted) + return false; + + uint perms = GetObjectPermissions(sp, sog, true); + if((perms & (uint)PermissionMask.Modify) == 0) + return false; + return true; } - private bool CanEditParcelProperties(UUID user, ILandObject parcel, GroupPowers p, Scene scene) + private bool CanEditObjectPerms(SceneObjectGroup sog, UUID userID) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; - return GenericParcelOwnerPermission(user, parcel, (ulong)p, false); + if (sog == null) + return false; + + if(sog.OwnerID == userID || IsAdministrator(userID)) + return true; + + UUID sogGroupID = sog.GroupID; + if(sogGroupID == UUID.Zero || sogGroupID != sog.OwnerID) + return false; + + uint perms = sog.EffectiveOwnerPerms; + if((perms & (uint)PermissionMask.Modify) == 0) + return false; + + ulong powers = 0; + if(GroupMemberPowers(sogGroupID, userID, ref powers)) + { + if((powers & (ulong)GroupPowers.ObjectManipulate) != 0) + return true; + } + + return false; + } + + private bool CanEditObjectInventory(UUID objectID, UUID userID) + { + DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); + if (m_bypassPermissions) return m_bypassPermissionsValue; + + SceneObjectGroup sog = m_scene.GetGroupByPrim(objectID); + if (sog == null) + return false; + + uint perms = GetObjectPermissions(userID, sog, true); + if((perms & (uint)PermissionMask.Modify) == 0) + return false; + return true; + } + + private bool CanEditParcelProperties(UUID userID, ILandObject parcel, GroupPowers p, bool allowManager) + { + DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); + if (m_bypassPermissions) return m_bypassPermissionsValue; + + return GenericParcelOwnerPermission(userID, parcel, (ulong)p, false); } /// @@ -1068,18 +1449,18 @@ namespace OpenSim.Region.CoreModules.World.Permissions /// /// /// - private bool CanEditScript(UUID script, UUID objectID, UUID user, Scene scene) + private bool CanEditScript(UUID script, UUID objectID, UUID userID) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; - - if (m_allowedScriptEditors == UserSet.Administrators && !IsAdministrator(user)) + + if (m_allowedScriptEditors == UserSet.Administrators && !IsAdministrator(userID)) return false; - + // Ordinarily, if you can view it, you can edit it // There is no viewing a no mod script // - return CanViewScript(script, objectID, user, scene); + return CanViewScript(script, objectID, userID); } /// @@ -1090,7 +1471,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions /// /// /// - private bool CanEditNotecard(UUID notecard, UUID objectID, UUID user, Scene scene) + private bool CanEditNotecard(UUID notecard, UUID objectID, UUID user) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; @@ -1098,8 +1479,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions if (objectID == UUID.Zero) // User inventory { IInventoryService invService = m_scene.InventoryService; - InventoryItemBase assetRequestItem = new InventoryItemBase(notecard, user); - assetRequestItem = invService.GetItem(assetRequestItem); + InventoryItemBase assetRequestItem = invService.GetItem(user, notecard); if (assetRequestItem == null && LibraryRootFolder != null) // Library item { assetRequestItem = LibraryRootFolder.FindItem(notecard); @@ -1122,69 +1502,68 @@ namespace OpenSim.Region.CoreModules.World.Permissions } else // Prim inventory { - SceneObjectPart part = scene.GetSceneObjectPart(objectID); - + SceneObjectPart part = m_scene.GetSceneObjectPart(objectID); if (part == null) return false; - if (part.OwnerID != user) - { - if (part.GroupID == UUID.Zero) - return false; + SceneObjectGroup sog = part.ParentGroup; + if (sog == null) + return false; - if (!IsGroupMember(part.GroupID, user, 0)) - return false; - - if ((part.GroupMask & (uint)PermissionMask.Modify) == 0) - return false; - } - else - { - if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) + // check object mod right + uint perms = GetObjectPermissions(user, sog, true); + if((perms & (uint)PermissionMask.Modify) == 0) return false; - } TaskInventoryItem ti = part.Inventory.GetInventoryItem(notecard); - if (ti == null) return false; - + if (ti.OwnerID != user) { - if (ti.GroupID == UUID.Zero) + UUID tiGroupID = ti.GroupID; + if (tiGroupID == UUID.Zero) return false; - if (!IsGroupMember(ti.GroupID, user, 0)) + ulong powers = 0; + if(!GroupMemberPowers(tiGroupID, user, ref powers)) return false; + + if(tiGroupID == ti.OwnerID && (powers & (ulong)GroupPowers.ObjectManipulate) != 0) + { + if ((ti.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy)) == + ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy)) + return true; + } + if ((ti.GroupPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy)) == + ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy)) + return true; + return false; } // Require full perms - if ((ti.CurrentPermissions & - ((uint)PermissionMask.Modify | - (uint)PermissionMask.Copy)) != - ((uint)PermissionMask.Modify | - (uint)PermissionMask.Copy)) + if ((ti.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy)) != + ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy)) return false; } - return true; } - private bool CanInstantMessage(UUID user, UUID target, Scene startScene) + private bool CanInstantMessage(UUID user, UUID target) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; // If the sender is an object, check owner instead // - SceneObjectPart part = startScene.GetSceneObjectPart(user); + SceneObjectPart part = m_scene.GetSceneObjectPart(user); if (part != null) user = part.OwnerID; return GenericCommunicationPermission(user, target); } - private bool CanInventoryTransfer(UUID user, UUID target, Scene startScene) + private bool CanInventoryTransfer(UUID user, UUID target) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; @@ -1192,7 +1571,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions return GenericCommunicationPermission(user, target); } - private bool CanIssueEstateCommand(UUID user, Scene requestFromScene, bool ownerCommand) + private bool CanIssueEstateCommand(UUID user, bool ownerCommand) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; @@ -1200,174 +1579,161 @@ namespace OpenSim.Region.CoreModules.World.Permissions if (IsAdministrator(user)) return true; - if (m_scene.RegionInfo.EstateSettings.IsEstateOwner(user)) - return true; - if (ownerCommand) - return false; + return m_scene.RegionInfo.EstateSettings.IsEstateOwner(user); - return GenericEstatePermission(user); + return IsEstateManager(user); } - private bool CanMoveObject(UUID objectID, UUID moverID, Scene scene) + private bool CanMoveObject(SceneObjectGroup sog, ScenePresence sp) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); + + if(sog == null || sog.IsDeleted || sp == null || sp.IsDeleted) + return false; + if (m_bypassPermissions) { - SceneObjectPart part = scene.GetSceneObjectPart(objectID); - if (part.OwnerID != moverID) - { - if (!part.ParentGroup.IsDeleted) - { - if (part.ParentGroup.IsAttachment) - return false; - } - } + if (sog.OwnerID != sp.UUID && sog.IsAttachment) + return false; return m_bypassPermissionsValue; } - bool permission = GenericObjectPermission(moverID, objectID, true); - if (!permission) - { - if (!m_scene.Entities.ContainsKey(objectID)) - { - return false; - } + uint perms = GetObjectPermissions(sp, sog, true); + if((perms & (uint)PermissionMask.Move) == 0) + return false; + return true; + } - // The client - // may request to edit linked parts, and therefore, it needs - // to also check for SceneObjectPart + private bool CanObjectEntry(SceneObjectGroup sog, bool enteringRegion, Vector3 newPoint) + { + DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); - // If it's not an object, we cant edit it. - if ((!(m_scene.Entities[objectID] is SceneObjectGroup))) - { - return false; - } + float newX = newPoint.X; + float newY = newPoint.Y; + // allow outside region this is needed for crossings + if (newX < -1f || newX > (m_scene.RegionInfo.RegionSizeX + 1.0f) || + newY < -1f || newY > (m_scene.RegionInfo.RegionSizeY + 1.0f) ) + return true; - SceneObjectGroup task = (SceneObjectGroup)m_scene.Entities[objectID]; + if(sog == null || sog.IsDeleted) + return false; + if (m_bypassPermissions) + return m_bypassPermissionsValue; - // UUID taskOwner = null; - // Added this because at this point in time it wouldn't be wise for - // the administrator object permissions to take effect. - // UUID objectOwner = task.OwnerID; + ILandObject parcel = m_scene.LandChannel.GetLandObject(newX, newY); + if (parcel == null) + return false; - // Anyone can move - if ((task.RootPart.EveryoneMask & PERM_MOVE) != 0) - permission = true; + if ((parcel.LandData.Flags & ((int)ParcelFlags.AllowAPrimitiveEntry)) != 0) + return true; - // Locked - if ((task.RootPart.OwnerMask & PERM_LOCKED) == 0) - permission = false; - } - else + if (!enteringRegion) { - bool locked = false; - if (!m_scene.Entities.ContainsKey(objectID)) - { - return false; - } - - // If it's not an object, we cant edit it. - if ((!(m_scene.Entities[objectID] is SceneObjectGroup))) - { - return false; - } + Vector3 oldPoint = sog.AbsolutePosition; + ILandObject fromparcel = m_scene.LandChannel.GetLandObject(oldPoint.X, oldPoint.Y); + if (fromparcel != null && fromparcel.Equals(parcel)) // it already entered parcel ???? + return true; + } - SceneObjectGroup group = (SceneObjectGroup)m_scene.Entities[objectID]; + UUID userID = sog.OwnerID; + LandData landdata = parcel.LandData; - UUID objectOwner = group.OwnerID; - locked = ((group.RootPart.OwnerMask & PERM_LOCKED) == 0); + if (landdata.OwnerID == userID) + return true; - // This is an exception to the generic object permission. - // Administrators who lock their objects should not be able to move them, - // however generic object permission should return true. - // This keeps locked objects from being affected by random click + drag actions by accident - // and allows the administrator to grab or delete a locked object. + if (IsAdministrator(userID)) + return true; - // Administrators and estate managers are still able to click+grab locked objects not - // owned by them in the scene - // This is by design. + UUID landGroupID = landdata.GroupID; + if (landGroupID != UUID.Zero) + { + if ((parcel.LandData.Flags & ((int)ParcelFlags.AllowGroupObjectEntry)) != 0) + return IsGroupMember(landGroupID, userID, 0); - if (locked && (moverID == objectOwner)) - return false; + if (landdata.IsGroupOwned && IsGroupMember(landGroupID, userID, (ulong)GroupPowers.AllowRez)) + return true; } - return permission; + + //Otherwise, false! + return false; } - private bool CanObjectEntry(UUID objectID, bool enteringRegion, Vector3 newPoint, Scene scene) + private bool OnObjectEnterWithScripts(SceneObjectGroup sog, ILandObject parcel) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); - if (m_bypassPermissions) return m_bypassPermissionsValue; - if ((newPoint.X > 257f || newPoint.X < -1f || newPoint.Y > 257f || newPoint.Y < -1f)) - { - return true; - } + if(sog == null || sog.IsDeleted) + return false; - SceneObjectGroup task = (SceneObjectGroup)m_scene.Entities[objectID]; + if (m_bypassPermissions) + return m_bypassPermissionsValue; - ILandObject land = m_scene.LandChannel.GetLandObject(newPoint.X, newPoint.Y); + if (parcel == null) + return true; - if (!enteringRegion) - { - ILandObject fromland = m_scene.LandChannel.GetLandObject(task.AbsolutePosition.X, task.AbsolutePosition.Y); + int checkflags = ((int)ParcelFlags.AllowAPrimitiveEntry); + bool scripts = (sog.ScriptCount() > 0); + if(scripts) + checkflags |= ((int)ParcelFlags.AllowOtherScripts); - if (fromland == land) // Not entering - return true; - } + if ((parcel.LandData.Flags & checkflags) == checkflags) + return true; - if (land == null) - { - return false; - } + UUID userID = sog.OwnerID; + LandData landdata = parcel.LandData; - if ((land.LandData.Flags & ((int)ParcelFlags.AllowAPrimitiveEntry)) != 0) - { + if (landdata.OwnerID == userID) return true; - } - if (!m_scene.Entities.ContainsKey(objectID)) - { - return false; - } + if (IsAdministrator(userID)) + return true; - // If it's not an object, we cant edit it. - if (!(m_scene.Entities[objectID] is SceneObjectGroup)) + UUID landGroupID = landdata.GroupID; + if (landGroupID != UUID.Zero) { - return false; - } + checkflags = (int)ParcelFlags.AllowGroupObjectEntry; + if(scripts) + checkflags |= ((int)ParcelFlags.AllowGroupScripts); + if ((parcel.LandData.Flags & checkflags) == checkflags) + return IsGroupMember(landGroupID, userID, 0); - if (GenericParcelPermission(task.OwnerID, newPoint, 0)) - { - return true; + if (landdata.IsGroupOwned && IsGroupMember(landGroupID, userID, (ulong)GroupPowers.AllowRez)) + return true; } //Otherwise, false! return false; } - private bool CanReturnObjects(ILandObject land, UUID user, List objects, Scene scene) + private bool CanReturnObjects(ILandObject land, ScenePresence sp, List objects) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; - GroupPowers powers; - ILandObject l; + if(sp == null) + return true; // assuming that in this case rights are as owner - ScenePresence sp = scene.GetScenePresence(user); - if (sp == null) - return false; + UUID userID = sp.UUID; + bool isPrivUser = sp.IsGod || IsEstateManager(userID); IClientAPI client = sp.ControllingClient; + ulong powers = 0; + ILandObject l; + foreach (SceneObjectGroup g in new List(objects)) { - // Any user can return their own objects at any time - // - if (GenericObjectPermission(user, g.UUID, false)) + if(g.IsAttachment) + { + objects.Remove(g); + continue; + } + + if (isPrivUser || g.OwnerID == userID) continue; // This is a short cut for efficiency. If land is non-null, @@ -1381,39 +1747,40 @@ namespace OpenSim.Region.CoreModules.World.Permissions else { Vector3 pos = g.AbsolutePosition; - - l = scene.LandChannel.GetLandObject(pos.X, pos.Y); + l = m_scene.LandChannel.GetLandObject(pos.X, pos.Y); } // If it's not over any land, then we can't do a thing - if (l == null) + if (l == null || l.LandData == null) { objects.Remove(g); continue; } + LandData ldata = l.LandData; // If we own the land outright, then allow // - if (l.LandData.OwnerID == user) + if (ldata.OwnerID == userID) continue; // Group voodoo // - if (l.LandData.IsGroupOwned) + if (ldata.IsGroupOwned) { - powers = (GroupPowers)client.GetGroupPowers(l.LandData.GroupID); + UUID lGroupID = ldata.GroupID; // Not a group member, or no rights at all // - if (powers == (GroupPowers)0) + powers = client.GetGroupPowers(lGroupID); + if(powers == 0) { objects.Remove(g); continue; } - + // Group deeded object? // - if (g.OwnerID == l.LandData.GroupID && - (powers & GroupPowers.ReturnGroupOwned) == (GroupPowers)0) + if (g.OwnerID == lGroupID && + (powers & (ulong)GroupPowers.ReturnGroupOwned) == 0) { objects.Remove(g); continue; @@ -1421,14 +1788,14 @@ namespace OpenSim.Region.CoreModules.World.Permissions // Group set object? // - if (g.GroupID == l.LandData.GroupID && - (powers & GroupPowers.ReturnGroupSet) == (GroupPowers)0) + if (g.GroupID == lGroupID && + (powers & (ulong)GroupPowers.ReturnGroupSet) == 0) { objects.Remove(g); continue; } - if ((powers & GroupPowers.ReturnNonGroup) == (GroupPowers)0) + if ((powers & (ulong)GroupPowers.ReturnNonGroup) == 0) { objects.Remove(g); continue; @@ -1451,125 +1818,257 @@ namespace OpenSim.Region.CoreModules.World.Permissions return true; } - private bool CanRezObject(int objectCount, UUID owner, Vector3 objectPosition, Scene scene) + private bool CanRezObject(int objectCount, UUID userID, Vector3 objectPosition) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); - if (m_bypassPermissions) return m_bypassPermissionsValue; + if (m_bypassPermissions) + return m_bypassPermissionsValue; // m_log.DebugFormat("[PERMISSIONS MODULE]: Checking rez object at {0} in {1}", objectPosition, m_scene.Name); ILandObject parcel = m_scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y); - if (parcel == null) + if (parcel == null || parcel.LandData == null) return false; - if ((parcel.LandData.Flags & (uint)ParcelFlags.CreateObjects) != 0) - { + LandData landdata = parcel.LandData; + if ((userID == landdata.OwnerID)) return true; - } - else if ((owner == parcel.LandData.OwnerID) || IsAdministrator(owner)) - { + + if ((landdata.Flags & (uint)ParcelFlags.CreateObjects) != 0) return true; - } - else if (((parcel.LandData.Flags & (uint)ParcelFlags.CreateGroupObjects) != 0) - && (parcel.LandData.GroupID != UUID.Zero) && IsGroupMember(parcel.LandData.GroupID, owner, 0)) - { + + if(IsAdministrator(userID)) return true; - } - else if (parcel.LandData.GroupID != UUID.Zero && IsGroupMember(parcel.LandData.GroupID, owner, (ulong)GroupPowers.AllowRez)) + + if(landdata.GroupID != UUID.Zero) { - return true; + if ((landdata.Flags & (uint)ParcelFlags.CreateGroupObjects) != 0) + return IsGroupMember(landdata.GroupID, userID, 0); + + if (landdata.IsGroupOwned && IsGroupMember(landdata.GroupID, userID, (ulong)GroupPowers.AllowRez)) + return true; } - else - { + + return false; + } + + private bool CanRunConsoleCommand(UUID user) + { + DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); + if (m_bypassPermissions) return m_bypassPermissionsValue; + + + return IsAdministrator(user); + } + + private bool CanRunScript(TaskInventoryItem scriptitem, SceneObjectPart part) + { + DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); + if (m_bypassPermissions) return m_bypassPermissionsValue; + + if(scriptitem == null || part == null) return false; - } + + SceneObjectGroup sog = part.ParentGroup; + if(sog == null) + return false; + + Vector3 pos = sog.AbsolutePosition; + ILandObject parcel = m_scene.LandChannel.GetLandObject(pos.X, pos.Y); + if (parcel == null) + return false; + + LandData ldata = parcel.LandData; + if(ldata == null) + return false; + + uint lflags = ldata.Flags; + + if ((lflags & (uint)ParcelFlags.AllowOtherScripts) != 0) + return true; + + if ((part.OwnerID == ldata.OwnerID)) + return true; + + if (((lflags & (uint)ParcelFlags.AllowGroupScripts) != 0) + && (ldata.GroupID != UUID.Zero) && (ldata.GroupID == part.GroupID)) + return true; + + return GenericEstatePermission(part.OwnerID); + } + + private bool CanSellParcel(UUID user, ILandObject parcel) + { + DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); + if (m_bypassPermissions) return m_bypassPermissionsValue; + + return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandSetSale, true); } - private bool CanRunConsoleCommand(UUID user, Scene requestFromScene) - { - DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); - if (m_bypassPermissions) return m_bypassPermissionsValue; + private bool CanSellGroupObject(UUID userID, UUID groupID) + { + DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); + if (m_bypassPermissions) return m_bypassPermissionsValue; + + return IsGroupMember(groupID, userID, (ulong)GroupPowers.ObjectSetForSale); + } + + private bool CanSellObjectByUserID(SceneObjectGroup sog, UUID userID, byte saleType) + { + DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); + if (m_bypassPermissions) return m_bypassPermissionsValue; + + if (sog == null || sog.IsDeleted || userID == UUID.Zero) + return false; + + // sell is not a attachment op + if(sog.IsAttachment) + return false; + + if(IsAdministrator(userID)) + return true; + + uint sogEffectiveOwnerPerms = sog.EffectiveOwnerPerms; + if((sogEffectiveOwnerPerms & (uint)PermissionMask.Transfer) == 0) + return false; + + if(saleType == (byte)SaleType.Copy && + (sogEffectiveOwnerPerms & (uint)PermissionMask.Copy) == 0) + return false; + + UUID sogOwnerID = sog.OwnerID; + + if(sogOwnerID == userID) + return true; + + // else only group owned can be sold by members with powers + UUID sogGroupID = sog.GroupID; + if(sog.OwnerID != sogGroupID || sogGroupID == UUID.Zero) + return false; + + return IsGroupMember(sogGroupID, userID, (ulong)GroupPowers.ObjectSetForSale); + } + + private bool CanSellObject(SceneObjectGroup sog, ScenePresence sp, byte saleType) + { + DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); + if (m_bypassPermissions) return m_bypassPermissionsValue; + + if (sog == null || sog.IsDeleted || sp == null || sp.IsDeleted) + return false; + + // sell is not a attachment op + if(sog.IsAttachment) + return false; + + if(sp.IsGod) + return true; + + uint sogEffectiveOwnerPerms = sog.EffectiveOwnerPerms; + if((sogEffectiveOwnerPerms & (uint)PermissionMask.Transfer) == 0) + return false; + + if(saleType == (byte)SaleType.Copy && + (sogEffectiveOwnerPerms & (uint)PermissionMask.Copy) == 0) + return false; + + UUID userID = sp.UUID; + UUID sogOwnerID = sog.OwnerID; + if(sogOwnerID == userID) + return true; - return IsAdministrator(user); - } + // else only group owned can be sold by members with powers + UUID sogGroupID = sog.GroupID; + if(sog.OwnerID != sogGroupID || sogGroupID == UUID.Zero) + return false; - private bool CanRunScript(UUID script, UUID objectID, UUID user, Scene scene) - { - DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); - if (m_bypassPermissions) return m_bypassPermissionsValue; + ulong powers = 0; + if(!GroupMemberPowers(sogGroupID, sp, ref powers)) + return false; + + if((powers & (ulong)GroupPowers.ObjectSetForSale) == 0) + return false; return true; } - private bool CanSellParcel(UUID user, ILandObject parcel, Scene scene) + private bool CanTakeObject(SceneObjectGroup sog, ScenePresence sp) { + // ignore locked, viewers shell ask for confirmation DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; - return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandSetSale, false); - } + if (sog == null || sog.IsDeleted || sp == null || sp.IsDeleted) + return false; - private bool CanTakeObject(UUID objectID, UUID stealer, Scene scene) - { - DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); - if (m_bypassPermissions) return m_bypassPermissionsValue; + // take is not a attachment op + if(sog.IsAttachment) + return false; - return GenericObjectPermission(stealer,objectID, false); - } + UUID sogOwnerID = sog.OwnerID; + UUID spID = sp.UUID; - private bool CanTakeCopyObject(UUID objectID, UUID userID, Scene inScene) - { - DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); - if (m_bypassPermissions) return m_bypassPermissionsValue; + if(sogOwnerID == spID) + return true; - bool permission = GenericObjectPermission(userID, objectID, false); + if (sp.IsGod) + return true; - SceneObjectGroup so = (SceneObjectGroup)m_scene.Entities[objectID]; + if((sog.EffectiveOwnerPerms & (uint)PermissionMask.Transfer) == 0) + return false; + + if (IsFriendWithPerms(sog.UUID, sogOwnerID)) + return true; - if (!permission) + UUID sogGroupID = sog.GroupID; + if (sogGroupID != UUID.Zero) { - if (!m_scene.Entities.ContainsKey(objectID)) + ulong powers = 0; + if(GroupMemberPowers(sogGroupID, sp, ref powers)) { - return false; - } + if(sogGroupID == sogOwnerID) + { + if((powers & (ulong)GroupPowers.ObjectManipulate) != 0) + return true; + } + return (sog.EffectiveGroupPerms & (uint)PermissionMask.Modify) != 0; + } + } + return false; + } - // If it's not an object, we cant edit it. - if (!(m_scene.Entities[objectID] is SceneObjectGroup)) - { - return false; - } + private bool CanTakeCopyObject(SceneObjectGroup sog, ScenePresence sp) + { + DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); + if (m_bypassPermissions) return m_bypassPermissionsValue; - // UUID taskOwner = null; - // Added this because at this point in time it wouldn't be wise for - // the administrator object permissions to take effect. - // UUID objectOwner = task.OwnerID; + if (sog == null || sog.IsDeleted || sp == null || sp.IsDeleted) + return false; - if ((so.RootPart.EveryoneMask & PERM_COPY) != 0) - permission = true; - } + // refuse on attachments + if(sog.IsAttachment && !sp.IsGod) + return false; - if (so.OwnerID != userID) - { - if ((so.GetEffectivePermissions() & (PERM_COPY | PERM_TRANS)) != (PERM_COPY | PERM_TRANS)) - permission = false; - } - else + uint perms = GetObjectPermissions(sp, sog, true); + if((perms & (uint)PermissionMask.Copy) == 0) { - if ((so.GetEffectivePermissions() & PERM_COPY) != PERM_COPY) - permission = false; + sp.ControllingClient.SendAgentAlertMessage("Copying this item has been denied by the permissions system", false); + return false; } - - return permission; + + if(sog.OwnerID != sp.UUID && (perms & (uint)PermissionMask.Transfer) == 0) + return false; + return true; } - private bool CanTerraformLand(UUID user, Vector3 position, Scene requestFromScene) + private bool CanTerraformLand(UUID userID, Vector3 position) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; // Estate override - if (GenericEstatePermission(user)) + if (GenericEstatePermission(userID)) return true; float X = position.X; @@ -1587,13 +2086,19 @@ namespace OpenSim.Region.CoreModules.World.Permissions ILandObject parcel = m_scene.LandChannel.GetLandObject(X, Y); if (parcel == null) return false; - - // Others allowed to terraform? - if ((parcel.LandData.Flags & ((int)ParcelFlags.AllowTerraform)) != 0) + + LandData landdata = parcel.LandData; + if (landdata == null) + return false; + + if ((landdata.Flags & ((int)ParcelFlags.AllowTerraform)) != 0) return true; - // Land owner can terraform too - if (parcel != null && GenericParcelPermission(user, parcel, (ulong)GroupPowers.AllowEditLand)) + if(landdata.OwnerID == userID) + return true; + + if (landdata.IsGroupOwned && parcel.LandData.GroupID != UUID.Zero && + IsGroupMember(landdata.GroupID, userID, (ulong)GroupPowers.AllowEditLand)) return true; return false; @@ -1607,16 +2112,19 @@ namespace OpenSim.Region.CoreModules.World.Permissions /// /// /// - private bool CanViewScript(UUID script, UUID objectID, UUID user, Scene scene) + private bool CanViewScript(UUID script, UUID objectID, UUID userID) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; + // A god is a god is a god + if (IsAdministrator(userID)) + return true; + if (objectID == UUID.Zero) // User inventory { IInventoryService invService = m_scene.InventoryService; - InventoryItemBase assetRequestItem = new InventoryItemBase(script, user); - assetRequestItem = invService.GetItem(assetRequestItem); + InventoryItemBase assetRequestItem = invService.GetItem(userID, script); if (assetRequestItem == null && LibraryRootFolder != null) // Library item { assetRequestItem = LibraryRootFolder.FindItem(script); @@ -1636,60 +2144,53 @@ namespace OpenSim.Region.CoreModules.World.Permissions // readable only if it's really full perms // if ((assetRequestItem.CurrentPermissions & +/* ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) +*/ + (uint)(PermissionMask.Modify | PermissionMask.Copy)) != + (uint)(PermissionMask.Modify | PermissionMask.Copy)) return false; } else // Prim inventory { - SceneObjectPart part = scene.GetSceneObjectPart(objectID); - + SceneObjectPart part = m_scene.GetSceneObjectPart(objectID); if (part == null) return false; - - if (part.OwnerID != user) - { - if (part.GroupID == UUID.Zero) - return false; - if (!IsGroupMember(part.GroupID, user, 0)) - return false; - - if ((part.GroupMask & (uint)PermissionMask.Modify) == 0) - return false; - } - else - { - if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) - return false; - } + SceneObjectGroup sog = part.ParentGroup; + if (sog == null) + return false; + + uint perms = GetObjectPermissions(userID, sog, true); + if((perms & (uint)PermissionMask.Modify) == 0) + return false; TaskInventoryItem ti = part.Inventory.GetInventoryItem(script); - if (ti == null) +// if (ti == null || ti.InvType != (int)InventoryType.LSL) + if (ti == null) // legacy may not have type return false; - - if (ti.OwnerID != user) - { - if (ti.GroupID == UUID.Zero) - return false; - - if (!IsGroupMember(ti.GroupID, user, 0)) - return false; - } + + uint itperms = GetObjectItemPermissions(userID, ti); // Require full perms - if ((ti.CurrentPermissions & - ((uint)PermissionMask.Modify | + + if ((itperms & +/* + ((uint)(PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) +*/ + (uint)(PermissionMask.Modify | PermissionMask.Copy)) != + (uint)(PermissionMask.Modify | PermissionMask.Copy)) return false; } @@ -1704,16 +2205,19 @@ namespace OpenSim.Region.CoreModules.World.Permissions /// /// /// - private bool CanViewNotecard(UUID notecard, UUID objectID, UUID user, Scene scene) + private bool CanViewNotecard(UUID notecard, UUID objectID, UUID userID) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; + // A god is a god is a god + if (IsAdministrator(userID)) + return true; + if (objectID == UUID.Zero) // User inventory { IInventoryService invService = m_scene.InventoryService; - InventoryItemBase assetRequestItem = new InventoryItemBase(notecard, user); - assetRequestItem = invService.GetItem(assetRequestItem); + InventoryItemBase assetRequestItem = invService.GetItem(userID, notecard); if (assetRequestItem == null && LibraryRootFolder != null) // Library item { assetRequestItem = LibraryRootFolder.FindItem(notecard); @@ -1731,40 +2235,29 @@ namespace OpenSim.Region.CoreModules.World.Permissions } else // Prim inventory { - SceneObjectPart part = scene.GetSceneObjectPart(objectID); - + SceneObjectPart part = m_scene.GetSceneObjectPart(objectID); if (part == null) return false; - - if (part.OwnerID != user) - { - if (part.GroupID == UUID.Zero) - return false; - - if (!IsGroupMember(part.GroupID, user, 0)) - return false; - } - if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) + SceneObjectGroup sog = part.ParentGroup; + if (sog == null) + return false; + + uint perms = GetObjectPermissions(userID, sog, true); + if((perms & (uint)PermissionMask.Modify) == 0) return false; TaskInventoryItem ti = part.Inventory.GetInventoryItem(notecard); +// if (ti == null || ti.InvType != (int)InventoryType.Notecard) if (ti == null) return false; - if (ti.OwnerID != user) - { - if (ti.GroupID == UUID.Zero) - return false; - - if (!IsGroupMember(ti.GroupID, user, 0)) - return false; - } + uint itperms = GetObjectItemPermissions(userID, ti); // Notecards are always readable unless no copy // - if ((ti.CurrentPermissions & + if ((itperms & (uint)PermissionMask.Copy) != (uint)PermissionMask.Copy) return false; @@ -1780,7 +2273,14 @@ namespace OpenSim.Region.CoreModules.World.Permissions DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; - return GenericObjectPermission(userID, objectID, false); + SceneObjectGroup sog = m_scene.GetGroupByPrim(objectID); + if (sog == null) + return false; + + uint perms = GetObjectPermissions(userID, sog, true); + if((perms & (uint)PermissionMask.Modify) == 0) + return false; + return true; } private bool CanDelinkObject(UUID userID, UUID objectID) @@ -1788,10 +2288,17 @@ namespace OpenSim.Region.CoreModules.World.Permissions DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; - return GenericObjectPermission(userID, objectID, false); + SceneObjectGroup sog = m_scene.GetGroupByPrim(objectID); + if (sog == null) + return false; + + uint perms = GetObjectPermissions(userID, sog, true); + if((perms & (uint)PermissionMask.Modify) == 0) + return false; + return true; } - private bool CanBuyLand(UUID userID, ILandObject parcel, Scene scene) + private bool CanBuyLand(UUID userID, ILandObject parcel) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; @@ -1804,6 +2311,138 @@ namespace OpenSim.Region.CoreModules.World.Permissions DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; + SceneObjectPart part = m_scene.GetSceneObjectPart(objectID); + if (part == null) + return false; + + SceneObjectGroup sog = part.ParentGroup; + if (sog == null) + return false; + + if(sog.OwnerID == userID || IsAdministrator(userID)) + return true; + + if(sog.IsAttachment) + return false; + + UUID sogGroupID = sog.GroupID; + + if(sogGroupID == UUID.Zero || sogGroupID != sog.OwnerID) + return false; + + TaskInventoryItem ti = part.Inventory.GetInventoryItem(itemID); + if(ti == null) + return false; + + ulong powers = 0; + if(GroupMemberPowers(sogGroupID, userID, ref powers)) + { + if((powers & (ulong)GroupPowers.ObjectManipulate) != 0) + return true; + + if((ti.EveryonePermissions & (uint)PermissionMask.Copy) != 0) + return true; + } + return false; + } + + // object inventory to object inventory item drag and drop + private bool CanDoObjectInvToObjectInv(TaskInventoryItem item, SceneObjectPart sourcePart, SceneObjectPart destPart) + { + DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); + + if (sourcePart == null || destPart == null || item == null) + return false; + + if (m_bypassPermissions) + return m_bypassPermissionsValue; + + SceneObjectGroup srcsog = sourcePart.ParentGroup; + SceneObjectGroup destsog = destPart.ParentGroup; + if (srcsog == null || destsog == null) + return false; + + // dest is locked + if((destsog.EffectiveOwnerPerms & (uint)PermissionMask.Move) == 0) + return false; + + uint itperms = item.CurrentPermissions; + + // if item is no copy the source is modifed + if((itperms & (uint)PermissionMask.Copy) == 0 && (srcsog.EffectiveOwnerPerms & (uint)PermissionMask.Modify) == 0) + return false; + + UUID srcOwner = srcsog.OwnerID; + UUID destOwner = destsog.OwnerID; + bool notSameOwner = srcOwner != destOwner; + + if(notSameOwner) + { + if((itperms & (uint)PermissionMask.Transfer) == 0) + return false; + + // scripts can't be droped + if(item.InvType == (int)InventoryType.LSL) + return false; + + if((destsog.RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.AllowInventoryDrop) == 0) + return false; + } + else + { + if((destsog.RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.AllowInventoryDrop) == 0 && + (destsog.EffectiveOwnerPerms & (uint)PermissionMask.Modify) == 0) + return false; + } + + return true; + } + + private bool CanDropInObjectInv(InventoryItemBase item, ScenePresence sp, SceneObjectPart destPart) + { + DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); + + if (sp == null || sp.IsDeleted || destPart == null || item == null) + return false; + + SceneObjectGroup destsog = destPart.ParentGroup; + if (destsog == null || destsog.IsDeleted) + return false; + + if (m_bypassPermissions) + return m_bypassPermissionsValue; + + if(sp.IsGod) + return true; + + // dest is locked + if((destsog.EffectiveOwnerPerms & (uint)PermissionMask.Move) == 0) + return false; + + UUID destOwner = destsog.OwnerID; + UUID spID = sp.UUID; + bool spNotOwner = spID != destOwner; + + // scripts can't be droped + if(spNotOwner && item.InvType == (int)InventoryType.LSL) + return false; + + if(spNotOwner || item.Owner != destOwner) + { + // no copy item will be moved if it has transfer + uint itperms = item.CurrentPermissions; + if((itperms & (uint)PermissionMask.Transfer) == 0) + return false; + } + + // allowdrop is a root part thing and does bypass modify rights + if((destsog.RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.AllowInventoryDrop) != 0) + return true; + + uint perms = GetObjectPermissions(spID, destsog, true); + if((perms & (uint)PermissionMask.Modify) == 0) + return false; + return true; } @@ -1812,6 +2451,23 @@ namespace OpenSim.Region.CoreModules.World.Permissions DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; + SceneObjectPart part = m_scene.GetSceneObjectPart(objectID); + if (part == null) + return false; + + SceneObjectGroup sog = part.ParentGroup; + if (sog == null) + return false; + + uint perms = GetObjectPermissions(userID, sog, true); + if((perms & (uint)PermissionMask.Modify) == 0) + return false; + + TaskInventoryItem ti = part.Inventory.GetInventoryItem(itemID); + if(ti == null) + return false; + + //TODO item perm ? return true; } @@ -1828,31 +2484,28 @@ namespace OpenSim.Region.CoreModules.World.Permissions DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; - SceneObjectPart part = m_scene.GetSceneObjectPart(objectID); ScenePresence p = m_scene.GetScenePresence(userID); - if (part == null || p == null) + if (p == null) + return false; + + SceneObjectGroup sog = m_scene.GetGroupByPrim(objectID); + if (sog == null) + return false; + + uint perms = GetObjectPermissions(userID, sog, true); + if((perms & (uint)PermissionMask.Modify) == 0) return false; - if (!IsAdministrator(userID)) + if ((int)InventoryType.LSL == invType) { - if (part.OwnerID != userID) - { - // Group permissions - if ((part.GroupID == UUID.Zero) || (p.ControllingClient.GetGroupPowers(part.GroupID) == 0) || ((part.GroupMask & (uint)PermissionMask.Modify) == 0)) - return false; - } else { - if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) - return false; - } - if ((int)InventoryType.LSL == invType) - if (m_allowedScriptCreators == UserSet.Administrators) - return false; + if (m_allowedScriptCreators == UserSet.Administrators) + return false; } return true; } - + /// /// Check whether the specified user is allowed to create the given inventory type in their inventory. /// @@ -1867,10 +2520,10 @@ namespace OpenSim.Region.CoreModules.World.Permissions if ((int)InventoryType.LSL == invType) if (m_allowedScriptCreators == UserSet.Administrators && !IsAdministrator(userID)) return false; - + return true; } - + /// /// Check whether the specified user is allowed to copy the given inventory type in their inventory. /// @@ -1884,7 +2537,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions return true; } - + /// /// Check whether the specified user is allowed to edit the given inventory item within their own inventory. /// @@ -1898,7 +2551,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions return true; } - + /// /// Check whether the specified user is allowed to delete the given inventory item from their own inventory. /// @@ -1921,22 +2574,22 @@ namespace OpenSim.Region.CoreModules.World.Permissions return true; } - private bool CanResetScript(UUID prim, UUID script, UUID agentID, Scene scene) + private bool CanResetScript(UUID primID, UUID script, UUID agentID) { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; - SceneObjectPart part = m_scene.GetSceneObjectPart(prim); - - // If we selected a sub-prim to reset, prim won't represent the object, but only a part. - // We have to check the permissions of the object, though. - if (part.ParentID != 0) prim = part.ParentUUID; + SceneObjectGroup sog = m_scene.GetGroupByPrim(primID); + if (sog == null) + return false; - // You can reset the scripts in any object you can edit - return GenericObjectPermission(agentID, prim, false); + uint perms = GetObjectPermissions(agentID, sog, false); + if((perms & (uint)PermissionMask.Modify) == 0) // ?? + return false; + return true; } - private bool CanCompileScript(UUID ownerUUID, int scriptType, Scene scene) + private bool CanCompileScript(UUID ownerUUID, int scriptType) { //m_log.DebugFormat("check if {0} is allowed to compile {1}", ownerUUID, scriptType); switch (scriptType) { @@ -1970,64 +2623,71 @@ namespace OpenSim.Region.CoreModules.World.Permissions } return(false); } - + private bool CanControlPrimMedia(UUID agentID, UUID primID, int face) { // m_log.DebugFormat( // "[PERMISSONS]: Performing CanControlPrimMedia check with agentID {0}, primID {1}, face {2}", // agentID, primID, face); - + if (null == MoapModule) return false; - + SceneObjectPart part = m_scene.GetSceneObjectPart(primID); if (null == part) return false; - + MediaEntry me = MoapModule.GetMediaEntry(part, face); - + // If there is no existing media entry then it can be controlled (in this context, created). if (null == me) return true; - + // m_log.DebugFormat( -// "[PERMISSIONS]: Checking CanControlPrimMedia for {0} on {1} face {2} with control permissions {3}", +// "[PERMISSIONS]: Checking CanControlPrimMedia for {0} on {1} face {2} with control permissions {3}", // agentID, primID, face, me.ControlPermissions); - - return GenericObjectPermission(agentID, part.ParentGroup.UUID, true); + + SceneObjectGroup sog = part.ParentGroup; + if (sog == null) + return false; + + uint perms = GetObjectPermissions(agentID, sog, false); + if((perms & (uint)PermissionMask.Modify) == 0) + return false; + return true; } - + private bool CanInteractWithPrimMedia(UUID agentID, UUID primID, int face) { // m_log.DebugFormat( // "[PERMISSONS]: Performing CanInteractWithPrimMedia check with agentID {0}, primID {1}, face {2}", // agentID, primID, face); - + if (null == MoapModule) return false; - + SceneObjectPart part = m_scene.GetSceneObjectPart(primID); if (null == part) return false; - + MediaEntry me = MoapModule.GetMediaEntry(part, face); - + // If there is no existing media entry then it can be controlled (in this context, created). if (null == me) return true; - + // m_log.DebugFormat( -// "[PERMISSIONS]: Checking CanInteractWithPrimMedia for {0} on {1} face {2} with interact permissions {3}", +// "[PERMISSIONS]: Checking CanInteractWithPrimMedia for {0} on {1} face {2} with interact permissions {3}", // agentID, primID, face, me.InteractPermissions); - + return GenericPrimMediaPermission(part, agentID, me.InteractPermissions); } - + private bool GenericPrimMediaPermission(SceneObjectPart part, UUID agentID, MediaPermission perms) { // if (IsAdministrator(agentID)) // return true; - + if ((perms & MediaPermission.Anyone) == MediaPermission.Anyone) return true; @@ -2036,13 +2696,13 @@ namespace OpenSim.Region.CoreModules.World.Permissions if (agentID == part.OwnerID) return true; } - + if ((perms & MediaPermission.Group) == MediaPermission.Group) { if (IsGroupMember(part.GroupID, agentID, 0)) return true; } - + return false; } } diff --git a/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs b/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs index bb4dcce..49246a2 100644 --- a/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs +++ b/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs @@ -40,6 +40,7 @@ using OpenSim.Framework.Console; using OpenSim.Framework.Monitoring; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; namespace OpenSim.Region.CoreModules.World.Objects.Commands { @@ -53,24 +54,24 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands private ICommandConsole m_console; public string Name { get { return "Region Commands Module"; } } - + public Type ReplaceableInterface { get { return null; } } - + public void Initialise(IConfigSource source) { // m_log.DebugFormat("[REGION COMMANDS MODULE]: INITIALIZED MODULE"); } - + public void PostInitialise() { // m_log.DebugFormat("[REGION COMMANDS MODULE]: POST INITIALIZED MODULE"); } - + public void Close() { // m_log.DebugFormat("[REGION COMMANDS MODULE]: CLOSED MODULE"); } - + public void AddRegion(Scene scene) { // m_log.DebugFormat("[REGION COMMANDS MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName); @@ -86,14 +87,14 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands m_console.Commands.AddCommand( "Regions", false, "show region", "show region", - "Show control information for the currently selected region (host name, max physical prim size, etc).", + "Show control information for the currently selected region (host name, max physical prim size, etc).", "A synonym for \"region get\"", HandleShowRegion); m_console.Commands.AddCommand( "Regions", false, "region get", "region get", - "Show control information for the currently selected region (host name, max physical prim size, etc).", + "Show control information for the currently selected region (host name, max physical prim size, etc).", "Some parameters can be set with the \"region set\" command.\n" + "Others must be changed via a viewer (usually via the region/estate dialog box).", HandleShowRegion); @@ -107,6 +108,15 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands + "max-agent-limit - Maximum root agent limit. agent-limit cannot exceed this." + " This is not persisted over restart - to set it every time you must add a MaxAgents entry to your regions file.", HandleRegionSet); + + m_console.Commands.AddCommand("Regions", false, "show neighbours", + "show neighbours", + "Shows the local region neighbours", HandleShowNeighboursCommand); + + m_console.Commands.AddCommand("Regions", false, "show regionsinview", + "show regionsinview", + "Shows regions that can be seen from a region", HandleShowRegionsInViewCommand); + } public void RemoveRegion(Scene scene) @@ -194,7 +204,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands { MainConsole.Instance.OutputFormat("Usage: region set "); return; - } + } string param = args[2]; string rawValue = args[3]; @@ -215,7 +225,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands if (newValue > ri.AgentCapacity) { MainConsole.Instance.OutputFormat( - "Cannot set {0} to {1} in {2} as max-agent-limit is {3}", "agent-limit", + "Cannot set {0} to {1} in {2} as max-agent-limit is {3}", "agent-limit", newValue, m_scene.Name, ri.AgentCapacity); } else @@ -271,8 +281,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands float totalFrameTime = stats[8]; // float netFrameTime = stats.StatsBlock[9].StatValue; // Ignored - not used by OpenSimulator float physicsFrameTime = stats[10]; - float otherFrameTime = stats[11]; -// float imageFrameTime = stats.StatsBlock[12].StatValue; // Ignored + float otherFrameTime = stats[12]; +// float imageFrameTime = stats.StatsBlock[11].StatValue; // Ignored float inPacketsPerSecond = stats[13]; float outPacketsPerSecond = stats[14]; float unackedBytes = stats[15]; @@ -280,7 +290,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands float pendingDownloads = stats[17]; float pendingUploads = stats[18]; float activeScripts = stats[19]; - float scriptLinesPerSecond = stats[20]; + float scriptLinesPerSecond = stats[23]; StringBuilder sb = new StringBuilder(); sb.AppendFormat("Scene statistics for {0}\n", m_scene.RegionInfo.RegionName); @@ -309,5 +319,60 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands MainConsole.Instance.Output(sb.ToString()); } + + public void HandleShowNeighboursCommand(string module, string[] cmdparams) + { + if(m_scene == null) + return; + + if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene)) + return; + + System.Text.StringBuilder caps = new System.Text.StringBuilder(); + + RegionInfo sr = m_scene.RegionInfo; + caps.AppendFormat("*** Neighbours of {0} ({1}) ***\n", sr.RegionName, sr.RegionID); + List regions = m_scene.GridService.GetNeighbours(sr.ScopeID, sr.RegionID); + foreach (GridRegion r in regions) + caps.AppendFormat(" {0} @ {1}-{2}\n", r.RegionName, Util.WorldToRegionLoc((uint)r.RegionLocX), Util.WorldToRegionLoc((uint)r.RegionLocY)); + + MainConsole.Instance.Output(caps.ToString()); + } + + public void HandleShowRegionsInViewCommand(string module, string[] cmdparams) + { + if(m_scene == null) + return; + + if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene)) + return; + + System.Text.StringBuilder caps = new System.Text.StringBuilder(); + int maxview = (int)m_scene.MaxRegionViewDistance; + RegionInfo sr = m_scene.RegionInfo; + caps.AppendFormat("*** Regions that can be seen from {0} ({1}) (MaxRegionViewDistance {2}m) ***\n", sr.RegionName, sr.RegionID, maxview); + int startX = (int)sr.WorldLocX; + int endX = startX + (int)sr.RegionSizeX; + int startY = (int)sr.WorldLocY; + int endY = startY + (int)sr.RegionSizeY; + startX -= maxview; + if(startX < 0 ) + startX = 0; + startY -= maxview; + if(startY < 0) + startY = 0; + endX += maxview; + endY += maxview; + + List regions = m_scene.GridService.GetRegionRange(sr.ScopeID, startX, endX, startY, endY); + foreach (GridRegion r in regions) + { + if(r.RegionHandle == sr.RegionHandle) + continue; + caps.AppendFormat(" {0} @ {1}-{2}\n", r.RegionName, Util.WorldToRegionLoc((uint)r.RegionLocX), Util.WorldToRegionLoc((uint)r.RegionLocY)); + } + + MainConsole.Instance.Output(caps.ToString()); + } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/World/Region/RestartModule.cs b/OpenSim/Region/CoreModules/World/Region/RestartModule.cs index 75a8295..bb3b860 100644 --- a/OpenSim/Region/CoreModules/World/Region/RestartModule.cs +++ b/OpenSim/Region/CoreModules/World/Region/RestartModule.cs @@ -29,6 +29,8 @@ using System; using System.Linq; using System.Reflection; using System.Timers; +using System.IO; +using System.Diagnostics; using System.Threading; using System.Collections.Generic; using log4net; @@ -57,30 +59,46 @@ namespace OpenSim.Region.CoreModules.World.Region protected UUID m_Initiator; protected bool m_Notice = false; protected IDialogModule m_DialogModule = null; + protected string m_MarkerPath = String.Empty; + private int[] m_CurrentAlerts = null; + protected bool m_shortCircuitDelays = false; + protected bool m_rebootAll = false; public void Initialise(IConfigSource config) { + IConfig restartConfig = config.Configs["RestartModule"]; + if (restartConfig != null) + { + m_MarkerPath = restartConfig.GetString("MarkerPath", String.Empty); + } + IConfig startupConfig = config.Configs["Startup"]; + m_shortCircuitDelays = startupConfig.GetBoolean("SkipDelayOnEmptyRegion", false); + m_rebootAll = startupConfig.GetBoolean("InworldRestartShutsDown", false); } public void AddRegion(Scene scene) { + if (m_MarkerPath != String.Empty) + File.Delete(Path.Combine(m_MarkerPath, + scene.RegionInfo.RegionID.ToString())); + m_Scene = scene; - + scene.RegisterModuleInterface(this); MainConsole.Instance.Commands.AddCommand("Regions", false, "region restart bluebox", "region restart bluebox +", - "Schedule a region restart", + "Schedule a region restart", "Schedule a region restart after a given number of seconds. If one delta is given then the region is restarted in delta seconds time. A time to restart is sent to users in the region as a dismissable bluebox notice. If multiple deltas are given then a notice is sent when we reach each delta.", HandleRegionRestart); - + MainConsole.Instance.Commands.AddCommand("Regions", false, "region restart notice", "region restart notice +", - "Schedule a region restart", + "Schedule a region restart", "Schedule a region restart after a given number of seconds. If one delta is given then the region is restarted in delta seconds time. A time to restart is sent to users in the region as a transient notice. If multiple deltas are given then a notice is sent when we reach each delta.", HandleRegionRestart); - + MainConsole.Instance.Commands.AddCommand("Regions", false, "region restart abort", "region restart abort []", @@ -118,10 +136,14 @@ namespace OpenSim.Region.CoreModules.World.Region public void ScheduleRestart(UUID initiator, string message, int[] alerts, bool notice) { if (m_CountdownTimer != null) - return; + { + m_CountdownTimer.Stop(); + m_CountdownTimer = null; + } if (alerts == null) { + CreateMarkerFile(); m_Scene.RestartNow(); return; } @@ -129,25 +151,28 @@ namespace OpenSim.Region.CoreModules.World.Region m_Message = message; m_Initiator = initiator; m_Notice = notice; + m_CurrentAlerts = alerts; m_Alerts = new List(alerts); m_Alerts.Sort(); m_Alerts.Reverse(); if (m_Alerts[0] == 0) { + CreateMarkerFile(); m_Scene.RestartNow(); return; } - int nextInterval = DoOneNotice(); + int nextInterval = DoOneNotice(true); SetTimer(nextInterval); } - public int DoOneNotice() + public int DoOneNotice(bool sendOut) { if (m_Alerts.Count == 0 || m_Alerts[0] == 0) { + CreateMarkerFile(); m_Scene.RestartNow(); return 0; } @@ -163,39 +188,42 @@ namespace OpenSim.Region.CoreModules.World.Region nextAlert = m_Alerts[1]; break; } - + int currentAlert = m_Alerts[0]; m_Alerts.RemoveAt(0); - int minutes = currentAlert / 60; - string currentAlertString = String.Empty; - if (minutes > 0) + if (sendOut) { - if (minutes == 1) - currentAlertString += "1 minute"; - else - currentAlertString += String.Format("{0} minutes", minutes); + int minutes = currentAlert / 60; + string currentAlertString = String.Empty; + if (minutes > 0) + { + if (minutes == 1) + currentAlertString += "1 minute"; + else + currentAlertString += String.Format("{0} minutes", minutes); + if ((currentAlert % 60) != 0) + currentAlertString += " and "; + } if ((currentAlert % 60) != 0) - currentAlertString += " and "; - } - if ((currentAlert % 60) != 0) - { - int seconds = currentAlert % 60; - if (seconds == 1) - currentAlertString += "1 second"; - else - currentAlertString += String.Format("{0} seconds", seconds); - } + { + int seconds = currentAlert % 60; + if (seconds == 1) + currentAlertString += "1 second"; + else + currentAlertString += String.Format("{0} seconds", seconds); + } - string msg = String.Format(m_Message, currentAlertString); + string msg = String.Format(m_Message, currentAlertString); - if (m_DialogModule != null && msg != String.Empty) - { - if (m_Notice) - m_DialogModule.SendGeneralAlert(msg); - else - m_DialogModule.SendNotificationToUsersInRegion(m_Initiator, "System", msg); + if (m_DialogModule != null && msg != String.Empty) + { + if (m_Notice) + m_DialogModule.SendGeneralAlert(msg); + else + m_DialogModule.SendNotificationToUsersInRegion(m_Initiator, "System", msg); + } } return currentAlert - nextAlert; @@ -219,14 +247,42 @@ namespace OpenSim.Region.CoreModules.World.Region else { m_log.WarnFormat( - "[RESTART MODULE]: Tried to set restart timer to {0} in {1}, which is not a valid interval", + "[RESTART MODULE]: Tried to set restart timer to {0} in {1}, which is not a valid interval", intervalSeconds, m_Scene.Name); } } private void OnTimer(object source, ElapsedEventArgs e) { - SetTimer(DoOneNotice()); + int nextInterval = DoOneNotice(true); + if (m_shortCircuitDelays) + { + if (CountAgents() == 0) + { + m_Scene.RestartNow(); + return; + } + } + + SetTimer(nextInterval); + } + + public void DelayRestart(int seconds, string message) + { + if (m_CountdownTimer == null) + return; + + m_CountdownTimer.Stop(); + m_CountdownTimer = null; + + m_Alerts = new List(m_CurrentAlerts); + m_Alerts.Add(seconds); + m_Alerts.Sort(); + m_Alerts.Reverse(); + + int nextInterval = DoOneNotice(false); + + SetTimer(nextInterval); } public void AbortRestart(string message) @@ -236,10 +292,14 @@ namespace OpenSim.Region.CoreModules.World.Region m_CountdownTimer.Stop(); m_CountdownTimer = null; if (m_DialogModule != null && message != String.Empty) - m_DialogModule.SendGeneralAlert(message); + m_DialogModule.SendNotificationToUsersInRegion(UUID.Zero, "System", message); + //m_DialogModule.SendGeneralAlert(message); } + if (m_MarkerPath != String.Empty) + File.Delete(Path.Combine(m_MarkerPath, + m_Scene.RegionInfo.RegionID.ToString())); } - + private void HandleRegionRestart(string module, string[] args) { if (!(MainConsole.Instance.ConsoleScene is Scene)) @@ -282,5 +342,55 @@ namespace OpenSim.Region.CoreModules.World.Region ScheduleRestart(UUID.Zero, args[3], times.ToArray(), notice); } + + protected void CreateMarkerFile() + { + if (m_MarkerPath == String.Empty) + return; + + string path = Path.Combine(m_MarkerPath, m_Scene.RegionInfo.RegionID.ToString()); + try + { + string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); + FileStream fs = File.Create(path); + System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); + Byte[] buf = enc.GetBytes(pidstring); + fs.Write(buf, 0, buf.Length); + fs.Close(); + } + catch (Exception) + { + } + } + + int CountAgents() + { + m_log.Info("[RESTART MODULE]: Counting affected avatars"); + int agents = 0; + + if (m_rebootAll) + { + foreach (Scene s in SceneManager.Instance.Scenes) + { + foreach (ScenePresence sp in s.GetScenePresences()) + { + if (!sp.IsChildAgent && !sp.IsNPC) + agents++; + } + } + } + else + { + foreach (ScenePresence sp in m_Scene.GetScenePresences()) + { + if (!sp.IsChildAgent && !sp.IsNPC) + agents++; + } + } + + m_log.InfoFormat("[RESTART MODULE]: Avatars in region: {0}", agents); + + return agents; + } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs b/OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs index 65f464a..52a80d6 100644 --- a/OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs +++ b/OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs @@ -69,7 +69,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser MemoryStream stream = new MemoryStream(); XmlTextWriter formatter = new XmlTextWriter(stream, Encoding.UTF8); XmlDocument doc = new XmlDocument(); - + doc.XmlResolver=null; doc.LoadXml(xmlstream); formatter.Formatting = Formatting.Indented; doc.WriteContentTo(formatter); diff --git a/OpenSim/Region/CoreModules/World/Serialiser/SerialiserModule.cs b/OpenSim/Region/CoreModules/World/Serialiser/SerialiserModule.cs index e0247d9..c9bc335 100644 --- a/OpenSim/Region/CoreModules/World/Serialiser/SerialiserModule.cs +++ b/OpenSim/Region/CoreModules/World/Serialiser/SerialiserModule.cs @@ -45,7 +45,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SerialiserModule")] public class SerialiserModule : ISharedRegionModule, IRegionSerialiserModule { - private static readonly ILog m_log = + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // private Commander m_commander = new Commander("export"); @@ -55,15 +55,15 @@ namespace OpenSim.Region.CoreModules.World.Serialiser #region ISharedRegionModule Members - public Type ReplaceableInterface - { + public Type ReplaceableInterface + { get { return null; } } public void Initialise(IConfigSource source) { IConfig config = source.Configs["Serialiser"]; - if (config != null) + if (config != null) { m_savedir = config.GetString("save_dir", m_savedir); } @@ -150,7 +150,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser { SceneXmlLoader.SavePrimsToXml2(scene, stream, min, max); } - + public void SaveNamedPrimsToXml2(Scene scene, string primName, string fileName) { SceneXmlLoader.SaveNamedPrimsToXml2(scene, primName, fileName); diff --git a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs index a5bb1a7..23475a1 100644 --- a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs +++ b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs @@ -43,7 +43,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests [TestFixture] public class SerialiserTests : OpenSimTestCase { - private const string ObjectRootPartStubXml = + private const string ObjectRootPartStubXml = @" @@ -149,9 +149,9 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests MyNamespace - + MyStore - + the answer 42 @@ -162,12 +162,12 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests "; - private const string ObjectWithNoOtherPartsXml = ObjectRootPartStubXml + + private const string ObjectWithNoOtherPartsXml = ObjectRootPartStubXml + @" "; - private const string ObjectWithOtherPartsXml = ObjectRootPartStubXml + + private const string ObjectWithOtherPartsXml = ObjectRootPartStubXml + @" @@ -574,9 +574,9 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests MyNamespace - + MyStore - + last words Rosebud @@ -636,7 +636,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests Assert.That(part.Name, Is.EqualTo("PrimMyRide")); OSDMap store = part.DynAttrs.GetStore("MyNamespace", "MyStore"); Assert.AreEqual(42, store["the answer"].AsInteger()); - } + } { SceneObjectPart part = parts[1]; @@ -720,10 +720,12 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests string xml = SceneObjectSerializer.ToOriginalXmlFormat(so); XmlTextReader xtr = new XmlTextReader(new StringReader(xml)); + xtr.ProhibitDtd = true; + xtr.ReadStartElement("SceneObjectGroup"); xtr.ReadStartElement("RootPart"); xtr.ReadStartElement("SceneObjectPart"); - + UUID uuid = UUID.Zero; string name = null; UUID creatorId = UUID.Zero; @@ -733,7 +735,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests { if (xtr.NodeType != XmlNodeType.Element) continue; - + switch (xtr.Name) { case "UUID": @@ -831,9 +833,11 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests string xml2 = m_serialiserModule.SerializeGroupToXml2(so, options); XmlTextReader xtr = new XmlTextReader(new StringReader(xml2)); + xtr.ProhibitDtd = true; + xtr.ReadStartElement("SceneObjectGroup"); xtr.ReadStartElement("SceneObjectPart"); - + UUID uuid = UUID.Zero; string name = null; UUID creatorId = UUID.Zero; @@ -843,7 +847,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests { if (xtr.NodeType != XmlNodeType.Element) continue; - + switch (xtr.Name) { case "UUID": diff --git a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs index d093224..2b7db18 100644 --- a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs +++ b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs @@ -48,6 +48,18 @@ namespace OpenSim.Region.CoreModules.World.Sound private Scene m_scene; + public enum SoundFlags: byte + { + NONE = 0, + LOOP = 1 << 0, + SYNC_MASTER = 1<<1, + SYNC_SLAVE = 1<<2, + SYNC_PENDING = 1<<3, + QUEUE = 1<<4, + STOP = 1<<5, + SYNC_MASK = SYNC_MASTER | SYNC_SLAVE | SYNC_PENDING + } + public bool Enabled { get; private set; } public float MaxDistance { get; private set; } @@ -124,26 +136,30 @@ namespace OpenSim.Region.CoreModules.World.Sound if (radius == 0) radius = MaxDistance; - m_scene.ForEachRootScenePresence(delegate(ScenePresence sp) + if (part.SoundQueueing) + flags |= (byte)SoundFlags.QUEUE; + + if (grp.IsAttachment) { - double dis = Util.GetDistanceTo(sp.AbsolutePosition, position); - if (dis > MaxDistance) // Max audio distance + ScenePresence ssp = null; + if (!m_scene.TryGetScenePresence(grp.AttachedAvatar, out ssp)) return; - if (grp.IsAttachment) + if (grp.HasPrivateAttachmentPoint) { - if (grp.HasPrivateAttachmentPoint && sp.ControllingClient.AgentId != grp.OwnerID) - return; - - if (sp.ControllingClient.AgentId == grp.OwnerID) - dis = 0; + ssp.ControllingClient.SendPlayAttachedSound(soundID, objectID, + ownerID, (float)gain, flags); + return; } - // Scale by distance - double thisSpGain = gain * ((radius - dis) / radius); + if (!ssp.ParcelAllowThisAvatarSounds) + return; + } + m_scene.ForEachRootScenePresence(delegate(ScenePresence sp) + { sp.ControllingClient.SendPlayAttachedSound(soundID, objectID, - ownerID, (float)thisSpGain, flags); + ownerID, (float)gain, flags); }); } @@ -151,20 +167,35 @@ namespace OpenSim.Region.CoreModules.World.Sound UUID soundId, UUID ownerID, UUID objectID, UUID parentID, double gain, Vector3 position, UInt64 handle, float radius) { SceneObjectPart part; + ScenePresence ssp = null; if (!m_scene.TryGetSceneObjectPart(objectID, out part)) { - ScenePresence sp; - if (!m_scene.TryGetScenePresence(ownerID, out sp)) + if (!m_scene.TryGetScenePresence(ownerID, out ssp)) + return; + if (!ssp.ParcelAllowThisAvatarSounds) return; } else { SceneObjectGroup grp = part.ParentGroup; - if (grp.IsAttachment && grp.AttachmentPoint > 30) + if (grp.IsAttachment) { - objectID = ownerID; - parentID = ownerID; + if (!m_scene.TryGetScenePresence(grp.AttachedAvatar, out ssp)) + return; + + if (!ssp.ParcelAllowThisAvatarSounds) + return; + +/* mantis 7942: coment out to allow trigger in HUDs to send sounds to all + if (grp.HasPrivateAttachmentPoint) + { + ssp.ControllingClient.SendTriggeredSound(soundId, ownerID, + objectID, parentID, handle, position, + (float)gain); + return; + } +*/ } } @@ -174,16 +205,12 @@ namespace OpenSim.Region.CoreModules.World.Sound m_scene.ForEachRootScenePresence(delegate(ScenePresence sp) { double dis = Util.GetDistanceTo(sp.AbsolutePosition, position); - - if (dis > MaxDistance) // Max audio distance + if (dis > radius) // Max audio distance return; - // Scale by distance - double thisSpGain = gain * ((radius - dis) / radius); - sp.ControllingClient.SendTriggeredSound(soundId, ownerID, objectID, parentID, handle, position, - (float)thisSpGain); + (float)gain); }); } @@ -198,40 +225,13 @@ namespace OpenSim.Region.CoreModules.World.Sound private static void StopSound(SceneObjectPart m_host) { - m_host.AdjustSoundGain(0); - // Xantor 20080528: Clear prim data of sound instead - if (m_host.ParentGroup.LoopSoundSlavePrims.Contains(m_host)) - { - if (m_host.ParentGroup.LoopSoundMasterPrim == m_host) - { - foreach (SceneObjectPart part in m_host.ParentGroup.LoopSoundSlavePrims) - { - part.Sound = UUID.Zero; - part.SoundFlags = 1 << 5; - part.SoundRadius = 0; - part.ScheduleFullUpdate(); - part.SendFullUpdateToAllClients(); - } - m_host.ParentGroup.LoopSoundMasterPrim = null; - m_host.ParentGroup.LoopSoundSlavePrims.Clear(); - } - else - { - m_host.Sound = UUID.Zero; - m_host.SoundFlags = 1 << 5; - m_host.SoundRadius = 0; - m_host.ScheduleFullUpdate(); - m_host.SendFullUpdateToAllClients(); - } - } - else - { - m_host.Sound = UUID.Zero; - m_host.SoundFlags = 1 << 5; - m_host.SoundRadius = 0; - m_host.ScheduleFullUpdate(); - m_host.SendFullUpdateToAllClients(); - } +// m_host.AdjustSoundGain(0); + m_host.Sound = UUID.Zero; + m_host.SoundFlags = (byte)SoundFlags.STOP; + m_host.SoundRadius = 0; + m_host.SoundGain = 0; + m_host.ScheduleFullUpdate(); + m_host.SendFullUpdateToAllClients(); } public virtual void PreloadSound(UUID objectID, UUID soundID, float radius) @@ -248,7 +248,7 @@ namespace OpenSim.Region.CoreModules.World.Sound m_scene.ForEachRootScenePresence(delegate(ScenePresence sp) { - if (!(Util.GetDistanceTo(sp.AbsolutePosition, part.AbsolutePosition) >= MaxDistance)) + if (Util.GetDistanceTo(sp.AbsolutePosition, part.AbsolutePosition) < radius) sp.ControllingClient.SendPreLoadSound(objectID, objectID, soundID); }); } @@ -262,21 +262,24 @@ namespace OpenSim.Region.CoreModules.World.Sound // 20080530 Updated to remove code duplication // 20080530 Stop sound if there is one, otherwise volume only changes don't work public void LoopSound(UUID objectID, UUID soundID, - double volume, double radius, bool isMaster) + double volume, double radius, bool isMaster, bool isSlave) { SceneObjectPart m_host; if (!m_scene.TryGetSceneObjectPart(objectID, out m_host)) return; + byte iflags = 1; // looping if (isMaster) - m_host.ParentGroup.LoopSoundMasterPrim = m_host; - - if (m_host.Sound != UUID.Zero) - StopSound(m_host); + iflags |= (byte)SoundFlags.SYNC_MASTER; + // TODO check viewer seems to accept both + if (isSlave) + iflags |= (byte)SoundFlags.SYNC_SLAVE; + if (m_host.SoundQueueing) + iflags |= (byte)SoundFlags.QUEUE; m_host.Sound = soundID; m_host.SoundGain = volume; - m_host.SoundFlags = 1; // looping + m_host.SoundFlags = iflags; m_host.SoundRadius = radius; m_host.ScheduleFullUpdate(); @@ -301,41 +304,18 @@ namespace OpenSim.Region.CoreModules.World.Sound Vector3 position = part.AbsolutePosition; // region local ulong regionHandle = m_scene.RegionInfo.RegionHandle; - if (useMaster) - { - if (isMaster) - { - if (triggered) - TriggerSound(soundID, part.OwnerID, part.UUID, parentID, volume, position, regionHandle, radius); - else - PlayAttachedSound(soundID, part.OwnerID, part.UUID, volume, position, flags, radius); - part.ParentGroup.PlaySoundMasterPrim = part; - if (triggered) - TriggerSound(soundID, part.OwnerID, part.UUID, parentID, volume, position, regionHandle, radius); - else - PlayAttachedSound(soundID, part.OwnerID, part.UUID, volume, position, flags, radius); - foreach (SceneObjectPart prim in part.ParentGroup.PlaySoundSlavePrims) - { - position = prim.AbsolutePosition; // region local - if (triggered) - TriggerSound(soundID, part.OwnerID, prim.UUID, parentID, volume, position, regionHandle, radius); - else - PlayAttachedSound(soundID, part.OwnerID, prim.UUID, volume, position, flags, radius); - } - part.ParentGroup.PlaySoundSlavePrims.Clear(); - part.ParentGroup.PlaySoundMasterPrim = null; - } - else - { - part.ParentGroup.PlaySoundSlavePrims.Add(part); - } - } + if(triggered) + TriggerSound(soundID, part.OwnerID, part.UUID, parentID, volume, position, regionHandle, radius); else { - if (triggered) - TriggerSound(soundID, part.OwnerID, part.UUID, parentID, volume, position, regionHandle, radius); - else - PlayAttachedSound(soundID, part.OwnerID, part.UUID, volume, position, flags, radius); + byte bflags = 0; + + if (isMaster) + bflags |= (byte)SoundFlags.SYNC_MASTER; + // TODO check viewer seems to accept both + if (useMaster) + bflags |= (byte)SoundFlags.SYNC_SLAVE; + PlayAttachedSound(soundID, part.OwnerID, part.UUID, volume, position, bflags, radius); } } diff --git a/OpenSim/Region/CoreModules/World/Sun/SunModule.cs b/OpenSim/Region/CoreModules/World/Sun/SunModule.cs index d0318eb..e2b3487 100644 --- a/OpenSim/Region/CoreModules/World/Sun/SunModule.cs +++ b/OpenSim/Region/CoreModules/World/Sun/SunModule.cs @@ -77,7 +77,7 @@ namespace OpenSim.Region.CoreModules // Number of virtual days to a virtual year private int m_YearLengthDays = 0; - // Ratio of Daylight hours to Night time hours. This is accomplished by shifting the + // Ratio of Daylight hours to Night time hours. This is accomplished by shifting the // sun's orbit above the horizon private double m_HorizonShift = 0; @@ -162,7 +162,7 @@ namespace OpenSim.Region.CoreModules // Determine the current "day" from current time, so we can use "today" // to determine Seasonal Tilt and what'not - // Integer math rounded is on purpose to drop fractional day, determines number + // Integer math rounded is on purpose to drop fractional day, determines number // of virtual days since Epoch PosTime = CurrentTime / SecondsPerSunCycle; @@ -343,7 +343,7 @@ namespace OpenSim.Region.CoreModules m_log.Debug("[SUN]: Positional data updated every " + m_UpdateInterval + " frames"); } - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -417,7 +417,7 @@ namespace OpenSim.Region.CoreModules client.SendSunPos(Position, Velocity, CurrentTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition); } } - } + } public void SunUpdate() { @@ -464,7 +464,7 @@ namespace OpenSim.Region.CoreModules while (sunFixedHour < 0) sunFixedHour += 24; - + m_SunFixedHour = sunFixedHour; m_SunFixed = fixedSun; @@ -516,7 +516,7 @@ namespace OpenSim.Region.CoreModules case "current_time": return GetCurrentTimeAsLindenSunHour(); - + default: throw new Exception("Unknown sun parameter."); } diff --git a/OpenSim/Region/CoreModules/World/Terrain/Effects/ChannelDigger.cs b/OpenSim/Region/CoreModules/World/Terrain/Effects/ChannelDigger.cs index 36917e9..b456aa1 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/Effects/ChannelDigger.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/Effects/ChannelDigger.cs @@ -64,7 +64,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Effects for (int i = 0; i < rounds; i++) { - smoothFunction.FloodEffect(map, bitmap, 1.0); + smoothFunction.FloodEffect(map, bitmap, 1.0, 0, map.Width - 1, 0, map.Height - 1); } } @@ -99,7 +99,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Effects } } - raiseFunction.FloodEffect(map, bitmap, height); + raiseFunction.FloodEffect(map, bitmap, height, 0, map.Width - 1, 0, map.Height - 1); } } } diff --git a/OpenSim/Region/CoreModules/World/Terrain/Effects/CookieCutter.cs b/OpenSim/Region/CoreModules/World/Terrain/Effects/CookieCutter.cs index dc76ad5..3222524 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/Effects/CookieCutter.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/Effects/CookieCutter.cs @@ -84,7 +84,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Effects for (y = 0; y < map.Height; y++) { if (cliffMask[x, y]) - eroder.PaintEffect(map, allowMask, x, y, -1, 4, 0.1); + eroder.PaintEffect(map, allowMask, x, y, -1, 4, 0.1,0,map.Width - 1,0,map.Height - 1); } } diff --git a/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs b/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs index 89087b1..80396c4 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs @@ -53,4 +53,4 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Effects #endregion } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/BMP.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/BMP.cs index fb57c82..ec2d085 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/BMP.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/BMP.cs @@ -47,9 +47,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders /// The terrain channel being saved public override void SaveFile(string filename, ITerrainChannel map) { - Bitmap colours = CreateGrayscaleBitmapFromMap(map); - - colours.Save(filename, ImageFormat.Bmp); + using(Bitmap colours = CreateGrayscaleBitmapFromMap(map)) + colours.Save(filename,ImageFormat.Bmp); } /// @@ -59,9 +58,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders /// The terrain channel being saved public override void SaveStream(Stream stream, ITerrainChannel map) { - Bitmap colours = CreateGrayscaleBitmapFromMap(map); - - colours.Save(stream, ImageFormat.Png); + using(Bitmap colours = CreateGrayscaleBitmapFromMap(map)) + colours.Save(stream,ImageFormat.Bmp); } /// diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GIF.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GIF.cs index 79cc50b..3843708 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GIF.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GIF.cs @@ -36,9 +36,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders { public override void SaveFile(string filename, ITerrainChannel map) { - Bitmap colours = CreateGrayscaleBitmapFromMap(map); - - colours.Save(filename, ImageFormat.Gif); + using(Bitmap colours = CreateGrayscaleBitmapFromMap(map)) + colours.Save(filename,ImageFormat.Gif); } /// @@ -48,9 +47,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders /// The terrain channel being saved public override void SaveStream(Stream stream, ITerrainChannel map) { - Bitmap colours = CreateGrayscaleBitmapFromMap(map); - - colours.Save(stream, ImageFormat.Gif); + using(Bitmap colours = CreateGrayscaleBitmapFromMap(map)) + colours.Save(stream,ImageFormat.Gif); } public override string ToString() diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs index d5c77ec..bcd9dcd 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs @@ -59,7 +59,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders /// A terrain channel generated from the image. public virtual ITerrainChannel LoadFile(string filename) { - using (Bitmap b = new Bitmap(filename)) + using(Bitmap b = new Bitmap(filename)) return LoadBitmap(b); } @@ -111,9 +111,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders /// The terrain channel being saved public virtual void SaveFile(string filename, ITerrainChannel map) { - Bitmap colours = CreateGrayscaleBitmapFromMap(map); - - colours.Save(filename, ImageFormat.Png); + using(Bitmap colours = CreateGrayscaleBitmapFromMap(map)) + colours.Save(filename,ImageFormat.Png); } /// @@ -123,12 +122,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders /// The terrain channel being saved public virtual void SaveStream(Stream stream, ITerrainChannel map) { - Bitmap colours = CreateGrayscaleBitmapFromMap(map); - - colours.Save(stream, ImageFormat.Png); + using(Bitmap colours = CreateGrayscaleBitmapFromMap(map)) + colours.Save(stream,ImageFormat.Png); } - public virtual void SaveFile(ITerrainChannel m_channel, string filename, + public virtual void SaveFile(ITerrainChannel m_channel, string filename, int offsetX, int offsetY, int fileWidth, int fileHeight, int regionSizeX, int regionSizeY) @@ -162,13 +160,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders { newBitmap = new Bitmap(fileWidth * regionSizeX, fileHeight * regionSizeY); } - + thisBitmap = CreateGrayscaleBitmapFromMap(m_channel); - // Console.WriteLine("offsetX=" + offsetX + " offsetY=" + offsetY); + // Console.WriteLine("offsetX=" + offsetX + " offsetY=" + offsetY); for (int x = 0; x < regionSizeX; x++) for (int y = 0; y < regionSizeY; y++) newBitmap.SetPixel(x + offsetX * regionSizeX, y + (fileHeight - 1 - offsetY) * regionSizeY, thisBitmap.GetPixel(x, y)); - + Save(newBitmap, filename); } finally @@ -213,8 +211,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders /// A System.Drawing.Bitmap containing a grayscale image protected static Bitmap CreateGrayscaleBitmapFromMap(ITerrainChannel map) { + // Bitmap bmp = new Bitmap(map.Width, map.Height, PixelFormat.Format24bppRgb); Bitmap bmp = new Bitmap(map.Width, map.Height); + const int pallete = 256; Color[] grays = new Color[pallete]; @@ -227,59 +227,24 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders { for (int x = 0; x < map.Width; x++) { - // 512 is the largest possible height before colours clamp - int colorindex = (int) (Math.Max(Math.Min(1.0, map[x, y] / 128.0), 0.0) * (pallete - 1)); - - // Handle error conditions - if (colorindex > pallete - 1 || colorindex < 0) - bmp.SetPixel(x, map.Height - y - 1, Color.Red); - else - bmp.SetPixel(x, map.Height - y - 1, grays[colorindex]); - } - } - return bmp; - } - - /// - /// Protected method, generates a coloured bitmap - /// image from a specified terrain channel. - /// - /// The terrain channel to export to bitmap - /// A System.Drawing.Bitmap containing a coloured image - protected static Bitmap CreateBitmapFromMap(ITerrainChannel map) - { - int pallete; - Bitmap bmp; - Color[] colours; + // to change this, loading also needs change - using (Bitmap gradientmapLd = new Bitmap("defaultstripe.png")) - { - pallete = gradientmapLd.Height; - - bmp = new Bitmap(map.Width, map.Height); - colours = new Color[pallete]; - - for (int i = 0; i < pallete; i++) - { - colours[i] = gradientmapLd.GetPixel(0, i); - } - } + // int colorindex = (int)map[x, y]; // one to one conversion 0 - 255m range + // int colorindex = (int)map[x, y] / 2; // 0 - 510 range - for (int y = 0; y < map.Height; y++) - { - for (int x = 0; x < map.Width; x++) - { - // 512 is the largest possible height before colours clamp - int colorindex = (int) (Math.Max(Math.Min(1.0, map[x, y] / 512.0), 0.0) * (pallete - 1)); + int colorindex = (int)map[x, y] * 2; // the original 0 - 127.5 range - // Handle error conditions - if (colorindex > pallete - 1 || colorindex < 0) - bmp.SetPixel(x, map.Height - y - 1, Color.Red); - else - bmp.SetPixel(x, map.Height - y - 1, colours[colorindex]); + // clamp it not adding the red warning + if (colorindex < 0) + colorindex = 0; + else if (colorindex >= pallete) + colorindex = pallete - 1; + bmp.SetPixel(x, map.Height - y - 1, grays[colorindex]); } } return bmp; } } } + + diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/JPEG.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/JPEG.cs index 9cc767a..d604dc7 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/JPEG.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/JPEG.cs @@ -59,9 +59,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders public void SaveFile(string filename, ITerrainChannel map) { - Bitmap colours = CreateBitmapFromMap(map); - - colours.Save(filename, ImageFormat.Jpeg); + using(Bitmap colours = CreateBitmapFromMap(map)) + colours.Save(filename,ImageFormat.Jpeg); } /// @@ -71,9 +70,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders /// The terrain channel being saved public void SaveStream(Stream stream, ITerrainChannel map) { - Bitmap colours = CreateBitmapFromMap(map); - - colours.Save(stream, ImageFormat.Jpeg); + using(Bitmap colours = CreateBitmapFromMap(map)) + colours.Save(stream,ImageFormat.Jpeg); } public virtual void SaveFile(ITerrainChannel m_channel, string filename, @@ -106,10 +104,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders using (Bitmap gradientmapLd = new Bitmap("defaultstripe.png")) { pallete = gradientmapLd.Height; - + bmp = new Bitmap(map.Width, map.Height); colours = new Color[pallete]; - + for (int i = 0; i < pallete; i++) { colours[i] = gradientmapLd.GetPixel(0, i); diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs index be1fb24..68d6ed2 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs @@ -57,6 +57,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders public LLRAW() { + } + + private void BuildLookupHeightTable() + { LookupHeightTable = new HeightmapLookupValue[256 * 256]; for (int i = 0; i < 256; i++) @@ -186,6 +190,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders public void SaveStream(Stream s, ITerrainChannel map) { + if (LookupHeightTable == null) + BuildLookupHeightTable(); + using (BinaryWriter binStream = new BinaryWriter(s)) { // Output the calculated raw @@ -241,6 +248,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders } } } + LookupHeightTable = null; } public string FileExtension @@ -267,6 +275,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders public bool SupportsTileSave() { return false; - } + } } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/PNG.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/PNG.cs index c5c12ae..8ea8e9d 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/PNG.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/PNG.cs @@ -36,9 +36,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders { public override void SaveFile(string filename, ITerrainChannel map) { - Bitmap colours = CreateGrayscaleBitmapFromMap(map); - - colours.Save(filename, ImageFormat.Png); + using(Bitmap colours = CreateGrayscaleBitmapFromMap(map)) + colours.Save(filename,ImageFormat.Png); } /// @@ -48,9 +47,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders /// The terrain channel being saved public override void SaveStream(Stream stream, ITerrainChannel map) { - Bitmap colours = CreateGrayscaleBitmapFromMap(map); - - colours.Save(stream, ImageFormat.Png); + using(Bitmap colours = CreateGrayscaleBitmapFromMap(map)) + colours.Save(stream,ImageFormat.Png); } public override string ToString() diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/TIFF.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/TIFF.cs index b416b82..d103a6f 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/TIFF.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/TIFF.cs @@ -36,9 +36,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders { public override void SaveFile(string filename, ITerrainChannel map) { - Bitmap colours = CreateGrayscaleBitmapFromMap(map); - - colours.Save(filename, ImageFormat.Tiff); + using(Bitmap colours = CreateGrayscaleBitmapFromMap(map)) + colours.Save(filename,ImageFormat.Tiff); } /// @@ -48,9 +47,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders /// The terrain channel being saved public override void SaveStream(Stream stream, ITerrainChannel map) { - Bitmap colours = CreateGrayscaleBitmapFromMap(map); - - colours.Save(stream, ImageFormat.Tiff); + using(Bitmap colours = CreateGrayscaleBitmapFromMap(map)) + colours.Save(stream,ImageFormat.Tiff); } public override string ToString() diff --git a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/FlattenArea.cs b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/FlattenArea.cs index 774e7b2..0c4171e 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/FlattenArea.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/FlattenArea.cs @@ -33,15 +33,16 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes { #region ITerrainFloodEffect Members - public void FloodEffect(ITerrainChannel map, bool[,] fillArea, double strength) + public void FloodEffect(ITerrainChannel map, bool[,] fillArea, double strength, + int startX, int endX, int startY, int endY) { double sum = 0.0; double steps = 0.0; int x, y; - for (x = 0; x < map.Width; x++) + for (x = startX; x <= endX; x++) { - for (y = 0; y < map.Height; y++) + for (y = startY; y <= endY; y++) { if (fillArea[x, y]) { @@ -55,9 +56,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes double str = 0.1 * strength; // == 0.2 in the default client - for (x = 0; x < map.Width; x++) + for (x = startX; x <= endX; x++) { - for (y = 0; y < map.Height; y++) + for (y = startY; y <= endY; y++) { if (fillArea[x, y]) map[x, y] = (map[x, y] * (1.0 - str)) + (avg * str); diff --git a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/LowerArea.cs b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/LowerArea.cs index 3e87390..a275a86 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/LowerArea.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/LowerArea.cs @@ -33,13 +33,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes { #region ITerrainFloodEffect Members - public void FloodEffect(ITerrainChannel map, bool[,] fillArea, double strength) + public void FloodEffect(ITerrainChannel map, bool[,] fillArea, double strength, + int startX, int endX, int startY, int endY) { - int x; - for (x = 0; x < map.Width; x++) + int x,y; + for (x = startX; x <= endX; x++) { - int y; - for (y = 0; y < map.Height; y++) + for (y = startY; y <= endY; y++) { if (fillArea[x, y]) { diff --git a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs index b6c635c..d634e8b 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs @@ -35,18 +35,17 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes { #region ITerrainFloodEffect Members - public void FloodEffect(ITerrainChannel map, bool[,] fillArea, double strength) + public void FloodEffect(ITerrainChannel map, bool[,] fillArea, double strength, + int startX, int endX, int startY, int endY) { - int x; - for (x = 0; x < map.Width; x++) + int x, y; + for (x = startX; x <= endX; x++) { - int y; - for (y = 0; y < map.Height; y++) + for (y = startY; y <= endY; y++) { if (fillArea[x, y]) { double noise = TerrainUtil.PerlinNoise2D((double) x / map.Width, (double) y / map.Height, 8, 1.0); - map[x, y] += noise * strength; } } @@ -55,4 +54,4 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes #endregion } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/RaiseArea.cs b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/RaiseArea.cs index 3bdc5e7..6ccd5df 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/RaiseArea.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/RaiseArea.cs @@ -33,13 +33,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes { #region ITerrainFloodEffect Members - public void FloodEffect(ITerrainChannel map, bool[,] fillArea, double strength) + public void FloodEffect(ITerrainChannel map, bool[,] fillArea, double strength, + int startX, int endX, int startY, int endY) { - int x; - for (x = 0; x < map.Width; x++) + int x,y; + for (x = startX; x <= endX; x++) { - int y; - for (y = 0; y < map.Height; y++) + for (y = startY; y <= endY; y++) { if (fillArea[x, y]) { diff --git a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/RevertArea.cs b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/RevertArea.cs index c5527fa..4230133 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/RevertArea.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/RevertArea.cs @@ -46,13 +46,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes /// the current heightmap /// array indicating which sections of the map are to be reverted /// unused - public void FloodEffect(ITerrainChannel map, bool[,] fillArea, double strength) + public void FloodEffect(ITerrainChannel map, bool[,] fillArea, double strength, + int startX, int endX, int startY, int endY) { - int x; - for (x = 0; x < map.Width; x++) + int x, y; + for (x = startX; x <= endX; x++) { - int y; - for (y = 0; y < map.Height; y++) + for (y = startY; y <= endY; y++) { if (fillArea[x, y]) { diff --git a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/SmoothArea.cs b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/SmoothArea.cs index 6b07747..6c0d60d 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/SmoothArea.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/SmoothArea.cs @@ -33,16 +33,17 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes { #region ITerrainFloodEffect Members - public void FloodEffect(ITerrainChannel map, bool[,] fillArea, double strength) + public void FloodEffect(ITerrainChannel map, bool[,] fillArea, double strength, + int startX, int endX, int startY, int endY) { double area = strength; double step = strength / 4.0; double[,] manipulate = new double[map.Width,map.Height]; int x, y; - for (x = 0; x < map.Width; x++) + for (x = startX; x <= endX; x++) { - for (y = 0; y < map.Height; y++) + for (y = startY; y <= endY; y++) { if (!fillArea[x, y]) continue; @@ -64,9 +65,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes manipulate[x, y] = average / avgsteps; } } - for (x = 0; x < map.Width; x++) + for (x = startX; x <= endX; x++) { - for (y = 0; y < map.Height; y++) + for (y = startY; y <= endY; y++) { if (!fillArea[x, y]) continue; diff --git a/OpenSim/Region/CoreModules/World/Terrain/ITerrainFloodEffect.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainFloodEffect.cs index 3984a30..f7be25f 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/ITerrainFloodEffect.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainFloodEffect.cs @@ -32,6 +32,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain { public interface ITerrainFloodEffect { - void FloodEffect(ITerrainChannel map, Boolean[,] fillArea, double strength); + void FloodEffect(ITerrainChannel map, Boolean[,] fillArea, double strength, + int startX, int endX, int startY, int endY); } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/World/Terrain/ITerrainLoader.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainLoader.cs index 3ba3657..855d131 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/ITerrainLoader.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainLoader.cs @@ -33,7 +33,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain public interface ITerrainLoader { // Returns true if that extension can be used for terrain save-tile - // (Look into each file in Region.CoreModules.World.Terrain.FileLoaders) + // (Look into each file in Region.CoreModules.World.Terrain.FileLoaders) bool SupportsTileSave(); string FileExtension { get; } diff --git a/OpenSim/Region/CoreModules/World/Terrain/ITerrainPaintableEffect.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainPaintableEffect.cs index b73defd..d0b05e4 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/ITerrainPaintableEffect.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainPaintableEffect.cs @@ -31,6 +31,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain { public interface ITerrainPaintableEffect { - void PaintEffect(ITerrainChannel map, bool[,] allowMask, double x, double y, double z, double strength, double duration); + void PaintEffect(ITerrainChannel map, bool[,] allowMask, double x, double y, double z, + double strength, double duration, int startX, int endX, int startY, int endY); } } diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/ErodeSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/ErodeSphere.cs index 7a78cd8..7358ba3 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/ErodeSphere.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/ErodeSphere.cs @@ -151,7 +151,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes #region ITerrainPaintableEffect Members - public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, double strength, double duration) + public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, + double strength, double duration, int startX, int endX, int startY, int endY) { strength = TerrainUtil.MetersToSphericalStrength(strength); @@ -163,18 +164,23 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes ITerrainChannel sediment = new TerrainChannel(map.Width, map.Height); // Fill with rain - for (x = 0; x < water.Width; x++) - for (y = 0; y < water.Height; y++) - water[x, y] = Math.Max(0.0, TerrainUtil.SphericalFactor(x, y, rx, ry, strength) * rainHeight * duration); + for (x = startX; x <= endX; x++) + { + for (y = startY; y <= endY; y++) + { + if (mask[x, y]) + water[x, y] = Math.Max(0.0, TerrainUtil.SphericalFactor(x, y, rx, ry, strength) * rainHeight * duration); + } + } for (int i = 0; i < rounds; i++) { // Erode underlying terrain - for (x = 0; x < water.Width; x++) + for (x = startX; x <= endX; x++) { - for (y = 0; y < water.Height; y++) + for (y = startY; y <= endY; y++) { - if (mask[x,y]) + if (mask[x, y]) { const double solConst = (1.0 / rounds); double sedDelta = water[x, y] * solConst; @@ -185,9 +191,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes } // Move water - for (x = 0; x < water.Width; x++) + for (x = startX; x <= endX; x++) { - for (y = 0; y < water.Height; y++) + for (y = startY; y <= endY; y++) { if (water[x, y] <= 0) continue; @@ -296,7 +302,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes double sedimentDeposit = sediment[x, y] - waterCapacity; if (sedimentDeposit > 0) { - if (mask[x,y]) + if (mask[x, y]) { sediment[x, y] -= sedimentDeposit; map[x, y] += sedimentDeposit; @@ -309,10 +315,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes // Deposit any remainder (should be minimal) for (x = 0; x < water.Width; x++) for (y = 0; y < water.Height; y++) - if (mask[x,y] && sediment[x, y] > 0) + if (mask[x, y] && sediment[x, y] > 0) map[x, y] += sediment[x, y]; } - #endregion } } diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/FlattenSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/FlattenSphere.cs index 9aa3dff..9d3d4cb 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/FlattenSphere.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/FlattenSphere.cs @@ -35,16 +35,17 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes { #region ITerrainPaintableEffect Members - public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, double strength, double duration) + public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, + double strength, double duration, int startX, int endX, int startY, int endY) { strength = TerrainUtil.MetersToSphericalStrength(strength); int x, y; // blend in map - for (x = 0; x < map.Width; x++) + for (x = startX; x <= endX; x++) { - for (y = 0; y < map.Height; y++) + for (y = startY; y <= endY; y++) { if (!mask[x,y]) continue; @@ -76,7 +77,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes { map[x, y] += delta; } - + } } } diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/LowerSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/LowerSphere.cs index 68145f2..a88a022 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/LowerSphere.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/LowerSphere.cs @@ -34,34 +34,18 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes { #region ITerrainPaintableEffect Members - public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, double strength, double duration) + public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, + double strength, double duration, int startX, int endX, int startY, int endY) { int s = (int) (Math.Pow(2, strength) + 0.5); - int x; - int xFrom = (int)(rx-s+0.5); - int xTo = (int)(rx+s+0.5) + 1; - int yFrom = (int)(ry-s+0.5); - int yTo = (int)(ry+s+0.5) + 1; + int x, y; - if (xFrom < 0) - xFrom = 0; - - if (yFrom < 0) - yFrom = 0; - - if (xTo > map.Width) - xTo = map.Width; - - if (yTo > map.Width) - yTo = map.Width; - - for (x = xFrom; x < xTo; x++) + for (x = startX; x <= endX; x++) { - int y; - for (y = yFrom; y < yTo; y++) + for (y = startY; y <= endY; y++) { - if (!mask[x,y]) + if (!mask[x, y]) continue; // Calculate a cos-sphere and add it to the heighmap @@ -74,7 +58,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes map[x, y] = 0.0; else map[x, y] = newz; - } + } } } diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs index e7df3f8..46d47b4 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs @@ -35,17 +35,18 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes { #region ITerrainPaintableEffect Members - public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, double strength, double duration) + public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, + double strength, double duration, int startX, int endX, int startY, int endY) { strength = TerrainUtil.MetersToSphericalStrength(strength); - int x; - for (x = 0; x < map.Width; x++) + int x, y; + + for (x = startX; x <= endX; x++) { - int y; - for (y = 0; y < map.Height; y++) + for (y = startY; y <= endY; y++) { - if (!mask[x,y]) + if (!mask[x, y]) continue; // Calculate a sphere and add it to the heighmap diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/OlsenSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/OlsenSphere.cs index b199df3..281690d 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/OlsenSphere.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/OlsenSphere.cs @@ -152,18 +152,18 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes #region ITerrainPaintableEffect Members - public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, double strength, double duration) + public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, + double strength, double duration, int startX, int endX, int startY, int endY) { strength = TerrainUtil.MetersToSphericalStrength(strength); - int x; + int x, y; - for (x = 0; x < map.Width; x++) + for (x = startX; x <= endX; x++) { - int y; - for (y = 0; y < map.Height; y++) + for (y = startY; y <= endY; y++) { - if (!mask[x,y]) + if (!mask[x, y]) continue; double z = TerrainUtil.SphericalFactor(x, y, rx, ry, strength); diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/RaiseSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/RaiseSphere.cs index bd9a8a0..5305cb4 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/RaiseSphere.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/RaiseSphere.cs @@ -33,40 +33,24 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes public class RaiseSphere : ITerrainPaintableEffect { #region ITerrainPaintableEffect Members - - public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, double strength, double duration) + + public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, + double strength, double duration, int startX, int endX, int startY, int endY) { int s = (int) (Math.Pow(2, strength) + 0.5); - int x; - int xFrom = (int)(rx-s+0.5); - int xTo = (int)(rx+s+0.5) + 1; - int yFrom = (int)(ry-s+0.5); - int yTo = (int)(ry+s+0.5) + 1; - - if (xFrom < 0) - xFrom = 0; - - if (yFrom < 0) - yFrom = 0; - - if (xTo > map.Width) - xTo = map.Width; - - if (yTo > map.Width) - yTo = map.Width; + int x,y; - for (x = xFrom; x < xTo; x++) + for (x = startX; x <= endX; x++) { - int y; - for (y = yFrom; y < yTo; y++) + for (y = startY; y <= endY; y++) { - if (!mask[x,y]) + if (!mask[x, y]) continue; // Calculate a cos-sphere and add it to the heighmap - double r = Math.Sqrt((x-rx) * (x-rx) + ((y-ry) * (y-ry))); + double r = Math.Sqrt((x - rx) * (x - rx) + ((y - ry) * (y - ry))); double z = Math.Cos(r * Math.PI / (s * 2)); if (z > 0.0) map[x, y] += z * duration; diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/RevertSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/RevertSphere.cs index 4b28275..ca30e9e 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/RevertSphere.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/RevertSphere.cs @@ -41,23 +41,23 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes #region ITerrainPaintableEffect Members - public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, double strength, double duration) + public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, + double strength, double duration, int startX, int endX, int startY, int endY) { strength = TerrainUtil.MetersToSphericalStrength(strength); duration = 0.03; //MCP Should be read from ini file - + if (duration > 1.0) duration = 1.0; if (duration < 0) return; - int x; - for (x = 0; x < map.Width; x++) + int x,y; + for (x = startX; x <= endX; x++) { - int y; - for (y = 0; y < map.Height; y++) + for (y = startY; y <= endY; y++) { - if (!mask[x,y]) + if (!mask[x, y]) continue; // Calculate a sphere and add it to the heighmap diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/SmoothSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/SmoothSphere.cs index 4834c86..0342962 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/SmoothSphere.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/SmoothSphere.cs @@ -34,23 +34,27 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes { #region ITerrainPaintableEffect Members - public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, double strength, double duration) + public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, + double strength, double duration, int startX, int endX, int startY, int endY) { strength = TerrainUtil.MetersToSphericalStrength(strength); int x, y; double[,] tweak = new double[map.Width,map.Height]; - double area = strength; + double area = strength; double step = strength / 4.0; duration = 0.03; //MCP Should be read from ini file - + // compute delta map - for (x = 0; x < map.Width; x++) + for (x = startX; x <= endX; x++) { - for (y = 0; y < map.Height; y++) + for (y = startY; y <= endY; y++) { + if (!mask[x, y]) + continue; + double z = TerrainUtil.SphericalFactor(x, y, rx, ry, strength); if (z > 0) // add in non-zero amount @@ -73,11 +77,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes } } // blend in map - for (x = 0; x < map.Width; x++) + for (x = startX; x <= endX; x++) { - for (y = 0; y < map.Height; y++) + for (y = startY; y <= endY; y++) { - if (!mask[x,y]) + if (!mask[x, y]) continue; double z = TerrainUtil.SphericalFactor(x, y, rx, ry, strength); diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/WeatherSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/WeatherSphere.cs index f31c8b6..f52fe07 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/WeatherSphere.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/WeatherSphere.cs @@ -148,16 +148,16 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes #region ITerrainPaintableEffect Members - public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, double strength, double duration) + public void PaintEffect(ITerrainChannel map, bool[,] mask, double rx, double ry, double rz, + double strength, double duration, int startX, int endX, int startY, int endY) { strength = TerrainUtil.MetersToSphericalStrength(strength); - int x; + int x,y; - for (x = 0; x < map.Width; x++) + for (x = startX; x <= endX; x++) { - int y; - for (y = 0; y < map.Height; y++) + for (y = startY; y <= endY; y++) { if (!mask[x,y]) continue; diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs index 7ebd08e..c6e992f 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs @@ -370,9 +370,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain } return mask; } - - } - } diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index 932652c..65d4c4a 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs @@ -29,6 +29,7 @@ using System.Collections.Generic; using System.IO; using System.Reflection; using System.Net; +using System.Threading; using log4net; using Nini.Config; @@ -36,7 +37,6 @@ using Nini.Config; using OpenMetaverse; using Mono.Addins; -using OpenSim.Data; using OpenSim.Framework; using OpenSim.Framework.Console; using OpenSim.Region.CoreModules.Framework.InterfaceCommander; @@ -86,14 +86,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain private readonly Dictionary m_loaders = new Dictionary(); private readonly Dictionary m_painteffects = new Dictionary(); - private Dictionary m_plugineffects; private Dictionary m_modifyOperations = - new Dictionary(); + new Dictionary(); + private Dictionary m_plugineffects; private ITerrainChannel m_channel; - private ITerrainChannel m_revert; + private ITerrainChannel m_baked; private Scene m_scene; private volatile bool m_tainted; - private readonly Stack m_undo = new Stack(5); + private String m_InitialTerrain = "pinhead-island"; // If true, send terrain patch updates to clients based on their view distance @@ -107,13 +107,16 @@ namespace OpenSim.Region.CoreModules.World.Terrain private bool[,] updated; // for each patch, whether it needs to be sent to this client private int updateCount; // number of patches that need to be sent public ScenePresence Presence; // a reference to the client to send to - public TerrainData Terrain; // reference to the underlying terrain + public bool sendAll; + public int sendAllcurrentX; + public int sendAllcurrentY; + + public PatchUpdates(TerrainData terrData, ScenePresence pPresence) { updated = new bool[terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize]; updateCount = 0; Presence = pPresence; - Terrain = terrData; // Initially, send all patches to the client SetAll(true); } @@ -146,12 +149,16 @@ namespace OpenSim.Region.CoreModules.World.Terrain public void SetAll(bool state) { updateCount = 0; - for(int xx = 0; xx < updated.GetLength(0); xx++) - for(int yy = 0; yy < updated.GetLength(1); yy++) + for (int xx = 0; xx < updated.GetLength(0); xx++) + for (int yy = 0; yy < updated.GetLength(1); yy++) updated[xx, yy] = state; if (state) updateCount = updated.GetLength(0) * updated.GetLength(1); + sendAllcurrentX = 0; + sendAllcurrentY = 0; + sendAll = true; } + // Logically OR's the terrain data's patch taint map into this client's update map. public void SetAll(TerrainData terrData) { @@ -164,9 +171,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize) ); } - for(int xx = 0; xx < terrData.SizeX; xx += Constants.TerrainPatchSize) + + for (int xx = 0; xx < terrData.SizeX; xx += Constants.TerrainPatchSize) { - for(int yy = 0; yy < terrData.SizeY; yy += Constants.TerrainPatchSize) + for (int yy = 0; yy < terrData.SizeY; yy += Constants.TerrainPatchSize) { // Only set tainted. The patch bit may be set if the patch was to be sent later. if (terrData.IsTaintedAt(xx, yy, false)) @@ -210,7 +218,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain if (terrainConfig != null) { m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); - m_sendTerrainUpdatesByViewDistance = terrainConfig.GetBoolean("SendTerrainUpdatesByViewDistance", m_sendTerrainUpdatesByViewDistance); + m_sendTerrainUpdatesByViewDistance = + terrainConfig.GetBoolean( + "SendTerrainUpdatesByViewDistance",m_sendTerrainUpdatesByViewDistance); } } @@ -221,26 +231,34 @@ namespace OpenSim.Region.CoreModules.World.Terrain // Install terrain module in the simulator lock(m_scene) { + if(m_scene.Bakedmap != null) + { + m_baked = m_scene.Bakedmap; + } if (m_scene.Heightmap == null) { - m_channel = new TerrainChannel(m_InitialTerrain, (int)m_scene.RegionInfo.RegionSizeX, - (int)m_scene.RegionInfo.RegionSizeY, - (int)m_scene.RegionInfo.RegionSizeZ); + if(m_baked != null) + m_channel = m_baked.MakeCopy(); + else + m_channel = new TerrainChannel(m_InitialTerrain, + (int)m_scene.RegionInfo.RegionSizeX, + (int)m_scene.RegionInfo.RegionSizeY, + (int)m_scene.RegionInfo.RegionSizeZ); m_scene.Heightmap = m_channel; - UpdateRevertMap(); } else { m_channel = m_scene.Heightmap; - UpdateRevertMap(); } + if(m_baked == null) + UpdateBakedMap(); m_scene.RegisterModuleInterface(this); m_scene.EventManager.OnNewClient += EventManager_OnNewClient; m_scene.EventManager.OnClientClosed += EventManager_OnClientClosed; m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; m_scene.EventManager.OnTerrainTick += EventManager_OnTerrainTick; - m_scene.EventManager.OnFrame += EventManager_OnFrame; + m_scene.EventManager.OnTerrainCheckUpdates += EventManager_TerrainCheckUpdates; } InstallDefaultEffects(); @@ -279,7 +297,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain // remove the commands m_scene.UnregisterModuleCommander(m_commander.Name); // remove the event-handlers - m_scene.EventManager.OnFrame -= EventManager_OnFrame; + + m_scene.EventManager.OnTerrainCheckUpdates -= EventManager_TerrainCheckUpdates; m_scene.EventManager.OnTerrainTick -= EventManager_OnTerrainTick; m_scene.EventManager.OnPluginConsole -= EventManager_OnPluginConsole; m_scene.EventManager.OnClientClosed -= EventManager_OnClientClosed; @@ -334,7 +353,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_log.DebugFormat("[TERRAIN]: Loaded terrain, wd/ht: {0}/{1}", channel.Width, channel.Height); m_scene.Heightmap = channel; m_channel = channel; - UpdateRevertMap(); + UpdateBakedMap(); } catch(NotImplementedException) { @@ -426,7 +445,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain { ITerrainChannel channel = loader.Value.LoadStream(stream); m_channel.Merge(channel, displacement, radianRotation, rotationDisplacement); - UpdateRevertMap(); + UpdateBakedMap(); } catch(NotImplementedException) { @@ -444,6 +463,37 @@ namespace OpenSim.Region.CoreModules.World.Terrain throw new TerrainException(String.Format("unable to load heightmap from file {0}: no loader available for that format", filename)); } + public void LoadFromStream(string filename, Vector3 displacement, + float rotationDegrees, Vector2 boundingOrigin, Vector2 boundingSize, Stream stream) + { + foreach (KeyValuePair loader in m_loaders) + { + if (filename.EndsWith(loader.Key)) + { + lock (m_scene) + { + try + { + ITerrainChannel channel = loader.Value.LoadStream(stream); + m_channel.MergeWithBounding(channel, displacement, rotationDegrees, boundingOrigin, boundingSize); + UpdateBakedMap(); + } + catch (NotImplementedException) + { + m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value + + " parser does not support file loading. (May be save only)"); + throw new TerrainException(String.Format("unable to load heightmap: parser {0} does not support loading", loader.Value)); + } + } + + m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully"); + return; + } + } + m_log.Error("[TERRAIN]: Unable to load heightmap, no file loader available for that format."); + throw new TerrainException(String.Format("unable to load heightmap from file {0}: no loader available for that format", filename)); + } + private static Stream URIFetch(Uri uri) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); @@ -506,12 +556,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain // Someone diddled terrain outside the normal code paths. Set the taintedness for all clients. // ITerrainModule.TaintTerrain() - public void TaintTerrain() + public void TaintTerrain () { - lock(m_perClientPatchUpdates) + lock (m_perClientPatchUpdates) { // Set the flags for all clients so the tainted patches will be sent out - foreach(PatchUpdates pups in m_perClientPatchUpdates.Values) + foreach (PatchUpdates pups in m_perClientPatchUpdates.Values) { pups.SetAll(m_scene.Heightmap.GetTerrainData()); } @@ -521,13 +571,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain // ITerrainModule.PushTerrain() public void PushTerrain(IClientAPI pClient) { - // If view distance based, set the modified patch bits and the frame event will send the updates if (m_sendTerrainUpdatesByViewDistance) { ScenePresence presence = m_scene.GetScenePresence(pClient.AgentId); if (presence != null) { - lock(m_perClientPatchUpdates) + lock (m_perClientPatchUpdates) { PatchUpdates pups; if (!m_perClientPatchUpdates.TryGetValue(pClient.AgentId, out pups)) @@ -536,7 +585,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain pups = new PatchUpdates(m_scene.Heightmap.GetTerrainData(), presence); m_perClientPatchUpdates.Add(presence.UUID, pups); } - // By setting all to modified, the next update tick will send the patches pups.SetAll(true); } } @@ -547,6 +595,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain pClient.SendLayerData(new float[10]); } } + #region Plugin Loading Methods private void LoadPlugins() @@ -636,7 +685,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_painteffects[StandardTerrainEffects.Smooth] = new SmoothSphere(); m_painteffects[StandardTerrainEffects.Noise] = new NoiseSphere(); m_painteffects[StandardTerrainEffects.Flatten] = new FlattenSphere(); - m_painteffects[StandardTerrainEffects.Revert] = new RevertSphere(m_revert); + m_painteffects[StandardTerrainEffects.Revert] = new RevertSphere(m_baked); m_painteffects[StandardTerrainEffects.Erode] = new ErodeSphere(); m_painteffects[StandardTerrainEffects.Weather] = new WeatherSphere(); m_painteffects[StandardTerrainEffects.Olsen] = new OlsenSphere(); @@ -647,9 +696,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_floodeffects[StandardTerrainEffects.Smooth] = new SmoothArea(); m_floodeffects[StandardTerrainEffects.Noise] = new NoiseArea(); m_floodeffects[StandardTerrainEffects.Flatten] = new FlattenArea(); - m_floodeffects[StandardTerrainEffects.Revert] = new RevertArea(m_revert); + m_floodeffects[StandardTerrainEffects.Revert] = new RevertArea(m_baked); // Terrain Modifier operations + m_modifyOperations["min"] = new MinModifier(this); m_modifyOperations["max"] = new MaxModifier(this); m_modifyOperations["raise"] = new RaiseModifier(this); @@ -673,22 +723,16 @@ namespace OpenSim.Region.CoreModules.World.Terrain } /// - /// Saves the current state of the region into the revert map buffer. + /// Saves the current state of the region into the baked map buffer. + /// - public void UpdateRevertMap() + public void UpdateBakedMap() { - /* - int x; - for (x = 0; x < m_channel.Width; x++) - { - int y; - for (y = 0; y < m_channel.Height; y++) - { - m_revert[x, y] = m_channel[x, y]; - } - } - */ - m_revert = m_channel.MakeCopy(); + m_baked = m_channel.MakeCopy(); + m_painteffects[StandardTerrainEffects.Revert] = new RevertSphere(m_baked); + m_floodeffects[StandardTerrainEffects.Revert] = new RevertArea(m_baked); + m_scene.Bakedmap = m_baked; + m_scene.SaveBakedTerrain(); } /// @@ -715,11 +759,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain { ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY, fileWidth, fileHeight, - (int)m_scene.RegionInfo.RegionSizeX, - (int)m_scene.RegionInfo.RegionSizeY); + (int) m_scene.RegionInfo.RegionSizeX, + (int) m_scene.RegionInfo.RegionSizeY); m_scene.Heightmap = channel; m_channel = channel; - UpdateRevertMap(); + UpdateBakedMap(); } return; @@ -781,39 +825,54 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_scene.RegionInfo.RegionName, filename, m_supportFileExtensionsForTileSave); } + /// - /// Called before processing of every simulation frame. /// This is used to check to see of any of the terrain is tainted and, if so, schedule /// updates for all the presences. /// This also checks to see if there are updates that need to be sent for each presence. /// This is where the logic is to send terrain updates to clients. /// - private void EventManager_OnFrame() + /// doing it async, since currently this is 2 heavy for heartbeat + private void EventManager_TerrainCheckUpdates() { - TerrainData terrData = m_channel.GetTerrainData(); + Util.FireAndForget( + EventManager_TerrainCheckUpdatesAsync); + } + + object TerrainCheckUpdatesLock = new object(); - bool shouldTaint = false; - for(int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) + private void EventManager_TerrainCheckUpdatesAsync(object o) + { + // dont overlap execution + if(Monitor.TryEnter(TerrainCheckUpdatesLock)) { - for(int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) + // this needs fixing + TerrainData terrData = m_channel.GetTerrainData(); + + bool shouldTaint = false; + for (int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) { - if (terrData.IsTaintedAt(x, y)) + for (int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) { - // Found a patch that was modified. Push this flag into the clients. - SendToClients(terrData, x, y); - shouldTaint = true; + if (terrData.IsTaintedAt(x, y,true)) + { + // Found a patch that was modified. Push this flag into the clients. + SendToClients(terrData, x, y); + shouldTaint = true; + } } } - } - // This event also causes changes to be sent to the clients - CheckSendingPatchesToClients(); + // This event also causes changes to be sent to the clients + CheckSendingPatchesToClients(); - // If things changes, generate some events - if (shouldTaint) - { - m_scene.EventManager.TriggerTerrainTainted(); - m_tainted = true; + // If things changes, generate some events + if (shouldTaint) + { + m_scene.EventManager.TriggerTerrainTainted(); + m_tainted = true; + } + Monitor.Exit(TerrainCheckUpdatesLock); } } @@ -883,8 +942,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain presence.ControllingClient.OnLandUndo -= client_OnLandUndo; presence.ControllingClient.OnUnackedTerrain -= client_OnUnackedTerrain; } - - lock(m_perClientPatchUpdates) + lock (m_perClientPatchUpdates) m_perClientPatchUpdates.Remove(client); } @@ -898,12 +956,33 @@ namespace OpenSim.Region.CoreModules.World.Terrain TerrainData terrData = m_channel.GetTerrainData(); bool wasLimited = false; - for(int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) + for (int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) { - for(int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) + for (int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) { if (terrData.IsTaintedAt(x, y, false /* clearOnTest */)) - { + { + // If we should respect the estate settings then + // fixup and height deltas that don't respect them. + // Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values. + wasLimited |= LimitChannelChanges(terrData, x, y); + } + } + } + return wasLimited; + } + + private bool EnforceEstateLimits(int startX, int startY, int endX, int endY) + { + TerrainData terrData = m_channel.GetTerrainData(); + + bool wasLimited = false; + for (int x = startX; x <= endX; x += Constants.TerrainPatchSize) + { + for (int y = startX; y <= endY; y += Constants.TerrainPatchSize) + { + if (terrData.IsTaintedAt(x, y, false /* clearOnTest */)) + { // If we should respect the estate settings then // fixup and height deltas that don't respect them. // Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values. @@ -926,13 +1005,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain float maxDelta = (float)m_scene.RegionInfo.RegionSettings.TerrainRaiseLimit; // loop through the height map for this patch and compare it against - // the revert map - for(int x = xStart; x < xStart + Constants.TerrainPatchSize; x++) + // the baked map + for (int x = xStart; x < xStart + Constants.TerrainPatchSize; x++) { for(int y = yStart; y < yStart + Constants.TerrainPatchSize; y++) { float requestedHeight = terrData[x, y]; - float bakedHeight = (float)m_revert[x, y]; + float bakedHeight = (float)m_baked[x, y]; float requestedDelta = requestedHeight - bakedHeight; if (requestedDelta > maxDelta) @@ -953,15 +1032,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void client_OnLandUndo(IClientAPI client) { - lock(m_undo) - { - if (m_undo.Count > 0) - { - LandUndoState goback = m_undo.Pop(); - if (goback != null) - goback.PlaybackState(); - } - } } /// @@ -975,19 +1045,19 @@ namespace OpenSim.Region.CoreModules.World.Terrain if (m_sendTerrainUpdatesByViewDistance) { // Add that this patch needs to be sent to the accounting for each client. - lock(m_perClientPatchUpdates) + lock (m_perClientPatchUpdates) { m_scene.ForEachScenePresence(presence => - { - PatchUpdates thisClientUpdates; - if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates)) { - // There is a ScenePresence without a send patch map. Create one. - thisClientUpdates = new PatchUpdates(terrData, presence); - m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates); + PatchUpdates thisClientUpdates; + if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates)) + { + // There is a ScenePresence without a send patch map. Create one. + thisClientUpdates = new PatchUpdates(terrData, presence); + m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates); + } + thisClientUpdates.SetByXY(x, y, true); } - thisClientUpdates.SetByXY(x, y, true); - } ); } } @@ -998,7 +1068,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain //float[] heightMap = terrData.GetFloatsSerialized(); float[] heightMap = new float[10]; m_scene.ForEachClient( - delegate(IClientAPI controller) + delegate (IClientAPI controller) { controller.SendLayerData(x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, @@ -1013,14 +1083,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain public int PatchX; public int PatchY; public float Dist; - public PatchesToSend(int pX, int pY, float pDist) { PatchX = pX; PatchY = pY; Dist = pDist; } - public int CompareTo(PatchesToSend other) { return Dist.CompareTo(other.Dist); @@ -1029,113 +1097,216 @@ namespace OpenSim.Region.CoreModules.World.Terrain // Called each frame time to see if there are any patches to send to any of the // ScenePresences. - // We know this is only called if we are doing view distance patch sending so some - // tests are not made. // Loop through all the per-client info and send any patches necessary. private void CheckSendingPatchesToClients() { - lock(m_perClientPatchUpdates) + lock (m_perClientPatchUpdates) { - foreach(PatchUpdates pups in m_perClientPatchUpdates.Values) + foreach (PatchUpdates pups in m_perClientPatchUpdates.Values) { + if(pups.Presence.IsDeleted) + continue; + + // limit rate acording to udp land queue state + if (!pups.Presence.ControllingClient.CanSendLayerData()) + continue; + if (pups.HasUpdates()) { - // There is something that could be sent to this client. - List toSend = GetModifiedPatchesInViewDistance(pups); - if (toSend.Count > 0) + if (m_sendTerrainUpdatesByViewDistance) { - // m_log.DebugFormat("{0} CheckSendingPatchesToClient: sending {1} patches to {2} in region {3}", - // LogHeader, toSend.Count, pups.Presence.Name, m_scene.RegionInfo.RegionName); - // Sort the patches to send by the distance from the presence - toSend.Sort(); - /* old way that sent individual patches - foreach (PatchesToSend pts in toSend) - { - pups.Presence.ControllingClient.SendLayerData(pts.PatchX, pts.PatchY, null); - // presence.ControllingClient.SendLayerData(xs.ToArray(), ys.ToArray(), null, TerrainPatch.LayerType.Land); - } - */ - - // new way that sends all patches to the protocol so they can be sent in one block - int[] xPieces = new int[toSend.Count]; - int[] yPieces = new int[toSend.Count]; - float[] patchPieces = new float[toSend.Count * 2]; - int pieceIndex = 0; - foreach(PatchesToSend pts in toSend) + // There is something that could be sent to this client. + List toSend = GetModifiedPatchesInViewDistance(pups); + if (toSend.Count > 0) { - patchPieces[pieceIndex++] = pts.PatchX; - patchPieces[pieceIndex++] = pts.PatchY; + // m_log.DebugFormat("{0} CheckSendingPatchesToClient: sending {1} patches to {2} in region {3}", + // LogHeader, toSend.Count, pups.Presence.Name, m_scene.RegionInfo.RegionName); + // Sort the patches to send by the distance from the presence + toSend.Sort(); + /* + foreach (PatchesToSend pts in toSend) + { + pups.Presence.ControllingClient.SendLayerData(pts.PatchX, pts.PatchY, null); + // presence.ControllingClient.SendLayerData(xs.ToArray(), ys.ToArray(), null, TerrainPatch.LayerType.Land); + } + */ + + float[] patchPieces = new float[toSend.Count * 2]; + int pieceIndex = 0; + foreach (PatchesToSend pts in toSend) + { + patchPieces[pieceIndex++] = pts.PatchX; + patchPieces[pieceIndex++] = pts.PatchY; + } + pups.Presence.ControllingClient.SendLayerData(-toSend.Count, 0, patchPieces); } - pups.Presence.ControllingClient.SendLayerData(-toSend.Count, 0, patchPieces); + if (pups.sendAll && toSend.Count < 1024) + SendAllModifiedPatchs(pups); + } + else + SendAllModifiedPatchs(pups); + } + } + } + } + private void SendAllModifiedPatchs(PatchUpdates pups) + { + if (!pups.sendAll) // sanity + return; + + int limitX = (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize; + int limitY = (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize; + + if (pups.sendAllcurrentX >= limitX && pups.sendAllcurrentY >= limitY) + { + pups.sendAll = false; + pups.sendAllcurrentX = 0; + pups.sendAllcurrentY = 0; + return; + } + + int npatchs = 0; + List patchs = new List(); + int x = pups.sendAllcurrentX; + int y = pups.sendAllcurrentY; + // send it in the order viewer draws it + // even if not best for memory scan + for (; y < limitY; y++) + { + for (; x < limitX; x++) + { + if (pups.GetByPatch(x, y)) + { + pups.SetByPatch(x, y, false); + patchs.Add(new PatchesToSend(x, y, 0)); + if (++npatchs >= 128) + { + x++; + break; } } } + if (npatchs >= 128) + break; + x = 0; + } + + if (x >= limitX && y >= limitY) + { + pups.sendAll = false; + pups.sendAllcurrentX = 0; + pups.sendAllcurrentY = 0; + } + else + { + pups.sendAllcurrentX = x; + pups.sendAllcurrentY = y; + } + + npatchs = patchs.Count; + if (npatchs > 0) + { + int[] xPieces = new int[npatchs]; + int[] yPieces = new int[npatchs]; + float[] patchPieces = new float[npatchs * 2]; + int pieceIndex = 0; + foreach (PatchesToSend pts in patchs) + { + patchPieces[pieceIndex++] = pts.PatchX; + patchPieces[pieceIndex++] = pts.PatchY; + } + pups.Presence.ControllingClient.SendLayerData(-npatchs, 0, patchPieces); } } - // Compute a list of modified patches that are within our view distance. private List GetModifiedPatchesInViewDistance(PatchUpdates pups) { List ret = new List(); + int npatchs = 0; + ScenePresence presence = pups.Presence; if (presence == null) return ret; - Vector3 presencePos = presence.AbsolutePosition; - - // Before this distance check, the whole region just showed up. Adding the distance - // check causes different things to happen for the current and adjacent regions. - // So, to keep legacy views, if the region is legacy sized, don't do distance check. - bool isLegacySizedRegion = pups.Terrain.SizeX == Constants.RegionSize && pups.Terrain.SizeY == Constants.RegionSize; - bool shouldCheckViewDistance = m_sendTerrainUpdatesByViewDistance && !isLegacySizedRegion; - - int startX = 0; - int endX = (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize; - int startY = 0; - int endY = (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize; - - // The following only reduces the size of area scanned for updates. Only significant for very large varregions. - if (shouldCheckViewDistance) - { - // Compute the area of patches within our draw distance - startX = (((int)(presencePos.X - presence.DrawDistance)) / Constants.TerrainPatchSize) - 2; - startX = Math.Max(startX, 0); - startX = Math.Min(startX, (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize); - startY = (((int)(presencePos.Y - presence.DrawDistance)) / Constants.TerrainPatchSize) - 2; - startY = Math.Max(startY, 0); - startY = Math.Min(startY, (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize); - endX = (((int)(presencePos.X + presence.DrawDistance)) / Constants.TerrainPatchSize) + 2; - endX = Math.Max(endX, 0); - endX = Math.Min(endX, (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize); - endY = (((int)(presencePos.Y + presence.DrawDistance)) / Constants.TerrainPatchSize) + 2; - endY = Math.Max(endY, 0); - endY = Math.Min(endY, (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize); - } - - // m_log.DebugFormat("{0} GetModifiedPatchesInViewDistance. rName={1}, ddist={2}, apos={3}, cpos={4}, isChild={5}, start=<{6},{7}>, end=<{8},{9}>", - // LogHeader, m_scene.RegionInfo.RegionName, - // presence.DrawDistance, presencePos, presence.CameraPosition, - // isLegacySizeChildRegion, - // startX, startY, endX, endY); - for(int x = startX; x < endX; x++) - { - for(int y = startY; y < endY; y++) + float minz = presence.AbsolutePosition.Z; + if (presence.CameraPosition.Z < minz) + minz = presence.CameraPosition.Z; + + // this limit should be max terrainheight + max draw + if (minz > 1500f) + return ret; + + int DrawDistance = (int)presence.DrawDistance; + + DrawDistance = DrawDistance / Constants.TerrainPatchSize; + + int testposX; + int testposY; + + if (Math.Abs(presence.AbsolutePosition.X - presence.CameraPosition.X) > 30 + || Math.Abs(presence.AbsolutePosition.Y - presence.CameraPosition.Y) > 30) + { + testposX = (int)presence.CameraPosition.X / Constants.TerrainPatchSize; + testposY = (int)presence.CameraPosition.Y / Constants.TerrainPatchSize; + } + else + { + testposX = (int)presence.AbsolutePosition.X / Constants.TerrainPatchSize; + testposY = (int)presence.AbsolutePosition.Y / Constants.TerrainPatchSize; + } + int limitX = (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize; + int limitY = (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize; + + // Compute the area of patches within our draw distance + int startX = testposX - DrawDistance; + if (startX < 0) + startX = 0; + else if (startX >= limitX) + startX = limitX - 1; + + int startY = testposY - DrawDistance; + if (startY < 0) + startY = 0; + else if (startY >= limitY) + startY = limitY - 1; + + int endX = testposX + DrawDistance; + if (endX < 0) + endX = 0; + else if (endX > limitX) + endX = limitX; + + int endY = testposY + DrawDistance; + if (endY < 0) + endY = 0; + else if (endY > limitY) + endY = limitY; + + int distx; + int disty; + int distsq; + + DrawDistance *= DrawDistance; + + for (int x = startX; x < endX; x++) + { + for (int y = startY; y < endY; y++) { - //Need to make sure we don't send the same ones over and over - Vector3 patchPos = new Vector3(x * Constants.TerrainPatchSize, y * Constants.TerrainPatchSize, presencePos.Z); if (pups.GetByPatch(x, y)) { - //Check which has less distance, camera or avatar position, both have to be done. - //Its not a radius, its a diameter and we add 50 so that it doesn't look like it cuts off - if (!shouldCheckViewDistance - || Util.DistanceLessThan(presencePos, patchPos, presence.DrawDistance + 50) - || Util.DistanceLessThan(presence.CameraPosition, patchPos, presence.DrawDistance + 50)) + distx = x - testposX; + disty = y - testposY; + distsq = distx * distx + disty * disty; + if (distsq < DrawDistance) { - //They can see it, send it to them pups.SetByPatch(x, y, false); - float dist = Vector3.DistanceSquared(presencePos, patchPos); - ret.Add(new PatchesToSend(x, y, dist)); + ret.Add(new PatchesToSend(x, y, (float)distsq)); + if (npatchs++ > 1024) + { + y = endY; + x = endX; + } } } } @@ -1161,33 +1332,44 @@ namespace OpenSim.Region.CoreModules.World.Terrain int zx = (int)(west + 0.5); int zy = (int)(north + 0.5); - int dx; - for(dx=-n; dx<=n; dx++) + int startX = zx - n; + if (startX < 0) + startX = 0; + + int startY = zy - n; + if (startY < 0) + startY = 0; + + int endX = zx + n; + if (endX >= m_channel.Width) + endX = m_channel.Width - 1; + int endY = zy + n; + if (endY >= m_channel.Height) + endY = m_channel.Height - 1; + + int x, y; + + for (x = startX; x <= endX; x++) { - int dy; - for(dy=-n; dy<=n; dy++) + for (y = startY; y <= endY; y++) { - int x = zx + dx; - int y = zy + dy; - if (x >= 0 && y >= 0 && x < m_channel.Width && y < m_channel.Height) + if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0))) { - if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0))) - { - allowMask[x, y] = true; - allowed = true; - } + allowMask[x, y] = true; + allowed = true; } } } if (allowed) { StoreUndoState(); - m_painteffects[(StandardTerrainEffects)action].PaintEffect( - m_channel, allowMask, west, south, height, size, seconds); + m_painteffects[(StandardTerrainEffects) action].PaintEffect( + m_channel, allowMask, west, south, height, size, seconds, + startX, endX, startY, endY); - //revert changes outside estate limits + //block changes outside estate limits if (!god) - EnforceEstateLimits(); + EnforceEstateLimits(startX, endX, startY, endY); } } else @@ -1202,22 +1384,42 @@ namespace OpenSim.Region.CoreModules.World.Terrain bool[,] fillArea = new bool[m_channel.Width, m_channel.Height]; fillArea.Initialize(); - int x; - for(x = 0; x < m_channel.Width; x++) + int startX = (int)west; + int startY = (int)south; + int endX = (int)east; + int endY = (int)north; + + if (startX < 0) + startX = 0; + else if (startX >= m_channel.Width) + startX = m_channel.Width - 1; + + if (endX < 0) + endX = 0; + else if (endX >= m_channel.Width) + endX = m_channel.Width - 1; + + if (startY < 0) + startY = 0; + else if (startY >= m_channel.Height) + startY = m_channel.Height - 1; + + if (endY < 0) + endY = 0; + else if (endY >= m_channel.Height) + endY = m_channel.Height - 1; + + + int x, y; + + for (x = startX; x <= endX; x++) { - int y; - for(y = 0; y < m_channel.Height; y++) + for (y = startY; y <= endY; y++) { - if (x < east && x > west) + if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0))) { - if (y < north && y > south) - { - if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0))) - { - fillArea[x, y] = true; - allowed = true; - } - } + fillArea[x, y] = true; + allowed = true; } } } @@ -1225,11 +1427,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain if (allowed) { StoreUndoState(); - m_floodeffects[(StandardTerrainEffects)action].FloodEffect(m_channel, fillArea, size); + m_floodeffects[(StandardTerrainEffects)action].FloodEffect(m_channel, fillArea, size, + startX, endX, startY, endY); - //revert changes outside estate limits + //block changes outside estate limits if (!god) - EnforceEstateLimits(); + EnforceEstateLimits(startX, endX, startY, endY); } } else @@ -1260,37 +1463,22 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void StoreUndoState() { - lock(m_undo) - { - if (m_undo.Count > 0) - { - LandUndoState last = m_undo.Peek(); - if (last != null) - { - if (last.Compare(m_channel)) - return; - } - } - - LandUndoState nUndo = new LandUndoState(this, m_channel); - m_undo.Push(nUndo); - } } #region Console Commands private void InterfaceLoadFile(Object[] args) { - LoadFromFile((string)args[0]); + LoadFromFile((string) args[0]); } private void InterfaceLoadTileFile(Object[] args) { - LoadFromFile((string)args[0], - (int)args[1], - (int)args[2], - (int)args[3], - (int)args[4]); + LoadFromFile((string) args[0], + (int) args[1], + (int) args[2], + (int) args[3], + (int) args[4]); } private void InterfaceSaveFile(Object[] args) @@ -1309,15 +1497,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void InterfaceBakeTerrain(Object[] args) { - UpdateRevertMap(); + UpdateBakedMap(); } private void InterfaceRevertTerrain(Object[] args) { int x, y; - for(x = 0; x < m_channel.Width; x++) - for(y = 0; y < m_channel.Height; y++) - m_channel[x, y] = m_revert[x, y]; + for (x = 0; x < m_channel.Width; x++) + for (y = 0; y < m_channel.Height; y++) + m_channel[x, y] = m_baked[x, y]; } @@ -1327,9 +1515,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain if (direction.ToLower().StartsWith("y")) { - for(int x = 0; x < m_channel.Width; x++) + for (int x = 0; x < m_channel.Width; x++) { - for(int y = 0; y < m_channel.Height / 2; y++) + for (int y = 0; y < m_channel.Height / 2; y++) { double height = m_channel[x, y]; double flippedHeight = m_channel[x, (int)m_channel.Height - 1 - y]; @@ -1341,9 +1529,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain } else if (direction.ToLower().StartsWith("x")) { - for(int y = 0; y < m_channel.Height; y++) + for (int y = 0; y < m_channel.Height; y++) { - for(int x = 0; x < m_channel.Width / 2; x++) + for (int x = 0; x < m_channel.Width / 2; x++) { double height = m_channel[x, y]; double flippedHeight = m_channel[(int)m_channel.Width - 1 - x, y]; @@ -1415,50 +1603,57 @@ namespace OpenSim.Region.CoreModules.World.Terrain } } - } private void InterfaceElevateTerrain(Object[] args) { + double val = (double)args[0]; + int x, y; - for(x = 0; x < m_channel.Width; x++) - for(y = 0; y < m_channel.Height; y++) - m_channel[x, y] += (double)args[0]; + for (x = 0; x < m_channel.Width; x++) + for (y = 0; y < m_channel.Height; y++) + m_channel[x, y] += val; } private void InterfaceMultiplyTerrain(Object[] args) { int x, y; - for(x = 0; x < m_channel.Width; x++) - for(y = 0; y < m_channel.Height; y++) - m_channel[x, y] *= (double)args[0]; + double val = (double)args[0]; + + for (x = 0; x < m_channel.Width; x++) + for (y = 0; y < m_channel.Height; y++) + m_channel[x, y] *= val; } private void InterfaceLowerTerrain(Object[] args) { int x, y; - for(x = 0; x < m_channel.Width; x++) - for(y = 0; y < m_channel.Height; y++) - m_channel[x, y] -= (double)args[0]; + double val = (double)args[0]; + + for (x = 0; x < m_channel.Width; x++) + for (y = 0; y < m_channel.Height; y++) + m_channel[x, y] -= val; } public void InterfaceFillTerrain(Object[] args) { int x, y; + double val = (double)args[0]; - for(x = 0; x < m_channel.Width; x++) - for(y = 0; y < m_channel.Height; y++) - m_channel[x, y] = (double)args[0]; + for (x = 0; x < m_channel.Width; x++) + for (y = 0; y < m_channel.Height; y++) + m_channel[x, y] = val; } private void InterfaceMinTerrain(Object[] args) { int x, y; - for(x = 0; x < m_channel.Width; x++) + double val = (double)args[0]; + for (x = 0; x < m_channel.Width; x++) { for(y = 0; y < m_channel.Height; y++) { - m_channel[x, y] = Math.Max((double)args[0], m_channel[x, y]); + m_channel[x, y] = Math.Max(val, m_channel[x, y]); } } } @@ -1466,11 +1661,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void InterfaceMaxTerrain(Object[] args) { int x, y; - for(x = 0; x < m_channel.Width; x++) + double val = (double)args[0]; + for (x = 0; x < m_channel.Width; x++) { for(y = 0; y < m_channel.Height; y++) { - m_channel[x, y] = Math.Min((double)args[0], m_channel[x, y]); + m_channel[x, y] = Math.Min(val, m_channel[x, y]); } } } @@ -1620,9 +1816,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain multiplyCommand.AddArgument("value", "The value to multiply the heightmap by.", "Double"); Command bakeRegionCommand = - new Command("bake", CommandIntentions.COMMAND_HAZARDOUS, InterfaceBakeTerrain, "Saves the current terrain into the regions revert map."); + new Command("bake", CommandIntentions.COMMAND_HAZARDOUS, InterfaceBakeTerrain, "Saves the current terrain into the regions baked map."); Command revertRegionCommand = - new Command("revert", CommandIntentions.COMMAND_HAZARDOUS, InterfaceRevertTerrain, "Loads the revert map terrain into the regions heightmap."); + new Command("revert", CommandIntentions.COMMAND_HAZARDOUS, InterfaceRevertTerrain, "Loads the baked map terrain into the regions heightmap."); Command flipCommand = new Command("flip", CommandIntentions.COMMAND_HAZARDOUS, InterfaceFlipTerrain, "Flips the current terrain about the X or Y axis"); diff --git a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainModuleTests.cs b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainModuleTests.cs index 0563ad0..6a832bc 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainModuleTests.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainModuleTests.cs @@ -45,8 +45,8 @@ namespace OpenSim.Region.CoreModules.Terrain.Tests //UUID userId = TestHelpers.ParseTail(0x1); TerrainModule tm = new TerrainModule(); - Scene scene = new SceneHelpers().SetupScene(); - SceneHelpers.SetupSceneModules(scene, tm); + Scene scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(scene, tm); // Fillheight of 30 { diff --git a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs index 29e80ef..8e77962 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs @@ -60,12 +60,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests TerrainChannel map = new TerrainChannel((int)Constants.RegionSize, (int)Constants.RegionSize); ITerrainPaintableEffect effect = new RaiseSphere(); - effect.PaintEffect(map, allowMask, midRegion, midRegion, -1.0, 2, 6.0); + effect.PaintEffect(map, allowMask, midRegion, midRegion, -1.0, 2, 6.0, + 0, midRegion - 1,0, (int)Constants.RegionSize -1); Assert.That(map[127, midRegion] > 0.0, "Raise brush should raising value at this point (127,128)."); Assert.That(map[125, midRegion] > 0.0, "Raise brush should raising value at this point (124,128)."); Assert.That(map[120, midRegion] == 0.0, "Raise brush should not change value at this point (120,128)."); Assert.That(map[128, midRegion] == 0.0, "Raise brush should not change value at this point (128,128)."); - Assert.That(map[0, midRegion] == 0.0, "Raise brush should not change value at this point (0,128)."); +// Assert.That(map[0, midRegion] == 0.0, "Raise brush should not change value at this point (0,128)."); // // Test LowerSphere // @@ -79,13 +80,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests } effect = new LowerSphere(); - effect.PaintEffect(map, allowMask, midRegion, midRegion, -1.0, 2, 6.0); + effect.PaintEffect(map, allowMask, midRegion, midRegion, -1.0, 2, 6.0, + 0, (int)Constants.RegionSize -1,0, (int)Constants.RegionSize -1); Assert.That(map[127, midRegion] >= 0.0, "Lower should not lowering value below 0.0 at this point (127,128)."); Assert.That(map[127, midRegion] == 0.0, "Lower brush should lowering value to 0.0 at this point (127,128)."); Assert.That(map[125, midRegion] < 1.0, "Lower brush should lowering value at this point (124,128)."); Assert.That(map[120, midRegion] == 1.0, "Lower brush should not change value at this point (120,128)."); Assert.That(map[128, midRegion] == 1.0, "Lower brush should not change value at this point (128,128)."); - Assert.That(map[0, midRegion] == 1.0, "Lower brush should not change value at this point (0,128)."); +// Assert.That(map[0, midRegion] == 1.0, "Lower brush should not change value at this point (0,128)."); } [Test] diff --git a/OpenSim/Region/CoreModules/World/Vegetation/VegetationModule.cs b/OpenSim/Region/CoreModules/World/Vegetation/VegetationModule.cs index 3f5d375..4cee7a5 100644 --- a/OpenSim/Region/CoreModules/World/Vegetation/VegetationModule.cs +++ b/OpenSim/Region/CoreModules/World/Vegetation/VegetationModule.cs @@ -39,14 +39,14 @@ namespace OpenSim.Region.CoreModules.World.Vegetation { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "VegetationModule")] public class VegetationModule : INonSharedRegionModule, IVegetationModule - { + { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + protected Scene m_scene; - + protected static readonly PCode[] creationCapabilities = new PCode[] { PCode.Grass, PCode.NewTree, PCode.Tree }; public PCode[] CreationCapabilities { get { return creationCapabilities; } } - + public void Initialise(IConfigSource source) { } @@ -83,10 +83,10 @@ namespace OpenSim.Region.CoreModules.World.Vegetation treeShape.PCode = newTree ? (byte)PCode.NewTree : (byte)PCode.Tree; treeShape.Scale = scale; treeShape.State = (byte)treeType; - + return m_scene.AddNewPrim(uuid, groupID, position, rotation, treeShape); } - + public SceneObjectGroup CreateEntity( UUID ownerID, UUID groupID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) { @@ -95,22 +95,23 @@ namespace OpenSim.Region.CoreModules.World.Vegetation m_log.DebugFormat("[VEGETATION]: PCode {0} not handled by {1}", shape.PCode, Name); return null; } - + SceneObjectGroup sceneObject = new SceneObjectGroup(ownerID, pos, rot, shape); SceneObjectPart rootPart = sceneObject.GetPart(sceneObject.UUID); - + // if grass or tree, make phantom //rootPart.TrimPermissions(); rootPart.AddFlag(PrimFlags.Phantom); if (rootPart.Shape.PCode != (byte)PCode.Grass) AdaptTree(ref shape); - - m_scene.AddNewSceneObject(sceneObject, true); + sceneObject.SetGroup(groupID, null); - + m_scene.AddNewSceneObject(sceneObject, true); + sceneObject.InvalidateDeepEffectivePerms(); + return sceneObject; } - + protected void AdaptTree(ref PrimitiveBaseShape tree) { // Tree size has to be adapted depending on its type diff --git a/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs b/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs index 9534ad3..226b330 100644 --- a/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs +++ b/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs @@ -79,6 +79,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap /// Based on the algorithm described at http://opensimulator.org/wiki/Terrain_Splatting /// Note we create a 256x256 dimension texture even if the actual terrain is larger. /// + public static Bitmap Splat(ITerrainChannel terrain, UUID[] textureIDs, float[] startHeights, float[] heightRanges, Vector3d regionPosition, IAssetService assetService, bool textureTerrain) @@ -129,8 +130,8 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap asset = assetService.Get(textureIDs[i].ToString()); if (asset != null) { -// m_log.DebugFormat( -// "[TERRAIN SPLAT]: Got cached original JPEG2000 terrain texture {0} {1}", i, asset.ID); + // m_log.DebugFormat( + // "[TERRAIN SPLAT]: Got cached original JPEG2000 terrain texture {0} {1}", i, asset.ID); try { detailTexture[i] = (Bitmap)CSJ2K.J2kImage.FromBytes(asset.Data); } catch (Exception ex) @@ -140,7 +141,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap } if (detailTexture[i] != null) - { + { // Make sure this texture is the correct size, otherwise resize if (detailTexture[i].Width != 256 || detailTexture[i].Height != 256) { @@ -225,7 +226,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap float pctX = (float)x / 255f; float pctY = (float)y / 255f; - // Use bilinear interpolation between the four corners of start height and + // Use bilinear interpolation between the four corners of start height and // height range to select the current values at this position float startHeight = ImageUtils.Bilinear( startHeights[0], @@ -256,7 +257,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap float highFreq = Perlin.turbulence2(vec.X, vec.Y, 2f) * 2.25f; float noise = (lowFreq + highFreq) * 2f; - // Combine the current height, generated noise, start height, and height range parameters, then scale all of it + // Combine the current height, generated noise, start height, and height range parameters, then scale all of it float layer = ((height + noise - startHeight) / heightRange) * 4f; if (Single.IsNaN(layer)) layer = 0f; @@ -352,7 +353,6 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap b.Dispose(); return result; } - public static Bitmap SplatSimple(float[] heightmap) { const float BASE_HSV_H = 93f / 360f; diff --git a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs index 383a67f..4934ebd 100644 --- a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs +++ b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs @@ -35,7 +35,7 @@ using System.Reflection; using CSJ2K; using Nini.Config; using log4net; -using Rednettle.Warp3D; +using Warp3D; using Mono.Addins; using OpenSim.Framework; @@ -76,10 +76,12 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap private bool m_texturePrims = true; // true if should texture the rendered prims private float m_texturePrimSize = 48f; // size of prim before we consider texturing it private bool m_renderMeshes = false; // true if to render meshes rather than just bounding boxes - private bool m_useAntiAliasing = false; // true if to anti-alias the rendered image private bool m_Enabled = false; +// private Bitmap lastImage = null; + private DateTime lastImageTime = DateTime.MinValue; + #region Region Module interface public void Initialise(IConfigSource source) @@ -94,9 +96,9 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap m_Enabled = true; - m_drawPrimVolume + m_drawPrimVolume = Util.GetConfigVarFromSections(m_config, "DrawPrimOnMapTile", configSections, m_drawPrimVolume); - m_textureTerrain + m_textureTerrain = Util.GetConfigVarFromSections(m_config, "TextureOnMapTile", configSections, m_textureTerrain); m_texturePrims = Util.GetConfigVarFromSections(m_config, "TexturePrims", configSections, m_texturePrims); @@ -104,10 +106,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap = Util.GetConfigVarFromSections(m_config, "TexturePrimSize", configSections, m_texturePrimSize); m_renderMeshes = Util.GetConfigVarFromSections(m_config, "RenderMeshes", configSections, m_renderMeshes); - m_useAntiAliasing - = Util.GetConfigVarFromSections(m_config, "UseAntiAliasing", configSections, m_useAntiAliasing); - - } + } public void AddRegion(Scene scene) { @@ -118,14 +117,9 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap List renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory()); if (renderers.Count > 0) - { - m_primMesher = RenderingLoader.LoadRenderer(renderers[0]); - m_log.DebugFormat("[WARP 3D IMAGE MODULE]: Loaded prim mesher {0}", m_primMesher); - } + m_log.Info("[MAPTILE]: Loaded prim mesher " + renderers[0]); else - { - m_log.Debug("[WARP 3D IMAGE MODULE]: No prim mesher loaded, prim rendering will be disabled"); - } + m_log.Info("[MAPTILE]: No prim mesher loaded, prim rendering will be disabled"); m_scene.RegisterModuleInterface(this); } @@ -158,18 +152,36 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap public Bitmap CreateMapTile() { - // Vector3 camPos = new Vector3(127.5f, 127.5f, 221.7025033688163f); - // Camera above the middle of the region + /* this must be on all map, not just its image + if ((DateTime.Now - lastImageTime).TotalSeconds < 3600) + { + return (Bitmap)lastImage.Clone(); + } + */ + + List renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory()); + if (renderers.Count > 0) + { + m_primMesher = RenderingLoader.LoadRenderer(renderers[0]); + } + Vector3 camPos = new Vector3( - m_scene.RegionInfo.RegionSizeX/2 - 0.5f, - m_scene.RegionInfo.RegionSizeY/2 - 0.5f, + m_scene.RegionInfo.RegionSizeX / 2 - 0.5f, + m_scene.RegionInfo.RegionSizeY / 2 - 0.5f, 221.7025033688163f); // Viewport viewing down onto the region Viewport viewport = new Viewport(camPos, -Vector3.UnitZ, 1024f, 0.1f, (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY, - (float)m_scene.RegionInfo.RegionSizeX, (float)m_scene.RegionInfo.RegionSizeY ); - // Fill the viewport and return the image - return CreateMapTile(viewport, false); + (float)m_scene.RegionInfo.RegionSizeX, (float)m_scene.RegionInfo.RegionSizeY); + + Bitmap tile = CreateMapTile(viewport, false); + m_primMesher = null; + return tile; +/* + lastImage = tile; + lastImageTime = DateTime.Now; + return (Bitmap)lastImage.Clone(); + */ } public Bitmap CreateViewImage(Vector3 camPos, Vector3 camDir, float fov, int width, int height, bool useTextures) @@ -185,21 +197,14 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap int width = viewport.Width; int height = viewport.Height; - if (m_useAntiAliasing) - { - width *= 2; - height *= 2; - } - WarpRenderer renderer = new WarpRenderer(); - renderer.CreateScene(width, height); - renderer.Scene.autoCalcNormals = false; + if(!renderer.CreateScene(width, height)) + return new Bitmap(width,height); #region Camera warp_Vector pos = ConvertVector(viewport.Position); - pos.z -= 0.001f; // Works around an issue with the Warp3D camera warp_Vector lookat = warp_Vector.add(ConvertVector(viewport.Position), ConvertVector(viewport.LookDirection)); renderer.Scene.defaultCamera.setPos(pos); @@ -207,9 +212,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap if (viewport.Orthographic) { - renderer.Scene.defaultCamera.isOrthographic = true; - renderer.Scene.defaultCamera.orthoViewWidth = viewport.OrthoWindowWidth; - renderer.Scene.defaultCamera.orthoViewHeight = viewport.OrthoWindowHeight; + renderer.Scene.defaultCamera.setOrthographic(true,viewport.OrthoWindowWidth, viewport.OrthoWindowHeight); } else { @@ -231,24 +234,8 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap renderer.Render(); Bitmap bitmap = renderer.Scene.getImage(); - if (m_useAntiAliasing) - { - using (Bitmap origBitmap = bitmap) - bitmap = ImageUtils.ResizeImage(origBitmap, viewport.Width, viewport.Height); - } - - // XXX: It shouldn't really be necesary to force a GC here as one should occur anyway pretty shortly - // afterwards. It's generally regarded as a bad idea to manually GC. If Warp3D is using lots of memory - // then this may be some issue with the Warp3D code itself, though it's also quite possible that generating - // this map tile simply takes a lot of memory. - foreach (var o in renderer.Scene.objectData.Values) - { - warp_Object obj = (warp_Object)o; - obj.vertexData = null; - obj.triangleData = null; - } - - renderer.Scene.removeAllObjects(); + renderer.Scene.destroy(); + renderer.Reset(); renderer = null; viewport = null; @@ -285,12 +272,12 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight; renderer.AddPlane("Water", m_scene.RegionInfo.RegionSizeX * 0.5f); - renderer.Scene.sceneobject("Water").setPos(m_scene.RegionInfo.RegionSizeX/2 - 0.5f, + renderer.Scene.sceneobject("Water").setPos(m_scene.RegionInfo.RegionSizeX * 0.5f - 0.5f, waterHeight, - m_scene.RegionInfo.RegionSizeY/2 - 0.5f ); + m_scene.RegionInfo.RegionSizeY * 0.5f - 0.5f); warp_Material waterColorMaterial = new warp_Material(ConvertColor(WATER_COLOR)); - waterColorMaterial.setReflectivity(0); // match water color with standard map module thanks lkalif + waterColorMaterial.setReflectivity(0); // match water color with standard map module thanks lkalif waterColorMaterial.setTransparency((byte)((1f - WATER_COLOR.A) * 255f)); renderer.Scene.addMaterial("WaterColor", waterColorMaterial); renderer.SetObjectMaterial("Water", "WaterColor"); @@ -303,53 +290,53 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap { ITerrainChannel terrain = m_scene.Heightmap; + float regionsx = m_scene.RegionInfo.RegionSizeX; + float regionsy = m_scene.RegionInfo.RegionSizeY; + // 'diff' is the difference in scale between the real region size and the size of terrain we're buiding - float diff = (float)m_scene.RegionInfo.RegionSizeX / 256f; + float diff = regionsx / 256f; - warp_Object obj = new warp_Object(256 * 256, 255 * 255 * 2); + int npointsx =(int)(regionsx / diff); + int npointsy =(int)(regionsy / diff); + + float invsx = 1.0f / regionsx; + float invsy = 1.0f / (float)m_scene.RegionInfo.RegionSizeY; // Create all the vertices for the terrain - for (float y = 0; y < m_scene.RegionInfo.RegionSizeY; y += diff) + warp_Object obj = new warp_Object(); + for (float y = 0; y < regionsy; y += diff) { - for (float x = 0; x < m_scene.RegionInfo.RegionSizeX; x += diff) + for (float x = 0; x < regionsx; x += diff) { - warp_Vector pos = ConvertVector(x, y, (float)terrain[(int)x, (int)y]); - obj.addVertex(new warp_Vertex(pos, - x / (float)m_scene.RegionInfo.RegionSizeX, - (((float)m_scene.RegionInfo.RegionSizeY) - y) / m_scene.RegionInfo.RegionSizeY) ); + warp_Vector pos = ConvertVector(x , y , (float)terrain[(int)x, (int)y]); + obj.addVertex(new warp_Vertex(pos, x * invsx, 1.0f - y * invsy)); } } - // Now that we have all the vertices, make another pass and create - // the normals for each of the surface triangles and - // create the list of triangle indices. - for (float y = 0; y < m_scene.RegionInfo.RegionSizeY; y += diff) + // Now that we have all the vertices, make another pass and + // create the list of triangle indices. + float invdiff = 1.0f / diff; + int limx = npointsx - 1; + int limy = npointsy - 1; + for (float y = 0; y < regionsy; y += diff) { - for (float x = 0; x < m_scene.RegionInfo.RegionSizeX; x += diff) + for (float x = 0; x < regionsx; x += diff) { - float newX = x / diff; - float newY = y / diff; - if (newX < 255 && newY < 255) + float newX = x * invdiff; + float newY = y * invdiff; + if (newX < limx && newY < limy) { - int v = (int)newY * 256 + (int)newX; - - // Normal for a triangle made up of three adjacent vertices - Vector3 v1 = new Vector3(newX, newY, (float)terrain[(int)x, (int)y]); - Vector3 v2 = new Vector3(newX + 1, newY, (float)terrain[(int)(x + 1), (int)y]); - Vector3 v3 = new Vector3(newX, newY + 1, (float)terrain[(int)x, ((int)(y + 1))]); - warp_Vector norm = ConvertVector(SurfaceNormal(v1, v2, v3)); - norm = norm.reverse(); - obj.vertex(v).n = norm; + int v = (int)newY * npointsx + (int)newX; // Make two triangles for each of the squares in the grid of vertices obj.addTriangle( v, v + 1, - v + 256); + v + npointsx); obj.addTriangle( - v + 256 + 1, - v + 256, + v + npointsx + 1, + v + npointsx, v + 1); } } @@ -382,18 +369,15 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle, out globalX, out globalY); warp_Texture texture; - using ( - Bitmap image - = TerrainSplat.Splat(terrain, textureIDs, startHeights, heightRanges, + using (Bitmap image = TerrainSplat.Splat( + terrain, textureIDs, startHeights, heightRanges, new Vector3d(globalX, globalY, 0.0), m_scene.AssetService, textureTerrain)) - { texture = new warp_Texture(image); - } warp_Material material = new warp_Material(texture); material.setReflectivity(50); renderer.Scene.addMaterial("TerrainColor", material); - renderer.Scene.material("TerrainColor").setReflectivity(0); // reduces tile seams a bit thanks lkalif + renderer.Scene.material("TerrainColor").setReflectivity(0); // reduces tile seams a bit thanks lkalif renderer.SetObjectMaterial("Terrain", "TerrainColor"); } @@ -414,11 +398,13 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap private void CreatePrim(WarpRenderer renderer, SceneObjectPart prim, bool useTextures) { - const float MIN_SIZE = 2f; + const float MIN_SIZE_SQUARE = 4f; if ((PCode)prim.Shape.PCode != PCode.Prim) return; - if (prim.Scale.LengthSquared() < MIN_SIZE * MIN_SIZE) + float primScaleLenSquared = prim.Scale.LengthSquared(); + + if (primScaleLenSquared < MIN_SIZE_SQUARE) return; FacetedMesh renderMesh = null; @@ -442,25 +428,14 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap else // It's sculptie { IJ2KDecoder imgDecoder = m_scene.RequestModuleInterface(); - if (imgDecoder != null) + if(imgDecoder != null) { - try + Image sculpt = imgDecoder.DecodeToImage(sculptAsset); + if(sculpt != null) { - Image sculpt = imgDecoder.DecodeToImage(sculptAsset); - if (sculpt != null) - { - renderMesh = m_primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt, - DetailLevel.Medium); - sculpt.Dispose(); - } - } - catch (Exception e) - { - Vector3 objectPos = prim.ParentGroup.RootPart.AbsolutePosition; -//// TODO - print out owner of SceneObjectPart prim. - m_log.Warn(string.Format("[WARP 3D IMAGE MODULE]: Failed to decode asset {0} @ {1},{2},{3} - {4}.", - omvPrim.Sculpt.SculptTexture, objectPos.X, objectPos.Y, objectPos.Z, - prim.ParentGroup.RootPart.Name)); + renderMesh = m_primMesher.GenerateFacetedSculptMesh(omvPrim,(Bitmap)sculpt, + DetailLevel.Medium); + sculpt.Dispose(); } } } @@ -477,20 +452,6 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap if (renderMesh == null) return; - warp_Vector primPos = ConvertVector(prim.GetWorldPosition()); - warp_Quaternion primRot = ConvertQuaternion(prim.RotationOffset); - - warp_Matrix m = warp_Matrix.quaternionMatrix(primRot); - - if (prim.ParentID != 0) - { - SceneObjectGroup group = m_scene.SceneGraph.GetGroupByPrim(prim.LocalId); - if (group != null) - m.transform(warp_Matrix.quaternionMatrix(ConvertQuaternion(group.RootPart.RotationOffset))); - } - - warp_Vector primScale = ConvertVector(prim.Scale); - string primID = prim.UUID.ToString(); // Create the prim faces @@ -498,27 +459,18 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap for (int i = 0; i < renderMesh.Faces.Count; i++) { Face face = renderMesh.Faces[i]; - string meshName = primID + "-Face-" + i.ToString(); + string meshName = primID + i.ToString(); // Avoid adding duplicate meshes to the scene if (renderer.Scene.objectData.ContainsKey(meshName)) - { continue; - } - - warp_Object faceObj = new warp_Object(face.Vertices.Count, face.Indices.Count / 3); + warp_Object faceObj = new warp_Object(); for (int j = 0; j < face.Vertices.Count; j++) { Vertex v = face.Vertices[j]; - warp_Vector pos = ConvertVector(v.Position); - warp_Vector norm = ConvertVector(v.Normal); - - if (prim.Shape.SculptTexture == UUID.Zero) - norm = norm.reverse(); - warp_Vertex vert = new warp_Vertex(pos, norm, v.TexCoord.X, v.TexCoord.Y); - + warp_Vertex vert = new warp_Vertex(pos, v.TexCoord.X, v.TexCoord.Y); faceObj.addVertex(vert); } @@ -533,17 +485,19 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap Primitive.TextureEntryFace teFace = prim.Shape.Textures.GetFace((uint)i); Color4 faceColor = GetFaceColor(teFace); string materialName = String.Empty; - if (m_texturePrims && prim.Scale.LengthSquared() > m_texturePrimSize*m_texturePrimSize) + if (m_texturePrims && primScaleLenSquared > m_texturePrimSize*m_texturePrimSize) materialName = GetOrCreateMaterial(renderer, faceColor, teFace.TextureID); else materialName = GetOrCreateMaterial(renderer, faceColor); + warp_Vector primPos = ConvertVector(prim.GetWorldPosition()); + warp_Quaternion primRot = ConvertQuaternion(prim.GetWorldRotation()); + warp_Matrix m = warp_Matrix.quaternionMatrix(primRot); faceObj.transform(m); faceObj.setPos(primPos); - faceObj.scaleSelf(primScale.x, primScale.y, primScale.z); + faceObj.scaleSelf(prim.Scale.X, prim.Scale.Z, prim.Scale.Y); renderer.Scene.addObject(meshName, faceObj); - renderer.SetObjectMaterial(meshName, materialName); } } @@ -576,7 +530,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap if (!fetched) { - // Fetch the texture, decode and get the average color, + // Fetch the texture, decode and get the average color, // then save it to a temporary metadata asset AssetBase textureAsset = m_scene.AssetService.Get(face.TextureID.ToString()); if (textureAsset != null) @@ -671,7 +625,6 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap #endregion Rendering Methods #region Static Helpers - // Note: axis change. private static warp_Vector ConvertVector(float x, float y, float z) { @@ -725,10 +678,10 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap { width = bitmap.Width; height = bitmap.Height; - + BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bitmap.PixelFormat); pixelBytes = (bitmap.PixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4; - + // Sum up the individual channels unsafe { @@ -737,7 +690,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap for (int y = 0; y < height; y++) { byte* row = (byte*)bitmapData.Scan0 + (y * bitmapData.Stride); - + for (int x = 0; x < width; x++) { b += row[x * pixelBytes + 0]; @@ -752,7 +705,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap for (int y = 0; y < height; y++) { byte* row = (byte*)bitmapData.Scan0 + (y * bitmapData.Stride); - + for (int x = 0; x < width; x++) { b += row[x * pixelBytes + 0]; diff --git a/OpenSim/Region/CoreModules/World/Wind/Plugins/ConfigurableWind.cs b/OpenSim/Region/CoreModules/World/Wind/Plugins/ConfigurableWind.cs index 6af4050..a2b44df 100644 --- a/OpenSim/Region/CoreModules/World/Wind/Plugins/ConfigurableWind.cs +++ b/OpenSim/Region/CoreModules/World/Wind/Plugins/ConfigurableWind.cs @@ -50,7 +50,7 @@ namespace OpenSim.Region.CoreModules.World.Wind.Plugins private float m_avgDirection = 0.0f; // Average direction of the wind in degrees private float m_varStrength = 5.0f; // Max Strength Variance private float m_varDirection = 30.0f;// Max Direction Variance - private float m_rateChange = 1.0f; // + private float m_rateChange = 1.0f; // private Vector2 m_curPredominateWind = new Vector2(); @@ -70,7 +70,7 @@ namespace OpenSim.Region.CoreModules.World.Wind.Plugins public void Initialise() { - + } #endregion @@ -103,7 +103,7 @@ namespace OpenSim.Region.CoreModules.World.Wind.Plugins } } - public void WindUpdate(uint frame) + public bool WindUpdate(uint frame) { double avgAng = m_avgDirection * (Math.PI/180.0f); double varDir = m_varDirection * (Math.PI/180.0f); @@ -111,7 +111,7 @@ namespace OpenSim.Region.CoreModules.World.Wind.Plugins // Prevailing wind algorithm // Inspired by Kanker Greenacre - // TODO: + // TODO: // * This should probably be based on in-world time. // * should probably move all these local variables to class members and constants double time = DateTime.Now.TimeOfDay.Seconds / 86400.0f; @@ -125,10 +125,8 @@ namespace OpenSim.Region.CoreModules.World.Wind.Plugins offset = Math.Sin(theta) * Math.Sin(theta*4) + (Math.Sin(theta*13) / 3); double windSpeed = m_avgStrength + (m_varStrength * offset); - if (windSpeed<0) - windSpeed=0; - - + if (windSpeed < 0) + windSpeed = -windSpeed; m_curPredominateWind.X = (float)Math.Cos(windDir); m_curPredominateWind.Y = (float)Math.Sin(windDir); @@ -144,6 +142,7 @@ namespace OpenSim.Region.CoreModules.World.Wind.Plugins m_windSpeeds[y * 16 + x] = m_curPredominateWind; } } + return true; } public Vector3 WindSpeed(float fX, float fY, float fZ) @@ -158,9 +157,9 @@ namespace OpenSim.Region.CoreModules.World.Wind.Plugins public string Description { - get + get { - return "Provides a predominate wind direction that can change within configured variances for direction and speed."; + return "Provides a predominate wind direction that can change within configured variances for direction and speed."; } } diff --git a/OpenSim/Region/CoreModules/World/Wind/Plugins/SimpleRandomWind.cs b/OpenSim/Region/CoreModules/World/Wind/Plugins/SimpleRandomWind.cs index fcb0c10..d2ff7b3 100644 --- a/OpenSim/Region/CoreModules/World/Wind/Plugins/SimpleRandomWind.cs +++ b/OpenSim/Region/CoreModules/World/Wind/Plugins/SimpleRandomWind.cs @@ -82,22 +82,23 @@ namespace OpenSim.Region.CoreModules.World.Wind.Plugins } } - public void WindUpdate(uint frame) + public bool WindUpdate(uint frame) { //Make sure our object is valid (we haven't been disposed of yet) - if (m_windSpeeds != null) + if (m_windSpeeds == null) + return false; + + for (int y = 0; y < 16; y++) { - for (int y = 0; y < 16; y++) + for (int x = 0; x < 16; x++) { - for (int x = 0; x < 16; x++) - { - m_windSpeeds[y * 16 + x].X = (float)(m_rndnums.NextDouble() * 2d - 1d); // -1 to 1 - m_windSpeeds[y * 16 + x].Y = (float)(m_rndnums.NextDouble() * 2d - 1d); // -1 to 1 - m_windSpeeds[y * 16 + x].X *= m_strength; - m_windSpeeds[y * 16 + x].Y *= m_strength; - } + m_windSpeeds[y * 16 + x].X = (float)(m_rndnums.NextDouble() * 2d - 1d); // -1 to 1 + m_windSpeeds[y * 16 + x].Y = (float)(m_rndnums.NextDouble() * 2d - 1d); // -1 to 1 + m_windSpeeds[y * 16 + x].X *= m_strength; + m_windSpeeds[y * 16 + x].Y *= m_strength; } } + return true; } public Vector3 WindSpeed(float fX, float fY, float fZ) diff --git a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs index 35014f5..a1fff62 100644 --- a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs +++ b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs @@ -46,11 +46,13 @@ namespace OpenSim.Region.CoreModules private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private uint m_frame = 0; - private uint m_frameLastUpdateClientArray = 0; + private int m_dataVersion = 0; + private int m_regionID = 0; private int m_frameUpdateRate = 150; //private Random m_rndnums = new Random(Environment.TickCount); private Scene m_scene = null; private bool m_ready = false; + private bool m_inUpdate = false; private bool m_enabled = false; private IConfig m_windConfig; @@ -96,7 +98,6 @@ namespace OpenSim.Region.CoreModules m_scene = scene; m_frame = 0; - // Register all the Wind Model Plug-ins foreach (IWindModelPlugin windPlugin in AddinManager.GetExtensionObjects("/OpenSim/WindModule", false)) { @@ -118,7 +119,6 @@ namespace OpenSim.Region.CoreModules } } - // if the plug-in wasn't found, default to no wind. if (m_activeWindPlugin == null) { @@ -154,14 +154,14 @@ namespace OpenSim.Region.CoreModules // Register event handlers for when Avatars enter the region, and frame ticks m_scene.EventManager.OnFrame += WindUpdate; - m_scene.EventManager.OnMakeRootAgent += OnAgentEnteredRegion; - // Register the wind module + // Register the wind module m_scene.RegisterModuleInterface(this); // Generate initial wind values - GenWindPos(); - + GenWind(); + // hopefully this will not be the same for all regions on same instance + m_dataVersion = (int)m_scene.AllocateLocalId(); // Mark Module Ready for duty m_ready = true; } @@ -184,7 +184,7 @@ namespace OpenSim.Region.CoreModules // Remove our hooks m_scene.EventManager.OnFrame -= WindUpdate; - m_scene.EventManager.OnMakeRootAgent -= OnAgentEnteredRegion; +// m_scene.EventManager.OnMakeRootAgent -= OnAgentEnteredRegion; } @@ -351,7 +351,7 @@ namespace OpenSim.Region.CoreModules #region IWindModule Methods /// - /// Retrieve the wind speed at the given region coordinate. This + /// Retrieve the wind speed at the given region coordinate. This /// implimentation ignores Z. /// /// 0...255 @@ -396,7 +396,7 @@ namespace OpenSim.Region.CoreModules public string WindActiveModelPluginName { - get + get { if (m_activeWindPlugin != null) { @@ -416,67 +416,43 @@ namespace OpenSim.Region.CoreModules /// public void WindUpdate() { - if (((m_frame++ % m_frameUpdateRate) != 0) || !m_ready) - { + if ((!m_ready || m_inUpdate || (m_frame++ % m_frameUpdateRate) != 0)) return; - } - - GenWindPos(); - - SendWindAllClients(); - } - public void OnAgentEnteredRegion(ScenePresence avatar) - { - if (m_ready) + m_inUpdate = true; + Util.FireAndForget(delegate { - if (m_activeWindPlugin != null) + try { - // Ask wind plugin to generate a LL wind array to be cached locally - // Try not to update this too often, as it may involve array copies - if (m_frame >= (m_frameLastUpdateClientArray + m_frameUpdateRate)) + GenWind(); + m_scene.ForEachClient(delegate(IClientAPI client) { - windSpeeds = m_activeWindPlugin.WindLLClientArray(); - m_frameLastUpdateClientArray = m_frame; - } - } - - avatar.ControllingClient.SendWindData(windSpeeds); - } - } + client.SendWindData(m_dataVersion, windSpeeds); + }); - private void SendWindAllClients() - { - if (m_ready) - { - if (m_scene.GetRootAgentCount() > 0) + } + finally { - // Ask wind plugin to generate a LL wind array to be cached locally - // Try not to update this too often, as it may involve array copies - if (m_frame >= (m_frameLastUpdateClientArray + m_frameUpdateRate)) - { - windSpeeds = m_activeWindPlugin.WindLLClientArray(); - m_frameLastUpdateClientArray = m_frame; - } - - m_scene.ForEachRootClient(delegate(IClientAPI client) - { - client.SendWindData(windSpeeds); - }); + m_inUpdate = false; } - } + }, + null, "WindModuleUpdate"); } + /// - /// Calculate the sun's orbital position and its velocity. + /// Calculate new wind + /// returns false if no change /// - private void GenWindPos() + private bool GenWind() { - if (m_activeWindPlugin != null) + if (m_activeWindPlugin != null && m_activeWindPlugin.WindUpdate(m_frame)) { - // Tell Wind Plugin to update it's wind data - m_activeWindPlugin.WindUpdate(m_frame); + windSpeeds = m_activeWindPlugin.WindLLClientArray(); + m_dataVersion++; + return true; } + return false; } } } diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs index d862f18..5876df3 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs @@ -128,109 +128,116 @@ namespace OpenSim.Region.CoreModules.World.WorldMap m_Clients.Add(remoteClient.AgentId); } - try - { - OnMapNameRequest(remoteClient, mapName, flags); - } - finally - { - lock (m_Clients) - m_Clients.Remove(remoteClient.AgentId); - } + OnMapNameRequest(remoteClient, mapName, flags); } private void OnMapNameRequest(IClientAPI remoteClient, string mapName, uint flags) { - List blocks = new List(); - if (mapName.Length < 3 || (mapName.EndsWith("#") && mapName.Length < 4)) + Util.FireAndForget(x => { - // final block, closing the search result - AddFinalBlock(blocks); + try + { + List blocks = new List(); + if (mapName.Length < 3 || (mapName.EndsWith("#") && mapName.Length < 4)) + { + // final block, closing the search result + AddFinalBlock(blocks,mapName); - // flags are agent flags sent from the viewer. - // they have different values depending on different viewers, apparently - remoteClient.SendMapBlock(blocks, flags); - remoteClient.SendAlertMessage("Use a search string with at least 3 characters"); - return; - } + // flags are agent flags sent from the viewer. + // they have different values depending on different viewers, apparently + remoteClient.SendMapBlock(blocks, flags); + remoteClient.SendAlertMessage("Use a search string with at least 3 characters"); + return; + } + //m_log.DebugFormat("MAP NAME=({0})", mapName); - List regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20); - - string mapNameOrig = mapName; - if (regionInfos.Count == 0) - { - // Hack to get around the fact that ll V3 now drops the port from the - // map name. See https://jira.secondlife.com/browse/VWR-28570 - // - // Caller, use this magic form instead: - // secondlife://http|!!mygrid.com|8002|Region+Name/128/128 - // or url encode if possible. - // the hacks we do with this viewer... - // - if (mapName.Contains("|")) - mapName = mapName.Replace('|', ':'); - if (mapName.Contains("+")) - mapName = mapName.Replace('+', ' '); - if (mapName.Contains("!")) - mapName = mapName.Replace('!', '/'); - - if (mapName != mapNameOrig) - regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20); - } - - m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions. Flags={2}", mapName, regionInfos.Count, flags); - - if (regionInfos.Count > 0) - { - foreach (GridRegion info in regionInfos) - { - if ((flags & 2) == 2) // V2 sends this + // Hack to get around the fact that ll V3 now drops the port from the + // map name. See https://jira.secondlife.com/browse/VWR-28570 + // + // Caller, use this magic form instead: + // secondlife://http|!!mygrid.com|8002|Region+Name/128/128 + // or url encode if possible. + // the hacks we do with this viewer... + // + bool needOriginalName = false; + string mapNameOrig = mapName; + if (mapName.Contains("|")) { - List datas = WorldMap.Map2BlockFromGridRegion(info, flags); - // ugh! V2-3 is very sensitive about the result being - // exactly the same as the requested name - if (regionInfos.Count == 1 && (mapName != mapNameOrig)) - datas.ForEach(d => d.Name = mapNameOrig); - - blocks.AddRange(datas); + mapName = mapName.Replace('|', ':'); + needOriginalName = true; } - else + if (mapName.Contains("+")) { - MapBlockData data = WorldMap.MapBlockFromGridRegion(info, flags); - blocks.Add(data); + mapName = mapName.Replace('+', ' '); + needOriginalName = true; } - } - } + if (mapName.Contains("!")) + { + mapName = mapName.Replace('!', '/'); + needOriginalName = true; + } + if (mapName.Contains(".")) + needOriginalName = true; - // final block, closing the search result - AddFinalBlock(blocks); + // try to fetch from GridServer + List regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20); + // if (regionInfos.Count == 0) + // remoteClient.SendAlertMessage("Hyperlink could not be established."); - // flags are agent flags sent from the viewer. - // they have different values depending on different viewers, apparently - remoteClient.SendMapBlock(blocks, flags); + //m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions", mapName, regionInfos.Count); - // send extra user messages for V3 - // because the UI is very confusing - // while we don't fix the hard-coded urls - if (flags == 2) - { - if (regionInfos.Count == 0) - remoteClient.SendAlertMessage("No regions found with that name."); - // this seems unnecessary because found regions will show up in the search results - //else if (regionInfos.Count == 1) - // remoteClient.SendAlertMessage("Region found!"); - } + MapBlockData data; + if (regionInfos != null && regionInfos.Count > 0) + { + foreach (GridRegion info in regionInfos) + { + data = new MapBlockData(); + data.Agents = 0; + data.Access = info.Access; + MapBlockData block = new MapBlockData(); + WorldMap.MapBlockFromGridRegion(block, info, flags); + + if (flags == 2 && regionInfos.Count == 1 && needOriginalName) + block.Name = mapNameOrig; + blocks.Add(block); + } + } + + // final block, closing the search result + AddFinalBlock(blocks,mapNameOrig); + + // flags are agent flags sent from the viewer. + // they have different values depending on different viewers, apparently + remoteClient.SendMapBlock(blocks, flags); + + // send extra user messages for V3 + // because the UI is very confusing + // while we don't fix the hard-coded urls + if (flags == 2) + { + if (regionInfos == null || regionInfos.Count == 0) + remoteClient.SendAgentAlertMessage("No regions found with that name.", true); + // else if (regionInfos.Count == 1) + // remoteClient.SendAgentAlertMessage("Region found!", false); + } + } + finally + { + lock (m_Clients) + m_Clients.Remove(remoteClient.AgentId); + } + }); } - private void AddFinalBlock(List blocks) + private void AddFinalBlock(List blocks,string name) { // final block, closing the search result MapBlockData data = new MapBlockData(); data.Agents = 0; data.Access = (byte)SimAccess.NonExistent; data.MapImageId = UUID.Zero; - data.Name = ""; + data.Name = name; data.RegionFlags = 0; data.WaterHeight = 0; // not used data.X = 0; diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index db1187e..03a4d34 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs @@ -66,32 +66,34 @@ namespace OpenSim.Region.CoreModules.World.WorldMap private static readonly string DEFAULT_WORLD_MAP_EXPORT_PATH = "exportmap.jpg"; private static readonly UUID STOP_UUID = UUID.Random(); - private static readonly string m_mapLayerPath = "0001/"; + + private OpenSim.Framework.BlockingQueue requests = new OpenSim.Framework.BlockingQueue(); + + private ManualResetEvent m_mapBlockRequestEvent = new ManualResetEvent(false); + private Dictionary> m_mapBlockRequests = new Dictionary>(); private IMapImageGenerator m_mapImageGenerator; private IMapImageUploadModule m_mapImageServiceModule; - private OpenSim.Framework.BlockingQueue requests = new OpenSim.Framework.BlockingQueue(); - protected Scene m_scene; private List cachedMapBlocks = new List(); - private int cachedTime = 0; - private int blacklistTimeout = 10*60*1000; // 10 minutes private byte[] myMapImageJPEG; protected volatile bool m_Enabled = false; - private Dictionary m_openRequests = new Dictionary(); - private Dictionary m_blacklistedurls = new Dictionary(); - private Dictionary m_blacklistedregions = new Dictionary(); - private Dictionary m_cachedRegionMapItemsAddress = new Dictionary(); + private ExpiringCache m_blacklistedurls = new ExpiringCache(); + private ExpiringCache m_blacklistedregions = new ExpiringCache(); + private ExpiringCache m_cachedRegionMapItemsAddress = new ExpiringCache(); + private ExpiringCache m_cachedRegionMapItemsResponses = + new ExpiringCache(); private List m_rootAgents = new List(); private volatile bool threadrunning = false; - - private IServiceThrottleModule m_ServiceThrottle; - + // expire time for the blacklists in seconds + private double expireBlackListTime = 600.0; // 10 minutes + // expire mapItems responses time in seconds. Throttles requests to regions that do answer + private const double expireResponsesTime = 120.0; // 2 minutes ? //private int CacheRegionsDistance = 256; #region INonSharedRegionModule Members - public virtual void Initialise (IConfigSource config) + public virtual void Initialise(IConfigSource config) { string[] configSections = new string[] { "Map", "Startup" }; @@ -99,8 +101,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap config, "WorldMapModule", configSections, "WorldMap") == "WorldMap") m_Enabled = true; - blacklistTimeout - = Util.GetConfigVarFromSections(config, "BlacklistTimeout", configSections, 10 * 60) * 1000; + expireBlackListTime = (double)Util.GetConfigVarFromSections(config, "BlacklistTimeout", configSections, 10 * 60); } public virtual void AddRegion(Scene scene) @@ -128,7 +129,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap } } - public virtual void RemoveRegion (Scene scene) + public virtual void RemoveRegion(Scene scene) { if (!m_Enabled) return; @@ -141,13 +142,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap } } - public virtual void RegionLoaded (Scene scene) + public virtual void RegionLoaded(Scene scene) { if (!m_Enabled) return; - m_ServiceThrottle = scene.RequestModuleInterface(); - m_mapImageGenerator = m_scene.RequestModuleInterface(); m_mapImageServiceModule = m_scene.RequestModuleInterface(); } @@ -177,16 +176,20 @@ namespace OpenSim.Region.CoreModules.World.WorldMap regionimage = regionimage.Replace("-", ""); m_log.Info("[WORLD MAP]: JPEG Map location: " + m_scene.RegionInfo.ServerURI + "index.php?method=" + regionimage); +/* MainServer.Instance.AddHTTPHandler(regionimage, new GenericHTTPDOSProtector(OnHTTPGetMapImage, OnHTTPThrottled, new BasicDosProtectorOptions() - { - AllowXForwardedFor = false, - ForgetTimeSpan = TimeSpan.FromMinutes(2), - MaxRequestsInTimeframe = 4, - ReportingName = "MAPDOSPROTECTOR", - RequestTimeSpan = TimeSpan.FromSeconds(10), - ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod - }).Process); + { + AllowXForwardedFor = false, + ForgetTimeSpan = TimeSpan.FromMinutes(2), + MaxRequestsInTimeframe = 4, + ReportingName = "MAPDOSPROTECTOR", + RequestTimeSpan = TimeSpan.FromSeconds(10), + ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod + }).Process); +*/ + + MainServer.Instance.AddHTTPHandler(regionimage, OnHTTPGetMapImage); MainServer.Instance.AddLLSDHandler( "/MAP/MapItems/" + m_scene.RegionInfo.RegionHandle.ToString(), HandleRemoteMapItemRequest); @@ -197,13 +200,13 @@ namespace OpenSim.Region.CoreModules.World.WorldMap m_scene.EventManager.OnMakeRootAgent += MakeRootAgent; m_scene.EventManager.OnRegionUp += OnRegionUp; -// StartThread(new object()); + StartThread(new object()); } // this has to be called with a lock on m_scene protected virtual void RemoveHandlers() { -// StopThread(); + StopThread(); m_scene.EventManager.OnRegionUp -= OnRegionUp; m_scene.EventManager.OnMakeRootAgent -= MakeRootAgent; @@ -212,6 +215,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap m_scene.EventManager.OnNewClient -= OnNewClient; m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps; + m_scene.UnregisterModuleInterface(this); + string regionimage = "regionImage" + m_scene.RegionInfo.RegionID.ToString(); regionimage = regionimage.Replace("-", ""); MainServer.Instance.RemoveLLSDHandler("/MAP/MapItems/" + m_scene.RegionInfo.RegionHandle.ToString(), @@ -222,12 +227,12 @@ namespace OpenSim.Region.CoreModules.World.WorldMap public void OnRegisterCaps(UUID agentID, Caps caps) { //m_log.DebugFormat("[WORLD MAP]: OnRegisterCaps: agentID {0} caps {1}", agentID, caps); - string capsBase = "/CAPS/" + caps.CapsObjectPath; + string capspath = "/CAPS/" + UUID.Random(); caps.RegisterHandler( "MapLayer", new RestStreamHandler( "POST", - capsBase + m_mapLayerPath, + capspath, (request, path, param, httpRequest, httpResponse) => MapLayerRequest(request, path, param, agentID, caps), "MapLayer", @@ -246,6 +251,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap public string MapLayerRequest(string request, string path, string param, UUID agentID, Caps caps) { + // not sure about this.... + //try // //m_log.DebugFormat("[MAPLAYER]: path: {0}, param: {1}, agent:{2}", @@ -261,54 +268,54 @@ namespace OpenSim.Region.CoreModules.World.WorldMap // 6/8/2011 -- I'm adding an explicit 2048 check, so that we never forget that there is // a hack here, and so that regions below 4096 don't get spammed with unnecessary map blocks. - if (m_scene.RegionInfo.RegionLocX >= 2048 || m_scene.RegionInfo.RegionLocY >= 2048) - { - ScenePresence avatarPresence = null; - - m_scene.TryGetScenePresence(agentID, out avatarPresence); - - if (avatarPresence != null) - { - bool lookup = false; - - lock (cachedMapBlocks) - { - if (cachedMapBlocks.Count > 0 && ((cachedTime + 1800) > Util.UnixTimeSinceEpoch())) - { - List mapBlocks; - - mapBlocks = cachedMapBlocks; - avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); - } - else - { - lookup = true; - } - } - if (lookup) - { - List mapBlocks = new List(); ; - - // Get regions that are within 8 regions of here - List regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, - (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX - 8), - (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX + 8), - (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY - 8), - (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY + 8) ); - foreach (GridRegion r in regions) - { - MapBlockData block = MapBlockFromGridRegion(r, 0); - mapBlocks.Add(block); - } - avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); - - lock (cachedMapBlocks) - cachedMapBlocks = mapBlocks; - - cachedTime = Util.UnixTimeSinceEpoch(); - } - } - } + //if (m_scene.RegionInfo.RegionLocX >= 2048 || m_scene.RegionInfo.RegionLocY >= 2048) + //{ + // ScenePresence avatarPresence = null; + + // m_scene.TryGetScenePresence(agentID, out avatarPresence); + + // if (avatarPresence != null) + // { + // bool lookup = false; + + // lock (cachedMapBlocks) + // { + // if (cachedMapBlocks.Count > 0 && ((cachedTime + 1800) > Util.UnixTimeSinceEpoch())) + // { + // List mapBlocks; + + // mapBlocks = cachedMapBlocks; + // avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); + // } + // else + // { + // lookup = true; + // } + // } + // if (lookup) + // { + // List mapBlocks = new List(); ; + + // List regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, + // (int)(m_scene.RegionInfo.RegionLocX - 8) * (int)Constants.RegionSize, + // (int)(m_scene.RegionInfo.RegionLocX + 8) * (int)Constants.RegionSize, + // (int)(m_scene.RegionInfo.RegionLocY - 8) * (int)Constants.RegionSize, + // (int)(m_scene.RegionInfo.RegionLocY + 8) * (int)Constants.RegionSize); + // foreach (GridRegion r in regions) + // { + // MapBlockData block = new MapBlockData(); + // MapBlockFromGridRegion(block, r, 0); + // mapBlocks.Add(block); + // } + // avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); + + // lock (cachedMapBlocks) + // cachedMapBlocks = mapBlocks; + + // cachedTime = Util.UnixTimeSinceEpoch(); + // } + // } + //} LLSDMapLayerResponse mapResponse = new LLSDMapLayerResponse(); mapResponse.LayerData.Array.Add(GetOSDMapLayerResponse()); @@ -334,9 +341,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap /// protected static OSDMapLayer GetOSDMapLayerResponse() { + // not sure about this.... 2048 or master 5000 and hack above? + OSDMapLayer mapLayer = new OSDMapLayer(); - mapLayer.Right = 5000; - mapLayer.Top = 5000; + mapLayer.Right = 2048; + mapLayer.Top = 2048; mapLayer.ImageID = new UUID("00000000-0000-1111-9999-000000000006"); return mapLayer; @@ -365,6 +374,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap { m_rootAgents.Remove(AgentId); } + lock (m_mapBlockRequestEvent) + { + if (m_mapBlockRequests.ContainsKey(AgentId)) + m_mapBlockRequests.Remove(AgentId); + } } #endregion @@ -379,14 +393,20 @@ namespace OpenSim.Region.CoreModules.World.WorldMap if (threadrunning) return; threadrunning = true; -// m_log.Debug("[WORLD MAP]: Starting remote MapItem request thread"); + // m_log.Debug("[WORLD MAP]: Starting remote MapItem request thread"); WorkManager.StartThread( process, string.Format("MapItemRequestThread ({0})", m_scene.RegionInfo.RegionName), ThreadPriority.BelowNormal, true, - true); + false); + WorkManager.StartThread( + MapBlockSendThread, + string.Format("MapBlockSendThread ({0})", m_scene.RegionInfo.RegionName), + ThreadPriority.BelowNormal, + true, + false); } /// @@ -396,13 +416,29 @@ namespace OpenSim.Region.CoreModules.World.WorldMap { MapRequestState st = new MapRequestState(); st.agentID = STOP_UUID; - st.EstateID=0; - st.flags=0; - st.godlike=false; - st.itemtype=0; - st.regionhandle=0; + st.EstateID = 0; + st.flags = 0; + st.godlike = false; + st.itemtype = 0; + st.regionhandle = 0; requests.Enqueue(st); + + MapBlockRequestData req = new MapBlockRequestData(); + + req.client = null; + req.minX = 0; + req.maxX = 0; + req.minY = 0; + req.maxY = 0; + req.flags = 0; + + lock (m_mapBlockRequestEvent) + { + m_mapBlockRequests[UUID.Zero] = new Queue(); + m_mapBlockRequests[UUID.Zero].Enqueue(req); + m_mapBlockRequestEvent.Set(); + } } public virtual void HandleMapItemRequest(IClientAPI remoteClient, uint flags, @@ -415,315 +451,371 @@ namespace OpenSim.Region.CoreModules.World.WorldMap if (!m_rootAgents.Contains(remoteClient.AgentId)) return; } + + // local or remote request? + if (regionhandle != 0 && regionhandle != m_scene.RegionInfo.RegionHandle) + { + // its Remote Map Item Request + // ensures that the blockingqueue doesn't get borked if the GetAgents() timing changes. + RequestMapItems("", remoteClient.AgentId, flags, EstateID, godlike, itemtype, regionhandle); + return; + } + uint xstart = 0; uint ystart = 0; Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle, out xstart, out ystart); - if (itemtype == (int)GridItemType.AgentLocations) + + // its about this region... + + List mapitems = new List(); + mapItemReply mapitem = new mapItemReply(); + + // viewers only ask for green dots to each region now + // except at login with regionhandle 0 + // possible on some other rare ocasions + // use previus hack of sending all items with the green dots + + bool adultRegion; + if (regionhandle == 0) { - if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) + switch (itemtype) { - // Just requesting map info about the current, local region - int tc = Environment.TickCount; - List mapitems = new List(); - mapItemReply mapitem = new mapItemReply(); - if (m_scene.GetRootAgentCount() <= 1) - { - mapitem = new mapItemReply( + case (int)GridItemType.AgentLocations: + // Service 6 right now (MAP_ITEM_AGENTS_LOCATION; green dots) + + int tc = Environment.TickCount; + if (m_scene.GetRootAgentCount() <= 1) + { + mapitem = new mapItemReply( xstart + 1, ystart + 1, UUID.Zero, Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()), 0, 0); - mapitems.Add(mapitem); - } - else - { - m_scene.ForEachRootScenePresence(delegate(ScenePresence sp) + mapitems.Add(mapitem); + } + else { + m_scene.ForEachRootScenePresence(delegate (ScenePresence sp) + { // Don't send a green dot for yourself if (sp.UUID != remoteClient.AgentId) - { - mapitem = new mapItemReply( + { + mapitem = new mapItemReply( xstart + (uint)sp.AbsolutePosition.X, ystart + (uint)sp.AbsolutePosition.Y, UUID.Zero, Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()), 1, 0); - mapitems.Add(mapitem); - } - }); - } - remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags); - } - else - { - // Remote Map Item Request + mapitems.Add(mapitem); + } + }); + } + remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags); + break; - // ensures that the blockingqueue doesn't get borked if the GetAgents() timing changes. - RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle); - } - } - else if (itemtype == (int)GridItemType.LandForSale) // Service 7 (MAP_ITEM_LAND_FOR_SALE) - { - if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) - { - // Parcels - ILandChannel landChannel = m_scene.LandChannel; - List parcels = landChannel.AllParcels(); - - // Local Map Item Request - List mapitems = new List(); - mapItemReply mapitem = new mapItemReply(); - if ((parcels != null) && (parcels.Count >= 1)) - { - foreach (ILandObject parcel_interface in parcels) + case (int)GridItemType.Telehub: + // Service 1 (MAP_ITEM_TELEHUB) + + SceneObjectGroup sog = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject); + if (sog != null) { - // Play it safe - if (!(parcel_interface is LandObject)) - continue; + mapitem = new mapItemReply( + xstart + (uint)sog.AbsolutePosition.X, + ystart + (uint)sog.AbsolutePosition.Y, + UUID.Zero, + sog.Name, + 0, // color (not used) + 0 // 0 = telehub / 1 = infohub + ); + mapitems.Add(mapitem); + remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags); + } + break; - LandObject land = (LandObject)parcel_interface; - LandData parcel = land.LandData; + case (int)GridItemType.AdultLandForSale: + case (int)GridItemType.LandForSale: - // Show land for sale - if ((parcel.Flags & (uint)ParcelFlags.ForSale) == (uint)ParcelFlags.ForSale) - { - Vector3 min = parcel.AABBMin; - Vector3 max = parcel.AABBMax; - float x = (min.X+max.X)/2; - float y = (min.Y+max.Y)/2; + // Service 7 (MAP_ITEM_LAND_FOR_SALE) + adultRegion = m_scene.RegionInfo.RegionSettings.Maturity == 2; + if (adultRegion) + { + if (itemtype == (int)GridItemType.LandForSale) + break; + } + else + { + if (itemtype == (int)GridItemType.AdultLandForSale) + break; + } + + // Parcels + ILandChannel landChannel = m_scene.LandChannel; + List parcels = landChannel.AllParcels(); - mapitem = new mapItemReply( + if ((parcels != null) && (parcels.Count >= 1)) + { + foreach (ILandObject parcel_interface in parcels) + { + // Play it safe + if (!(parcel_interface is LandObject)) + continue; + + LandObject land = (LandObject)parcel_interface; + LandData parcel = land.LandData; + + // Show land for sale + if ((parcel.Flags & (uint)ParcelFlags.ForSale) == (uint)ParcelFlags.ForSale) + { + Vector3 min = parcel.AABBMin; + Vector3 max = parcel.AABBMax; + float x = (min.X + max.X) / 2; + float y = (min.Y + max.Y) / 2; + mapitem = new mapItemReply( xstart + (uint)x, ystart + (uint)y, parcel.GlobalID, parcel.Name, parcel.Area, parcel.SalePrice - ); - mapitems.Add(mapitem); + ); + mapitems.Add(mapitem); + } } } - } - remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags); - } - else - { - // Remote Map Item Request + remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags); + break; - // ensures that the blockingqueue doesn't get borked if the GetAgents() timing changes. - RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle); + case (uint)GridItemType.PgEvent: + case (uint)GridItemType.MatureEvent: + case (uint)GridItemType.AdultEvent: + case (uint)GridItemType.Classified: + case (uint)GridItemType.Popular: + // TODO + // just dont not cry about them + break; + + default: + // unkown map item type + m_log.DebugFormat("[WORLD MAP]: Unknown MapItem type {1}", itemtype); + break; } } - else if (itemtype == (int)GridItemType.Telehub) // Service 1 (MAP_ITEM_TELEHUB) + else { - if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) - { - List mapitems = new List(); - mapItemReply mapitem = new mapItemReply(); + // send all items till we get a better fix - SceneObjectGroup sog = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject); - if (sog != null) - { - mapitem = new mapItemReply( - xstart + (uint)sog.AbsolutePosition.X, - ystart + (uint)sog.AbsolutePosition.Y, - UUID.Zero, - sog.Name, - 0, // color (not used) - 0 // 0 = telehub / 1 = infohub - ); - mapitems.Add(mapitem); + // Service 6 right now (MAP_ITEM_AGENTS_LOCATION; green dots) - remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags); - } + int tc = Environment.TickCount; + if (m_scene.GetRootAgentCount() <= 1) + { + mapitem = new mapItemReply( + xstart + 1, + ystart + 1, + UUID.Zero, + Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()), + 0, 0); + mapitems.Add(mapitem); } else { - // Remote Map Item Request - RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle); + m_scene.ForEachRootScenePresence(delegate (ScenePresence sp) + { + // Don't send a green dot for yourself + if (sp.UUID != remoteClient.AgentId) + { + mapitem = new mapItemReply( + xstart + (uint)sp.AbsolutePosition.X, + ystart + (uint)sp.AbsolutePosition.Y, + UUID.Zero, + Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()), + 1, 0); + mapitems.Add(mapitem); + } + }); } - } - } + remoteClient.SendMapItemReply(mapitems.ToArray(), 6, flags); + mapitems.Clear(); - private int nAsyncRequests = 0; - /// - /// Processing thread main() loop for doing remote mapitem requests - /// - public void process() - { - //const int MAX_ASYNC_REQUESTS = 20; - try - { - while (true) + // Service 1 (MAP_ITEM_TELEHUB) + + SceneObjectGroup sog = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject); + if (sog != null) { - MapRequestState st = requests.Dequeue(1000); + mapitem = new mapItemReply( + xstart + (uint)sog.AbsolutePosition.X, + ystart + (uint)sog.AbsolutePosition.Y, + UUID.Zero, + sog.Name, + 0, // color (not used) + 0 // 0 = telehub / 1 = infohub + ); + mapitems.Add(mapitem); + remoteClient.SendMapItemReply(mapitems.ToArray(), 1, flags); + mapitems.Clear(); + } - // end gracefully - if (st.agentID == STOP_UUID) - break; + // Service 7 (MAP_ITEM_LAND_FOR_SALE) + + uint its = 7; + if (m_scene.RegionInfo.RegionSettings.Maturity == 2) + its = 10; + + // Parcels + ILandChannel landChannel = m_scene.LandChannel; + List parcels = landChannel.AllParcels(); - if (st.agentID != UUID.Zero) + if ((parcels != null) && (parcels.Count >= 1)) + { + foreach (ILandObject parcel_interface in parcels) { - bool dorequest = true; - lock (m_rootAgents) - { - if (!m_rootAgents.Contains(st.agentID)) - dorequest = false; - } + // Play it safe + if (!(parcel_interface is LandObject)) + continue; + + LandObject land = (LandObject)parcel_interface; + LandData parcel = land.LandData; - if (dorequest && !m_blacklistedregions.ContainsKey(st.regionhandle)) + // Show land for sale + if ((parcel.Flags & (uint)ParcelFlags.ForSale) == (uint)ParcelFlags.ForSale) { - while (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break - Thread.Sleep(80); - - RequestMapItemsDelegate d = RequestMapItemsAsync; - d.BeginInvoke(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle, RequestMapItemsCompleted, null); - //OSDMap response = RequestMapItemsAsync(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle); - //RequestMapItemsCompleted(response); - Interlocked.Increment(ref nAsyncRequests); + Vector3 min = parcel.AABBMin; + Vector3 max = parcel.AABBMax; + float x = (min.X + max.X) / 2; + float y = (min.Y + max.Y) / 2; + mapitem = new mapItemReply( + xstart + (uint)x, + ystart + (uint)y, + parcel.GlobalID, + parcel.Name, + parcel.Area, + parcel.SalePrice + ); + mapitems.Add(mapitem); } } - - Watchdog.UpdateThread(); + if(mapitems.Count >0) + remoteClient.SendMapItemReply(mapitems.ToArray(), its, flags); + mapitems.Clear(); } } - catch (Exception e) - { - m_log.ErrorFormat("[WORLD MAP]: Map item request thread terminated abnormally with exception {0}", e); - } - - threadrunning = false; - Watchdog.RemoveThread(); } - const int MAX_ASYNC_REQUESTS = 20; - + private int nAsyncRequests = 0; /// - /// Enqueues the map item request into the services throttle processing thread + /// Processing thread main() loop for doing remote mapitem requests /// - /// - public void EnqueueMapItemRequest(MapRequestState st) + public void process() { + const int MAX_ASYNC_REQUESTS = 20; + ScenePresence av = null; + MapRequestState st = null; - m_ServiceThrottle.Enqueue("map-item", st.regionhandle.ToString() + st.agentID.ToString(), delegate + try { - if (st.agentID != UUID.Zero) + while (true) { - bool dorequest = true; - lock (m_rootAgents) - { - if (!m_rootAgents.Contains(st.agentID)) - dorequest = false; - } + av = null; + st = null; - if (dorequest && !m_blacklistedregions.ContainsKey(st.regionhandle)) - { - if (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break - { - // AH!!! Recursive ! - // Put this request back in the queue and return - EnqueueMapItemRequest(st); - return; - } + st = requests.Dequeue(4500); + Watchdog.UpdateThread(); - RequestMapItemsDelegate d = RequestMapItemsAsync; - d.BeginInvoke(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle, RequestMapItemsCompleted, null); - //OSDMap response = RequestMapItemsAsync(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle); - //RequestMapItemsCompleted(response); - Interlocked.Increment(ref nAsyncRequests); - } - } - }); - } + if (st == null || st.agentID == UUID.Zero) + continue; - /// - /// Sends the mapitem response to the IClientAPI - /// - /// The OSDMap Response for the mapitem - private void RequestMapItemsCompleted(IAsyncResult iar) - { - AsyncResult result = (AsyncResult)iar; - RequestMapItemsDelegate icon = (RequestMapItemsDelegate)result.AsyncDelegate; + // end gracefully + if (st.agentID == STOP_UUID) + break; - OSDMap response = (OSDMap)icon.EndInvoke(iar); + // agent gone? - Interlocked.Decrement(ref nAsyncRequests); + m_scene.TryGetScenePresence(st.agentID, out av); + if (av == null || av.IsChildAgent || av.IsDeleted || av.IsInTransit) + continue; - if (!response.ContainsKey("requestID")) - return; + // region unreachable? + if (m_blacklistedregions.Contains(st.regionhandle)) + continue; - UUID requestID = response["requestID"].AsUUID(); + bool dorequest = true; + OSDMap responseMap = null; - if (requestID != UUID.Zero) - { - MapRequestState mrs = new MapRequestState(); - mrs.agentID = UUID.Zero; - lock (m_openRequests) - { - if (m_openRequests.ContainsKey(requestID)) + // check if we are already serving this region + lock (m_cachedRegionMapItemsResponses) { - mrs = m_openRequests[requestID]; - m_openRequests.Remove(requestID); + if (m_cachedRegionMapItemsResponses.Contains(st.regionhandle)) + { + m_cachedRegionMapItemsResponses.TryGetValue(st.regionhandle, out responseMap); + dorequest = false; + } + else + m_cachedRegionMapItemsResponses.Add(st.regionhandle, null, expireResponsesTime); // a bit more time for the access } - } - if (mrs.agentID != UUID.Zero) - { - ScenePresence av = null; - m_scene.TryGetScenePresence(mrs.agentID, out av); - if (av != null) + if (dorequest) { - if (response.ContainsKey(mrs.itemtype.ToString())) + // nothig for region, fire a request + Interlocked.Increment(ref nAsyncRequests); + MapRequestState rst = st; + Util.FireAndForget(x => { - List returnitems = new List(); - OSDArray itemarray = (OSDArray)response[mrs.itemtype.ToString()]; - for (int i = 0; i < itemarray.Count; i++) - { - OSDMap mapitem = (OSDMap)itemarray[i]; - mapItemReply mi = new mapItemReply(); - mi.FromOSD(mapitem); - returnitems.Add(mi); - } - av.ControllingClient.SendMapItemReply(returnitems.ToArray(), mrs.itemtype, mrs.flags); - } - - // Service 7 (MAP_ITEM_LAND_FOR_SALE) - uint itemtype = (uint)GridItemType.LandForSale; - - if (response.ContainsKey(itemtype.ToString())) + RequestMapItemsAsync(rst.agentID, rst.flags, rst.EstateID, rst.godlike, rst.itemtype, rst.regionhandle); + }); + } + else + { + // do we have the response? + if (responseMap != null) { - List returnitems = new List(); - OSDArray itemarray = (OSDArray)response[itemtype.ToString()]; - for (int i = 0; i < itemarray.Count; i++) + if(av!=null) { - OSDMap mapitem = (OSDMap)itemarray[i]; - mapItemReply mi = new mapItemReply(); - mi.FromOSD(mapitem); - returnitems.Add(mi); + // this will mainly only send green dots now + if (responseMap.ContainsKey(st.itemtype.ToString())) + { + List returnitems = new List(); + OSDArray itemarray = (OSDArray)responseMap[st.itemtype.ToString()]; + for (int i = 0; i < itemarray.Count; i++) + { + OSDMap mapitem = (OSDMap)itemarray[i]; + mapItemReply mi = new mapItemReply(); + mi.x = (uint)mapitem["X"].AsInteger(); + mi.y = (uint)mapitem["Y"].AsInteger(); + mi.id = mapitem["ID"].AsUUID(); + mi.Extra = mapitem["Extra"].AsInteger(); + mi.Extra2 = mapitem["Extra2"].AsInteger(); + mi.name = mapitem["Name"].AsString(); + returnitems.Add(mi); + } + av.ControllingClient.SendMapItemReply(returnitems.ToArray(), st.itemtype, st.flags & 0xffff); + } } - av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags); } - - // Service 1 (MAP_ITEM_TELEHUB) - itemtype = (uint)GridItemType.Telehub; - - if (response.ContainsKey(itemtype.ToString())) + else { - List returnitems = new List(); - OSDArray itemarray = (OSDArray)response[itemtype.ToString()]; - for (int i = 0; i < itemarray.Count; i++) - { - OSDMap mapitem = (OSDMap)itemarray[i]; - mapItemReply mi = new mapItemReply(); - mi.FromOSD(mapitem); - returnitems.Add(mi); - } - av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags); + // request still beeing processed, enqueue it back + requests.Enqueue(st); + if (requests.Count() < 3) + Thread.Sleep(100); } } + + while (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break + { + Thread.Sleep(100); + Watchdog.UpdateThread(); + } } } + + catch (Exception e) + { + m_log.ErrorFormat("[WORLD MAP]: Map item request thread terminated abnormally with exception {0}", e); + } + + threadrunning = false; + Watchdog.RemoveThread(); } /// @@ -746,11 +838,12 @@ namespace OpenSim.Region.CoreModules.World.WorldMap st.godlike = godlike; st.itemtype = itemtype; st.regionhandle = regionhandle; - EnqueueMapItemRequest(st); + + requests.Enqueue(st); } - private delegate OSDMap RequestMapItemsDelegate(UUID id, uint flags, - uint EstateID, bool godlike, uint itemtype, ulong regionhandle); + uint[] itemTypesForcedSend = new uint[] { 6, 1, 7, 10 }; // green dots, infohub, land sells + /// /// Does the actual remote mapitem request /// This should be called from an asynchronous thread @@ -765,94 +858,55 @@ namespace OpenSim.Region.CoreModules.World.WorldMap /// passed in from packet /// Region we're looking up /// - private OSDMap RequestMapItemsAsync(UUID id, uint flags, + private void RequestMapItemsAsync(UUID id, uint flags, uint EstateID, bool godlike, uint itemtype, ulong regionhandle) { -// m_log.DebugFormat("[WORLDMAP]: RequestMapItemsAsync; region handle: {0} {1}", regionhandle, itemtype); + // m_log.DebugFormat("[WORLDMAP]: RequestMapItemsAsync; region handle: {0} {1}", regionhandle, itemtype); string httpserver = ""; bool blacklisted = false; - lock (m_blacklistedregions) - { - if (m_blacklistedregions.ContainsKey(regionhandle)) - { - if (Environment.TickCount > (m_blacklistedregions[regionhandle] + blacklistTimeout)) - { - m_log.DebugFormat("[WORLD MAP]: Unblock blacklisted region {0}", regionhandle); - m_blacklistedregions.Remove(regionhandle); - } - else - blacklisted = true; - } - } + lock (m_blacklistedregions) + blacklisted = m_blacklistedregions.Contains(regionhandle); if (blacklisted) - return new OSDMap(); + { + Interlocked.Decrement(ref nAsyncRequests); + return; + } UUID requestID = UUID.Random(); lock (m_cachedRegionMapItemsAddress) - { - if (m_cachedRegionMapItemsAddress.ContainsKey(regionhandle)) - httpserver = m_cachedRegionMapItemsAddress[regionhandle]; - } - if (httpserver.Length == 0) + m_cachedRegionMapItemsAddress.TryGetValue(regionhandle, out httpserver); + + if (httpserver == null || httpserver.Length == 0) { uint x = 0, y = 0; Util.RegionHandleToWorldLoc(regionhandle, out x, out y); + GridRegion mreg = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); if (mreg != null) { httpserver = mreg.ServerURI + "MAP/MapItems/" + regionhandle.ToString(); lock (m_cachedRegionMapItemsAddress) - { - if (!m_cachedRegionMapItemsAddress.ContainsKey(regionhandle)) - m_cachedRegionMapItemsAddress.Add(regionhandle, httpserver); - } - } - else - { - lock (m_blacklistedregions) - { - if (!m_blacklistedregions.ContainsKey(regionhandle)) - m_blacklistedregions.Add(regionhandle, Environment.TickCount); - } - //m_log.InfoFormat("[WORLD MAP]: Blacklisted region {0}", regionhandle.ToString()); + m_cachedRegionMapItemsAddress.AddOrUpdate(regionhandle, httpserver, 2.0 * expireBlackListTime); } } - blacklisted = false; lock (m_blacklistedurls) { - if (m_blacklistedurls.ContainsKey(httpserver)) + if (httpserver == null || httpserver.Length == 0 || m_blacklistedurls.Contains(httpserver)) { - if (Environment.TickCount > (m_blacklistedurls[httpserver] + blacklistTimeout)) - { - m_log.DebugFormat("[WORLD MAP]: Unblock blacklisted URL {0}", httpserver); + // Can't find the http server or its blocked + lock (m_blacklistedregions) + m_blacklistedregions.AddOrUpdate(regionhandle, 0, expireBlackListTime); - m_blacklistedurls.Remove(httpserver); - } - else - blacklisted = true; + Interlocked.Decrement(ref nAsyncRequests); + return; } } - // Can't find the http server - if (httpserver.Length == 0 || blacklisted) - return new OSDMap(); - - MapRequestState mrs = new MapRequestState(); - mrs.agentID = id; - mrs.EstateID = EstateID; - mrs.flags = flags; - mrs.godlike = godlike; - mrs.itemtype=itemtype; - mrs.regionhandle = regionhandle; - - lock (m_openRequests) - m_openRequests.Add(requestID, mrs); - WebRequest mapitemsrequest = null; try { @@ -861,132 +915,144 @@ namespace OpenSim.Region.CoreModules.World.WorldMap catch (Exception e) { m_log.DebugFormat("[WORLD MAP]: Access to {0} failed with {1}", httpserver, e); - return new OSDMap(); + Interlocked.Decrement(ref nAsyncRequests); + return; } mapitemsrequest.Method = "POST"; mapitemsrequest.ContentType = "application/xml+llsd"; - OSDMap RAMap = new OSDMap(); + OSDMap RAMap = new OSDMap(); // string RAMapString = RAMap.ToString(); OSD LLSDofRAMap = RAMap; // RENAME if this works byte[] buffer = OSDParser.SerializeLLSDXmlBytes(LLSDofRAMap); + OSDMap responseMap = new OSDMap(); - responseMap["requestID"] = OSD.FromUUID(requestID); - Stream os = null; try { // send the Post mapitemsrequest.ContentLength = buffer.Length; //Count bytes to send - os = mapitemsrequest.GetRequestStream(); - os.Write(buffer, 0, buffer.Length); //Send it - //m_log.DebugFormat("[WORLD MAP]: Getting MapItems from {0}", httpserver); + using (Stream os = mapitemsrequest.GetRequestStream()) + os.Write(buffer, 0, buffer.Length); //Send it + //m_log.DebugFormat("[WORLD MAP]: Getting MapItems from {0}", httpserver); } catch (WebException ex) { m_log.WarnFormat("[WORLD MAP]: Bad send on GetMapItems {0}", ex.Message); - responseMap["connect"] = OSD.FromBoolean(false); + m_log.WarnFormat("[WORLD MAP]: Blacklisted url {0}", httpserver); lock (m_blacklistedurls) - { - if (!m_blacklistedurls.ContainsKey(httpserver)) - m_blacklistedurls.Add(httpserver, Environment.TickCount); - } - - m_log.WarnFormat("[WORLD MAP]: Blacklisted {0}", httpserver); + m_blacklistedurls.AddOrUpdate(httpserver, 0, expireBlackListTime); + lock (m_blacklistedregions) + m_blacklistedregions.AddOrUpdate(regionhandle, 0, expireBlackListTime); - return responseMap; + Interlocked.Decrement(ref nAsyncRequests); + return; } catch { m_log.DebugFormat("[WORLD MAP]: RequestMapItems failed for {0}", httpserver); - responseMap["connect"] = OSD.FromBoolean(false); - return responseMap; - } - finally - { - if (os != null) - os.Dispose(); + Interlocked.Decrement(ref nAsyncRequests); + return; } string response_mapItems_reply = null; - { + { // get the response try { using (WebResponse webResponse = mapitemsrequest.GetResponse()) { if (webResponse != null) { - using (Stream s = webResponse.GetResponseStream()) - using (StreamReader sr = new StreamReader(s)) - response_mapItems_reply = sr.ReadToEnd().Trim(); + using (StreamReader sr = new StreamReader(webResponse.GetResponseStream())) + { + response_mapItems_reply = sr.ReadToEnd().Trim(); + } } else { - return new OSDMap(); - } + Interlocked.Decrement(ref nAsyncRequests); + return; } + } } catch (WebException) { - responseMap["connect"] = OSD.FromBoolean(false); lock (m_blacklistedurls) - { - if (!m_blacklistedurls.ContainsKey(httpserver)) - m_blacklistedurls.Add(httpserver, Environment.TickCount); - } + m_blacklistedurls.AddOrUpdate(httpserver, 0, expireBlackListTime); + lock (m_blacklistedregions) + m_blacklistedregions.AddOrUpdate(regionhandle, 0, expireBlackListTime); - m_log.WarnFormat("[WORLD MAP]: Blacklisted {0}", httpserver); + m_log.WarnFormat("[WORLD MAP]: Blacklisted url {0}", httpserver); - return responseMap; + Interlocked.Decrement(ref nAsyncRequests); + return; } catch { m_log.DebugFormat("[WORLD MAP]: RequestMapItems failed for {0}", httpserver); - responseMap["connect"] = OSD.FromBoolean(false); lock (m_blacklistedregions) - { - if (!m_blacklistedregions.ContainsKey(regionhandle)) - m_blacklistedregions.Add(regionhandle, Environment.TickCount); - } + m_blacklistedregions.AddOrUpdate(regionhandle, 0, expireBlackListTime); - return responseMap; + Interlocked.Decrement(ref nAsyncRequests); + return; } - OSD rezResponse = null; try { - rezResponse = OSDParser.DeserializeLLSDXml(response_mapItems_reply); - - responseMap = (OSDMap)rezResponse; - responseMap["requestID"] = OSD.FromUUID(requestID); + responseMap = (OSDMap)OSDParser.DeserializeLLSDXml(response_mapItems_reply); } catch (Exception ex) { m_log.InfoFormat("[WORLD MAP]: exception on parse of RequestMapItems reply from {0}: {1}", httpserver, ex.Message); - responseMap["connect"] = OSD.FromBoolean(false); - lock (m_blacklistedregions) - { - if (!m_blacklistedregions.ContainsKey(regionhandle)) - m_blacklistedregions.Add(regionhandle, Environment.TickCount); - } + m_blacklistedregions.AddOrUpdate(regionhandle, 0, expireBlackListTime); - return responseMap; + Interlocked.Decrement(ref nAsyncRequests); + return; } } - if (!responseMap.ContainsKey(itemtype.ToString())) // remote sim doesnt have the stated region handle + // cache the response that may include other valid items + lock (m_cachedRegionMapItemsResponses) + m_cachedRegionMapItemsResponses.AddOrUpdate(regionhandle, responseMap, expireResponsesTime); + + flags &= 0xffff; + + if (id != UUID.Zero) { - m_log.DebugFormat("[WORLD MAP]: Remote sim does not have the stated region. Blacklisting."); - lock (m_blacklistedregions) + ScenePresence av = null; + m_scene.TryGetScenePresence(id, out av); + if (av != null && !av.IsChildAgent && !av.IsDeleted && !av.IsInTransit) { - if (!m_blacklistedregions.ContainsKey(regionhandle)) - m_blacklistedregions.Add(regionhandle, Environment.TickCount); + // send all the items or viewers will never ask for them, except green dots + foreach (uint itfs in itemTypesForcedSend) + { + if (responseMap.ContainsKey(itfs.ToString())) + { + List returnitems = new List(); +// OSDArray itemarray = (OSDArray)responseMap[itemtype.ToString()]; + OSDArray itemarray = (OSDArray)responseMap[itfs.ToString()]; + for (int i = 0; i < itemarray.Count; i++) + { + OSDMap mapitem = (OSDMap)itemarray[i]; + mapItemReply mi = new mapItemReply(); + mi.x = (uint)mapitem["X"].AsInteger(); + mi.y = (uint)mapitem["Y"].AsInteger(); + mi.id = mapitem["ID"].AsUUID(); + mi.Extra = mapitem["Extra"].AsInteger(); + mi.Extra2 = mapitem["Extra2"].AsInteger(); + mi.name = mapitem["Name"].AsString(); + returnitems.Add(mi); + } +// av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, flags); + av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itfs, flags); + } + } } } - return responseMap; + Interlocked.Decrement(ref nAsyncRequests); } /// @@ -996,87 +1062,196 @@ namespace OpenSim.Region.CoreModules.World.WorldMap /// /// /// - public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) + public void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) { - if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible +// m_log.DebugFormat("[WoldMapModule] RequestMapBlocks {0}={1}={2}={3} {4}", minX, minY, maxX, maxY, flag); + + GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); + } + + private const double SPAMBLOCKTIMEms = 300000; // 5 minutes + private Dictionary spamBlocked = new Dictionary(); + + protected virtual List GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) + { + // anti spam because of FireStorm 4.7.7 absurd request repeat rates + // possible others + + double now = Util.GetTimeStampMS(); + UUID agentID = remoteClient.AgentId; + + lock (m_mapBlockRequestEvent) { - List response = new List(); - - // this should return one mapblock at most. It is triggered by a click - // on an unloaded square. - // But make sure: Look whether the one we requested is in there - List regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, - (int)Util.RegionToWorldLoc((uint)minX), (int)Util.RegionToWorldLoc((uint)maxX), - (int)Util.RegionToWorldLoc((uint)minY), (int)Util.RegionToWorldLoc((uint)maxY) ); - - m_log.DebugFormat("[WORLD MAP MODULE] RequestMapBlocks min=<{0},{1}>, max=<{2},{3}>, flag={4}, cntFound={5}", - minX, minY, maxX, maxY, flag.ToString("X"), regions.Count); - if (regions != null) + if(spamBlocked.ContainsKey(agentID)) { - foreach (GridRegion r in regions) + if(spamBlocked[agentID] < now && + (!m_mapBlockRequests.ContainsKey(agentID) || + m_mapBlockRequests[agentID].Count == 0 )) { - if (r.RegionLocX == Util.RegionToWorldLoc((uint)minX) - && r.RegionLocY == Util.RegionToWorldLoc((uint)minY) ) + spamBlocked.Remove(agentID); + m_log.DebugFormat("[WoldMapModule] RequestMapBlocks release spammer {0}", agentID); + } + else + return new List(); + } + else + { + // ugly slow expire spammers + if(spamBlocked.Count > 0) + { + UUID k = UUID.Zero; + bool expireone = false; + foreach(UUID k2 in spamBlocked.Keys) { - // found it => add it to response - // Version 2 viewers can handle the larger regions - if ((flag & 2) == 2) - response.AddRange(Map2BlockFromGridRegion(r, flag)); - else - response.Add(MapBlockFromGridRegion(r, flag)); - break; + if(spamBlocked[k2] < now && + (!m_mapBlockRequests.ContainsKey(k2) || + m_mapBlockRequests[k2].Count == 0 )) + { + m_log.DebugFormat("[WoldMapModule] RequestMapBlocks release spammer {0}", k2); + k = k2; + expireone = true; + } + break; // doing one at a time } + if(expireone) + spamBlocked.Remove(k); } } - if (response.Count == 0) +// m_log.DebugFormat("[WoldMapModule] RequestMapBlocks {0}={1}={2}={3} {4}", minX, minY, maxX, maxY, flag); + + MapBlockRequestData req = new MapBlockRequestData(); + + req.client = remoteClient; + req.minX = minX; + req.maxX = maxX; + req.minY = minY; + req.maxY = maxY; + req.flags = flag; + + if (!m_mapBlockRequests.ContainsKey(agentID)) + m_mapBlockRequests[agentID] = new Queue(); + if(m_mapBlockRequests[agentID].Count < 150 ) + m_mapBlockRequests[agentID].Enqueue(req); + else { - // response still empty => couldn't find the map-tile the user clicked on => tell the client - MapBlockData block = new MapBlockData(); - block.X = (ushort)minX; - block.Y = (ushort)minY; - block.Access = (byte)SimAccess.Down; // means 'simulator is offline' - // block.Access = (byte)SimAccess.NonExistent; - response.Add(block); + spamBlocked[agentID] = now + SPAMBLOCKTIMEms; + m_log.DebugFormat("[WoldMapModule] RequestMapBlocks blocking spammer {0} for {1} s",agentID, SPAMBLOCKTIMEms/1000.0); } - // The lower 16 bits are an unsigned int16 - remoteClient.SendMapBlock(response, flag & 0xffff); + m_mapBlockRequestEvent.Set(); } - else + + return new List(); + } + + protected void MapBlockSendThread() + { + List thisRunData = new List(); + while (true) { - // normal mapblock request. Use the provided values - GetAndSendBlocks(remoteClient, minX, minY, maxX, maxY, flag); + while(!m_mapBlockRequestEvent.WaitOne(4900)) + { + Watchdog.UpdateThread(); + if(m_scene == null) + return; + } + Watchdog.UpdateThread(); + lock (m_mapBlockRequestEvent) + { + int total = 0; + foreach (Queue q in m_mapBlockRequests.Values) + { + if (q.Count > 0) + thisRunData.Add(q.Dequeue()); + + total += q.Count; + } + + if (total == 0) + m_mapBlockRequestEvent.Reset(); + } + + if(thisRunData.Count > 0) + { + foreach (MapBlockRequestData req in thisRunData) + { + // Null client stops thread + if (req.client == null) + return; + + GetAndSendBlocksInternal(req.client, req.minX, req.minY, req.maxX, req.maxY, req.flags); + } + + thisRunData.Clear(); + } + + Thread.Sleep(50); } } - protected virtual List GetAndSendBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) + protected virtual List GetAndSendBlocksInternal(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) { + List allBlocks = new List(); List mapBlocks = new List(); List regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, - (int)Util.RegionToWorldLoc((uint)(minX - 4)), (int)Util.RegionToWorldLoc((uint)(maxX + 4)), - (int)Util.RegionToWorldLoc((uint)(minY - 4)), (int)Util.RegionToWorldLoc((uint)(maxY + 4)) ); - //m_log.DebugFormat("{0} GetAndSendBlocks. min=<{1},{2}>, max=<{3},{4}>, cntFound={5}", - // LogHeader, minX, minY, maxX, maxY, regions.Count); + minX * (int)Constants.RegionSize, + maxX * (int)Constants.RegionSize, + minY * (int)Constants.RegionSize, + maxY * (int)Constants.RegionSize); + + // only send a negative answer for a single region request + // corresponding to a click on the map. Current viewers + // keep displaying "loading.." without this + if (regions.Count == 0 && (flag & 0x10000) != 0 && minX == maxX && minY == maxY) + { + MapBlockData block = new MapBlockData(); + block.X = (ushort)minX; + block.Y = (ushort)minY; + block.MapImageId = UUID.Zero; + block.Access = (byte)SimAccess.NonExistent; + allBlocks.Add(block); + mapBlocks.Add(block); + remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); + return allBlocks; + } + + flag &= 0xffff; + foreach (GridRegion r in regions) { - // Version 2 viewers can handle the larger regions - if ((flag & 2) == 2) - mapBlocks.AddRange(Map2BlockFromGridRegion(r, flag)); - else - mapBlocks.Add(MapBlockFromGridRegion(r, flag)); + if (r == null) + continue; + MapBlockData block = new MapBlockData(); + MapBlockFromGridRegion(block, r, flag); + mapBlocks.Add(block); + allBlocks.Add(block); + + if (mapBlocks.Count >= 10) + { + remoteClient.SendMapBlock(mapBlocks, flag); + mapBlocks.Clear(); + Thread.Sleep(50); + } } - remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); + if (mapBlocks.Count > 0) + remoteClient.SendMapBlock(mapBlocks, flag); - return mapBlocks; + return allBlocks; } - // Fill a passed MapBlockData from a GridRegion - public MapBlockData MapBlockFromGridRegion(GridRegion r, uint flag) + public void MapBlockFromGridRegion(MapBlockData block, GridRegion r, uint flag) { - MapBlockData block = new MapBlockData(); + if (r == null) + { + // we should not get here ?? +// block.Access = (byte)SimAccess.Down; this is for a grid reply on r + block.Access = (byte)SimAccess.NonExistent; + block.MapImageId = UUID.Zero; + return; + } block.Access = r.Access; - switch (flag & 0xffff) + switch (flag) { case 0: block.MapImageId = r.TerrainImage; @@ -1089,50 +1264,13 @@ namespace OpenSim.Region.CoreModules.World.WorldMap break; } block.Name = r.RegionName; - block.X = (ushort)Util.WorldToRegionLoc((uint)r.RegionLocX); - block.Y = (ushort)Util.WorldToRegionLoc((uint)r.RegionLocY); - block.SizeX = (ushort) r.RegionSizeX; - block.SizeY = (ushort) r.RegionSizeY; + block.X = (ushort)(r.RegionLocX / Constants.RegionSize); + block.Y = (ushort)(r.RegionLocY / Constants.RegionSize); + block.SizeX = (ushort)r.RegionSizeX; + block.SizeY = (ushort)r.RegionSizeY; - return block; } - public List Map2BlockFromGridRegion(GridRegion r, uint flag) - { - List blocks = new List(); - MapBlockData block = new MapBlockData(); - if (r == null) - { - block.Access = (byte)SimAccess.Down; - block.MapImageId = UUID.Zero; - blocks.Add(block); - } - else - { - block.Access = r.Access; - switch (flag & 0xffff) - { - case 0: - block.MapImageId = r.TerrainImage; - break; - case 2: - block.MapImageId = r.ParcelImage; - break; - default: - block.MapImageId = UUID.Zero; - break; - } - block.Name = r.RegionName; - block.X = (ushort)(r.RegionLocX / Constants.RegionSize); - block.Y = (ushort)(r.RegionLocY / Constants.RegionSize); - block.SizeX = (ushort)r.RegionSizeX; - block.SizeY = (ushort)r.RegionSizeY; - blocks.Add(block); - } - return blocks; - } - - public Hashtable OnHTTPThrottled(Hashtable keysvals) { Hashtable reply = new Hashtable(); @@ -1145,67 +1283,71 @@ namespace OpenSim.Region.CoreModules.World.WorldMap public Hashtable OnHTTPGetMapImage(Hashtable keysvals) { - m_log.Debug("[WORLD MAP]: Sending map image jpeg"); Hashtable reply = new Hashtable(); int statuscode = 200; byte[] jpeg = new byte[0]; - if (myMapImageJPEG.Length == 0) + if (m_scene.RegionInfo.RegionSettings.TerrainImageID != UUID.Zero) { - MemoryStream imgstream = null; - Bitmap mapTexture = new Bitmap(1,1); - ManagedImage managedImage; - Image image = (Image)mapTexture; + m_log.Debug("[WORLD MAP]: Sending map image jpeg"); - try + if (myMapImageJPEG.Length == 0) { - // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular jpeg data + MemoryStream imgstream = null; + Bitmap mapTexture = new Bitmap(1, 1); + ManagedImage managedImage; + Image image = (Image)mapTexture; + + try + { + // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular jpeg data - imgstream = new MemoryStream(); + imgstream = new MemoryStream(); - // non-async because we know we have the asset immediately. - AssetBase mapasset = m_scene.AssetService.Get(m_scene.RegionInfo.RegionSettings.TerrainImageID.ToString()); + // non-async because we know we have the asset immediately. + AssetBase mapasset = m_scene.AssetService.Get(m_scene.RegionInfo.RegionSettings.TerrainImageID.ToString()); - // Decode image to System.Drawing.Image - if (OpenJPEG.DecodeToImage(mapasset.Data, out managedImage, out image)) - { - // Save to bitmap - mapTexture = new Bitmap(image); + // Decode image to System.Drawing.Image + if (OpenJPEG.DecodeToImage(mapasset.Data, out managedImage, out image)) + { + // Save to bitmap + mapTexture = new Bitmap(image); - EncoderParameters myEncoderParameters = new EncoderParameters(); - myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 95L); + EncoderParameters myEncoderParameters = new EncoderParameters(); + myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 95L); - // Save bitmap to stream - mapTexture.Save(imgstream, GetEncoderInfo("image/jpeg"), myEncoderParameters); + // Save bitmap to stream + mapTexture.Save(imgstream, GetEncoderInfo("image/jpeg"), myEncoderParameters); - // Write the stream to a byte array for output - jpeg = imgstream.ToArray(); - myMapImageJPEG = jpeg; + // Write the stream to a byte array for output + jpeg = imgstream.ToArray(); + myMapImageJPEG = jpeg; + } } - } - catch (Exception) - { - // Dummy! - m_log.Warn("[WORLD MAP]: Unable to generate Map image"); - } - finally - { - // Reclaim memory, these are unmanaged resources - // If we encountered an exception, one or more of these will be null - if (mapTexture != null) - mapTexture.Dispose(); + catch (Exception) + { + // Dummy! + m_log.Warn("[WORLD MAP]: Unable to generate Map image"); + } + finally + { + // Reclaim memory, these are unmanaged resources + // If we encountered an exception, one or more of these will be null + if (mapTexture != null) + mapTexture.Dispose(); - if (image != null) - image.Dispose(); + if (image != null) + image.Dispose(); - if (imgstream != null) - imgstream.Dispose(); + if (imgstream != null) + imgstream.Dispose(); + } + } + else + { + // Use cached version so we don't have to loose our mind + jpeg = myMapImageJPEG; } - } - else - { - // Use cached version so we don't have to loose our mind - jpeg = myMapImageJPEG; } reply["str_response_string"] = Convert.ToBase64String(jpeg); @@ -1267,22 +1409,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap foreach (GridRegion r in regions) { - MapBlockData mapBlock = MapBlockFromGridRegion(r, 0); + MapBlockData mapBlock = new MapBlockData(); + MapBlockFromGridRegion(mapBlock, r, 0); AssetBase texAsset = m_scene.AssetService.Get(mapBlock.MapImageId.ToString()); if (texAsset != null) { textures.Add(texAsset); } - //else - //{ - // // WHAT?!? This doesn't seem right. Commenting (diva) - // texAsset = m_scene.AssetService.Get(mapBlock.MapImageId.ToString()); - // if (texAsset != null) - // { - // textures.Add(texAsset); - // } - //} } foreach (AssetBase asset in textures) @@ -1308,6 +1442,10 @@ namespace OpenSim.Region.CoreModules.World.WorldMap mapTexture.Save(exportPath, ImageFormat.Jpeg); + g.Dispose(); + mapTexture.Dispose(); + sea.Dispose(); + m_log.InfoFormat( "[WORLD MAP]: Successfully exported world map for {0} to {1}", m_scene.RegionInfo.RegionName, exportPath); @@ -1320,17 +1458,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap if (consoleScene != null && consoleScene != m_scene) return; - if (m_mapImageGenerator == null) - { - Console.WriteLine("No map image generator available for {0}", m_scene.Name); - return; - } - - using (Bitmap mapbmp = m_mapImageGenerator.CreateMapTile()) - { - GenerateMaptile(mapbmp); - m_mapImageServiceModule.UploadMapTile(m_scene, mapbmp); - } + GenerateMaptile(); } public OSD HandleRemoteMapItemRequest(string path, OSD request, string endpoint) @@ -1338,9 +1466,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap uint xstart = 0; uint ystart = 0; - Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle,out xstart,out ystart); - // m_log.DebugFormat("{0} HandleRemoteMapItemRequest. loc=<{1},{2}>", - // LogHeader, Util.WorldToRegionLoc(xstart), Util.WorldToRegionLoc(ystart)); + Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle, out xstart, out ystart); // Service 6 (MAP_ITEM_AGENTS_LOCATION; green dots) @@ -1362,8 +1488,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap } else { - OSDArray responsearr = new OSDArray(m_scene.GetRootAgentCount()); - m_scene.ForEachRootScenePresence(delegate(ScenePresence sp) + OSDArray responsearr = new OSDArray(); // Don't preallocate. MT (m_scene.GetRootAgentCount()); + m_scene.ForEachRootScenePresence(delegate (ScenePresence sp) { OSDMap responsemapdata = new OSDMap(); responsemapdata["X"] = OSD.FromInteger((int)(xstart + sp.AbsolutePosition.X)); @@ -1377,28 +1503,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap responsemap["6"] = responsearr; } - // Service 7 (MAP_ITEM_LAND_FOR_SALE) + // Service 7/10 (MAP_ITEM_LAND_FOR_SALE/ADULT) ILandChannel landChannel = m_scene.LandChannel; List parcels = landChannel.AllParcels(); - if ((parcels == null) || (parcels.Count == 0)) + if ((parcels != null) && (parcels.Count >= 0)) { - OSDMap responsemapdata = new OSDMap(); - responsemapdata["X"] = OSD.FromInteger((int)(xstart + 1)); - responsemapdata["Y"] = OSD.FromInteger((int)(ystart + 1)); - responsemapdata["ID"] = OSD.FromUUID(UUID.Zero); - responsemapdata["Name"] = OSD.FromString(""); - responsemapdata["Extra"] = OSD.FromInteger(0); - responsemapdata["Extra2"] = OSD.FromInteger(0); - OSDArray responsearr = new OSDArray(); - responsearr.Add(responsemapdata); - - responsemap["7"] = responsearr; - } - else - { - OSDArray responsearr = new OSDArray(m_scene.GetRootAgentCount()); + OSDArray responsearr = new OSDArray(parcels.Count); foreach (ILandObject parcel_interface in parcels) { // Play it safe @@ -1413,8 +1525,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap { Vector3 min = parcel.AABBMin; Vector3 max = parcel.AABBMax; - float x = (min.X+max.X)/2; - float y = (min.Y+max.Y)/2; + float x = (min.X + max.X) / 2; + float y = (min.Y + max.Y) / 2; OSDMap responsemapdata = new OSDMap(); responsemapdata["X"] = OSD.FromInteger((int)(xstart + x)); @@ -1427,7 +1539,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap responsearr.Add(responsemapdata); } } - responsemap["7"] = responsearr; + + if(responsearr.Count > 0) + { + if(m_scene.RegionInfo.RegionSettings.Maturity == 2) + responsemap["10"] = responsearr; + else + responsemap["7"] = responsearr; + } } if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero) @@ -1459,55 +1578,110 @@ namespace OpenSim.Region.CoreModules.World.WorldMap if (m_scene.Heightmap == null) return; + if (m_mapImageGenerator == null) + { + Console.WriteLine("No map image generator available for {0}", m_scene.Name); + return; + } m_log.DebugFormat("[WORLD MAP]: Generating map image for {0}", m_scene.Name); using (Bitmap mapbmp = m_mapImageGenerator.CreateMapTile()) { - // V1 (This Module) GenerateMaptile(mapbmp); - // v2/3 (MapImageServiceModule) - m_mapImageServiceModule.UploadMapTile(m_scene, mapbmp); + if (m_mapImageServiceModule != null) + m_mapImageServiceModule.UploadMapTile(m_scene, mapbmp); } } private void GenerateMaptile(Bitmap mapbmp) { - byte[] data; + bool needRegionSave = false; - try + // remove old assets + UUID lastID = m_scene.RegionInfo.RegionSettings.TerrainImageID; + if (lastID != UUID.Zero) { - data = OpenJPEG.EncodeFromImage(mapbmp, true); + m_scene.AssetService.Delete(lastID.ToString()); + m_scene.RegionInfo.RegionSettings.TerrainImageID = UUID.Zero; + myMapImageJPEG = new byte[0]; + needRegionSave = true; } - catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke + + lastID = m_scene.RegionInfo.RegionSettings.ParcelImageID; + if (lastID != UUID.Zero) { - m_log.Error("[WORLD MAP]: Failed generating terrain map: " + e); - return; + m_scene.AssetService.Delete(lastID.ToString()); + m_scene.RegionInfo.RegionSettings.ParcelImageID = UUID.Zero; + needRegionSave = true; } - byte[] overlay = GenerateOverlay(); + if(mapbmp != null) + { + try + { + byte[] data; + + // if large region limit its size since new viewers will not use it + // but it is still usable for ossl + if(m_scene.RegionInfo.RegionSizeX > Constants.RegionSize || + m_scene.RegionInfo.RegionSizeY > Constants.RegionSize) + { + int bx = mapbmp.Width; + int by = mapbmp.Height; + int mb = bx; + if(mb < by) + mb = by; + if(mb > Constants.RegionSize && mb > 0) + { + float scale = (float)Constants.RegionSize/(float)mb; + Size newsize = new Size(); + newsize.Width = (int)(bx * scale); + newsize.Height = (int)(by * scale); + + using(Bitmap scaledbmp = new Bitmap(mapbmp,newsize)) + data = OpenJPEG.EncodeFromImage(scaledbmp, true); + } + else + data = OpenJPEG.EncodeFromImage(mapbmp, true); + } + else + data = OpenJPEG.EncodeFromImage(mapbmp, true); + + if (data != null && data.Length > 0) + { + UUID terrainImageID = UUID.Random(); + + AssetBase asset = new AssetBase( + terrainImageID, + "terrainImage_" + m_scene.RegionInfo.RegionID.ToString(), + (sbyte)AssetType.Texture, + m_scene.RegionInfo.RegionID.ToString()); + asset.Data = data; + asset.Description = m_scene.RegionInfo.RegionName; + asset.Temporary = false; + asset.Flags = AssetFlags.Maptile; - UUID terrainImageID = UUID.Random(); - UUID parcelImageID = UUID.Zero; + // Store the new one + m_log.DebugFormat("[WORLD MAP]: Storing map image {0} for {1}", asset.ID, m_scene.RegionInfo.RegionName); - AssetBase asset = new AssetBase( - terrainImageID, - "terrainImage_" + m_scene.RegionInfo.RegionID.ToString(), - (sbyte)AssetType.Texture, - m_scene.RegionInfo.RegionID.ToString()); - asset.Data = data; - asset.Description = m_scene.RegionInfo.RegionName; - asset.Temporary = false; - asset.Flags = AssetFlags.Maptile; + m_scene.AssetService.Store(asset); - // Store the new one - m_log.DebugFormat("[WORLD MAP]: Storing map tile {0} for {1}", asset.ID, m_scene.RegionInfo.RegionName); - - m_scene.AssetService.Store(asset); + m_scene.RegionInfo.RegionSettings.TerrainImageID = terrainImageID; + needRegionSave = true; + } + } + catch (Exception e) + { + m_log.Error("[WORLD MAP]: Failed generating terrain map: " + e); + } + } + // V2/3 still seem to need this, or we are missing something somewhere + byte[] overlay = GenerateOverlay(); if (overlay != null) { - parcelImageID = UUID.Random(); + UUID parcelImageID = UUID.Random(); AssetBase parcels = new AssetBase( parcelImageID, @@ -1520,20 +1694,13 @@ namespace OpenSim.Region.CoreModules.World.WorldMap parcels.Flags = AssetFlags.Maptile; m_scene.AssetService.Store(parcels); + + m_scene.RegionInfo.RegionSettings.ParcelImageID = parcelImageID; + needRegionSave = true; } - // Switch to the new one - UUID lastTerrainImageID = m_scene.RegionInfo.RegionSettings.TerrainImageID; - UUID lastParcelImageID = m_scene.RegionInfo.RegionSettings.ParcelImageID; - m_scene.RegionInfo.RegionSettings.TerrainImageID = terrainImageID; - m_scene.RegionInfo.RegionSettings.ParcelImageID = parcelImageID; - m_scene.RegionInfo.RegionSettings.Save(); - - // Delete the old one - // m_log.DebugFormat("[WORLDMAP]: Deleting old map tile {0}", lastTerrainImageID); - m_scene.AssetService.Delete(lastTerrainImageID.ToString()); - if (lastParcelImageID != UUID.Zero) - m_scene.AssetService.Delete(lastParcelImageID.ToString()); + if (needRegionSave) + m_scene.RegionInfo.RegionSettings.Save(); } private void MakeRootAgent(ScenePresence avatar) @@ -1553,6 +1720,12 @@ namespace OpenSim.Region.CoreModules.World.WorldMap { m_rootAgents.Remove(avatar.UUID); } + + lock (m_mapBlockRequestEvent) + { + if (m_mapBlockRequests.ContainsKey(avatar.UUID)) + m_mapBlockRequests.Remove(avatar.UUID); + } } public void OnRegionUp(GridRegion otherRegion) @@ -1562,46 +1735,67 @@ namespace OpenSim.Region.CoreModules.World.WorldMap lock (m_blacklistedregions) { - if (!m_blacklistedregions.ContainsKey(regionhandle)) + if (m_blacklistedregions.Contains(regionhandle)) m_blacklistedregions.Remove(regionhandle); } lock (m_blacklistedurls) { - if (m_blacklistedurls.ContainsKey(httpserver)) + if (m_blacklistedurls.Contains(httpserver)) m_blacklistedurls.Remove(httpserver); } lock (m_cachedRegionMapItemsAddress) { - if (!m_cachedRegionMapItemsAddress.ContainsKey(regionhandle)) - m_cachedRegionMapItemsAddress.Remove(regionhandle); + m_cachedRegionMapItemsAddress.AddOrUpdate(regionhandle, + httpserver, 5.0 * expireBlackListTime); } } private Byte[] GenerateOverlay() { + int landTileSize = LandManagementModule.LandUnit; + // These need to be ints for bitmap generation int regionSizeX = (int)m_scene.RegionInfo.RegionSizeX; - int regionSizeY = (int)m_scene.RegionInfo.RegionSizeY; - - int landTileSize = LandManagementModule.LandUnit; int regionLandTilesX = regionSizeX / landTileSize; + + int regionSizeY = (int)m_scene.RegionInfo.RegionSizeY; int regionLandTilesY = regionSizeY / landTileSize; - using (Bitmap overlay = new Bitmap(regionSizeX, regionSizeY)) + bool landForSale = false; + ILandObject land; + + // scan terrain avoiding potencial merges of large bitmaps + //TODO create the sell bitmap at landchannel / landmaster ? + // and auction also, still not suported + + bool[,] saleBitmap = new bool[regionLandTilesX, regionLandTilesY]; + for (int x = 0, xx = 0; x < regionLandTilesX; x++ ,xx += landTileSize) { - bool[,] saleBitmap = new bool[regionLandTilesX, regionLandTilesY]; - for (int x = 0; x < regionLandTilesX; x++) + for (int y = 0, yy = 0; y < regionLandTilesY; y++, yy += landTileSize) { - for (int y = 0; y < regionLandTilesY; y++) + land = m_scene.LandChannel.GetLandObject(xx, yy); + if (land != null && (land.LandData.Flags & (uint)ParcelFlags.ForSale) != 0) + { + saleBitmap[x, y] = true; + landForSale = true; + } + else saleBitmap[x, y] = false; } + } - bool landForSale = false; + if (!landForSale) + { + m_log.DebugFormat("[WORLD MAP]: Region {0} has no parcels for sale, not generating overlay", m_scene.RegionInfo.RegionName); + return null; + } - List parcels = m_scene.LandChannel.AllParcels(); + m_log.DebugFormat("[WORLD MAP]: Region {0} has parcels for sale, generating overlay", m_scene.RegionInfo.RegionName); + using (Bitmap overlay = new Bitmap(regionSizeX, regionSizeY)) + { Color background = Color.FromArgb(0, 0, 0, 0); using (Graphics g = Graphics.FromImage(overlay)) @@ -1609,36 +1803,19 @@ namespace OpenSim.Region.CoreModules.World.WorldMap using (SolidBrush transparent = new SolidBrush(background)) g.FillRectangle(transparent, 0, 0, regionSizeX, regionSizeY); - foreach (ILandObject land in parcels) + // make it a bit transparent + using (SolidBrush yellow = new SolidBrush(Color.FromArgb(192, 249, 223, 9))) { - // m_log.DebugFormat("[WORLD MAP]: Parcel {0} flags {1}", land.LandData.Name, land.LandData.Flags); - if ((land.LandData.Flags & (uint)ParcelFlags.ForSale) != 0) + for (int x = 0; x < regionLandTilesX; x++) { - landForSale = true; - - saleBitmap = land.MergeLandBitmaps(saleBitmap, land.GetLandBitmap()); - } - } - - if (!landForSale) - { - m_log.DebugFormat("[WORLD MAP]: Region {0} has no parcels for sale, not generating overlay", m_scene.RegionInfo.RegionName); - return null; - } - - m_log.DebugFormat("[WORLD MAP]: Region {0} has parcels for sale, generating overlay", m_scene.RegionInfo.RegionName); - - using (SolidBrush yellow = new SolidBrush(Color.FromArgb(255, 249, 223, 9))) - { - for (int x = 0 ; x < regionLandTilesX ; x++) - { - for (int y = 0 ; y < regionLandTilesY ; y++) + for (int y = 0; y < regionLandTilesY; y++) { if (saleBitmap[x, y]) g.FillRectangle( - yellow, x * landTileSize, - regionSizeX - landTileSize - (y * landTileSize), - landTileSize, + yellow, + x * landTileSize, + regionSizeX - landTileSize - (y * landTileSize), + landTileSize, landTileSize); } } @@ -1659,7 +1836,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap } } - public struct MapRequestState + public class MapRequestState { public UUID agentID; public uint flags; @@ -1668,4 +1845,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap public uint itemtype; public ulong regionhandle; } + + public struct MapBlockRequestData + { + public IClientAPI client; + public int minX; + public int minY; + public int maxX; + public int maxY; + public uint flags; + } } -- cgit v1.1 From 295e91b8f44a356ab742dedd27c1b7edfe7b1157 Mon Sep 17 00:00:00 2001 From: onefang Date: Sun, 19 May 2019 22:15:41 +1000 Subject: Move cache, config, logs out of tree, and various related clean ups. --- OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index c1bf544..bb0f424 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -66,7 +66,7 @@ namespace OpenSim.Region.CoreModules.Asset private bool m_cleanupRunning; private const string m_ModuleName = "FlotsamAssetCache"; - private const string m_DefaultCacheDirectory = "./assetcache"; + private const string m_DefaultCacheDirectory = "assetcache"; private string m_CacheDirectory = m_DefaultCacheDirectory; private readonly List m_InvalidChars = new List(); @@ -159,7 +159,7 @@ namespace OpenSim.Region.CoreModules.Asset else { m_FileCacheEnabled = assetConfig.GetBoolean("FileCacheEnabled", m_FileCacheEnabled); - m_CacheDirectory = assetConfig.GetString("CacheDirectory", m_DefaultCacheDirectory); + m_CacheDirectory = assetConfig.GetString("CacheDirectory", Path.Combine(Util.cacheDir(), m_DefaultCacheDirectory)); m_MemoryCacheEnabled = assetConfig.GetBoolean("MemoryCacheEnabled", m_MemoryCacheEnabled); m_MemoryExpiration = assetConfig.GetDouble("MemoryCacheTimeout", m_MemoryExpiration); -- cgit v1.1 From 48872e10630d1ae56b07fba9897b51afb16a4dd2 Mon Sep 17 00:00:00 2001 From: onefang Date: Sun, 19 May 2019 22:19:02 +1000 Subject: Remove useless executable bit that Windows adds. --- .../World/Archiver/Tests/Resources/test-sound.wav | Bin 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 OpenSim/Region/CoreModules/World/Archiver/Tests/Resources/test-sound.wav (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/Resources/test-sound.wav b/OpenSim/Region/CoreModules/World/Archiver/Tests/Resources/test-sound.wav old mode 100755 new mode 100644 -- cgit v1.1 From 66d7ba733f296f81398a040f05dd945c2facb2b4 Mon Sep 17 00:00:00 2001 From: onefang Date: Sun, 19 May 2019 22:25:06 +1000 Subject: Various logging fix ups. Mostly removing console spam. Default to INFO on the console and DEBUG in the log files. More time stamp resolution. --- OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs | 5 ----- 1 file changed, 5 deletions(-) (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs index 3092fe0..0a955c5 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs @@ -143,11 +143,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver asset.Data); m_assetsWritten++; - - //m_log.DebugFormat("[ARCHIVER]: Added asset {0}", m_assetsWritten); - - if (m_assetsWritten % LOG_ASSET_LOAD_NOTIFICATION_INTERVAL == 0) - m_log.InfoFormat("[ARCHIVER]: Added {0} assets to archive", m_assetsWritten); } } -- cgit v1.1 From 30cc9a733f4e7013c82696985c8481be1a8aac1c Mon Sep 17 00:00:00 2001 From: onefang Date: Sun, 19 May 2019 22:28:19 +1000 Subject: Remove silly 4096 sim TP check for a client bug that was fixed long ago. --- .../EntityTransfer/EntityTransferModule.cs | 47 ---------------------- 1 file changed, 47 deletions(-) (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 2334e0b..9ce6201 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -54,15 +54,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly string LogHeader = "[ENTITY TRANSFER MODULE]"; - public const int DefaultMaxTransferDistance = 4095; public const bool WaitForAgentArrivedAtDestinationDefault = true; /// - /// The maximum distance, in standard region units (256m) that an agent is allowed to transfer. - /// - public int MaxTransferDistance { get; set; } - - /// /// If true then on a teleport, the source region waits for a callback from the destination region. If /// a callback fails to arrive within a set time then the user is pulled back into the source region. /// @@ -226,12 +220,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer WaitForAgentArrivedAtDestination = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault); - - MaxTransferDistance = transferConfig.GetInt("max_distance", DefaultMaxTransferDistance); - } - else - { - MaxTransferDistance = DefaultMaxTransferDistance; } m_entityTransferStateMachine = new EntityTransferStateMachine(this); @@ -639,29 +627,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } /// - /// Determines whether this instance is within the max transfer distance. - /// - /// - /// - /// - /// true if this instance is within max transfer distance; otherwise, false. - /// - private bool IsWithinMaxTeleportDistance(RegionInfo sourceRegion, GridRegion destRegion) - { - if(MaxTransferDistance == 0) - return true; - -// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY); -// -// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}", -// destRegionX, destRegionY, finalDestination.RegionID, finalDestination.ServerURI); - - // Insanely, RegionLoc on RegionInfo is the 256m map co-ord whilst GridRegion.RegionLoc is the raw meters position. - return Math.Abs(sourceRegion.RegionLocX - destRegion.RegionCoordX) <= MaxTransferDistance - && Math.Abs(sourceRegion.RegionLocY - destRegion.RegionCoordY) <= MaxTransferDistance; - } - - /// /// Wraps DoTeleportInternal() and manages the transfer state. /// public void DoTeleport( @@ -721,18 +686,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer RegionInfo sourceRegion = sp.Scene.RegionInfo; - if (!IsWithinMaxTeleportDistance(sourceRegion, finalDestination)) - { - sp.ControllingClient.SendTeleportFailed( - string.Format( - "Can't teleport to {0} ({1},{2}) from {3} ({4},{5}), destination is more than {6} regions way", - finalDestination.RegionName, finalDestination.RegionCoordX, finalDestination.RegionCoordY, - sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY, - MaxTransferDistance)); - - return; - } - ulong destinationHandle = finalDestination.RegionHandle; // Let's do DNS resolution only once in this process, please! -- cgit v1.1 From 459a5d77ee6ceda20ff21798f6dc8dab37ba0b77 Mon Sep 17 00:00:00 2001 From: onefang Date: Sun, 19 May 2019 22:31:34 +1000 Subject: Merge Warp3DCachedImageModule from Christopher Latza. Plus some of my own tweaks. Minus some of his. --- .../World/Warp3DMap/Warp3DImageModule.cs | 225 ++++++++++++++++----- 1 file changed, 180 insertions(+), 45 deletions(-) (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs index 4934ebd..7b7cce8 100644 --- a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs +++ b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs @@ -41,8 +41,8 @@ using Mono.Addins; using OpenSim.Framework; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; -using OpenSim.Region.PhysicsModules.SharedBase; -using OpenSim.Services.Interfaces; +//using OpenSim.Region.PhysicsModules.SharedBase; +//using OpenSim.Services.Interfaces; using OpenMetaverse; using OpenMetaverse.Assets; @@ -51,6 +51,7 @@ using OpenMetaverse.Rendering; using OpenMetaverse.StructuredData; using WarpRenderer = global::Warp3D.Warp3D; +using System.Drawing.Drawing2D; namespace OpenSim.Region.CoreModules.World.Warp3DMap { @@ -76,10 +77,17 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap private bool m_texturePrims = true; // true if should texture the rendered prims private float m_texturePrimSize = 48f; // size of prim before we consider texturing it private bool m_renderMeshes = false; // true if to render meshes rather than just bounding boxes - + private String m_cacheDirectory = ""; private bool m_Enabled = false; -// private Bitmap lastImage = null; +// private bool m_enable_date = false; +// private bool m_enable_regionName = false; + private bool m_enable_regionPosition = false; + private bool m_enable_refreshEveryMonth = false; +// private bool m_enable_HostedBy = false; +// private String m_enable_HostedByText = ""; + + // private Bitmap lastImage = null; private DateTime lastImageTime = DateTime.MinValue; #region Region Module interface @@ -106,7 +114,20 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap = Util.GetConfigVarFromSections(m_config, "TexturePrimSize", configSections, m_texturePrimSize); m_renderMeshes = Util.GetConfigVarFromSections(m_config, "RenderMeshes", configSections, m_renderMeshes); - } + m_cacheDirectory + = Util.GetConfigVarFromSections(m_config, "CacheDirectory", configSections, System.IO.Path.Combine(Util.cacheDir(), "MapImageCache")); + + +// m_enable_date = Util.GetConfigVarFromSections(m_config, "enableDate", configSections, false); +// m_enable_regionName = Util.GetConfigVarFromSections(m_config, "enableName", configSections, false); + m_enable_regionPosition = Util.GetConfigVarFromSections(m_config, "enablePosition", configSections, false); + m_enable_refreshEveryMonth = Util.GetConfigVarFromSections(m_config, "RefreshEveryMonth", configSections, true); +// m_enable_HostedBy = Util.GetConfigVarFromSections(m_config, "enableHostedBy", configSections, false); +// m_enable_HostedByText = Util.GetConfigVarFromSections(m_config, "HosterText", configSections, String.Empty); + + if (!Directory.Exists(m_cacheDirectory)) + Directory.CreateDirectory(m_cacheDirectory); + } public void AddRegion(Scene scene) { @@ -149,39 +170,138 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap #endregion #region IMapImageGenerator Members - - public Bitmap CreateMapTile() +/* + public static string fillInt(int _i, int _l) { - /* this must be on all map, not just its image - if ((DateTime.Now - lastImageTime).TotalSeconds < 3600) + String _return = _i.ToString(); + + while(_return.Length < _l) { - return (Bitmap)lastImage.Clone(); + _return = 0 + _return; } - */ - List renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory()); - if (renderers.Count > 0) + return _return; + } + + public static int getCurrentUnixTime() + { + return (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds; + } + + public static String unixTimeToDateString(int unixTime) + { + DateTime unixStart = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc); + long unixTimeStampInTicks = (long)(unixTime * TimeSpan.TicksPerSecond); + DateTime _date = new DateTime(unixStart.Ticks + unixTimeStampInTicks, System.DateTimeKind.Utc); + + return fillInt(_date.Day, 2) + "." + fillInt(_date.Month, 2) + "." + fillInt(_date.Year, 4) + " " + fillInt(_date.Hour, 2) + ":" + fillInt(_date.Minute, 2); + } + + private void writeDateOnMap(ref Bitmap _map) + { + RectangleF rectf = new RectangleF(2, 1, 200, 25); + + Graphics g = Graphics.FromImage(_map); + g.SmoothingMode = SmoothingMode.AntiAlias; + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + g.DrawString(unixTimeToDateString(getCurrentUnixTime()), new Font("Arial", 8), Brushes.White, rectf); + g.Flush(); + } + + private void writeNameOnMap(ref Bitmap _map) + { + RectangleF rectf = new RectangleF(2, m_scene.RegionInfo.RegionSizeX - 15, 200, 25); + + Graphics g = Graphics.FromImage(_map); + g.SmoothingMode = SmoothingMode.AntiAlias; + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + g.DrawString(m_scene.Name, new Font("Arial", 8), Brushes.White, rectf); + g.Flush(); + } +*/ + private void writePositionOnMap(ref Bitmap _map) + { + RectangleF rectf = new RectangleF(m_scene.RegionInfo.RegionSizeY - 75, m_scene.RegionInfo.RegionSizeX - 15, 80, 25); + + Graphics g = Graphics.FromImage(_map); + g.SmoothingMode = SmoothingMode.AntiAlias; + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + g.DrawString("<" + m_scene.RegionInfo.RegionLocX + " " + m_scene.RegionInfo.RegionLocY + ">", new Font("Arial", 8), Brushes.White, rectf); + g.Flush(); + } +/* + private void writeHostedByOnMap(ref Bitmap _map) + { + RectangleF rectf = new RectangleF(2, m_scene.RegionInfo.RegionSizeX - 15, 200, 25); + + Graphics g = Graphics.FromImage(_map); + g.SmoothingMode = SmoothingMode.AntiAlias; + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + g.DrawString(m_enable_HostedByText, new Font("Arial", 8), Brushes.Gray, rectf); + g.Flush(); + } +*/ + public Bitmap CreateMapTile() + { + if ((File.GetCreationTime(System.IO.Path.Combine(m_cacheDirectory, m_scene.RegionInfo.RegionID + ".bmp")).Month != DateTime.Now.Month) && m_enable_refreshEveryMonth == true) + File.Delete(System.IO.Path.Combine(m_cacheDirectory, m_scene.RegionInfo.RegionID + ".bmp")); + + if(File.Exists(System.IO.Path.Combine(m_cacheDirectory, m_scene.RegionInfo.RegionID + ".bmp"))) { - m_primMesher = RenderingLoader.LoadRenderer(renderers[0]); + return new Bitmap(System.IO.Path.Combine(m_cacheDirectory, m_scene.RegionInfo.RegionID + ".bmp")); } + else + { + /* this must be on all map, not just its image + if ((DateTime.Now - lastImageTime).TotalSeconds < 3600) + { + return (Bitmap)lastImage.Clone(); + } + */ - Vector3 camPos = new Vector3( - m_scene.RegionInfo.RegionSizeX / 2 - 0.5f, - m_scene.RegionInfo.RegionSizeY / 2 - 0.5f, - 221.7025033688163f); - // Viewport viewing down onto the region - Viewport viewport = new Viewport(camPos, -Vector3.UnitZ, 1024f, 0.1f, - (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY, - (float)m_scene.RegionInfo.RegionSizeX, (float)m_scene.RegionInfo.RegionSizeY); - - Bitmap tile = CreateMapTile(viewport, false); - m_primMesher = null; - return tile; -/* - lastImage = tile; - lastImageTime = DateTime.Now; - return (Bitmap)lastImage.Clone(); - */ + List renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory()); + if (renderers.Count > 0) + { + m_primMesher = RenderingLoader.LoadRenderer(renderers[0]); + } + + Vector3 camPos = new Vector3( + m_scene.RegionInfo.RegionSizeX / 2 - 0.5f, + m_scene.RegionInfo.RegionSizeY / 2 - 0.5f, + 221.7025033688163f); + // Viewport viewing down onto the region + Viewport viewport = new Viewport(camPos, -Vector3.UnitZ, 1024f, 0.1f, + (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY, + (float)m_scene.RegionInfo.RegionSizeX, (float)m_scene.RegionInfo.RegionSizeY); + + Bitmap tile = CreateMapTile(viewport, false); + +// if (m_enable_date) +// writeDateOnMap(ref tile); + +// if (m_enable_regionName) +// writeNameOnMap(ref tile); + + if (m_enable_regionPosition) + writePositionOnMap(ref tile); + +// if (m_enable_HostedBy) +// writeHostedByOnMap(ref tile); + + tile.Save(System.IO.Path.Combine(m_cacheDirectory, m_scene.RegionInfo.RegionID + ".bmp")); + m_primMesher = null; + return tile; + + /* + lastImage = tile; + lastImageTime = DateTime.Now; + return (Bitmap)lastImage.Clone(); + */ + } } public Bitmap CreateViewImage(Vector3 camPos, Vector3 camDir, float fov, int width, int height, bool useTextures) @@ -271,16 +391,20 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap { float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight; - renderer.AddPlane("Water", m_scene.RegionInfo.RegionSizeX * 0.5f); - renderer.Scene.sceneobject("Water").setPos(m_scene.RegionInfo.RegionSizeX * 0.5f - 0.5f, - waterHeight, - m_scene.RegionInfo.RegionSizeY * 0.5f - 0.5f); - warp_Material waterColorMaterial = new warp_Material(ConvertColor(WATER_COLOR)); waterColorMaterial.setReflectivity(0); // match water color with standard map module thanks lkalif waterColorMaterial.setTransparency((byte)((1f - WATER_COLOR.A) * 255f)); renderer.Scene.addMaterial("WaterColor", waterColorMaterial); - renderer.SetObjectMaterial("Water", "WaterColor"); + + for (int x = 0; x < m_scene.RegionInfo.RegionSizeX / 256; x++) + { + for (int y = 0; y < m_scene.RegionInfo.RegionSizeY / 256; y++) + { + renderer.AddPlane("Water-" + x + "-" + y, 256); + renderer.Scene.sceneobject("Water-" + x + "-" + y).setPos(256 * x, waterHeight, 256 * y); + renderer.SetObjectMaterial("Water-" + x + "-" + y, "WaterColor"); + } + } } // Add a terrain to the renderer. @@ -428,14 +552,25 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap else // It's sculptie { IJ2KDecoder imgDecoder = m_scene.RequestModuleInterface(); - if(imgDecoder != null) + if (imgDecoder != null) { - Image sculpt = imgDecoder.DecodeToImage(sculptAsset); - if(sculpt != null) + try + { + Image sculpt = imgDecoder.DecodeToImage(sculptAsset); + if (sculpt != null) + { + renderMesh = m_primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt, + DetailLevel.Medium); + sculpt.Dispose(); + } + } + catch (Exception e) { - renderMesh = m_primMesher.GenerateFacetedSculptMesh(omvPrim,(Bitmap)sculpt, - DetailLevel.Medium); - sculpt.Dispose(); + Vector3 objectPos = prim.ParentGroup.RootPart.AbsolutePosition; +//// TODO - print out owner of SceneObjectPart prim. + m_log.Error(string.Format("[WARP 3D IMAGE MODULE]: Failed to decode asset {0} @ {1},{2},{3} - {4}.", + omvPrim.Sculpt.SculptTexture, objectPos.X, objectPos.Y, objectPos.Z, + prim.ParentGroup.RootPart.Name)); } } } @@ -615,7 +750,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap } catch (Exception e) { - m_log.Warn(string.Format("[WARP 3D IMAGE MODULE]: Failed to decode asset {0}, exception ", id), e); + m_log.Debug(string.Format("[WARP 3D IMAGE MODULE]: Failed to decode asset {0}, exception ", id)); } } @@ -733,7 +868,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap } catch (Exception ex) { - m_log.WarnFormat( + m_log.DebugFormat( "[WARP 3D IMAGE MODULE]: Error decoding JPEG2000 texture {0} ({1} bytes): {2}", textureID, j2kData.Length, ex.Message); -- cgit v1.1 From f3902d0e9b4341dd65019cb07ade5766bd6f1585 Mon Sep 17 00:00:00 2001 From: onefang Date: Sun, 19 May 2019 22:34:26 +1000 Subject: ProfileServiceURL not ProfileURL --- OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index e02ca49..b25ef58 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -154,7 +154,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return; } - // If we find ProfileURL then we configure for FULL support + // If we find ProfileServiceURL then we configure for FULL support // else we setup for BASIC support ProfileServerUri = profileConfig.GetString("ProfileServiceURL", ""); if (ProfileServerUri == "") -- cgit v1.1 From f3b8aaa9e949e9eebd35dd61dfec49649d7f0c17 Mon Sep 17 00:00:00 2001 From: onefang Date: Sat, 1 Jun 2019 01:58:47 +1000 Subject: A little tweaking of log levels. --- OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs | 6 +++--- OpenSim/Region/CoreModules/World/Wind/WindModule.cs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index 65d4c4a..6df0075 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs @@ -644,7 +644,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain { ITerrainLoader terLoader = (ITerrainLoader)Activator.CreateInstance(library.GetType(pluginType.ToString())); m_loaders[terLoader.FileExtension] = terLoader; - m_log.Info("L ... " + typeName); + m_log.Debug("L ... " + typeName); } } catch(AmbiguousMatchException) @@ -660,12 +660,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain if (!m_plugineffects.ContainsKey(pluginName)) { m_plugineffects.Add(pluginName, effect); - m_log.Info("E ... " + pluginName); + m_log.Debug("E ... " + pluginName); } else { m_plugineffects[pluginName] = effect; - m_log.Info("E ... " + pluginName + " (Replaced)"); + m_log.Debug("E ... " + pluginName + " (Replaced)"); } } } diff --git a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs index a1fff62..b1eb0a5 100644 --- a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs +++ b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs @@ -101,7 +101,7 @@ namespace OpenSim.Region.CoreModules // Register all the Wind Model Plug-ins foreach (IWindModelPlugin windPlugin in AddinManager.GetExtensionObjects("/OpenSim/WindModule", false)) { - m_log.InfoFormat("[WIND] Found Plugin: {0}", windPlugin.Name); + m_log.DebugFormat("[WIND] Found Plugin: {0}", windPlugin.Name); m_availableWindPlugins.Add(windPlugin.Name, windPlugin); } @@ -110,7 +110,7 @@ namespace OpenSim.Region.CoreModules { m_activeWindPlugin = m_availableWindPlugins[m_dWindPluginName]; - m_log.InfoFormat("[WIND] {0} plugin found, initializing.", m_dWindPluginName); + m_log.DebugFormat("[WIND] {0} plugin found, initializing.", m_dWindPluginName); if (m_windConfig != null) { -- cgit v1.1 From 0ea33d58fc0b0f27d80e58ee926eb51018cd472c Mon Sep 17 00:00:00 2001 From: onefang Date: Mon, 3 Jun 2019 21:08:02 +1000 Subject: Add DefaultRegionAccess in [AuthorizationService] section. --- .../ServiceConnectorsOut/Authorization/AuthorizationService.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/AuthorizationService.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/AuthorizationService.cs index 93dff1f..2e06bc8 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/AuthorizationService.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/AuthorizationService.cs @@ -69,7 +69,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization if (config != null) { - string accessStr = config.GetString("Region_" + scene.RegionInfo.RegionName.Replace(' ', '_'), String.Empty); + string defaultAccess = config.GetString("DefaultRegionAccess", "None"); + string accessStr = config.GetString("Region_" + scene.RegionInfo.RegionName.Replace(' ', '_'), defaultAccess); if (accessStr != string.Empty) { try -- cgit v1.1 From cdb1851f438349a8721c0d9cef54837d0b302189 Mon Sep 17 00:00:00 2001 From: onefang Date: Tue, 4 Jun 2019 00:50:59 +1000 Subject: Warnings-- --- OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs | 2 +- .../Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs | 2 +- OpenSim/Region/CoreModules/World/Land/LandObject.cs | 3 +-- OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs | 4 ++-- OpenSim/Region/CoreModules/World/Wind/WindModule.cs | 2 +- 5 files changed, 6 insertions(+), 7 deletions(-) (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 9f52a14..4afac28 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -369,7 +369,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments { string xmlData; XmlDocument d = null; - UUID asset; +// UUID asset; if (itemData.TryGetValue(attach.ItemID, out xmlData)) { d = new XmlDocument(); diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs index f5b575b..84b4707 100644 --- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs @@ -666,7 +666,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest ResponseBody = e.Message; } } - catch (Exception e) + catch (Exception) { // Don't crash on anything else } diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index 4471432..ce67fcc 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs @@ -1396,9 +1396,8 @@ namespace OpenSim.Region.CoreModules.World.Land byte[] tempConvertArr = new byte[LandBitmap.GetLength(0) * LandBitmap.GetLength(1) / 8]; int tempByte = 0; - int i, byteNum = 0; + int byteNum = 0; int mask = 1; - i = 0; for (int y = 0; y < LandBitmap.GetLength(1); y++) { for (int x = 0; x < LandBitmap.GetLength(0); x++) diff --git a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs index 7b7cce8..fb94853 100644 --- a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs +++ b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs @@ -564,7 +564,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap sculpt.Dispose(); } } - catch (Exception e) + catch /*(Exception e)*/ { Vector3 objectPos = prim.ParentGroup.RootPart.AbsolutePosition; //// TODO - print out owner of SceneObjectPart prim. @@ -748,7 +748,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap using (Bitmap img = (Bitmap)imgDecoder.DecodeToImage(asset)) ret = new warp_Texture(img); } - catch (Exception e) + catch /*(Exception e)*/ { m_log.Debug(string.Format("[WARP 3D IMAGE MODULE]: Failed to decode asset {0}, exception ", id)); } diff --git a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs index b1eb0a5..96ba003 100644 --- a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs +++ b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs @@ -47,7 +47,7 @@ namespace OpenSim.Region.CoreModules private uint m_frame = 0; private int m_dataVersion = 0; - private int m_regionID = 0; +// private int m_regionID = 0; private int m_frameUpdateRate = 150; //private Random m_rndnums = new Random(Environment.TickCount); private Scene m_scene = null; -- cgit v1.1 From 15b2a91ffc6d240277a852aa750a0259ae6a2a17 Mon Sep 17 00:00:00 2001 From: onefang Date: Wed, 24 Jul 2019 05:49:26 +1000 Subject: For the "teleport from above" case, do the right thing. Which includes looking for designated floor prims, which have ^ as the first character of their description. Don't do "teleport from above" when we have proper coords. --- .../CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 9ce6201..59e71c6 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -679,9 +679,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer string homeURI = Scene.GetAgentHomeURI(sp.ControllingClient.AgentId); - m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Teleporting {0} {1} from {2} to {3} ({4}) {5}/{6}", - sp.Name, sp.UUID, sp.Scene.RegionInfo.RegionName, +//// m_log.DebugFormat( + m_log.InfoFormat( + "[ENTITY TRANSFER MODULE]: Teleporting {0} {1} from {2}/{3} to {4} ({5}) {6}/{7}", + sp.Name, sp.UUID, sp.Scene.RegionInfo.RegionName, sp.AbsolutePosition, reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position); RegionInfo sourceRegion = sp.Scene.RegionInfo; -- cgit v1.1 From b4b52f5f75d39e4b9b0dc9ad42c339bdc3dc75c2 Mon Sep 17 00:00:00 2001 From: onefang Date: Wed, 24 Jul 2019 16:27:08 +1000 Subject: Move the terrain.raw file out of tree to a sim specific name. --- .../CoreModules/World/Estate/EstateManagementModule.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index 3c45b68..4b55860 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -1355,15 +1355,24 @@ namespace OpenSim.Region.CoreModules.World.Estate if (terr != null) { + string file = Util.cacheDir() + "/terrain_"; + try + { + file = file + Uri.EscapeDataString(Scene.Name) + ".raw"; + } + catch (Exception ex) + { + file = file + ".raw"; + } // m_log.Warn("[CLIENT]: Got Request to Send Terrain in region " + Scene.RegionInfo.RegionName); - if (File.Exists(Util.dataDir() + "/terrain.raw")) + if (File.Exists(file)) { - File.Delete(Util.dataDir() + "/terrain.raw"); + File.Delete(file); } - terr.SaveToFile(Util.dataDir() + "/terrain.raw"); + terr.SaveToFile(file); byte[] bdata; - using(FileStream input = new FileStream(Util.dataDir() + "/terrain.raw",FileMode.Open)) + using(FileStream input = new FileStream(file, FileMode.Open)) { bdata = new byte[input.Length]; input.Read(bdata, 0, (int)input.Length); -- cgit v1.1 From 55262c8e1c6338662e0cff6563fe500531edfe32 Mon Sep 17 00:00:00 2001 From: onefang Date: Wed, 24 Jul 2019 18:27:05 +1000 Subject: Allow sitting on attachments, and attaching tings with people sitting on them. Now we have to fix all the viewers that though it would be great to enshrine this bug in viewer side. --- .../Avatar/Attachments/AttachmentsModule.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 4afac28..f99cf4c 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -485,15 +485,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // group.Name, group.LocalId, sp.Name, attachmentPt, silent); - if (group.GetSittingAvatarsCount() != 0) - { - if (DebugLevel > 0) - m_log.WarnFormat( - "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it", - group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount()); - - return false; - } +//// if (group.GetSittingAvatarsCount() != 0) +//// { +//// if (DebugLevel > 0) +//// m_log.WarnFormat( +//// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it", +//// group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount()); +//// +//// return false; +//// } List attachments = sp.GetAttachments(attachmentPt); if (attachments.Contains(group)) -- cgit v1.1 From 73934c7cae0d295bbe0fde8f8502b0ccece2ba15 Mon Sep 17 00:00:00 2001 From: onefang Date: Thu, 25 Jul 2019 00:23:57 +1000 Subject: Combine LureModule and HGLureModule. Still need to clean up after this, LureModule.cs isn't needed anymore. --- .../Region/CoreModules/Avatar/Lure/HGLureModule.cs | 170 ++++++++++++--------- 1 file changed, 101 insertions(+), 69 deletions(-) (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs index 10781e9..381bb4d 100644 --- a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs @@ -29,10 +29,9 @@ using System; using System.Collections.Generic; using System.Reflection; using log4net; +using Mono.Addins; using Nini.Config; using OpenMetaverse; -using Mono.Addins; - using OpenSim.Framework; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; @@ -45,8 +44,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "HGLureModule")] public class HGLureModule : ISharedRegionModule { - private static readonly ILog m_log = LogManager.GetLogger( - MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private readonly List m_scenes = new List(); @@ -69,6 +67,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure new string[] { "Startup", "Hypergrid", "Messaging" }, String.Empty); // Legacy. Remove soon! m_ThisGridURL = config.Configs["Messaging"].GetString("Gatekeeper", m_ThisGridURL); + m_log.DebugFormat("[LURE MODULE]: {0} enabled", Name); } } @@ -154,19 +153,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure void OnIncomingInstantMessage(GridInstantMessage im) { - if (im.dialog == (byte)InstantMessageDialog.RequestTeleport - || im.dialog == (byte)InstantMessageDialog.GodLikeRequestTeleport) + if (im.dialog == (byte)InstantMessageDialog.RequestTeleport || im.dialog == (byte)InstantMessageDialog.GodLikeRequestTeleport) { - UUID sessionID = new UUID(im.imSessionID); - - if (!m_PendingLures.Contains(sessionID)) + if (1 == im.binaryBucket[0]) { - m_log.DebugFormat("[HG LURE MODULE]: RequestTeleport sessionID={0}, regionID={1}, message={2}", im.imSessionID, im.RegionID, im.message); - m_PendingLures.Add(sessionID, im, 7200); // 2 hours + UUID sessionID = new UUID(im.imSessionID); + + if (!m_PendingLures.Contains(sessionID)) + { + m_log.DebugFormat("[HG LURE MODULE]: RequestTeleport sessionID={0}, regionID={1}, message={2}", im.imSessionID, im.RegionID, im.message); + m_PendingLures.Add(sessionID, im, 7200); // 2 hours + } } - // Forward. We do this, because the IM module explicitly rejects - // IMs of this type + // Forward. We do this, because the IM module explicitly rejects IMs of this type if (m_TransferModule != null) m_TransferModule.SendInstantMessage(im, delegate(bool success) { }); } @@ -179,22 +179,47 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure Scene scene = (Scene)(client.Scene); ScenePresence presence = scene.GetScenePresence(client.AgentId); + ScenePresence target = scene.GetScenePresence(targetid); + Guid start = client.Scene.RegionInfo.RegionID.Guid; + UUID dest; + byte reqType = (byte)InstantMessageDialog.RequestTeleport; + byte[] bucket = new Byte[1]; - message += "@" + m_ThisGridURL; + m_log.DebugFormat("[LURE MODULE]: TP invite with message {0}, type {1} {2} {3} {4}", message, lureType, scene.Permissions.IsAdministrator(client.AgentId), presence.IsViewerUIGod, (!scene.Permissions.IsAdministrator(targetid))); - m_log.DebugFormat("[HG LURE MODULE]: TP invite with message {0}", message); + GridInstantMessage m; - UUID sessionID = UUID.Random(); + GridRegion region = scene.GridService.GetRegionByUUID(scene.RegionInfo.ScopeID, new UUID(start)); + if (region != null) + { + bucket[0] = 0; + dest = Util.BuildFakeParcelID(scene.RegionInfo.RegionHandle, + (uint)presence.AbsolutePosition.X, (uint)presence.AbsolutePosition.Y, (uint)presence.AbsolutePosition.Z); + if (scene.Permissions.IsAdministrator(client.AgentId) && presence.IsViewerUIGod && (!scene.Permissions.IsAdministrator(targetid))) + { + reqType = (byte)InstantMessageDialog.GodLikeRequestTeleport; + m_log.DebugFormat("[LURE MODULE]: TP FORCE GOD LURE with message {0}, type {1}", message, lureType); + } + else + m_log.DebugFormat("[LURE MODULE]: TP lure with message {0}, type {1}", message, lureType); + } + else + { + m_log.DebugFormat("[LURE MODULE]: HG lure with message {0}, type {1}", message, lureType); + bucket[0] = 1; + message += "@" + m_ThisGridURL; + dest = UUID.Random(); + } - GridInstantMessage m = new GridInstantMessage(scene, client.AgentId, - client.FirstName+" "+client.LastName, targetid, - (byte)InstantMessageDialog.RequestTeleport, false, - message, sessionID, false, presence.AbsolutePosition, - new Byte[0], true); - m.RegionID = client.Scene.RegionInfo.RegionID.Guid; + m = new GridInstantMessage(scene, client.AgentId, client.FirstName+" "+client.LastName, targetid, + reqType, false, message, dest, false, presence.AbsolutePosition, bucket, true); - m_log.DebugFormat("[HG LURE MODULE]: RequestTeleport sessionID={0}, regionID={1}, message={2}", m.imSessionID, m.RegionID, m.message); - m_PendingLures.Add(sessionID, m, 7200); // 2 hours + if (region == null) + { + m.RegionID = start; + m_log.DebugFormat("[LURE MODULE]: Hypergrid RequestTeleport sessionID={0}, regionID={1}, message={2}", m.imSessionID, m.RegionID, m.message); + m_PendingLures.Add(dest, m, 7200); // 2 hours + } if (m_TransferModule != null) { @@ -208,64 +233,71 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure if (!(client.Scene is Scene)) return; -// Scene scene = (Scene)(client.Scene); - + Scene scene = (Scene)(client.Scene); GridInstantMessage im = null; + if (m_PendingLures.TryGetValue(lureID, out im)) { m_PendingLures.Remove(lureID); - Lure(client, teleportFlags, im); - } - else - m_log.DebugFormat("[HG LURE MODULE]: pending lure {0} not found", lureID); - - } - - private void Lure(IClientAPI client, uint teleportflags, GridInstantMessage im) - { - Scene scene = (Scene)(client.Scene); - GridRegion region = scene.GridService.GetRegionByUUID(scene.RegionInfo.ScopeID, new UUID(im.RegionID)); - if (region != null) - scene.RequestTeleportLocation(client, region.RegionHandle, im.Position + new Vector3(0.5f, 0.5f, 0f), Vector3.UnitX, teleportflags); - else // we don't have that region here. Check if it's HG - { - string[] parts = im.message.Split(new char[] { '@' }); - if (parts.Length > 1) + GridRegion region = scene.GridService.GetRegionByUUID(scene.RegionInfo.ScopeID, new UUID(im.RegionID)); + if (region != null) + scene.RequestTeleportLocation(client, region.RegionHandle, im.Position + new Vector3(0.5f, 0.5f, 2f), Vector3.UnitX, teleportFlags); + else // we don't have that region here. Check if it's HG { - string url = parts[parts.Length - 1]; // the last part - if (url.Trim(new char[] {'/'}) != m_ThisGridURL.Trim(new char[] {'/'})) + string[] parts = im.message.Split(new char[] { '@' }); + if (parts.Length > 1) { - m_log.DebugFormat("[HG LURE MODULE]: Luring agent to grid {0} region {1} position {2}", url, im.RegionID, im.Position); - GatekeeperServiceConnector gConn = new GatekeeperServiceConnector(); - GridRegion gatekeeper = new GridRegion(); - gatekeeper.ServerURI = url; - string homeURI = scene.GetAgentHomeURI(client.AgentId); - - string message; - GridRegion finalDestination = gConn.GetHyperlinkRegion(gatekeeper, new UUID(im.RegionID), client.AgentId, homeURI, out message); - if (finalDestination != null) + string url = parts[parts.Length - 1]; // the last part + if (url.Trim(new char[] {'/'}) != m_ThisGridURL.Trim(new char[] {'/'})) { - ScenePresence sp = scene.GetScenePresence(client.AgentId); - IEntityTransferModule transferMod = scene.RequestModuleInterface(); - - if (transferMod != null && sp != null) + m_log.DebugFormat("[HG LURE MODULE]: Luring agent to remote grid {0} region {1} position {2}", url, im.RegionID, im.Position); + GatekeeperServiceConnector gConn = new GatekeeperServiceConnector(); + GridRegion gatekeeper = new GridRegion(); + gatekeeper.ServerURI = url; + string homeURI = scene.GetAgentHomeURI(client.AgentId); + + string message; + GridRegion finalDestination = gConn.GetHyperlinkRegion(gatekeeper, new UUID(im.RegionID), client.AgentId, homeURI, out message); + if (finalDestination != null) { - if (message != null) - sp.ControllingClient.SendAgentAlertMessage(message, true); + ScenePresence sp = scene.GetScenePresence(client.AgentId); + IEntityTransferModule transferMod = scene.RequestModuleInterface(); - transferMod.DoTeleport( - sp, gatekeeper, finalDestination, im.Position + new Vector3(0.5f, 0.5f, 0f), - Vector3.UnitX, teleportflags); + if (transferMod != null && sp != null) + { + if (message != null) + sp.ControllingClient.SendAgentAlertMessage(message, true); + + transferMod.DoTeleport(sp, gatekeeper, finalDestination, im.Position + new Vector3(0.5f, 0.5f, 2f), Vector3.UnitX, teleportFlags); + } + } + else + { + m_log.InfoFormat("[HG LURE MODULE]: Lure failed: {0}", message); + client.SendAgentAlertMessage(message, true); } - } - else - { - m_log.InfoFormat("[HG LURE MODULE]: Lure failed: {0}", message); - client.SendAgentAlertMessage(message, true); } } } } + else + { + ulong handle = 0; + uint x = 128; + uint y = 128; + uint z = 70; + + Util.ParseFakeParcelID(lureID, out handle, out x, out y, out z); + + Vector3 position = new Vector3(); + position.X = (float)x; + position.Y = (float)y; + position.Z = (float)z; + + m_log.DebugFormat("[LURE MODULE]: Luring agent to local region {0}, position {1}", scene.Name, position); + scene.RequestTeleportLocation(client, handle, position + new Vector3(0.5f, 0.5f, 2f), Vector3.Zero, teleportFlags); + } + } } -} \ No newline at end of file +} -- cgit v1.1 From 50c02b41c7233113b9dddbf191e3e9270b944493 Mon Sep 17 00:00:00 2001 From: onefang Date: Thu, 25 Jul 2019 17:32:20 +1000 Subject: OpenSim dev typo-- --- .../CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs index ba3a7c9..8ebd999 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs @@ -103,7 +103,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess new string[] { "Startup", "Hypergrid", "HGInventoryAccessModule" }, String.Empty); m_ThisGatekeeper = Util.GetConfigVarFromSections(source, "GatekeeperURI", new string[] { "Startup", "Hypergrid", "HGInventoryAccessModule" }, String.Empty); - // Legacy. Renove soon! + // Legacy. Remove soon! m_ThisGatekeeper = thisModuleConfig.GetString("Gatekeeper", m_ThisGatekeeper); m_OutboundPermission = thisModuleConfig.GetBoolean("OutboundPermission", true); -- cgit v1.1 From 77737c81234c98d72bffaa6ddca374504f971b12 Mon Sep 17 00:00:00 2001 From: onefang Date: Thu, 25 Jul 2019 20:19:51 +1000 Subject: Gatekeeper -> GatekeeperURI Coz it says all over the source code - // Legacy. Remove soon! And has since later OpenSim 0.7s. --- OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs | 5 ++--- .../CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs | 2 +- .../ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs index 381bb4d..dfcf925 100644 --- a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs @@ -65,11 +65,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure m_ThisGridURL = Util.GetConfigVarFromSections(config, "GatekeeperURI", new string[] { "Startup", "Hypergrid", "Messaging" }, String.Empty); - // Legacy. Remove soon! - m_ThisGridURL = config.Configs["Messaging"].GetString("Gatekeeper", m_ThisGridURL); - m_log.DebugFormat("[LURE MODULE]: {0} enabled", Name); } + // Legacy. Remove soon! +//// m_ThisGridURL = config.Configs["Messaging"].GetString("Gatekeeper", m_ThisGridURL); } } diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs index 8ebd999..8f6eca6 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs @@ -104,7 +104,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess m_ThisGatekeeper = Util.GetConfigVarFromSections(source, "GatekeeperURI", new string[] { "Startup", "Hypergrid", "HGInventoryAccessModule" }, String.Empty); // Legacy. Remove soon! - m_ThisGatekeeper = thisModuleConfig.GetString("Gatekeeper", m_ThisGatekeeper); +//// m_ThisGatekeeper = thisModuleConfig.GetString("Gatekeeper", m_ThisGatekeeper); m_OutboundPermission = thisModuleConfig.GetBoolean("OutboundPermission", true); m_RestrictInventoryAccessAbroad = thisModuleConfig.GetBoolean("RestrictInventoryAccessAbroad", true); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs index ee17093..0efe99d 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs @@ -129,7 +129,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid m_ThisGatekeeper = Util.GetConfigVarFromSections(source, "GatekeeperURI", new string[] { "Startup", "Hypergrid", "GridService" }, String.Empty); // Legacy. Remove soon! - m_ThisGatekeeper = gridConfig.GetString("Gatekeeper", m_ThisGatekeeper); +//// m_ThisGatekeeper = gridConfig.GetString("Gatekeeper", m_ThisGatekeeper); Util.checkServiceURI(m_ThisGatekeeper, out m_ThisGatekeeper); -- cgit v1.1 From 0a38585d4a15100183acb293edcb9c69190c61db Mon Sep 17 00:00:00 2001 From: onefang Date: Thu, 25 Jul 2019 20:20:21 +1000 Subject: Merge LureModule into HGLureModule. --- .../Region/CoreModules/Avatar/Lure/HGLureModule.cs | 88 ++------ .../Region/CoreModules/Avatar/Lure/LureModule.cs | 234 --------------------- 2 files changed, 18 insertions(+), 304 deletions(-) delete mode 100644 OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs index dfcf925..3dc9bf5 100644 --- a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs @@ -49,7 +49,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure private readonly List m_scenes = new List(); private IMessageTransferModule m_TransferModule = null; - private bool m_Enabled = false; private string m_ThisGridURL; @@ -59,24 +58,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure { if (config.Configs["Messaging"] != null) { - if (config.Configs["Messaging"].GetString("LureModule", string.Empty) == "HGLureModule") - { - m_Enabled = true; - - m_ThisGridURL = Util.GetConfigVarFromSections(config, "GatekeeperURI", - new string[] { "Startup", "Hypergrid", "Messaging" }, String.Empty); - m_log.DebugFormat("[LURE MODULE]: {0} enabled", Name); - } + m_ThisGridURL = Util.GetConfigVarFromSections(config, "GatekeeperURI", new string[] { "Startup", "Hypergrid", "Messaging" }, String.Empty); // Legacy. Remove soon! //// m_ThisGridURL = config.Configs["Messaging"].GetString("Gatekeeper", m_ThisGridURL); + m_log.DebugFormat("[HG LURE MODULE]: {0} enabled", Name); } } public void AddRegion(Scene scene) { - if (!m_Enabled) - return; - lock (m_scenes) { m_scenes.Add(scene); @@ -87,9 +77,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure public void RegionLoaded(Scene scene) { - if (!m_Enabled) - return; - if (m_TransferModule == null) { m_TransferModule = @@ -97,9 +84,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure if (m_TransferModule == null) { - m_log.Error("[LURE MODULE]: No message transfer module, lures will not work!"); - - m_Enabled = false; + m_log.Error("[HG LURE MODULE]: No message transfer module, lures will not work!"); m_scenes.Clear(); scene.EventManager.OnNewClient -= OnNewClient; scene.EventManager.OnIncomingInstantMessage -= OnIncomingInstantMessage; @@ -110,9 +95,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure public void RemoveRegion(Scene scene) { - if (!m_Enabled) - return; - lock (m_scenes) { m_scenes.Remove(scene); @@ -154,17 +136,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure { if (im.dialog == (byte)InstantMessageDialog.RequestTeleport || im.dialog == (byte)InstantMessageDialog.GodLikeRequestTeleport) { - if (1 == im.binaryBucket[0]) + UUID sessionID = new UUID(im.imSessionID); + if (!m_PendingLures.Contains(sessionID)) { - UUID sessionID = new UUID(im.imSessionID); - - if (!m_PendingLures.Contains(sessionID)) - { - m_log.DebugFormat("[HG LURE MODULE]: RequestTeleport sessionID={0}, regionID={1}, message={2}", im.imSessionID, im.RegionID, im.message); - m_PendingLures.Add(sessionID, im, 7200); // 2 hours - } + m_log.DebugFormat("[HG LURE MODULE]: RequestTeleport sessionID={0}, regionID={1}, message={2}", im.imSessionID, im.RegionID, im.message); + m_PendingLures.Add(sessionID, im, 7200); // 2 hours } - // Forward. We do this, because the IM module explicitly rejects IMs of this type if (m_TransferModule != null) m_TransferModule.SendInstantMessage(im, delegate(bool success) { }); @@ -180,45 +157,31 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure ScenePresence presence = scene.GetScenePresence(client.AgentId); ScenePresence target = scene.GetScenePresence(targetid); Guid start = client.Scene.RegionInfo.RegionID.Guid; - UUID dest; + UUID dest = UUID.Random(); byte reqType = (byte)InstantMessageDialog.RequestTeleport; - byte[] bucket = new Byte[1]; - - m_log.DebugFormat("[LURE MODULE]: TP invite with message {0}, type {1} {2} {3} {4}", message, lureType, scene.Permissions.IsAdministrator(client.AgentId), presence.IsViewerUIGod, (!scene.Permissions.IsAdministrator(targetid))); - GridInstantMessage m; GridRegion region = scene.GridService.GetRegionByUUID(scene.RegionInfo.ScopeID, new UUID(start)); if (region != null) { - bucket[0] = 0; - dest = Util.BuildFakeParcelID(scene.RegionInfo.RegionHandle, - (uint)presence.AbsolutePosition.X, (uint)presence.AbsolutePosition.Y, (uint)presence.AbsolutePosition.Z); if (scene.Permissions.IsAdministrator(client.AgentId) && presence.IsViewerUIGod && (!scene.Permissions.IsAdministrator(targetid))) { reqType = (byte)InstantMessageDialog.GodLikeRequestTeleport; - m_log.DebugFormat("[LURE MODULE]: TP FORCE GOD LURE with message {0}, type {1}", message, lureType); + m_log.DebugFormat("[HG LURE MODULE]: TP FORCE GOD LURE with message {0}, type {1}", message, lureType); } else - m_log.DebugFormat("[LURE MODULE]: TP lure with message {0}, type {1}", message, lureType); + m_log.DebugFormat("[HG LURE MODULE]: TP lure with message {0}, type {1}", message, lureType); } else { - m_log.DebugFormat("[LURE MODULE]: HG lure with message {0}, type {1}", message, lureType); - bucket[0] = 1; + m_log.DebugFormat("[HG LURE MODULE]: hypergrid TP lure with message {0}, type {1}", message, lureType); message += "@" + m_ThisGridURL; - dest = UUID.Random(); } m = new GridInstantMessage(scene, client.AgentId, client.FirstName+" "+client.LastName, targetid, - reqType, false, message, dest, false, presence.AbsolutePosition, bucket, true); - - if (region == null) - { - m.RegionID = start; - m_log.DebugFormat("[LURE MODULE]: Hypergrid RequestTeleport sessionID={0}, regionID={1}, message={2}", m.imSessionID, m.RegionID, m.message); - m_PendingLures.Add(dest, m, 7200); // 2 hours - } + reqType, false, message, dest, false, presence.AbsolutePosition, new Byte[0], true); + m.RegionID = start; + m_PendingLures.Add(dest, m, 7200); // 2 hours if (m_TransferModule != null) { @@ -237,10 +200,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure if (m_PendingLures.TryGetValue(lureID, out im)) { + im.Position = im.Position + new Vector3(0.5f, 0.5f, 2f); m_PendingLures.Remove(lureID); GridRegion region = scene.GridService.GetRegionByUUID(scene.RegionInfo.ScopeID, new UUID(im.RegionID)); if (region != null) - scene.RequestTeleportLocation(client, region.RegionHandle, im.Position + new Vector3(0.5f, 0.5f, 2f), Vector3.UnitX, teleportFlags); + scene.RequestTeleportLocation(client, region.RegionHandle, im.Position, Vector3.UnitX, teleportFlags); else // we don't have that region here. Check if it's HG { string[] parts = im.message.Split(new char[] { '@' }); @@ -267,7 +231,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure if (message != null) sp.ControllingClient.SendAgentAlertMessage(message, true); - transferMod.DoTeleport(sp, gatekeeper, finalDestination, im.Position + new Vector3(0.5f, 0.5f, 2f), Vector3.UnitX, teleportFlags); + transferMod.DoTeleport(sp, gatekeeper, finalDestination, im.Position, Vector3.UnitX, teleportFlags); } } else @@ -280,23 +244,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure } } else - { - ulong handle = 0; - uint x = 128; - uint y = 128; - uint z = 70; - - Util.ParseFakeParcelID(lureID, out handle, out x, out y, out z); - - Vector3 position = new Vector3(); - position.X = (float)x; - position.Y = (float)y; - position.Z = (float)z; - - m_log.DebugFormat("[LURE MODULE]: Luring agent to local region {0}, position {1}", scene.Name, position); - scene.RequestTeleportLocation(client, handle, position + new Vector3(0.5f, 0.5f, 2f), Vector3.Zero, teleportFlags); - } - + m_log.DebugFormat("[HG LURE MODULE]: pending lure {0} not found", lureID); } } } diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs deleted file mode 100644 index 6f79676..0000000 --- a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs +++ /dev/null @@ -1,234 +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 Mono.Addins; -using Nini.Config; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.Region.CoreModules.Avatar.Lure -{ - [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LureModule")] - public class LureModule : ISharedRegionModule - { - private static readonly ILog m_log = LogManager.GetLogger( - MethodBase.GetCurrentMethod().DeclaringType); - - private readonly List m_scenes = new List(); - - private IMessageTransferModule m_TransferModule = null; - private bool m_Enabled = false; - - public void Initialise(IConfigSource config) - { - if (config.Configs["Messaging"] != null) - { - if (config.Configs["Messaging"].GetString( - "LureModule", "LureModule") == - "LureModule") - { - m_Enabled = true; - m_log.DebugFormat("[LURE MODULE]: {0} enabled", Name); - } - } - } - - public void AddRegion(Scene scene) - { - if (!m_Enabled) - return; - - lock (m_scenes) - { - m_scenes.Add(scene); - scene.EventManager.OnNewClient += OnNewClient; - scene.EventManager.OnIncomingInstantMessage += - OnGridInstantMessage; - } - } - - public void RegionLoaded(Scene scene) - { - if (!m_Enabled) - return; - - if (m_TransferModule == null) - { - m_TransferModule = - scene.RequestModuleInterface(); - - if (m_TransferModule == null) - { - m_log.Error("[INSTANT MESSAGE]: No message transfer module, "+ - "lures will not work!"); - - m_Enabled = false; - m_scenes.Clear(); - scene.EventManager.OnNewClient -= OnNewClient; - scene.EventManager.OnIncomingInstantMessage -= - OnGridInstantMessage; - } - } - - } - - public void RemoveRegion(Scene scene) - { - if (!m_Enabled) - return; - - lock (m_scenes) - { - m_scenes.Remove(scene); - scene.EventManager.OnNewClient -= OnNewClient; - scene.EventManager.OnIncomingInstantMessage -= - OnGridInstantMessage; - } - } - - void OnNewClient(IClientAPI client) - { - client.OnInstantMessage += OnInstantMessage; - client.OnStartLure += OnStartLure; - client.OnTeleportLureRequest += OnTeleportLureRequest; - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public string Name - { - get { return "LureModule"; } - } - - public Type ReplaceableInterface - { - get { return null; } - } - - public void OnInstantMessage(IClientAPI client, GridInstantMessage im) - { - } - - public void OnStartLure(byte lureType, string message, UUID targetid, IClientAPI client) - { - if (!(client.Scene is Scene)) - return; - - Scene scene = (Scene)(client.Scene); - ScenePresence presence = scene.GetScenePresence(client.AgentId); - - // Round up Z co-ordinate rather than round-down by casting. This stops tall avatars from being given - // a teleport Z co-ordinate by short avatars that drops them through or embeds them in thin floors on - // arrival. - // - // Ideally we would give the exact float position adjusting for the relative height of the two avatars - // but it looks like a float component isn't possible with a parcel ID. - UUID dest = Util.BuildFakeParcelID( - scene.RegionInfo.RegionHandle, - (uint)presence.AbsolutePosition.X, - (uint)presence.AbsolutePosition.Y, - (uint)presence.AbsolutePosition.Z + 2); - - m_log.DebugFormat("[LURE MODULE]: TP invite with message {0}, type {1}", message, lureType); - - GridInstantMessage m; - - if (scene.Permissions.IsAdministrator(client.AgentId) && presence.IsViewerUIGod && (!scene.Permissions.IsAdministrator(targetid))) - { - m = new GridInstantMessage(scene, client.AgentId, - client.FirstName+" "+client.LastName, targetid, - (byte)InstantMessageDialog.GodLikeRequestTeleport, false, - message, dest, false, presence.AbsolutePosition, - new Byte[0], true); - } - else - { - m = new GridInstantMessage(scene, client.AgentId, - client.FirstName+" "+client.LastName, targetid, - (byte)InstantMessageDialog.RequestTeleport, false, - message, dest, false, presence.AbsolutePosition, - new Byte[0], true); - } - - if (m_TransferModule != null) - { - m_TransferModule.SendInstantMessage(m, - delegate(bool success) { }); - } - } - - public void OnTeleportLureRequest(UUID lureID, uint teleportFlags, IClientAPI client) - { - if (!(client.Scene is Scene)) - return; - - Scene scene = (Scene)(client.Scene); - - ulong handle = 0; - uint x = 128; - uint y = 128; - uint z = 70; - - Util.ParseFakeParcelID(lureID, out handle, out x, out y, out z); - - Vector3 position = new Vector3(); - position.X = (float)x; - position.Y = (float)y; - position.Z = (float)z; - - scene.RequestTeleportLocation(client, handle, position, - Vector3.Zero, teleportFlags); - } - - private void OnGridInstantMessage(GridInstantMessage msg) - { - // Forward remote teleport requests - // - if (msg.dialog != (byte)InstantMessageDialog.RequestTeleport && - msg.dialog != (byte)InstantMessageDialog.GodLikeRequestTeleport) - return; - - if (m_TransferModule != null) - { - m_TransferModule.SendInstantMessage(msg, - delegate(bool success) { }); - } - } - } -} -- cgit v1.1 From c3452d3f1b376cd32e89808470a2da470cc176cf Mon Sep 17 00:00:00 2001 From: onefang Date: Wed, 31 Jul 2019 03:55:58 +1000 Subject: OpenSim found a new way for archiving to be spammy. The few resources that I have checked are actually missing from the database. All the ones I tried in world are not missing anything. --- .../Archiver/InventoryArchiveWriteRequest.cs | 24 ++++++++-------------- .../World/Archiver/ArchiveWriteRequest.cs | 16 +++++++-------- 2 files changed, 17 insertions(+), 23 deletions(-) (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs index ad46107..520ea50 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs @@ -231,24 +231,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver if(curErrorCntr > 0 || possible > 0) { - string spath; - int indx = path.IndexOf("__"); - if(indx > 0) - spath = path.Substring(0,indx); - else - spath = path; - if(curErrorCntr > 0) { - m_log.ErrorFormat("[INVENTORY ARCHIVER Warning]: item {0} '{1}', type {2}, in '{3}', contains {4} references to missing or damaged assets", - inventoryItem.ID, inventoryItem.Name, itemAssetType.ToString(), spath, curErrorCntr); - if(possible > 0) - m_log.WarnFormat("[INVENTORY ARCHIVER Warning]: item also contains {0} references that may be to missing or damaged assets or not a problem", possible); - } - else if(possible > 0) - { - m_log.WarnFormat("[INVENTORY ARCHIVER Warning]: item {0} '{1}', type {2}, in '{3}', contains {4} references that may be to missing or damaged assets or not a problem", inventoryItem.ID, inventoryItem.Name, itemAssetType.ToString(), spath, possible); + // path is /name__UUID/name__UUID ... + m_log.WarnFormat("[INVENTORY ARCHIVER Warning]: item {0} '{1}', type {2}, in '{3}', contains {4} references to missing or damaged assets, or not a problem.", + inventoryItem.ID, inventoryItem.Name, itemAssetType.ToString(), path, curErrorCntr); +//// if(possible > 0) +//// m_log.WarnFormat("[INVENTORY ARCHIVER Warning]: item also contains {0} references that may be to missing or damaged assets or not a problem", possible); } +//// else if(possible > 0) +//// { +//// m_log.WarnFormat("[INVENTORY ARCHIVER Warning]: item {0} '{1}', type {2}, in '{3}', contains {4} references that may be to missing or damaged assets or not a problem", inventoryItem.ID, inventoryItem.Name, itemAssetType.ToString(), spath, possible); +//// } } } } diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs index 11c53d7..ec273d6 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs @@ -268,16 +268,16 @@ namespace OpenSim.Region.CoreModules.World.Archiver possible = assetGatherer.possibleNotAssetCount - possible; if(curErrorCntr > 0) { - m_log.ErrorFormat("[ARCHIVER]: object {0} '{1}', at {2}, contains {3} references to missing or damaged assets", + m_log.ErrorFormat("[ARCHIVER]: object {0} '{1}', at {2}, contains {3} references to missing or damaged assets, or not a problem.", sceneObject.UUID, sceneObject.Name ,sceneObject.AbsolutePosition.ToString(), curErrorCntr); - if(possible > 0) - m_log.WarnFormat("[ARCHIVER Warning]: object also contains {0} references that may be to missing or damaged assets or not a problem", possible); - } - else if(possible > 0) - { - m_log.WarnFormat("[ARCHIVER Warning]: object {0} '{1}', at {2}, contains {3} references that may be to missing or damaged assets or not a problem", - sceneObject.UUID, sceneObject.Name ,sceneObject.AbsolutePosition.ToString(), possible); +//// if(possible > 0) +//// m_log.WarnFormat("[ARCHIVER Warning]: object also contains {0} references that may be to missing or damaged assets or not a problem", possible); } +//// else if(possible > 0) +//// { +//// m_log.WarnFormat("[ARCHIVER Warning]: object {0} '{1}', at {2}, contains {3} references that may be to missing or damaged assets or not a problem", +//// sceneObject.UUID, sceneObject.Name ,sceneObject.AbsolutePosition.ToString(), possible); +//// } } assetGatherer.GatherAll(); -- cgit v1.1 From 85fcb4e75c94ff7b5b45609826df5113f32aacc0 Mon Sep 17 00:00:00 2001 From: onefang Date: Fri, 2 Aug 2019 21:20:11 +1000 Subject: Another attempt at sorting out the auto group chicken and egg problems. Are you a local? Asking for a friend. --- .../ServiceConnectorsOut/Authorization/AuthorizationService.cs | 8 +++++--- .../Authorization/LocalAuthorizationServiceConnector.cs | 5 +++-- .../Authorization/RemoteAuthorizationServiceConnector.cs | 4 +++- 3 files changed, 11 insertions(+), 6 deletions(-) (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/AuthorizationService.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/AuthorizationService.cs index 2e06bc8..c910422 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/AuthorizationService.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/AuthorizationService.cs @@ -88,8 +88,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization } public bool IsAuthorizedForRegion( - string user, string firstName, string lastName, string regionID, out string message) + string user, string firstName, string lastName, string regionID, out string message, out bool isLocal) { + UUID userID = new UUID(user); + isLocal = m_UserManagement.IsLocalGridUser(userID); + // This should not happen if (m_Scene.RegionInfo.RegionID.ToString() != regionID) { @@ -105,11 +108,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization return true; } - UUID userID = new UUID(user); if ((m_accessValue & AccessFlags.DisallowForeigners) != 0) { - if (!m_UserManagement.IsLocalGridUser(userID)) + if (!isLocal) { message = "No foreign users allowed in this region"; return false; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/LocalAuthorizationServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/LocalAuthorizationServiceConnector.cs index 0be0676..b2be907 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/LocalAuthorizationServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/LocalAuthorizationServiceConnector.cs @@ -114,13 +114,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization } public bool IsAuthorizedForRegion( - string userID, string firstName, string lastName, string regionID, out string message) + string userID, string firstName, string lastName, string regionID, out string message, out bool isLocal) { message = ""; + isLocal = false; if (!m_Enabled) return true; - return m_AuthorizationService.IsAuthorizedForRegion(userID, firstName, lastName, regionID, out message); + return m_AuthorizationService.IsAuthorizedForRegion(userID, firstName, lastName, regionID, out message, out isLocal); } } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/RemoteAuthorizationServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/RemoteAuthorizationServiceConnector.cs index f312b0d..3df3288 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/RemoteAuthorizationServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/RemoteAuthorizationServiceConnector.cs @@ -120,7 +120,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization } public bool IsAuthorizedForRegion( - string userID, string firstName, string lastName, string regionID, out string message) + string userID, string firstName, string lastName, string regionID, out string message, out bool isLocal) { m_log.InfoFormat( "[REMOTE AUTHORIZATION CONNECTOR]: IsAuthorizedForRegion checking {0} for region {1}", userID, regionID); @@ -141,6 +141,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization } } + isLocal = false; if (scene != null) { string mail = String.Empty; @@ -153,6 +154,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization mail = account.Email; firstName = account.FirstName; lastName = account.LastName; + isLocal = true; } isAuthorized -- cgit v1.1 From ef3c5c34f8b564203968b87453371f60478229f8 Mon Sep 17 00:00:00 2001 From: onefang Date: Mon, 5 Aug 2019 01:41:15 +1000 Subject: Warning-- --- OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index 4b55860..924f448 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -1360,7 +1360,7 @@ namespace OpenSim.Region.CoreModules.World.Estate { file = file + Uri.EscapeDataString(Scene.Name) + ".raw"; } - catch (Exception ex) + catch (Exception) { file = file + ".raw"; } -- cgit v1.1 From 7aecb3c7d9262b7dcd43b45736bb008a2f1ca742 Mon Sep 17 00:00:00 2001 From: onefang Date: Thu, 15 Aug 2019 02:18:35 +1000 Subject: Bandaid for ghost users, check and remove them from Presence when they log on. Once again OOP proves it's worse that spaghetti, but cutting up the spaghetti and hiding it all over the kitchen. Note the commented out bits from GateKeeperService.cs, this stuff is checked TWICE, though this time is for HGers, or not. --- .../ServiceConnectorsOut/Presence/BasePresenceServiceConnector.cs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/BasePresenceServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/BasePresenceServiceConnector.cs index fdbe10a..e014a57 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/BasePresenceServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/BasePresenceServiceConnector.cs @@ -123,6 +123,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence return m_PresenceService.GetAgent(sessionID); } + public PresenceInfo GetAgentByUser(UUID userID) + { + return m_PresenceService.GetAgentByUser(userID); + } + public PresenceInfo[] GetAgents(string[] userIDs) { // Don't bother potentially making a useless network call if we not going to ask for any users anyway. -- cgit v1.1 From fe8977564bda8ec2f328ebb2d2623c43073e9be5 Mon Sep 17 00:00:00 2001 From: onefang Date: Thu, 22 Aug 2019 12:01:47 +1000 Subject: When the generate map command is given, generate the map. The month check seems a bit dodgy, but I'll let it ride for now. --- .../CoreModules/World/LegacyMap/MapImageModule.cs | 4 ++++ .../World/Warp3DMap/Warp3DImageModule.cs | 13 +++++++++++- .../CoreModules/World/WorldMap/WorldMapModule.cs | 24 +++++++++++++++++++++- 3 files changed, 39 insertions(+), 2 deletions(-) (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs index b927cfa..1e63662 100644 --- a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs +++ b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs @@ -73,6 +73,10 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap #region IMapImageGenerator Members + public Bitmap CreateMapTileForce() + { + return CreateMapTile(); + } public Bitmap CreateMapTile() { bool drawPrimVolume = true; diff --git a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs index fb94853..d094bee 100644 --- a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs +++ b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs @@ -245,10 +245,20 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap g.Flush(); } */ + public Bitmap CreateMapTileForce() + { + m_log.Info("[MAPTILE]: Forcing a map tile regenerate."); + File.Delete(System.IO.Path.Combine(m_cacheDirectory, m_scene.RegionInfo.RegionID + ".bmp")); + return CreateMapTile(); + } public Bitmap CreateMapTile() { - if ((File.GetCreationTime(System.IO.Path.Combine(m_cacheDirectory, m_scene.RegionInfo.RegionID + ".bmp")).Month != DateTime.Now.Month) && m_enable_refreshEveryMonth == true) + if ((File.GetCreationTime(System.IO.Path.Combine(m_cacheDirectory, m_scene.RegionInfo.RegionID + ".bmp")).Month != DateTime.Now.Month) && (m_enable_refreshEveryMonth == true)) + { + m_log.InfoFormat("[MAPTILE]: Clearing old map tile out of cache {0} {1}.", + File.GetCreationTime(System.IO.Path.Combine(m_cacheDirectory, m_scene.RegionInfo.RegionID + ".bmp")).Month, DateTime.Now.Month); File.Delete(System.IO.Path.Combine(m_cacheDirectory, m_scene.RegionInfo.RegionID + ".bmp")); + } if(File.Exists(System.IO.Path.Combine(m_cacheDirectory, m_scene.RegionInfo.RegionID + ".bmp"))) { @@ -256,6 +266,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap } else { + m_log.Info("[MAPTILE]: Actually generating a map tile."); /* this must be on all map, not just its image if ((DateTime.Now - lastImageTime).TotalSeconds < 3600) { diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index 03a4d34..94072a5 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs @@ -1458,7 +1458,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap if (consoleScene != null && consoleScene != m_scene) return; - GenerateMaptile(); + GenerateMaptileForce(); } public OSD HandleRemoteMapItemRequest(string path, OSD request, string endpoint) @@ -1572,6 +1572,28 @@ namespace OpenSim.Region.CoreModules.World.WorldMap return responsemap; } + private void GenerateMaptileForce() + { + // Cannot create a map for a nonexistent heightmap + if (m_scene.Heightmap == null) + return; + + if (m_mapImageGenerator == null) + { + Console.WriteLine("No map image generator available for {0}", m_scene.Name); + return; + } + m_log.DebugFormat("[WORLD MAP]: Generating map image for {0}", m_scene.Name); + + using (Bitmap mapbmp = m_mapImageGenerator.CreateMapTileForce()) + { + GenerateMaptile(mapbmp); + + if (m_mapImageServiceModule != null) + m_mapImageServiceModule.UploadMapTile(m_scene, mapbmp); + } + } + public void GenerateMaptile() { // Cannot create a map for a nonexistent heightmap -- cgit v1.1