aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules
diff options
context:
space:
mode:
authorDavid Walter Seikel2016-11-03 21:44:39 +1000
committerDavid Walter Seikel2016-11-03 21:44:39 +1000
commit134f86e8d5c414409631b25b8c6f0ee45fbd8631 (patch)
tree216b89d3fb89acfb81be1e440c25c41ab09fa96d /OpenSim/Region/CoreModules
parentMore changing to production grid. Double oops. (diff)
downloadopensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.zip
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.gz
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.bz2
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.xz
Initial update to OpenSim 0.8.2.1 source code.
Diffstat (limited to '')
-rwxr-xr-xOpenSim/Framework/LogWriter.cs (renamed from OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs)21
-rw-r--r--OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs9
-rw-r--r--OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs21
-rw-r--r--OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs28
-rw-r--r--OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs17
-rw-r--r--OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs5
-rw-r--r--OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs400
-rw-r--r--OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs5
-rw-r--r--OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs1
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs792
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs430
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs544
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs93
-rw-r--r--OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs200
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs168
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs285
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs5
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs30
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs5
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs50
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs31
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs20
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs1
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs198
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs18
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs170
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs1
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs10
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs155
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs86
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs120
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs106
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs (renamed from OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs)179
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs192
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs (renamed from OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs)275
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs8
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs166
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs448
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs23
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs3
-rw-r--r--OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs1406
-rw-r--r--OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs419
-rw-r--r--OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs124
-rw-r--r--OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs139
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs2058
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs148
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs290
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs224
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs198
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs359
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs146
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs7
-rw-r--r--OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs6
-rw-r--r--OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs48
-rw-r--r--OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs46
-rw-r--r--OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs199
-rw-r--r--OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs256
-rw-r--r--OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs19
-rw-r--r--OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs (renamed from OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs)81
-rw-r--r--OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs619
-rw-r--r--OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs72
-rw-r--r--OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs8
-rw-r--r--OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs6
-rw-r--r--OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs4
-rw-r--r--OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs355
-rw-r--r--OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs199
-rw-r--r--OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs96
-rw-r--r--OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs57
-rw-r--r--OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs23
-rw-r--r--OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs5
-rw-r--r--OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs21
-rw-r--r--OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs10
-rw-r--r--OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs31
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs228
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/LocalAgentPreferencesServiceConnector.cs153
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/RemoteAgentPreferencesServiceConnector.cs116
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs47
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs13
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs46
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/AuthorizationService.cs34
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs100
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs9
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs57
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs3
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs28
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs131
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs84
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs38
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs50
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs137
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs4
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs5
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs86
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs74
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs10
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs7
-rw-r--r--OpenSim/Region/CoreModules/World/Access/AccessModule.cs10
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs314
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs84
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs109
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs9
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs36
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs23
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs45
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs519
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/EstateTerrainXferHandler.cs6
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs218
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs255
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs288
-rw-r--r--OpenSim/Region/CoreModules/World/Land/DwellModule.cs22
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandChannel.cs5
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs938
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandObject.cs324
-rw-r--r--OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs11
-rw-r--r--OpenSim/Region/CoreModules/World/Land/Tests/LandManagementModuleTests.cs266
-rw-r--r--OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs1
-rw-r--r--OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs694
-rw-r--r--OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs41
-rw-r--r--OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs64
-rw-r--r--OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs7
-rw-r--r--OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs3
-rw-r--r--OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs1
-rw-r--r--OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs21
-rw-r--r--OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs32
-rw-r--r--OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs153
-rw-r--r--OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs160
-rw-r--r--OpenSim/Region/CoreModules/World/Region/RestartModule.cs32
-rw-r--r--OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs30
-rw-r--r--OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs556
-rw-r--r--OpenSim/Region/CoreModules/World/Sound/SoundModule.cs9
-rw-r--r--OpenSim/Region/CoreModules/World/Sun/SunModule.cs225
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs235
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs13
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs49
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/ITerrainFeature.cs (renamed from OpenSim/Framework/Communications/XMPP/XmppStanza.cs)54
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs (renamed from OpenSim/Framework/ForeignUserProfileData.cs)72
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs93
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs92
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs92
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs92
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs108
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs92
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs131
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs378
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs17
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs814
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainModuleTests.cs75
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs36
-rw-r--r--OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs436
-rw-r--r--OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs260
-rw-r--r--OpenSim/Region/CoreModules/World/Wind/WindModule.cs38
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs94
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs517
161 files changed, 18226 insertions, 5547 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs b/OpenSim/Framework/LogWriter.cs
index fd8d5e3..2e0bf4a 100755
--- a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs
+++ b/OpenSim/Framework/LogWriter.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -30,7 +30,7 @@ using System.IO;
30using System.Text; 30using System.Text;
31using log4net; 31using log4net;
32 32
33namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging 33namespace OpenSim.Framework
34{ 34{
35 /// <summary> 35 /// <summary>
36 /// Class for writing a high performance, high volume log file. 36 /// Class for writing a high performance, high volume log file.
@@ -52,6 +52,7 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
52 private TimeSpan m_logFileLife; 52 private TimeSpan m_logFileLife;
53 private DateTime m_logFileEndTime; 53 private DateTime m_logFileEndTime;
54 private Object m_logFileWriteLock = new Object(); 54 private Object m_logFileWriteLock = new Object();
55 private bool m_flushWrite;
55 56
56 // set externally when debugging. If let 'null', this does not write any error messages. 57 // set externally when debugging. If let 'null', this does not write any error messages.
57 public ILog ErrorLogger = null; 58 public ILog ErrorLogger = null;
@@ -73,7 +74,9 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
73 /// <param name="dir">The directory to create the log file in. May be 'null' for default.</param> 74 /// <param name="dir">The directory to create the log file in. May be 'null' for default.</param>
74 /// <param name="headr">The characters that begin the log file name. May be 'null' for default.</param> 75 /// <param name="headr">The characters that begin the log file name. May be 'null' for default.</param>
75 /// <param name="maxFileTime">Maximum age of a log file in minutes. If zero, will set default.</param> 76 /// <param name="maxFileTime">Maximum age of a log file in minutes. If zero, will set default.</param>
76 public LogWriter(string dir, string headr, int maxFileTime) 77 /// <param name="flushWrite">Whether to do a flush after every log write. Best left off but
78 /// if one is looking for a crash, this is a good thing to turn on.</param>
79 public LogWriter(string dir, string headr, int maxFileTime, bool flushWrite)
77 { 80 {
78 m_logDirectory = dir == null ? "." : dir; 81 m_logDirectory = dir == null ? "." : dir;
79 82
@@ -86,8 +89,14 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
86 m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0); 89 m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0);
87 m_logFileEndTime = DateTime.Now + m_logFileLife; 90 m_logFileEndTime = DateTime.Now + m_logFileLife;
88 91
92 m_flushWrite = flushWrite;
93
89 Enabled = true; 94 Enabled = true;
90 } 95 }
96 // Constructor that assumes flushWrite is off.
97 public LogWriter(string dir, string headr, int maxFileTime) : this(dir, headr, maxFileTime, false)
98 {
99 }
91 100
92 public void Dispose() 101 public void Dispose()
93 { 102 {
@@ -127,7 +136,7 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
127 { 136 {
128 lock (m_logFileWriteLock) 137 lock (m_logFileWriteLock)
129 { 138 {
130 DateTime now = DateTime.Now; 139 DateTime now = DateTime.UtcNow;
131 if (m_logFile == null || now > m_logFileEndTime) 140 if (m_logFile == null || now > m_logFileEndTime)
132 { 141 {
133 if (m_logFile != null) 142 if (m_logFile != null)
@@ -142,7 +151,7 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
142 string path = (m_logDirectory.Length > 0 ? m_logDirectory 151 string path = (m_logDirectory.Length > 0 ? m_logDirectory
143 + System.IO.Path.DirectorySeparatorChar.ToString() : "") 152 + System.IO.Path.DirectorySeparatorChar.ToString() : "")
144 + String.Format("{0}{1}.log", LogFileHeader, now.ToString("yyyyMMddHHmmss")); 153 + String.Format("{0}{1}.log", LogFileHeader, now.ToString("yyyyMMddHHmmss"));
145 m_logFile = new StreamWriter(File.Open(path, FileMode.Append, FileAccess.Write)); 154 m_logFile = new StreamWriter(File.Open(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite));
146 } 155 }
147 if (m_logFile != null) 156 if (m_logFile != null)
148 { 157 {
@@ -153,6 +162,8 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
153 buff.Append(line); 162 buff.Append(line);
154 buff.Append("\r\n"); 163 buff.Append("\r\n");
155 m_logFile.Write(buff.ToString()); 164 m_logFile.Write(buff.ToString());
165 if (m_flushWrite)
166 m_logFile.Flush();
156 } 167 }
157 } 168 }
158 } 169 }
diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs
index 0271738..f56d17d 100644
--- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs
+++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs
@@ -33,6 +33,7 @@ using OpenSim.Framework;
33 33
34using OpenSim.Region.Framework.Scenes; 34using OpenSim.Region.Framework.Scenes;
35using OpenSim.Services.Interfaces; 35using OpenSim.Services.Interfaces;
36using OpenSim.Region.Framework.Interfaces;
36 37
37namespace OpenSim.Region.CoreModules.Agent.AssetTransaction 38namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
38{ 39{
@@ -119,6 +120,14 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
119 } 120 }
120 else 121 else
121 { 122 {
123 // Check if the xfer is a terrain xfer
124 IEstateModule estateModule = m_Scene.RequestModuleInterface<IEstateModule>();
125 if (estateModule != null)
126 {
127 if (estateModule.IsTerrainXfer(xferID))
128 return;
129 }
130
122 m_log.ErrorFormat( 131 m_log.ErrorFormat(
123 "[AGENT ASSET TRANSACTIONS]: Could not find uploader for xfer id {0}, packet id {1}, data length {2}", 132 "[AGENT ASSET TRANSACTIONS]: Could not find uploader for xfer id {0}, packet id {1}, data length {2}",
124 xferID, packetID, data.Length); 133 xferID, packetID, data.Length);
diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs
index d1ad74f..b67c0df 100644
--- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs
+++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs
@@ -42,7 +42,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
42 public class AssetTransactionModule : INonSharedRegionModule, 42 public class AssetTransactionModule : INonSharedRegionModule,
43 IAgentAssetTransactions 43 IAgentAssetTransactions
44 { 44 {
45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 45// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 46
47 protected Scene m_Scene; 47 protected Scene m_Scene;
48 private bool m_dumpAssetsToFile = false; 48 private bool m_dumpAssetsToFile = false;
diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs
index 11efe6d..5143204 100644
--- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs
+++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs
@@ -31,8 +31,10 @@ using System.Reflection;
31using log4net; 31using log4net;
32using OpenMetaverse; 32using OpenMetaverse;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes; 35using OpenSim.Region.Framework.Scenes;
35using OpenSim.Services.Interfaces; 36using OpenSim.Services.Interfaces;
37using PermissionMask = OpenSim.Framework.PermissionMask;
36 38
37namespace OpenSim.Region.CoreModules.Agent.AssetTransaction 39namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
38{ 40{
@@ -317,12 +319,14 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
317 m_asset.Description = item.Description; 319 m_asset.Description = item.Description;
318 m_asset.Type = (sbyte)item.AssetType; 320 m_asset.Type = (sbyte)item.AssetType;
319 321
320 // We must always store the item at this point even if the asset hasn't finished uploading, in order 322 if (m_asset.FullID != UUID.Zero)
321 // to avoid a race condition when the appearance module retrieves the item to set the asset id in 323 {
322 // the AvatarAppearance structure. 324 // We must always store the item at this point even if the asset hasn't finished uploading, in order
323 item.AssetID = m_asset.FullID; 325 // to avoid a race condition when the appearance module retrieves the item to set the asset id in
324 if (item.AssetID != UUID.Zero) 326 // the AvatarAppearance structure.
327 item.AssetID = m_asset.FullID;
325 m_Scene.InventoryService.UpdateItem(item); 328 m_Scene.InventoryService.UpdateItem(item);
329 }
326 330
327 if (m_uploadState == UploadState.Complete) 331 if (m_uploadState == UploadState.Complete)
328 { 332 {
@@ -375,6 +379,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
375 m_Scene.AssetService.Store(m_asset); 379 m_Scene.AssetService.Store(m_asset);
376 380
377 m_transactions.RemoveXferUploader(m_transactionID); 381 m_transactions.RemoveXferUploader(m_transactionID);
382
383 m_Scene.EventManager.TriggerOnNewInventoryItemUploadComplete(ourClient.AgentId, (AssetType)type, m_asset.FullID, m_asset.Name, 0);
378 } 384 }
379 385
380 /// <summary> 386 /// <summary>
@@ -406,8 +412,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
406 item.AssetType = type; 412 item.AssetType = type;
407 item.InvType = invType; 413 item.InvType = invType;
408 item.Folder = InventFolder; 414 item.Folder = InventFolder;
409 item.BasePermissions = 0x7fffffff; 415 item.BasePermissions = (uint)(PermissionMask.All | PermissionMask.Export);
410 item.CurrentPermissions = 0x7fffffff; 416 item.CurrentPermissions = item.BasePermissions;
411 item.GroupPermissions=0; 417 item.GroupPermissions=0;
412 item.EveryOnePermissions=0; 418 item.EveryOnePermissions=0;
413 item.NextPermissions = nextPerm; 419 item.NextPermissions = nextPerm;
@@ -421,5 +427,6 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
421 427
422 m_transactions.RemoveXferUploader(m_transactionID); 428 m_transactions.RemoveXferUploader(m_transactionID);
423 } 429 }
430
424 } 431 }
425} \ No newline at end of file 432} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs b/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs
index 3764685..47dcbcd 100644
--- a/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs
+++ b/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Drawing;
30using System.IO; 31using System.IO;
31using System.Reflection; 32using System.Reflection;
32using System.Text; 33using System.Text;
@@ -166,7 +167,7 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
166 167
167 // Do Decode! 168 // Do Decode!
168 if (decode) 169 if (decode)
169 Decode(assetID, j2kData); 170 Util.FireAndForget(delegate { Decode(assetID, j2kData); }, null, "J2KDecoderModule.BeginDecode");
170 } 171 }
171 } 172 }
172 173
@@ -182,6 +183,25 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
182 return DoJ2KDecode(assetID, j2kData, out layers, out components); 183 return DoJ2KDecode(assetID, j2kData, out layers, out components);
183 } 184 }
184 185
186 public Image DecodeToImage(byte[] j2kData)
187 {
188 if (m_useCSJ2K)
189 return J2kImage.FromBytes(j2kData);
190 else
191 {
192 ManagedImage mimage;
193 Image image;
194 if (OpenJPEG.DecodeToImage(j2kData, out mimage, out image))
195 {
196 mimage = null;
197 return image;
198 }
199 else
200 return null;
201 }
202 }
203
204
185 #endregion IJ2KDecoder 205 #endregion IJ2KDecoder
186 206
187 /// <summary> 207 /// <summary>
@@ -211,7 +231,11 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
211 { 231 {
212 try 232 try
213 { 233 {
214 List<int> layerStarts = CSJ2K.J2kImage.GetLayerBoundaries(new MemoryStream(j2kData)); 234 List<int> layerStarts;
235 using (MemoryStream ms = new MemoryStream(j2kData))
236 {
237 layerStarts = CSJ2K.J2kImage.GetLayerBoundaries(ms);
238 }
215 239
216 if (layerStarts != null && layerStarts.Count > 0) 240 if (layerStarts != null && layerStarts.Count > 0)
217 { 241 {
diff --git a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs
index e40caec..ebec9d2 100644
--- a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs
+++ b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs
@@ -194,6 +194,14 @@ namespace OpenSim.Region.CoreModules.Asset
194 194
195 #region IImprovedAssetCache Members 195 #region IImprovedAssetCache Members
196 196
197 public bool Check(string id)
198 {
199 AssetBase asset;
200
201 // XXX:This is probably not an efficient implementation.
202 return m_cache.TryGetValue(id, out asset);
203 }
204
197 /// <summary> 205 /// <summary>
198 /// Cache asset. 206 /// Cache asset.
199 /// </summary> 207 /// </summary>
@@ -308,9 +316,12 @@ namespace OpenSim.Region.CoreModules.Asset
308 /// </summary> 316 /// </summary>
309 public void Close() 317 public void Close()
310 { 318 {
311 m_enabled = false; 319 if (m_enabled)
312 m_cache.Clear(); 320 {
313 m_cache = null; 321 m_enabled = false;
322 m_cache.Clear();
323 m_cache = null;
324 }
314 } 325 }
315 326
316 /// <summary> 327 /// <summary>
diff --git a/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs
index 9742a5c..f720748 100644
--- a/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs
+++ b/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs
@@ -112,6 +112,11 @@ namespace OpenSim.Region.CoreModules.Asset
112 //////////////////////////////////////////////////////////// 112 ////////////////////////////////////////////////////////////
113 // IImprovedAssetCache 113 // IImprovedAssetCache
114 // 114 //
115 public bool Check(string id)
116 {
117 // XXX This is probably not an efficient implementation.
118 return Get(id) != null;
119 }
115 120
116 public void Cache(AssetBase asset) 121 public void Cache(AssetBase asset)
117 { 122 {
diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
index 8e800cb..7d9c9a9 100644
--- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
+++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
@@ -31,26 +31,26 @@
31using System; 31using System;
32using System.IO; 32using System.IO;
33using System.Collections.Generic; 33using System.Collections.Generic;
34using System.Linq;
34using System.Reflection; 35using System.Reflection;
35using System.Runtime.Serialization; 36using System.Runtime.Serialization;
36using System.Runtime.Serialization.Formatters.Binary; 37using System.Runtime.Serialization.Formatters.Binary;
37using System.Threading; 38using System.Threading;
38using System.Timers; 39using System.Timers;
39
40using log4net; 40using log4net;
41using Nini.Config; 41using Nini.Config;
42using Mono.Addins; 42using Mono.Addins;
43using OpenMetaverse; 43using OpenMetaverse;
44
45using OpenSim.Framework; 44using OpenSim.Framework;
46using OpenSim.Framework.Console; 45using OpenSim.Framework.Console;
46using OpenSim.Framework.Monitoring;
47using OpenSim.Region.Framework.Interfaces; 47using OpenSim.Region.Framework.Interfaces;
48using OpenSim.Region.Framework.Scenes; 48using OpenSim.Region.Framework.Scenes;
49using OpenSim.Services.Interfaces; 49using OpenSim.Services.Interfaces;
50 50
51 51
52//[assembly: Addin("FlotsamAssetCache", "1.1")] 52//[assembly: Addin("FlotsamAssetCache", "1.1")]
53//[assembly: AddinDependency("OpenSim", "0.5")] 53//[assembly: AddinDependency("OpenSim", "0.8.1")]
54 54
55namespace OpenSim.Region.CoreModules.Asset 55namespace OpenSim.Region.CoreModules.Asset
56{ 56{
@@ -76,8 +76,6 @@ namespace OpenSim.Region.CoreModules.Asset
76 private static ulong m_RequestsForInprogress; 76 private static ulong m_RequestsForInprogress;
77 private static ulong m_DiskHits; 77 private static ulong m_DiskHits;
78 private static ulong m_MemoryHits; 78 private static ulong m_MemoryHits;
79 private static double m_HitRateMemory;
80 private static double m_HitRateFile;
81 79
82#if WAIT_ON_INPROGRESS_REQUESTS 80#if WAIT_ON_INPROGRESS_REQUESTS
83 private Dictionary<string, ManualResetEvent> m_CurrentlyWriting = new Dictionary<string, ManualResetEvent>(); 81 private Dictionary<string, ManualResetEvent> m_CurrentlyWriting = new Dictionary<string, ManualResetEvent>();
@@ -251,23 +249,19 @@ namespace OpenSim.Region.CoreModules.Asset
251 249
252 private void UpdateFileCache(string key, AssetBase asset) 250 private void UpdateFileCache(string key, AssetBase asset)
253 { 251 {
254 string filename = GetFileName(asset.ID); 252 string filename = GetFileName(key);
255 253
256 try 254 try
257 { 255 {
258 // If the file is already cached just update access time. 256 // If the file is already cached, don't cache it, just touch it so access time is updated
259 if (File.Exists(filename)) 257 if (File.Exists(filename))
260 { 258 {
261 lock (m_CurrentlyWriting) 259 UpdateFileLastAccessTime(filename);
262 { 260 }
263 if (!m_CurrentlyWriting.Contains(filename)) 261 else
264 File.SetLastAccessTime(filename, DateTime.Now);
265 }
266 }
267 else
268 { 262 {
269 // Once we start writing, make sure we flag that we're writing 263 // Once we start writing, make sure we flag that we're writing
270 // that object to the cache so that we don't try to write the 264 // that object to the cache so that we don't try to write the
271 // same file multiple times. 265 // same file multiple times.
272 lock (m_CurrentlyWriting) 266 lock (m_CurrentlyWriting)
273 { 267 {
@@ -279,7 +273,7 @@ namespace OpenSim.Region.CoreModules.Asset
279 else 273 else
280 { 274 {
281 m_CurrentlyWriting.Add(filename, new ManualResetEvent(false)); 275 m_CurrentlyWriting.Add(filename, new ManualResetEvent(false));
282 } 276 }
283 277
284#else 278#else
285 if (m_CurrentlyWriting.Contains(filename)) 279 if (m_CurrentlyWriting.Contains(filename))
@@ -291,10 +285,11 @@ namespace OpenSim.Region.CoreModules.Asset
291 m_CurrentlyWriting.Add(filename); 285 m_CurrentlyWriting.Add(filename);
292 } 286 }
293#endif 287#endif
288
294 } 289 }
295 290
296 Util.FireAndForget( 291 Util.FireAndForget(
297 delegate { WriteFileCache(filename, asset); }); 292 delegate { WriteFileCache(filename, asset); }, null, "FlotsamAssetCache.UpdateFileCache");
298 } 293 }
299 } 294 }
300 catch (Exception e) 295 catch (Exception e)
@@ -321,6 +316,24 @@ namespace OpenSim.Region.CoreModules.Asset
321 } 316 }
322 317
323 /// <summary> 318 /// <summary>
319 /// Updates the cached file with the current time.
320 /// </summary>
321 /// <param name="filename">Filename.</param>
322 /// <returns><c>true</c>, if the update was successful, false otherwise.</returns>
323 private bool UpdateFileLastAccessTime(string filename)
324 {
325 try
326 {
327 File.SetLastAccessTime(filename, DateTime.Now);
328 return true;
329 }
330 catch
331 {
332 return false;
333 }
334 }
335
336 /// <summary>
324 /// Try to get an asset from the in-memory cache. 337 /// Try to get an asset from the in-memory cache.
325 /// </summary> 338 /// </summary>
326 /// <param name="id"></param> 339 /// <param name="id"></param>
@@ -335,31 +348,62 @@ namespace OpenSim.Region.CoreModules.Asset
335 return asset; 348 return asset;
336 } 349 }
337 350
351 private bool CheckFromMemoryCache(string id)
352 {
353 return m_MemoryCache.Contains(id);
354 }
355
338 /// <summary> 356 /// <summary>
339 /// Try to get an asset from the file cache. 357 /// Try to get an asset from the file cache.
340 /// </summary> 358 /// </summary>
341 /// <param name="id"></param> 359 /// <param name="id"></param>
342 /// <returns></returns> 360 /// <returns>An asset retrieved from the file cache. null if there was a problem retrieving an asset.</returns>
343 private AssetBase GetFromFileCache(string id) 361 private AssetBase GetFromFileCache(string id)
344 { 362 {
363 string filename = GetFileName(id);
364
365#if WAIT_ON_INPROGRESS_REQUESTS
366 // Check if we're already downloading this asset. If so, try to wait for it to
367 // download.
368 if (m_WaitOnInprogressTimeout > 0)
369 {
370 m_RequestsForInprogress++;
371
372 ManualResetEvent waitEvent;
373 if (m_CurrentlyWriting.TryGetValue(filename, out waitEvent))
374 {
375 waitEvent.WaitOne(m_WaitOnInprogressTimeout);
376 return Get(id);
377 }
378 }
379#else
380 // Track how often we have the problem that an asset is requested while
381 // it is still being downloaded by a previous request.
382 if (m_CurrentlyWriting.Contains(filename))
383 {
384 m_RequestsForInprogress++;
385 return null;
386 }
387#endif
388
345 AssetBase asset = null; 389 AssetBase asset = null;
346 390
347 string filename = GetFileName(id);
348 if (File.Exists(filename)) 391 if (File.Exists(filename))
349 { 392 {
350 FileStream stream = null;
351 try 393 try
352 { 394 {
353 stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read); 395 using (FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
354 BinaryFormatter bformatter = new BinaryFormatter(); 396 {
397 BinaryFormatter bformatter = new BinaryFormatter();
355 398
356 asset = (AssetBase)bformatter.Deserialize(stream); 399 asset = (AssetBase)bformatter.Deserialize(stream);
357 400
358 m_DiskHits++; 401 m_DiskHits++;
402 }
359 } 403 }
360 catch (System.Runtime.Serialization.SerializationException e) 404 catch (System.Runtime.Serialization.SerializationException e)
361 { 405 {
362 m_log.ErrorFormat( 406 m_log.WarnFormat(
363 "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}", 407 "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}",
364 filename, id, e.Message, e.StackTrace); 408 filename, id, e.Message, e.StackTrace);
365 409
@@ -371,40 +415,40 @@ namespace OpenSim.Region.CoreModules.Asset
371 } 415 }
372 catch (Exception e) 416 catch (Exception e)
373 { 417 {
374 m_log.ErrorFormat( 418 m_log.WarnFormat(
375 "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}", 419 "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}",
376 filename, id, e.Message, e.StackTrace); 420 filename, id, e.Message, e.StackTrace);
377 } 421 }
378 finally
379 {
380 if (stream != null)
381 stream.Close();
382 }
383 } 422 }
384 423
385#if WAIT_ON_INPROGRESS_REQUESTS 424 return asset;
386 // Check if we're already downloading this asset. If so, try to wait for it to 425 }
387 // download.
388 if (m_WaitOnInprogressTimeout > 0)
389 {
390 m_RequestsForInprogress++;
391 426
392 ManualResetEvent waitEvent; 427 private bool CheckFromFileCache(string id)
393 if (m_CurrentlyWriting.TryGetValue(filename, out waitEvent)) 428 {
429 bool found = false;
430
431 string filename = GetFileName(id);
432
433 if (File.Exists(filename))
434 {
435 try
394 { 436 {
395 waitEvent.WaitOne(m_WaitOnInprogressTimeout); 437 using (FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
396 return Get(id); 438 {
439 if (stream != null)
440 found = true;
441 }
442 }
443 catch (Exception e)
444 {
445 m_log.ErrorFormat(
446 "[FLOTSAM ASSET CACHE]: Failed to check file {0} for asset {1}. Exception {2} {3}",
447 filename, id, e.Message, e.StackTrace);
397 } 448 }
398 } 449 }
399#else 450
400 // Track how often we have the problem that an asset is requested while 451 return found;
401 // it is still being downloaded by a previous request.
402 if (m_CurrentlyWriting.Contains(filename))
403 {
404 m_RequestsForInprogress++;
405 }
406#endif
407 return asset;
408 } 452 }
409 453
410 public AssetBase Get(string id) 454 public AssetBase Get(string id)
@@ -426,23 +470,24 @@ namespace OpenSim.Region.CoreModules.Asset
426 470
427 if (((m_LogLevel >= 1)) && (m_HitRateDisplay != 0) && (m_Requests % m_HitRateDisplay == 0)) 471 if (((m_LogLevel >= 1)) && (m_HitRateDisplay != 0) && (m_Requests % m_HitRateDisplay == 0))
428 { 472 {
429 m_HitRateFile = (double)m_DiskHits / m_Requests * 100.0;
430
431 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Get :: {0} :: {1}", id, asset == null ? "Miss" : "Hit"); 473 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Get :: {0} :: {1}", id, asset == null ? "Miss" : "Hit");
432 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: File Hit Rate {0}% for {1} requests", m_HitRateFile.ToString("0.00"), m_Requests);
433
434 if (m_MemoryCacheEnabled)
435 {
436 m_HitRateMemory = (double)m_MemoryHits / m_Requests * 100.0;
437 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Memory Hit Rate {0}% for {1} requests", m_HitRateMemory.ToString("0.00"), m_Requests);
438 }
439 474
440 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: {0} unnessesary requests due to requests for assets that are currently downloading.", m_RequestsForInprogress); 475 GenerateCacheHitReport().ForEach(l => m_log.InfoFormat("[FLOTSAM ASSET CACHE]: {0}", l));
441 } 476 }
442 477
443 return asset; 478 return asset;
444 } 479 }
445 480
481 public bool Check(string id)
482 {
483 if (m_MemoryCacheEnabled && CheckFromMemoryCache(id))
484 return true;
485
486 if (m_FileCacheEnabled && CheckFromFileCache(id))
487 return true;
488 return false;
489 }
490
446 public AssetBase GetCached(string id) 491 public AssetBase GetCached(string id)
447 { 492 {
448 return Get(id); 493 return Get(id);
@@ -469,7 +514,7 @@ namespace OpenSim.Region.CoreModules.Asset
469 } 514 }
470 catch (Exception e) 515 catch (Exception e)
471 { 516 {
472 m_log.ErrorFormat( 517 m_log.WarnFormat(
473 "[FLOTSAM ASSET CACHE]: Failed to expire cached file {0}. Exception {1} {2}", 518 "[FLOTSAM ASSET CACHE]: Failed to expire cached file {0}. Exception {1} {2}",
474 id, e.Message, e.StackTrace); 519 id, e.Message, e.StackTrace);
475 } 520 }
@@ -520,29 +565,39 @@ namespace OpenSim.Region.CoreModules.Asset
520 /// <param name="purgeLine"></param> 565 /// <param name="purgeLine"></param>
521 private void CleanExpiredFiles(string dir, DateTime purgeLine) 566 private void CleanExpiredFiles(string dir, DateTime purgeLine)
522 { 567 {
523 foreach (string file in Directory.GetFiles(dir)) 568 try
524 { 569 {
525 if (File.GetLastAccessTime(file) < purgeLine) 570 foreach (string file in Directory.GetFiles(dir))
526 { 571 {
527 File.Delete(file); 572 if (File.GetLastAccessTime(file) < purgeLine)
573 {
574 File.Delete(file);
575 }
528 } 576 }
529 }
530 577
531 // Recurse into lower tiers 578 // Recurse into lower tiers
532 foreach (string subdir in Directory.GetDirectories(dir)) 579 foreach (string subdir in Directory.GetDirectories(dir))
533 { 580 {
534 CleanExpiredFiles(subdir, purgeLine); 581 CleanExpiredFiles(subdir, purgeLine);
535 } 582 }
536 583
537 // Check if a tier directory is empty, if so, delete it 584 // Check if a tier directory is empty, if so, delete it
538 int dirSize = Directory.GetFiles(dir).Length + Directory.GetDirectories(dir).Length; 585 int dirSize = Directory.GetFiles(dir).Length + Directory.GetDirectories(dir).Length;
539 if (dirSize == 0) 586 if (dirSize == 0)
540 { 587 {
541 Directory.Delete(dir); 588 Directory.Delete(dir);
589 }
590 else if (dirSize >= m_CacheWarnAt)
591 {
592 m_log.WarnFormat(
593 "[FLOTSAM ASSET CACHE]: Cache folder exceeded CacheWarnAt limit {0} {1}. Suggest increasing tiers, tier length, or reducing cache expiration",
594 dir, dirSize);
595 }
542 } 596 }
543 else if (dirSize >= m_CacheWarnAt) 597 catch (Exception e)
544 { 598 {
545 m_log.WarnFormat("[FLOTSAM ASSET CACHE]: Cache folder exceeded CacheWarnAt limit {0} {1}. Suggest increasing tiers, tier length, or reducing cache expiration", dir, dirSize); 599 m_log.Warn(
600 string.Format("[FLOTSAM ASSET CACHE]: Could not complete clean of expired files in {0}, exception ", dir), e);
546 } 601 }
547 } 602 }
548 603
@@ -601,7 +656,7 @@ namespace OpenSim.Region.CoreModules.Asset
601 } 656 }
602 catch (IOException e) 657 catch (IOException e)
603 { 658 {
604 m_log.ErrorFormat( 659 m_log.WarnFormat(
605 "[FLOTSAM ASSET CACHE]: Failed to write asset {0} to temporary location {1} (final {2}) on cache in {3}. Exception {4} {5}.", 660 "[FLOTSAM ASSET CACHE]: Failed to write asset {0} to temporary location {1} (final {2}) on cache in {3}. Exception {4} {5}.",
606 asset.ID, tempname, filename, directory, e.Message, e.StackTrace); 661 asset.ID, tempname, filename, directory, e.Message, e.StackTrace);
607 662
@@ -680,17 +735,31 @@ namespace OpenSim.Region.CoreModules.Asset
680 /// <summary> 735 /// <summary>
681 /// This notes the last time the Region had a deep asset scan performed on it. 736 /// This notes the last time the Region had a deep asset scan performed on it.
682 /// </summary> 737 /// </summary>
683 /// <param name="RegionID"></param> 738 /// <param name="regionID"></param>
684 private void StampRegionStatusFile(UUID RegionID) 739 private void StampRegionStatusFile(UUID regionID)
685 { 740 {
686 string RegionCacheStatusFile = Path.Combine(m_CacheDirectory, "RegionStatus_" + RegionID.ToString() + ".fac"); 741 string RegionCacheStatusFile = Path.Combine(m_CacheDirectory, "RegionStatus_" + regionID.ToString() + ".fac");
687 if (File.Exists(RegionCacheStatusFile)) 742
743 try
688 { 744 {
689 File.SetLastWriteTime(RegionCacheStatusFile, DateTime.Now); 745 if (File.Exists(RegionCacheStatusFile))
746 {
747 File.SetLastWriteTime(RegionCacheStatusFile, DateTime.Now);
748 }
749 else
750 {
751 File.WriteAllText(
752 RegionCacheStatusFile,
753 "Please do not delete this file unless you are manually clearing your Flotsam Asset Cache.");
754 }
690 } 755 }
691 else 756 catch (Exception e)
692 { 757 {
693 File.WriteAllText(RegionCacheStatusFile, "Please do not delete this file unless you are manually clearing your Flotsam Asset Cache."); 758 m_log.Warn(
759 string.Format(
760 "[FLOTSAM ASSET CACHE]: Could not stamp region status file for region {0}. Exception ",
761 regionID),
762 e);
694 } 763 }
695 } 764 }
696 765
@@ -707,32 +776,49 @@ namespace OpenSim.Region.CoreModules.Asset
707 { 776 {
708 UuidGatherer gatherer = new UuidGatherer(m_AssetService); 777 UuidGatherer gatherer = new UuidGatherer(m_AssetService);
709 778
710 Dictionary<UUID, AssetType> assets = new Dictionary<UUID, AssetType>(); 779 Dictionary<UUID, bool> assetsFound = new Dictionary<UUID, bool>();
780
711 foreach (Scene s in m_Scenes) 781 foreach (Scene s in m_Scenes)
712 { 782 {
713 StampRegionStatusFile(s.RegionInfo.RegionID); 783 StampRegionStatusFile(s.RegionInfo.RegionID);
714 784
715 s.ForEachSOG(delegate(SceneObjectGroup e) 785 s.ForEachSOG(delegate(SceneObjectGroup e)
716 { 786 {
717 gatherer.GatherAssetUuids(e, assets); 787 gatherer.AddForInspection(e);
718 }); 788 gatherer.GatherAll();
719 }
720 789
721 foreach (UUID assetID in assets.Keys) 790 foreach (UUID assetID in gatherer.GatheredUuids.Keys)
722 { 791 {
723 string filename = GetFileName(assetID.ToString()); 792 if (!assetsFound.ContainsKey(assetID))
793 {
794 string filename = GetFileName(assetID.ToString());
724 795
725 if (File.Exists(filename)) 796 if (File.Exists(filename))
726 { 797 {
727 File.SetLastAccessTime(filename, DateTime.Now); 798 UpdateFileLastAccessTime(filename);
728 } 799 }
729 else if (storeUncached) 800 else if (storeUncached)
730 { 801 {
731 m_AssetService.Get(assetID.ToString()); 802 AssetBase cachedAsset = m_AssetService.Get(assetID.ToString());
732 } 803 if (cachedAsset == null && gatherer.GatheredUuids[assetID] != (sbyte)AssetType.Unknown)
804 assetsFound[assetID] = false;
805 else
806 assetsFound[assetID] = true;
807 }
808 }
809 else if (!assetsFound[assetID])
810 {
811 m_log.DebugFormat(
812 "[FLOTSAM ASSET CACHE]: Could not find asset {0}, type {1} referenced by object {2} at {3} in scene {4} when pre-caching all scene assets",
813 assetID, gatherer.GatheredUuids[assetID], e.Name, e.AbsolutePosition, s.Name);
814 }
815 }
816
817 gatherer.GatheredUuids.Clear();
818 });
733 } 819 }
734 820
735 return assets.Keys.Count; 821 return assetsFound.Count;
736 } 822 }
737 823
738 /// <summary> 824 /// <summary>
@@ -748,7 +834,7 @@ namespace OpenSim.Region.CoreModules.Asset
748 } 834 }
749 catch (Exception e) 835 catch (Exception e)
750 { 836 {
751 m_log.ErrorFormat( 837 m_log.WarnFormat(
752 "[FLOTSAM ASSET CACHE]: Couldn't clear asset cache directory {0} from {1}. Exception {2} {3}", 838 "[FLOTSAM ASSET CACHE]: Couldn't clear asset cache directory {0} from {1}. Exception {2} {3}",
753 dir, m_CacheDirectory, e.Message, e.StackTrace); 839 dir, m_CacheDirectory, e.Message, e.StackTrace);
754 } 840 }
@@ -762,52 +848,84 @@ namespace OpenSim.Region.CoreModules.Asset
762 } 848 }
763 catch (Exception e) 849 catch (Exception e)
764 { 850 {
765 m_log.ErrorFormat( 851 m_log.WarnFormat(
766 "[FLOTSAM ASSET CACHE]: Couldn't clear asset cache file {0} from {1}. Exception {1} {2}", 852 "[FLOTSAM ASSET CACHE]: Couldn't clear asset cache file {0} from {1}. Exception {1} {2}",
767 file, m_CacheDirectory, e.Message, e.StackTrace); 853 file, m_CacheDirectory, e.Message, e.StackTrace);
768 } 854 }
769 } 855 }
770 } 856 }
771 857
858 private List<string> GenerateCacheHitReport()
859 {
860 List<string> outputLines = new List<string>();
861
862 double fileHitRate = (double)m_DiskHits / m_Requests * 100.0;
863 outputLines.Add(
864 string.Format("File Hit Rate: {0}% for {1} requests", fileHitRate.ToString("0.00"), m_Requests));
865
866 if (m_MemoryCacheEnabled)
867 {
868 double memHitRate = (double)m_MemoryHits / m_Requests * 100.0;
869
870 outputLines.Add(
871 string.Format("Memory Hit Rate: {0}% for {1} requests", memHitRate.ToString("0.00"), m_Requests));
872 }
873
874 outputLines.Add(
875 string.Format(
876 "Unnecessary requests due to requests for assets that are currently downloading: {0}",
877 m_RequestsForInprogress));
878
879 return outputLines;
880 }
881
772 #region Console Commands 882 #region Console Commands
773 private void HandleConsoleCommand(string module, string[] cmdparams) 883 private void HandleConsoleCommand(string module, string[] cmdparams)
774 { 884 {
885 ICommandConsole con = MainConsole.Instance;
886
775 if (cmdparams.Length >= 2) 887 if (cmdparams.Length >= 2)
776 { 888 {
777 string cmd = cmdparams[1]; 889 string cmd = cmdparams[1];
890
778 switch (cmd) 891 switch (cmd)
779 { 892 {
780 case "status": 893 case "status":
781 if (m_MemoryCacheEnabled) 894 if (m_MemoryCacheEnabled)
782 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Memory Cache : {0} assets", m_MemoryCache.Count); 895 con.OutputFormat("Memory Cache: {0} assets", m_MemoryCache.Count);
783 else 896 else
784 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Memory cache disabled"); 897 con.OutputFormat("Memory cache disabled");
785 898
786 if (m_FileCacheEnabled) 899 if (m_FileCacheEnabled)
787 { 900 {
788 int fileCount = GetFileCacheCount(m_CacheDirectory); 901 int fileCount = GetFileCacheCount(m_CacheDirectory);
789 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: File Cache : {0} assets", fileCount); 902 con.OutputFormat("File Cache: {0} assets", fileCount);
903 }
904 else
905 {
906 con.Output("File cache disabled");
907 }
908
909 GenerateCacheHitReport().ForEach(l => con.Output(l));
910
911 if (m_FileCacheEnabled)
912 {
913 con.Output("Deep scans have previously been performed on the following regions:");
790 914
791 foreach (string s in Directory.GetFiles(m_CacheDirectory, "*.fac")) 915 foreach (string s in Directory.GetFiles(m_CacheDirectory, "*.fac"))
792 { 916 {
793 m_log.Info("[FLOTSAM ASSET CACHE]: Deep scans have previously been performed on the following regions:");
794
795 string RegionID = s.Remove(0,s.IndexOf("_")).Replace(".fac",""); 917 string RegionID = s.Remove(0,s.IndexOf("_")).Replace(".fac","");
796 DateTime RegionDeepScanTMStamp = File.GetLastWriteTime(s); 918 DateTime RegionDeepScanTMStamp = File.GetLastWriteTime(s);
797 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Region: {0}, {1}", RegionID, RegionDeepScanTMStamp.ToString("MM/dd/yyyy hh:mm:ss")); 919 con.OutputFormat("Region: {0}, {1}", RegionID, RegionDeepScanTMStamp.ToString("MM/dd/yyyy hh:mm:ss"));
798 } 920 }
799 } 921 }
800 else
801 {
802 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: File cache disabled");
803 }
804 922
805 break; 923 break;
806 924
807 case "clear": 925 case "clear":
808 if (cmdparams.Length < 2) 926 if (cmdparams.Length < 2)
809 { 927 {
810 m_log.Warn("[FLOTSAM ASSET CACHE]: Usage is fcache clear [file] [memory]"); 928 con.Output("Usage is fcache clear [file] [memory]");
811 break; 929 break;
812 } 930 }
813 931
@@ -831,11 +949,11 @@ namespace OpenSim.Region.CoreModules.Asset
831 if (m_MemoryCacheEnabled) 949 if (m_MemoryCacheEnabled)
832 { 950 {
833 m_MemoryCache.Clear(); 951 m_MemoryCache.Clear();
834 m_log.Info("[FLOTSAM ASSET CACHE]: Memory cache cleared."); 952 con.Output("Memory cache cleared.");
835 } 953 }
836 else 954 else
837 { 955 {
838 m_log.Info("[FLOTSAM ASSET CACHE]: Memory cache not enabled."); 956 con.Output("Memory cache not enabled.");
839 } 957 }
840 } 958 }
841 959
@@ -844,32 +962,31 @@ namespace OpenSim.Region.CoreModules.Asset
844 if (m_FileCacheEnabled) 962 if (m_FileCacheEnabled)
845 { 963 {
846 ClearFileCache(); 964 ClearFileCache();
847 m_log.Info("[FLOTSAM ASSET CACHE]: File cache cleared."); 965 con.Output("File cache cleared.");
848 } 966 }
849 else 967 else
850 { 968 {
851 m_log.Info("[FLOTSAM ASSET CACHE]: File cache not enabled."); 969 con.Output("File cache not enabled.");
852 } 970 }
853 } 971 }
854 972
855 break; 973 break;
856 974
857 case "assets": 975 case "assets":
858 m_log.Info("[FLOTSAM ASSET CACHE]: Ensuring assets are cached for all scenes."); 976 con.Output("Ensuring assets are cached for all scenes.");
859 977
860 Util.FireAndForget(delegate { 978 WorkManager.RunInThread(delegate
979 {
861 int assetReferenceTotal = TouchAllSceneAssets(true); 980 int assetReferenceTotal = TouchAllSceneAssets(true);
862 m_log.InfoFormat( 981 con.OutputFormat("Completed check with {0} assets.", assetReferenceTotal);
863 "[FLOTSAM ASSET CACHE]: Completed check with {0} assets.", 982 }, null, "TouchAllSceneAssets");
864 assetReferenceTotal);
865 });
866 983
867 break; 984 break;
868 985
869 case "expire": 986 case "expire":
870 if (cmdparams.Length < 3) 987 if (cmdparams.Length < 3)
871 { 988 {
872 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Invalid parameters for Expire, please specify a valid date & time", cmd); 989 con.OutputFormat("Invalid parameters for Expire, please specify a valid date & time", cmd);
873 break; 990 break;
874 } 991 }
875 992
@@ -887,28 +1004,27 @@ namespace OpenSim.Region.CoreModules.Asset
887 1004
888 if (!DateTime.TryParse(s_expirationDate, out expirationDate)) 1005 if (!DateTime.TryParse(s_expirationDate, out expirationDate))
889 { 1006 {
890 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: {0} is not a valid date & time", cmd); 1007 con.OutputFormat("{0} is not a valid date & time", cmd);
891 break; 1008 break;
892 } 1009 }
893 1010
894 if (m_FileCacheEnabled) 1011 if (m_FileCacheEnabled)
895 CleanExpiredFiles(m_CacheDirectory, expirationDate); 1012 CleanExpiredFiles(m_CacheDirectory, expirationDate);
896 else 1013 else
897 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: File cache not active, not clearing."); 1014 con.OutputFormat("File cache not active, not clearing.");
898 1015
899 break; 1016 break;
900 default: 1017 default:
901 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Unknown command {0}", cmd); 1018 con.OutputFormat("Unknown command {0}", cmd);
902 break; 1019 break;
903 } 1020 }
904 } 1021 }
905 else if (cmdparams.Length == 1) 1022 else if (cmdparams.Length == 1)
906 { 1023 {
907 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache status - Display cache status"); 1024 con.Output("fcache assets - Attempt a deep cache of all assets in all scenes");
908 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache clearmem - Remove all assets cached in memory"); 1025 con.Output("fcache expire <datetime> - Purge assets older then the specified date & time");
909 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache clearfile - Remove all assets cached on disk"); 1026 con.Output("fcache clear [file] [memory] - Remove cached assets");
910 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache cachescenes - Attempt a deep cache of all assets in all scenes"); 1027 con.Output("fcache status - Display cache status");
911 m_log.InfoFormat("[FLOTSAM ASSET CACHE]: fcache <datetime> - Purge assets older then the specified date & time");
912 } 1028 }
913 } 1029 }
914 1030
@@ -935,6 +1051,18 @@ namespace OpenSim.Region.CoreModules.Asset
935 return true; 1051 return true;
936 } 1052 }
937 1053
1054 public bool[] AssetsExist(string[] ids)
1055 {
1056 bool[] exist = new bool[ids.Length];
1057
1058 for (int i = 0; i < ids.Length; i++)
1059 {
1060 exist[i] = Check(ids[i]);
1061 }
1062
1063 return exist;
1064 }
1065
938 public string Store(AssetBase asset) 1066 public string Store(AssetBase asset)
939 { 1067 {
940 if (asset.FullID == UUID.Zero) 1068 if (asset.FullID == UUID.Zero)
diff --git a/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs b/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs
index 9592ca0..5f76ac2 100644
--- a/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs
+++ b/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs
@@ -115,6 +115,11 @@ namespace OpenSim.Region.CoreModules.Asset
115 // IImprovedAssetCache 115 // IImprovedAssetCache
116 // 116 //
117 117
118 public bool Check(string id)
119 {
120 return m_Cache.Contains(id);
121 }
122
118 public void Cache(AssetBase asset) 123 public void Cache(AssetBase asset)
119 { 124 {
120 if (asset != null) 125 if (asset != null)
diff --git a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs
index fd02b08..73e4431 100644
--- a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs
+++ b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs
@@ -39,7 +39,6 @@ using OpenSim.Framework;
39using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Region.Framework.Scenes.Serialization; 40using OpenSim.Region.Framework.Scenes.Serialization;
41using OpenSim.Tests.Common; 41using OpenSim.Tests.Common;
42using OpenSim.Tests.Common.Mock;
43 42
44namespace OpenSim.Region.CoreModules.Asset.Tests 43namespace OpenSim.Region.CoreModules.Asset.Tests
45{ 44{
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index 58ed554..2f67c4e 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -29,6 +29,7 @@ using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Reflection; 30using System.Reflection;
31using System.IO; 31using System.IO;
32using System.Threading;
32using System.Xml; 33using System.Xml;
33using log4net; 34using log4net;
34using Mono.Addins; 35using Mono.Addins;
@@ -48,6 +49,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
48 { 49 {
49 #region INonSharedRegionModule 50 #region INonSharedRegionModule
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52
53 public int DebugLevel { get; set; }
54
55 /// <summary>
56 /// Period to sleep per 100 prims in order to avoid CPU spikes when an avatar with many attachments logs in/changes
57 /// outfit or many avatars with a medium levels of attachments login/change outfit simultaneously.
58 /// </summary>
59 /// <remarks>
60 /// A value of 0 will apply no pause. The pause is specified in milliseconds.
61 /// </remarks>
62 public int ThrottlePer100PrimsRezzed { get; set; }
51 63
52 private Scene m_scene; 64 private Scene m_scene;
53 private IInventoryAccessModule m_invAccessModule; 65 private IInventoryAccessModule m_invAccessModule;
@@ -64,21 +76,127 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
64 { 76 {
65 IConfig config = source.Configs["Attachments"]; 77 IConfig config = source.Configs["Attachments"];
66 if (config != null) 78 if (config != null)
79 {
67 Enabled = config.GetBoolean("Enabled", true); 80 Enabled = config.GetBoolean("Enabled", true);
81
82 ThrottlePer100PrimsRezzed = config.GetInt("ThrottlePer100PrimsRezzed", 0);
83 }
68 else 84 else
85 {
69 Enabled = true; 86 Enabled = true;
87 }
70 } 88 }
71 89
72 public void AddRegion(Scene scene) 90 public void AddRegion(Scene scene)
73 { 91 {
74 m_scene = scene; 92 m_scene = scene;
75 m_scene.RegisterModuleInterface<IAttachmentsModule>(this);
76
77 if (Enabled) 93 if (Enabled)
94 {
95 // Only register module with scene if it is enabled. All callers check for a null attachments module.
96 // Ideally, there should be a null attachments module for when this core attachments module has been
97 // disabled. Registering only when enabled allows for other attachments module implementations.
98 m_scene.RegisterModuleInterface<IAttachmentsModule>(this);
78 m_scene.EventManager.OnNewClient += SubscribeToClientEvents; 99 m_scene.EventManager.OnNewClient += SubscribeToClientEvents;
100 m_scene.EventManager.OnStartScript += (localID, itemID) => HandleScriptStateChange(localID, true);
101 m_scene.EventManager.OnStopScript += (localID, itemID) => HandleScriptStateChange(localID, false);
102
103 MainConsole.Instance.Commands.AddCommand(
104 "Debug",
105 false,
106 "debug attachments log",
107 "debug attachments log [0|1]",
108 "Turn on attachments debug logging",
109 " <= 0 - turns off debug logging\n"
110 + " >= 1 - turns on attachment message debug logging",
111 HandleDebugAttachmentsLog);
112
113 MainConsole.Instance.Commands.AddCommand(
114 "Debug",
115 false,
116 "debug attachments throttle",
117 "debug attachments throttle <ms>",
118 "Turn on attachments throttling.",
119 "This requires a millisecond value. " +
120 " == 0 - disable throttling.\n"
121 + " > 0 - sleeps for this number of milliseconds per 100 prims rezzed.",
122 HandleDebugAttachmentsThrottle);
123
124 MainConsole.Instance.Commands.AddCommand(
125 "Debug",
126 false,
127 "debug attachments status",
128 "debug attachments status",
129 "Show current attachments debug status",
130 HandleDebugAttachmentsStatus);
131 }
79 132
80 // TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI 133 // TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI
81 } 134 }
135
136 private void HandleDebugAttachmentsLog(string module, string[] args)
137 {
138 int debugLevel;
139
140 if (!(args.Length == 4 && int.TryParse(args[3], out debugLevel)))
141 {
142 MainConsole.Instance.OutputFormat("Usage: debug attachments log [0|1]");
143 }
144 else
145 {
146 DebugLevel = debugLevel;
147 MainConsole.Instance.OutputFormat(
148 "Set attachments debug level to {0} in {1}", DebugLevel, m_scene.Name);
149 }
150 }
151
152 private void HandleDebugAttachmentsThrottle(string module, string[] args)
153 {
154 int ms;
155
156 if (args.Length == 4 && int.TryParse(args[3], out ms))
157 {
158 ThrottlePer100PrimsRezzed = ms;
159 MainConsole.Instance.OutputFormat(
160 "Attachments rez throttle per 100 prims is now {0} in {1}", ThrottlePer100PrimsRezzed, m_scene.Name);
161
162 return;
163 }
164
165 MainConsole.Instance.OutputFormat("Usage: debug attachments throttle <ms>");
166 }
167
168 private void HandleDebugAttachmentsStatus(string module, string[] args)
169 {
170 MainConsole.Instance.OutputFormat("Settings for {0}", m_scene.Name);
171 MainConsole.Instance.OutputFormat("Debug logging level: {0}", DebugLevel);
172 MainConsole.Instance.OutputFormat("Throttle per 100 prims: {0}ms", ThrottlePer100PrimsRezzed);
173 }
174
175 /// <summary>
176 /// Listen for client triggered running state changes so that we can persist the script's object if necessary.
177 /// </summary>
178 /// <param name='localID'></param>
179 /// <param name='itemID'></param>
180 private void HandleScriptStateChange(uint localID, bool started)
181 {
182 SceneObjectGroup sog = m_scene.GetGroupByPrim(localID);
183 if (sog != null && sog.IsAttachment)
184 {
185 if (!started)
186 {
187 // FIXME: This is a convoluted way for working out whether the script state has changed to stop
188 // because it has been manually stopped or because the stop was called in UpdateDetachedObject() below
189 // This needs to be handled in a less tangled way.
190 ScenePresence sp = m_scene.GetScenePresence(sog.AttachedAvatar);
191 if (sp.ControllingClient.IsActive)
192 sog.HasGroupChanged = true;
193 }
194 else
195 {
196 sog.HasGroupChanged = true;
197 }
198 }
199 }
82 200
83 public void RemoveRegion(Scene scene) 201 public void RemoveRegion(Scene scene)
84 { 202 {
@@ -127,8 +245,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
127 string state = sog.GetStateSnapshot(); 245 string state = sog.GetStateSnapshot();
128 ad.AttachmentObjectStates.Add(state); 246 ad.AttachmentObjectStates.Add(state);
129 sp.InTransitScriptStates.Add(state); 247 sp.InTransitScriptStates.Add(state);
130 // Let's remove the scripts of the original object here 248
131 sog.RemoveScriptInstances(true); 249 // Scripts of the originals will be removed when the Agent is successfully removed.
250 // sog.RemoveScriptInstances(true);
132 } 251 }
133 } 252 }
134 } 253 }
@@ -136,6 +255,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
136 255
137 public void CopyAttachments(AgentData ad, IScenePresence sp) 256 public void CopyAttachments(AgentData ad, IScenePresence sp)
138 { 257 {
258// m_log.DebugFormat("[ATTACHMENTS MODULE]: Copying attachment data into {0} in {1}", sp.Name, m_scene.Name);
259
139 if (ad.AttachmentObjects != null && ad.AttachmentObjects.Count > 0) 260 if (ad.AttachmentObjects != null && ad.AttachmentObjects.Count > 0)
140 { 261 {
141 lock (sp.AttachmentsSyncLock) 262 lock (sp.AttachmentsSyncLock)
@@ -146,16 +267,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
146 { 267 {
147 ((SceneObjectGroup)so).LocalId = 0; 268 ((SceneObjectGroup)so).LocalId = 0;
148 ((SceneObjectGroup)so).RootPart.ClearUpdateSchedule(); 269 ((SceneObjectGroup)so).RootPart.ClearUpdateSchedule();
270
271// m_log.DebugFormat(
272// "[ATTACHMENTS MODULE]: Copying script state with {0} bytes for object {1} for {2} in {3}",
273// ad.AttachmentObjectStates[i].Length, so.Name, sp.Name, m_scene.Name);
274
149 so.SetState(ad.AttachmentObjectStates[i++], m_scene); 275 so.SetState(ad.AttachmentObjectStates[i++], m_scene);
150 m_scene.IncomingCreateObject(Vector3.Zero, so); 276 m_scene.IncomingCreateObject(Vector3.Zero, so);
151 } 277 }
152 } 278 }
153 } 279 }
154 280
155 /// <summary>
156 /// RezAttachments. This should only be called upon login on the first region.
157 /// Attachment rezzings on crossings and TPs are done in a different way.
158 /// </summary>
159 public void RezAttachments(IScenePresence sp) 281 public void RezAttachments(IScenePresence sp)
160 { 282 {
161 if (!Enabled) 283 if (!Enabled)
@@ -164,15 +286,35 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
164 if (null == sp.Appearance) 286 if (null == sp.Appearance)
165 { 287 {
166 m_log.WarnFormat("[ATTACHMENTS MODULE]: Appearance has not been initialized for agent {0}", sp.UUID); 288 m_log.WarnFormat("[ATTACHMENTS MODULE]: Appearance has not been initialized for agent {0}", sp.UUID);
289
167 return; 290 return;
168 } 291 }
169 292
170// m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing any attachments for {0}", sp.Name); 293 if (sp.GetAttachments().Count > 0)
294 {
295 if (DebugLevel > 0)
296 m_log.DebugFormat(
297 "[ATTACHMENTS MODULE]: Not doing simulator-side attachment rez for {0} in {1} as their viewer has already rezzed attachments",
298 m_scene.Name, sp.Name);
299
300 return;
301 }
302
303 if (DebugLevel > 0)
304 m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing any attachments for {0} from simulator-side", sp.Name);
171 305
172 List<AvatarAttachment> attachments = sp.Appearance.GetAttachments(); 306 List<AvatarAttachment> attachments = sp.Appearance.GetAttachments();
307
308 // Let's get all items at once, so they get cached
309 UUID[] items = new UUID[attachments.Count];
310 int i = 0;
311 foreach (AvatarAttachment attach in attachments)
312 items[i++] = attach.ItemID;
313 m_scene.InventoryService.GetMultipleItems(sp.UUID, items);
314
173 foreach (AvatarAttachment attach in attachments) 315 foreach (AvatarAttachment attach in attachments)
174 { 316 {
175 uint p = (uint)attach.AttachPoint; 317 uint attachmentPt = (uint)attach.AttachPoint;
176 318
177// m_log.DebugFormat( 319// m_log.DebugFormat(
178// "[ATTACHMENTS MODULE]: Doing initial rez of attachment with itemID {0}, assetID {1}, point {2} for {3} in {4}", 320// "[ATTACHMENTS MODULE]: Doing initial rez of attachment with itemID {0}, assetID {1}, point {2} for {3} in {4}",
@@ -190,16 +332,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
190 { 332 {
191 // If we're an NPC then skip all the item checks and manipulations since we don't have an 333 // If we're an NPC then skip all the item checks and manipulations since we don't have an
192 // inventory right now. 334 // inventory right now.
193 if (sp.PresenceType == PresenceType.Npc) 335 RezSingleAttachmentFromInventoryInternal(
194 RezSingleAttachmentFromInventoryInternal(sp, UUID.Zero, attach.AssetID, p); 336 sp, sp.PresenceType == PresenceType.Npc ? UUID.Zero : attach.ItemID, attach.AssetID, attachmentPt, true);
195 else
196 RezSingleAttachmentFromInventory(sp, attach.ItemID, p);
197 } 337 }
198 catch (Exception e) 338 catch (Exception e)
199 { 339 {
200 UUID agentId = (sp.ControllingClient == null) ? (UUID)null : sp.ControllingClient.AgentId; 340 UUID agentId = (sp.ControllingClient == null) ? default(UUID) : sp.ControllingClient.AgentId;
201 m_log.ErrorFormat("[ATTACHMENTS MODULE]: Unable to rez attachment with itemID {0}, assetID {1}, point {2} for {3}: {4}\n{5}", 341 m_log.ErrorFormat("[ATTACHMENTS MODULE]: Unable to rez attachment with itemID {0}, assetID {1}, point {2} for {3}: {4}\n{5}",
202 attach.ItemID, attach.AssetID, p, agentId, e.Message, e.StackTrace); 342 attach.ItemID, attach.AssetID, attachmentPt, agentId, e.Message, e.StackTrace);
203 } 343 }
204 } 344 }
205 } 345 }
@@ -209,14 +349,36 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
209 if (!Enabled) 349 if (!Enabled)
210 return; 350 return;
211 351
212// m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name); 352 List<SceneObjectGroup> attachments = sp.GetAttachments();
353
354 if (DebugLevel > 0)
355 m_log.DebugFormat(
356 "[ATTACHMENTS MODULE]: Saving for {0} attachments for {1} in {2}",
357 attachments.Count, sp.Name, m_scene.Name);
358
359 if (attachments.Count <= 0)
360 return;
361
362 Dictionary<SceneObjectGroup, string> scriptStates = new Dictionary<SceneObjectGroup, string>();
363
364 foreach (SceneObjectGroup so in attachments)
365 {
366 // Scripts MUST be snapshotted before the object is
367 // removed from the scene because doing otherwise will
368 // clobber the run flag
369 // This must be done outside the sp.AttachmentSyncLock so that there is no risk of a deadlock from
370 // scripts performing attachment operations at the same time. Getting object states stops the scripts.
371 scriptStates[so] = PrepareScriptInstanceForSave(so, false);
372
373// m_log.DebugFormat(
374// "[ATTACHMENTS MODULE]: For object {0} for {1} in {2} got saved state {3}",
375// so.Name, sp.Name, m_scene.Name, scriptStates[so]);
376 }
213 377
214 lock (sp.AttachmentsSyncLock) 378 lock (sp.AttachmentsSyncLock)
215 { 379 {
216 foreach (SceneObjectGroup so in sp.GetAttachments()) 380 foreach (SceneObjectGroup so in attachments)
217 { 381 UpdateDetachedObject(sp, so, scriptStates[so]);
218 UpdateDetachedObject(sp, so);
219 }
220 382
221 sp.ClearAttachments(); 383 sp.ClearAttachments();
222 } 384 }
@@ -227,9 +389,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
227 if (!Enabled) 389 if (!Enabled)
228 return; 390 return;
229 391
230// m_log.DebugFormat( 392 if (DebugLevel > 0)
231// "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}", 393 m_log.DebugFormat(
232// m_scene.RegionInfo.RegionName, sp.Name, silent); 394 "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}",
395 m_scene.RegionInfo.RegionName, sp.Name, silent);
233 396
234 foreach (SceneObjectGroup sop in sp.GetAttachments()) 397 foreach (SceneObjectGroup sop in sp.GetAttachments())
235 { 398 {
@@ -238,114 +401,149 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
238 401
239 sp.ClearAttachments(); 402 sp.ClearAttachments();
240 } 403 }
241 404
242 public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool temp) 405 public bool AttachObject(
406 IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool addToInventory, bool append)
243 { 407 {
244 if (!Enabled) 408 if (!Enabled)
245 return false; 409 return false;
246 410
247 if (AttachObjectInternal(sp, group, attachmentPt, silent, temp)) 411 group.DetachFromBackup();
248 {
249 m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID);
250 return true;
251 }
252 412
253 return false; 413 bool success = AttachObjectInternal(sp, group, attachmentPt, silent, addToInventory, false, append);
414
415 if (!success)
416 group.AttachToBackup();
417
418 return success;
254 } 419 }
255 420
256 private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool temp) 421 /// <summary>
422 /// Internal method which actually does all the work for attaching an object.
423 /// </summary>
424 /// <returns>The object attached.</returns>
425 /// <param name='sp'></param>
426 /// <param name='group'>The object to attach.</param>
427 /// <param name='attachmentPt'></param>
428 /// <param name='silent'></param>
429 /// <param name='addToInventory'>If true then add object to user inventory.</param>
430 /// <param name='resumeScripts'>If true then scripts are resumed on the attached object.</param>
431 /// <param name='append'>Append to attachment point rather than replace.</param>
432 private bool AttachObjectInternal(
433 IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool addToInventory, bool resumeScripts, bool append)
257 { 434 {
258 lock (sp.AttachmentsSyncLock) 435 if (group.GetSittingAvatarsCount() != 0)
259 { 436 {
260// m_log.DebugFormat( 437 if (DebugLevel > 0)
261// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})", 438 m_log.WarnFormat(
262// group.Name, group.LocalId, sp.Name, attachmentPt, silent); 439 "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it",
440 group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount());
263 441
264 if (group.GetSittingAvatarsCount() != 0) 442 return false;
265 { 443 }
266// m_log.WarnFormat( 444
267// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it", 445 Vector3 attachPos = group.AbsolutePosition;
268// group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount()); 446 // If the attachment point isn't the same as the one previously used
269 447 // set it's offset position = 0 so that it appears on the attachment point
270 return false; 448 // and not in a weird location somewhere unknown.
271 } 449 if (attachmentPt != (uint)AttachmentPoint.Default && attachmentPt != group.AttachmentPoint)
272 450 {
273 if (sp.GetAttachments(attachmentPt).Contains(group)) 451 attachPos = Vector3.Zero;
274 { 452 }
275 // m_log.WarnFormat( 453
276 // "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached", 454 // if the attachment point is the same as previous, make sure we get the saved
277 // group.Name, group.LocalId, sp.Name, AttachmentPt); 455 // position info.
278 456 if (attachmentPt != 0 && attachmentPt == group.RootPart.Shape.LastAttachPoint)
279 return false; 457 {
280 } 458 attachPos = group.RootPart.AttachedPos;
281 459 }
282 Vector3 attachPos = group.AbsolutePosition; 460
283 461 // AttachmentPt 0 means the client chose to 'wear' the attachment.
284 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should 462 if (attachmentPt == (uint)AttachmentPoint.Default)
285 // be removed when that functionality is implemented in opensim 463 {
286 attachmentPt &= 0x7f; 464 // Check object for stored attachment point
287 465 attachmentPt = group.AttachmentPoint;
288 // If the attachment point isn't the same as the one previously used 466 }
289 // set it's offset position = 0 so that it appears on the attachment point 467
290 // and not in a weird location somewhere unknown. 468 // if we didn't find an attach point, look for where it was last attached
291 if (attachmentPt != 0 && attachmentPt != group.AttachmentPoint) 469 if (attachmentPt == 0)
292 { 470 {
293 attachPos = Vector3.Zero; 471 attachmentPt = (uint)group.RootPart.Shape.LastAttachPoint;
294 } 472 attachPos = group.RootPart.AttachedPos;
295 473 group.HasGroupChanged = true;
296 // AttachmentPt 0 means the client chose to 'wear' the attachment. 474 }
297 if (attachmentPt == 0) 475
476 // if we still didn't find a suitable attachment point.......
477 if (attachmentPt == 0)
478 {
479 // Stick it on left hand with Zero Offset from the attachment point.
480 attachmentPt = (uint)AttachmentPoint.LeftHand;
481 attachPos = Vector3.Zero;
482 }
483
484 group.AttachmentPoint = attachmentPt;
485 group.AbsolutePosition = attachPos;
486
487 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
488
489 if (attachments.Contains(group))
490 {
491 if (DebugLevel > 0)
492 m_log.WarnFormat(
493 "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached",
494 group.Name, group.LocalId, sp.Name, attachmentPt);
495
496 return false;
497 }
498
499 // If we already have 5, remove the oldest until only 4 are left. Skip over temp ones
500 while (attachments.Count >= 5)
501 {
502 if (attachments[0].FromItemID != UUID.Zero)
503 DetachSingleAttachmentToInv(sp, attachments[0]);
504 attachments.RemoveAt(0);
505 }
506
507 // If we're not appending, remove the rest as well
508 if (attachments.Count != 0 && !append)
509 {
510 foreach (SceneObjectGroup g in attachments)
298 { 511 {
299 // Check object for stored attachment point 512 if (g.FromItemID != UUID.Zero)
300 attachmentPt = group.AttachmentPoint; 513 DetachSingleAttachmentToInv(sp, g);
301 } 514 }
515 }
516
517 lock (sp.AttachmentsSyncLock)
518 {
519 if (addToInventory && sp.PresenceType != PresenceType.Npc)
520 UpdateUserInventoryWithAttachment(sp, group, attachmentPt, append);
302 521
303 // if we still didn't find a suitable attachment point....... 522 AttachToAgent(sp, group, attachmentPt, attachPos, silent);
304 if (attachmentPt == 0) 523
524 if (resumeScripts)
305 { 525 {
306 // Stick it on left hand with Zero Offset from the attachment point. 526 // Fire after attach, so we don't get messy perms dialogs
307 attachmentPt = (uint)AttachmentPoint.LeftHand; 527 // 4 == AttachedRez
308 attachPos = Vector3.Zero; 528 group.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
529 group.ResumeScripts();
309 } 530 }
310
311 group.AttachmentPoint = attachmentPt;
312 group.AbsolutePosition = attachPos;
313 531
314 if (sp.PresenceType != PresenceType.Npc) 532 // Do this last so that event listeners have access to all the effects of the attachment
315 UpdateUserInventoryWithAttachment(sp, group, attachmentPt, temp); 533 m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID);
316
317 AttachToAgent(sp, group, attachmentPt, attachPos, silent);
318 } 534 }
319 535
320 return true; 536 return true;
321 } 537 }
322 538
323 private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool temp) 539 private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool append)
324 { 540 {
325 // Remove any previous attachments
326 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
327
328 // At the moment we can only deal with a single attachment
329 if (attachments.Count != 0)
330 {
331 if (attachments[0].FromItemID != UUID.Zero)
332 DetachSingleAttachmentToInvInternal(sp, attachments[0]);
333 // Error logging commented because UUID.Zero now means temp attachment
334// else
335// m_log.WarnFormat(
336// "[ATTACHMENTS MODULE]: When detaching existing attachment {0} {1} at point {2} to make way for {3} {4} for {5}, couldn't find the associated item ID to adjust inventory attachment record!",
337// attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name);
338 }
339
340 // Add the new attachment to inventory if we don't already have it. 541 // Add the new attachment to inventory if we don't already have it.
341 if (!temp) 542 UUID newAttachmentItemID = group.FromItemID;
342 { 543 if (newAttachmentItemID == UUID.Zero)
343 UUID newAttachmentItemID = group.FromItemID; 544 newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID;
344 if (newAttachmentItemID == UUID.Zero)
345 newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID;
346 545
347 ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group); 546 ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group, append);
348 }
349 } 547 }
350 548
351 public SceneObjectGroup RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt) 549 public SceneObjectGroup RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt)
@@ -353,41 +551,40 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
353 if (!Enabled) 551 if (!Enabled)
354 return null; 552 return null;
355 553
356// m_log.DebugFormat( 554 if (DebugLevel > 0)
357// "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2}", 555 m_log.DebugFormat(
358// (AttachmentPoint)AttachmentPt, itemID, sp.Name); 556 "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2} in {3}",
359 557 (AttachmentPoint)AttachmentPt, itemID, sp.Name, m_scene.Name);
360 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should
361 // be removed when that functionality is implemented in opensim
362 AttachmentPt &= 0x7f;
363 558
364 // Viewer 2/3 sometimes asks to re-wear items that are already worn (and show up in it's inventory as such). 559 // We check the attachments in the avatar appearance here rather than the objects attached to the
365 // This often happens during login - not sure the exact reason. 560 // ScenePresence itself so that we can ignore calls by viewer 2/3 to attach objects on startup. We are
366 // For now, we will ignore the request. Unfortunately, this means that we need to dig through all the 561 // already doing this in ScenePresence.MakeRootAgent(). Simulator-side attaching needs to be done
367 // ScenePresence attachments. We can't use the data in AvatarAppearance because that's present at login 562 // because pre-outfit folder viewers (most version 1 viewers) require it.
368 // before anything has actually been attached.
369 bool alreadyOn = false; 563 bool alreadyOn = false;
370 List<SceneObjectGroup> existingAttachments = sp.GetAttachments(); 564 List<AvatarAttachment> existingAttachments = sp.Appearance.GetAttachments();
371 foreach (SceneObjectGroup so in existingAttachments) 565 foreach (AvatarAttachment existingAttachment in existingAttachments)
372 { 566 {
373 if (so.FromItemID == itemID) 567 if (existingAttachment.ItemID == itemID)
374 { 568 {
375 alreadyOn = true; 569 alreadyOn = true;
376 break; 570 break;
377 } 571 }
378 } 572 }
379 573
380// if (sp.Appearance.GetAttachmentForItem(itemID) != null)
381 if (alreadyOn) 574 if (alreadyOn)
382 { 575 {
383// m_log.WarnFormat( 576 if (DebugLevel > 0)
384// "[ATTACHMENTS MODULE]: Ignoring request by {0} to wear item {1} at {2} since it is already worn", 577 m_log.DebugFormat(
385// sp.Name, itemID, AttachmentPt); 578 "[ATTACHMENTS MODULE]: Ignoring request by {0} to wear item {1} at {2} since it is already worn",
579 sp.Name, itemID, AttachmentPt);
386 580
387 return null; 581 return null;
388 } 582 }
389 583
390 return RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt); 584 bool append = (AttachmentPt & 0x80) != 0;
585 AttachmentPt &= 0x7f;
586
587 return RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt, append);
391 } 588 }
392 589
393 public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List<KeyValuePair<UUID, uint>> rezlist) 590 public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List<KeyValuePair<UUID, uint>> rezlist)
@@ -395,13 +592,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
395 if (!Enabled) 592 if (!Enabled)
396 return; 593 return;
397 594
398 // m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing multiple attachments from inventory for {0}", sp.Name); 595 if (DebugLevel > 0)
399 lock (sp.AttachmentsSyncLock) 596 m_log.DebugFormat(
597 "[ATTACHMENTS MODULE]: Rezzing {0} attachments from inventory for {1} in {2}",
598 rezlist.Count, sp.Name, m_scene.Name);
599
600 foreach (KeyValuePair<UUID, uint> rez in rezlist)
400 { 601 {
401 foreach (KeyValuePair<UUID, uint> rez in rezlist) 602 RezSingleAttachmentFromInventory(sp, rez.Key, rez.Value);
402 {
403 RezSingleAttachmentFromInventory(sp, rez.Key, rez.Value);
404 }
405 } 603 }
406 } 604 }
407 605
@@ -415,9 +613,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
415 if (!Enabled) 613 if (!Enabled)
416 return; 614 return;
417 615
418// m_log.DebugFormat( 616 if (DebugLevel > 0)
419// "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}", 617 m_log.DebugFormat(
420// sp.UUID, soLocalId); 618 "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}",
619 sp.UUID, soLocalId);
421 620
422 SceneObjectGroup so = m_scene.GetGroupByPrim(soLocalId); 621 SceneObjectGroup so = m_scene.GetGroupByPrim(soLocalId);
423 622
@@ -433,9 +632,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
433 if (inventoryID == UUID.Zero) 632 if (inventoryID == UUID.Zero)
434 return; 633 return;
435 634
436// m_log.DebugFormat( 635 if (DebugLevel > 0)
437// "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}", 636 m_log.DebugFormat(
438// so.Name, so.LocalId, inventoryID); 637 "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}",
638 so.Name, so.LocalId, inventoryID);
439 639
440 lock (sp.AttachmentsSyncLock) 640 lock (sp.AttachmentsSyncLock)
441 { 641 {
@@ -463,6 +663,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
463 so.ClearPartAttachmentData(); 663 so.ClearPartAttachmentData();
464 rootPart.ApplyPhysics(rootPart.GetEffectiveObjectFlags(), rootPart.VolumeDetectActive); 664 rootPart.ApplyPhysics(rootPart.GetEffectiveObjectFlags(), rootPart.VolumeDetectActive);
465 so.HasGroupChanged = true; 665 so.HasGroupChanged = true;
666 so.RootPart.Shape.LastAttachPoint = (byte)so.AttachmentPoint;
466 rootPart.Rezzed = DateTime.Now; 667 rootPart.Rezzed = DateTime.Now;
467 rootPart.RemFlag(PrimFlags.TemporaryOnRez); 668 rootPart.RemFlag(PrimFlags.TemporaryOnRez);
468 so.AttachToBackup(); 669 so.AttachToBackup();
@@ -481,25 +682,38 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
481 682
482 public void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup so) 683 public void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup so)
483 { 684 {
685 if (so.AttachedAvatar != sp.UUID)
686 {
687 m_log.WarnFormat(
688 "[ATTACHMENTS MODULE]: Tried to detach object {0} from {1} {2} but attached avatar id was {3} in {4}",
689 so.Name, sp.Name, sp.UUID, so.AttachedAvatar, m_scene.RegionInfo.RegionName);
690
691 return;
692 }
693
694 if (DebugLevel > 0)
695 m_log.DebugFormat(
696 "[ATTACHMENTS MODULE]: Detaching object {0} {1} (FromItemID {2}) for {3} in {4}",
697 so.Name, so.LocalId, so.FromItemID, sp.Name, m_scene.Name);
698
699 // Scripts MUST be snapshotted before the object is
700 // removed from the scene because doing otherwise will
701 // clobber the run flag
702 // This must be done outside the sp.AttachmentSyncLock so that there is no risk of a deadlock from
703 // scripts performing attachment operations at the same time. Getting object states stops the scripts.
704 string scriptedState = PrepareScriptInstanceForSave(so, true);
705
484 lock (sp.AttachmentsSyncLock) 706 lock (sp.AttachmentsSyncLock)
485 { 707 {
486 // Save avatar attachment information 708 // Save avatar attachment information
487// m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID); 709// m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID);
488 710
489 if (so.AttachedAvatar != sp.UUID)
490 {
491 m_log.WarnFormat(
492 "[ATTACHMENTS MODULE]: Tried to detach object {0} from {1} {2} but attached avatar id was {3} in {4}",
493 so.Name, sp.Name, sp.UUID, so.AttachedAvatar, m_scene.RegionInfo.RegionName);
494
495 return;
496 }
497
498 bool changed = sp.Appearance.DetachAttachment(so.FromItemID); 711 bool changed = sp.Appearance.DetachAttachment(so.FromItemID);
499 if (changed && m_scene.AvatarFactory != null) 712 if (changed && m_scene.AvatarFactory != null)
500 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); 713 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID);
501 714
502 DetachSingleAttachmentToInvInternal(sp, so); 715 sp.RemoveAttachment(so);
716 UpdateDetachedObject(sp, so, scriptedState);
503 } 717 }
504 } 718 }
505 719
@@ -588,15 +802,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
588 (sbyte)AssetType.Object, 802 (sbyte)AssetType.Object,
589 Utils.StringToBytes(sceneObjectXml), 803 Utils.StringToBytes(sceneObjectXml),
590 sp.UUID); 804 sp.UUID);
591 m_scene.AssetService.Store(asset);
592 805
593 item.AssetID = asset.FullID; 806 if (m_invAccessModule != null)
594 item.Description = asset.Description; 807 m_invAccessModule.UpdateInventoryItemAsset(sp.UUID, item, asset);
595 item.Name = asset.Name;
596 item.AssetType = asset.Type;
597 item.InvType = (int)InventoryType.Object;
598
599 m_scene.InventoryService.UpdateItem(item);
600 808
601 // If the name of the object has been changed whilst attached then we want to update the inventory 809 // If the name of the object has been changed whilst attached then we want to update the inventory
602 // item in the viewer. 810 // item in the viewer.
@@ -606,12 +814,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
606 814
607 grp.HasGroupChanged = false; // Prevent it being saved over and over 815 grp.HasGroupChanged = false; // Prevent it being saved over and over
608 } 816 }
609// else 817 else if (DebugLevel > 0)
610// { 818 {
611// m_log.DebugFormat( 819 m_log.DebugFormat(
612// "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}", 820 "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}",
613// grp.UUID, grp.AttachmentPoint); 821 grp.UUID, grp.AttachmentPoint);
614// } 822 }
615 } 823 }
616 824
617 /// <summary> 825 /// <summary>
@@ -629,11 +837,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
629 private void AttachToAgent( 837 private void AttachToAgent(
630 IScenePresence sp, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent) 838 IScenePresence sp, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
631 { 839 {
632// m_log.DebugFormat( 840 if (DebugLevel > 0)
633// "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", 841 m_log.DebugFormat(
634// so.Name, sp.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos); 842 "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} at pt {2} pos {3} {4} in {5}",
635 843 so.Name, sp.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos, m_scene.Name);
636 so.DetachFromBackup();
637 844
638 // Remove from database and parcel prim count 845 // Remove from database and parcel prim count
639 m_scene.DeleteFromStorage(so.UUID); 846 m_scene.DeleteFromStorage(so.UUID);
@@ -656,16 +863,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
656 { 863 {
657 if (so.HasPrivateAttachmentPoint) 864 if (so.HasPrivateAttachmentPoint)
658 { 865 {
659// m_log.DebugFormat( 866 if (DebugLevel > 0)
660// "[ATTACHMENTS MODULE]: Killing private HUD {0} for avatars other than {1} at attachment point {2}", 867 m_log.DebugFormat(
661// so.Name, sp.Name, so.AttachmentPoint); 868 "[ATTACHMENTS MODULE]: Killing private HUD {0} for avatars other than {1} at attachment point {2}",
869 so.Name, sp.Name, so.AttachmentPoint);
662 870
663 // As this scene object can now only be seen by the attaching avatar, tell everybody else in the 871 // As this scene object can now only be seen by the attaching avatar, tell everybody else in the
664 // scene that it's no longer in their awareness. 872 // scene that it's no longer in their awareness.
665 m_scene.ForEachClient( 873 m_scene.ForEachClient(
666 client => 874 client =>
667 { if (client.AgentId != so.AttachedAvatar) 875 { if (client.AgentId != so.AttachedAvatar)
668 client.SendKillObject(m_scene.RegionInfo.RegionHandle, new List<uint>() { so.LocalId }); 876 client.SendKillObject(new List<uint>() { so.LocalId });
669 }); 877 });
670 } 878 }
671 879
@@ -692,14 +900,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
692 if (m_invAccessModule == null) 900 if (m_invAccessModule == null)
693 return null; 901 return null;
694 902
695 // m_log.DebugFormat( 903 if (DebugLevel > 0)
696 // "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}", 904 m_log.DebugFormat(
697 // grp.Name, grp.LocalId, remoteClient.Name); 905 "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}",
906 grp.Name, grp.LocalId, sp.Name);
698 907
699 InventoryItemBase newItem 908 InventoryItemBase newItem
700 = m_invAccessModule.CopyToInventory( 909 = m_invAccessModule.CopyToInventory(
701 DeRezAction.TakeCopy, 910 DeRezAction.TakeCopy,
702 m_scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object).ID, 911 m_scene.InventoryService.GetFolderForType(sp.UUID, FolderType.Object).ID,
703 new List<SceneObjectGroup> { grp }, 912 new List<SceneObjectGroup> { grp },
704 sp.ControllingClient, true)[0]; 913 sp.ControllingClient, true)[0];
705 914
@@ -709,8 +918,32 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
709 return newItem; 918 return newItem;
710 } 919 }
711 920
712 private string GetObjectScriptStates(SceneObjectGroup grp) 921 /// <summary>
922 /// Prepares the script instance for save.
923 /// </summary>
924 /// <remarks>
925 /// This involves triggering the detach event and getting the script state (which also stops the script)
926 /// This MUST be done outside sp.AttachmentsSyncLock, since otherwise there is a chance of deadlock if a
927 /// running script is performing attachment operations.
928 /// </remarks>
929 /// <returns>
930 /// The script state ready for persistence.
931 /// </returns>
932 /// <param name='grp'>
933 /// </param>
934 /// <param name='fireDetachEvent'>
935 /// If true, then fire the script event before we save its state.
936 /// </param>
937 private string PrepareScriptInstanceForSave(SceneObjectGroup grp, bool fireDetachEvent)
713 { 938 {
939 if (fireDetachEvent)
940 {
941 m_scene.EventManager.TriggerOnAttach(grp.LocalId, grp.FromItemID, UUID.Zero);
942
943 // Allow detach event time to do some work before stopping the script
944 Thread.Sleep(2);
945 }
946
714 using (StringWriter sw = new StringWriter()) 947 using (StringWriter sw = new StringWriter())
715 { 948 {
716 using (XmlTextWriter writer = new XmlTextWriter(sw)) 949 using (XmlTextWriter writer = new XmlTextWriter(sw))
@@ -722,7 +955,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
722 } 955 }
723 } 956 }
724 957
725 private void UpdateDetachedObject(IScenePresence sp, SceneObjectGroup so) 958 private void UpdateDetachedObject(IScenePresence sp, SceneObjectGroup so, string scriptedState)
726 { 959 {
727 // Don't save attachments for HG visitors, it 960 // Don't save attachments for HG visitors, it
728 // messes up their inventory. When a HG visitor logs 961 // messes up their inventory. When a HG visitor logs
@@ -735,11 +968,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
735 && (m_scene.UserManagementModule == null 968 && (m_scene.UserManagementModule == null
736 || m_scene.UserManagementModule.IsLocalGridUser(sp.UUID)); 969 || m_scene.UserManagementModule.IsLocalGridUser(sp.UUID));
737 970
738 // Scripts MUST be snapshotted before the object is
739 // removed from the scene because doing otherwise will
740 // clobber the run flag
741 string scriptedState = GetObjectScriptStates(so);
742
743 // Remove the object from the scene so no more updates 971 // Remove the object from the scene so no more updates
744 // are sent. Doing this before the below changes will ensure 972 // are sent. Doing this before the below changes will ensure
745 // updates can't cause "HUD artefacts" 973 // updates can't cause "HUD artefacts"
@@ -763,91 +991,88 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
763 so.RemoveScriptInstances(true); 991 so.RemoveScriptInstances(true);
764 } 992 }
765 993
766 private void DetachSingleAttachmentToInvInternal(IScenePresence sp, SceneObjectGroup so) 994 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal(
995 IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, bool append)
767 { 996 {
768 // m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name); 997 if (m_invAccessModule == null)
998 return null;
769 999
770 m_scene.EventManager.TriggerOnAttach(so.LocalId, so.FromItemID, UUID.Zero); 1000 SceneObjectGroup objatt;
771 sp.RemoveAttachment(so);
772 1001
773 UpdateDetachedObject(sp, so); 1002 if (itemID != UUID.Zero)
774 } 1003 objatt = m_invAccessModule.RezObject(sp.ControllingClient,
1004 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
1005 false, false, sp.UUID, true);
1006 else
1007 objatt = m_invAccessModule.RezObject(sp.ControllingClient,
1008 null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
1009 false, false, sp.UUID, true);
775 1010
776 private SceneObjectGroup RezSingleAttachmentFromInventoryInternal( 1011 if (objatt == null)
777 IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt) 1012 {
778 { 1013 m_log.WarnFormat(
779 if (m_invAccessModule == null) 1014 "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}",
780 return null; 1015 itemID, sp.Name, attachmentPt);
781 1016
782 lock (sp.AttachmentsSyncLock) 1017 return null;
1018 }
1019 else if (itemID == UUID.Zero)
783 { 1020 {
784 SceneObjectGroup objatt; 1021 // We need to have a FromItemID for multiple attachments on a single attach point to appear. This is
1022 // true on Singularity 1.8.5 and quite possibly other viewers as well. As NPCs don't have an inventory
1023 // we will satisfy this requirement by inserting a random UUID.
1024 objatt.FromItemID = UUID.Random();
1025 }
785 1026
786 if (itemID != UUID.Zero) 1027 if (DebugLevel > 0)
787 objatt = m_invAccessModule.RezObject(sp.ControllingClient, 1028 m_log.DebugFormat(
788 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, 1029 "[ATTACHMENTS MODULE]: Rezzed single object {0} with {1} prims for attachment to {2} on point {3} in {4}",
789 false, false, sp.UUID, true); 1030 objatt.Name, objatt.PrimCount, sp.Name, attachmentPt, m_scene.Name);
790 else 1031
791 objatt = m_invAccessModule.RezObject(sp.ControllingClient, 1032 // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
792 null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, 1033 objatt.HasGroupChanged = false;
793 false, false, sp.UUID, true); 1034 bool tainted = false;
1035 if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
1036 tainted = true;
1037
1038 // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal
1039 // course of events. If not, then it's probably not worth trying to recover the situation
1040 // since this is more likely to trigger further exceptions and confuse later debugging. If
1041 // exceptions can be thrown in expected error conditions (not NREs) then make this consistent
1042 // since other normal error conditions will simply return false instead.
1043 // This will throw if the attachment fails
1044 try
1045 {
1046 AttachObjectInternal(sp, objatt, attachmentPt, false, true, true, append);
1047 }
1048 catch (Exception e)
1049 {
1050 m_log.ErrorFormat(
1051 "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
1052 objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
794 1053
795 if (objatt != null) 1054 // Make sure the object doesn't stick around and bail
796 { 1055 sp.RemoveAttachment(objatt);
797// m_log.DebugFormat( 1056 m_scene.DeleteSceneObject(objatt, false);
798// "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}", 1057 return null;
799// objatt.Name, sp.Name, attachmentPt, m_scene.Name); 1058 }
800
801 // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
802 objatt.HasGroupChanged = false;
803 bool tainted = false;
804 if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
805 tainted = true;
806
807 // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal
808 // course of events. If not, then it's probably not worth trying to recover the situation
809 // since this is more likely to trigger further exceptions and confuse later debugging. If
810 // exceptions can be thrown in expected error conditions (not NREs) then make this consistent
811 // since other normal error conditions will simply return false instead.
812 // This will throw if the attachment fails
813 try
814 {
815 AttachObjectInternal(sp, objatt, attachmentPt, false, false);
816 }
817 catch (Exception e)
818 {
819 m_log.ErrorFormat(
820 "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
821 objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
822
823 // Make sure the object doesn't stick around and bail
824 sp.RemoveAttachment(objatt);
825 m_scene.DeleteSceneObject(objatt, false);
826 return null;
827 }
828 1059
829 if (tainted) 1060 if (tainted)
830 objatt.HasGroupChanged = true; 1061 objatt.HasGroupChanged = true;
831 1062
832 // Fire after attach, so we don't get messy perms dialogs 1063 if (ThrottlePer100PrimsRezzed > 0)
833 // 4 == AttachedRez 1064 {
834 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); 1065 int throttleMs = (int)Math.Round((float)objatt.PrimCount / 100 * ThrottlePer100PrimsRezzed);
835 objatt.ResumeScripts();
836 1066
837 // Do this last so that event listeners have access to all the effects of the attachment 1067 if (DebugLevel > 0)
838 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); 1068 m_log.DebugFormat(
1069 "[ATTACHMENTS MODULE]: Throttling by {0}ms after rez of {1} with {2} prims for attachment to {3} on point {4} in {5}",
1070 throttleMs, objatt.Name, objatt.PrimCount, sp.Name, attachmentPt, m_scene.Name);
839 1071
840 return objatt; 1072 Thread.Sleep(throttleMs);
841 }
842 else
843 {
844 m_log.WarnFormat(
845 "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}",
846 itemID, sp.Name, attachmentPt);
847 }
848 } 1073 }
849 1074
850 return null; 1075 return objatt;
851 } 1076 }
852 1077
853 /// <summary> 1078 /// <summary>
@@ -857,7 +1082,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
857 /// <param name="AttachmentPt"></param> 1082 /// <param name="AttachmentPt"></param>
858 /// <param name="itemID"></param> 1083 /// <param name="itemID"></param>
859 /// <param name="att"></param> 1084 /// <param name="att"></param>
860 private void ShowAttachInUserInventory(IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att) 1085 private void ShowAttachInUserInventory(IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att, bool append)
861 { 1086 {
862// m_log.DebugFormat( 1087// m_log.DebugFormat(
863// "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", 1088// "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}",
@@ -880,12 +1105,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
880 if (item == null) 1105 if (item == null)
881 return; 1106 return;
882 1107
883 bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); 1108 int attFlag = append ? 0x80 : 0;
1109 bool changed = sp.Appearance.SetAttachment((int)AttachmentPt | attFlag, itemID, item.AssetID);
884 if (changed && m_scene.AvatarFactory != null) 1110 if (changed && m_scene.AvatarFactory != null)
885 { 1111 {
886// m_log.DebugFormat( 1112 if (DebugLevel > 0)
887// "[ATTACHMENTS MODULE]: Queueing appearance save for {0}, attachment {1} point {2} in ShowAttachInUserInventory()", 1113 m_log.DebugFormat(
888// sp.Name, att.Name, AttachmentPt); 1114 "[ATTACHMENTS MODULE]: Queueing appearance save for {0}, attachment {1} point {2} in ShowAttachInUserInventory()",
1115 sp.Name, att.Name, AttachmentPt);
889 1116
890 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); 1117 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID);
891 } 1118 }
@@ -900,9 +1127,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
900 if (!Enabled) 1127 if (!Enabled)
901 return null; 1128 return null;
902 1129
903 // m_log.DebugFormat( 1130 if (DebugLevel > 0)
904 // "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", 1131 m_log.DebugFormat(
905 // (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name); 1132 "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}",
1133 (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name);
906 1134
907 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); 1135 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
908 1136
@@ -933,9 +1161,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
933 1161
934 private void Client_OnObjectAttach(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent) 1162 private void Client_OnObjectAttach(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent)
935 { 1163 {
936// m_log.DebugFormat( 1164 if (DebugLevel > 0)
937// "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})", 1165 m_log.DebugFormat(
938// objectLocalID, remoteClient.Name, AttachmentPt, silent); 1166 "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})",
1167 objectLocalID, remoteClient.Name, AttachmentPt, silent);
939 1168
940 if (!Enabled) 1169 if (!Enabled)
941 return; 1170 return;
@@ -964,12 +1193,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
964 return; 1193 return;
965 } 1194 }
966 1195
967 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should 1196 bool append = (AttachmentPt & 0x80) != 0;
968 // be removed when that functionality is implemented in opensim
969 AttachmentPt &= 0x7f; 1197 AttachmentPt &= 0x7f;
970 1198
971 // Calls attach with a Zero position 1199 // Calls attach with a Zero position
972 AttachObject(sp, part.ParentGroup, AttachmentPt, false, false); 1200 if (AttachObject(sp, part.ParentGroup, AttachmentPt, false, true, append))
1201 {
1202 if (DebugLevel > 0)
1203 m_log.Debug(
1204 "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId
1205 + ", AttachmentPoint: " + AttachmentPt);
1206
1207 // Save avatar attachment information
1208 m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.FromItemID, remoteClient.AgentId);
1209 }
973 } 1210 }
974 catch (Exception e) 1211 catch (Exception e)
975 { 1212 {
@@ -997,17 +1234,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
997 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); 1234 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
998 if (sp != null) 1235 if (sp != null)
999 { 1236 {
1000 lock (sp.AttachmentsSyncLock) 1237 List<SceneObjectGroup> attachments = sp.GetAttachments();
1238
1239 foreach (SceneObjectGroup group in attachments)
1001 { 1240 {
1002 List<SceneObjectGroup> attachments = sp.GetAttachments(); 1241 if (group.FromItemID == itemID && group.FromItemID != UUID.Zero)
1003
1004 foreach (SceneObjectGroup group in attachments)
1005 { 1242 {
1006 if (group.FromItemID == itemID && group.FromItemID != UUID.Zero) 1243 DetachSingleAttachmentToInv(sp, group);
1007 { 1244 return;
1008 DetachSingleAttachmentToInv(sp, group);
1009 return;
1010 }
1011 } 1245 }
1012 } 1246 }
1013 } 1247 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
index 0ee01c7..0ac3add 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
@@ -37,7 +37,8 @@ using Nini.Config;
37using NUnit.Framework; 37using NUnit.Framework;
38using OpenMetaverse; 38using OpenMetaverse;
39using OpenSim.Framework; 39using OpenSim.Framework;
40using OpenSim.Framework.Communications; 40using OpenSim.Framework.Servers;
41using OpenSim.Framework.Servers.HttpServer;
41using OpenSim.Region.CoreModules.Avatar.Attachments; 42using OpenSim.Region.CoreModules.Avatar.Attachments;
42using OpenSim.Region.CoreModules.Framework; 43using OpenSim.Region.CoreModules.Framework;
43using OpenSim.Region.CoreModules.Framework.EntityTransfer; 44using OpenSim.Region.CoreModules.Framework.EntityTransfer;
@@ -51,7 +52,6 @@ using OpenSim.Region.ScriptEngine.Interfaces;
51using OpenSim.Region.ScriptEngine.XEngine; 52using OpenSim.Region.ScriptEngine.XEngine;
52using OpenSim.Services.Interfaces; 53using OpenSim.Services.Interfaces;
53using OpenSim.Tests.Common; 54using OpenSim.Tests.Common;
54using OpenSim.Tests.Common.Mock;
55 55
56namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests 56namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
57{ 57{
@@ -130,7 +130,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
130 config.AddConfig("Modules"); 130 config.AddConfig("Modules");
131 config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); 131 config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule");
132 132
133 modules.Add(new AttachmentsModule()); 133 AttachmentsModule attMod = new AttachmentsModule();
134 attMod.DebugLevel = 1;
135 modules.Add(attMod);
134 modules.Add(new BasicInventoryAccessModule()); 136 modules.Add(new BasicInventoryAccessModule());
135 } 137 }
136 138
@@ -195,9 +197,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
195 string attName = "att"; 197 string attName = "att";
196 198
197 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID); 199 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID);
200 Assert.That(so.Backup, Is.True);
198 201
199 m_numberOfAttachEventsFired = 0; 202 m_numberOfAttachEventsFired = 0;
200 scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false); 203 scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, true, false);
201 204
202 // Check status on scene presence 205 // Check status on scene presence
203 Assert.That(sp.HasAttachments(), Is.True); 206 Assert.That(sp.HasAttachments(), Is.True);
@@ -209,6 +212,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
209 Assert.That(attSo.IsAttachment); 212 Assert.That(attSo.IsAttachment);
210 Assert.That(attSo.UsesPhysics, Is.False); 213 Assert.That(attSo.UsesPhysics, Is.False);
211 Assert.That(attSo.IsTemporary, Is.False); 214 Assert.That(attSo.IsTemporary, Is.False);
215 Assert.That(attSo.Backup, Is.False);
212 216
213 // Check item status 217 // Check item status
214 Assert.That( 218 Assert.That(
@@ -219,7 +223,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
219 Assert.That(attachmentItem, Is.Not.Null); 223 Assert.That(attachmentItem, Is.Not.Null);
220 Assert.That(attachmentItem.Name, Is.EqualTo(attName)); 224 Assert.That(attachmentItem.Name, Is.EqualTo(attName));
221 225
222 InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object); 226 InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, FolderType.Object);
223 Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID)); 227 Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
224 228
225 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); 229 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
@@ -228,6 +232,120 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
228 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); 232 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
229 } 233 }
230 234
235 [Test]
236 public void TestWearAttachmentFromGround()
237 {
238 TestHelpers.InMethod();
239// TestHelpers.EnableLogging();
240
241 Scene scene = CreateTestScene();
242 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
243 ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
244
245 SceneObjectGroup so2 = SceneHelpers.AddSceneObject(scene, "att2", sp.UUID);
246
247 {
248 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "att1", sp.UUID);
249
250 m_numberOfAttachEventsFired = 0;
251 scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Default, false, true, false);
252
253 // Check status on scene presence
254 Assert.That(sp.HasAttachments(), Is.True);
255 List<SceneObjectGroup> attachments = sp.GetAttachments();
256 Assert.That(attachments.Count, Is.EqualTo(1));
257 SceneObjectGroup attSo = attachments[0];
258 Assert.That(attSo.Name, Is.EqualTo(so.Name));
259 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
260 Assert.That(attSo.IsAttachment);
261 Assert.That(attSo.UsesPhysics, Is.False);
262 Assert.That(attSo.IsTemporary, Is.False);
263
264 // Check item status
265 Assert.That(
266 sp.Appearance.GetAttachpoint(attSo.FromItemID),
267 Is.EqualTo((int)AttachmentPoint.LeftHand));
268
269 InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID));
270 Assert.That(attachmentItem, Is.Not.Null);
271 Assert.That(attachmentItem.Name, Is.EqualTo(so.Name));
272
273 InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, FolderType.Object);
274 Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
275
276 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(2));
277
278 // Check events
279 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
280 }
281
282 // Test wearing a different attachment from the ground.
283 {
284 scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, true, false);
285
286 // Check status on scene presence
287 Assert.That(sp.HasAttachments(), Is.True);
288 List<SceneObjectGroup> attachments = sp.GetAttachments();
289 Assert.That(attachments.Count, Is.EqualTo(1));
290 SceneObjectGroup attSo = attachments[0];
291 Assert.That(attSo.Name, Is.EqualTo(so2.Name));
292 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
293 Assert.That(attSo.IsAttachment);
294 Assert.That(attSo.UsesPhysics, Is.False);
295 Assert.That(attSo.IsTemporary, Is.False);
296
297 // Check item status
298 Assert.That(
299 sp.Appearance.GetAttachpoint(attSo.FromItemID),
300 Is.EqualTo((int)AttachmentPoint.LeftHand));
301
302 InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID));
303 Assert.That(attachmentItem, Is.Not.Null);
304 Assert.That(attachmentItem.Name, Is.EqualTo(so2.Name));
305
306 InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, FolderType.Object);
307 Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
308
309 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
310
311 // Check events
312 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
313 }
314
315 // Test rewearing an already worn attachment from ground. Nothing should happen.
316 {
317 scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, true, false);
318
319 // Check status on scene presence
320 Assert.That(sp.HasAttachments(), Is.True);
321 List<SceneObjectGroup> attachments = sp.GetAttachments();
322 Assert.That(attachments.Count, Is.EqualTo(1));
323 SceneObjectGroup attSo = attachments[0];
324 Assert.That(attSo.Name, Is.EqualTo(so2.Name));
325 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
326 Assert.That(attSo.IsAttachment);
327 Assert.That(attSo.UsesPhysics, Is.False);
328 Assert.That(attSo.IsTemporary, Is.False);
329
330 // Check item status
331 Assert.That(
332 sp.Appearance.GetAttachpoint(attSo.FromItemID),
333 Is.EqualTo((int)AttachmentPoint.LeftHand));
334
335 InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID));
336 Assert.That(attachmentItem, Is.Not.Null);
337 Assert.That(attachmentItem.Name, Is.EqualTo(so2.Name));
338
339 InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, FolderType.Object);
340 Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
341
342 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
343
344 // Check events
345 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
346 }
347 }
348
231 /// <summary> 349 /// <summary>
232 /// Test that we do not attempt to attach an in-world object that someone else is sitting on. 350 /// Test that we do not attempt to attach an in-world object that someone else is sitting on.
233 /// </summary> 351 /// </summary>
@@ -254,7 +372,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
254 sp2.AbsolutePosition = new Vector3(0, 0, 0); 372 sp2.AbsolutePosition = new Vector3(0, 0, 0);
255 sp2.HandleAgentRequestSit(sp2.ControllingClient, sp2.UUID, so.UUID, Vector3.Zero); 373 sp2.HandleAgentRequestSit(sp2.ControllingClient, sp2.UUID, so.UUID, Vector3.Zero);
256 374
257 scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false); 375 scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, true, false);
258 376
259 Assert.That(sp.HasAttachments(), Is.False); 377 Assert.That(sp.HasAttachments(), Is.False);
260 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); 378 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
@@ -267,7 +385,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
267 public void TestRezAttachmentFromInventory() 385 public void TestRezAttachmentFromInventory()
268 { 386 {
269 TestHelpers.InMethod(); 387 TestHelpers.InMethod();
270// log4net.Config.XmlConfigurator.Configure(); 388// TestHelpers.EnableLogging();
271 389
272 Scene scene = CreateTestScene(); 390 Scene scene = CreateTestScene();
273 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); 391 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
@@ -275,29 +393,141 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
275 393
276 InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); 394 InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
277 395
278 m_numberOfAttachEventsFired = 0; 396 {
279 scene.AttachmentsModule.RezSingleAttachmentFromInventory( 397 scene.AttachmentsModule.RezSingleAttachmentFromInventory(
280 sp, attItem.ID, (uint)AttachmentPoint.Chest); 398 sp, attItem.ID, (uint)AttachmentPoint.Chest);
281 399
282 // Check scene presence status 400 // Check scene presence status
283 Assert.That(sp.HasAttachments(), Is.True); 401 Assert.That(sp.HasAttachments(), Is.True);
284 List<SceneObjectGroup> attachments = sp.GetAttachments(); 402 List<SceneObjectGroup> attachments = sp.GetAttachments();
285 Assert.That(attachments.Count, Is.EqualTo(1)); 403 Assert.That(attachments.Count, Is.EqualTo(1));
286 SceneObjectGroup attSo = attachments[0]; 404 SceneObjectGroup attSo = attachments[0];
287 Assert.That(attSo.Name, Is.EqualTo(attItem.Name)); 405 Assert.That(attSo.Name, Is.EqualTo(attItem.Name));
288 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); 406 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest));
289 Assert.That(attSo.IsAttachment); 407 Assert.That(attSo.IsAttachment);
290 Assert.That(attSo.UsesPhysics, Is.False); 408 Assert.That(attSo.UsesPhysics, Is.False);
291 Assert.That(attSo.IsTemporary, Is.False); 409 Assert.That(attSo.IsTemporary, Is.False);
410 Assert.IsFalse(attSo.Backup);
411
412 // Check appearance status
413 Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
414 Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
415 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
416
417 // Check events
418 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
419 }
420
421 // Test attaching an already attached attachment
422 {
423 scene.AttachmentsModule.RezSingleAttachmentFromInventory(
424 sp, attItem.ID, (uint)AttachmentPoint.Chest);
292 425
293 // Check appearance status 426 // Check scene presence status
294 Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); 427 Assert.That(sp.HasAttachments(), Is.True);
295 Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); 428 List<SceneObjectGroup> attachments = sp.GetAttachments();
429 Assert.That(attachments.Count, Is.EqualTo(1));
430 SceneObjectGroup attSo = attachments[0];
431 Assert.That(attSo.Name, Is.EqualTo(attItem.Name));
432 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest));
433 Assert.That(attSo.IsAttachment);
434 Assert.That(attSo.UsesPhysics, Is.False);
435 Assert.That(attSo.IsTemporary, Is.False);
436
437 // Check appearance status
438 Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
439 Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
440 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
441
442 // Check events
443 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
444 }
445 }
296 446
297 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); 447 /// <summary>
448 /// Test wearing an attachment from inventory, as opposed to explicit choosing the rez point
449 /// </summary>
450 [Test]
451 public void TestWearAttachmentFromInventory()
452 {
453 TestHelpers.InMethod();
454// TestHelpers.EnableLogging();
298 455
299 // Check events 456 Scene scene = CreateTestScene();
300 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); 457 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
458 ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID);
459
460 InventoryItemBase attItem1 = CreateAttachmentItem(scene, ua1.PrincipalID, "att1", 0x10, 0x20);
461 InventoryItemBase attItem2 = CreateAttachmentItem(scene, ua1.PrincipalID, "att2", 0x11, 0x21);
462
463 {
464 m_numberOfAttachEventsFired = 0;
465 scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem1.ID, (uint)AttachmentPoint.Default);
466
467 // default attachment point is currently the left hand.
468 Assert.That(sp.HasAttachments(), Is.True);
469 List<SceneObjectGroup> attachments = sp.GetAttachments();
470 Assert.That(attachments.Count, Is.EqualTo(1));
471 SceneObjectGroup attSo = attachments[0];
472 Assert.That(attSo.Name, Is.EqualTo(attItem1.Name));
473 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
474 Assert.That(attSo.IsAttachment);
475
476 // Check appearance status
477 Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
478 Assert.That(sp.Appearance.GetAttachpoint(attItem1.ID), Is.EqualTo((int)AttachmentPoint.LeftHand));
479 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
480
481 // Check events
482 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
483 }
484
485 // Test wearing a second attachment at the same position
486 // Until multiple attachments at one point is implemented, this will remove the first attachment
487 // This test relies on both attachments having the same default attachment point (in this case LeftHand
488 // since none other has been set).
489 {
490 scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem2.ID, (uint)AttachmentPoint.Default);
491
492 // default attachment point is currently the left hand.
493 Assert.That(sp.HasAttachments(), Is.True);
494 List<SceneObjectGroup> attachments = sp.GetAttachments();
495 Assert.That(attachments.Count, Is.EqualTo(1));
496 SceneObjectGroup attSo = attachments[0];
497 Assert.That(attSo.Name, Is.EqualTo(attItem2.Name));
498 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
499 Assert.That(attSo.IsAttachment);
500
501 // Check appearance status
502 Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
503 Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand));
504 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
505
506 // Check events
507 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
508 }
509
510 // Test wearing an already attached attachment
511 {
512 scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem2.ID, (uint)AttachmentPoint.Default);
513
514 // default attachment point is currently the left hand.
515 Assert.That(sp.HasAttachments(), Is.True);
516 List<SceneObjectGroup> attachments = sp.GetAttachments();
517 Assert.That(attachments.Count, Is.EqualTo(1));
518 SceneObjectGroup attSo = attachments[0];
519 Assert.That(attSo.Name, Is.EqualTo(attItem2.Name));
520 Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
521 Assert.That(attSo.IsAttachment);
522
523 // Check appearance status
524 Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
525 Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand));
526 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
527
528 // Check events
529 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
530 }
301 } 531 }
302 532
303 /// <summary> 533 /// <summary>
@@ -315,7 +545,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
315 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10); 545 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10);
316 TaskInventoryItem scriptItem 546 TaskInventoryItem scriptItem
317 = TaskInventoryHelpers.AddScript( 547 = TaskInventoryHelpers.AddScript(
318 scene, 548 scene.AssetService,
319 so.RootPart, 549 so.RootPart,
320 "scriptItem", 550 "scriptItem",
321 "default { attach(key id) { if (id != NULL_KEY) { llSay(0, \"Hello World\"); } } }"); 551 "default { attach(key id) { if (id != NULL_KEY) { llSay(0, \"Hello World\"); } } }");
@@ -372,7 +602,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
372 Assert.That(scene.InventoryService.GetItem(new InventoryItemBase(attItem.ID)), Is.Null); 602 Assert.That(scene.InventoryService.GetItem(new InventoryItemBase(attItem.ID)), Is.Null);
373 603
374 // Check object in scene 604 // Check object in scene
375 Assert.That(scene.GetSceneObjectGroup("att"), Is.Not.Null); 605 SceneObjectGroup soInScene = scene.GetSceneObjectGroup("att");
606 Assert.That(soInScene, Is.Not.Null);
607 Assert.IsTrue(soInScene.Backup);
376 608
377 // Check events 609 // Check events
378 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); 610 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
@@ -426,7 +658,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
426 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10); 658 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10);
427 TaskInventoryItem scriptTaskItem 659 TaskInventoryItem scriptTaskItem
428 = TaskInventoryHelpers.AddScript( 660 = TaskInventoryHelpers.AddScript(
429 scene, 661 scene.AssetService,
430 so.RootPart, 662 so.RootPart,
431 "scriptItem", 663 "scriptItem",
432 "default { attach(key id) { if (id != NULL_KEY) { llSay(0, \"Hello World\"); } } }"); 664 "default { attach(key id) { if (id != NULL_KEY) { llSay(0, \"Hello World\"); } } }");
@@ -490,7 +722,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
490 SceneObjectGroup rezzedAtt = presence.GetAttachments()[0]; 722 SceneObjectGroup rezzedAtt = presence.GetAttachments()[0];
491 723
492 m_numberOfAttachEventsFired = 0; 724 m_numberOfAttachEventsFired = 0;
493 scene.IncomingCloseAgent(presence.UUID, false); 725 scene.CloseAgent(presence.UUID, false);
494 726
495 // Check that we can't retrieve this attachment from the scene. 727 // Check that we can't retrieve this attachment from the scene.
496 Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null); 728 Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null);
@@ -503,7 +735,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
503 public void TestRezAttachmentsOnAvatarEntrance() 735 public void TestRezAttachmentsOnAvatarEntrance()
504 { 736 {
505 TestHelpers.InMethod(); 737 TestHelpers.InMethod();
506// log4net.Config.XmlConfigurator.Configure(); 738// TestHelpers.EnableLogging();
507 739
508 Scene scene = CreateTestScene(); 740 Scene scene = CreateTestScene();
509 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); 741 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
@@ -526,6 +758,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
526 Assert.That(attSo.IsAttachment); 758 Assert.That(attSo.IsAttachment);
527 Assert.That(attSo.UsesPhysics, Is.False); 759 Assert.That(attSo.UsesPhysics, Is.False);
528 Assert.That(attSo.IsTemporary, Is.False); 760 Assert.That(attSo.IsTemporary, Is.False);
761 Assert.IsFalse(attSo.Backup);
529 762
530 // Check appearance status 763 // Check appearance status
531 List<AvatarAttachment> retreivedAttachments = presence.Appearance.GetAttachments(); 764 List<AvatarAttachment> retreivedAttachments = presence.Appearance.GetAttachments();
@@ -569,12 +802,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
569 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0)); 802 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
570 } 803 }
571 804
805/*
572 [Test] 806 [Test]
573 public void TestSameSimulatorNeighbouringRegionsTeleport() 807 public void TestSameSimulatorNeighbouringRegionsTeleportV1()
574 { 808 {
575 TestHelpers.InMethod(); 809 TestHelpers.InMethod();
576// TestHelpers.EnableLogging(); 810// TestHelpers.EnableLogging();
577 811
812 BaseHttpServer httpServer = new BaseHttpServer(99999);
813 MainServer.AddHttpServer(httpServer);
814 MainServer.Instance = httpServer;
815
578 AttachmentsModule attModA = new AttachmentsModule(); 816 AttachmentsModule attModA = new AttachmentsModule();
579 AttachmentsModule attModB = new AttachmentsModule(); 817 AttachmentsModule attModB = new AttachmentsModule();
580 EntityTransferModule etmA = new EntityTransferModule(); 818 EntityTransferModule etmA = new EntityTransferModule();
@@ -603,8 +841,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
603 SceneHelpers.SetupSceneModules( 841 SceneHelpers.SetupSceneModules(
604 sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule()); 842 sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule());
605 843
844 // FIXME: Hack - this is here temporarily to revert back to older entity transfer behaviour
845 lscm.ServiceVersion = 0.1f;
846
606 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1); 847 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1);
607 ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, ua1.PrincipalID, sh.SceneManager); 848
849 AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID);
850 TestClient tc = new TestClient(acd, sceneA);
851 List<TestClient> destinationTestClients = new List<TestClient>();
852 EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients);
853
854 ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd);
608 beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32); 855 beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32);
609 856
610 InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20); 857 InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20);
@@ -623,7 +870,119 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
623 teleportLookAt, 870 teleportLookAt,
624 (uint)TeleportFlags.ViaLocation); 871 (uint)TeleportFlags.ViaLocation);
625 872
626 ((TestClient)beforeTeleportSp.ControllingClient).CompleteTeleportClientSide(); 873 destinationTestClients[0].CompleteMovement();
874
875 // Check attachments have made it into sceneB
876 ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID);
877
878 // This is appearance data, as opposed to actually rezzed attachments
879 List<AvatarAttachment> sceneBAttachments = afterTeleportSceneBSp.Appearance.GetAttachments();
880 Assert.That(sceneBAttachments.Count, Is.EqualTo(1));
881 Assert.That(sceneBAttachments[0].AttachPoint, Is.EqualTo((int)AttachmentPoint.Chest));
882 Assert.That(sceneBAttachments[0].ItemID, Is.EqualTo(attItem.ID));
883 Assert.That(sceneBAttachments[0].AssetID, Is.EqualTo(attItem.AssetID));
884 Assert.That(afterTeleportSceneBSp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
885
886 // This is the actual attachment
887 List<SceneObjectGroup> actualSceneBAttachments = afterTeleportSceneBSp.GetAttachments();
888 Assert.That(actualSceneBAttachments.Count, Is.EqualTo(1));
889 SceneObjectGroup actualSceneBAtt = actualSceneBAttachments[0];
890 Assert.That(actualSceneBAtt.Name, Is.EqualTo(attItem.Name));
891 Assert.That(actualSceneBAtt.AttachmentPoint, Is.EqualTo((uint)AttachmentPoint.Chest));
892 Assert.IsFalse(actualSceneBAtt.Backup);
893
894 Assert.That(sceneB.GetSceneObjectGroups().Count, Is.EqualTo(1));
895
896 // Check attachments have been removed from sceneA
897 ScenePresence afterTeleportSceneASp = sceneA.GetScenePresence(ua1.PrincipalID);
898
899 // Since this is appearance data, it is still present on the child avatar!
900 List<AvatarAttachment> sceneAAttachments = afterTeleportSceneASp.Appearance.GetAttachments();
901 Assert.That(sceneAAttachments.Count, Is.EqualTo(1));
902 Assert.That(afterTeleportSceneASp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
903
904 // This is the actual attachment, which should no longer exist
905 List<SceneObjectGroup> actualSceneAAttachments = afterTeleportSceneASp.GetAttachments();
906 Assert.That(actualSceneAAttachments.Count, Is.EqualTo(0));
907
908 Assert.That(sceneA.GetSceneObjectGroups().Count, Is.EqualTo(0));
909
910 // Check events
911 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
912 }
913*/
914
915 [Test]
916 public void TestSameSimulatorNeighbouringRegionsTeleportV2()
917 {
918 TestHelpers.InMethod();
919// TestHelpers.EnableLogging();
920
921 BaseHttpServer httpServer = new BaseHttpServer(99999);
922 MainServer.AddHttpServer(httpServer);
923 MainServer.Instance = httpServer;
924
925 AttachmentsModule attModA = new AttachmentsModule();
926 AttachmentsModule attModB = new AttachmentsModule();
927 EntityTransferModule etmA = new EntityTransferModule();
928 EntityTransferModule etmB = new EntityTransferModule();
929 LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
930
931 IConfigSource config = new IniConfigSource();
932 IConfig modulesConfig = config.AddConfig("Modules");
933 modulesConfig.Set("EntityTransferModule", etmA.Name);
934 modulesConfig.Set("SimulationServices", lscm.Name);
935
936 modulesConfig.Set("InventoryAccessModule", "BasicInventoryAccessModule");
937
938 SceneHelpers sh = new SceneHelpers();
939 TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000);
940 TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1001, 1000);
941
942 SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
943 SceneHelpers.SetupSceneModules(
944 sceneA, config, new CapabilitiesModule(), etmA, attModA, new BasicInventoryAccessModule());
945 SceneHelpers.SetupSceneModules(
946 sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule());
947
948 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1);
949
950 AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID);
951 TestClient tc = new TestClient(acd, sceneA);
952 List<TestClient> destinationTestClients = new List<TestClient>();
953 EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients);
954
955 ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd);
956 beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32);
957
958 Assert.That(destinationTestClients.Count, Is.EqualTo(1));
959 Assert.That(destinationTestClients[0], Is.Not.Null);
960
961 InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20);
962
963 sceneA.AttachmentsModule.RezSingleAttachmentFromInventory(
964 beforeTeleportSp, attItem.ID, (uint)AttachmentPoint.Chest);
965
966 Vector3 teleportPosition = new Vector3(10, 11, 12);
967 Vector3 teleportLookAt = new Vector3(20, 21, 22);
968
969 // Here, we need to make clientA's receipt of SendRegionTeleport trigger clientB's CompleteMovement(). This
970 // is to operate the teleport V2 mechanism where the EntityTransferModule will first request the client to
971 // CompleteMovement to the region and then call UpdateAgent to the destination region to confirm the receipt
972 // Both these operations will occur on different threads and will wait for each other.
973 // We have to do this via ThreadPool directly since FireAndForget has been switched to sync for the V1
974 // test protocol, where we are trying to avoid unpredictable async operations in regression tests.
975 tc.OnTestClientSendRegionTeleport
976 += (regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL)
977 => ThreadPool.UnsafeQueueUserWorkItem(o => destinationTestClients[0].CompleteMovement(), null);
978
979 m_numberOfAttachEventsFired = 0;
980 sceneA.RequestTeleportLocation(
981 beforeTeleportSp.ControllingClient,
982 sceneB.RegionInfo.RegionHandle,
983 teleportPosition,
984 teleportLookAt,
985 (uint)TeleportFlags.ViaLocation);
627 986
628 // Check attachments have made it into sceneB 987 // Check attachments have made it into sceneB
629 ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID); 988 ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID);
@@ -642,6 +1001,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
642 SceneObjectGroup actualSceneBAtt = actualSceneBAttachments[0]; 1001 SceneObjectGroup actualSceneBAtt = actualSceneBAttachments[0];
643 Assert.That(actualSceneBAtt.Name, Is.EqualTo(attItem.Name)); 1002 Assert.That(actualSceneBAtt.Name, Is.EqualTo(attItem.Name));
644 Assert.That(actualSceneBAtt.AttachmentPoint, Is.EqualTo((uint)AttachmentPoint.Chest)); 1003 Assert.That(actualSceneBAtt.AttachmentPoint, Is.EqualTo((uint)AttachmentPoint.Chest));
1004 Assert.IsFalse(actualSceneBAtt.Backup);
645 1005
646 Assert.That(sceneB.GetSceneObjectGroups().Count, Is.EqualTo(1)); 1006 Assert.That(sceneB.GetSceneObjectGroups().Count, Is.EqualTo(1));
647 1007
@@ -663,4 +1023,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
663 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0)); 1023 Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
664 } 1024 }
665 } 1025 }
666} \ No newline at end of file 1026}
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
index 0a69979..cfb082b 100644
--- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
@@ -40,6 +40,7 @@ using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces; 40using OpenSim.Services.Interfaces;
41 41
42using Mono.Addins; 42using Mono.Addins;
43using PermissionMask = OpenSim.Framework.PermissionMask;
43 44
44namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory 45namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
45{ 46{
@@ -54,6 +55,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
54 55
55 private int m_savetime = 5; // seconds to wait before saving changed appearance 56 private int m_savetime = 5; // seconds to wait before saving changed appearance
56 private int m_sendtime = 2; // seconds to wait before sending changed appearance 57 private int m_sendtime = 2; // seconds to wait before sending changed appearance
58 private bool m_reusetextures = false;
57 59
58 private int m_checkTime = 500; // milliseconds to wait between checks for appearance updates 60 private int m_checkTime = 500; // milliseconds to wait between checks for appearance updates
59 private System.Timers.Timer m_updateTimer = new System.Timers.Timer(); 61 private System.Timers.Timer m_updateTimer = new System.Timers.Timer();
@@ -72,6 +74,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
72 { 74 {
73 m_savetime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSave",Convert.ToString(m_savetime))); 75 m_savetime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSave",Convert.ToString(m_savetime)));
74 m_sendtime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSend",Convert.ToString(m_sendtime))); 76 m_sendtime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSend",Convert.ToString(m_sendtime)));
77 m_reusetextures = appearanceConfig.GetBoolean("ReuseTextures",m_reusetextures);
78
75 // m_log.InfoFormat("[AVFACTORY] configured for {0} save and {1} send",m_savetime,m_sendtime); 79 // m_log.InfoFormat("[AVFACTORY] configured for {0} save and {1} send",m_savetime,m_sendtime);
76 } 80 }
77 81
@@ -130,6 +134,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
130 client.OnRequestWearables += Client_OnRequestWearables; 134 client.OnRequestWearables += Client_OnRequestWearables;
131 client.OnSetAppearance += Client_OnSetAppearance; 135 client.OnSetAppearance += Client_OnSetAppearance;
132 client.OnAvatarNowWearing += Client_OnAvatarNowWearing; 136 client.OnAvatarNowWearing += Client_OnAvatarNowWearing;
137 client.OnCachedTextureRequest += Client_OnCachedTextureRequest;
133 } 138 }
134 139
135 #endregion 140 #endregion
@@ -140,9 +145,24 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
140 /// <param name="sp"></param> 145 /// <param name="sp"></param>
141 /// <param name="texture"></param> 146 /// <param name="texture"></param>
142 /// <param name="visualParam"></param> 147 /// <param name="visualParam"></param>
143 public void SetAppearance(IScenePresence sp, AvatarAppearance appearance) 148 public void SetAppearance(IScenePresence sp, AvatarAppearance appearance, WearableCacheItem[] cacheItems)
144 { 149 {
145 SetAppearance(sp, appearance.Texture, appearance.VisualParams); 150 SetAppearance(sp, appearance.Texture, appearance.VisualParams, cacheItems);
151 }
152
153
154 public void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems)
155 {
156 float oldoff = sp.Appearance.AvatarFeetOffset;
157 Vector3 oldbox = sp.Appearance.AvatarBoxSize;
158
159 SetAppearance(sp, textureEntry, visualParams, cacheItems);
160 sp.Appearance.SetSize(avSize);
161
162 float off = sp.Appearance.AvatarFeetOffset;
163 Vector3 box = sp.Appearance.AvatarBoxSize;
164 if (oldoff != off || oldbox != box)
165 ((ScenePresence)sp).SetSize(box, off);
146 } 166 }
147 167
148 /// <summary> 168 /// <summary>
@@ -151,7 +171,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
151 /// <param name="sp"></param> 171 /// <param name="sp"></param>
152 /// <param name="texture"></param> 172 /// <param name="texture"></param>
153 /// <param name="visualParam"></param> 173 /// <param name="visualParam"></param>
154 public void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams) 174 public void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams, WearableCacheItem[] cacheItems)
155 { 175 {
156// m_log.DebugFormat( 176// m_log.DebugFormat(
157// "[AVFACTORY]: start SetAppearance for {0}, te {1}, visualParams {2}", 177// "[AVFACTORY]: start SetAppearance for {0}, te {1}, visualParams {2}",
@@ -174,18 +194,27 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
174 // m_log.DebugFormat( 194 // m_log.DebugFormat(
175 // "[AVFACTORY]: Setting visual params for {0} to {1}", 195 // "[AVFACTORY]: Setting visual params for {0} to {1}",
176 // client.Name, string.Join(", ", visualParamsStrings)); 196 // client.Name, string.Join(", ", visualParamsStrings));
177 197/*
178 float oldHeight = sp.Appearance.AvatarHeight; 198 float oldHeight = sp.Appearance.AvatarHeight;
179 changed = sp.Appearance.SetVisualParams(visualParams); 199 changed = sp.Appearance.SetVisualParams(visualParams);
180 200
181 if (sp.Appearance.AvatarHeight != oldHeight && sp.Appearance.AvatarHeight > 0) 201 if (sp.Appearance.AvatarHeight != oldHeight && sp.Appearance.AvatarHeight > 0)
182 ((ScenePresence)sp).SetHeight(sp.Appearance.AvatarHeight); 202 ((ScenePresence)sp).SetHeight(sp.Appearance.AvatarHeight);
183 } 203 */
204// float oldoff = sp.Appearance.AvatarFeetOffset;
205// Vector3 oldbox = sp.Appearance.AvatarBoxSize;
206 changed = sp.Appearance.SetVisualParams(visualParams);
207// float off = sp.Appearance.AvatarFeetOffset;
208// Vector3 box = sp.Appearance.AvatarBoxSize;
209// if(oldoff != off || oldbox != box)
210// ((ScenePresence)sp).SetSize(box,off);
184 211
212 }
213
185 // Process the baked texture array 214 // Process the baked texture array
186 if (textureEntry != null) 215 if (textureEntry != null)
187 { 216 {
188// m_log.DebugFormat("[AVFACTORY]: Received texture update for {0} {1}", sp.Name, sp.UUID); 217 m_log.DebugFormat("[AVFACTORY]: Received texture update for {0} {1}", sp.Name, sp.UUID);
189 218
190// WriteBakedTexturesReport(sp, m_log.DebugFormat); 219// WriteBakedTexturesReport(sp, m_log.DebugFormat);
191 220
@@ -222,7 +251,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
222 private void SendAppearance(ScenePresence sp) 251 private void SendAppearance(ScenePresence sp)
223 { 252 {
224 // Send the appearance to everyone in the scene 253 // Send the appearance to everyone in the scene
225 sp.SendAppearanceToAllOtherAgents(); 254 sp.SendAppearanceToAllOtherClients();
226 255
227 // Send animations back to the avatar as well 256 // Send animations back to the avatar as well
228 sp.Animator.SendAnimPack(); 257 sp.Animator.SendAnimPack();
@@ -254,6 +283,17 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
254 return GetBakedTextureFaces(sp); 283 return GetBakedTextureFaces(sp);
255 } 284 }
256 285
286 public WearableCacheItem[] GetCachedItems(UUID agentId)
287 {
288 ScenePresence sp = m_scene.GetScenePresence(agentId);
289 WearableCacheItem[] items = sp.Appearance.WearableCacheItems;
290 //foreach (WearableCacheItem item in items)
291 //{
292
293 //}
294 return items;
295 }
296
257 public bool SaveBakedTextures(UUID agentId) 297 public bool SaveBakedTextures(UUID agentId)
258 { 298 {
259 ScenePresence sp = m_scene.GetScenePresence(agentId); 299 ScenePresence sp = m_scene.GetScenePresence(agentId);
@@ -287,6 +327,9 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
287 327
288 if (asset != null) 328 if (asset != null)
289 { 329 {
330 // Replace an HG ID with the simple asset ID so that we can persist textures for foreign HG avatars
331 asset.ID = asset.FullID.ToString();
332
290 asset.Temporary = false; 333 asset.Temporary = false;
291 asset.Local = false; 334 asset.Local = false;
292 m_scene.AssetService.Store(asset); 335 m_scene.AssetService.Store(asset);
@@ -323,7 +366,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
323 366
324 public void QueueAppearanceSave(UUID agentid) 367 public void QueueAppearanceSave(UUID agentid)
325 { 368 {
326 // m_log.WarnFormat("[AVFACTORY]: Queue appearance save for {0}", agentid); 369// m_log.DebugFormat("[AVFACTORY]: Queueing appearance save for {0}", agentid);
327 370
328 // 10000 ticks per millisecond, 1000 milliseconds per second 371 // 10000 ticks per millisecond, 1000 milliseconds per second
329 long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000); 372 long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000);
@@ -337,6 +380,53 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
337 public bool ValidateBakedTextureCache(IScenePresence sp) 380 public bool ValidateBakedTextureCache(IScenePresence sp)
338 { 381 {
339 bool defonly = true; // are we only using default textures 382 bool defonly = true; // are we only using default textures
383 IImprovedAssetCache cache = m_scene.RequestModuleInterface<IImprovedAssetCache>();
384 IBakedTextureModule bakedModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
385 WearableCacheItem[] wearableCache = null;
386
387 // Cache wearable data for teleport.
388 // Only makes sense if there's a bake module and a cache module
389 if (bakedModule != null && cache != null)
390 {
391 try
392 {
393 wearableCache = bakedModule.Get(sp.UUID);
394 }
395 catch (Exception)
396 {
397
398 }
399 if (wearableCache != null)
400 {
401 for (int i = 0; i < wearableCache.Length; i++)
402 {
403 cache.Cache(wearableCache[i].TextureAsset);
404 }
405 }
406 }
407 /*
408 IBakedTextureModule bakedModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
409 if (invService.GetRootFolder(userID) != null)
410 {
411 WearableCacheItem[] wearableCache = null;
412 if (bakedModule != null)
413 {
414 try
415 {
416 wearableCache = bakedModule.Get(userID);
417 appearance.WearableCacheItems = wearableCache;
418 appearance.WearableCacheItemsDirty = false;
419 foreach (WearableCacheItem item in wearableCache)
420 {
421 appearance.Texture.FaceTextures[item.TextureIndex].TextureID = item.TextureID;
422 }
423 }
424 catch (Exception)
425 {
426
427 }
428 }
429 */
340 430
341 // Process the texture entry 431 // Process the texture entry
342 for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) 432 for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++)
@@ -344,10 +434,32 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
344 int idx = AvatarAppearance.BAKE_INDICES[i]; 434 int idx = AvatarAppearance.BAKE_INDICES[i];
345 Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx]; 435 Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx];
346 436
347 // if there is no texture entry, skip it 437 // No face, so lets check our baked service cache, teleport or login.
348 if (face == null) 438 if (face == null)
349 continue; 439 {
350 440 if (wearableCache != null)
441 {
442 // If we find the an appearance item, set it as the textureentry and the face
443 WearableCacheItem searchitem = WearableCacheItem.SearchTextureIndex((uint) idx, wearableCache);
444 if (searchitem != null)
445 {
446 sp.Appearance.Texture.FaceTextures[idx] = sp.Appearance.Texture.CreateFace((uint) idx);
447 sp.Appearance.Texture.FaceTextures[idx].TextureID = searchitem.TextureID;
448 face = sp.Appearance.Texture.FaceTextures[idx];
449 }
450 else
451 {
452 // if there is no texture entry and no baked cache, skip it
453 continue;
454 }
455 }
456 else
457 {
458 //No texture entry face and no cache. Skip this face.
459 continue;
460 }
461 }
462
351// m_log.DebugFormat( 463// m_log.DebugFormat(
352// "[AVFACTORY]: Looking for texture {0}, id {1} for {2} {3}", 464// "[AVFACTORY]: Looking for texture {0}, id {1} for {2} {3}",
353// face.TextureID, idx, client.Name, client.AgentId); 465// face.TextureID, idx, client.Name, client.AgentId);
@@ -374,6 +486,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
374 public int RequestRebake(IScenePresence sp, bool missingTexturesOnly) 486 public int RequestRebake(IScenePresence sp, bool missingTexturesOnly)
375 { 487 {
376 int texturesRebaked = 0; 488 int texturesRebaked = 0;
489// IImprovedAssetCache cache = m_scene.RequestModuleInterface<IImprovedAssetCache>();
377 490
378 for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) 491 for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++)
379 { 492 {
@@ -480,7 +593,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
480 593
481 if (sendTime < now) 594 if (sendTime < now)
482 { 595 {
483 Util.FireAndForget(o => SendAppearance(avatarID)); 596 Util.FireAndForget(o => SendAppearance(avatarID), null, "AvatarFactoryModule.SendAppearance");
484 m_sendqueue.Remove(avatarID); 597 m_sendqueue.Remove(avatarID);
485 } 598 }
486 } 599 }
@@ -498,7 +611,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
498 611
499 if (sendTime < now) 612 if (sendTime < now)
500 { 613 {
501 Util.FireAndForget(o => SaveAppearance(avatarID)); 614 Util.FireAndForget(o => SaveAppearance(avatarID), null, "AvatarFactoryModule.SaveAppearance");
502 m_savequeue.Remove(avatarID); 615 m_savequeue.Remove(avatarID);
503 } 616 }
504 } 617 }
@@ -526,7 +639,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
526 return; 639 return;
527 } 640 }
528 641
529 // m_log.WarnFormat("[AVFACTORY] avatar {0} save appearance",agentid); 642// m_log.DebugFormat("[AVFACTORY]: Saving appearance for avatar {0}", agentid);
530 643
531 // This could take awhile since it needs to pull inventory 644 // This could take awhile since it needs to pull inventory
532 // We need to do it at the point of save so that there is a sufficient delay for any upload of new body part/shape 645 // We need to do it at the point of save so that there is a sufficient delay for any upload of new body part/shape
@@ -535,6 +648,14 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
535 // multiple save requests. 648 // multiple save requests.
536 SetAppearanceAssets(sp.UUID, sp.Appearance); 649 SetAppearanceAssets(sp.UUID, sp.Appearance);
537 650
651// List<AvatarAttachment> attachments = sp.Appearance.GetAttachments();
652// foreach (AvatarAttachment att in attachments)
653// {
654// m_log.DebugFormat(
655// "[AVFACTORY]: For {0} saving attachment {1} at point {2}",
656// sp.Name, att.ItemID, att.AttachPoint);
657// }
658
538 m_scene.AvatarService.SetAppearance(agentid, sp.Appearance); 659 m_scene.AvatarService.SetAppearance(agentid, sp.Appearance);
539 660
540 // Trigger this here because it's the final step in the set/queue/save process for appearance setting. 661 // Trigger this here because it's the final step in the set/queue/save process for appearance setting.
@@ -542,6 +663,12 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
542 m_scene.EventManager.TriggerAvatarAppearanceChanged(sp); 663 m_scene.EventManager.TriggerAvatarAppearanceChanged(sp);
543 } 664 }
544 665
666 /// <summary>
667 /// For a given set of appearance items, check whether the items are valid and add their asset IDs to
668 /// appearance data.
669 /// </summary>
670 /// <param name='userID'></param>
671 /// <param name='appearance'></param>
545 private void SetAppearanceAssets(UUID userID, AvatarAppearance appearance) 672 private void SetAppearanceAssets(UUID userID, AvatarAppearance appearance)
546 { 673 {
547 IInventoryService invService = m_scene.InventoryService; 674 IInventoryService invService = m_scene.InventoryService;
@@ -553,7 +680,13 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
553 for (int j = 0; j < appearance.Wearables[i].Count; j++) 680 for (int j = 0; j < appearance.Wearables[i].Count; j++)
554 { 681 {
555 if (appearance.Wearables[i][j].ItemID == UUID.Zero) 682 if (appearance.Wearables[i][j].ItemID == UUID.Zero)
683 {
684 m_log.WarnFormat(
685 "[AVFACTORY]: Wearable item {0}:{1} for user {2} unexpectedly UUID.Zero. Ignoring.",
686 i, j, userID);
687
556 continue; 688 continue;
689 }
557 690
558 // Ignore ruth's assets 691 // Ignore ruth's assets
559 if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID) 692 if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID)
@@ -568,7 +701,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
568 } 701 }
569 else 702 else
570 { 703 {
571 m_log.ErrorFormat( 704 m_log.WarnFormat(
572 "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default", 705 "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default",
573 appearance.Wearables[i][j].ItemID, (WearableType)i); 706 appearance.Wearables[i][j].ItemID, (WearableType)i);
574 707
@@ -581,8 +714,311 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
581 { 714 {
582 m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID); 715 m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID);
583 } 716 }
717
718// IInventoryService invService = m_scene.InventoryService;
719// bool resetwearable = false;
720// if (invService.GetRootFolder(userID) != null)
721// {
722// for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++)
723// {
724// for (int j = 0; j < appearance.Wearables[i].Count; j++)
725// {
726// // Check if the default wearables are not set
727// if (appearance.Wearables[i][j].ItemID == UUID.Zero)
728// {
729// switch ((WearableType) i)
730// {
731// case WearableType.Eyes:
732// case WearableType.Hair:
733// case WearableType.Shape:
734// case WearableType.Skin:
735// //case WearableType.Underpants:
736// TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance);
737// resetwearable = true;
738// m_log.Warn("[AVFACTORY]: UUID.Zero Wearables, passing fake values.");
739// resetwearable = true;
740// break;
741//
742// }
743// continue;
744// }
745//
746// // Ignore ruth's assets except for the body parts! missing body parts fail avatar appearance on V1
747// if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID)
748// {
749// switch ((WearableType)i)
750// {
751// case WearableType.Eyes:
752// case WearableType.Hair:
753// case WearableType.Shape:
754// case WearableType.Skin:
755// //case WearableType.Underpants:
756// TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance);
757//
758// m_log.WarnFormat("[AVFACTORY]: {0} Default Wearables, passing existing values.", (WearableType)i);
759// resetwearable = true;
760// break;
761//
762// }
763// continue;
764// }
765//
766// InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i][j].ItemID, userID);
767// baseItem = invService.GetItem(baseItem);
768//
769// if (baseItem != null)
770// {
771// appearance.Wearables[i].Add(appearance.Wearables[i][j].ItemID, baseItem.AssetID);
772// int unmodifiedWearableIndexForClosure = i;
773// m_scene.AssetService.Get(baseItem.AssetID.ToString(), this,
774// delegate(string x, object y, AssetBase z)
775// {
776// if (z == null)
777// {
778// TryAndRepairBrokenWearable(
779// (WearableType)unmodifiedWearableIndexForClosure, invService,
780// userID, appearance);
781// }
782// });
783// }
784// else
785// {
786// m_log.ErrorFormat(
787// "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default",
788// appearance.Wearables[i][j].ItemID, (WearableType)i);
789//
790// TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance);
791// resetwearable = true;
792//
793// }
794// }
795// }
796//
797// // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason....
798// if (appearance.Wearables[(int) WearableType.Eyes] == null)
799// {
800// m_log.WarnFormat("[AVFACTORY]: {0} Eyes are Null, passing existing values.", (WearableType.Eyes));
801//
802// TryAndRepairBrokenWearable(WearableType.Eyes, invService, userID, appearance);
803// resetwearable = true;
804// }
805// else
806// {
807// if (appearance.Wearables[(int) WearableType.Eyes][0].ItemID == UUID.Zero)
808// {
809// m_log.WarnFormat("[AVFACTORY]: Eyes are UUID.Zero are broken, {0} {1}",
810// appearance.Wearables[(int) WearableType.Eyes][0].ItemID,
811// appearance.Wearables[(int) WearableType.Eyes][0].AssetID);
812// TryAndRepairBrokenWearable(WearableType.Eyes, invService, userID, appearance);
813// resetwearable = true;
814//
815// }
816//
817// }
818// // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason....
819// if (appearance.Wearables[(int)WearableType.Shape] == null)
820// {
821// m_log.WarnFormat("[AVFACTORY]: {0} shape is Null, passing existing values.", (WearableType.Shape));
822//
823// TryAndRepairBrokenWearable(WearableType.Shape, invService, userID, appearance);
824// resetwearable = true;
825// }
826// else
827// {
828// if (appearance.Wearables[(int)WearableType.Shape][0].ItemID == UUID.Zero)
829// {
830// m_log.WarnFormat("[AVFACTORY]: Shape is UUID.Zero and broken, {0} {1}",
831// appearance.Wearables[(int)WearableType.Shape][0].ItemID,
832// appearance.Wearables[(int)WearableType.Shape][0].AssetID);
833// TryAndRepairBrokenWearable(WearableType.Shape, invService, userID, appearance);
834// resetwearable = true;
835//
836// }
837//
838// }
839// // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason....
840// if (appearance.Wearables[(int)WearableType.Hair] == null)
841// {
842// m_log.WarnFormat("[AVFACTORY]: {0} Hair is Null, passing existing values.", (WearableType.Hair));
843//
844// TryAndRepairBrokenWearable(WearableType.Hair, invService, userID, appearance);
845// resetwearable = true;
846// }
847// else
848// {
849// if (appearance.Wearables[(int)WearableType.Hair][0].ItemID == UUID.Zero)
850// {
851// m_log.WarnFormat("[AVFACTORY]: Hair is UUID.Zero and broken, {0} {1}",
852// appearance.Wearables[(int)WearableType.Hair][0].ItemID,
853// appearance.Wearables[(int)WearableType.Hair][0].AssetID);
854// TryAndRepairBrokenWearable(WearableType.Hair, invService, userID, appearance);
855// resetwearable = true;
856//
857// }
858//
859// }
860// // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason....
861// if (appearance.Wearables[(int)WearableType.Skin] == null)
862// {
863// m_log.WarnFormat("[AVFACTORY]: {0} Skin is Null, passing existing values.", (WearableType.Skin));
864//
865// TryAndRepairBrokenWearable(WearableType.Skin, invService, userID, appearance);
866// resetwearable = true;
867// }
868// else
869// {
870// if (appearance.Wearables[(int)WearableType.Skin][0].ItemID == UUID.Zero)
871// {
872// m_log.WarnFormat("[AVFACTORY]: Skin is UUID.Zero and broken, {0} {1}",
873// appearance.Wearables[(int)WearableType.Skin][0].ItemID,
874// appearance.Wearables[(int)WearableType.Skin][0].AssetID);
875// TryAndRepairBrokenWearable(WearableType.Skin, invService, userID, appearance);
876// resetwearable = true;
877//
878// }
879//
880// }
881// if (resetwearable)
882// {
883// ScenePresence presence = null;
884// if (m_scene.TryGetScenePresence(userID, out presence))
885// {
886// presence.ControllingClient.SendWearables(presence.Appearance.Wearables,
887// presence.Appearance.Serial++);
888// }
889// }
890//
891// }
892// else
893// {
894// m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID);
895// }
896 }
897
898 private void TryAndRepairBrokenWearable(WearableType type, IInventoryService invService, UUID userID,AvatarAppearance appearance)
899 {
900 UUID defaultwearable = GetDefaultItem(type);
901 if (defaultwearable != UUID.Zero)
902 {
903 UUID newInvItem = UUID.Random();
904 InventoryItemBase itembase = new InventoryItemBase(newInvItem, userID)
905 {
906 AssetID =
907 defaultwearable,
908 AssetType
909 =
910 (int)
911 FolderType
912 .BodyPart,
913 CreatorId
914 =
915 userID
916 .ToString
917 (),
918 //InvType = (int)InventoryType.Wearable,
919
920 Description
921 =
922 "Failed Wearable Replacement",
923 Folder =
924 invService
925 .GetFolderForType
926 (userID,
927 FolderType
928 .BodyPart)
929 .ID,
930 Flags = (uint) type,
931 Name = Enum.GetName(typeof (WearableType), type),
932 BasePermissions = (uint) PermissionMask.Copy,
933 CurrentPermissions = (uint) PermissionMask.Copy,
934 EveryOnePermissions = (uint) PermissionMask.Copy,
935 GroupPermissions = (uint) PermissionMask.Copy,
936 NextPermissions = (uint) PermissionMask.Copy
937 };
938 invService.AddItem(itembase);
939 UUID LinkInvItem = UUID.Random();
940 itembase = new InventoryItemBase(LinkInvItem, userID)
941 {
942 AssetID =
943 newInvItem,
944 AssetType
945 =
946 (int)
947 AssetType
948 .Link,
949 CreatorId
950 =
951 userID
952 .ToString
953 (),
954 InvType = (int) InventoryType.Wearable,
955
956 Description
957 =
958 "Failed Wearable Replacement",
959 Folder =
960 invService
961 .GetFolderForType
962 (userID,
963 FolderType
964 .CurrentOutfit)
965 .ID,
966 Flags = (uint) type,
967 Name = Enum.GetName(typeof (WearableType), type),
968 BasePermissions = (uint) PermissionMask.Copy,
969 CurrentPermissions = (uint) PermissionMask.Copy,
970 EveryOnePermissions = (uint) PermissionMask.Copy,
971 GroupPermissions = (uint) PermissionMask.Copy,
972 NextPermissions = (uint) PermissionMask.Copy
973 };
974 invService.AddItem(itembase);
975 appearance.Wearables[(int)type] = new AvatarWearable(newInvItem, GetDefaultItem(type));
976 ScenePresence presence = null;
977 if (m_scene.TryGetScenePresence(userID, out presence))
978 {
979 m_scene.SendInventoryUpdate(presence.ControllingClient,
980 invService.GetFolderForType(userID,
981 FolderType
982 .CurrentOutfit),
983 false, true);
984 }
985 }
584 } 986 }
585 987
988 private UUID GetDefaultItem(WearableType wearable)
989 {
990 // These are ruth
991 UUID ret = UUID.Zero;
992 switch (wearable)
993 {
994 case WearableType.Eyes:
995 ret = new UUID("4bb6fa4d-1cd2-498a-a84c-95c1a0e745a7");
996 break;
997 case WearableType.Hair:
998 ret = new UUID("d342e6c0-b9d2-11dc-95ff-0800200c9a66");
999 break;
1000 case WearableType.Pants:
1001 ret = new UUID("00000000-38f9-1111-024e-222222111120");
1002 break;
1003 case WearableType.Shape:
1004 ret = new UUID("66c41e39-38f9-f75a-024e-585989bfab73");
1005 break;
1006 case WearableType.Shirt:
1007 ret = new UUID("00000000-38f9-1111-024e-222222111110");
1008 break;
1009 case WearableType.Skin:
1010 ret = new UUID("77c41e39-38f9-f75a-024e-585989bbabbb");
1011 break;
1012 case WearableType.Undershirt:
1013 ret = new UUID("16499ebb-3208-ec27-2def-481881728f47");
1014 break;
1015 case WearableType.Underpants:
1016 ret = new UUID("4ac2e9c7-3671-d229-316a-67717730841d");
1017 break;
1018 }
1019
1020 return ret;
1021 }
586 #endregion 1022 #endregion
587 1023
588 #region Client Event Handlers 1024 #region Client Event Handlers
@@ -592,12 +1028,17 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
592 /// <param name="client"></param> 1028 /// <param name="client"></param>
593 private void Client_OnRequestWearables(IClientAPI client) 1029 private void Client_OnRequestWearables(IClientAPI client)
594 { 1030 {
595 // m_log.DebugFormat("[AVFACTORY]: Client_OnRequestWearables called for {0} ({1})", client.Name, client.AgentId); 1031 Util.FireAndForget(delegate(object x)
596 ScenePresence sp = m_scene.GetScenePresence(client.AgentId); 1032 {
597 if (sp != null) 1033 Thread.Sleep(4000);
598 client.SendWearables(sp.Appearance.Wearables, sp.Appearance.Serial++); 1034
599 else 1035 // m_log.DebugFormat("[AVFACTORY]: Client_OnRequestWearables called for {0} ({1})", client.Name, client.AgentId);
600 m_log.WarnFormat("[AVFACTORY]: Client_OnRequestWearables unable to find presence for {0}", client.AgentId); 1036 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
1037 if (sp != null)
1038 client.SendWearables(sp.Appearance.Wearables, sp.Appearance.Serial++);
1039 else
1040 m_log.WarnFormat("[AVFACTORY]: Client_OnRequestWearables unable to find presence for {0}", client.AgentId);
1041 }, null, "AvatarFactoryModule.OnClientRequestWearables");
601 } 1042 }
602 1043
603 /// <summary> 1044 /// <summary>
@@ -606,12 +1047,12 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
606 /// <param name="client"></param> 1047 /// <param name="client"></param>
607 /// <param name="texture"></param> 1048 /// <param name="texture"></param>
608 /// <param name="visualParam"></param> 1049 /// <param name="visualParam"></param>
609 private void Client_OnSetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams) 1050 private void Client_OnSetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems)
610 { 1051 {
611 // m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance called for {0} ({1})", client.Name, client.AgentId); 1052 // m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance called for {0} ({1})", client.Name, client.AgentId);
612 ScenePresence sp = m_scene.GetScenePresence(client.AgentId); 1053 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
613 if (sp != null) 1054 if (sp != null)
614 SetAppearance(sp, textureEntry, visualParams); 1055 SetAppearance(sp, textureEntry, visualParams,avSize, cacheItems);
615 else 1056 else
616 m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance unable to find presence for {0}", client.AgentId); 1057 m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance unable to find presence for {0}", client.AgentId);
617 } 1058 }
@@ -659,6 +1100,61 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
659 QueueAppearanceSave(client.AgentId); 1100 QueueAppearanceSave(client.AgentId);
660 } 1101 }
661 } 1102 }
1103
1104 /// <summary>
1105 /// Respond to the cached textures request from the client
1106 /// </summary>
1107 /// <param name="client"></param>
1108 /// <param name="serial"></param>
1109 /// <param name="cachedTextureRequest"></param>
1110 private void Client_OnCachedTextureRequest(IClientAPI client, int serial, List<CachedTextureRequestArg> cachedTextureRequest)
1111 {
1112 // m_log.WarnFormat("[AVFACTORY]: Client_OnCachedTextureRequest called for {0} ({1})", client.Name, client.AgentId);
1113 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
1114
1115 List<CachedTextureResponseArg> cachedTextureResponse = new List<CachedTextureResponseArg>();
1116 foreach (CachedTextureRequestArg request in cachedTextureRequest)
1117 {
1118 UUID texture = UUID.Zero;
1119 int index = request.BakedTextureIndex;
1120
1121 if (m_reusetextures)
1122 {
1123 // this is the most insanely dumb way to do this... however it seems to
1124 // actually work. if the appearance has been reset because wearables have
1125 // changed then the texture entries are zero'd out until the bakes are
1126 // uploaded. on login, if the textures exist in the cache (eg if you logged
1127 // into the simulator recently, then the appearance will pull those and send
1128 // them back in the packet and you won't have to rebake. if the textures aren't
1129 // in the cache then the intial makeroot() call in scenepresence will zero
1130 // them out.
1131 //
1132 // a better solution (though how much better is an open question) is to
1133 // store the hashes in the appearance and compare them. Thats's coming.
1134
1135 Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[index];
1136 if (face != null)
1137 texture = face.TextureID;
1138
1139 // m_log.WarnFormat("[AVFACTORY]: reuse texture {0} for index {1}",texture,index);
1140 }
1141
1142 CachedTextureResponseArg response = new CachedTextureResponseArg();
1143 response.BakedTextureIndex = index;
1144 response.BakedTextureID = texture;
1145 response.HostName = null;
1146
1147 cachedTextureResponse.Add(response);
1148 }
1149
1150 // m_log.WarnFormat("[AVFACTORY]: serial is {0}",serial);
1151 // The serial number appears to be used to match requests and responses
1152 // in the texture transaction. We just send back the serial number
1153 // that was provided in the request. The viewer bumps this for us.
1154 client.SendCachedTextureResponse(sp, serial, cachedTextureResponse);
1155 }
1156
1157
662 #endregion 1158 #endregion
663 1159
664 public void WriteBakedTexturesReport(IScenePresence sp, ReportOutputAction outputAction) 1160 public void WriteBakedTexturesReport(IScenePresence sp, ReportOutputAction outputAction)
@@ -690,7 +1186,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
690 } 1186 }
691 1187
692 bool bakedTextureValid = m_scene.AvatarFactory.ValidateBakedTextureCache(sp); 1188 bool bakedTextureValid = m_scene.AvatarFactory.ValidateBakedTextureCache(sp);
693 outputAction("{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "corrupt"); 1189 outputAction("{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "incomplete");
694 } 1190 }
695 } 1191 }
696} 1192}
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs
index 1830d41..9513408 100644
--- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs
@@ -34,7 +34,6 @@ using OpenSim.Framework;
34using OpenSim.Region.CoreModules.Asset; 34using OpenSim.Region.CoreModules.Asset;
35using OpenSim.Region.Framework.Scenes; 35using OpenSim.Region.Framework.Scenes;
36using OpenSim.Tests.Common; 36using OpenSim.Tests.Common;
37using OpenSim.Tests.Common.Mock;
38 37
39namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory 38namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
40{ 39{
@@ -48,23 +47,103 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
48 public void TestSetAppearance() 47 public void TestSetAppearance()
49 { 48 {
50 TestHelpers.InMethod(); 49 TestHelpers.InMethod();
51// log4net.Config.XmlConfigurator.Configure(); 50// TestHelpers.EnableLogging();
52 51
53 UUID userId = TestHelpers.ParseTail(0x1); 52 UUID userId = TestHelpers.ParseTail(0x1);
53 UUID bakedTextureID = TestHelpers.ParseTail(0x2);
54 54
55 // We need an asset cache because otherwise the LocalAssetServiceConnector will short-circuit directly
56 // to the AssetService, which will then store temporary and local assets permanently
57 CoreAssetCache assetCache = new CoreAssetCache();
58
55 AvatarFactoryModule afm = new AvatarFactoryModule(); 59 AvatarFactoryModule afm = new AvatarFactoryModule();
56 TestScene scene = new SceneHelpers().SetupScene(); 60 TestScene scene = new SceneHelpers(assetCache).SetupScene();
57 SceneHelpers.SetupSceneModules(scene, afm); 61 SceneHelpers.SetupSceneModules(scene, afm);
58 ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId); 62 ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId);
59 63
64 // TODO: Use the actual BunchOfCaps functionality once we slot in the CapabilitiesModules
65 AssetBase bakedTextureAsset;
66 bakedTextureAsset
67 = new AssetBase(
68 bakedTextureID, "Test Baked Texture", (sbyte)AssetType.Texture, userId.ToString());
69 bakedTextureAsset.Data = new byte[] { 2 }; // Not necessary to have a genuine JPEG2000 asset here yet
70 bakedTextureAsset.Temporary = true;
71 bakedTextureAsset.Local = true;
72 scene.AssetService.Store(bakedTextureAsset);
73
60 byte[] visualParams = new byte[AvatarAppearance.VISUALPARAM_COUNT]; 74 byte[] visualParams = new byte[AvatarAppearance.VISUALPARAM_COUNT];
61 for (byte i = 0; i < visualParams.Length; i++) 75 for (byte i = 0; i < visualParams.Length; i++)
62 visualParams[i] = i; 76 visualParams[i] = i;
63 77
64 afm.SetAppearance(sp, new Primitive.TextureEntry(TestHelpers.ParseTail(0x10)), visualParams); 78 Primitive.TextureEntry bakedTextureEntry = new Primitive.TextureEntry(TestHelpers.ParseTail(0x10));
79 uint eyesFaceIndex = (uint)AppearanceManager.BakeTypeToAgentTextureIndex(BakeType.Eyes);
80 Primitive.TextureEntryFace eyesFace = bakedTextureEntry.CreateFace(eyesFaceIndex);
81
82 int rebakeRequestsReceived = 0;
83 ((TestClient)sp.ControllingClient).OnReceivedSendRebakeAvatarTextures += id => rebakeRequestsReceived++;
84
85 // This is the alpha texture
86 eyesFace.TextureID = bakedTextureID;
87 afm.SetAppearance(sp, bakedTextureEntry, visualParams, null);
88
89 Assert.That(rebakeRequestsReceived, Is.EqualTo(0));
90
91 AssetBase eyesBake = scene.AssetService.Get(bakedTextureID.ToString());
92 Assert.That(eyesBake, Is.Not.Null);
93 Assert.That(eyesBake.Temporary, Is.True);
94 Assert.That(eyesBake.Local, Is.True);
95 }
96
97 /// <summary>
98 /// Test appearance setting where the baked texture UUID are library alpha textures.
99 /// </summary>
100 /// <remarks>
101 /// For a mesh avatar, it appears these 'baked textures' are used. So these should not trigger a request to
102 /// rebake.
103 /// </remarks>
104 [Test]
105 public void TestSetAppearanceAlphaBakedTextures()
106 {
107 TestHelpers.InMethod();
108// TestHelpers.EnableLogging();
109
110 UUID userId = TestHelpers.ParseTail(0x1);
111 UUID alphaTextureID = new UUID("3a367d1c-bef1-6d43-7595-e88c1e3aadb3");
112
113 // We need an asset cache because otherwise the LocalAssetServiceConnector will short-circuit directly
114 // to the AssetService, which will then store temporary and local assets permanently
115 CoreAssetCache assetCache = new CoreAssetCache();
116
117 AvatarFactoryModule afm = new AvatarFactoryModule();
118 TestScene scene = new SceneHelpers(assetCache).SetupScene();
119 SceneHelpers.SetupSceneModules(scene, afm);
120 ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId);
121
122 AssetBase libraryAsset;
123 libraryAsset
124 = new AssetBase(
125 alphaTextureID, "Default Alpha Layer Texture", (sbyte)AssetType.Texture, userId.ToString());
126 libraryAsset.Data = new byte[] { 2 }; // Not necessary to have a genuine JPEG2000 asset here yet
127 libraryAsset.Temporary = false;
128 libraryAsset.Local = false;
129 scene.AssetService.Store(libraryAsset);
130
131 byte[] visualParams = new byte[AvatarAppearance.VISUALPARAM_COUNT];
132 for (byte i = 0; i < visualParams.Length; i++)
133 visualParams[i] = i;
134
135 Primitive.TextureEntry bakedTextureEntry = new Primitive.TextureEntry(TestHelpers.ParseTail(0x10));
136 uint eyesFaceIndex = (uint)AppearanceManager.BakeTypeToAgentTextureIndex(BakeType.Eyes);
137 Primitive.TextureEntryFace eyesFace = bakedTextureEntry.CreateFace(eyesFaceIndex);
138
139 int rebakeRequestsReceived = 0;
140 ((TestClient)sp.ControllingClient).OnReceivedSendRebakeAvatarTextures += id => rebakeRequestsReceived++;
65 141
66 // TODO: Check baked texture 142 // This is the alpha texture
67 Assert.AreEqual(visualParams, sp.Appearance.VisualParams); 143 eyesFace.TextureID = alphaTextureID;
144 afm.SetAppearance(sp, bakedTextureEntry, visualParams, null);
145
146 Assert.That(rebakeRequestsReceived, Is.EqualTo(0));
68 } 147 }
69 148
70 [Test] 149 [Test]
@@ -102,7 +181,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
102 Primitive.TextureEntryFace eyesFace = bakedTextureEntry.CreateFace(eyesFaceIndex); 181 Primitive.TextureEntryFace eyesFace = bakedTextureEntry.CreateFace(eyesFaceIndex);
103 eyesFace.TextureID = eyesTextureId; 182 eyesFace.TextureID = eyesTextureId;
104 183
105 afm.SetAppearance(sp, bakedTextureEntry, visualParams); 184 afm.SetAppearance(sp, bakedTextureEntry, visualParams, null);
106 afm.SaveBakedTextures(userId); 185 afm.SaveBakedTextures(userId);
107// Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures = afm.GetBakedTextureFaces(userId); 186// Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures = afm.GetBakedTextureFaces(userId);
108 187
diff --git a/OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs b/OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs
new file mode 100644
index 0000000..414f06a
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs
@@ -0,0 +1,200 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenMetaverse;
29using Nini.Config;
30using System;
31using System.IO;
32using System.Text;
33using System.Xml;
34using System.Xml.Serialization;
35using System.Collections;
36using System.Collections.Generic;
37using System.Reflection;
38using log4net;
39using OpenSim.Framework;
40using OpenSim.Framework.ServiceAuth;
41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Services.Interfaces;
44using Mono.Addins;
45
46namespace OpenSim.Region.CoreModules.Avatar.BakedTextures
47{
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XBakes.Module")]
49 public class XBakesModule : INonSharedRegionModule, IBakedTextureModule
50 {
51 protected Scene m_Scene;
52 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53 private UTF8Encoding enc = new UTF8Encoding();
54 private string m_URL = String.Empty;
55 private static XmlSerializer m_serializer = new XmlSerializer(typeof(AssetBase));
56
57 private static IServiceAuth m_Auth;
58
59 public void Initialise(IConfigSource configSource)
60 {
61 IConfig config = configSource.Configs["XBakes"];
62 if (config == null)
63 return;
64
65 m_URL = config.GetString("URL", String.Empty);
66 m_Auth = ServiceAuth.Create(configSource, "XBakes");
67 }
68
69 public void AddRegion(Scene scene)
70 {
71 // m_log.InfoFormat("[XBakes]: Enabled for region {0}", scene.RegionInfo.RegionName);
72 m_Scene = scene;
73
74 scene.RegisterModuleInterface<IBakedTextureModule>(this);
75 }
76
77 public void RegionLoaded(Scene scene)
78 {
79 }
80
81 public void RemoveRegion(Scene scene)
82 {
83 }
84
85 public void Close()
86 {
87 }
88
89 public string Name
90 {
91 get { return "XBakes.Module"; }
92 }
93
94 public Type ReplaceableInterface
95 {
96 get { return null; }
97 }
98
99 public WearableCacheItem[] Get(UUID id)
100 {
101 if (m_URL == String.Empty)
102 return null;
103
104 int size = 0;
105
106 using (RestClient rc = new RestClient(m_URL))
107 {
108 List<WearableCacheItem> ret = new List<WearableCacheItem>();
109 rc.AddResourcePath("bakes");
110 rc.AddResourcePath(id.ToString());
111
112 rc.RequestMethod = "GET";
113
114 try
115 {
116 Stream s = rc.Request(m_Auth);
117
118 using (XmlTextReader sr = new XmlTextReader(s))
119 {
120 sr.ReadStartElement("BakedAppearance");
121 while (sr.LocalName == "BakedTexture")
122 {
123 string sTextureIndex = sr.GetAttribute("TextureIndex");
124 int lTextureIndex = Convert.ToInt32(sTextureIndex);
125 string sCacheId = sr.GetAttribute("CacheId");
126 UUID lCacheId = UUID.Zero;
127 if (!(UUID.TryParse(sCacheId, out lCacheId)))
128 {
129 // ?? Nothing here
130 }
131
132 ++size;
133
134 sr.ReadStartElement("BakedTexture");
135 AssetBase a = (AssetBase)m_serializer.Deserialize(sr);
136 ret.Add(new WearableCacheItem() { CacheId = lCacheId, TextureIndex = (uint)lTextureIndex, TextureAsset = a, TextureID = a.FullID });
137
138 sr.ReadEndElement();
139 }
140
141 m_log.DebugFormat("[XBakes]: read {0} textures for user {1}", ret.Count, id);
142 }
143
144 return ret.ToArray();
145 }
146 catch (XmlException)
147 {
148 return null;
149 }
150 }
151 }
152
153 public void Store(UUID agentId, WearableCacheItem[] data)
154 {
155 if (m_URL == String.Empty)
156 return;
157
158 MemoryStream reqStream;
159
160 using (MemoryStream bakeStream = new MemoryStream())
161 using (XmlTextWriter bakeWriter = new XmlTextWriter(bakeStream, null))
162 {
163 bakeWriter.WriteStartElement(String.Empty, "BakedAppearance", String.Empty);
164
165 for (int i = 0; i < data.Length; i++)
166 {
167 if (data[i] != null)
168 {
169 bakeWriter.WriteStartElement(String.Empty, "BakedTexture", String.Empty);
170 bakeWriter.WriteAttributeString(String.Empty, "TextureIndex", String.Empty, data[i].TextureIndex.ToString());
171 bakeWriter.WriteAttributeString(String.Empty, "CacheId", String.Empty, data[i].CacheId.ToString());
172 if (data[i].TextureAsset != null)
173 m_serializer.Serialize(bakeWriter, data[i].TextureAsset);
174
175 bakeWriter.WriteEndElement();
176 }
177 }
178
179 bakeWriter.WriteEndElement();
180 bakeWriter.Flush();
181
182 reqStream = new MemoryStream(bakeStream.ToArray());
183 }
184
185 RestClient rc = new RestClient(m_URL);
186 rc.AddResourcePath("bakes");
187 rc.AddResourcePath(agentId.ToString());
188
189 rc.RequestMethod = "POST";
190
191 Util.FireAndForget(
192 delegate
193 {
194 rc.Request(reqStream, m_Auth);
195 m_log.DebugFormat("[XBakes]: stored {0} textures for user {1}", data.Length, agentId);
196 }, null, "XBakesModule.Store"
197 );
198 }
199 }
200} \ 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 6d62ff0..f0b1e67 100644
--- a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
@@ -32,6 +32,7 @@ using log4net;
32using Nini.Config; 32using Nini.Config;
33using Mono.Addins; 33using Mono.Addins;
34using OpenMetaverse; 34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
35using OpenSim.Framework; 36using OpenSim.Framework;
36using OpenSim.Region.Framework.Interfaces; 37using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes; 38using OpenSim.Region.Framework.Scenes;
@@ -50,7 +51,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
50 private int m_saydistance = 20; 51 private int m_saydistance = 20;
51 private int m_shoutdistance = 100; 52 private int m_shoutdistance = 100;
52 private int m_whisperdistance = 10; 53 private int m_whisperdistance = 10;
53 private List<Scene> m_scenes = new List<Scene>();
54 54
55 internal object m_syncy = new object(); 55 internal object m_syncy = new object();
56 56
@@ -61,18 +61,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
61 { 61 {
62 m_config = config.Configs["Chat"]; 62 m_config = config.Configs["Chat"];
63 63
64 if (null == m_config) 64 if (m_config != null)
65 { 65 {
66 m_log.Info("[CHAT]: no config found, plugin disabled"); 66 if (!m_config.GetBoolean("enabled", true))
67 m_enabled = false; 67 {
68 return; 68 m_log.Info("[CHAT]: plugin disabled by configuration");
69 } 69 m_enabled = false;
70 70 return;
71 if (!m_config.GetBoolean("enabled", true)) 71 }
72 {
73 m_log.Info("[CHAT]: plugin disabled by configuration");
74 m_enabled = false;
75 return;
76 } 72 }
77 73
78 m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance); 74 m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance);
@@ -82,18 +78,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
82 78
83 public virtual void AddRegion(Scene scene) 79 public virtual void AddRegion(Scene scene)
84 { 80 {
85 if (!m_enabled) return; 81 if (!m_enabled)
82 return;
86 83
87 lock (m_syncy) 84 scene.EventManager.OnNewClient += OnNewClient;
88 { 85 scene.EventManager.OnChatFromWorld += OnChatFromWorld;
89 if (!m_scenes.Contains(scene)) 86 scene.EventManager.OnChatBroadcast += OnChatBroadcast;
90 {
91 m_scenes.Add(scene);
92 scene.EventManager.OnNewClient += OnNewClient;
93 scene.EventManager.OnChatFromWorld += OnChatFromWorld;
94 scene.EventManager.OnChatBroadcast += OnChatBroadcast;
95 }
96 }
97 87
98 m_log.InfoFormat("[CHAT]: Initialized for {0} w:{1} s:{2} S:{3}", scene.RegionInfo.RegionName, 88 m_log.InfoFormat("[CHAT]: Initialized for {0} w:{1} s:{2} S:{3}", scene.RegionInfo.RegionName,
99 m_whisperdistance, m_saydistance, m_shoutdistance); 89 m_whisperdistance, m_saydistance, m_shoutdistance);
@@ -101,22 +91,24 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
101 91
102 public virtual void RegionLoaded(Scene scene) 92 public virtual void RegionLoaded(Scene scene)
103 { 93 {
94 if (!m_enabled)
95 return;
96
97 ISimulatorFeaturesModule featuresModule = scene.RequestModuleInterface<ISimulatorFeaturesModule>();
98
99 if (featuresModule != null)
100 featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest;
101
104 } 102 }
105 103
106 public virtual void RemoveRegion(Scene scene) 104 public virtual void RemoveRegion(Scene scene)
107 { 105 {
108 if (!m_enabled) return; 106 if (!m_enabled)
107 return;
109 108
110 lock (m_syncy) 109 scene.EventManager.OnNewClient -= OnNewClient;
111 { 110 scene.EventManager.OnChatFromWorld -= OnChatFromWorld;
112 if (m_scenes.Contains(scene)) 111 scene.EventManager.OnChatBroadcast -= OnChatBroadcast;
113 {
114 scene.EventManager.OnNewClient -= OnNewClient;
115 scene.EventManager.OnChatFromWorld -= OnChatFromWorld;
116 scene.EventManager.OnChatBroadcast -= OnChatBroadcast;
117 m_scenes.Remove(scene);
118 }
119 }
120 } 112 }
121 113
122 public virtual void Close() 114 public virtual void Close()
@@ -191,23 +183,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
191 UUID ownerID = UUID.Zero; 183 UUID ownerID = UUID.Zero;
192 UUID targetID = c.TargetUUID; 184 UUID targetID = c.TargetUUID;
193 string message = c.Message; 185 string message = c.Message;
194 IScene scene = c.Scene; 186 Scene scene = (Scene)c.Scene;
195 Vector3 fromPos = c.Position; 187 Vector3 fromPos = c.Position;
196 Vector3 regionPos = new Vector3(scene.RegionInfo.RegionLocX * Constants.RegionSize, 188 Vector3 regionPos = new Vector3(scene.RegionInfo.WorldLocX, scene.RegionInfo.WorldLocY, 0);
197 scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
198 189
199 if (c.Channel == DEBUG_CHANNEL) c.Type = ChatTypeEnum.DebugChannel; 190 if (c.Channel == DEBUG_CHANNEL) c.Type = ChatTypeEnum.DebugChannel;
200 191
201 switch (sourceType) 192 switch (sourceType)
202 { 193 {
203 case ChatSourceType.Agent: 194 case ChatSourceType.Agent:
204 if (!(scene is Scene)) 195 ScenePresence avatar = scene.GetScenePresence(c.Sender.AgentId);
205 {
206 m_log.WarnFormat("[CHAT]: scene {0} is not a Scene object, cannot obtain scene presence for {1}",
207 scene.RegionInfo.RegionName, c.Sender.AgentId);
208 return;
209 }
210 ScenePresence avatar = (scene as Scene).GetScenePresence(c.Sender.AgentId);
211 fromPos = avatar.AbsolutePosition; 196 fromPos = avatar.AbsolutePosition;
212 fromName = avatar.Name; 197 fromName = avatar.Name;
213 fromID = c.Sender.AgentId; 198 fromID = c.Sender.AgentId;
@@ -234,36 +219,33 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
234 219
235 HashSet<UUID> receiverIDs = new HashSet<UUID>(); 220 HashSet<UUID> receiverIDs = new HashSet<UUID>();
236 221
237 foreach (Scene s in m_scenes) 222 if (targetID == UUID.Zero)
238 { 223 {
239 if (targetID == UUID.Zero) 224 // This should use ForEachClient, but clients don't have a position.
240 { 225 // If camera is moved into client, then camera position can be used
241 // This should use ForEachClient, but clients don't have a position. 226 scene.ForEachScenePresence(
242 // If camera is moved into client, then camera position can be used 227 delegate(ScenePresence presence)
243 s.ForEachRootScenePresence(
244 delegate(ScenePresence presence)
245 {
246 if (TrySendChatMessage(
247 presence, fromPos, regionPos, fromID, ownerID, fromName, c.Type, message, sourceType, false))
248 receiverIDs.Add(presence.UUID);
249 }
250 );
251 }
252 else
253 {
254 // This is a send to a specific client eg from llRegionSayTo
255 // no need to check distance etc, jand send is as say
256 ScenePresence presence = s.GetScenePresence(targetID);
257 if (presence != null && !presence.IsChildAgent)
258 { 228 {
259 if (TrySendChatMessage( 229 if (TrySendChatMessage(
260 presence, fromPos, regionPos, fromID, ownerID, fromName, ChatTypeEnum.Say, message, sourceType, true)) 230 presence, fromPos, regionPos, fromID, ownerID, fromName, c.Type, message, sourceType, false))
261 receiverIDs.Add(presence.UUID); 231 receiverIDs.Add(presence.UUID);
262 } 232 }
233 );
234 }
235 else
236 {
237 // This is a send to a specific client eg from llRegionSayTo
238 // no need to check distance etc, jand send is as say
239 ScenePresence presence = scene.GetScenePresence(targetID);
240 if (presence != null && !presence.IsChildAgent)
241 {
242 if (TrySendChatMessage(
243 presence, fromPos, regionPos, fromID, ownerID, fromName, ChatTypeEnum.Say, message, sourceType, true))
244 receiverIDs.Add(presence.UUID);
263 } 245 }
264 } 246 }
265 247
266 (scene as Scene).EventManager.TriggerOnChatToClients( 248 scene.EventManager.TriggerOnChatToClients(
267 fromID, receiverIDs, message, c.Type, fromPos, fromName, sourceType, ChatAudibleLevel.Fully); 249 fromID, receiverIDs, message, c.Type, fromPos, fromName, sourceType, ChatAudibleLevel.Fully);
268 } 250 }
269 251
@@ -288,17 +270,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
288 string fromName = c.From; 270 string fromName = c.From;
289 271
290 UUID fromID = UUID.Zero; 272 UUID fromID = UUID.Zero;
273 UUID ownerID = UUID.Zero;
291 ChatSourceType sourceType = ChatSourceType.Object; 274 ChatSourceType sourceType = ChatSourceType.Object;
292 if (null != c.Sender) 275 if (null != c.Sender)
293 { 276 {
294 ScenePresence avatar = (c.Scene as Scene).GetScenePresence(c.Sender.AgentId); 277 ScenePresence avatar = (c.Scene as Scene).GetScenePresence(c.Sender.AgentId);
295 fromID = c.Sender.AgentId; 278 fromID = c.Sender.AgentId;
296 fromName = avatar.Name; 279 fromName = avatar.Name;
280 ownerID = c.Sender.AgentId;
297 sourceType = ChatSourceType.Agent; 281 sourceType = ChatSourceType.Agent;
298 } 282 }
299 else if (c.SenderUUID != UUID.Zero) 283 else if (c.SenderUUID != UUID.Zero)
300 { 284 {
301 fromID = c.SenderUUID; 285 fromID = c.SenderUUID;
286 ownerID = ((SceneObjectPart)c.SenderObject).OwnerID;
302 } 287 }
303 288
304 // m_log.DebugFormat("[CHAT] Broadcast: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, cType, sourceType); 289 // m_log.DebugFormat("[CHAT] Broadcast: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, cType, sourceType);
@@ -316,7 +301,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
316 return; 301 return;
317 302
318 client.SendChatMessage( 303 client.SendChatMessage(
319 c.Message, (byte)cType, CenterOfRegion, fromName, fromID, fromID, 304 c.Message, (byte)cType, CenterOfRegion, fromName, fromID, ownerID,
320 (byte)sourceType, (byte)ChatAudibleLevel.Fully); 305 (byte)sourceType, (byte)ChatAudibleLevel.Fully);
321 306
322 receiverIDs.Add(client.AgentId); 307 receiverIDs.Add(client.AgentId);
@@ -348,18 +333,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
348 UUID fromAgentID, UUID ownerID, string fromName, ChatTypeEnum type, 333 UUID fromAgentID, UUID ownerID, string fromName, ChatTypeEnum type,
349 string message, ChatSourceType src, bool ignoreDistance) 334 string message, ChatSourceType src, bool ignoreDistance)
350 { 335 {
351 // don't send stuff to child agents 336 if (presence.LifecycleState != ScenePresenceState.Running)
352 if (presence.IsChildAgent) return false; 337 return false;
353
354 Vector3 fromRegionPos = fromPos + regionPos;
355 Vector3 toRegionPos = presence.AbsolutePosition +
356 new Vector3(presence.Scene.RegionInfo.RegionLocX * Constants.RegionSize,
357 presence.Scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
358
359 int dis = (int)Util.GetDistanceTo(toRegionPos, fromRegionPos);
360 338
361 if (!ignoreDistance) 339 if (!ignoreDistance)
362 { 340 {
341 Vector3 fromRegionPos = fromPos + regionPos;
342 Vector3 toRegionPos = presence.AbsolutePosition +
343 new Vector3(presence.Scene.RegionInfo.WorldLocX, presence.Scene.RegionInfo.WorldLocY, 0);
344
345 int dis = (int)Util.GetDistanceTo(toRegionPos, fromRegionPos);
346
363 if (type == ChatTypeEnum.Whisper && dis > m_whisperdistance || 347 if (type == ChatTypeEnum.Whisper && dis > m_whisperdistance ||
364 type == ChatTypeEnum.Say && dis > m_saydistance || 348 type == ChatTypeEnum.Say && dis > m_saydistance ||
365 type == ChatTypeEnum.Shout && dis > m_shoutdistance) 349 type == ChatTypeEnum.Shout && dis > m_shoutdistance)
@@ -375,5 +359,33 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
375 359
376 return true; 360 return true;
377 } 361 }
362
363 #region SimulatorFeaturesRequest
364
365 static OSDInteger m_SayRange, m_WhisperRange, m_ShoutRange;
366
367 private void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features)
368 {
369 OSD extras = new OSDMap();
370 if (features.ContainsKey("OpenSimExtras"))
371 extras = features["OpenSimExtras"];
372 else
373 features["OpenSimExtras"] = extras;
374
375 if (m_SayRange == null)
376 {
377 // Do this only once
378 m_SayRange = new OSDInteger(m_saydistance);
379 m_WhisperRange = new OSDInteger(m_whisperdistance);
380 m_ShoutRange = new OSDInteger(m_shoutdistance);
381 }
382
383 ((OSDMap)extras)["say-range"] = m_SayRange;
384 ((OSDMap)extras)["whisper-range"] = m_WhisperRange;
385 ((OSDMap)extras)["shout-range"] = m_ShoutRange;
386
387 }
388
389 #endregion
378 } 390 }
379} \ No newline at end of file 391}
diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs
new file mode 100644
index 0000000..3018d94
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs
@@ -0,0 +1,285 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using log4net.Config;
31using Nini.Config;
32using NUnit.Framework;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Framework.Servers;
36using OpenSim.Framework.Servers.HttpServer;
37using OpenSim.Region.CoreModules.Avatar.Chat;
38using OpenSim.Region.CoreModules.Framework;
39using OpenSim.Region.CoreModules.Framework.EntityTransfer;
40using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Services.Interfaces;
43using OpenSim.Tests.Common;
44
45namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests
46{
47 [TestFixture]
48 public class ChatModuleTests : OpenSimTestCase
49 {
50 [TestFixtureSetUp]
51 public void FixtureInit()
52 {
53 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
54 // We must do this here so that child agent positions are updated in a predictable manner.
55 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
56 }
57
58 [TestFixtureTearDown]
59 public void TearDown()
60 {
61 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
62 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
63 // tests really shouldn't).
64 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
65 }
66
67 private void SetupNeighbourRegions(TestScene sceneA, TestScene sceneB)
68 {
69 // XXX: HTTP server is not (and should not be) necessary for this test, though it's absence makes the
70 // CapabilitiesModule complain when it can't set up HTTP endpoints.
71 // BaseHttpServer httpServer = new BaseHttpServer(99999);
72 // MainServer.AddHttpServer(httpServer);
73 // MainServer.Instance = httpServer;
74
75 // We need entity transfer modules so that when sp2 logs into the east region, the region calls
76 // EntityTransferModuleto set up a child agent on the west region.
77 // XXX: However, this is not an entity transfer so is misleading.
78 EntityTransferModule etmA = new EntityTransferModule();
79 EntityTransferModule etmB = new EntityTransferModule();
80 LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
81
82 IConfigSource config = new IniConfigSource();
83 config.AddConfig("Chat");
84 IConfig modulesConfig = config.AddConfig("Modules");
85 modulesConfig.Set("EntityTransferModule", etmA.Name);
86 modulesConfig.Set("SimulationServices", lscm.Name);
87
88 SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
89 SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA, new ChatModule());
90 SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB, new ChatModule());
91 }
92
93 /// <summary>
94 /// Tests chat between neighbour regions on the east-west axis
95 /// </summary>
96 /// <remarks>
97 /// Really, this is a combination of a child agent position update test and a chat range test. These need
98 /// to be separated later on.
99 /// </remarks>
100 [Test]
101 public void TestInterRegionChatDistanceEastWest()
102 {
103 TestHelpers.InMethod();
104// TestHelpers.EnableLogging();
105
106 UUID sp1Uuid = TestHelpers.ParseTail(0x11);
107 UUID sp2Uuid = TestHelpers.ParseTail(0x12);
108
109 Vector3 sp1Position = new Vector3(6, 128, 20);
110 Vector3 sp2Position = new Vector3(250, 128, 20);
111
112 SceneHelpers sh = new SceneHelpers();
113 TestScene sceneWest = sh.SetupScene("sceneWest", TestHelpers.ParseTail(0x1), 1000, 1000);
114 TestScene sceneEast = sh.SetupScene("sceneEast", TestHelpers.ParseTail(0x2), 1001, 1000);
115
116 SetupNeighbourRegions(sceneWest, sceneEast);
117
118 ScenePresence sp1 = SceneHelpers.AddScenePresence(sceneEast, sp1Uuid);
119 TestClient sp1Client = (TestClient)sp1.ControllingClient;
120
121 // If we don't set agents to flying, test will go wrong as they instantly fall to z = 0.
122 // TODO: May need to create special complete no-op test physics module rather than basic physics, since
123 // physics is irrelevant to this test.
124 sp1.Flying = true;
125
126 // When sp1 logs in to sceneEast, it sets up a child agent in sceneWest and informs the sp2 client to
127 // make the connection. For this test, will simplify this chain by making the connection directly.
128 ScenePresence sp1Child = SceneHelpers.AddChildScenePresence(sceneWest, sp1Uuid);
129 TestClient sp1ChildClient = (TestClient)sp1Child.ControllingClient;
130
131 sp1.AbsolutePosition = sp1Position;
132
133 ScenePresence sp2 = SceneHelpers.AddScenePresence(sceneWest, sp2Uuid);
134 TestClient sp2Client = (TestClient)sp2.ControllingClient;
135 sp2.Flying = true;
136
137 ScenePresence sp2Child = SceneHelpers.AddChildScenePresence(sceneEast, sp2Uuid);
138 TestClient sp2ChildClient = (TestClient)sp2Child.ControllingClient;
139
140 sp2.AbsolutePosition = sp2Position;
141
142 // We must update the scenes in order to make the root new root agents trigger position updates in their
143 // children.
144 sceneWest.Update(1);
145 sceneEast.Update(1);
146
147 // Check child positions are correct.
148 Assert.AreEqual(
149 new Vector3(sp1Position.X + sceneEast.RegionInfo.RegionSizeX, sp1Position.Y, sp1Position.Z),
150 sp1ChildClient.SceneAgent.AbsolutePosition);
151
152 Assert.AreEqual(
153 new Vector3(sp2Position.X - sceneWest.RegionInfo.RegionSizeX, sp2Position.Y, sp2Position.Z),
154 sp2ChildClient.SceneAgent.AbsolutePosition);
155
156 string receivedSp1ChatMessage = "";
157 string receivedSp2ChatMessage = "";
158
159 sp1ChildClient.OnReceivedChatMessage
160 += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp1ChatMessage = message;
161 sp2ChildClient.OnReceivedChatMessage
162 += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp2ChatMessage = message;
163
164 TestUserInRange(sp1Client, "ello darling", ref receivedSp2ChatMessage);
165 TestUserInRange(sp2Client, "fantastic cats", ref receivedSp1ChatMessage);
166
167 sp1Position = new Vector3(30, 128, 20);
168 sp1.AbsolutePosition = sp1Position;
169 sceneEast.Update(1);
170
171 // Check child position is correct.
172 Assert.AreEqual(
173 new Vector3(sp1Position.X + sceneEast.RegionInfo.RegionSizeX, sp1Position.Y, sp1Position.Z),
174 sp1ChildClient.SceneAgent.AbsolutePosition);
175
176 TestUserOutOfRange(sp1Client, "beef", ref receivedSp2ChatMessage);
177 TestUserOutOfRange(sp2Client, "lentils", ref receivedSp1ChatMessage);
178 }
179
180 /// <summary>
181 /// Tests chat between neighbour regions on the north-south axis
182 /// </summary>
183 /// <remarks>
184 /// Really, this is a combination of a child agent position update test and a chat range test. These need
185 /// to be separated later on.
186 /// </remarks>
187 [Test]
188 public void TestInterRegionChatDistanceNorthSouth()
189 {
190 TestHelpers.InMethod();
191 // TestHelpers.EnableLogging();
192
193 UUID sp1Uuid = TestHelpers.ParseTail(0x11);
194 UUID sp2Uuid = TestHelpers.ParseTail(0x12);
195
196 Vector3 sp1Position = new Vector3(128, 250, 20);
197 Vector3 sp2Position = new Vector3(128, 6, 20);
198
199 SceneHelpers sh = new SceneHelpers();
200 TestScene sceneNorth = sh.SetupScene("sceneNorth", TestHelpers.ParseTail(0x1), 1000, 1000);
201 TestScene sceneSouth = sh.SetupScene("sceneSouth", TestHelpers.ParseTail(0x2), 1000, 1001);
202
203 SetupNeighbourRegions(sceneNorth, sceneSouth);
204
205 ScenePresence sp1 = SceneHelpers.AddScenePresence(sceneNorth, sp1Uuid);
206 TestClient sp1Client = (TestClient)sp1.ControllingClient;
207
208 // If we don't set agents to flying, test will go wrong as they instantly fall to z = 0.
209 // TODO: May need to create special complete no-op test physics module rather than basic physics, since
210 // physics is irrelevant to this test.
211 sp1.Flying = true;
212
213 // When sp1 logs in to sceneEast, it sets up a child agent in sceneNorth and informs the sp2 client to
214 // make the connection. For this test, will simplify this chain by making the connection directly.
215 ScenePresence sp1Child = SceneHelpers.AddChildScenePresence(sceneSouth, sp1Uuid);
216 TestClient sp1ChildClient = (TestClient)sp1Child.ControllingClient;
217
218 sp1.AbsolutePosition = sp1Position;
219
220 ScenePresence sp2 = SceneHelpers.AddScenePresence(sceneSouth, sp2Uuid);
221 TestClient sp2Client = (TestClient)sp2.ControllingClient;
222 sp2.Flying = true;
223
224 ScenePresence sp2Child = SceneHelpers.AddChildScenePresence(sceneNorth, sp2Uuid);
225 TestClient sp2ChildClient = (TestClient)sp2Child.ControllingClient;
226
227 sp2.AbsolutePosition = sp2Position;
228
229 // We must update the scenes in order to make the root new root agents trigger position updates in their
230 // children.
231 sceneNorth.Update(1);
232 sceneSouth.Update(1);
233
234 // Check child positions are correct.
235 Assert.AreEqual(
236 new Vector3(sp1Position.X, sp1Position.Y - sceneNorth.RegionInfo.RegionSizeY, sp1Position.Z),
237 sp1ChildClient.SceneAgent.AbsolutePosition);
238
239 Assert.AreEqual(
240 new Vector3(sp2Position.X, sp2Position.Y + sceneSouth.RegionInfo.RegionSizeY, sp2Position.Z),
241 sp2ChildClient.SceneAgent.AbsolutePosition);
242
243 string receivedSp1ChatMessage = "";
244 string receivedSp2ChatMessage = "";
245
246 sp1ChildClient.OnReceivedChatMessage
247 += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp1ChatMessage = message;
248 sp2ChildClient.OnReceivedChatMessage
249 += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp2ChatMessage = message;
250
251 TestUserInRange(sp1Client, "ello darling", ref receivedSp2ChatMessage);
252 TestUserInRange(sp2Client, "fantastic cats", ref receivedSp1ChatMessage);
253
254 sp1Position = new Vector3(30, 128, 20);
255 sp1.AbsolutePosition = sp1Position;
256 sceneNorth.Update(1);
257
258 // Check child position is correct.
259 Assert.AreEqual(
260 new Vector3(sp1Position.X, sp1Position.Y - sceneNorth.RegionInfo.RegionSizeY, sp1Position.Z),
261 sp1ChildClient.SceneAgent.AbsolutePosition);
262
263 TestUserOutOfRange(sp1Client, "beef", ref receivedSp2ChatMessage);
264 TestUserOutOfRange(sp2Client, "lentils", ref receivedSp1ChatMessage);
265 }
266
267 private void TestUserInRange(TestClient speakClient, string testMessage, ref string receivedMessage)
268 {
269 receivedMessage = "";
270
271 speakClient.Chat(0, ChatTypeEnum.Say, testMessage);
272
273 Assert.AreEqual(testMessage, receivedMessage);
274 }
275
276 private void TestUserOutOfRange(TestClient speakClient, string testMessage, ref string receivedMessage)
277 {
278 receivedMessage = "";
279
280 speakClient.Chat(0, ChatTypeEnum.Say, testMessage);
281
282 Assert.AreNotEqual(testMessage, receivedMessage);
283 }
284 }
285} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs b/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs
index 343cdb5..fc23b72 100644
--- a/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs
@@ -31,6 +31,7 @@ using Nini.Config;
31using OpenSim.Framework; 31using OpenSim.Framework;
32using OpenSim.Region.Framework.Interfaces; 32using OpenSim.Region.Framework.Interfaces;
33using OpenSim.Region.Framework.Scenes; 33using OpenSim.Region.Framework.Scenes;
34using OpenSim.Services.Interfaces;
34using OpenMetaverse; 35using OpenMetaverse;
35 36
36using Mono.Addins; 37using Mono.Addins;
@@ -182,6 +183,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Combat.CombatModule
182 try 183 try
183 { 184 {
184 ILandObject obj = avatar.Scene.LandChannel.GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); 185 ILandObject obj = avatar.Scene.LandChannel.GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
186
187 if (obj == null)
188 return;
189
185 if ((obj.LandData.Flags & (uint)ParcelFlags.AllowDamage) != 0 190 if ((obj.LandData.Flags & (uint)ParcelFlags.AllowDamage) != 0
186 || avatar.Scene.RegionInfo.RegionSettings.AllowDamage) 191 || avatar.Scene.RegionInfo.RegionSettings.AllowDamage)
187 { 192 {
diff --git a/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs b/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
index d26907b..a896897 100644
--- a/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
@@ -133,13 +133,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Dialog
133 UUID objectID, UUID ownerID, string message, UUID textureID, 133 UUID objectID, UUID ownerID, string message, UUID textureID,
134 int ch, string[] buttonlabels) 134 int ch, string[] buttonlabels)
135 { 135 {
136 UserAccount account = m_scene.UserAccountService.GetUserAccount( 136 string username = m_scene.UserManagementModule.GetUserName(ownerID);
137 m_scene.RegionInfo.ScopeID, ownerID); 137 string ownerFirstName, ownerLastName = String.Empty;
138 string ownerFirstName, ownerLastName; 138 if (!String.IsNullOrEmpty(username))
139 if (account != null)
140 { 139 {
141 ownerFirstName = account.FirstName; 140 string[] parts = username.Split(' ');
142 ownerLastName = account.LastName; 141 ownerFirstName = parts[0];
142 if (parts.Length > 1)
143 ownerLastName = username.Split(' ')[1];
143 } 144 }
144 else 145 else
145 { 146 {
@@ -170,17 +171,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Dialog
170 } 171 }
171 172
172 public void SendTextBoxToUser(UUID avatarid, string message, 173 public void SendTextBoxToUser(UUID avatarid, string message,
173 int chatChannel, string name, UUID objectid, UUID ownerid) 174 int chatChannel, string name, UUID objectid, UUID ownerID)
174 { 175 {
175 UserAccount account = m_scene.UserAccountService.GetUserAccount( 176 string username = m_scene.UserManagementModule.GetUserName(ownerID);
176 m_scene.RegionInfo.ScopeID, ownerid); 177 string ownerFirstName, ownerLastName = String.Empty;
177 string ownerFirstName, ownerLastName; 178 if (!String.IsNullOrEmpty(username))
178 UUID ownerID = UUID.Zero;
179 if (account != null)
180 { 179 {
181 ownerFirstName = account.FirstName; 180 string[] parts = username.Split(' ');
182 ownerLastName = account.LastName; 181 ownerFirstName = parts[0];
183 ownerID = account.PrincipalID; 182 if (parts.Length > 1)
183 ownerLastName = username.Split(' ')[1];
184 } 184 }
185 else 185 else
186 { 186 {
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs
index 5ec0ea9..eb23e83 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs
@@ -36,6 +36,7 @@ using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes; 36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Services.Interfaces; 37using OpenSim.Services.Interfaces;
38using Mono.Addins; 38using Mono.Addins;
39using PermissionMask = OpenSim.Framework.PermissionMask;
39 40
40namespace OpenSim.Region.CoreModules.Avatar.Friends 41namespace OpenSim.Region.CoreModules.Avatar.Friends
41{ 42{
@@ -180,7 +181,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
180 if (folderID == UUID.Zero) 181 if (folderID == UUID.Zero)
181 { 182 {
182 InventoryFolderBase folder = inv.GetFolderForType(userID, 183 InventoryFolderBase folder = inv.GetFolderForType(userID,
183 AssetType.CallingCard); 184 FolderType.CallingCard);
184 185
185 if (folder == null) // Nowhere to put it 186 if (folder == null) // Nowhere to put it
186 return UUID.Zero; 187 return UUID.Zero;
@@ -236,7 +237,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
236 IInventoryService invService = m_Scenes[0].InventoryService; 237 IInventoryService invService = m_Scenes[0].InventoryService;
237 238
238 InventoryFolderBase trashFolder = 239 InventoryFolderBase trashFolder =
239 invService.GetFolderForType(client.AgentId, AssetType.TrashFolder); 240 invService.GetFolderForType(client.AgentId, FolderType.Trash);
240 241
241 InventoryItemBase item = new InventoryItemBase(transactionID, client.AgentId); 242 InventoryItemBase item = new InventoryItemBase(transactionID, client.AgentId);
242 item = invService.GetItem(item); 243 item = invService.GetItem(item);
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
index 8056030..08e7dd2 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
@@ -38,7 +38,6 @@ using OpenMetaverse;
38using Mono.Addins; 38using Mono.Addins;
39using OpenSim.Framework; 39using OpenSim.Framework;
40using OpenSim.Framework.Servers.HttpServer; 40using OpenSim.Framework.Servers.HttpServer;
41using OpenSim.Framework.Communications;
42using OpenSim.Framework.Servers; 41using OpenSim.Framework.Servers;
43using OpenSim.Region.Framework.Interfaces; 42using OpenSim.Region.Framework.Interfaces;
44using OpenSim.Region.Framework.Scenes; 43using OpenSim.Region.Framework.Scenes;
@@ -94,6 +93,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
94 protected Dictionary<UUID, UserFriendData> m_Friends = new Dictionary<UUID, UserFriendData>(); 93 protected Dictionary<UUID, UserFriendData> m_Friends = new Dictionary<UUID, UserFriendData>();
95 94
96 /// <summary> 95 /// <summary>
96 /// Maintain a record of clients that need to notify about their online status. This only
97 /// needs to be done on login. Subsequent online/offline friend changes are sent by a different mechanism.
98 /// </summary>
99 protected HashSet<UUID> m_NeedsToNotifyStatus = new HashSet<UUID>();
100
101 /// <summary>
97 /// Maintain a record of viewers that need to be sent notifications for friends that are online. This only 102 /// Maintain a record of viewers that need to be sent notifications for friends that are online. This only
98 /// needs to be done on login. Subsequent online/offline friend changes are sent by a different mechanism. 103 /// needs to be done on login. Subsequent online/offline friend changes are sent by a different mechanism.
99 /// </summary> 104 /// </summary>
@@ -324,6 +329,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
324 private void OnMakeRootAgent(ScenePresence sp) 329 private void OnMakeRootAgent(ScenePresence sp)
325 { 330 {
326 RecacheFriends(sp.ControllingClient); 331 RecacheFriends(sp.ControllingClient);
332
333 lock (m_NeedsToNotifyStatus)
334 {
335 if (m_NeedsToNotifyStatus.Remove(sp.UUID))
336 {
337 // Inform the friends that this user is online. This can only be done once the client is a Root Agent.
338 StatusChange(sp.UUID, true);
339 }
340 }
327 } 341 }
328 342
329 private void OnClientLogin(IClientAPI client) 343 private void OnClientLogin(IClientAPI client)
@@ -331,8 +345,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
331 UUID agentID = client.AgentId; 345 UUID agentID = client.AgentId;
332 346
333 //m_log.DebugFormat("[XXX]: OnClientLogin!"); 347 //m_log.DebugFormat("[XXX]: OnClientLogin!");
334 // Inform the friends that this user is online 348
335 StatusChange(agentID, true); 349 // Register that we need to send this user's status to friends. This can only be done
350 // once the client becomes a Root Agent, because as part of sending out the presence
351 // we also get back the presence of the HG friends, and we need to send that to the
352 // client, but that can only be done when the client is a Root Agent.
353 lock (m_NeedsToNotifyStatus)
354 m_NeedsToNotifyStatus.Add(agentID);
336 355
337 // Register that we need to send the list of online friends to this user 356 // Register that we need to send the list of online friends to this user
338 lock (m_NeedsListOfOnlineFriends) 357 lock (m_NeedsListOfOnlineFriends)
@@ -371,7 +390,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
371 foreach (string fid in outstanding) 390 foreach (string fid in outstanding)
372 { 391 {
373 UUID fromAgentID; 392 UUID fromAgentID;
374 string firstname = "Unknown", lastname = "User"; 393 string firstname = "Unknown", lastname = "UserFMSFOIN";
375 if (!GetAgentInfo(client.Scene.RegionInfo.ScopeID, fid, out fromAgentID, out firstname, out lastname)) 394 if (!GetAgentInfo(client.Scene.RegionInfo.ScopeID, fid, out fromAgentID, out firstname, out lastname))
376 { 395 {
377 m_log.DebugFormat("[FRIENDS MODULE]: skipping malformed friend {0}", fid); 396 m_log.DebugFormat("[FRIENDS MODULE]: skipping malformed friend {0}", fid);
@@ -397,7 +416,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
397 416
398 protected virtual bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last) 417 protected virtual bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last)
399 { 418 {
400 first = "Unknown"; last = "User"; 419 first = "Unknown"; last = "UserFMGAI";
401 if (!UUID.TryParse(fid, out agentID)) 420 if (!UUID.TryParse(fid, out agentID))
402 return false; 421 return false;
403 422
@@ -491,13 +510,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
491 510
492 // Notify about this user status 511 // Notify about this user status
493 StatusNotify(friendList, agentID, online); 512 StatusNotify(friendList, agentID, online);
494 } 513 }, null, "FriendsModule.StatusChange"
495 ); 514 );
496 } 515 }
497 } 516 }
498 517
499 protected virtual void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online) 518 protected virtual void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online)
500 { 519 {
520 //m_log.DebugFormat("[FRIENDS]: Entering StatusNotify for {0}", userID);
521
501 List<string> friendStringIds = friendList.ConvertAll<string>(friend => friend.Friend); 522 List<string> friendStringIds = friendList.ConvertAll<string>(friend => friend.Friend);
502 List<string> remoteFriendStringIds = new List<string>(); 523 List<string> remoteFriendStringIds = new List<string>();
503 foreach (string friendStringId in friendStringIds) 524 foreach (string friendStringId in friendStringIds)
@@ -523,12 +544,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
523 foreach (PresenceInfo friendSession in friendSessions) 544 foreach (PresenceInfo friendSession in friendSessions)
524 { 545 {
525 // let's guard against sessions-gone-bad 546 // let's guard against sessions-gone-bad
526 if (friendSession.RegionID != UUID.Zero) 547 if (friendSession != null && friendSession.RegionID != UUID.Zero)
527 { 548 {
549 //m_log.DebugFormat("[FRIENDS]: Get region {0}", friendSession.RegionID);
528 GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID); 550 GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
529 //m_log.DebugFormat("[FRIENDS]: Remote Notify to region {0}", region.RegionName); 551 if (region != null)
530 m_FriendsSimConnector.StatusNotify(region, userID, friendSession.UserID, online); 552 {
553 m_FriendsSimConnector.StatusNotify(region, userID, friendSession.UserID, online);
554 }
531 } 555 }
556 //else
557 // m_log.DebugFormat("[FRIENDS]: friend session is null or the region is UUID.Zero");
532 } 558 }
533 } 559 }
534 560
@@ -685,7 +711,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
685 // 711 //
686 712
687 // Try local 713 // Try local
688 if (LocalFriendshipTerminated(exfriendID)) 714 if (LocalFriendshipTerminated(client.AgentId, exfriendID))
689 return; 715 return;
690 716
691 PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { exfriendID.ToString() }); 717 PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { exfriendID.ToString() });
@@ -827,13 +853,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
827 return false; 853 return false;
828 } 854 }
829 855
830 public bool LocalFriendshipTerminated(UUID exfriendID) 856 public bool LocalFriendshipTerminated(UUID userID, UUID exfriendID)
831 { 857 {
832 IClientAPI friendClient = LocateClientObject(exfriendID); 858 IClientAPI friendClient = LocateClientObject(exfriendID);
833 if (friendClient != null) 859 if (friendClient != null)
834 { 860 {
835 // the friend in this sim as root agent 861 // the friend in this sim as root agent
836 friendClient.SendTerminateFriend(exfriendID); 862 friendClient.SendTerminateFriend(userID);
837 // update local cache 863 // update local cache
838 RecacheFriends(friendClient); 864 RecacheFriends(friendClient);
839 // we're done 865 // we're done
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs
index 637beef..13512a2 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -42,19 +42,27 @@ using log4net;
42 42
43namespace OpenSim.Region.CoreModules.Avatar.Friends 43namespace OpenSim.Region.CoreModules.Avatar.Friends
44{ 44{
45 public class FriendsRequestHandler : BaseStreamHandler 45 public class FriendsRequestHandler : BaseStreamHandlerBasicDOSProtector
46 { 46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 48
49 private FriendsModule m_FriendsModule; 49 private FriendsModule m_FriendsModule;
50 50
51 public FriendsRequestHandler(FriendsModule fmodule) 51 public FriendsRequestHandler(FriendsModule fmodule)
52 : base("POST", "/friends") 52 : base("POST", "/friends", new BasicDosProtectorOptions()
53 {
54 AllowXForwardedFor = true,
55 ForgetTimeSpan = TimeSpan.FromMinutes(2),
56 MaxRequestsInTimeframe = 20,
57 ReportingName = "FRIENDSDOSPROTECTOR",
58 RequestTimeSpan = TimeSpan.FromSeconds(5),
59 ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod
60 })
53 { 61 {
54 m_FriendsModule = fmodule; 62 m_FriendsModule = fmodule;
55 } 63 }
56 64
57 public override byte[] Handle( 65 protected override byte[] ProcessRequest(
58 string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 66 string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
59 { 67 {
60 StreamReader sr = new StreamReader(requestData); 68 StreamReader sr = new StreamReader(requestData);
@@ -193,7 +201,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
193 if (!UUID.TryParse(request["ToID"].ToString(), out toID)) 201 if (!UUID.TryParse(request["ToID"].ToString(), out toID))
194 return FailureResult(); 202 return FailureResult();
195 203
196 if (m_FriendsModule.LocalFriendshipTerminated(toID)) 204 if (m_FriendsModule.LocalFriendshipTerminated(fromID, toID))
197 return SuccessResult(); 205 return SuccessResult();
198 206
199 return FailureResult(); 207 return FailureResult();
@@ -281,18 +289,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
281 289
282 rootElement.AppendChild(result); 290 rootElement.AppendChild(result);
283 291
284 return DocToBytes(doc); 292 return Util.DocToBytes(doc);
285 }
286
287 private byte[] DocToBytes(XmlDocument doc)
288 {
289 MemoryStream ms = new MemoryStream();
290 XmlTextWriter xw = new XmlTextWriter(ms, null);
291 xw.Formatting = Formatting.Indented;
292 doc.WriteTo(xw);
293 xw.Flush();
294
295 return ms.ToArray();
296 } 293 }
297 294
298 #endregion 295 #endregion
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
index bf5c0bb..27b7376 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
@@ -183,6 +183,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
183 if (Util.ParseUniversalUserIdentifier(finfo.Friend, out id, out url, out first, out last, out tmp)) 183 if (Util.ParseUniversalUserIdentifier(finfo.Friend, out id, out url, out first, out last, out tmp))
184 { 184 {
185 IUserManagement uMan = m_Scenes[0].RequestModuleInterface<IUserManagement>(); 185 IUserManagement uMan = m_Scenes[0].RequestModuleInterface<IUserManagement>();
186 m_log.DebugFormat("[HGFRIENDS MODULE]: caching {0}", finfo.Friend);
186 uMan.AddUser(id, url + ";" + first + " " + last); 187 uMan.AddUser(id, url + ";" + first + " " + last);
187 } 188 }
188 } 189 }
@@ -238,6 +239,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
238 fList.Add(s.Substring(0, 36)); 239 fList.Add(s.Substring(0, 36));
239 } 240 }
240 241
242 // FIXME: also query the presence status of friends in other grids (like in HGStatusNotifier.Notify())
243
241 PresenceInfo[] presence = PresenceService.GetAgents(fList.ToArray()); 244 PresenceInfo[] presence = PresenceService.GetAgents(fList.ToArray());
242 foreach (PresenceInfo pi in presence) 245 foreach (PresenceInfo pi in presence)
243 { 246 {
@@ -251,7 +254,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
251 254
252 protected override void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online) 255 protected override void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online)
253 { 256 {
254// m_log.DebugFormat("[HGFRIENDS MODULE]: Entering StatusNotify for {0}", userID); 257 //m_log.DebugFormat("[HGFRIENDS MODULE]: Entering StatusNotify for {0}", userID);
255 258
256 // First, let's divide the friends on a per-domain basis 259 // First, let's divide the friends on a per-domain basis
257 Dictionary<string, List<FriendInfo>> friendsPerDomain = new Dictionary<string, List<FriendInfo>>(); 260 Dictionary<string, List<FriendInfo>> friendsPerDomain = new Dictionary<string, List<FriendInfo>>();
@@ -293,7 +296,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
293 296
294 protected override bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last) 297 protected override bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last)
295 { 298 {
296 first = "Unknown"; last = "User"; 299 first = "Unknown"; last = "UserHGGAI";
297 if (base.GetAgentInfo(scopeID, fid, out agentID, out first, out last)) 300 if (base.GetAgentInfo(scopeID, fid, out agentID, out first, out last))
298 return true; 301 return true;
299 302
@@ -349,7 +352,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
349 352
350 public override FriendInfo[] GetFriendsFromService(IClientAPI client) 353 public override FriendInfo[] GetFriendsFromService(IClientAPI client)
351 { 354 {
352// m_log.DebugFormat("[HGFRIENDS MODULE]: Entering GetFriendsFromService for {0}", client.Name); 355 // m_log.DebugFormat("[HGFRIENDS MODULE]: Entering GetFriendsFromService for {0}", client.Name);
353 Boolean agentIsLocal = true; 356 Boolean agentIsLocal = true;
354 if (UserManagementModule != null) 357 if (UserManagementModule != null)
355 agentIsLocal = UserManagementModule.IsLocalGridUser(client.AgentId); 358 agentIsLocal = UserManagementModule.IsLocalGridUser(client.AgentId);
@@ -362,13 +365,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
362 AgentCircuitData agentClientCircuit = ((Scene)(client.Scene)).AuthenticateHandler.GetAgentCircuitData(client.CircuitCode); 365 AgentCircuitData agentClientCircuit = ((Scene)(client.Scene)).AuthenticateHandler.GetAgentCircuitData(client.CircuitCode);
363 if (agentClientCircuit != null) 366 if (agentClientCircuit != null)
364 { 367 {
365 //[XXX] string agentUUI = Util.ProduceUserUniversalIdentifier(agentClientCircuit); 368 // Note that this is calling a different interface than base; this one calls with a string param!
366
367 finfos = FriendsService.GetFriends(client.AgentId.ToString()); 369 finfos = FriendsService.GetFriends(client.AgentId.ToString());
368 m_log.DebugFormat("[HGFRIENDS MODULE]: Fetched {0} local friends for visitor {1}", finfos.Length, client.AgentId.ToString()); 370 m_log.DebugFormat("[HGFRIENDS MODULE]: Fetched {0} local friends for visitor {1}", finfos.Length, client.AgentId.ToString());
369 } 371 }
370 372
371// m_log.DebugFormat("[HGFRIENDS MODULE]: Exiting GetFriendsFromService for {0}", client.Name); 373 // m_log.DebugFormat("[HGFRIENDS MODULE]: Exiting GetFriendsFromService for {0}", client.Name);
372 374
373 return finfos; 375 return finfos;
374 } 376 }
@@ -658,7 +660,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
658 FriendsService.Delete(friendUUI, agentID.ToString()); 660 FriendsService.Delete(friendUUI, agentID.ToString());
659 661
660 // notify the exfriend's service 662 // notify the exfriend's service
661 Util.FireAndForget(delegate { Delete(exfriendID, agentID, friendUUI); }); 663 Util.FireAndForget(
664 delegate { Delete(exfriendID, agentID, friendUUI); }, null, "HGFriendsModule.DeleteFriendshipForeignFriend");
662 665
663 m_log.DebugFormat("[HGFRIENDS MODULE]: {0} terminated {1}", agentID, friendUUI); 666 m_log.DebugFormat("[HGFRIENDS MODULE]: {0} terminated {1}", agentID, friendUUI);
664 return true; 667 return true;
@@ -676,7 +679,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
676 FriendsService.Delete(agentUUI, exfriendID.ToString()); 679 FriendsService.Delete(agentUUI, exfriendID.ToString());
677 680
678 // notify the agent's service? 681 // notify the agent's service?
679 Util.FireAndForget(delegate { Delete(agentID, exfriendID, agentUUI); }); 682 Util.FireAndForget(
683 delegate { Delete(agentID, exfriendID, agentUUI); }, null, "HGFriendsModule.DeleteFriendshipLocalFriend");
680 684
681 m_log.DebugFormat("[HGFRIENDS MODULE]: {0} terminated {1}", agentUUI, exfriendID); 685 m_log.DebugFormat("[HGFRIENDS MODULE]: {0} terminated {1}", agentUUI, exfriendID);
682 return true; 686 return true;
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs
index 961117e..e6fd54e 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs
@@ -35,7 +35,6 @@ using OpenSim.Framework;
35using OpenSim.Region.CoreModules.Avatar.Friends; 35using OpenSim.Region.CoreModules.Avatar.Friends;
36using OpenSim.Region.Framework.Scenes; 36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Tests.Common; 37using OpenSim.Tests.Common;
38using OpenSim.Tests.Common.Mock;
39 38
40namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests 39namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests
41{ 40{
diff --git a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
index 5a7446f..3b6d970 100644
--- a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
@@ -26,20 +26,37 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections;
29using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Collections.Specialized;
32using System.IO;
33using System.Reflection;
34using System.Web;
35using System.Xml;
36using log4net;
37using Mono.Addins;
30using Nini.Config; 38using Nini.Config;
31using OpenMetaverse; 39using OpenMetaverse;
40using OpenMetaverse.Messages.Linden;
41using OpenMetaverse.StructuredData;
32using OpenSim.Framework; 42using OpenSim.Framework;
43using OpenSim.Framework.Capabilities;
44using OpenSim.Framework.Servers;
45using OpenSim.Framework.Servers.HttpServer;
33using OpenSim.Region.Framework.Scenes; 46using OpenSim.Region.Framework.Scenes;
34using OpenSim.Region.Framework.Interfaces; 47using OpenSim.Region.Framework.Interfaces;
35 48using Caps = OpenSim.Framework.Capabilities.Caps;
36using Mono.Addins; 49using OSDArray = OpenMetaverse.StructuredData.OSDArray;
50using OSDMap = OpenMetaverse.StructuredData.OSDMap;
37 51
38namespace OpenSim.Region.CoreModules.Avatar.Gods 52namespace OpenSim.Region.CoreModules.Avatar.Gods
39{ 53{
40 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GodsModule")] 54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GodsModule")]
41 public class GodsModule : INonSharedRegionModule, IGodsModule 55 public class GodsModule : INonSharedRegionModule, IGodsModule
42 { 56 {
57 private static readonly ILog m_log =
58 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
59
43 /// <summary>Special UUID for actions that apply to all agents</summary> 60 /// <summary>Special UUID for actions that apply to all agents</summary>
44 private static readonly UUID ALL_AGENTS = new UUID("44e87126-e794-4ded-05b3-7c42da3d5cdb"); 61 private static readonly UUID ALL_AGENTS = new UUID("44e87126-e794-4ded-05b3-7c42da3d5cdb");
45 62
@@ -65,6 +82,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
65 m_scene = scene; 82 m_scene = scene;
66 m_scene.RegisterModuleInterface<IGodsModule>(this); 83 m_scene.RegisterModuleInterface<IGodsModule>(this);
67 m_scene.EventManager.OnNewClient += SubscribeToClientEvents; 84 m_scene.EventManager.OnNewClient += SubscribeToClientEvents;
85 m_scene.EventManager.OnRegisterCaps += OnRegisterCaps;
86 scene.EventManager.OnIncomingInstantMessage +=
87 OnIncomingInstantMessage;
68 } 88 }
69 89
70 public void RemoveRegion(Scene scene) 90 public void RemoveRegion(Scene scene)
@@ -98,6 +118,47 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
98 client.OnRequestGodlikePowers -= RequestGodlikePowers; 118 client.OnRequestGodlikePowers -= RequestGodlikePowers;
99 } 119 }
100 120
121 private void OnRegisterCaps(UUID agentID, Caps caps)
122 {
123 string uri = "/CAPS/" + UUID.Random();
124
125 caps.RegisterHandler(
126 "UntrustedSimulatorMessage",
127 new RestStreamHandler("POST", uri, HandleUntrustedSimulatorMessage, "UntrustedSimulatorMessage", null));
128 }
129
130 private string HandleUntrustedSimulatorMessage(string request,
131 string path, string param, IOSHttpRequest httpRequest,
132 IOSHttpResponse httpResponse)
133 {
134 OSDMap osd = (OSDMap)OSDParser.DeserializeLLSDXml(request);
135
136 string message = osd["message"].AsString();
137
138 if (message == "GodKickUser")
139 {
140 OSDMap body = (OSDMap)osd["body"];
141 OSDArray userInfo = (OSDArray)body["UserInfo"];
142 OSDMap userData = (OSDMap)userInfo[0];
143
144 UUID agentID = userData["AgentID"].AsUUID();
145 UUID godID = userData["GodID"].AsUUID();
146 UUID godSessionID = userData["GodSessionID"].AsUUID();
147 uint kickFlags = userData["KickFlags"].AsUInteger();
148 string reason = userData["Reason"].AsString();
149 ScenePresence god = m_scene.GetScenePresence(godID);
150 if (god == null || god.ControllingClient.SessionId != godSessionID)
151 return String.Empty;
152
153 KickUser(godID, godSessionID, agentID, kickFlags, Util.StringToBytes1024(reason));
154 }
155 else
156 {
157 m_log.ErrorFormat("[GOD]: Unhandled UntrustedSimulatorMessage: {0}", message);
158 }
159 return String.Empty;
160 }
161
101 public void RequestGodlikePowers( 162 public void RequestGodlikePowers(
102 UUID agentID, UUID sessionID, UUID token, bool godLike, IClientAPI controllingClient) 163 UUID agentID, UUID sessionID, UUID token, bool godLike, IClientAPI controllingClient)
103 { 164 {
@@ -146,76 +207,85 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
146 /// <param name="reason">The message to send to the user after it's been turned into a field</param> 207 /// <param name="reason">The message to send to the user after it's been turned into a field</param>
147 public void KickUser(UUID godID, UUID sessionID, UUID agentID, uint kickflags, byte[] reason) 208 public void KickUser(UUID godID, UUID sessionID, UUID agentID, uint kickflags, byte[] reason)
148 { 209 {
149 UUID kickUserID = ALL_AGENTS; 210 if (!m_scene.Permissions.IsGod(godID))
150 211 return;
212
151 ScenePresence sp = m_scene.GetScenePresence(agentID); 213 ScenePresence sp = m_scene.GetScenePresence(agentID);
152 214
153 if (sp != null || agentID == kickUserID) 215 if (sp == null && agentID != ALL_AGENTS)
154 { 216 {
155 if (m_scene.Permissions.IsGod(godID)) 217 IMessageTransferModule transferModule =
218 m_scene.RequestModuleInterface<IMessageTransferModule>();
219 if (transferModule != null)
156 { 220 {
157 if (kickflags == 0) 221 m_log.DebugFormat("[GODS]: Sending nonlocal kill for agent {0}", agentID);
158 { 222 transferModule.SendInstantMessage(new GridInstantMessage(
159 if (agentID == kickUserID) 223 m_scene, godID, "God", agentID, (byte)250, false,
160 { 224 Utils.BytesToString(reason), UUID.Zero, true,
161 string reasonStr = Utils.BytesToString(reason); 225 new Vector3(), new byte[] {(byte)kickflags}, true),
162 226 delegate(bool success) {} );
163 m_scene.ForEachClient( 227 }
164 delegate(IClientAPI controller) 228 return;
165 { 229 }
166 if (controller.AgentId != godID)
167 controller.Kick(reasonStr);
168 }
169 );
170
171 // This is a bit crude. It seems the client will be null before it actually stops the thread
172 // The thread will kill itself eventually :/
173 // Is there another way to make sure *all* clients get this 'inter region' message?
174 m_scene.ForEachRootClient(
175 delegate(IClientAPI client)
176 {
177 if (client.AgentId != godID)
178 {
179 client.Close();
180 }
181 }
182 );
183 }
184 else
185 {
186 m_scene.SceneGraph.removeUserCount(!sp.IsChildAgent);
187 230
188 sp.ControllingClient.Kick(Utils.BytesToString(reason)); 231 switch (kickflags)
189 sp.ControllingClient.Close(); 232 {
190 } 233 case 0:
191 } 234 if (sp != null)
192 235 {
193 if (kickflags == 1) 236 KickPresence(sp, Utils.BytesToString(reason));
194 {
195 sp.AllowMovement = false;
196 if (DialogModule != null)
197 {
198 DialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason));
199 DialogModule.SendAlertToUser(godID, "User Frozen");
200 }
201 }
202
203 if (kickflags == 2)
204 {
205 sp.AllowMovement = true;
206 if (DialogModule != null)
207 {
208 DialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason));
209 DialogModule.SendAlertToUser(godID, "User Unfrozen");
210 }
211 }
212 } 237 }
213 else 238 else if (agentID == ALL_AGENTS)
214 { 239 {
215 if (DialogModule != null) 240 m_scene.ForEachRootScenePresence(
216 DialogModule.SendAlertToUser(godID, "Kick request denied"); 241 delegate(ScenePresence p)
242 {
243 if (p.UUID != godID && (!m_scene.Permissions.IsGod(p.UUID)))
244 KickPresence(p, Utils.BytesToString(reason));
245 }
246 );
217 } 247 }
248 break;
249 case 1:
250 if (sp != null)
251 {
252 sp.AllowMovement = false;
253 m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason));
254 m_dialogModule.SendAlertToUser(godID, "User Frozen");
255 }
256 break;
257 case 2:
258 if (sp != null)
259 {
260 sp.AllowMovement = true;
261 m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason));
262 m_dialogModule.SendAlertToUser(godID, "User Unfrozen");
263 }
264 break;
265 default:
266 break;
267 }
268 }
269
270 private void KickPresence(ScenePresence sp, string reason)
271 {
272 if (sp.IsChildAgent)
273 return;
274 sp.ControllingClient.Kick(reason);
275 sp.Scene.CloseAgent(sp.UUID, true);
276 }
277
278 private void OnIncomingInstantMessage(GridInstantMessage msg)
279 {
280 if (msg.dialog == (uint)250) // Nonlocal kick
281 {
282 UUID agentID = new UUID(msg.toAgentID);
283 string reason = msg.message;
284 UUID godID = new UUID(msg.fromAgentID);
285 uint kickMode = (uint)msg.binaryBucket[0];
286
287 KickUser(godID, UUID.Zero, agentID, kickMode, Util.StringToBytes1024(reason));
218 } 288 }
219 } 289 }
220 } 290 }
221} \ No newline at end of file 291}
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs
index 7bf19c2..a1b918a 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs
@@ -210,10 +210,10 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
210 success = m_IMService.OutgoingInstantMessage(im, url, foreigner); 210 success = m_IMService.OutgoingInstantMessage(im, url, foreigner);
211 211
212 if (!success && !foreigner) 212 if (!success && !foreigner)
213 HandleUndeliveredMessage(im, result); 213 HandleUndeliverableMessage(im, result);
214 else 214 else
215 result(success); 215 result(success);
216 }); 216 }, null, "HGMessageTransferModule.SendInstantMessage");
217 217
218 return; 218 return;
219 } 219 }
@@ -246,7 +246,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
246 return successful; 246 return successful;
247 } 247 }
248 248
249 protected void HandleUndeliveredMessage(GridInstantMessage im, MessageResultNotification result) 249 public void HandleUndeliverableMessage(GridInstantMessage im, MessageResultNotification result)
250 { 250 {
251 UndeliveredMessage handlerUndeliveredMessage = OnUndeliveredMessage; 251 UndeliveredMessage handlerUndeliveredMessage = OnUndeliveredMessage;
252 252
@@ -282,7 +282,17 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
282 string uasURL = circuit.ServiceURLs["HomeURI"].ToString(); 282 string uasURL = circuit.ServiceURLs["HomeURI"].ToString();
283 m_log.DebugFormat("[HG MESSAGE TRANSFER]: getting UUI of user {0} from {1}", toAgent, uasURL); 283 m_log.DebugFormat("[HG MESSAGE TRANSFER]: getting UUI of user {0} from {1}", toAgent, uasURL);
284 UserAgentServiceConnector uasConn = new UserAgentServiceConnector(uasURL); 284 UserAgentServiceConnector uasConn = new UserAgentServiceConnector(uasURL);
285 return uasConn.GetUUI(fromAgent, toAgent); 285
286 string agentUUI = string.Empty;
287 try
288 {
289 agentUUI = uasConn.GetUUI(fromAgent, toAgent);
290 }
291 catch (Exception e) {
292 m_log.Debug("[HG MESSAGE TRANSFER]: GetUUI call failed ", e);
293 }
294
295 return agentUUI;
286 } 296 }
287 } 297 }
288 } 298 }
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
index fa935cd..2462ff8 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
@@ -181,7 +181,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
181 SendGridInstantMessageViaXMLRPC(im, result); 181 SendGridInstantMessageViaXMLRPC(im, result);
182 } 182 }
183 183
184 private void HandleUndeliveredMessage(GridInstantMessage im, MessageResultNotification result) 184 public void HandleUndeliverableMessage(GridInstantMessage im, MessageResultNotification result)
185 { 185 {
186 UndeliveredMessage handlerUndeliveredMessage = OnUndeliveredMessage; 186 UndeliveredMessage handlerUndeliveredMessage = OnUndeliveredMessage;
187 187
@@ -372,7 +372,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
372 gim.fromAgentName = fromAgentName; 372 gim.fromAgentName = fromAgentName;
373 gim.fromGroup = fromGroup; 373 gim.fromGroup = fromGroup;
374 gim.imSessionID = imSessionID.Guid; 374 gim.imSessionID = imSessionID.Guid;
375 gim.RegionID = UUID.Zero.Guid; // RegionID.Guid; 375 gim.RegionID = RegionID.Guid;
376 gim.timestamp = timestamp; 376 gim.timestamp = timestamp;
377 gim.toAgentID = toAgentID.Guid; 377 gim.toAgentID = toAgentID.Guid;
378 gim.message = message; 378 gim.message = message;
@@ -428,7 +428,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
428 /// <summary> 428 /// <summary>
429 /// delegate for sending a grid instant message asynchronously 429 /// delegate for sending a grid instant message asynchronously
430 /// </summary> 430 /// </summary>
431 public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID); 431 public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result);
432 432
433 protected virtual void GridInstantMessageCompleted(IAsyncResult iar) 433 protected virtual void GridInstantMessageCompleted(IAsyncResult iar)
434 { 434 {
@@ -442,138 +442,87 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
442 { 442 {
443 GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync; 443 GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync;
444 444
445 d.BeginInvoke(im, result, UUID.Zero, GridInstantMessageCompleted, d); 445 d.BeginInvoke(im, result, GridInstantMessageCompleted, d);
446 } 446 }
447 447
448 /// <summary> 448 /// <summary>
449 /// Recursive SendGridInstantMessage over XMLRPC method. 449 /// Internal SendGridInstantMessage over XMLRPC method.
450 /// This is called from within a dedicated thread.
451 /// The first time this is called, prevRegionHandle will be 0 Subsequent times this is called from
452 /// itself, prevRegionHandle will be the last region handle that we tried to send.
453 /// If the handles are the same, we look up the user's location using the grid.
454 /// If the handles are still the same, we end. The send failed.
455 /// </summary> 450 /// </summary>
456 /// <param name="prevRegionHandle"> 451 /// <remarks>
457 /// Pass in 0 the first time this method is called. It will be called recursively with the last 452 /// This is called from within a dedicated thread.
458 /// regionhandle tried 453 /// </remarks>
459 /// </param> 454 private void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result)
460 protected virtual void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID)
461 { 455 {
462 UUID toAgentID = new UUID(im.toAgentID); 456 UUID toAgentID = new UUID(im.toAgentID);
463 457 UUID regionID;
464 PresenceInfo upd = null; 458 bool needToLookupAgent;
465
466 bool lookupAgent = false;
467 459
468 lock (m_UserRegionMap) 460 lock (m_UserRegionMap)
461 needToLookupAgent = !m_UserRegionMap.TryGetValue(toAgentID, out regionID);
462
463 while (true)
469 { 464 {
470 if (m_UserRegionMap.ContainsKey(toAgentID)) 465 if (needToLookupAgent)
471 { 466 {
472 upd = new PresenceInfo(); 467 PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() });
473 upd.RegionID = m_UserRegionMap[toAgentID];
474 468
475 // We need to compare the current regionhandle with the previous region handle 469 UUID foundRegionID = UUID.Zero;
476 // or the recursive loop will never end because it will never try to lookup the agent again
477 if (prevRegionID == upd.RegionID)
478 {
479 lookupAgent = true;
480 }
481 }
482 else
483 {
484 lookupAgent = true;
485 }
486 }
487
488 470
489 // Are we needing to look-up an agent? 471 if (presences != null)
490 if (lookupAgent)
491 {
492 // Non-cached user agent lookup.
493 PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() });
494 if (presences != null && presences.Length > 0)
495 {
496 foreach (PresenceInfo p in presences)
497 { 472 {
498 if (p.RegionID != UUID.Zero) 473 foreach (PresenceInfo p in presences)
499 { 474 {
500 upd = p; 475 if (p.RegionID != UUID.Zero)
501 break; 476 {
477 foundRegionID = p.RegionID;
478 break;
479 }
502 } 480 }
503 } 481 }
504 }
505 482
506 if (upd != null) 483 // If not found or the found region is the same as the last lookup, then message is undeliverable
507 { 484 if (foundRegionID == UUID.Zero || foundRegionID == regionID)
508 // check if we've tried this before.. 485 break;
509 // This is one way to end the recursive loop 486 else
510 // 487 regionID = foundRegionID;
511 if (upd.RegionID == prevRegionID)
512 {
513 // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
514 HandleUndeliveredMessage(im, result);
515 return;
516 }
517 } 488 }
518 else 489
490 GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, regionID);
491 if (reginfo == null)
519 { 492 {
520 // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); 493 m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", regionID);
521 HandleUndeliveredMessage(im, result); 494 break;
522 return;
523 } 495 }
524 }
525 496
526 if (upd != null) 497 // Try to send the message to the agent via the retrieved region.
527 { 498 Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im);
528 GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, 499 msgdata["region_handle"] = 0;
529 upd.RegionID); 500 bool imresult = doIMSending(reginfo, msgdata);
530 if (reginfo != null) 501
502 // If the message delivery was successful, then cache the entry.
503 if (imresult)
531 { 504 {
532 Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im); 505 lock (m_UserRegionMap)
533 // Not actually used anymore, left in for compatibility
534 // Remove at next interface change
535 //
536 msgdata["region_handle"] = 0;
537 bool imresult = doIMSending(reginfo, msgdata);
538 if (imresult)
539 {
540 // IM delivery successful, so store the Agent's location in our local cache.
541 lock (m_UserRegionMap)
542 {
543 if (m_UserRegionMap.ContainsKey(toAgentID))
544 {
545 m_UserRegionMap[toAgentID] = upd.RegionID;
546 }
547 else
548 {
549 m_UserRegionMap.Add(toAgentID, upd.RegionID);
550 }
551 }
552 result(true);
553 }
554 else
555 { 506 {
556 // try again, but lookup user this time. 507 m_UserRegionMap[toAgentID] = regionID;
557 // Warning, this must call the Async version
558 // of this method or we'll be making thousands of threads
559 // The version within the spawned thread is SendGridInstantMessageViaXMLRPCAsync
560 // The version that spawns the thread is SendGridInstantMessageViaXMLRPC
561
562 // This is recursive!!!!!
563 SendGridInstantMessageViaXMLRPCAsync(im, result,
564 upd.RegionID);
565 } 508 }
509 result(true);
510 return;
566 } 511 }
567 else 512
568 { 513 // If we reach this point in the first iteration of the while, then we may have unsuccessfully tried
569 m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", upd.RegionID); 514 // to use a locally cached region ID. All subsequent attempts need to lookup agent details from
570 HandleUndeliveredMessage(im, result); 515 // the presence service.
571 } 516 needToLookupAgent = true;
572 }
573 else
574 {
575 HandleUndeliveredMessage(im, result);
576 } 517 }
518
519 // If we reached this point then the message was not deliverable. Remove the bad cache entry and
520 // signal the delivery failure.
521 lock (m_UserRegionMap)
522 m_UserRegionMap.Remove(toAgentID);
523
524 // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
525 HandleUndeliverableMessage(im, result);
577 } 526 }
578 527
579 /// <summary> 528 /// <summary>
@@ -584,7 +533,6 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
584 /// <returns>Bool if the message was successfully delivered at the other side.</returns> 533 /// <returns>Bool if the message was successfully delivered at the other side.</returns>
585 protected virtual bool doIMSending(GridRegion reginfo, Hashtable xmlrpcdata) 534 protected virtual bool doIMSending(GridRegion reginfo, Hashtable xmlrpcdata)
586 { 535 {
587
588 ArrayList SendParams = new ArrayList(); 536 ArrayList SendParams = new ArrayList();
589 SendParams.Add(xmlrpcdata); 537 SendParams.Add(xmlrpcdata);
590 XmlRpcRequest GridReq = new XmlRpcRequest("grid_instant_message", SendParams); 538 XmlRpcRequest GridReq = new XmlRpcRequest("grid_instant_message", SendParams);
@@ -672,7 +620,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
672 gim["position_x"] = msg.Position.X.ToString(); 620 gim["position_x"] = msg.Position.X.ToString();
673 gim["position_y"] = msg.Position.Y.ToString(); 621 gim["position_y"] = msg.Position.Y.ToString();
674 gim["position_z"] = msg.Position.Z.ToString(); 622 gim["position_z"] = msg.Position.Z.ToString();
675 gim["region_id"] = msg.RegionID.ToString(); 623 gim["region_id"] = new UUID(msg.RegionID).ToString();
676 gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket,Base64FormattingOptions.None); 624 gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket,Base64FormattingOptions.None);
677 return gim; 625 return gim;
678 } 626 }
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs
index 7ce2813..315d372 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs
@@ -32,7 +32,6 @@ using Nini.Config;
32using Mono.Addins; 32using Mono.Addins;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenSim.Framework.Communications;
36using OpenSim.Framework.Servers; 35using OpenSim.Framework.Servers;
37using OpenSim.Framework.Client; 36using OpenSim.Framework.Client;
38using OpenSim.Region.Framework.Interfaces; 37using OpenSim.Region.Framework.Interfaces;
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
index 7d763fa..9cdb1c2 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
@@ -32,7 +32,6 @@ using Mono.Addins;
32using Nini.Config; 32using Nini.Config;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenSim.Framework.Communications;
36using OpenSim.Framework.Servers; 35using OpenSim.Framework.Servers;
37using OpenSim.Framework.Client; 36using OpenSim.Framework.Client;
38using OpenSim.Region.Framework.Interfaces; 37using OpenSim.Region.Framework.Interfaces;
@@ -182,7 +181,10 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
182 "POST", m_RestURL + "/RetrieveMessages/", client.AgentId); 181 "POST", m_RestURL + "/RetrieveMessages/", client.AgentId);
183 182
184 if (msglist == null) 183 if (msglist == null)
184 {
185 m_log.WarnFormat("[OFFLINE MESSAGING]: WARNING null message list."); 185 m_log.WarnFormat("[OFFLINE MESSAGING]: WARNING null message list.");
186 return;
187 }
186 188
187 foreach (GridInstantMessage im in msglist) 189 foreach (GridInstantMessage im in msglist)
188 { 190 {
@@ -223,12 +225,8 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
223 return; 225 return;
224 } 226 }
225 227
226 Scene scene = FindScene(new UUID(im.fromAgentID));
227 if (scene == null)
228 scene = m_SceneList[0];
229
230 bool success = SynchronousRestObjectRequester.MakeRequest<GridInstantMessage, bool>( 228 bool success = SynchronousRestObjectRequester.MakeRequest<GridInstantMessage, bool>(
231 "POST", m_RestURL+"/SaveMessage/", im); 229 "POST", m_RestURL+"/SaveMessage/", im, 10000);
232 230
233 if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent) 231 if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent)
234 { 232 {
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs
index 4c678c2..c2440d8 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs
@@ -49,8 +49,10 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
49 private static readonly ILog m_log = LogManager.GetLogger( 49 private static readonly ILog m_log = LogManager.GetLogger(
50 MethodBase.GetCurrentMethod().DeclaringType); 50 MethodBase.GetCurrentMethod().DeclaringType);
51 51
52#pragma warning disable 0067
52 public event PresenceChange OnPresenceChange; 53 public event PresenceChange OnPresenceChange;
53 public event BulkPresenceData OnBulkPresenceData; 54 public event BulkPresenceData OnBulkPresenceData;
55#pragma warning restore 0067
54 56
55 protected List<Scene> m_Scenes = new List<Scene>(); 57 protected List<Scene> m_Scenes = new List<Scene>();
56 58
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
index ecbd07f..4a06fd1 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
@@ -61,16 +61,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
61 61
62 private UserAccount m_userInfo; 62 private UserAccount m_userInfo;
63 private string m_invPath; 63 private string m_invPath;
64
65 /// <value>
66 /// ID of this request
67 /// </value>
68 protected UUID m_id;
64 69
65 /// <summary> 70 /// <summary>
66 /// Do we want to merge this load with existing inventory? 71 /// Do we want to merge this load with existing inventory?
67 /// </summary> 72 /// </summary>
68 protected bool m_merge; 73 protected bool m_merge;
69 74
70 /// <value> 75 protected IInventoryService m_InventoryService;
71 /// We only use this to request modules 76 protected IAssetService m_AssetService;
72 /// </value> 77 protected IUserAccountService m_UserAccountService;
73 protected Scene m_scene; 78
79 private InventoryArchiverModule m_module;
74 80
75 /// <value> 81 /// <value>
76 /// The stream from which the inventory archive will be loaded. 82 /// The stream from which the inventory archive will be loaded.
@@ -115,12 +121,29 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
115 /// Record the creator id that should be associated with an asset. This is used to adjust asset creator ids 121 /// Record the creator id that should be associated with an asset. This is used to adjust asset creator ids
116 /// after OSP resolution (since OSP creators are only stored in the item 122 /// after OSP resolution (since OSP creators are only stored in the item
117 /// </summary> 123 /// </summary>
118 protected Dictionary<UUID, UUID> m_creatorIdForAssetId = new Dictionary<UUID, UUID>(); 124 protected Dictionary<UUID, UUID> m_creatorIdForAssetId = new Dictionary<UUID, UUID>();
125
126 public InventoryArchiveReadRequest(
127 IInventoryService inv, IAssetService assets, IUserAccountService uacc, UserAccount userInfo, string invPath, string loadPath, bool merge)
128 : this(UUID.Zero, null,
129 inv,
130 assets,
131 uacc,
132 userInfo,
133 invPath,
134 loadPath,
135 merge)
136 {
137 }
119 138
120 public InventoryArchiveReadRequest( 139 public InventoryArchiveReadRequest(
121 Scene scene, UserAccount userInfo, string invPath, string loadPath, bool merge) 140 UUID id, InventoryArchiverModule module, IInventoryService inv, IAssetService assets, IUserAccountService uacc, UserAccount userInfo, string invPath, string loadPath, bool merge)
122 : this( 141 : this(
123 scene, 142 id,
143 module,
144 inv,
145 assets,
146 uacc,
124 userInfo, 147 userInfo,
125 invPath, 148 invPath,
126 new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress), 149 new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress),
@@ -129,13 +152,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
129 } 152 }
130 153
131 public InventoryArchiveReadRequest( 154 public InventoryArchiveReadRequest(
132 Scene scene, UserAccount userInfo, string invPath, Stream loadStream, bool merge) 155 UUID id, InventoryArchiverModule module, IInventoryService inv, IAssetService assets, IUserAccountService uacc, UserAccount userInfo, string invPath, Stream loadStream, bool merge)
133 { 156 {
134 m_scene = scene; 157 m_id = id;
158 m_InventoryService = inv;
159 m_AssetService = assets;
160 m_UserAccountService = uacc;
135 m_merge = merge; 161 m_merge = merge;
136 m_userInfo = userInfo; 162 m_userInfo = userInfo;
137 m_invPath = invPath; 163 m_invPath = invPath;
138 m_loadStream = loadStream; 164 m_loadStream = loadStream;
165 m_module = module;
139 166
140 // FIXME: Do not perform this check since older versions of OpenSim do save the control file after other things 167 // FIXME: Do not perform this check since older versions of OpenSim do save the control file after other things
141 // (I thought they weren't). We will need to bump the version number and perform this check on all 168 // (I thought they weren't). We will need to bump the version number and perform this check on all
@@ -158,11 +185,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
158 { 185 {
159 try 186 try
160 { 187 {
188 Exception reportedException = null;
189
161 string filePath = "ERROR"; 190 string filePath = "ERROR";
162 191
163 List<InventoryFolderBase> folderCandidates 192 List<InventoryFolderBase> folderCandidates
164 = InventoryArchiveUtils.FindFolderByPath( 193 = InventoryArchiveUtils.FindFoldersByPath(
165 m_scene.InventoryService, m_userInfo.PrincipalID, m_invPath); 194 m_InventoryService, m_userInfo.PrincipalID, m_invPath);
166 195
167 if (folderCandidates.Count == 0) 196 if (folderCandidates.Count == 0)
168 { 197 {
@@ -194,14 +223,25 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
194 } 223 }
195 224
196 archive.Close(); 225 archive.Close();
197 226
198 m_log.DebugFormat( 227 m_log.DebugFormat(
199 "[INVENTORY ARCHIVER]: Successfully loaded {0} assets with {1} failures", 228 "[INVENTORY ARCHIVER]: Successfully loaded {0} assets with {1} failures",
200 m_successfulAssetRestores, m_failedAssetRestores); 229 m_successfulAssetRestores, m_failedAssetRestores);
201 m_log.InfoFormat("[INVENTORY ARCHIVER]: Successfully loaded {0} items", m_successfulItemRestores); 230
231 //Alicia: When this is called by LibraryModule or Tests, m_module will be null as event is not required
232 if(m_module != null)
233 m_module.TriggerInventoryArchiveLoaded(m_id, true, m_userInfo, m_invPath, m_loadStream, reportedException, m_successfulItemRestores);
202 234
203 return m_loadedNodes; 235 return m_loadedNodes;
204 } 236 }
237 catch(Exception Ex)
238 {
239 // Trigger saved event with failed result and exception data
240 if (m_module != null)
241 m_module.TriggerInventoryArchiveLoaded(m_id, false, m_userInfo, m_invPath, m_loadStream, Ex, 0);
242
243 return m_loadedNodes;
244 }
205 finally 245 finally
206 { 246 {
207 m_loadStream.Close(); 247 m_loadStream.Close();
@@ -296,8 +336,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
296 // iar name and try to find that instead. 336 // iar name and try to find that instead.
297 string plainPath = ArchiveConstants.ExtractPlainPathFromIarPath(archivePath); 337 string plainPath = ArchiveConstants.ExtractPlainPathFromIarPath(archivePath);
298 List<InventoryFolderBase> folderCandidates 338 List<InventoryFolderBase> folderCandidates
299 = InventoryArchiveUtils.FindFolderByPath( 339 = InventoryArchiveUtils.FindFoldersByPath(
300 m_scene.InventoryService, m_userInfo.PrincipalID, plainPath); 340 m_InventoryService, m_userInfo.PrincipalID, plainPath);
301 341
302 if (folderCandidates.Count != 0) 342 if (folderCandidates.Count != 0)
303 { 343 {
@@ -372,15 +412,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
372 newFolderName = InventoryArchiveUtils.UnescapeArchivePath(newFolderName); 412 newFolderName = InventoryArchiveUtils.UnescapeArchivePath(newFolderName);
373 UUID newFolderId = UUID.Random(); 413 UUID newFolderId = UUID.Random();
374 414
375 // Asset type has to be Unknown here rather than Folder, otherwise the created folder can't be
376 // deleted once the client has relogged.
377 // The root folder appears to be labelled AssetType.Folder (shows up as "Category" in the client)
378 // even though there is a AssetType.RootCategory
379 destFolder 415 destFolder
380 = new InventoryFolderBase( 416 = new InventoryFolderBase(
381 newFolderId, newFolderName, m_userInfo.PrincipalID, 417 newFolderId, newFolderName, m_userInfo.PrincipalID,
382 (short)AssetType.Unknown, destFolder.ID, 1); 418 (short)FolderType.None, destFolder.ID, 1);
383 m_scene.InventoryService.AddFolder(destFolder); 419 m_InventoryService.AddFolder(destFolder);
384 420
385 // Record that we have now created this folder 421 // Record that we have now created this folder
386 iarPathExisting += rawDirsToCreate[i] + "/"; 422 iarPathExisting += rawDirsToCreate[i] + "/";
@@ -406,7 +442,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
406 // Don't use the item ID that's in the file 442 // Don't use the item ID that's in the file
407 item.ID = UUID.Random(); 443 item.ID = UUID.Random();
408 444
409 UUID ospResolvedId = OspResolver.ResolveOspa(item.CreatorId, m_scene.UserAccountService); 445 UUID ospResolvedId = OspResolver.ResolveOspa(item.CreatorId, m_UserAccountService);
410 if (UUID.Zero != ospResolvedId) // The user exists in this grid 446 if (UUID.Zero != ospResolvedId) // The user exists in this grid
411 { 447 {
412// m_log.DebugFormat("[INVENTORY ARCHIVER]: Found creator {0} via OSPA resolution", ospResolvedId); 448// m_log.DebugFormat("[INVENTORY ARCHIVER]: Found creator {0} via OSPA resolution", ospResolvedId);
@@ -418,7 +454,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
418 item.CreatorId = ospResolvedId.ToString(); 454 item.CreatorId = ospResolvedId.ToString();
419 item.CreatorData = string.Empty; 455 item.CreatorData = string.Empty;
420 } 456 }
421 else if (item.CreatorData == null || item.CreatorData == String.Empty) 457 else if (string.IsNullOrEmpty(item.CreatorData))
422 { 458 {
423 item.CreatorId = m_userInfo.PrincipalID.ToString(); 459 item.CreatorId = m_userInfo.PrincipalID.ToString();
424// item.CreatorIdAsUuid = new UUID(item.CreatorId); 460// item.CreatorIdAsUuid = new UUID(item.CreatorId);
@@ -436,7 +472,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
436 // relying on native tar tools. 472 // relying on native tar tools.
437 m_creatorIdForAssetId[item.AssetID] = item.CreatorIdAsUuid; 473 m_creatorIdForAssetId[item.AssetID] = item.CreatorIdAsUuid;
438 474
439 m_scene.AddInventoryItem(item); 475 if (!m_InventoryService.AddItem(item))
476 m_log.WarnFormat("[INVENTORY ARCHIVER]: Unable to save item {0} in folder {1}", item.Name, item.Folder);
440 477
441 return item; 478 return item;
442 } 479 }
@@ -479,52 +516,24 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
479 { 516 {
480 if (m_creatorIdForAssetId.ContainsKey(assetId)) 517 if (m_creatorIdForAssetId.ContainsKey(assetId))
481 { 518 {
482 string xmlData = Utils.BytesToString(data); 519 data = SceneObjectSerializer.ModifySerializedObject(assetId, data,
483 List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>(); 520 sog => {
521 bool modified = false;
522
523 foreach (SceneObjectPart sop in sog.Parts)
524 {
525 if (string.IsNullOrEmpty(sop.CreatorData))
526 {
527 sop.CreatorID = m_creatorIdForAssetId[assetId];
528 modified = true;
529 }
530 }
531
532 return modified;
533 });
484 534
485 CoalescedSceneObjects coa = null; 535 if (data == null)
486 if (CoalescedSceneObjectsSerializer.TryFromXml(xmlData, out coa)) 536 return false;
487 {
488// m_log.DebugFormat(
489// "[INVENTORY ARCHIVER]: Loaded coalescence {0} has {1} objects", assetId, coa.Count);
490
491 if (coa.Objects.Count == 0)
492 {
493 m_log.WarnFormat(
494 "[INVENTORY ARCHIVE READ REQUEST]: Aborting load of coalesced object from asset {0} as it has zero loaded components",
495 assetId);
496 return false;
497 }
498
499 sceneObjects.AddRange(coa.Objects);
500 }
501 else
502 {
503 SceneObjectGroup deserializedObject = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
504
505 if (deserializedObject != null)
506 {
507 sceneObjects.Add(deserializedObject);
508 }
509 else
510 {
511 m_log.WarnFormat(
512 "[INVENTORY ARCHIVE READ REQUEST]: Aborting load of object from asset {0} as deserialization failed",
513 assetId);
514
515 return false;
516 }
517 }
518
519 foreach (SceneObjectGroup sog in sceneObjects)
520 foreach (SceneObjectPart sop in sog.Parts)
521 if (sop.CreatorData == null || sop.CreatorData == "")
522 sop.CreatorID = m_creatorIdForAssetId[assetId];
523
524 if (coa != null)
525 data = Utils.StringToBytes(CoalescedSceneObjectsSerializer.ToXml(coa));
526 else
527 data = Utils.StringToBytes(SceneObjectSerializer.ToOriginalXmlFormat(sceneObjects[0]));
528 } 537 }
529 } 538 }
530 539
@@ -533,7 +542,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
533 AssetBase asset = new AssetBase(assetId, "From IAR", assetType, UUID.Zero.ToString()); 542 AssetBase asset = new AssetBase(assetId, "From IAR", assetType, UUID.Zero.ToString());
534 asset.Data = data; 543 asset.Data = data;
535 544
536 m_scene.AssetService.Store(asset); 545 m_AssetService.Store(asset);
537 546
538 return true; 547 return true;
539 } 548 }
@@ -546,7 +555,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
546 return false; 555 return false;
547 } 556 }
548 } 557 }
549 558
550 /// <summary> 559 /// <summary>
551 /// Load control file 560 /// Load control file
552 /// </summary> 561 /// </summary>
@@ -652,4 +661,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
652 m_assetsLoaded = true; 661 m_assetsLoaded = true;
653 } 662 }
654 } 663 }
655} \ No newline at end of file 664}
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs
index 0d90a15..dbaf2aa 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveUtils.cs
@@ -52,13 +52,82 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
52 /// <summary> 52 /// <summary>
53 /// Find a folder given a PATH_DELIMITER delimited path starting from a user's root folder 53 /// Find a folder given a PATH_DELIMITER delimited path starting from a user's root folder
54 /// </summary> 54 /// </summary>
55 /// <remarks>
56 /// This method does not handle paths that contain multiple delimitors
57 ///
58 /// FIXME: We have no way of distinguishing folders with the same path
55 /// 59 ///
60 /// FIXME: Delimitors which occur in names themselves are not currently escapable.
61 /// </remarks>
62 /// <param name="inventoryService">
63 /// Inventory service to query
64 /// </param>
65 /// <param name="userId">
66 /// User id to search
67 /// </param>
68 /// <param name="path">
69 /// The path to the required folder.
70 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned.
71 /// </param>
72 /// <returns>The folder found. Please note that if there are multiple folders with the same name then an
73 /// unspecified one will be returned. If no such folder eixsts then null is returned</returns>
74 public static InventoryFolderBase FindFolderByPath(
75 IInventoryService inventoryService, UUID userId, string path)
76 {
77 List<InventoryFolderBase> folders = FindFoldersByPath(inventoryService, userId, path);
78
79 if (folders.Count == 0)
80 return null;
81 else
82 return folders[0];
83 }
84
85 /// <summary>
86 /// Find a folder given a PATH_DELIMITER delimited path starting from a given folder
87 /// </summary>
88 /// <remarks>
56 /// This method does not handle paths that contain multiple delimitors 89 /// This method does not handle paths that contain multiple delimitors
57 /// 90 ///
58 /// FIXME: We have no way of distinguishing folders with the same path 91 /// FIXME: We have no way of distinguishing folders with the same path
59 /// 92 ///
60 /// FIXME: Delimitors which occur in names themselves are not currently escapable. 93 /// FIXME: Delimitors which occur in names themselves are not currently escapable.
94 /// </remarks>
95 /// <param name="inventoryService">
96 /// Inventory service to query
97 /// </param>
98 /// <param name="startFolder">
99 /// The folder from which the path starts
100 /// </param>
101 /// <param name="path">
102 /// The path to the required folder.
103 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned.
104 /// </param>
105 /// <returns>The folder found. Please note that if there are multiple folders with the same name then an
106 /// unspecified one will be returned. If no such folder eixsts then null is returned</returns>
107 public static InventoryFolderBase FindFolderByPath(
108 IInventoryService inventoryService, InventoryFolderBase startFolder, string path)
109 {
110 if (null == startFolder)
111 return null;
112
113 List<InventoryFolderBase> folders = FindFoldersByPath(inventoryService, startFolder, path);
114
115 if (folders.Count == 0)
116 return null;
117 else
118 return folders[0];
119 }
120
121 /// <summary>
122 /// Find a set of folders given a PATH_DELIMITER delimited path starting from a user's root folder
123 /// </summary>
124 /// <remarks>
125 /// This method does not handle paths that contain multiple delimitors
126 ///
127 /// FIXME: We have no way of distinguishing folders with the same path
61 /// 128 ///
129 /// FIXME: Delimitors which occur in names themselves are not currently escapable.
130 /// </remarks>
62 /// <param name="inventoryService"> 131 /// <param name="inventoryService">
63 /// Inventory service to query 132 /// Inventory service to query
64 /// </param> 133 /// </param>
@@ -70,7 +139,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
70 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned. 139 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned.
71 /// </param> 140 /// </param>
72 /// <returns>An empty list if the folder is not found, otherwise a list of all folders that match the name</returns> 141 /// <returns>An empty list if the folder is not found, otherwise a list of all folders that match the name</returns>
73 public static List<InventoryFolderBase> FindFolderByPath( 142 public static List<InventoryFolderBase> FindFoldersByPath(
74 IInventoryService inventoryService, UUID userId, string path) 143 IInventoryService inventoryService, UUID userId, string path)
75 { 144 {
76 InventoryFolderBase rootFolder = inventoryService.GetRootFolder(userId); 145 InventoryFolderBase rootFolder = inventoryService.GetRootFolder(userId);
@@ -78,19 +147,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
78 if (null == rootFolder) 147 if (null == rootFolder)
79 return new List<InventoryFolderBase>(); 148 return new List<InventoryFolderBase>();
80 149
81 return FindFolderByPath(inventoryService, rootFolder, path); 150 return FindFoldersByPath(inventoryService, rootFolder, path);
82 } 151 }
83 152
84 /// <summary> 153 /// <summary>
85 /// Find a folder given a PATH_DELIMITER delimited path starting from this folder 154 /// Find a set of folders given a PATH_DELIMITER delimited path starting from this folder
86 /// </summary> 155 /// </summary>
87 /// 156 /// <remarks>
88 /// This method does not handle paths that contain multiple delimitors 157 /// This method does not handle paths that contain multiple delimitors
89 /// 158 ///
90 /// FIXME: We have no way of distinguishing folders with the same path. 159 /// FIXME: We have no way of distinguishing folders with the same path.
91 /// 160 ///
92 /// FIXME: Delimitors which occur in names themselves are not currently escapable. 161 /// FIXME: Delimitors which occur in names themselves are not currently escapable.
93 /// 162 /// </remarks>
94 /// <param name="inventoryService"> 163 /// <param name="inventoryService">
95 /// Inventory service to query 164 /// Inventory service to query
96 /// </param> 165 /// </param>
@@ -102,7 +171,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
102 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned. 171 /// It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned.
103 /// </param> 172 /// </param>
104 /// <returns>An empty list if the folder is not found, otherwise a list of all folders that match the name</returns> 173 /// <returns>An empty list if the folder is not found, otherwise a list of all folders that match the name</returns>
105 public static List<InventoryFolderBase> FindFolderByPath( 174 public static List<InventoryFolderBase> FindFoldersByPath(
106 IInventoryService inventoryService, InventoryFolderBase startFolder, string path) 175 IInventoryService inventoryService, InventoryFolderBase startFolder, string path)
107 { 176 {
108 List<InventoryFolderBase> foundFolders = new List<InventoryFolderBase>(); 177 List<InventoryFolderBase> foundFolders = new List<InventoryFolderBase>();
@@ -133,12 +202,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
133 202
134 InventoryCollection contents = inventoryService.GetFolderContent(startFolder.Owner, startFolder.ID); 203 InventoryCollection contents = inventoryService.GetFolderContent(startFolder.Owner, startFolder.ID);
135 204
205// m_log.DebugFormat(
206// "Found {0} folders in {1} for {2}", contents.Folders.Count, startFolder.Name, startFolder.Owner);
207
136 foreach (InventoryFolderBase folder in contents.Folders) 208 foreach (InventoryFolderBase folder in contents.Folders)
137 { 209 {
138 if (folder.Name == components[0]) 210 if (folder.Name == components[0])
139 { 211 {
140 if (components.Length > 1) 212 if (components.Length > 1)
141 foundFolders.AddRange(FindFolderByPath(inventoryService, folder, components[1])); 213 foundFolders.AddRange(FindFoldersByPath(inventoryService, folder, components[1]));
142 else 214 else
143 foundFolders.Add(folder); 215 foundFolders.Add(folder);
144 } 216 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
index d0e88f6..f002ad7 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
@@ -34,6 +34,7 @@ using System.Xml;
34using log4net; 34using log4net;
35using OpenMetaverse; 35using OpenMetaverse;
36using OpenSim.Framework; 36using OpenSim.Framework;
37using OpenSim.Framework.Monitoring;
37using OpenSim.Framework.Serialization; 38using OpenSim.Framework.Serialization;
38using OpenSim.Framework.Serialization.External; 39using OpenSim.Framework.Serialization.External;
39using OpenSim.Region.CoreModules.World.Archiver; 40using OpenSim.Region.CoreModules.World.Archiver;
@@ -42,6 +43,8 @@ using OpenSim.Services.Interfaces;
42using Ionic.Zlib; 43using Ionic.Zlib;
43using GZipStream = Ionic.Zlib.GZipStream; 44using GZipStream = Ionic.Zlib.GZipStream;
44using CompressionMode = Ionic.Zlib.CompressionMode; 45using CompressionMode = Ionic.Zlib.CompressionMode;
46using CompressionLevel = Ionic.Zlib.CompressionLevel;
47using PermissionMask = OpenSim.Framework.PermissionMask;
45 48
46namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver 49namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
47{ 50{
@@ -54,6 +57,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
54 /// </summary> 57 /// </summary>
55 public bool SaveAssets { get; set; } 58 public bool SaveAssets { get; set; }
56 59
60 /// <summary>
61 /// Determines which items will be included in the archive, according to their permissions.
62 /// Default is null, meaning no permission checks.
63 /// </summary>
64 public string FilterContent { get; set; }
65
66 /// <summary>
67 /// Counter for inventory items saved to archive for passing to compltion event
68 /// </summary>
69 public int CountItems { get; set; }
70
71 /// <summary>
72 /// Counter for inventory items skipped due to permission filter option for passing to compltion event
73 /// </summary>
74 public int CountFiltered { get; set; }
75
57 /// <value> 76 /// <value>
58 /// Used to select all inventory nodes in a folder but not the folder itself 77 /// Used to select all inventory nodes in a folder but not the folder itself
59 /// </value> 78 /// </value>
@@ -73,12 +92,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
73 /// <value> 92 /// <value>
74 /// ID of this request 93 /// ID of this request
75 /// </value> 94 /// </value>
76 protected Guid m_id; 95 protected UUID m_id;
77
78 /// <value>
79 /// Used to collect the uuids of the assets that we need to save into the archive
80 /// </value>
81 protected Dictionary<UUID, AssetType> m_assetUuids = new Dictionary<UUID, AssetType>();
82 96
83 /// <value> 97 /// <value>
84 /// Used to collect the uuids of the users that we need to save into the archive 98 /// Used to collect the uuids of the users that we need to save into the archive
@@ -94,7 +108,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
94 /// Constructor 108 /// Constructor
95 /// </summary> 109 /// </summary>
96 public InventoryArchiveWriteRequest( 110 public InventoryArchiveWriteRequest(
97 Guid id, InventoryArchiverModule module, Scene scene, 111 UUID id, InventoryArchiverModule module, Scene scene,
98 UserAccount userInfo, string invPath, string savePath) 112 UserAccount userInfo, string invPath, string savePath)
99 : this( 113 : this(
100 id, 114 id,
@@ -110,7 +124,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
110 /// Constructor 124 /// Constructor
111 /// </summary> 125 /// </summary>
112 public InventoryArchiveWriteRequest( 126 public InventoryArchiveWriteRequest(
113 Guid id, InventoryArchiverModule module, Scene scene, 127 UUID id, InventoryArchiverModule module, Scene scene,
114 UserAccount userInfo, string invPath, Stream saveStream) 128 UserAccount userInfo, string invPath, Stream saveStream)
115 { 129 {
116 m_id = id; 130 m_id = id;
@@ -122,9 +136,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
122 m_assetGatherer = new UuidGatherer(m_scene.AssetService); 136 m_assetGatherer = new UuidGatherer(m_scene.AssetService);
123 137
124 SaveAssets = true; 138 SaveAssets = true;
139 FilterContent = null;
125 } 140 }
126 141
127 protected void ReceivedAllAssets(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids) 142 protected void ReceivedAllAssets(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids, bool timedOut)
128 { 143 {
129 Exception reportedException = null; 144 Exception reportedException = null;
130 bool succeeded = true; 145 bool succeeded = true;
@@ -143,8 +158,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
143 m_saveStream.Close(); 158 m_saveStream.Close();
144 } 159 }
145 160
161 if (timedOut)
162 {
163 succeeded = false;
164 reportedException = new Exception("Loading assets timed out");
165 }
166
146 m_module.TriggerInventoryArchiveSaved( 167 m_module.TriggerInventoryArchiveSaved(
147 m_id, succeeded, m_userInfo, m_invPath, m_saveStream, reportedException); 168 m_id, succeeded, m_userInfo, m_invPath, m_saveStream, reportedException, CountItems, CountFiltered);
148 } 169 }
149 170
150 protected void SaveInvItem(InventoryItemBase inventoryItem, string path, Dictionary<string, object> options, IUserAccountService userAccountService) 171 protected void SaveInvItem(InventoryItemBase inventoryItem, string path, Dictionary<string, object> options, IUserAccountService userAccountService)
@@ -160,10 +181,26 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
160 "[INVENTORY ARCHIVER]: Skipping inventory item {0} {1} at {2}", 181 "[INVENTORY ARCHIVER]: Skipping inventory item {0} {1} at {2}",
161 inventoryItem.Name, inventoryItem.ID, path); 182 inventoryItem.Name, inventoryItem.ID, path);
162 } 183 }
184
185 CountFiltered++;
186
163 return; 187 return;
164 } 188 }
165 } 189 }
166 190
191 // Check For Permissions Filter Flags
192 if (!CanUserArchiveObject(m_userInfo.PrincipalID, inventoryItem))
193 {
194 m_log.InfoFormat(
195 "[INVENTORY ARCHIVER]: Insufficient permissions, skipping inventory item {0} {1} at {2}",
196 inventoryItem.Name, inventoryItem.ID, path);
197
198 // Count Items Excluded
199 CountFiltered++;
200
201 return;
202 }
203
167 if (options.ContainsKey("verbose")) 204 if (options.ContainsKey("verbose"))
168 m_log.InfoFormat( 205 m_log.InfoFormat(
169 "[INVENTORY ARCHIVER]: Saving item {0} {1} (asset UUID {2})", 206 "[INVENTORY ARCHIVER]: Saving item {0} {1} (asset UUID {2})",
@@ -179,9 +216,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
179 216
180 AssetType itemAssetType = (AssetType)inventoryItem.AssetType; 217 AssetType itemAssetType = (AssetType)inventoryItem.AssetType;
181 218
219 // Count inventory items (different to asset count)
220 CountItems++;
221
182 // Don't chase down link asset items as they actually point to their target item IDs rather than an asset 222 // Don't chase down link asset items as they actually point to their target item IDs rather than an asset
183 if (SaveAssets && itemAssetType != AssetType.Link && itemAssetType != AssetType.LinkFolder) 223 if (SaveAssets && itemAssetType != AssetType.Link && itemAssetType != AssetType.LinkFolder)
184 m_assetGatherer.GatherAssetUuids(inventoryItem.AssetID, (AssetType)inventoryItem.AssetType, m_assetUuids); 224 m_assetGatherer.AddForInspection(inventoryItem.AssetID);
185 } 225 }
186 226
187 /// <summary> 227 /// <summary>
@@ -237,6 +277,35 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
237 } 277 }
238 278
239 /// <summary> 279 /// <summary>
280 /// Checks whether the user has permission to export an inventory item to an IAR.
281 /// </summary>
282 /// <param name="UserID">The user</param>
283 /// <param name="InvItem">The inventory item</param>
284 /// <returns>Whether the user is allowed to export the object to an IAR</returns>
285 private bool CanUserArchiveObject(UUID UserID, InventoryItemBase InvItem)
286 {
287 if (FilterContent == null)
288 return true;// Default To Allow Export
289
290 bool permitted = true;
291
292 bool canCopy = (InvItem.CurrentPermissions & (uint)PermissionMask.Copy) != 0;
293 bool canTransfer = (InvItem.CurrentPermissions & (uint)PermissionMask.Transfer) != 0;
294 bool canMod = (InvItem.CurrentPermissions & (uint)PermissionMask.Modify) != 0;
295
296 if (FilterContent.Contains("C") && !canCopy)
297 permitted = false;
298
299 if (FilterContent.Contains("T") && !canTransfer)
300 permitted = false;
301
302 if (FilterContent.Contains("M") && !canMod)
303 permitted = false;
304
305 return permitted;
306 }
307
308 /// <summary>
240 /// Execute the inventory write request 309 /// Execute the inventory write request
241 /// </summary> 310 /// </summary>
242 public void Execute(Dictionary<string, object> options, IUserAccountService userAccountService) 311 public void Execute(Dictionary<string, object> options, IUserAccountService userAccountService)
@@ -244,6 +313,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
244 if (options.ContainsKey("noassets") && (bool)options["noassets"]) 313 if (options.ContainsKey("noassets") && (bool)options["noassets"])
245 SaveAssets = false; 314 SaveAssets = false;
246 315
316 // Set Permission filter if flag is set
317 if (options.ContainsKey("checkPermissions"))
318 {
319 Object temp;
320 if (options.TryGetValue("checkPermissions", out temp))
321 FilterContent = temp.ToString().ToUpper();
322 }
323
247 try 324 try
248 { 325 {
249 InventoryFolderBase inventoryFolder = null; 326 InventoryFolderBase inventoryFolder = null;
@@ -266,6 +343,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
266 saveFolderContentsOnly = true; 343 saveFolderContentsOnly = true;
267 maxComponentIndex--; 344 maxComponentIndex--;
268 } 345 }
346 else if (maxComponentIndex == -1)
347 {
348 // If the user has just specified "/", then don't save the root "My Inventory" folder. This is
349 // more intuitive then requiring the user to specify "/*" for this.
350 saveFolderContentsOnly = true;
351 }
269 352
270 m_invPath = String.Empty; 353 m_invPath = String.Empty;
271 for (int i = 0; i <= maxComponentIndex; i++) 354 for (int i = 0; i <= maxComponentIndex; i++)
@@ -283,7 +366,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
283 { 366 {
284 m_invPath = m_invPath.Remove(m_invPath.LastIndexOf(InventoryFolderImpl.PATH_DELIMITER)); 367 m_invPath = m_invPath.Remove(m_invPath.LastIndexOf(InventoryFolderImpl.PATH_DELIMITER));
285 List<InventoryFolderBase> candidateFolders 368 List<InventoryFolderBase> candidateFolders
286 = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, rootFolder, m_invPath); 369 = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, rootFolder, m_invPath);
287 if (candidateFolders.Count > 0) 370 if (candidateFolders.Count > 0)
288 inventoryFolder = candidateFolders[0]; 371 inventoryFolder = candidateFolders[0];
289 } 372 }
@@ -297,7 +380,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
297 // We couldn't find the path indicated 380 // We couldn't find the path indicated
298 string errorMessage = string.Format("Aborted save. Could not find inventory path {0}", m_invPath); 381 string errorMessage = string.Format("Aborted save. Could not find inventory path {0}", m_invPath);
299 Exception e = new InventoryArchiverException(errorMessage); 382 Exception e = new InventoryArchiverException(errorMessage);
300 m_module.TriggerInventoryArchiveSaved(m_id, false, m_userInfo, m_invPath, m_saveStream, e); 383 m_module.TriggerInventoryArchiveSaved(m_id, false, m_userInfo, m_invPath, m_saveStream, e, 0, 0);
301 throw e; 384 throw e;
302 } 385 }
303 386
@@ -335,22 +418,25 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
335 418
336 if (SaveAssets) 419 if (SaveAssets)
337 { 420 {
338 m_log.DebugFormat("[INVENTORY ARCHIVER]: Saving {0} assets for items", m_assetUuids.Count); 421 m_assetGatherer.GatherAll();
422
423 m_log.DebugFormat(
424 "[INVENTORY ARCHIVER]: Saving {0} assets for items", m_assetGatherer.GatheredUuids.Count);
339 425
340 AssetsRequest ar 426 AssetsRequest ar
341 = new AssetsRequest( 427 = new AssetsRequest(
342 new AssetsArchiver(m_archiveWriter), 428 new AssetsArchiver(m_archiveWriter),
343 m_assetUuids, m_scene.AssetService, 429 m_assetGatherer.GatheredUuids, m_scene.AssetService,
344 m_scene.UserAccountService, m_scene.RegionInfo.ScopeID, 430 m_scene.UserAccountService, m_scene.RegionInfo.ScopeID,
345 options, ReceivedAllAssets); 431 options, ReceivedAllAssets);
346 432
347 Util.FireAndForget(o => ar.Execute()); 433 WorkManager.RunInThread(o => ar.Execute(), null, string.Format("AssetsRequest ({0})", m_scene.Name));
348 } 434 }
349 else 435 else
350 { 436 {
351 m_log.DebugFormat("[INVENTORY ARCHIVER]: Not saving assets since --noassets was specified"); 437 m_log.DebugFormat("[INVENTORY ARCHIVER]: Not saving assets since --noassets was specified");
352 438
353 ReceivedAllAssets(new List<UUID>(), new List<UUID>()); 439 ReceivedAllAssets(new List<UUID>(), new List<UUID>(), false);
354 } 440 }
355 } 441 }
356 catch (Exception) 442 catch (Exception)
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs
index 849449b..8847414 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs
@@ -34,7 +34,6 @@ using NDesk.Options;
34using Nini.Config; 34using Nini.Config;
35using OpenMetaverse; 35using OpenMetaverse;
36using OpenSim.Framework; 36using OpenSim.Framework;
37using OpenSim.Framework.Communications;
38using OpenSim.Framework.Console; 37using OpenSim.Framework.Console;
39using OpenSim.Region.Framework.Interfaces; 38using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
@@ -57,6 +56,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
57// public bool DisablePresenceChecks { get; set; } 56// public bool DisablePresenceChecks { get; set; }
58 57
59 public event InventoryArchiveSaved OnInventoryArchiveSaved; 58 public event InventoryArchiveSaved OnInventoryArchiveSaved;
59 public event InventoryArchiveLoaded OnInventoryArchiveLoaded;
60 60
61 /// <summary> 61 /// <summary>
62 /// The file to load and save inventory if no filename has been specified 62 /// The file to load and save inventory if no filename has been specified
@@ -64,9 +64,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
64 protected const string DEFAULT_INV_BACKUP_FILENAME = "user-inventory.iar"; 64 protected const string DEFAULT_INV_BACKUP_FILENAME = "user-inventory.iar";
65 65
66 /// <value> 66 /// <value>
67 /// Pending save completions initiated from the console 67 /// Pending save and load completions initiated from the console
68 /// </value> 68 /// </value>
69 protected List<Guid> m_pendingConsoleSaves = new List<Guid>(); 69 protected List<UUID> m_pendingConsoleTasks = new List<UUID>();
70 70
71 /// <value> 71 /// <value>
72 /// All scenes that this module knows about 72 /// All scenes that this module knows about
@@ -111,6 +111,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
111 { 111 {
112 scene.RegisterModuleInterface<IInventoryArchiverModule>(this); 112 scene.RegisterModuleInterface<IInventoryArchiverModule>(this);
113 OnInventoryArchiveSaved += SaveInvConsoleCommandCompleted; 113 OnInventoryArchiveSaved += SaveInvConsoleCommandCompleted;
114 OnInventoryArchiveLoaded += LoadInvConsoleCommandCompleted;
114 115
115 scene.AddCommand( 116 scene.AddCommand(
116 "Archiving", this, "load iar", 117 "Archiving", this, "load iar",
@@ -139,7 +140,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
139 + "-e|--exclude=<name/uuid> don't save the inventory item in archive" + Environment.NewLine 140 + "-e|--exclude=<name/uuid> don't save the inventory item in archive" + Environment.NewLine
140 + "-f|--excludefolder=<folder/uuid> don't save contents of the folder in archive" + Environment.NewLine 141 + "-f|--excludefolder=<folder/uuid> don't save contents of the folder in archive" + Environment.NewLine
141 + "-v|--verbose extra debug messages.\n" 142 + "-v|--verbose extra debug messages.\n"
142 + "--noassets stops assets being saved to the IAR.", 143 + "--noassets stops assets being saved to the IAR."
144 + "--perm=<permissions> stops items with insufficient permissions from being saved to the IAR.\n"
145 + " <permissions> can contain one or more of these characters: \"C\" = Copy, \"T\" = Transfer, \"M\" = Modify.\n",
143 HandleSaveInvConsoleCommand); 146 HandleSaveInvConsoleCommand);
144 147
145 m_aScene = scene; 148 m_aScene = scene;
@@ -175,22 +178,34 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
175 /// Trigger the inventory archive saved event. 178 /// Trigger the inventory archive saved event.
176 /// </summary> 179 /// </summary>
177 protected internal void TriggerInventoryArchiveSaved( 180 protected internal void TriggerInventoryArchiveSaved(
178 Guid id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream, 181 UUID id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream,
179 Exception reportedException) 182 Exception reportedException, int SaveCount, int FilterCount)
180 { 183 {
181 InventoryArchiveSaved handlerInventoryArchiveSaved = OnInventoryArchiveSaved; 184 InventoryArchiveSaved handlerInventoryArchiveSaved = OnInventoryArchiveSaved;
182 if (handlerInventoryArchiveSaved != null) 185 if (handlerInventoryArchiveSaved != null)
183 handlerInventoryArchiveSaved(id, succeeded, userInfo, invPath, saveStream, reportedException); 186 handlerInventoryArchiveSaved(id, succeeded, userInfo, invPath, saveStream, reportedException, SaveCount , FilterCount);
187 }
188
189 /// <summary>
190 /// Trigger the inventory archive loaded event.
191 /// </summary>
192 protected internal void TriggerInventoryArchiveLoaded(
193 UUID id, bool succeeded, UserAccount userInfo, string invPath, Stream loadStream,
194 Exception reportedException, int LoadCount)
195 {
196 InventoryArchiveLoaded handlerInventoryArchiveLoaded = OnInventoryArchiveLoaded;
197 if (handlerInventoryArchiveLoaded != null)
198 handlerInventoryArchiveLoaded(id, succeeded, userInfo, invPath, loadStream, reportedException, LoadCount);
184 } 199 }
185 200
186 public bool ArchiveInventory( 201 public bool ArchiveInventory(
187 Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream) 202 UUID id, string firstName, string lastName, string invPath, string pass, Stream saveStream)
188 { 203 {
189 return ArchiveInventory(id, firstName, lastName, invPath, pass, saveStream, new Dictionary<string, object>()); 204 return ArchiveInventory(id, firstName, lastName, invPath, pass, saveStream, new Dictionary<string, object>());
190 } 205 }
191 206
192 public bool ArchiveInventory( 207 public bool ArchiveInventory(
193 Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream, 208 UUID id, string firstName, string lastName, string invPath, string pass, Stream saveStream,
194 Dictionary<string, object> options) 209 Dictionary<string, object> options)
195 { 210 {
196 if (m_scenes.Count > 0) 211 if (m_scenes.Count > 0)
@@ -230,7 +245,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
230 } 245 }
231 246
232 public bool ArchiveInventory( 247 public bool ArchiveInventory(
233 Guid id, string firstName, string lastName, string invPath, string pass, string savePath, 248 UUID id, string firstName, string lastName, string invPath, string pass, string savePath,
234 Dictionary<string, object> options) 249 Dictionary<string, object> options)
235 { 250 {
236// if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, savePath)) 251// if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, savePath))
@@ -272,13 +287,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
272 return false; 287 return false;
273 } 288 }
274 289
275 public bool DearchiveInventory(string firstName, string lastName, string invPath, string pass, Stream loadStream) 290 public bool DearchiveInventory(UUID id, string firstName, string lastName, string invPath, string pass, Stream loadStream)
276 { 291 {
277 return DearchiveInventory(firstName, lastName, invPath, pass, loadStream, new Dictionary<string, object>()); 292 return DearchiveInventory(id, firstName, lastName, invPath, pass, loadStream, new Dictionary<string, object>());
278 } 293 }
279 294
280 public bool DearchiveInventory( 295 public bool DearchiveInventory(
281 string firstName, string lastName, string invPath, string pass, Stream loadStream, 296 UUID id, string firstName, string lastName, string invPath, string pass, Stream loadStream,
282 Dictionary<string, object> options) 297 Dictionary<string, object> options)
283 { 298 {
284 if (m_scenes.Count > 0) 299 if (m_scenes.Count > 0)
@@ -294,7 +309,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
294 309
295 try 310 try
296 { 311 {
297 request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadStream, merge); 312 request = new InventoryArchiveReadRequest(id, this, m_aScene.InventoryService, m_aScene.AssetService, m_aScene.UserAccountService, userInfo, invPath, loadStream, merge);
298 } 313 }
299 catch (EntryPointNotFoundException e) 314 catch (EntryPointNotFoundException e)
300 { 315 {
@@ -326,7 +341,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
326 } 341 }
327 342
328 public bool DearchiveInventory( 343 public bool DearchiveInventory(
329 string firstName, string lastName, string invPath, string pass, string loadPath, 344 UUID id, string firstName, string lastName, string invPath, string pass, string loadPath,
330 Dictionary<string, object> options) 345 Dictionary<string, object> options)
331 { 346 {
332 if (m_scenes.Count > 0) 347 if (m_scenes.Count > 0)
@@ -342,7 +357,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
342 357
343 try 358 try
344 { 359 {
345 request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadPath, merge); 360 request = new InventoryArchiveReadRequest(id, this, m_aScene.InventoryService, m_aScene.AssetService, m_aScene.UserAccountService, userInfo, invPath, loadPath, merge);
346 } 361 }
347 catch (EntryPointNotFoundException e) 362 catch (EntryPointNotFoundException e)
348 { 363 {
@@ -378,6 +393,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
378 { 393 {
379 try 394 try
380 { 395 {
396 UUID id = UUID.Random();
397
381 Dictionary<string, object> options = new Dictionary<string, object>(); 398 Dictionary<string, object> options = new Dictionary<string, object>();
382 OptionSet optionSet = new OptionSet().Add("m|merge", delegate (string v) { options["merge"] = v != null; }); 399 OptionSet optionSet = new OptionSet().Add("m|merge", delegate (string v) { options["merge"] = v != null; });
383 400
@@ -400,10 +417,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
400 "[INVENTORY ARCHIVER]: Loading archive {0} to inventory path {1} for {2} {3}", 417 "[INVENTORY ARCHIVER]: Loading archive {0} to inventory path {1} for {2} {3}",
401 loadPath, invPath, firstName, lastName); 418 loadPath, invPath, firstName, lastName);
402 419
403 if (DearchiveInventory(firstName, lastName, invPath, pass, loadPath, options)) 420 lock (m_pendingConsoleTasks)
404 m_log.InfoFormat( 421 m_pendingConsoleTasks.Add(id);
405 "[INVENTORY ARCHIVER]: Loaded archive {0} for {1} {2}", 422
406 loadPath, firstName, lastName); 423 DearchiveInventory(id, firstName, lastName, invPath, pass, loadPath, options);
407 } 424 }
408 catch (InventoryArchiverException e) 425 catch (InventoryArchiverException e)
409 { 426 {
@@ -417,7 +434,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
417 /// <param name="cmdparams"></param> 434 /// <param name="cmdparams"></param>
418 protected void HandleSaveInvConsoleCommand(string module, string[] cmdparams) 435 protected void HandleSaveInvConsoleCommand(string module, string[] cmdparams)
419 { 436 {
420 Guid id = Guid.NewGuid(); 437 UUID id = UUID.Random();
421 438
422 Dictionary<string, object> options = new Dictionary<string, object>(); 439 Dictionary<string, object> options = new Dictionary<string, object>();
423 440
@@ -439,6 +456,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
439 options["excludefolders"] = new List<String>(); 456 options["excludefolders"] = new List<String>();
440 ((List<String>)options["excludefolders"]).Add(v); 457 ((List<String>)options["excludefolders"]).Add(v);
441 }); 458 });
459 ops.Add("perm=", delegate(string v) { options["checkPermissions"] = v; });
442 460
443 List<string> mainParams = ops.Parse(cmdparams); 461 List<string> mainParams = ops.Parse(cmdparams);
444 462
@@ -464,8 +482,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
464 "[INVENTORY ARCHIVER]: Saving archive {0} using inventory path {1} for {2} {3}", 482 "[INVENTORY ARCHIVER]: Saving archive {0} using inventory path {1} for {2} {3}",
465 savePath, invPath, firstName, lastName); 483 savePath, invPath, firstName, lastName);
466 484
467 lock (m_pendingConsoleSaves) 485 lock (m_pendingConsoleTasks)
468 m_pendingConsoleSaves.Add(id); 486 m_pendingConsoleTasks.Add(id);
469 487
470 ArchiveInventory(id, firstName, lastName, invPath, pass, savePath, options); 488 ArchiveInventory(id, firstName, lastName, invPath, pass, savePath, options);
471 } 489 }
@@ -476,20 +494,24 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
476 } 494 }
477 495
478 private void SaveInvConsoleCommandCompleted( 496 private void SaveInvConsoleCommandCompleted(
479 Guid id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream, 497 UUID id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream,
480 Exception reportedException) 498 Exception reportedException, int SaveCount, int FilterCount)
481 { 499 {
482 lock (m_pendingConsoleSaves) 500 lock (m_pendingConsoleTasks)
483 { 501 {
484 if (m_pendingConsoleSaves.Contains(id)) 502 if (m_pendingConsoleTasks.Contains(id))
485 m_pendingConsoleSaves.Remove(id); 503 m_pendingConsoleTasks.Remove(id);
486 else 504 else
487 return; 505 return;
488 } 506 }
489 507
490 if (succeeded) 508 if (succeeded)
491 { 509 {
492 m_log.InfoFormat("[INVENTORY ARCHIVER]: Saved archive for {0} {1}", userInfo.FirstName, userInfo.LastName); 510 // Report success and include item count and filter count (Skipped items due to --perm or --exclude switches)
511 if(FilterCount == 0)
512 m_log.InfoFormat("[INVENTORY ARCHIVER]: Saved archive with {0} items for {1} {2}", SaveCount, userInfo.FirstName, userInfo.LastName);
513 else
514 m_log.InfoFormat("[INVENTORY ARCHIVER]: Saved archive with {0} items for {1} {2}. Skipped {3} items due to exclude and/or perm switches", SaveCount, userInfo.FirstName, userInfo.LastName, FilterCount);
493 } 515 }
494 else 516 else
495 { 517 {
@@ -499,6 +521,30 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
499 } 521 }
500 } 522 }
501 523
524 private void LoadInvConsoleCommandCompleted(
525 UUID id, bool succeeded, UserAccount userInfo, string invPath, Stream loadStream,
526 Exception reportedException, int LoadCount)
527 {
528 lock (m_pendingConsoleTasks)
529 {
530 if (m_pendingConsoleTasks.Contains(id))
531 m_pendingConsoleTasks.Remove(id);
532 else
533 return;
534 }
535
536 if (succeeded)
537 {
538 m_log.InfoFormat("[INVENTORY ARCHIVER]: Loaded {0} items from archive {1} for {2} {3}", LoadCount, invPath, userInfo.FirstName, userInfo.LastName);
539 }
540 else
541 {
542 m_log.ErrorFormat(
543 "[INVENTORY ARCHIVER]: Archive load for {0} {1} failed - {2}",
544 userInfo.FirstName, userInfo.LastName, reportedException.Message);
545 }
546 }
547
502 /// <summary> 548 /// <summary>
503 /// Get user information for the given name. 549 /// Get user information for the given name.
504 /// </summary> 550 /// </summary>
@@ -536,7 +582,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
536 } 582 }
537 catch (Exception e) 583 catch (Exception e)
538 { 584 {
539 m_log.ErrorFormat("[INVENTORY ARCHIVER]: Could not authenticate password, {0}", e.Message); 585 m_log.ErrorFormat("[INVENTORY ARCHIVER]: Could not authenticate password, {0}", e);
540 return null; 586 return null;
541 } 587 }
542 } 588 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs
index 6eb3605..c2e645f 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs
@@ -36,137 +36,19 @@ using OpenSim.Data;
36using OpenSim.Framework; 36using OpenSim.Framework;
37using OpenSim.Framework.Serialization; 37using OpenSim.Framework.Serialization;
38using OpenSim.Framework.Serialization.External; 38using OpenSim.Framework.Serialization.External;
39using OpenSim.Framework.Communications;
40using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; 39using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver;
41using OpenSim.Region.CoreModules.World.Serialiser; 40using OpenSim.Region.CoreModules.World.Serialiser;
42using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
43using OpenSim.Region.Framework.Scenes.Serialization; 42using OpenSim.Region.Framework.Scenes.Serialization;
44using OpenSim.Services.Interfaces; 43using OpenSim.Services.Interfaces;
45using OpenSim.Tests.Common; 44using OpenSim.Tests.Common;
46using OpenSim.Tests.Common.Mock;
47 45
48namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests 46namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
49{ 47{
50 [TestFixture] 48 [TestFixture]
51 public class PathTests : InventoryArchiveTestCase 49 public class InventoryArchiveLoadPathTests : InventoryArchiveTestCase
52 { 50 {
53 /// <summary> 51 /// <summary>
54 /// Test saving an inventory path to a V0.1 OpenSim Inventory Archive
55 /// (subject to change since there is no fixed format yet).
56 /// </summary>
57 [Test]
58 public void TestSavePathToIarV0_1()
59 {
60 TestHelpers.InMethod();
61// log4net.Config.XmlConfigurator.Configure();
62
63 InventoryArchiverModule archiverModule = new InventoryArchiverModule();
64
65 Scene scene = new SceneHelpers().SetupScene();
66 SceneHelpers.SetupSceneModules(scene, archiverModule);
67
68 // Create user
69 string userFirstName = "Jock";
70 string userLastName = "Stirrup";
71 string userPassword = "troll";
72 UUID userId = UUID.Parse("00000000-0000-0000-0000-000000000020");
73 UserAccountHelpers.CreateUserWithInventory(scene, userFirstName, userLastName, userId, userPassword);
74
75 // Create asset
76 SceneObjectGroup object1;
77 SceneObjectPart part1;
78 {
79 string partName = "My Little Dog Object";
80 UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040");
81 PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere();
82 Vector3 groupPosition = new Vector3(10, 20, 30);
83 Quaternion rotationOffset = new Quaternion(20, 30, 40, 50);
84 Vector3 offsetPosition = new Vector3(5, 10, 15);
85
86 part1 = new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, offsetPosition);
87 part1.Name = partName;
88
89 object1 = new SceneObjectGroup(part1);
90 scene.AddNewSceneObject(object1, false);
91 }
92
93 UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060");
94 AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1);
95 scene.AssetService.Store(asset1);
96
97 // Create item
98 UUID item1Id = UUID.Parse("00000000-0000-0000-0000-000000000080");
99 InventoryItemBase item1 = new InventoryItemBase();
100 item1.Name = "My Little Dog";
101 item1.AssetID = asset1.FullID;
102 item1.ID = item1Id;
103 InventoryFolderBase objsFolder
104 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, userId, "Objects")[0];
105 item1.Folder = objsFolder.ID;
106 scene.AddInventoryItem(item1);
107
108 MemoryStream archiveWriteStream = new MemoryStream();
109 archiverModule.OnInventoryArchiveSaved += SaveCompleted;
110
111 // Test saving a particular path
112 mre.Reset();
113 archiverModule.ArchiveInventory(
114 Guid.NewGuid(), userFirstName, userLastName, "Objects", userPassword, archiveWriteStream);
115 mre.WaitOne(60000, false);
116
117 byte[] archive = archiveWriteStream.ToArray();
118 MemoryStream archiveReadStream = new MemoryStream(archive);
119 TarArchiveReader tar = new TarArchiveReader(archiveReadStream);
120
121 //bool gotControlFile = false;
122 bool gotObject1File = false;
123 //bool gotObject2File = false;
124 string expectedObject1FileName = InventoryArchiveWriteRequest.CreateArchiveItemName(item1);
125 string expectedObject1FilePath = string.Format(
126 "{0}{1}{2}",
127 ArchiveConstants.INVENTORY_PATH,
128 InventoryArchiveWriteRequest.CreateArchiveFolderName(objsFolder),
129 expectedObject1FileName);
130
131 string filePath;
132 TarArchiveReader.TarEntryType tarEntryType;
133
134// Console.WriteLine("Reading archive");
135
136 while (tar.ReadEntry(out filePath, out tarEntryType) != null)
137 {
138// Console.WriteLine("Got {0}", filePath);
139
140// if (ArchiveConstants.CONTROL_FILE_PATH == filePath)
141// {
142// gotControlFile = true;
143// }
144
145 if (filePath.StartsWith(ArchiveConstants.INVENTORY_PATH) && filePath.EndsWith(".xml"))
146 {
147// string fileName = filePath.Remove(0, "Objects/".Length);
148//
149// if (fileName.StartsWith(part1.Name))
150// {
151 Assert.That(expectedObject1FilePath, Is.EqualTo(filePath));
152 gotObject1File = true;
153// }
154// else if (fileName.StartsWith(part2.Name))
155// {
156// Assert.That(fileName, Is.EqualTo(expectedObject2FileName));
157// gotObject2File = true;
158// }
159 }
160 }
161
162// Assert.That(gotControlFile, Is.True, "No control file in archive");
163 Assert.That(gotObject1File, Is.True, "No item1 file in archive");
164// Assert.That(gotObject2File, Is.True, "No object2 file in archive");
165
166 // TODO: Test presence of more files and contents of files.
167 }
168
169 /// <summary>
170 /// Test loading an IAR to various different inventory paths. 52 /// Test loading an IAR to various different inventory paths.
171 /// </summary> 53 /// </summary>
172 [Test] 54 [Test]
@@ -185,26 +67,26 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
185 67
186 UserAccountHelpers.CreateUserWithInventory(scene, m_uaMT, "meowfood"); 68 UserAccountHelpers.CreateUserWithInventory(scene, m_uaMT, "meowfood");
187 UserAccountHelpers.CreateUserWithInventory(scene, m_uaLL1, "hampshire"); 69 UserAccountHelpers.CreateUserWithInventory(scene, m_uaLL1, "hampshire");
188 70
189 archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream); 71 archiverModule.DearchiveInventory(UUID.Random(), m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream);
190 InventoryItemBase foundItem1 72 InventoryItemBase foundItem1
191 = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, m_uaMT.PrincipalID, m_item1Name); 73 = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, m_uaMT.PrincipalID, m_item1Name);
192 74
193 Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1"); 75 Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1");
194 76
195 // Now try loading to a root child folder 77 // Now try loading to a root child folder
196 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, m_uaMT.PrincipalID, "xA"); 78 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, m_uaMT.PrincipalID, "xA", false);
197 MemoryStream archiveReadStream = new MemoryStream(m_iarStream.ToArray()); 79 MemoryStream archiveReadStream = new MemoryStream(m_iarStream.ToArray());
198 archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "xA", "meowfood", archiveReadStream); 80 archiverModule.DearchiveInventory(UUID.Random(), m_uaMT.FirstName, m_uaMT.LastName, "xA", "meowfood", archiveReadStream);
199 81
200 InventoryItemBase foundItem2 82 InventoryItemBase foundItem2
201 = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, m_uaMT.PrincipalID, "xA/" + m_item1Name); 83 = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, m_uaMT.PrincipalID, "xA/" + m_item1Name);
202 Assert.That(foundItem2, Is.Not.Null, "Didn't find loaded item 2"); 84 Assert.That(foundItem2, Is.Not.Null, "Didn't find loaded item 2");
203 85
204 // Now try loading to a more deeply nested folder 86 // Now try loading to a more deeply nested folder
205 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, m_uaMT.PrincipalID, "xB/xC"); 87 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, m_uaMT.PrincipalID, "xB/xC", false);
206 archiveReadStream = new MemoryStream(archiveReadStream.ToArray()); 88 archiveReadStream = new MemoryStream(archiveReadStream.ToArray());
207 archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "xB/xC", "meowfood", archiveReadStream); 89 archiverModule.DearchiveInventory(UUID.Random(), m_uaMT.FirstName, m_uaMT.LastName, "xB/xC", "meowfood", archiveReadStream);
208 90
209 InventoryItemBase foundItem3 91 InventoryItemBase foundItem3
210 = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, m_uaMT.PrincipalID, "xB/xC/" + m_item1Name); 92 = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, m_uaMT.PrincipalID, "xB/xC/" + m_item1Name);
@@ -226,7 +108,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
226 SceneHelpers.SetupSceneModules(scene, serialiserModule, archiverModule); 108 SceneHelpers.SetupSceneModules(scene, serialiserModule, archiverModule);
227 109
228 UserAccountHelpers.CreateUserWithInventory(scene, m_uaMT, "password"); 110 UserAccountHelpers.CreateUserWithInventory(scene, m_uaMT, "password");
229 archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/Objects", "password", m_iarStream); 111 archiverModule.DearchiveInventory(UUID.Random(), m_uaMT.FirstName, m_uaMT.LastName, "/Objects", "password", m_iarStream);
230 112
231 InventoryItemBase foundItem1 113 InventoryItemBase foundItem1
232 = InventoryArchiveUtils.FindItemByPath( 114 = InventoryArchiveUtils.FindItemByPath(
@@ -287,7 +169,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
287 item1.AssetID = asset1.FullID; 169 item1.AssetID = asset1.FullID;
288 item1.ID = item1Id; 170 item1.ID = item1Id;
289 InventoryFolderBase objsFolder 171 InventoryFolderBase objsFolder
290 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, userId, "Objects")[0]; 172 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, userId, "Objects")[0];
291 item1.Folder = objsFolder.ID; 173 item1.Folder = objsFolder.ID;
292 scene.AddInventoryItem(item1); 174 scene.AddInventoryItem(item1);
293 175
@@ -296,13 +178,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
296 178
297 mre.Reset(); 179 mre.Reset();
298 archiverModule.ArchiveInventory( 180 archiverModule.ArchiveInventory(
299 Guid.NewGuid(), userFirstName, userLastName, "Objects", userPassword, archiveWriteStream); 181 UUID.Random(), userFirstName, userLastName, "Objects", userPassword, archiveWriteStream);
300 mre.WaitOne(60000, false); 182 mre.WaitOne(60000, false);
301 183
302 // LOAD ITEM 184 // LOAD ITEM
303 MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); 185 MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray());
304 186
305 archiverModule.DearchiveInventory(userFirstName, userLastName, "Scripts", userPassword, archiveReadStream); 187 archiverModule.DearchiveInventory(UUID.Random(), userFirstName, userLastName, "Scripts", userPassword, archiveReadStream);
306 188
307 InventoryItemBase foundItem1 189 InventoryItemBase foundItem1
308 = InventoryArchiveUtils.FindItemByPath( 190 = InventoryArchiveUtils.FindItemByPath(
@@ -345,40 +227,40 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
345 227
346 { 228 {
347 // Test replication of path1 229 // Test replication of path1
348 new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false) 230 new InventoryArchiveReadRequest(UUID.Random(), null, scene.InventoryService, scene.AssetService, scene.UserAccountService, ua1, null, (Stream)null, false)
349 .ReplicateArchivePathToUserInventory( 231 .ReplicateArchivePathToUserInventory(
350 iarPath1, scene.InventoryService.GetRootFolder(ua1.PrincipalID), 232 iarPath1, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
351 foldersCreated, nodesLoaded); 233 foldersCreated, nodesLoaded);
352 234
353 List<InventoryFolderBase> folder1Candidates 235 List<InventoryFolderBase> folder1Candidates
354 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1Name); 236 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1Name);
355 Assert.That(folder1Candidates.Count, Is.EqualTo(1)); 237 Assert.That(folder1Candidates.Count, Is.EqualTo(1));
356 238
357 InventoryFolderBase folder1 = folder1Candidates[0]; 239 InventoryFolderBase folder1 = folder1Candidates[0];
358 List<InventoryFolderBase> folder2aCandidates 240 List<InventoryFolderBase> folder2aCandidates
359 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1, folder2aName); 241 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1, folder2aName);
360 Assert.That(folder2aCandidates.Count, Is.EqualTo(1)); 242 Assert.That(folder2aCandidates.Count, Is.EqualTo(1));
361 } 243 }
362 244
363 { 245 {
364 // Test replication of path2 246 // Test replication of path2
365 new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false) 247 new InventoryArchiveReadRequest(UUID.Random(), null, scene.InventoryService, scene.AssetService, scene.UserAccountService, ua1, null, (Stream)null, false)
366 .ReplicateArchivePathToUserInventory( 248 .ReplicateArchivePathToUserInventory(
367 iarPath2, scene.InventoryService.GetRootFolder(ua1.PrincipalID), 249 iarPath2, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
368 foldersCreated, nodesLoaded); 250 foldersCreated, nodesLoaded);
369 251
370 List<InventoryFolderBase> folder1Candidates 252 List<InventoryFolderBase> folder1Candidates
371 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1Name); 253 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1Name);
372 Assert.That(folder1Candidates.Count, Is.EqualTo(1)); 254 Assert.That(folder1Candidates.Count, Is.EqualTo(1));
373 255
374 InventoryFolderBase folder1 = folder1Candidates[0]; 256 InventoryFolderBase folder1 = folder1Candidates[0];
375 257
376 List<InventoryFolderBase> folder2aCandidates 258 List<InventoryFolderBase> folder2aCandidates
377 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1, folder2aName); 259 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1, folder2aName);
378 Assert.That(folder2aCandidates.Count, Is.EqualTo(1)); 260 Assert.That(folder2aCandidates.Count, Is.EqualTo(1));
379 261
380 List<InventoryFolderBase> folder2bCandidates 262 List<InventoryFolderBase> folder2bCandidates
381 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1, folder2bName); 263 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1, folder2bName);
382 Assert.That(folder2bCandidates.Count, Is.EqualTo(1)); 264 Assert.That(folder2bCandidates.Count, Is.EqualTo(1));
383 } 265 }
384 } 266 }
@@ -401,20 +283,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
401 283
402 InventoryFolderBase folder1 284 InventoryFolderBase folder1
403 = UserInventoryHelpers.CreateInventoryFolder( 285 = UserInventoryHelpers.CreateInventoryFolder(
404 scene.InventoryService, ua1.PrincipalID, folder1ExistingName); 286 scene.InventoryService, ua1.PrincipalID, folder1ExistingName, false);
405 287
406 string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random()); 288 string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random());
407 string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random()); 289 string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random());
408 290
409 string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName }); 291 string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName });
410 292
411 new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false) 293 new InventoryArchiveReadRequest(UUID.Random(), null, scene.InventoryService, scene.AssetService, scene.UserAccountService, ua1, null, (Stream)null, false)
412 .ReplicateArchivePathToUserInventory( 294 .ReplicateArchivePathToUserInventory(
413 itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID), 295 itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
414 new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>()); 296 new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>());
415 297
416 List<InventoryFolderBase> folder1PostCandidates 298 List<InventoryFolderBase> folder1PostCandidates
417 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName); 299 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName);
418 Assert.That(folder1PostCandidates.Count, Is.EqualTo(2)); 300 Assert.That(folder1PostCandidates.Count, Is.EqualTo(2));
419 301
420 // FIXME: Temporarily, we're going to do something messy to make sure we pick up the created folder. 302 // FIXME: Temporarily, we're going to do something messy to make sure we pick up the created folder.
@@ -430,7 +312,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
430// Assert.That(folder1Post.ID, Is.EqualTo(folder1.ID)); 312// Assert.That(folder1Post.ID, Is.EqualTo(folder1.ID));
431 313
432 List<InventoryFolderBase> folder2PostCandidates 314 List<InventoryFolderBase> folder2PostCandidates
433 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1Post, "b"); 315 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1Post, "b");
434 Assert.That(folder2PostCandidates.Count, Is.EqualTo(1)); 316 Assert.That(folder2PostCandidates.Count, Is.EqualTo(1));
435 } 317 }
436 318
@@ -452,26 +334,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
452 334
453 InventoryFolderBase folder1 335 InventoryFolderBase folder1
454 = UserInventoryHelpers.CreateInventoryFolder( 336 = UserInventoryHelpers.CreateInventoryFolder(
455 scene.InventoryService, ua1.PrincipalID, folder1ExistingName); 337 scene.InventoryService, ua1.PrincipalID, folder1ExistingName, false);
456 338
457 string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random()); 339 string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random());
458 string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random()); 340 string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random());
459 341
460 string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName }); 342 string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName });
461 343
462 new InventoryArchiveReadRequest(scene, ua1, folder1ExistingName, (Stream)null, true) 344 new InventoryArchiveReadRequest(UUID.Random(), null, scene.InventoryService, scene.AssetService, scene.UserAccountService, ua1, folder1ExistingName, (Stream)null, true)
463 .ReplicateArchivePathToUserInventory( 345 .ReplicateArchivePathToUserInventory(
464 itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID), 346 itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
465 new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>()); 347 new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>());
466 348
467 List<InventoryFolderBase> folder1PostCandidates 349 List<InventoryFolderBase> folder1PostCandidates
468 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName); 350 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName);
469 Assert.That(folder1PostCandidates.Count, Is.EqualTo(1)); 351 Assert.That(folder1PostCandidates.Count, Is.EqualTo(1));
470 Assert.That(folder1PostCandidates[0].ID, Is.EqualTo(folder1.ID)); 352 Assert.That(folder1PostCandidates[0].ID, Is.EqualTo(folder1.ID));
471 353
472 List<InventoryFolderBase> folder2PostCandidates 354 List<InventoryFolderBase> folder2PostCandidates
473 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1PostCandidates[0], "b"); 355 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1PostCandidates[0], "b");
474 Assert.That(folder2PostCandidates.Count, Is.EqualTo(1)); 356 Assert.That(folder2PostCandidates.Count, Is.EqualTo(1));
475 } 357 }
476 } 358 }
477} \ No newline at end of file 359}
360
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs
new file mode 100644
index 0000000..57b4f80
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs
@@ -0,0 +1,192 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Threading;
33using NUnit.Framework;
34using OpenMetaverse;
35using OpenSim.Data;
36using OpenSim.Framework;
37using OpenSim.Framework.Serialization;
38using OpenSim.Framework.Serialization.External;
39using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver;
40using OpenSim.Region.CoreModules.World.Serialiser;
41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Region.Framework.Scenes.Serialization;
43using OpenSim.Services.Interfaces;
44using OpenSim.Tests.Common;
45
46namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
47{
48 [TestFixture]
49 public class InventoryArchiveLoadTests : InventoryArchiveTestCase
50 {
51 protected TestScene m_scene;
52 protected InventoryArchiverModule m_archiverModule;
53
54 [SetUp]
55 public override void SetUp()
56 {
57 base.SetUp();
58
59 SerialiserModule serialiserModule = new SerialiserModule();
60 m_archiverModule = new InventoryArchiverModule();
61
62 m_scene = new SceneHelpers().SetupScene();
63 SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule);
64 }
65
66 [Test]
67 public void TestLoadCoalesecedItem()
68 {
69 TestHelpers.InMethod();
70// TestHelpers.EnableLogging();
71
72 UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "password");
73 m_archiverModule.DearchiveInventory(UUID.Random(), m_uaLL1.FirstName, m_uaLL1.LastName, "/", "password", m_iarStream);
74
75 InventoryItemBase coaItem
76 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_coaItemName);
77
78 Assert.That(coaItem, Is.Not.Null, "Didn't find loaded item 1");
79
80 string assetXml = AssetHelpers.ReadAssetAsString(m_scene.AssetService, coaItem.AssetID);
81
82 CoalescedSceneObjects coa;
83 bool readResult = CoalescedSceneObjectsSerializer.TryFromXml(assetXml, out coa);
84
85 Assert.That(readResult, Is.True);
86 Assert.That(coa.Count, Is.EqualTo(2));
87
88 List<SceneObjectGroup> coaObjects = coa.Objects;
89 Assert.That(coaObjects[0].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000120")));
90 Assert.That(coaObjects[0].AbsolutePosition, Is.EqualTo(new Vector3(15, 30, 45)));
91
92 Assert.That(coaObjects[1].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000140")));
93 Assert.That(coaObjects[1].AbsolutePosition, Is.EqualTo(new Vector3(25, 50, 75)));
94 }
95
96 /// <summary>
97 /// Test case where a creator account exists for the creator UUID embedded in item metadata and serialized
98 /// objects.
99 /// </summary>
100 [Test]
101 public void TestLoadIarCreatorAccountPresent()
102 {
103 TestHelpers.InMethod();
104// log4net.Config.XmlConfigurator.Configure();
105
106 UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "meowfood");
107
108 m_archiverModule.DearchiveInventory(UUID.Random(), m_uaLL1.FirstName, m_uaLL1.LastName, "/", "meowfood", m_iarStream);
109 InventoryItemBase foundItem1
110 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_item1Name);
111
112 Assert.That(
113 foundItem1.CreatorId, Is.EqualTo(m_uaLL1.PrincipalID.ToString()),
114 "Loaded item non-uuid creator doesn't match original");
115 Assert.That(
116 foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL1.PrincipalID),
117 "Loaded item uuid creator doesn't match original");
118 Assert.That(foundItem1.Owner, Is.EqualTo(m_uaLL1.PrincipalID),
119 "Loaded item owner doesn't match inventory reciever");
120
121 AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
122 string xmlData = Utils.BytesToString(asset1.Data);
123 SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
124
125 Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL1.PrincipalID));
126 }
127
128// /// <summary>
129// /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where
130// /// an account exists with the same name as the creator, though not the same id.
131// /// </summary>
132// [Test]
133// public void TestLoadIarV0_1SameNameCreator()
134// {
135// TestHelpers.InMethod();
136// TestHelpers.EnableLogging();
137//
138// UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "meowfood");
139// UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL2, "hampshire");
140//
141// m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream);
142// InventoryItemBase foundItem1
143// = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name);
144//
145// Assert.That(
146// foundItem1.CreatorId, Is.EqualTo(m_uaLL2.PrincipalID.ToString()),
147// "Loaded item non-uuid creator doesn't match original");
148// Assert.That(
149// foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL2.PrincipalID),
150// "Loaded item uuid creator doesn't match original");
151// Assert.That(foundItem1.Owner, Is.EqualTo(m_uaMT.PrincipalID),
152// "Loaded item owner doesn't match inventory reciever");
153//
154// AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
155// string xmlData = Utils.BytesToString(asset1.Data);
156// SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
157//
158// Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL2.PrincipalID));
159// }
160
161 /// <summary>
162 /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where
163 /// the creator or an account with the creator's name does not exist within the system.
164 /// </summary>
165 [Test]
166 public void TestLoadIarV0_1AbsentCreator()
167 {
168 TestHelpers.InMethod();
169// log4net.Config.XmlConfigurator.Configure();
170
171 UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "password");
172 m_archiverModule.DearchiveInventory(UUID.Random(), m_uaMT.FirstName, m_uaMT.LastName, "/", "password", m_iarStream);
173
174 InventoryItemBase foundItem1
175 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name);
176
177 Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1");
178 Assert.That(
179 foundItem1.CreatorId, Is.EqualTo(m_uaMT.PrincipalID.ToString()),
180 "Loaded item non-uuid creator doesn't match that of the loading user");
181 Assert.That(
182 foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaMT.PrincipalID),
183 "Loaded item uuid creator doesn't match that of the loading user");
184
185 AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
186 string xmlData = Utils.BytesToString(asset1.Data);
187 SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
188
189 Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaMT.PrincipalID));
190 }
191 }
192} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs
index 06f6e49..7265405 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs
@@ -36,19 +36,17 @@ using OpenSim.Data;
36using OpenSim.Framework; 36using OpenSim.Framework;
37using OpenSim.Framework.Serialization; 37using OpenSim.Framework.Serialization;
38using OpenSim.Framework.Serialization.External; 38using OpenSim.Framework.Serialization.External;
39using OpenSim.Framework.Communications;
40using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; 39using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver;
41using OpenSim.Region.CoreModules.World.Serialiser; 40using OpenSim.Region.CoreModules.World.Serialiser;
42using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
43using OpenSim.Region.Framework.Scenes.Serialization; 42using OpenSim.Region.Framework.Scenes.Serialization;
44using OpenSim.Services.Interfaces; 43using OpenSim.Services.Interfaces;
45using OpenSim.Tests.Common; 44using OpenSim.Tests.Common;
46using OpenSim.Tests.Common.Mock;
47 45
48namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests 46namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
49{ 47{
50 [TestFixture] 48 [TestFixture]
51 public class InventoryArchiverTests : InventoryArchiveTestCase 49 public class InventoryArchiveSaveTests : InventoryArchiveTestCase
52 { 50 {
53 protected TestScene m_scene; 51 protected TestScene m_scene;
54 protected InventoryArchiverModule m_archiverModule; 52 protected InventoryArchiverModule m_archiverModule;
@@ -64,36 +62,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
64 m_scene = new SceneHelpers().SetupScene(); 62 m_scene = new SceneHelpers().SetupScene();
65 SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule); 63 SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule);
66 } 64 }
67
68 [Test]
69 public void TestLoadCoalesecedItem()
70 {
71 TestHelpers.InMethod();
72// TestHelpers.EnableLogging();
73
74 UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "password");
75 m_archiverModule.DearchiveInventory(m_uaLL1.FirstName, m_uaLL1.LastName, "/", "password", m_iarStream);
76
77 InventoryItemBase coaItem
78 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_coaItemName);
79
80 Assert.That(coaItem, Is.Not.Null, "Didn't find loaded item 1");
81
82 string assetXml = AssetHelpers.ReadAssetAsString(m_scene.AssetService, coaItem.AssetID);
83
84 CoalescedSceneObjects coa;
85 bool readResult = CoalescedSceneObjectsSerializer.TryFromXml(assetXml, out coa);
86
87 Assert.That(readResult, Is.True);
88 Assert.That(coa.Count, Is.EqualTo(2));
89
90 List<SceneObjectGroup> coaObjects = coa.Objects;
91 Assert.That(coaObjects[0].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000120")));
92 Assert.That(coaObjects[0].AbsolutePosition, Is.EqualTo(new Vector3(15, 30, 45)));
93
94 Assert.That(coaObjects[1].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000140")));
95 Assert.That(coaObjects[1].AbsolutePosition, Is.EqualTo(new Vector3(25, 50, 75)));
96 }
97 65
98 /// <summary> 66 /// <summary>
99 /// Test that the IAR has the required files in the right order. 67 /// Test that the IAR has the required files in the right order.
@@ -115,12 +83,145 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
115 byte[] data = tar.ReadEntry(out filePath, out tarEntryType); 83 byte[] data = tar.ReadEntry(out filePath, out tarEntryType);
116 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); 84 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
117 85
118 InventoryArchiveReadRequest iarr 86 InventoryArchiveReadRequest iarr
119 = new InventoryArchiveReadRequest(null, null, null, (Stream)null, false); 87 = new InventoryArchiveReadRequest(UUID.Random(), null, null, null, null, null, null, (Stream)null, false);
120 iarr.LoadControlFile(filePath, data); 88 iarr.LoadControlFile(filePath, data);
121 89
122 Assert.That(iarr.ControlFileLoaded, Is.True); 90 Assert.That(iarr.ControlFileLoaded, Is.True);
123 } 91 }
92
93 [Test]
94 public void TestSaveRootFolderToIar()
95 {
96 TestHelpers.InMethod();
97// TestHelpers.EnableLogging();
98
99 string userFirstName = "Jock";
100 string userLastName = "Stirrup";
101 string userPassword = "troll";
102 UUID userId = TestHelpers.ParseTail(0x20);
103
104 UserAccountHelpers.CreateUserWithInventory(m_scene, userFirstName, userLastName, userId, userPassword);
105
106 MemoryStream archiveWriteStream = new MemoryStream();
107 m_archiverModule.OnInventoryArchiveSaved += SaveCompleted;
108
109 mre.Reset();
110 m_archiverModule.ArchiveInventory(
111 UUID.Random(), userFirstName, userLastName, "/", userPassword, archiveWriteStream);
112 mre.WaitOne(60000, false);
113
114 // Test created iar
115 byte[] archive = archiveWriteStream.ToArray();
116 MemoryStream archiveReadStream = new MemoryStream(archive);
117 TarArchiveReader tar = new TarArchiveReader(archiveReadStream);
118
119// InventoryArchiveUtils.
120 bool gotObjectsFolder = false;
121
122 string objectsFolderName
123 = string.Format(
124 "{0}{1}",
125 ArchiveConstants.INVENTORY_PATH,
126 InventoryArchiveWriteRequest.CreateArchiveFolderName(
127 UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, userId, "Objects")));
128
129 string filePath;
130 TarArchiveReader.TarEntryType tarEntryType;
131
132 while (tar.ReadEntry(out filePath, out tarEntryType) != null)
133 {
134// Console.WriteLine("Got {0}", filePath);
135
136 // Lazily, we only bother to look for the system objects folder created when we call CreateUserWithInventory()
137 // XXX: But really we need to stop all that stuff being created in tests or check for such folders
138 // more thoroughly
139 if (filePath == objectsFolderName)
140 gotObjectsFolder = true;
141 }
142
143 Assert.That(gotObjectsFolder, Is.True);
144 }
145
146 [Test]
147 public void TestSaveNonRootFolderToIar()
148 {
149 TestHelpers.InMethod();
150// TestHelpers.EnableLogging();
151
152 string userFirstName = "Jock";
153 string userLastName = "Stirrup";
154 string userPassword = "troll";
155 UUID userId = TestHelpers.ParseTail(0x20);
156
157 UserAccountHelpers.CreateUserWithInventory(m_scene, userFirstName, userLastName, userId, userPassword);
158
159 // Create base folder
160 InventoryFolderBase f1
161 = UserInventoryHelpers.CreateInventoryFolder(m_scene.InventoryService, userId, "f1", true);
162
163 // Create item1
164 SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(1, userId, "My Little Dog Object", 0x5);
165 InventoryItemBase i1 = UserInventoryHelpers.AddInventoryItem(m_scene, so1, 0x50, 0x60, "f1");
166
167 // Create embedded folder
168 InventoryFolderBase f1_1
169 = UserInventoryHelpers.CreateInventoryFolder(m_scene.InventoryService, userId, "f1/f1.1", true);
170
171 // Create embedded item
172 SceneObjectGroup so1_1 = SceneHelpers.CreateSceneObject(1, userId, "My Little Cat Object", 0x6);
173 InventoryItemBase i2 = UserInventoryHelpers.AddInventoryItem(m_scene, so1_1, 0x500, 0x600, "f1/f1.1");
174
175 MemoryStream archiveWriteStream = new MemoryStream();
176 m_archiverModule.OnInventoryArchiveSaved += SaveCompleted;
177
178 mre.Reset();
179 m_archiverModule.ArchiveInventory(
180 UUID.Random(), userFirstName, userLastName, "f1", userPassword, archiveWriteStream);
181 mre.WaitOne(60000, false);
182
183 // Test created iar
184 byte[] archive = archiveWriteStream.ToArray();
185 MemoryStream archiveReadStream = new MemoryStream(archive);
186 TarArchiveReader tar = new TarArchiveReader(archiveReadStream);
187
188// InventoryArchiveUtils.
189 bool gotf1 = false, gotf1_1 = false, gotso1 = false, gotso2 = false;
190
191 string f1FileName
192 = string.Format("{0}{1}", ArchiveConstants.INVENTORY_PATH, InventoryArchiveWriteRequest.CreateArchiveFolderName(f1));
193 string f1_1FileName
194 = string.Format("{0}{1}", f1FileName, InventoryArchiveWriteRequest.CreateArchiveFolderName(f1_1));
195 string so1FileName
196 = string.Format("{0}{1}", f1FileName, InventoryArchiveWriteRequest.CreateArchiveItemName(i1));
197 string so2FileName
198 = string.Format("{0}{1}", f1_1FileName, InventoryArchiveWriteRequest.CreateArchiveItemName(i2));
199
200 string filePath;
201 TarArchiveReader.TarEntryType tarEntryType;
202
203 while (tar.ReadEntry(out filePath, out tarEntryType) != null)
204 {
205// Console.WriteLine("Got {0}", filePath);
206
207 if (filePath == f1FileName)
208 gotf1 = true;
209 else if (filePath == f1_1FileName)
210 gotf1_1 = true;
211 else if (filePath == so1FileName)
212 gotso1 = true;
213 else if (filePath == so2FileName)
214 gotso2 = true;
215 }
216
217// Assert.That(gotControlFile, Is.True, "No control file in archive");
218 Assert.That(gotf1, Is.True);
219 Assert.That(gotf1_1, Is.True);
220 Assert.That(gotso1, Is.True);
221 Assert.That(gotso2, Is.True);
222
223 // TODO: Test presence of more files and contents of files.
224 }
124 225
125 /// <summary> 226 /// <summary>
126 /// Test saving a single inventory item to an IAR 227 /// Test saving a single inventory item to an IAR
@@ -155,7 +256,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
155 item1.AssetID = asset1.FullID; 256 item1.AssetID = asset1.FullID;
156 item1.ID = item1Id; 257 item1.ID = item1Id;
157 InventoryFolderBase objsFolder 258 InventoryFolderBase objsFolder
158 = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, userId, "Objects")[0]; 259 = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, userId, "Objects")[0];
159 item1.Folder = objsFolder.ID; 260 item1.Folder = objsFolder.ID;
160 m_scene.AddInventoryItem(item1); 261 m_scene.AddInventoryItem(item1);
161 262
@@ -164,7 +265,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
164 265
165 mre.Reset(); 266 mre.Reset();
166 m_archiverModule.ArchiveInventory( 267 m_archiverModule.ArchiveInventory(
167 Guid.NewGuid(), userFirstName, userLastName, "Objects/" + item1Name, userPassword, archiveWriteStream); 268 UUID.Random(), userFirstName, userLastName, "Objects/" + item1Name, userPassword, archiveWriteStream);
168 mre.WaitOne(60000, false); 269 mre.WaitOne(60000, false);
169 270
170 byte[] archive = archiveWriteStream.ToArray(); 271 byte[] archive = archiveWriteStream.ToArray();
@@ -250,7 +351,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
250 item1.AssetID = asset1.FullID; 351 item1.AssetID = asset1.FullID;
251 item1.ID = item1Id; 352 item1.ID = item1Id;
252 InventoryFolderBase objsFolder 353 InventoryFolderBase objsFolder
253 = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, userId, "Objects")[0]; 354 = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, userId, "Objects")[0];
254 item1.Folder = objsFolder.ID; 355 item1.Folder = objsFolder.ID;
255 m_scene.AddInventoryItem(item1); 356 m_scene.AddInventoryItem(item1);
256 357
@@ -261,7 +362,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
261 362
262 // When we're not saving assets, archiving is being done synchronously. 363 // When we're not saving assets, archiving is being done synchronously.
263 m_archiverModule.ArchiveInventory( 364 m_archiverModule.ArchiveInventory(
264 Guid.NewGuid(), userFirstName, userLastName, "Objects/" + item1Name, userPassword, archiveWriteStream, options); 365 UUID.Random(), userFirstName, userLastName, "Objects/" + item1Name, userPassword, archiveWriteStream, options);
265 366
266 byte[] archive = archiveWriteStream.ToArray(); 367 byte[] archive = archiveWriteStream.ToArray();
267 MemoryStream archiveReadStream = new MemoryStream(archive); 368 MemoryStream archiveReadStream = new MemoryStream(archive);
@@ -317,101 +418,5 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
317 418
318 // TODO: Test presence of more files and contents of files. 419 // TODO: Test presence of more files and contents of files.
319 } 420 }
320
321 /// <summary>
322 /// Test case where a creator account exists for the creator UUID embedded in item metadata and serialized
323 /// objects.
324 /// </summary>
325 [Test]
326 public void TestLoadIarCreatorAccountPresent()
327 {
328 TestHelpers.InMethod();
329// log4net.Config.XmlConfigurator.Configure();
330
331 UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "meowfood");
332
333 m_archiverModule.DearchiveInventory(m_uaLL1.FirstName, m_uaLL1.LastName, "/", "meowfood", m_iarStream);
334 InventoryItemBase foundItem1
335 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_item1Name);
336
337 Assert.That(
338 foundItem1.CreatorId, Is.EqualTo(m_uaLL1.PrincipalID.ToString()),
339 "Loaded item non-uuid creator doesn't match original");
340 Assert.That(
341 foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL1.PrincipalID),
342 "Loaded item uuid creator doesn't match original");
343 Assert.That(foundItem1.Owner, Is.EqualTo(m_uaLL1.PrincipalID),
344 "Loaded item owner doesn't match inventory reciever");
345
346 AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
347 string xmlData = Utils.BytesToString(asset1.Data);
348 SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
349
350 Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL1.PrincipalID));
351 }
352
353// /// <summary>
354// /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where
355// /// an account exists with the same name as the creator, though not the same id.
356// /// </summary>
357// [Test]
358// public void TestLoadIarV0_1SameNameCreator()
359// {
360// TestHelpers.InMethod();
361// TestHelpers.EnableLogging();
362//
363// UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "meowfood");
364// UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL2, "hampshire");
365//
366// m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream);
367// InventoryItemBase foundItem1
368// = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name);
369//
370// Assert.That(
371// foundItem1.CreatorId, Is.EqualTo(m_uaLL2.PrincipalID.ToString()),
372// "Loaded item non-uuid creator doesn't match original");
373// Assert.That(
374// foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL2.PrincipalID),
375// "Loaded item uuid creator doesn't match original");
376// Assert.That(foundItem1.Owner, Is.EqualTo(m_uaMT.PrincipalID),
377// "Loaded item owner doesn't match inventory reciever");
378//
379// AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
380// string xmlData = Utils.BytesToString(asset1.Data);
381// SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
382//
383// Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL2.PrincipalID));
384// }
385
386 /// <summary>
387 /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where
388 /// the creator or an account with the creator's name does not exist within the system.
389 /// </summary>
390 [Test]
391 public void TestLoadIarV0_1AbsentCreator()
392 {
393 TestHelpers.InMethod();
394// log4net.Config.XmlConfigurator.Configure();
395
396 UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "password");
397 m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "password", m_iarStream);
398
399 InventoryItemBase foundItem1
400 = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name);
401
402 Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1");
403 Assert.That(
404 foundItem1.CreatorId, Is.EqualTo(m_uaMT.PrincipalID.ToString()),
405 "Loaded item non-uuid creator doesn't match that of the loading user");
406 Assert.That(
407 foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaMT.PrincipalID),
408 "Loaded item uuid creator doesn't match that of the loading user");
409
410 AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString());
411 string xmlData = Utils.BytesToString(asset1.Data);
412 SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
413
414 Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaMT.PrincipalID));
415 }
416 } 421 }
417} \ No newline at end of file 422} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs
index db78da9..519c697 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs
@@ -36,14 +36,12 @@ using OpenSim.Data;
36using OpenSim.Framework; 36using OpenSim.Framework;
37using OpenSim.Framework.Serialization; 37using OpenSim.Framework.Serialization;
38using OpenSim.Framework.Serialization.External; 38using OpenSim.Framework.Serialization.External;
39using OpenSim.Framework.Communications;
40using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; 39using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver;
41using OpenSim.Region.CoreModules.World.Serialiser; 40using OpenSim.Region.CoreModules.World.Serialiser;
42using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
43using OpenSim.Region.Framework.Scenes.Serialization; 42using OpenSim.Region.Framework.Scenes.Serialization;
44using OpenSim.Services.Interfaces; 43using OpenSim.Services.Interfaces;
45using OpenSim.Tests.Common; 44using OpenSim.Tests.Common;
46using OpenSim.Tests.Common.Mock;
47 45
48namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests 46namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
49{ 47{
@@ -163,14 +161,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
163 scene.AddInventoryItem(coaItem); 161 scene.AddInventoryItem(coaItem);
164 162
165 archiverModule.ArchiveInventory( 163 archiverModule.ArchiveInventory(
166 Guid.NewGuid(), m_uaLL1.FirstName, m_uaLL1.LastName, "/*", "hampshire", archiveWriteStream); 164 UUID.Random(), m_uaLL1.FirstName, m_uaLL1.LastName, "/*", "hampshire", archiveWriteStream);
167 165
168 m_iarStreamBytes = archiveWriteStream.ToArray(); 166 m_iarStreamBytes = archiveWriteStream.ToArray();
169 } 167 }
170 168
171 protected void SaveCompleted( 169 protected void SaveCompleted(
172 Guid id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream, 170 UUID id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream,
173 Exception reportedException) 171 Exception reportedException, int SaveCount, int FilterCount)
174 { 172 {
175 mre.Set(); 173 mre.Set();
176 } 174 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
index bcb7f42..bba48cc 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
@@ -47,10 +47,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
47 47
48 /// <summary> 48 /// <summary>
49 private List<Scene> m_Scenelist = new List<Scene>(); 49 private List<Scene> m_Scenelist = new List<Scene>();
50// private Dictionary<UUID, Scene> m_AgentRegions =
51// new Dictionary<UUID, Scene>();
52 50
53 private IMessageTransferModule m_TransferModule = null; 51 private IMessageTransferModule m_TransferModule;
54 private bool m_Enabled = true; 52 private bool m_Enabled = true;
55 53
56 #region Region Module interface 54 #region Region Module interface
@@ -81,9 +79,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
81// scene.RegisterModuleInterface<IInventoryTransferModule>(this); 79// scene.RegisterModuleInterface<IInventoryTransferModule>(this);
82 80
83 scene.EventManager.OnNewClient += OnNewClient; 81 scene.EventManager.OnNewClient += OnNewClient;
84// scene.EventManager.OnClientClosed += ClientLoggedOut;
85 scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; 82 scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
86// scene.EventManager.OnSetRootAgentScene += OnSetRootAgentScene;
87 } 83 }
88 84
89 public void RegionLoaded(Scene scene) 85 public void RegionLoaded(Scene scene)
@@ -96,11 +92,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
96 m_log.Error("[INVENTORY TRANSFER]: No Message transfer module found, transfers will be local only"); 92 m_log.Error("[INVENTORY TRANSFER]: No Message transfer module found, transfers will be local only");
97 m_Enabled = false; 93 m_Enabled = false;
98 94
99 m_Scenelist.Clear(); 95// m_Scenelist.Clear();
100 scene.EventManager.OnNewClient -= OnNewClient; 96// scene.EventManager.OnNewClient -= OnNewClient;
101// scene.EventManager.OnClientClosed -= ClientLoggedOut;
102 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; 97 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
103// scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
104 } 98 }
105 } 99 }
106 } 100 }
@@ -108,9 +102,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
108 public void RemoveRegion(Scene scene) 102 public void RemoveRegion(Scene scene)
109 { 103 {
110 scene.EventManager.OnNewClient -= OnNewClient; 104 scene.EventManager.OnNewClient -= OnNewClient;
111// scene.EventManager.OnClientClosed -= ClientLoggedOut;
112 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; 105 scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
113// scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
114 m_Scenelist.Remove(scene); 106 m_Scenelist.Remove(scene);
115 } 107 }
116 108
@@ -139,11 +131,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
139 // Inventory giving is conducted via instant message 131 // Inventory giving is conducted via instant message
140 client.OnInstantMessage += OnInstantMessage; 132 client.OnInstantMessage += OnInstantMessage;
141 } 133 }
142
143// protected void OnSetRootAgentScene(UUID id, Scene scene)
144// {
145// m_AgentRegions[id] = scene;
146// }
147 134
148 private Scene FindClientScene(UUID agentId) 135 private Scene FindClientScene(UUID agentId)
149 { 136 {
@@ -162,8 +149,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
162 private void OnInstantMessage(IClientAPI client, GridInstantMessage im) 149 private void OnInstantMessage(IClientAPI client, GridInstantMessage im)
163 { 150 {
164// m_log.DebugFormat( 151// m_log.DebugFormat(
165// "[INVENTORY TRANSFER]: {0} IM type received from {1}", 152// "[INVENTORY TRANSFER]: {0} IM type received from client {1}. From={2} ({3}), To={4}",
166// (InstantMessageDialog)im.dialog, client.Name); 153// (InstantMessageDialog)im.dialog, client.Name,
154// im.fromAgentID, im.fromAgentName, im.toAgentID);
167 155
168 Scene scene = FindClientScene(client.AgentId); 156 Scene scene = FindClientScene(client.AgentId);
169 157
@@ -188,12 +176,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
188 { 176 {
189 UUID folderID = new UUID(im.binaryBucket, 1); 177 UUID folderID = new UUID(im.binaryBucket, 1);
190 178
191 m_log.DebugFormat("[INVENTORY TRANSFER]: Inserting original folder {0} "+ 179 m_log.DebugFormat(
192 "into agent {1}'s inventory", 180 "[INVENTORY TRANSFER]: Inserting original folder {0} into agent {1}'s inventory",
193 folderID, new UUID(im.toAgentID)); 181 folderID, new UUID(im.toAgentID));
194 182
195 InventoryFolderBase folderCopy 183 InventoryFolderBase folderCopy
196 = scene.GiveInventoryFolder(receipientID, client.AgentId, folderID, UUID.Zero); 184 = scene.GiveInventoryFolder(client, receipientID, client.AgentId, folderID, UUID.Zero);
197 185
198 if (folderCopy == null) 186 if (folderCopy == null)
199 { 187 {
@@ -213,7 +201,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
213 user.ControllingClient.SendBulkUpdateInventory(folderCopy); 201 user.ControllingClient.SendBulkUpdateInventory(folderCopy);
214 202
215 // HACK!! 203 // HACK!!
216 im.imSessionID = folderID.Guid; 204 // Insert the ID of the copied folder into the IM so that we know which item to move to trash if it
205 // is rejected.
206 // XXX: This is probably a misuse of the session ID slot.
207 im.imSessionID = copyID.Guid;
217 } 208 }
218 else 209 else
219 { 210 {
@@ -226,13 +217,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
226 "into agent {1}'s inventory", 217 "into agent {1}'s inventory",
227 itemID, new UUID(im.toAgentID)); 218 itemID, new UUID(im.toAgentID));
228 219
229 InventoryItemBase itemCopy = scene.GiveInventoryItem( 220 string message;
230 new UUID(im.toAgentID), 221 InventoryItemBase itemCopy = scene.GiveInventoryItem(new UUID(im.toAgentID), client.AgentId, itemID, out message);
231 client.AgentId, itemID);
232 222
233 if (itemCopy == null) 223 if (itemCopy == null)
234 { 224 {
235 client.SendAgentAlertMessage("Can't find item to give. Nothing given.", false); 225 client.SendAgentAlertMessage(message, false);
236 return; 226 return;
237 } 227 }
238 228
@@ -243,7 +233,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
243 user.ControllingClient.SendBulkUpdateInventory(itemCopy); 233 user.ControllingClient.SendBulkUpdateInventory(itemCopy);
244 234
245 // HACK!! 235 // HACK!!
246 im.imSessionID = itemID.Guid; 236 // Insert the ID of the copied item into the IM so that we know which item to move to trash if it
237 // is rejected.
238 // XXX: This is probably a misuse of the session ID slot.
239 im.imSessionID = copyID.Guid;
247 } 240 }
248 241
249 // Send the IM to the recipient. The item is already 242 // Send the IM to the recipient. The item is already
@@ -379,7 +372,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
379 IInventoryService invService = scene.InventoryService; 372 IInventoryService invService = scene.InventoryService;
380 373
381 InventoryFolderBase trashFolder = 374 InventoryFolderBase trashFolder =
382 invService.GetFolderForType(client.AgentId, AssetType.TrashFolder); 375 invService.GetFolderForType(client.AgentId, FolderType.Trash);
383 376
384 UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip 377 UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip
385 378
@@ -403,7 +396,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
403 { 396 {
404 folder = new InventoryFolderBase(inventoryID, client.AgentId); 397 folder = new InventoryFolderBase(inventoryID, client.AgentId);
405 folder = invService.GetFolder(folder); 398 folder = invService.GetFolder(folder);
406 399
407 if (folder != null & trashFolder != null) 400 if (folder != null & trashFolder != null)
408 { 401 {
409 previousParentFolderID = folder.ParentID; 402 previousParentFolderID = folder.ParentID;
@@ -454,90 +447,61 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
454 } 447 }
455 } 448 }
456 449
457// public bool NeedSceneCacheClear(UUID agentID, Scene scene)
458// {
459// if (!m_AgentRegions.ContainsKey(agentID))
460// {
461// // Since we can get here two ways, we need to scan
462// // the scenes here. This is somewhat more expensive
463// // but helps avoid a nasty bug
464// //
465//
466// foreach (Scene s in m_Scenelist)
467// {
468// ScenePresence presence;
469//
470// if (s.TryGetScenePresence(agentID, out presence))
471// {
472// // If the agent is in this scene, then we
473// // are being called twice in a single
474// // teleport. This is wasteful of cycles
475// // but harmless due to this 2nd level check
476// //
477// // If the agent is found in another scene
478// // then the list wasn't current
479// //
480// // If the agent is totally unknown, then what
481// // are we even doing here??
482// //
483// if (s == scene)
484// {
485// //m_log.Debug("[INVTRANSFERMOD]: s == scene. Returning true in " + scene.RegionInfo.RegionName);
486// return true;
487// }
488// else
489// {
490// //m_log.Debug("[INVTRANSFERMOD]: s != scene. Returning false in " + scene.RegionInfo.RegionName);
491// return false;
492// }
493// }
494// }
495// //m_log.Debug("[INVTRANSFERMOD]: agent not in scene. Returning true in " + scene.RegionInfo.RegionName);
496// return true;
497// }
498//
499// // The agent is left in current Scene, so we must be
500// // going to another instance
501// //
502// if (m_AgentRegions[agentID] == scene)
503// {
504// //m_log.Debug("[INVTRANSFERMOD]: m_AgentRegions[agentID] == scene. Returning true in " + scene.RegionInfo.RegionName);
505// m_AgentRegions.Remove(agentID);
506// return true;
507// }
508//
509// // Another region has claimed the agent
510// //
511// //m_log.Debug("[INVTRANSFERMOD]: last resort. Returning false in " + scene.RegionInfo.RegionName);
512// return false;
513// }
514//
515// public void ClientLoggedOut(UUID agentID, Scene scene)
516// {
517// if (m_AgentRegions.ContainsKey(agentID))
518// m_AgentRegions.Remove(agentID);
519// }
520
521 /// <summary> 450 /// <summary>
522 /// 451 ///
523 /// </summary> 452 /// </summary>
524 /// <param name="msg"></param> 453 /// <param name="im"></param>
525 private void OnGridInstantMessage(GridInstantMessage msg) 454 private void OnGridInstantMessage(GridInstantMessage im)
526 { 455 {
456 // Check if it's a type of message that we should handle
457 if (!((im.dialog == (byte) InstantMessageDialog.InventoryOffered)
458 || (im.dialog == (byte) InstantMessageDialog.TaskInventoryOffered)
459 || (im.dialog == (byte) InstantMessageDialog.InventoryAccepted)
460 || (im.dialog == (byte) InstantMessageDialog.InventoryDeclined)
461 || (im.dialog == (byte) InstantMessageDialog.TaskInventoryDeclined)))
462 return;
463
464 m_log.DebugFormat(
465 "[INVENTORY TRANSFER]: {0} IM type received from grid. From={1} ({2}), To={3}",
466 (InstantMessageDialog)im.dialog, im.fromAgentID, im.fromAgentName, im.toAgentID);
467
527 // Check if this is ours to handle 468 // Check if this is ours to handle
528 // 469 //
529 Scene scene = FindClientScene(new UUID(msg.toAgentID)); 470 Scene scene = FindClientScene(new UUID(im.toAgentID));
530 471
531 if (scene == null) 472 if (scene == null)
532 return; 473 return;
533 474
534 // Find agent to deliver to 475 // Find agent to deliver to
535 // 476 //
536 ScenePresence user = scene.GetScenePresence(new UUID(msg.toAgentID)); 477 ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
537 478
538 // Just forward to local handling 479 if (user != null)
539 OnInstantMessage(user.ControllingClient, msg); 480 {
481 user.ControllingClient.SendInstantMessage(im);
482
483 if (im.dialog == (byte)InstantMessageDialog.InventoryOffered)
484 {
485 AssetType assetType = (AssetType)im.binaryBucket[0];
486 UUID inventoryID = new UUID(im.binaryBucket, 1);
487
488 IInventoryService invService = scene.InventoryService;
489 InventoryNodeBase node = null;
490 if (AssetType.Folder == assetType)
491 {
492 InventoryFolderBase folder = new InventoryFolderBase(inventoryID, new UUID(im.toAgentID));
493 node = invService.GetFolder(folder);
494 }
495 else
496 {
497 InventoryItemBase item = new InventoryItemBase(inventoryID, new UUID(im.toAgentID));
498 node = invService.GetItem(item);
499 }
540 500
501 if (node != null)
502 user.ControllingClient.SendBulkUpdateInventory(node);
503 }
504 }
541 } 505 }
542 } 506 }
543} 507}
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs
new file mode 100644
index 0000000..7ddc396
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs
@@ -0,0 +1,448 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using log4net.Config;
32using Nini.Config;
33using NUnit.Framework;
34using OpenMetaverse;
35using OpenMetaverse.Assets;
36using OpenSim.Framework;
37using OpenSim.Region.CoreModules.Avatar.Inventory.Transfer;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using OpenSim.Tests.Common;
42
43namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests
44{
45 [TestFixture]
46 public class InventoryTransferModuleTests : OpenSimTestCase
47 {
48 protected TestScene m_scene;
49
50 [SetUp]
51 public override void SetUp()
52 {
53 base.SetUp();
54
55 IConfigSource config = new IniConfigSource();
56 config.AddConfig("Messaging");
57 config.Configs["Messaging"].Set("InventoryTransferModule", "InventoryTransferModule");
58
59 m_scene = new SceneHelpers().SetupScene();
60 SceneHelpers.SetupSceneModules(m_scene, config, new InventoryTransferModule());
61 }
62
63 [Test]
64 public void TestAcceptGivenItem()
65 {
66// TestHelpers.EnableLogging();
67
68 UUID initialSessionId = TestHelpers.ParseTail(0x10);
69 UUID itemId = TestHelpers.ParseTail(0x100);
70 UUID assetId = TestHelpers.ParseTail(0x200);
71
72 UserAccount ua1
73 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw");
74 UserAccount ua2
75 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw");
76
77 ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1);
78 TestClient giverClient = (TestClient)giverSp.ControllingClient;
79
80 ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2);
81 TestClient receiverClient = (TestClient)receiverSp.ControllingClient;
82
83 // Create the object to test give
84 InventoryItemBase originalItem
85 = UserInventoryHelpers.CreateInventoryItem(
86 m_scene, "givenObj", itemId, assetId, giverSp.UUID, InventoryType.Object);
87
88 byte[] giveImBinaryBucket = new byte[17];
89 byte[] itemIdBytes = itemId.GetBytes();
90 Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length);
91
92 GridInstantMessage giveIm
93 = new GridInstantMessage(
94 m_scene,
95 giverSp.UUID,
96 giverSp.Name,
97 receiverSp.UUID,
98 (byte)InstantMessageDialog.InventoryOffered,
99 false,
100 "inventory offered msg",
101 initialSessionId,
102 false,
103 Vector3.Zero,
104 giveImBinaryBucket,
105 true);
106
107 giverClient.HandleImprovedInstantMessage(giveIm);
108
109 // These details might not all be correct.
110 GridInstantMessage acceptIm
111 = new GridInstantMessage(
112 m_scene,
113 receiverSp.UUID,
114 receiverSp.Name,
115 giverSp.UUID,
116 (byte)InstantMessageDialog.InventoryAccepted,
117 false,
118 "inventory accepted msg",
119 initialSessionId,
120 false,
121 Vector3.Zero,
122 null,
123 true);
124
125 receiverClient.HandleImprovedInstantMessage(acceptIm);
126
127 // Test for item remaining in the giver's inventory (here we assume a copy item)
128 // TODO: Test no-copy items.
129 InventoryItemBase originalItemAfterGive
130 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj");
131
132 Assert.That(originalItemAfterGive, Is.Not.Null);
133 Assert.That(originalItemAfterGive.ID, Is.EqualTo(originalItem.ID));
134
135 // Test for item successfully making it into the receiver's inventory
136 InventoryItemBase receivedItem
137 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, receiverSp.UUID, "Objects/givenObj");
138
139 Assert.That(receivedItem, Is.Not.Null);
140 Assert.That(receivedItem.ID, Is.Not.EqualTo(originalItem.ID));
141
142 // Test that on a delete, item still exists and is accessible for the giver.
143 m_scene.InventoryService.DeleteItems(receiverSp.UUID, new List<UUID>() { receivedItem.ID });
144
145 InventoryItemBase originalItemAfterDelete
146 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj");
147
148 Assert.That(originalItemAfterDelete, Is.Not.Null);
149
150 // TODO: Test scenario where giver deletes their item first.
151 }
152
153 /// <summary>
154 /// Test user rejection of a given item.
155 /// </summary>
156 /// <remarks>
157 /// A rejected item still ends up in the user's trash folder.
158 /// </remarks>
159 [Test]
160 public void TestRejectGivenItem()
161 {
162// TestHelpers.EnableLogging();
163
164 UUID initialSessionId = TestHelpers.ParseTail(0x10);
165 UUID itemId = TestHelpers.ParseTail(0x100);
166 UUID assetId = TestHelpers.ParseTail(0x200);
167
168 UserAccount ua1
169 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw");
170 UserAccount ua2
171 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw");
172
173 ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1);
174 TestClient giverClient = (TestClient)giverSp.ControllingClient;
175
176 ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2);
177 TestClient receiverClient = (TestClient)receiverSp.ControllingClient;
178
179 // Create the object to test give
180 InventoryItemBase originalItem
181 = UserInventoryHelpers.CreateInventoryItem(
182 m_scene, "givenObj", itemId, assetId, giverSp.UUID, InventoryType.Object);
183
184 GridInstantMessage receivedIm = null;
185 receiverClient.OnReceivedInstantMessage += im => receivedIm = im;
186
187 byte[] giveImBinaryBucket = new byte[17];
188 byte[] itemIdBytes = itemId.GetBytes();
189 Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length);
190
191 GridInstantMessage giveIm
192 = new GridInstantMessage(
193 m_scene,
194 giverSp.UUID,
195 giverSp.Name,
196 receiverSp.UUID,
197 (byte)InstantMessageDialog.InventoryOffered,
198 false,
199 "inventory offered msg",
200 initialSessionId,
201 false,
202 Vector3.Zero,
203 giveImBinaryBucket,
204 true);
205
206 giverClient.HandleImprovedInstantMessage(giveIm);
207
208 // These details might not all be correct.
209 // Session ID is now the created item ID (!)
210 GridInstantMessage rejectIm
211 = new GridInstantMessage(
212 m_scene,
213 receiverSp.UUID,
214 receiverSp.Name,
215 giverSp.UUID,
216 (byte)InstantMessageDialog.InventoryDeclined,
217 false,
218 "inventory declined msg",
219 new UUID(receivedIm.imSessionID),
220 false,
221 Vector3.Zero,
222 null,
223 true);
224
225 receiverClient.HandleImprovedInstantMessage(rejectIm);
226
227 // Test for item remaining in the giver's inventory (here we assume a copy item)
228 // TODO: Test no-copy items.
229 InventoryItemBase originalItemAfterGive
230 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj");
231
232 Assert.That(originalItemAfterGive, Is.Not.Null);
233 Assert.That(originalItemAfterGive.ID, Is.EqualTo(originalItem.ID));
234
235 // Test for item successfully making it into the receiver's inventory
236 InventoryItemBase receivedItem
237 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, receiverSp.UUID, "Trash/givenObj");
238
239 InventoryFolderBase trashFolder
240 = m_scene.InventoryService.GetFolderForType(receiverSp.UUID, FolderType.Trash);
241
242 Assert.That(receivedItem, Is.Not.Null);
243 Assert.That(receivedItem.ID, Is.Not.EqualTo(originalItem.ID));
244 Assert.That(receivedItem.Folder, Is.EqualTo(trashFolder.ID));
245
246 // Test that on a delete, item still exists and is accessible for the giver.
247 m_scene.InventoryService.PurgeFolder(trashFolder);
248
249 InventoryItemBase originalItemAfterDelete
250 = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj");
251
252 Assert.That(originalItemAfterDelete, Is.Not.Null);
253 }
254
255 [Test]
256 public void TestAcceptGivenFolder()
257 {
258 TestHelpers.InMethod();
259// TestHelpers.EnableLogging();
260
261 UUID initialSessionId = TestHelpers.ParseTail(0x10);
262 UUID folderId = TestHelpers.ParseTail(0x100);
263
264 UserAccount ua1
265 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw");
266 UserAccount ua2
267 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw");
268
269 ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1);
270 TestClient giverClient = (TestClient)giverSp.ControllingClient;
271
272 ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2);
273 TestClient receiverClient = (TestClient)receiverSp.ControllingClient;
274
275 InventoryFolderBase originalFolder
276 = UserInventoryHelpers.CreateInventoryFolder(
277 m_scene.InventoryService, giverSp.UUID, folderId, "f1", true);
278
279 byte[] giveImBinaryBucket = new byte[17];
280 giveImBinaryBucket[0] = (byte)AssetType.Folder;
281 byte[] itemIdBytes = folderId.GetBytes();
282 Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length);
283
284 GridInstantMessage giveIm
285 = new GridInstantMessage(
286 m_scene,
287 giverSp.UUID,
288 giverSp.Name,
289 receiverSp.UUID,
290 (byte)InstantMessageDialog.InventoryOffered,
291 false,
292 "inventory offered msg",
293 initialSessionId,
294 false,
295 Vector3.Zero,
296 giveImBinaryBucket,
297 true);
298
299 giverClient.HandleImprovedInstantMessage(giveIm);
300
301 // These details might not all be correct.
302 GridInstantMessage acceptIm
303 = new GridInstantMessage(
304 m_scene,
305 receiverSp.UUID,
306 receiverSp.Name,
307 giverSp.UUID,
308 (byte)InstantMessageDialog.InventoryAccepted,
309 false,
310 "inventory accepted msg",
311 initialSessionId,
312 false,
313 Vector3.Zero,
314 null,
315 true);
316
317 receiverClient.HandleImprovedInstantMessage(acceptIm);
318
319 // Test for item remaining in the giver's inventory (here we assume a copy item)
320 // TODO: Test no-copy items.
321 InventoryFolderBase originalFolderAfterGive
322 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1");
323
324 Assert.That(originalFolderAfterGive, Is.Not.Null);
325 Assert.That(originalFolderAfterGive.ID, Is.EqualTo(originalFolder.ID));
326
327 // Test for item successfully making it into the receiver's inventory
328 InventoryFolderBase receivedFolder
329 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, receiverSp.UUID, "f1");
330
331 Assert.That(receivedFolder, Is.Not.Null);
332 Assert.That(receivedFolder.ID, Is.Not.EqualTo(originalFolder.ID));
333
334 // Test that on a delete, item still exists and is accessible for the giver.
335 m_scene.InventoryService.DeleteFolders(receiverSp.UUID, new List<UUID>() { receivedFolder.ID });
336
337 InventoryFolderBase originalFolderAfterDelete
338 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1");
339
340 Assert.That(originalFolderAfterDelete, Is.Not.Null);
341
342 // TODO: Test scenario where giver deletes their item first.
343 }
344
345 /// <summary>
346 /// Test user rejection of a given item.
347 /// </summary>
348 /// <remarks>
349 /// A rejected item still ends up in the user's trash folder.
350 /// </remarks>
351 [Test]
352 public void TestRejectGivenFolder()
353 {
354 TestHelpers.InMethod();
355// TestHelpers.EnableLogging();
356
357 UUID initialSessionId = TestHelpers.ParseTail(0x10);
358 UUID folderId = TestHelpers.ParseTail(0x100);
359
360 UserAccount ua1
361 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw");
362 UserAccount ua2
363 = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw");
364
365 ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1);
366 TestClient giverClient = (TestClient)giverSp.ControllingClient;
367
368 ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2);
369 TestClient receiverClient = (TestClient)receiverSp.ControllingClient;
370
371 // Create the folder to test give
372 InventoryFolderBase originalFolder
373 = UserInventoryHelpers.CreateInventoryFolder(
374 m_scene.InventoryService, giverSp.UUID, folderId, "f1", true);
375
376 GridInstantMessage receivedIm = null;
377 receiverClient.OnReceivedInstantMessage += im => receivedIm = im;
378
379 byte[] giveImBinaryBucket = new byte[17];
380 giveImBinaryBucket[0] = (byte)AssetType.Folder;
381 byte[] itemIdBytes = folderId.GetBytes();
382 Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length);
383
384 GridInstantMessage giveIm
385 = new GridInstantMessage(
386 m_scene,
387 giverSp.UUID,
388 giverSp.Name,
389 receiverSp.UUID,
390 (byte)InstantMessageDialog.InventoryOffered,
391 false,
392 "inventory offered msg",
393 initialSessionId,
394 false,
395 Vector3.Zero,
396 giveImBinaryBucket,
397 true);
398
399 giverClient.HandleImprovedInstantMessage(giveIm);
400
401 // These details might not all be correct.
402 // Session ID is now the created item ID (!)
403 GridInstantMessage rejectIm
404 = new GridInstantMessage(
405 m_scene,
406 receiverSp.UUID,
407 receiverSp.Name,
408 giverSp.UUID,
409 (byte)InstantMessageDialog.InventoryDeclined,
410 false,
411 "inventory declined msg",
412 new UUID(receivedIm.imSessionID),
413 false,
414 Vector3.Zero,
415 null,
416 true);
417
418 receiverClient.HandleImprovedInstantMessage(rejectIm);
419
420 // Test for item remaining in the giver's inventory (here we assume a copy item)
421 // TODO: Test no-copy items.
422 InventoryFolderBase originalFolderAfterGive
423 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1");
424
425 Assert.That(originalFolderAfterGive, Is.Not.Null);
426 Assert.That(originalFolderAfterGive.ID, Is.EqualTo(originalFolder.ID));
427
428 // Test for folder successfully making it into the receiver's inventory
429 InventoryFolderBase receivedFolder
430 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, receiverSp.UUID, "Trash/f1");
431
432 InventoryFolderBase trashFolder
433 = m_scene.InventoryService.GetFolderForType(receiverSp.UUID, FolderType.Trash);
434
435 Assert.That(receivedFolder, Is.Not.Null);
436 Assert.That(receivedFolder.ID, Is.Not.EqualTo(originalFolder.ID));
437 Assert.That(receivedFolder.ParentID, Is.EqualTo(trashFolder.ID));
438
439 // Test that on a delete, item still exists and is accessible for the giver.
440 m_scene.InventoryService.PurgeFolder(trashFolder);
441
442 InventoryFolderBase originalFolderAfterDelete
443 = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1");
444
445 Assert.That(originalFolderAfterDelete, Is.Not.Null);
446 }
447 }
448} \ 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 232a4fe..24286a4 100644
--- a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs
@@ -65,7 +65,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
65 { 65 {
66 m_Enabled = true; 66 m_Enabled = true;
67 67
68 m_ThisGridURL = config.Configs["Messaging"].GetString("Gatekeeper", string.Empty); 68 m_ThisGridURL = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI",
69 new string[] { "Startup", "Hypergrid", "Messaging" }, String.Empty);
70 // Legacy. Remove soon!
71 m_ThisGridURL = config.Configs["Messaging"].GetString("Gatekeeper", m_ThisGridURL);
69 m_log.DebugFormat("[LURE MODULE]: {0} enabled", Name); 72 m_log.DebugFormat("[LURE MODULE]: {0} enabled", Name);
70 } 73 }
71 } 74 }
@@ -151,7 +154,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
151 154
152 void OnIncomingInstantMessage(GridInstantMessage im) 155 void OnIncomingInstantMessage(GridInstantMessage im)
153 { 156 {
154 if (im.dialog == (byte)InstantMessageDialog.RequestTeleport) 157 if (im.dialog == (byte)InstantMessageDialog.RequestTeleport
158 || im.dialog == (byte)InstantMessageDialog.GodLikeRequestTeleport)
155 { 159 {
156 UUID sessionID = new UUID(im.imSessionID); 160 UUID sessionID = new UUID(im.imSessionID);
157 161
@@ -235,16 +239,29 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
235 GatekeeperServiceConnector gConn = new GatekeeperServiceConnector(); 239 GatekeeperServiceConnector gConn = new GatekeeperServiceConnector();
236 GridRegion gatekeeper = new GridRegion(); 240 GridRegion gatekeeper = new GridRegion();
237 gatekeeper.ServerURI = url; 241 gatekeeper.ServerURI = url;
238 GridRegion finalDestination = gConn.GetHyperlinkRegion(gatekeeper, new UUID(im.RegionID)); 242 string homeURI = scene.GetAgentHomeURI(client.AgentId);
243
244 string message;
245 GridRegion finalDestination = gConn.GetHyperlinkRegion(gatekeeper, new UUID(im.RegionID), client.AgentId, homeURI, out message);
239 if (finalDestination != null) 246 if (finalDestination != null)
240 { 247 {
241 ScenePresence sp = scene.GetScenePresence(client.AgentId); 248 ScenePresence sp = scene.GetScenePresence(client.AgentId);
242 IEntityTransferModule transferMod = scene.RequestModuleInterface<IEntityTransferModule>(); 249 IEntityTransferModule transferMod = scene.RequestModuleInterface<IEntityTransferModule>();
243 250
244 if (transferMod != null && sp != null) 251 if (transferMod != null && sp != null)
252 {
253 if (message != null)
254 sp.ControllingClient.SendAgentAlertMessage(message, true);
255
245 transferMod.DoTeleport( 256 transferMod.DoTeleport(
246 sp, gatekeeper, finalDestination, im.Position + new Vector3(0.5f, 0.5f, 0f), 257 sp, gatekeeper, finalDestination, im.Position + new Vector3(0.5f, 0.5f, 0f),
247 Vector3.UnitX, teleportflags); 258 Vector3.UnitX, teleportflags);
259 }
260 }
261 else
262 {
263 m_log.InfoFormat("[HG LURE MODULE]: Lure failed: {0}", message);
264 client.SendAgentAlertMessage(message, true);
248 } 265 }
249 } 266 }
250 } 267 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
index e4b0cfa..465ffbc 100644
--- a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
@@ -165,7 +165,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
165 (uint)presence.AbsolutePosition.Y, 165 (uint)presence.AbsolutePosition.Y,
166 (uint)Math.Ceiling(presence.AbsolutePosition.Z)); 166 (uint)Math.Ceiling(presence.AbsolutePosition.Z));
167 167
168 m_log.DebugFormat("TP invite with message {0}", message); 168 m_log.DebugFormat("[LURE MODULE]: TP invite with message {0}, type {1}", message, lureType);
169 169
170 GridInstantMessage m = new GridInstantMessage(scene, client.AgentId, 170 GridInstantMessage m = new GridInstantMessage(scene, client.AgentId,
171 client.FirstName+" "+client.LastName, targetid, 171 client.FirstName+" "+client.LastName, targetid,
diff --git a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs
index bf24030..2bb24ae 100644
--- a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs
@@ -57,6 +57,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Profile
57 57
58 public void Initialise(IConfigSource config) 58 public void Initialise(IConfigSource config)
59 { 59 {
60 if(config.Configs["UserProfiles"] != null)
61 return;
62
60 m_log.DebugFormat("[PROFILE MODULE]: Basic Profile Module enabled"); 63 m_log.DebugFormat("[PROFILE MODULE]: Basic Profile Module enabled");
61 m_Enabled = true; 64 m_Enabled = true;
62 } 65 }
diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs
new file mode 100644
index 0000000..c20369c
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs
@@ -0,0 +1,1406 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Text;
31using System.Collections;
32using System.Collections.Generic;
33using System.Globalization;
34using System.Net;
35using System.Net.Sockets;
36using System.Reflection;
37using System.Xml;
38using OpenMetaverse;
39using OpenMetaverse.StructuredData;
40using log4net;
41using Nini.Config;
42using Nwc.XmlRpc;
43using OpenSim.Framework;
44using OpenSim.Region.Framework.Interfaces;
45using OpenSim.Region.Framework.Scenes;
46using OpenSim.Services.Interfaces;
47using Mono.Addins;
48using OpenSim.Services.Connectors.Hypergrid;
49using OpenSim.Framework.Servers.HttpServer;
50using OpenSim.Services.UserProfilesService;
51using GridRegion = OpenSim.Services.Interfaces.GridRegion;
52using Microsoft.CSharp;
53
54namespace OpenSim.Region.CoreModules.Avatar.UserProfiles
55{
56 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserProfilesModule")]
57 public class UserProfileModule : IProfileModule, INonSharedRegionModule
58 {
59 /// <summary>
60 /// Logging
61 /// </summary>
62 static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
63
64 // The pair of Dictionaries are used to handle the switching of classified ads
65 // by maintaining a cache of classified id to creator id mappings and an interest
66 // count. The entries are removed when the interest count reaches 0.
67 Dictionary<UUID, UUID> m_classifiedCache = new Dictionary<UUID, UUID>();
68 Dictionary<UUID, int> m_classifiedInterest = new Dictionary<UUID, int>();
69
70 private JsonRpcRequestManager rpc = new JsonRpcRequestManager();
71
72 public Scene Scene
73 {
74 get; private set;
75 }
76
77 /// <summary>
78 /// Gets or sets the ConfigSource.
79 /// </summary>
80 /// <value>
81 /// The configuration
82 /// </value>
83 public IConfigSource Config
84 {
85 get;
86 set;
87 }
88
89 /// <summary>
90 /// Gets or sets the URI to the profile server.
91 /// </summary>
92 /// <value>
93 /// The profile server URI.
94 /// </value>
95 public string ProfileServerUri
96 {
97 get;
98 set;
99 }
100
101 IProfileModule ProfileModule
102 {
103 get; set;
104 }
105
106 IUserManagement UserManagementModule
107 {
108 get; set;
109 }
110
111 /// <summary>
112 /// Gets or sets a value indicating whether this
113 /// <see cref="OpenSim.Region.Coremodules.UserProfiles.UserProfileModule"/> is enabled.
114 /// </summary>
115 /// <value>
116 /// <c>true</c> if enabled; otherwise, <c>false</c>.
117 /// </value>
118 public bool Enabled
119 {
120 get;
121 set;
122 }
123
124 public string MyGatekeeper
125 {
126 get; private set;
127 }
128
129
130 #region IRegionModuleBase implementation
131 /// <summary>
132 /// This is called to initialize the region module. For shared modules, this is called exactly once, after
133 /// creating the single (shared) instance. For non-shared modules, this is called once on each instance, after
134 /// the instace for the region has been created.
135 /// </summary>
136 /// <param name='source'>
137 /// Source.
138 /// </param>
139 public void Initialise(IConfigSource source)
140 {
141 Config = source;
142 ReplaceableInterface = typeof(IProfileModule);
143
144 IConfig profileConfig = Config.Configs["UserProfiles"];
145
146 if (profileConfig == null)
147 {
148 m_log.Debug("[PROFILES]: UserProfiles disabled, no configuration");
149 Enabled = false;
150 return;
151 }
152
153 // If we find ProfileURL then we configure for FULL support
154 // else we setup for BASIC support
155 ProfileServerUri = profileConfig.GetString("ProfileServiceURL", "");
156 if (ProfileServerUri == "")
157 {
158 Enabled = false;
159 return;
160 }
161
162 m_log.Debug("[PROFILES]: Full Profiles Enabled");
163 ReplaceableInterface = null;
164 Enabled = true;
165
166 MyGatekeeper = Util.GetConfigVarFromSections<string>(source, "GatekeeperURI",
167 new string[] { "Startup", "Hypergrid", "UserProfiles" }, String.Empty);
168 }
169
170 /// <summary>
171 /// Adds the region.
172 /// </summary>
173 /// <param name='scene'>
174 /// Scene.
175 /// </param>
176 public void AddRegion(Scene scene)
177 {
178 if(!Enabled)
179 return;
180
181 Scene = scene;
182 Scene.RegisterModuleInterface<IProfileModule>(this);
183 Scene.EventManager.OnNewClient += OnNewClient;
184 Scene.EventManager.OnMakeRootAgent += HandleOnMakeRootAgent;
185
186 UserManagementModule = Scene.RequestModuleInterface<IUserManagement>();
187 }
188
189 void HandleOnMakeRootAgent (ScenePresence obj)
190 {
191 if(obj.PresenceType == PresenceType.Npc)
192 return;
193
194 Util.FireAndForget(delegate
195 {
196 GetImageAssets(((IScenePresence)obj).UUID);
197 }, null, "UserProfileModule.GetImageAssets");
198 }
199
200 /// <summary>
201 /// Removes the region.
202 /// </summary>
203 /// <param name='scene'>
204 /// Scene.
205 /// </param>
206 public void RemoveRegion(Scene scene)
207 {
208 if(!Enabled)
209 return;
210 }
211
212 /// <summary>
213 /// This will be called once for every scene loaded. In a shared module this will be multiple times in one
214 /// instance, while a nonshared module instance will only be called once. This method is called after AddRegion
215 /// has been called in all modules for that scene, providing an opportunity to request another module's
216 /// interface, or hook an event from another module.
217 /// </summary>
218 /// <param name='scene'>
219 /// Scene.
220 /// </param>
221 public void RegionLoaded(Scene scene)
222 {
223 if(!Enabled)
224 return;
225 }
226
227 /// <summary>
228 /// If this returns non-null, it is the type of an interface that this module intends to register. This will
229 /// cause the loader to defer loading of this module until all other modules have been loaded. If no other
230 /// module has registered the interface by then, this module will be activated, else it will remain inactive,
231 /// letting the other module take over. This should return non-null ONLY in modules that are intended to be
232 /// easily replaceable, e.g. stub implementations that the developer expects to be replaced by third party
233 /// provided modules.
234 /// </summary>
235 /// <value>
236 /// The replaceable interface.
237 /// </value>
238 public Type ReplaceableInterface
239 {
240 get; private set;
241 }
242
243 /// <summary>
244 /// Called as the instance is closed.
245 /// </summary>
246 public void Close()
247 {
248 }
249
250 /// <value>
251 /// The name of the module
252 /// </value>
253 /// <summary>
254 /// Gets the module name.
255 /// </summary>
256 public string Name
257 {
258 get { return "UserProfileModule"; }
259 }
260 #endregion IRegionModuleBase implementation
261
262 #region Region Event Handlers
263 /// <summary>
264 /// Raises the new client event.
265 /// </summary>
266 /// <param name='client'>
267 /// Client.
268 /// </param>
269 void OnNewClient(IClientAPI client)
270 {
271 //Profile
272 client.OnRequestAvatarProperties += RequestAvatarProperties;
273 client.OnUpdateAvatarProperties += AvatarPropertiesUpdate;
274 client.OnAvatarInterestUpdate += AvatarInterestsUpdate;
275
276 // Classifieds
277 client.AddGenericPacketHandler("avatarclassifiedsrequest", ClassifiedsRequest);
278 client.OnClassifiedInfoUpdate += ClassifiedInfoUpdate;
279 client.OnClassifiedInfoRequest += ClassifiedInfoRequest;
280 client.OnClassifiedDelete += ClassifiedDelete;
281
282 // Picks
283 client.AddGenericPacketHandler("avatarpicksrequest", PicksRequest);
284 client.AddGenericPacketHandler("pickinforequest", PickInfoRequest);
285 client.OnPickInfoUpdate += PickInfoUpdate;
286 client.OnPickDelete += PickDelete;
287
288 // Notes
289 client.AddGenericPacketHandler("avatarnotesrequest", NotesRequest);
290 client.OnAvatarNotesUpdate += NotesUpdate;
291
292 // Preferences
293 client.OnUserInfoRequest += UserPreferencesRequest;
294 client.OnUpdateUserInfo += UpdateUserPreferences;
295 }
296 #endregion Region Event Handlers
297
298 #region Classified
299 ///
300 /// <summary>
301 /// Handles the avatar classifieds request.
302 /// </summary>
303 /// <param name='sender'>
304 /// Sender.
305 /// </param>
306 /// <param name='method'>
307 /// Method.
308 /// </param>
309 /// <param name='args'>
310 /// Arguments.
311 /// </param>
312 public void ClassifiedsRequest(Object sender, string method, List<String> args)
313 {
314 if (!(sender is IClientAPI))
315 return;
316
317 IClientAPI remoteClient = (IClientAPI)sender;
318
319 UUID targetID;
320 UUID.TryParse(args[0], out targetID);
321
322 // Can't handle NPC yet...
323 ScenePresence p = FindPresence(targetID);
324
325 if (null != p)
326 {
327 if (p.PresenceType == PresenceType.Npc)
328 return;
329 }
330
331 string serverURI = string.Empty;
332 GetUserProfileServerURI(targetID, out serverURI);
333 UUID creatorId = UUID.Zero;
334 Dictionary<UUID, string> classifieds = new Dictionary<UUID, string>();
335
336 OSDMap parameters= new OSDMap();
337 UUID.TryParse(args[0], out creatorId);
338 parameters.Add("creatorId", OSD.FromUUID(creatorId));
339 OSD Params = (OSD)parameters;
340 if(!rpc.JsonRpcRequest(ref Params, "avatarclassifiedsrequest", serverURI, UUID.Random().ToString()))
341 {
342 remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), classifieds);
343 return;
344 }
345
346 parameters = (OSDMap)Params;
347
348 OSDArray list = (OSDArray)parameters["result"];
349
350
351 foreach(OSD map in list)
352 {
353 OSDMap m = (OSDMap)map;
354 UUID cid = m["classifieduuid"].AsUUID();
355 string name = m["name"].AsString();
356
357 classifieds[cid] = name;
358
359 lock (m_classifiedCache)
360 {
361 if (!m_classifiedCache.ContainsKey(cid))
362 {
363 m_classifiedCache.Add(cid,creatorId);
364 m_classifiedInterest.Add(cid, 0);
365 }
366
367 m_classifiedInterest[cid]++;
368 }
369 }
370
371 remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), classifieds);
372 }
373
374 public void ClassifiedInfoRequest(UUID queryClassifiedID, IClientAPI remoteClient)
375 {
376 UUID target = remoteClient.AgentId;
377 UserClassifiedAdd ad = new UserClassifiedAdd();
378 ad.ClassifiedId = queryClassifiedID;
379
380 lock (m_classifiedCache)
381 {
382 if (m_classifiedCache.ContainsKey(queryClassifiedID))
383 {
384 target = m_classifiedCache[queryClassifiedID];
385
386 m_classifiedInterest[queryClassifiedID] --;
387
388 if (m_classifiedInterest[queryClassifiedID] == 0)
389 {
390 m_classifiedInterest.Remove(queryClassifiedID);
391 m_classifiedCache.Remove(queryClassifiedID);
392 }
393 }
394 }
395
396 string serverURI = string.Empty;
397 GetUserProfileServerURI(target, out serverURI);
398
399 object Ad = (object)ad;
400 if(!rpc.JsonRpcRequest(ref Ad, "classifieds_info_query", serverURI, UUID.Random().ToString()))
401 {
402 remoteClient.SendAgentAlertMessage(
403 "Error getting classified info", false);
404 return;
405 }
406 ad = (UserClassifiedAdd) Ad;
407
408 if(ad.CreatorId == UUID.Zero)
409 return;
410
411 Vector3 globalPos = new Vector3();
412 Vector3.TryParse(ad.GlobalPos, out globalPos);
413
414 remoteClient.SendClassifiedInfoReply(ad.ClassifiedId, ad.CreatorId, (uint)ad.CreationDate, (uint)ad.ExpirationDate,
415 (uint)ad.Category, ad.Name, ad.Description, ad.ParcelId, (uint)ad.ParentEstate,
416 ad.SnapshotId, ad.SimName, globalPos, ad.ParcelName, ad.Flags, ad.Price);
417
418 }
419
420 /// <summary>
421 /// Classifieds info update.
422 /// </summary>
423 /// <param name='queryclassifiedID'>
424 /// Queryclassified I.
425 /// </param>
426 /// <param name='queryCategory'>
427 /// Query category.
428 /// </param>
429 /// <param name='queryName'>
430 /// Query name.
431 /// </param>
432 /// <param name='queryDescription'>
433 /// Query description.
434 /// </param>
435 /// <param name='queryParcelID'>
436 /// Query parcel I.
437 /// </param>
438 /// <param name='queryParentEstate'>
439 /// Query parent estate.
440 /// </param>
441 /// <param name='querySnapshotID'>
442 /// Query snapshot I.
443 /// </param>
444 /// <param name='queryGlobalPos'>
445 /// Query global position.
446 /// </param>
447 /// <param name='queryclassifiedFlags'>
448 /// Queryclassified flags.
449 /// </param>
450 /// <param name='queryclassifiedPrice'>
451 /// Queryclassified price.
452 /// </param>
453 /// <param name='remoteClient'>
454 /// Remote client.
455 /// </param>
456 public void ClassifiedInfoUpdate(UUID queryclassifiedID, uint queryCategory, string queryName, string queryDescription, UUID queryParcelID,
457 uint queryParentEstate, UUID querySnapshotID, Vector3 queryGlobalPos, byte queryclassifiedFlags,
458 int queryclassifiedPrice, IClientAPI remoteClient)
459 {
460 Scene s = (Scene)remoteClient.Scene;
461 IMoneyModule money = s.RequestModuleInterface<IMoneyModule>();
462
463 if (money != null)
464 {
465 if (!money.AmountCovered(remoteClient.AgentId, queryclassifiedPrice))
466 {
467 remoteClient.SendAgentAlertMessage("You do not have enough money to create requested classified.", false);
468 return;
469 }
470 money.ApplyCharge(remoteClient.AgentId, queryclassifiedPrice, MoneyTransactionType.ClassifiedCharge);
471 }
472
473 UserClassifiedAdd ad = new UserClassifiedAdd();
474
475 Vector3 pos = remoteClient.SceneAgent.AbsolutePosition;
476 ILandObject land = s.LandChannel.GetLandObject(pos.X, pos.Y);
477 ScenePresence p = FindPresence(remoteClient.AgentId);
478
479 string serverURI = string.Empty;
480 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
481
482 if (land == null)
483 {
484 ad.ParcelName = string.Empty;
485 }
486 else
487 {
488 ad.ParcelName = land.LandData.Name;
489 }
490
491 ad.CreatorId = remoteClient.AgentId;
492 ad.ClassifiedId = queryclassifiedID;
493 ad.Category = Convert.ToInt32(queryCategory);
494 ad.Name = queryName;
495 ad.Description = queryDescription;
496 ad.ParentEstate = Convert.ToInt32(queryParentEstate);
497 ad.SnapshotId = querySnapshotID;
498 ad.SimName = remoteClient.Scene.RegionInfo.RegionName;
499 ad.GlobalPos = queryGlobalPos.ToString ();
500 ad.Flags = queryclassifiedFlags;
501 ad.Price = queryclassifiedPrice;
502 ad.ParcelId = p.currentParcelUUID;
503
504 object Ad = ad;
505
506 OSD.SerializeMembers(Ad);
507
508 if(!rpc.JsonRpcRequest(ref Ad, "classified_update", serverURI, UUID.Random().ToString()))
509 {
510 remoteClient.SendAgentAlertMessage(
511 "Error updating classified", false);
512 return;
513 }
514 }
515
516 /// <summary>
517 /// Classifieds delete.
518 /// </summary>
519 /// <param name='queryClassifiedID'>
520 /// Query classified I.
521 /// </param>
522 /// <param name='remoteClient'>
523 /// Remote client.
524 /// </param>
525 public void ClassifiedDelete(UUID queryClassifiedID, IClientAPI remoteClient)
526 {
527 string serverURI = string.Empty;
528 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
529
530 UUID classifiedId;
531 OSDMap parameters= new OSDMap();
532 UUID.TryParse(queryClassifiedID.ToString(), out classifiedId);
533 parameters.Add("classifiedId", OSD.FromUUID(classifiedId));
534 OSD Params = (OSD)parameters;
535 if(!rpc.JsonRpcRequest(ref Params, "classified_delete", serverURI, UUID.Random().ToString()))
536 {
537 remoteClient.SendAgentAlertMessage(
538 "Error classified delete", false);
539 return;
540 }
541
542 parameters = (OSDMap)Params;
543 }
544 #endregion Classified
545
546 #region Picks
547 /// <summary>
548 /// Handles the avatar picks request.
549 /// </summary>
550 /// <param name='sender'>
551 /// Sender.
552 /// </param>
553 /// <param name='method'>
554 /// Method.
555 /// </param>
556 /// <param name='args'>
557 /// Arguments.
558 /// </param>
559 public void PicksRequest(Object sender, string method, List<String> args)
560 {
561 if (!(sender is IClientAPI))
562 return;
563
564 IClientAPI remoteClient = (IClientAPI)sender;
565
566 UUID targetId;
567 UUID.TryParse(args[0], out targetId);
568
569 // Can't handle NPC yet...
570 ScenePresence p = FindPresence(targetId);
571
572 if (null != p)
573 {
574 if (p.PresenceType == PresenceType.Npc)
575 return;
576 }
577
578 string serverURI = string.Empty;
579 GetUserProfileServerURI(targetId, out serverURI);
580
581 Dictionary<UUID, string> picks = new Dictionary<UUID, string>();
582
583 OSDMap parameters= new OSDMap();
584 parameters.Add("creatorId", OSD.FromUUID(targetId));
585 OSD Params = (OSD)parameters;
586 if(!rpc.JsonRpcRequest(ref Params, "avatarpicksrequest", serverURI, UUID.Random().ToString()))
587 {
588 remoteClient.SendAvatarPicksReply(new UUID(args[0]), picks);
589 return;
590 }
591
592 parameters = (OSDMap)Params;
593
594 OSDArray list = (OSDArray)parameters["result"];
595
596 foreach(OSD map in list)
597 {
598 OSDMap m = (OSDMap)map;
599 UUID cid = m["pickuuid"].AsUUID();
600 string name = m["name"].AsString();
601
602 m_log.DebugFormat("[PROFILES]: PicksRequest {0}", name);
603
604 picks[cid] = name;
605 }
606 remoteClient.SendAvatarPicksReply(new UUID(args[0]), picks);
607 }
608
609 /// <summary>
610 /// Handles the pick info request.
611 /// </summary>
612 /// <param name='sender'>
613 /// Sender.
614 /// </param>
615 /// <param name='method'>
616 /// Method.
617 /// </param>
618 /// <param name='args'>
619 /// Arguments.
620 /// </param>
621 public void PickInfoRequest(Object sender, string method, List<String> args)
622 {
623 if (!(sender is IClientAPI))
624 return;
625
626 UUID targetID;
627 UUID.TryParse (args [0], out targetID);
628 string serverURI = string.Empty;
629 GetUserProfileServerURI (targetID, out serverURI);
630
631 string theirGatekeeperURI;
632 GetUserGatekeeperURI (targetID, out theirGatekeeperURI);
633
634 IClientAPI remoteClient = (IClientAPI)sender;
635
636 UserProfilePick pick = new UserProfilePick ();
637 UUID.TryParse (args [0], out pick.CreatorId);
638 UUID.TryParse (args [1], out pick.PickId);
639
640
641 object Pick = (object)pick;
642 if (!rpc.JsonRpcRequest (ref Pick, "pickinforequest", serverURI, UUID.Random ().ToString ())) {
643 remoteClient.SendAgentAlertMessage (
644 "Error selecting pick", false);
645 return;
646 }
647 pick = (UserProfilePick)Pick;
648
649 Vector3 globalPos = new Vector3(Vector3.Zero);
650
651 // Smoke and mirrors
652 if (pick.Gatekeeper == MyGatekeeper)
653 {
654 Vector3.TryParse(pick.GlobalPos,out globalPos);
655 }
656 else
657 {
658 // Setup the illusion
659 string region = string.Format("{0} {1}",pick.Gatekeeper,pick.SimName);
660 GridRegion target = Scene.GridService.GetRegionByName(Scene.RegionInfo.ScopeID, region);
661
662 if(target == null)
663 {
664 // This is a dead or unreachable region
665 }
666 else
667 {
668 // Work our slight of hand
669 int x = target.RegionLocX;
670 int y = target.RegionLocY;
671
672 dynamic synthX = globalPos.X - (globalPos.X/Constants.RegionSize) * Constants.RegionSize;
673 synthX += x;
674 globalPos.X = synthX;
675
676 dynamic synthY = globalPos.Y - (globalPos.Y/Constants.RegionSize) * Constants.RegionSize;
677 synthY += y;
678 globalPos.Y = synthY;
679 }
680 }
681
682 m_log.DebugFormat("[PROFILES]: PickInfoRequest: {0} : {1}", pick.Name.ToString(), pick.SnapshotId.ToString());
683
684 // Pull the rabbit out of the hat
685 remoteClient.SendPickInfoReply(pick.PickId,pick.CreatorId,pick.TopPick,pick.ParcelId,pick.Name,
686 pick.Desc,pick.SnapshotId,pick.ParcelName,pick.OriginalName,pick.SimName,
687 globalPos,pick.SortOrder,pick.Enabled);
688 }
689
690 /// <summary>
691 /// Updates the userpicks
692 /// </summary>
693 /// <param name='remoteClient'>
694 /// Remote client.
695 /// </param>
696 /// <param name='pickID'>
697 /// Pick I.
698 /// </param>
699 /// <param name='creatorID'>
700 /// the creator of the pick
701 /// </param>
702 /// <param name='topPick'>
703 /// Top pick.
704 /// </param>
705 /// <param name='name'>
706 /// Name.
707 /// </param>
708 /// <param name='desc'>
709 /// Desc.
710 /// </param>
711 /// <param name='snapshotID'>
712 /// Snapshot I.
713 /// </param>
714 /// <param name='sortOrder'>
715 /// Sort order.
716 /// </param>
717 /// <param name='enabled'>
718 /// Enabled.
719 /// </param>
720 public void PickInfoUpdate(IClientAPI remoteClient, UUID pickID, UUID creatorID, bool topPick, string name, string desc, UUID snapshotID, int sortOrder, bool enabled)
721 {
722 //TODO: See how this works with NPC, May need to test
723 m_log.DebugFormat("[PROFILES]: Start PickInfoUpdate Name: {0} PickId: {1} SnapshotId: {2}", name, pickID.ToString(), snapshotID.ToString());
724
725 UserProfilePick pick = new UserProfilePick();
726 string serverURI = string.Empty;
727 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
728 ScenePresence p = FindPresence(remoteClient.AgentId);
729
730 Vector3 avaPos = p.AbsolutePosition;
731 // Getting the global position for the Avatar
732 Vector3 posGlobal = new Vector3(remoteClient.Scene.RegionInfo.WorldLocX + avaPos.X,
733 remoteClient.Scene.RegionInfo.WorldLocY + avaPos.Y,
734 avaPos.Z);
735
736 string landParcelName = "My Parcel";
737 UUID landParcelID = p.currentParcelUUID;
738
739 ILandObject land = p.Scene.LandChannel.GetLandObject(avaPos.X, avaPos.Y);
740
741 if (land != null)
742 {
743 // If land found, use parcel uuid from here because the value from SP will be blank if the avatar hasnt moved
744 landParcelName = land.LandData.Name;
745 landParcelID = land.LandData.GlobalID;
746 }
747 else
748 {
749 m_log.WarnFormat(
750 "[PROFILES]: PickInfoUpdate found no parcel info at {0},{1} in {2}",
751 avaPos.X, avaPos.Y, p.Scene.Name);
752 }
753
754
755 pick.PickId = pickID;
756 pick.CreatorId = creatorID;
757 pick.TopPick = topPick;
758 pick.Name = name;
759 pick.Desc = desc;
760 pick.ParcelId = landParcelID;
761 pick.SnapshotId = snapshotID;
762 pick.ParcelName = landParcelName;
763 pick.SimName = remoteClient.Scene.RegionInfo.RegionName;
764 pick.Gatekeeper = MyGatekeeper;
765 pick.GlobalPos = posGlobal.ToString();
766 pick.SortOrder = sortOrder;
767 pick.Enabled = enabled;
768
769 object Pick = (object)pick;
770 if(!rpc.JsonRpcRequest(ref Pick, "picks_update", serverURI, UUID.Random().ToString()))
771 {
772 remoteClient.SendAgentAlertMessage(
773 "Error updating pick", false);
774 return;
775 }
776
777 m_log.DebugFormat("[PROFILES]: Finish PickInfoUpdate {0} {1}", pick.Name, pick.PickId.ToString());
778 }
779
780 /// <summary>
781 /// Delete a Pick
782 /// </summary>
783 /// <param name='remoteClient'>
784 /// Remote client.
785 /// </param>
786 /// <param name='queryPickID'>
787 /// Query pick I.
788 /// </param>
789 public void PickDelete(IClientAPI remoteClient, UUID queryPickID)
790 {
791 string serverURI = string.Empty;
792 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
793
794 OSDMap parameters= new OSDMap();
795 parameters.Add("pickId", OSD.FromUUID(queryPickID));
796 OSD Params = (OSD)parameters;
797 if(!rpc.JsonRpcRequest(ref Params, "picks_delete", serverURI, UUID.Random().ToString()))
798 {
799 remoteClient.SendAgentAlertMessage(
800 "Error picks delete", false);
801 return;
802 }
803 }
804 #endregion Picks
805
806 #region Notes
807 /// <summary>
808 /// Handles the avatar notes request.
809 /// </summary>
810 /// <param name='sender'>
811 /// Sender.
812 /// </param>
813 /// <param name='method'>
814 /// Method.
815 /// </param>
816 /// <param name='args'>
817 /// Arguments.
818 /// </param>
819 public void NotesRequest(Object sender, string method, List<String> args)
820 {
821 UserProfileNotes note = new UserProfileNotes();
822
823 if (!(sender is IClientAPI))
824 return;
825
826 IClientAPI remoteClient = (IClientAPI)sender;
827 string serverURI = string.Empty;
828 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
829 note.UserId = remoteClient.AgentId;
830 UUID.TryParse(args[0], out note.TargetId);
831
832 object Note = (object)note;
833 if(!rpc.JsonRpcRequest(ref Note, "avatarnotesrequest", serverURI, UUID.Random().ToString()))
834 {
835 remoteClient.SendAvatarNotesReply(note.TargetId, note.Notes);
836 return;
837 }
838 note = (UserProfileNotes) Note;
839
840 remoteClient.SendAvatarNotesReply(note.TargetId, note.Notes);
841 }
842
843 /// <summary>
844 /// Avatars the notes update.
845 /// </summary>
846 /// <param name='remoteClient'>
847 /// Remote client.
848 /// </param>
849 /// <param name='queryTargetID'>
850 /// Query target I.
851 /// </param>
852 /// <param name='queryNotes'>
853 /// Query notes.
854 /// </param>
855 public void NotesUpdate(IClientAPI remoteClient, UUID queryTargetID, string queryNotes)
856 {
857 UserProfileNotes note = new UserProfileNotes();
858
859 note.UserId = remoteClient.AgentId;
860 note.TargetId = queryTargetID;
861 note.Notes = queryNotes;
862
863 string serverURI = string.Empty;
864 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
865
866 object Note = note;
867 if(!rpc.JsonRpcRequest(ref Note, "avatar_notes_update", serverURI, UUID.Random().ToString()))
868 {
869 remoteClient.SendAgentAlertMessage(
870 "Error updating note", false);
871 return;
872 }
873 }
874 #endregion Notes
875
876 #region User Preferences
877 /// <summary>
878 /// Updates the user preferences.
879 /// </summary>
880 /// <param name='imViaEmail'>
881 /// Im via email.
882 /// </param>
883 /// <param name='visible'>
884 /// Visible.
885 /// </param>
886 /// <param name='remoteClient'>
887 /// Remote client.
888 /// </param>
889 public void UpdateUserPreferences(bool imViaEmail, bool visible, IClientAPI remoteClient)
890 {
891 UserPreferences pref = new UserPreferences();
892
893 pref.UserId = remoteClient.AgentId;
894 pref.IMViaEmail = imViaEmail;
895 pref.Visible = visible;
896
897 string serverURI = string.Empty;
898 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
899
900 object Pref = pref;
901 if(!rpc.JsonRpcRequest(ref Pref, "user_preferences_update", serverURI, UUID.Random().ToString()))
902 {
903 m_log.InfoFormat("[PROFILES]: UserPreferences update error");
904 remoteClient.SendAgentAlertMessage("Error updating preferences", false);
905 return;
906 }
907 }
908
909 /// <summary>
910 /// Users the preferences request.
911 /// </summary>
912 /// <param name='remoteClient'>
913 /// Remote client.
914 /// </param>
915 public void UserPreferencesRequest(IClientAPI remoteClient)
916 {
917 UserPreferences pref = new UserPreferences();
918
919 pref.UserId = remoteClient.AgentId;
920
921 string serverURI = string.Empty;
922 bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
923
924
925 object Pref = (object)pref;
926 if(!rpc.JsonRpcRequest(ref Pref, "user_preferences_request", serverURI, UUID.Random().ToString()))
927 {
928// m_log.InfoFormat("[PROFILES]: UserPreferences request error");
929// remoteClient.SendAgentAlertMessage("Error requesting preferences", false);
930 return;
931 }
932 pref = (UserPreferences) Pref;
933
934 remoteClient.SendUserInfoReply(pref.IMViaEmail, pref.Visible, pref.EMail);
935
936 }
937 #endregion User Preferences
938
939 #region Avatar Properties
940 /// <summary>
941 /// Update the avatars interests .
942 /// </summary>
943 /// <param name='remoteClient'>
944 /// Remote client.
945 /// </param>
946 /// <param name='wantmask'>
947 /// Wantmask.
948 /// </param>
949 /// <param name='wanttext'>
950 /// Wanttext.
951 /// </param>
952 /// <param name='skillsmask'>
953 /// Skillsmask.
954 /// </param>
955 /// <param name='skillstext'>
956 /// Skillstext.
957 /// </param>
958 /// <param name='languages'>
959 /// Languages.
960 /// </param>
961 public void AvatarInterestsUpdate(IClientAPI remoteClient, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages)
962 {
963 UserProfileProperties prop = new UserProfileProperties();
964
965 prop.UserId = remoteClient.AgentId;
966 prop.WantToMask = (int)wantmask;
967 prop.WantToText = wanttext;
968 prop.SkillsMask = (int)skillsmask;
969 prop.SkillsText = skillstext;
970 prop.Language = languages;
971
972 string serverURI = string.Empty;
973 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
974
975 object Param = prop;
976 if(!rpc.JsonRpcRequest(ref Param, "avatar_interests_update", serverURI, UUID.Random().ToString()))
977 {
978 remoteClient.SendAgentAlertMessage(
979 "Error updating interests", false);
980 return;
981 }
982 }
983
984 public void RequestAvatarProperties(IClientAPI remoteClient, UUID avatarID)
985 {
986 if (String.IsNullOrEmpty(avatarID.ToString()) || String.IsNullOrEmpty(remoteClient.AgentId.ToString()))
987 {
988 // Looking for a reason that some viewers are sending null Id's
989 m_log.DebugFormat("[PROFILES]: This should not happen remoteClient.AgentId {0} - avatarID {1}", remoteClient.AgentId, avatarID);
990 return;
991 }
992
993 // Can't handle NPC yet...
994 ScenePresence p = FindPresence(avatarID);
995
996 if (null != p)
997 {
998 if (p.PresenceType == PresenceType.Npc)
999 return;
1000 }
1001
1002 string serverURI = string.Empty;
1003 bool foreign = GetUserProfileServerURI(avatarID, out serverURI);
1004
1005 UserAccount account = null;
1006 Dictionary<string,object> userInfo;
1007
1008 if (!foreign)
1009 {
1010 account = Scene.UserAccountService.GetUserAccount(Scene.RegionInfo.ScopeID, avatarID);
1011 }
1012 else
1013 {
1014 userInfo = new Dictionary<string, object>();
1015 }
1016
1017 Byte[] charterMember = new Byte[1];
1018 string born = String.Empty;
1019 uint flags = 0x00;
1020
1021 if (null != account)
1022 {
1023 if (account.UserTitle == "")
1024 {
1025 charterMember[0] = (Byte)((account.UserFlags & 0xf00) >> 8);
1026 }
1027 else
1028 {
1029 charterMember = Utils.StringToBytes(account.UserTitle);
1030 }
1031
1032 born = Util.ToDateTime(account.Created).ToString(
1033 "M/d/yyyy", CultureInfo.InvariantCulture);
1034 flags = (uint)(account.UserFlags & 0xff);
1035 }
1036 else
1037 {
1038 if (GetUserAccountData(avatarID, out userInfo) == true)
1039 {
1040 if ((string)userInfo["user_title"] == "")
1041 {
1042 charterMember[0] = (Byte)(((Byte)userInfo["user_flags"] & 0xf00) >> 8);
1043 }
1044 else
1045 {
1046 charterMember = Utils.StringToBytes((string)userInfo["user_title"]);
1047 }
1048
1049 int val_born = (int)userInfo["user_created"];
1050 born = Util.ToDateTime(val_born).ToString(
1051 "M/d/yyyy", CultureInfo.InvariantCulture);
1052
1053 // picky, picky
1054 int val_flags = (int)userInfo["user_flags"];
1055 flags = (uint)(val_flags & 0xff);
1056 }
1057 }
1058
1059 UserProfileProperties props = new UserProfileProperties();
1060 string result = string.Empty;
1061
1062 props.UserId = avatarID;
1063
1064 if (!GetProfileData(ref props, foreign, out result))
1065 {
1066// m_log.DebugFormat("Error getting profile for {0}: {1}", avatarID, result);
1067 return;
1068 }
1069
1070 remoteClient.SendAvatarProperties(props.UserId, props.AboutText, born, charterMember , props.FirstLifeText, flags,
1071 props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId);
1072
1073
1074 remoteClient.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, props.WantToText, (uint)props.SkillsMask,
1075 props.SkillsText, props.Language);
1076 }
1077
1078 /// <summary>
1079 /// Updates the avatar properties.
1080 /// </summary>
1081 /// <param name='remoteClient'>
1082 /// Remote client.
1083 /// </param>
1084 /// <param name='newProfile'>
1085 /// New profile.
1086 /// </param>
1087 public void AvatarPropertiesUpdate(IClientAPI remoteClient, UserProfileData newProfile)
1088 {
1089 if (remoteClient.AgentId == newProfile.ID)
1090 {
1091 UserProfileProperties prop = new UserProfileProperties();
1092
1093 prop.UserId = remoteClient.AgentId;
1094 prop.WebUrl = newProfile.ProfileUrl;
1095 prop.ImageId = newProfile.Image;
1096 prop.AboutText = newProfile.AboutText;
1097 prop.FirstLifeImageId = newProfile.FirstLifeImage;
1098 prop.FirstLifeText = newProfile.FirstLifeAboutText;
1099
1100 string serverURI = string.Empty;
1101 GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
1102
1103 object Prop = prop;
1104
1105 if(!rpc.JsonRpcRequest(ref Prop, "avatar_properties_update", serverURI, UUID.Random().ToString()))
1106 {
1107 remoteClient.SendAgentAlertMessage(
1108 "Error updating properties", false);
1109 return;
1110 }
1111
1112 RequestAvatarProperties(remoteClient, newProfile.ID);
1113 }
1114 }
1115
1116 /// <summary>
1117 /// Gets the profile data.
1118 /// </summary>
1119 /// <returns>
1120 /// The profile data.
1121 /// </returns>
1122 bool GetProfileData(ref UserProfileProperties properties, bool foreign, out string message)
1123 {
1124 // Can't handle NPC yet...
1125 ScenePresence p = FindPresence(properties.UserId);
1126
1127 if (null != p)
1128 {
1129 if (p.PresenceType == PresenceType.Npc)
1130 {
1131 message = "Id points to NPC";
1132 return false;
1133 }
1134 }
1135
1136 string serverURI = string.Empty;
1137 GetUserProfileServerURI(properties.UserId, out serverURI);
1138
1139 // This is checking a friend on the home grid
1140 // Not HG friend
1141 if (String.IsNullOrEmpty(serverURI))
1142 {
1143 message = "No Presence - foreign friend";
1144 return false;
1145 }
1146
1147 object Prop = (object)properties;
1148 if (!rpc.JsonRpcRequest(ref Prop, "avatar_properties_request", serverURI, UUID.Random().ToString()))
1149 {
1150 // If it's a foreign user then try again using OpenProfile, in case that's what the grid is using
1151 bool secondChanceSuccess = false;
1152 if (foreign)
1153 {
1154 try
1155 {
1156 OpenProfileClient client = new OpenProfileClient(serverURI);
1157 if (client.RequestAvatarPropertiesUsingOpenProfile(ref properties))
1158 secondChanceSuccess = true;
1159 }
1160 catch (Exception e)
1161 {
1162 m_log.Debug(
1163 string.Format(
1164 "[PROFILES]: Request using the OpenProfile API for user {0} to {1} failed",
1165 properties.UserId, serverURI),
1166 e);
1167
1168 // Allow the return 'message' to say "JsonRpcRequest" and not "OpenProfile", because
1169 // the most likely reason that OpenProfile failed is that the remote server
1170 // doesn't support OpenProfile, and that's not very interesting.
1171 }
1172 }
1173
1174 if (!secondChanceSuccess)
1175 {
1176 message = string.Format("JsonRpcRequest for user {0} to {1} failed", properties.UserId, serverURI);
1177 m_log.DebugFormat("[PROFILES]: {0}", message);
1178
1179 return false;
1180 }
1181 // else, continue below
1182 }
1183
1184 properties = (UserProfileProperties)Prop;
1185
1186 message = "Success";
1187 return true;
1188 }
1189 #endregion Avatar Properties
1190
1191 #region Utils
1192 bool GetImageAssets(UUID avatarId)
1193 {
1194 string profileServerURI = string.Empty;
1195 string assetServerURI = string.Empty;
1196
1197 bool foreign = GetUserProfileServerURI(avatarId, out profileServerURI);
1198
1199 if(!foreign)
1200 return true;
1201
1202 assetServerURI = UserManagementModule.GetUserServerURL(avatarId, "AssetServerURI");
1203
1204 if(string.IsNullOrEmpty(profileServerURI) || string.IsNullOrEmpty(assetServerURI))
1205 return false;
1206
1207 OSDMap parameters= new OSDMap();
1208 parameters.Add("avatarId", OSD.FromUUID(avatarId));
1209 OSD Params = (OSD)parameters;
1210 if(!rpc.JsonRpcRequest(ref Params, "image_assets_request", profileServerURI, UUID.Random().ToString()))
1211 {
1212 return false;
1213 }
1214
1215 parameters = (OSDMap)Params;
1216
1217 if (parameters.ContainsKey("result"))
1218 {
1219 OSDArray list = (OSDArray)parameters["result"];
1220
1221 foreach (OSD asset in list)
1222 {
1223 OSDString assetId = (OSDString)asset;
1224
1225 Scene.AssetService.Get(string.Format("{0}/{1}", assetServerURI, assetId.AsString()));
1226 }
1227 return true;
1228 }
1229 else
1230 {
1231 m_log.ErrorFormat("[PROFILES]: Problematic response for image_assets_request from {0}", profileServerURI);
1232 return false;
1233 }
1234 }
1235
1236 /// <summary>
1237 /// Gets the user account data.
1238 /// </summary>
1239 /// <returns>
1240 /// The user profile data.
1241 /// </returns>
1242 /// <param name='userID'>
1243 /// If set to <c>true</c> user I.
1244 /// </param>
1245 /// <param name='userInfo'>
1246 /// If set to <c>true</c> user info.
1247 /// </param>
1248 bool GetUserAccountData(UUID userID, out Dictionary<string, object> userInfo)
1249 {
1250 Dictionary<string,object> info = new Dictionary<string, object>();
1251
1252 if (UserManagementModule.IsLocalGridUser(userID))
1253 {
1254 // Is local
1255 IUserAccountService uas = Scene.UserAccountService;
1256 UserAccount account = uas.GetUserAccount(Scene.RegionInfo.ScopeID, userID);
1257
1258 info["user_flags"] = account.UserFlags;
1259 info["user_created"] = account.Created;
1260
1261 if (!String.IsNullOrEmpty(account.UserTitle))
1262 info["user_title"] = account.UserTitle;
1263 else
1264 info["user_title"] = "";
1265
1266 userInfo = info;
1267
1268 return false;
1269 }
1270 else
1271 {
1272 // Is Foreign
1273 string home_url = UserManagementModule.GetUserServerURL(userID, "HomeURI");
1274
1275 if (String.IsNullOrEmpty(home_url))
1276 {
1277 info["user_flags"] = 0;
1278 info["user_created"] = 0;
1279 info["user_title"] = "Unavailable";
1280
1281 userInfo = info;
1282 return true;
1283 }
1284
1285 UserAgentServiceConnector uConn = new UserAgentServiceConnector(home_url);
1286
1287 Dictionary<string, object> account;
1288 try
1289 {
1290 account = uConn.GetUserInfo(userID);
1291 }
1292 catch (Exception e)
1293 {
1294 m_log.Debug("[PROFILES]: GetUserInfo call failed ", e);
1295 account = new Dictionary<string, object>();
1296 }
1297
1298 if (account.Count > 0)
1299 {
1300 if (account.ContainsKey("user_flags"))
1301 info["user_flags"] = account["user_flags"];
1302 else
1303 info["user_flags"] = "";
1304
1305 if (account.ContainsKey("user_created"))
1306 info["user_created"] = account["user_created"];
1307 else
1308 info["user_created"] = "";
1309
1310 info["user_title"] = "HG Visitor";
1311 }
1312 else
1313 {
1314 info["user_flags"] = 0;
1315 info["user_created"] = 0;
1316 info["user_title"] = "HG Visitor";
1317 }
1318 userInfo = info;
1319 return true;
1320 }
1321 }
1322
1323 /// <summary>
1324 /// Gets the user gatekeeper server URI.
1325 /// </summary>
1326 /// <returns>
1327 /// The user gatekeeper server URI.
1328 /// </returns>
1329 /// <param name='userID'>
1330 /// If set to <c>true</c> user URI.
1331 /// </param>
1332 /// <param name='serverURI'>
1333 /// If set to <c>true</c> server URI.
1334 /// </param>
1335 bool GetUserGatekeeperURI(UUID userID, out string serverURI)
1336 {
1337 bool local;
1338 local = UserManagementModule.IsLocalGridUser(userID);
1339
1340 if (!local)
1341 {
1342 serverURI = UserManagementModule.GetUserServerURL(userID, "GatekeeperURI");
1343 // Is Foreign
1344 return true;
1345 }
1346 else
1347 {
1348 serverURI = MyGatekeeper;
1349 // Is local
1350 return false;
1351 }
1352 }
1353
1354 /// <summary>
1355 /// Gets the user profile server UR.
1356 /// </summary>
1357 /// <returns>
1358 /// The user profile server UR.
1359 /// </returns>
1360 /// <param name='userID'>
1361 /// If set to <c>true</c> user I.
1362 /// </param>
1363 /// <param name='serverURI'>
1364 /// If set to <c>true</c> server UR.
1365 /// </param>
1366 bool GetUserProfileServerURI(UUID userID, out string serverURI)
1367 {
1368 bool local;
1369 local = UserManagementModule.IsLocalGridUser(userID);
1370
1371 if (!local)
1372 {
1373 serverURI = UserManagementModule.GetUserServerURL(userID, "ProfileServerURI");
1374 // Is Foreign
1375 return true;
1376 }
1377 else
1378 {
1379 serverURI = ProfileServerUri;
1380 // Is local
1381 return false;
1382 }
1383 }
1384
1385 /// <summary>
1386 /// Finds the presence.
1387 /// </summary>
1388 /// <returns>
1389 /// The presence.
1390 /// </returns>
1391 /// <param name='clientID'>
1392 /// Client I.
1393 /// </param>
1394 ScenePresence FindPresence(UUID clientID)
1395 {
1396 ScenePresence p;
1397
1398 p = Scene.GetScenePresence(clientID);
1399 if (p != null && !p.IsChildAgent)
1400 return p;
1401
1402 return null;
1403 }
1404 #endregion Util
1405 }
1406}
diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
index 8329af0..817ef85 100644
--- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
@@ -28,6 +28,7 @@
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Linq;
31using System.Reflection; 32using System.Reflection;
32using System.Text; 33using System.Text;
33using log4net; 34using log4net;
@@ -37,6 +38,7 @@ using OpenMetaverse;
37using OpenSim.Framework; 38using OpenSim.Framework;
38using OpenSim.Framework.Console; 39using OpenSim.Framework.Console;
39using OpenSim.Framework.Servers; 40using OpenSim.Framework.Servers;
41using OpenSim.Framework.Servers.HttpServer;
40using OpenSim.Region.Framework.Interfaces; 42using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes; 43using OpenSim.Region.Framework.Scenes;
42using Caps=OpenSim.Framework.Capabilities.Caps; 44using Caps=OpenSim.Framework.Capabilities.Caps;
@@ -57,8 +59,9 @@ namespace OpenSim.Region.CoreModules.Framework
57 /// </summary> 59 /// </summary>
58 protected Dictionary<UUID, Caps> m_capsObjects = new Dictionary<UUID, Caps>(); 60 protected Dictionary<UUID, Caps> m_capsObjects = new Dictionary<UUID, Caps>();
59 61
60 protected Dictionary<UUID, string> capsPaths = new Dictionary<UUID, string>(); 62 protected Dictionary<UUID, string> m_capsPaths = new Dictionary<UUID, string>();
61 protected Dictionary<UUID, Dictionary<ulong, string>> childrenSeeds 63
64 protected Dictionary<UUID, Dictionary<ulong, string>> m_childrenSeeds
62 = new Dictionary<UUID, Dictionary<ulong, string>>(); 65 = new Dictionary<UUID, Dictionary<ulong, string>>();
63 66
64 public void Initialise(IConfigSource source) 67 public void Initialise(IConfigSource source)
@@ -70,9 +73,24 @@ namespace OpenSim.Region.CoreModules.Framework
70 m_scene = scene; 73 m_scene = scene;
71 m_scene.RegisterModuleInterface<ICapabilitiesModule>(this); 74 m_scene.RegisterModuleInterface<ICapabilitiesModule>(this);
72 75
73 MainConsole.Instance.Commands.AddCommand("Comms", false, "show caps", 76 MainConsole.Instance.Commands.AddCommand(
74 "show caps", 77 "Comms", false, "show caps list",
75 "Shows all registered capabilities for users", HandleShowCapsCommand); 78 "show caps list",
79 "Shows list of registered capabilities for users.", HandleShowCapsListCommand);
80
81 MainConsole.Instance.Commands.AddCommand(
82 "Comms", false, "show caps stats by user",
83 "show caps stats by user [<first-name> <last-name>]",
84 "Shows statistics on capabilities use by user.",
85 "If a user name is given, then prints a detailed breakdown of caps use ordered by number of requests received.",
86 HandleShowCapsStatsByUserCommand);
87
88 MainConsole.Instance.Commands.AddCommand(
89 "Comms", false, "show caps stats by cap",
90 "show caps stats by cap [<cap-name>]",
91 "Shows statistics on capabilities use by capability.",
92 "If a capability name is given, then prints a detailed breakdown of use by each user.",
93 HandleShowCapsStatsByCapCommand);
76 } 94 }
77 95
78 public void RegionLoaded(Scene scene) 96 public void RegionLoaded(Scene scene)
@@ -105,35 +123,43 @@ namespace OpenSim.Region.CoreModules.Framework
105 if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId)) 123 if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId))
106 return; 124 return;
107 125
126 Caps caps;
108 String capsObjectPath = GetCapsPath(agentId); 127 String capsObjectPath = GetCapsPath(agentId);
109 128
110 if (m_capsObjects.ContainsKey(agentId)) 129 lock (m_capsObjects)
111 { 130 {
112 Caps oldCaps = m_capsObjects[agentId]; 131 if (m_capsObjects.ContainsKey(agentId))
113 132 {
114 m_log.DebugFormat( 133 Caps oldCaps = m_capsObjects[agentId];
115 "[CAPS]: Recreating caps for agent {0}. Old caps path {1}, new caps path {2}. ", 134
116 agentId, oldCaps.CapsObjectPath, capsObjectPath); 135 //m_log.WarnFormat(
117 // This should not happen. The caller code is confused. We need to fix that. 136 // "[CAPS]: Recreating caps for agent {0} in region {1}. Old caps path {2}, new caps path {3}. ",
118 // CAPs can never be reregistered, or the client will be confused. 137 // agentId, m_scene.RegionInfo.RegionName, oldCaps.CapsObjectPath, capsObjectPath);
119 // Hence this return here. 138 }
120 //return;
121 }
122 139
123 Caps caps = new Caps(MainServer.Instance, m_scene.RegionInfo.ExternalHostName, 140// m_log.DebugFormat(
124 (MainServer.Instance == null) ? 0: MainServer.Instance.Port, 141// "[CAPS]: Adding capabilities for agent {0} in {1} with path {2}",
125 capsObjectPath, agentId, m_scene.RegionInfo.RegionName); 142// agentId, m_scene.RegionInfo.RegionName, capsObjectPath);
126 143
127 m_capsObjects[agentId] = caps; 144 caps = new Caps(MainServer.Instance, m_scene.RegionInfo.ExternalHostName,
145 (MainServer.Instance == null) ? 0: MainServer.Instance.Port,
146 capsObjectPath, agentId, m_scene.RegionInfo.RegionName);
147
148 m_capsObjects[agentId] = caps;
149 }
128 150
129 m_scene.EventManager.TriggerOnRegisterCaps(agentId, caps); 151 m_scene.EventManager.TriggerOnRegisterCaps(agentId, caps);
130 } 152 }
131 153
132 public void RemoveCaps(UUID agentId) 154 public void RemoveCaps(UUID agentId)
133 { 155 {
134 if (childrenSeeds.ContainsKey(agentId)) 156 m_log.DebugFormat("[CAPS]: Remove caps for agent {0} in region {1}", agentId, m_scene.RegionInfo.RegionName);
157 lock (m_childrenSeeds)
135 { 158 {
136 childrenSeeds.Remove(agentId); 159 if (m_childrenSeeds.ContainsKey(agentId))
160 {
161 m_childrenSeeds.Remove(agentId);
162 }
137 } 163 }
138 164
139 lock (m_capsObjects) 165 lock (m_capsObjects)
@@ -168,16 +194,22 @@ namespace OpenSim.Region.CoreModules.Framework
168 194
169 public void SetAgentCapsSeeds(AgentCircuitData agent) 195 public void SetAgentCapsSeeds(AgentCircuitData agent)
170 { 196 {
171 capsPaths[agent.AgentID] = agent.CapsPath; 197 lock (m_capsPaths)
172 childrenSeeds[agent.AgentID] 198 m_capsPaths[agent.AgentID] = agent.CapsPath;
173 = ((agent.ChildrenCapSeeds == null) ? new Dictionary<ulong, string>() : agent.ChildrenCapSeeds); 199
200 lock (m_childrenSeeds)
201 m_childrenSeeds[agent.AgentID]
202 = ((agent.ChildrenCapSeeds == null) ? new Dictionary<ulong, string>() : agent.ChildrenCapSeeds);
174 } 203 }
175 204
176 public string GetCapsPath(UUID agentId) 205 public string GetCapsPath(UUID agentId)
177 { 206 {
178 if (capsPaths.ContainsKey(agentId)) 207 lock (m_capsPaths)
179 { 208 {
180 return capsPaths[agentId]; 209 if (m_capsPaths.ContainsKey(agentId))
210 {
211 return m_capsPaths[agentId];
212 }
181 } 213 }
182 214
183 return null; 215 return null;
@@ -186,17 +218,24 @@ namespace OpenSim.Region.CoreModules.Framework
186 public Dictionary<ulong, string> GetChildrenSeeds(UUID agentID) 218 public Dictionary<ulong, string> GetChildrenSeeds(UUID agentID)
187 { 219 {
188 Dictionary<ulong, string> seeds = null; 220 Dictionary<ulong, string> seeds = null;
189 if (childrenSeeds.TryGetValue(agentID, out seeds)) 221
190 return seeds; 222 lock (m_childrenSeeds)
223 if (m_childrenSeeds.TryGetValue(agentID, out seeds))
224 return seeds;
225
191 return new Dictionary<ulong, string>(); 226 return new Dictionary<ulong, string>();
192 } 227 }
193 228
194 public void DropChildSeed(UUID agentID, ulong handle) 229 public void DropChildSeed(UUID agentID, ulong handle)
195 { 230 {
196 Dictionary<ulong, string> seeds; 231 Dictionary<ulong, string> seeds;
197 if (childrenSeeds.TryGetValue(agentID, out seeds)) 232
233 lock (m_childrenSeeds)
198 { 234 {
199 seeds.Remove(handle); 235 if (m_childrenSeeds.TryGetValue(agentID, out seeds))
236 {
237 seeds.Remove(handle);
238 }
200 } 239 }
201 } 240 }
202 241
@@ -204,53 +243,327 @@ namespace OpenSim.Region.CoreModules.Framework
204 { 243 {
205 Dictionary<ulong, string> seeds; 244 Dictionary<ulong, string> seeds;
206 string returnval; 245 string returnval;
207 if (childrenSeeds.TryGetValue(agentID, out seeds)) 246
247 lock (m_childrenSeeds)
208 { 248 {
209 if (seeds.TryGetValue(handle, out returnval)) 249 if (m_childrenSeeds.TryGetValue(agentID, out seeds))
210 return returnval; 250 {
251 if (seeds.TryGetValue(handle, out returnval))
252 return returnval;
253 }
211 } 254 }
255
212 return null; 256 return null;
213 } 257 }
214 258
215 public void SetChildrenSeed(UUID agentID, Dictionary<ulong, string> seeds) 259 public void SetChildrenSeed(UUID agentID, Dictionary<ulong, string> seeds)
216 { 260 {
217 //m_log.DebugFormat(" !!! Setting child seeds in {0} to {1}", m_scene.RegionInfo.RegionName, seeds.Count); 261 //m_log.DebugFormat(" !!! Setting child seeds in {0} to {1}", m_scene.RegionInfo.RegionName, seeds.Count);
218 childrenSeeds[agentID] = seeds; 262
263 lock (m_childrenSeeds)
264 m_childrenSeeds[agentID] = seeds;
219 } 265 }
220 266
221 public void DumpChildrenSeeds(UUID agentID) 267 public void DumpChildrenSeeds(UUID agentID)
222 { 268 {
223 m_log.Info("================ ChildrenSeed "+m_scene.RegionInfo.RegionName+" ================"); 269 m_log.Info("================ ChildrenSeed "+m_scene.RegionInfo.RegionName+" ================");
224 foreach (KeyValuePair<ulong, string> kvp in childrenSeeds[agentID]) 270
271 lock (m_childrenSeeds)
272 {
273 foreach (KeyValuePair<ulong, string> kvp in m_childrenSeeds[agentID])
274 {
275 uint x, y;
276 Util.RegionHandleToRegionLoc(kvp.Key, out x, out y);
277 m_log.Info(" >> "+x+", "+y+": "+kvp.Value);
278 }
279 }
280 }
281
282 private void HandleShowCapsListCommand(string module, string[] cmdParams)
283 {
284 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
285 return;
286
287 StringBuilder capsReport = new StringBuilder();
288 capsReport.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName);
289
290 lock (m_capsObjects)
225 { 291 {
226 uint x, y; 292 foreach (KeyValuePair<UUID, Caps> kvp in m_capsObjects)
227 Utils.LongToUInts(kvp.Key, out x, out y); 293 {
228 x = x / Constants.RegionSize; 294 capsReport.AppendFormat("** User {0}:\n", kvp.Key);
229 y = y / Constants.RegionSize; 295 Caps caps = kvp.Value;
230 m_log.Info(" >> "+x+", "+y+": "+kvp.Value); 296
297 for (IDictionaryEnumerator kvp2 = caps.CapsHandlers.GetCapsDetails(false, null).GetEnumerator(); kvp2.MoveNext(); )
298 {
299 Uri uri = new Uri(kvp2.Value.ToString());
300 capsReport.AppendFormat(m_showCapsCommandFormat, kvp2.Key, uri.PathAndQuery);
301 }
302
303 foreach (KeyValuePair<string, PollServiceEventArgs> kvp2 in caps.GetPollHandlers())
304 capsReport.AppendFormat(m_showCapsCommandFormat, kvp2.Key, kvp2.Value.Url);
305
306 foreach (KeyValuePair<string, string> kvp3 in caps.ExternalCapsHandlers)
307 capsReport.AppendFormat(m_showCapsCommandFormat, kvp3.Key, kvp3.Value);
308 }
231 } 309 }
310
311 MainConsole.Instance.Output(capsReport.ToString());
232 } 312 }
233 313
234 private void HandleShowCapsCommand(string module, string[] cmdparams) 314 private void HandleShowCapsStatsByCapCommand(string module, string[] cmdParams)
235 { 315 {
236 StringBuilder caps = new StringBuilder(); 316 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
237 caps.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName); 317 return;
318
319 if (cmdParams.Length != 5 && cmdParams.Length != 6)
320 {
321 MainConsole.Instance.Output("Usage: show caps stats by cap [<cap-name>]");
322 return;
323 }
324
325 StringBuilder sb = new StringBuilder();
326 sb.AppendFormat("Region {0}:\n", m_scene.Name);
327
328 if (cmdParams.Length == 5)
329 {
330 BuildSummaryStatsByCapReport(sb);
331 }
332 else if (cmdParams.Length == 6)
333 {
334 BuildDetailedStatsByCapReport(sb, cmdParams[5]);
335 }
336
337 MainConsole.Instance.Output(sb.ToString());
338 }
339
340 private void BuildDetailedStatsByCapReport(StringBuilder sb, string capName)
341 {
342 sb.AppendFormat("Capability name {0}\n", capName);
343
344 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
345 cdt.AddColumn("User Name", 34);
346 cdt.AddColumn("Req Received", 12);
347 cdt.AddColumn("Req Handled", 12);
348 cdt.Indent = 2;
349
350 Dictionary<string, int> receivedStats = new Dictionary<string, int>();
351 Dictionary<string, int> handledStats = new Dictionary<string, int>();
352
353 m_scene.ForEachScenePresence(
354 sp =>
355 {
356 Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID);
238 357
239 foreach (KeyValuePair<UUID, Caps> kvp in m_capsObjects) 358 if (caps == null)
359 return;
360
361 Dictionary<string, IRequestHandler> capsHandlers = caps.CapsHandlers.GetCapsHandlers();
362
363 IRequestHandler reqHandler;
364 if (capsHandlers.TryGetValue(capName, out reqHandler))
365 {
366 receivedStats[sp.Name] = reqHandler.RequestsReceived;
367 handledStats[sp.Name] = reqHandler.RequestsHandled;
368 }
369 else
370 {
371 PollServiceEventArgs pollHandler = null;
372 if (caps.TryGetPollHandler(capName, out pollHandler))
373 {
374 receivedStats[sp.Name] = pollHandler.RequestsReceived;
375 handledStats[sp.Name] = pollHandler.RequestsHandled;
376 }
377 }
378 }
379 );
380
381 foreach (KeyValuePair<string, int> kvp in receivedStats.OrderByDescending(kp => kp.Value))
240 { 382 {
241 caps.AppendFormat("** User {0}:\n", kvp.Key); 383 cdt.AddRow(kvp.Key, kvp.Value, handledStats[kvp.Key]);
384 }
385
386 sb.Append(cdt.ToString());
387 }
388
389 private void BuildSummaryStatsByCapReport(StringBuilder sb)
390 {
391 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
392 cdt.AddColumn("Name", 34);
393 cdt.AddColumn("Req Received", 12);
394 cdt.AddColumn("Req Handled", 12);
395 cdt.Indent = 2;
396
397 Dictionary<string, int> receivedStats = new Dictionary<string, int>();
398 Dictionary<string, int> handledStats = new Dictionary<string, int>();
242 399
243 for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.GetCapsDetails(false).GetEnumerator(); kvp2.MoveNext(); ) 400 m_scene.ForEachScenePresence(
401 sp =>
244 { 402 {
245 Uri uri = new Uri(kvp2.Value.ToString()); 403 Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID);
246 caps.AppendFormat(m_showCapsCommandFormat, kvp2.Key, uri.PathAndQuery); 404
405 if (caps == null)
406 return;
407
408 foreach (IRequestHandler reqHandler in caps.CapsHandlers.GetCapsHandlers().Values)
409 {
410 string reqName = reqHandler.Name ?? "";
411
412 if (!receivedStats.ContainsKey(reqName))
413 {
414 receivedStats[reqName] = reqHandler.RequestsReceived;
415 handledStats[reqName] = reqHandler.RequestsHandled;
416 }
417 else
418 {
419 receivedStats[reqName] += reqHandler.RequestsReceived;
420 handledStats[reqName] += reqHandler.RequestsHandled;
421 }
422 }
423
424 foreach (KeyValuePair<string, PollServiceEventArgs> kvp in caps.GetPollHandlers())
425 {
426 string name = kvp.Key;
427 PollServiceEventArgs pollHandler = kvp.Value;
428
429 if (!receivedStats.ContainsKey(name))
430 {
431 receivedStats[name] = pollHandler.RequestsReceived;
432 handledStats[name] = pollHandler.RequestsHandled;
433 }
434 else
435 {
436 receivedStats[name] += pollHandler.RequestsReceived;
437 handledStats[name] += pollHandler.RequestsHandled;
438 }
439 }
247 } 440 }
441 );
442
443 foreach (KeyValuePair<string, int> kvp in receivedStats.OrderByDescending(kp => kp.Value))
444 cdt.AddRow(kvp.Key, kvp.Value, handledStats[kvp.Key]);
445
446 sb.Append(cdt.ToString());
447 }
448
449 private void HandleShowCapsStatsByUserCommand(string module, string[] cmdParams)
450 {
451 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
452 return;
453
454 if (cmdParams.Length != 5 && cmdParams.Length != 7)
455 {
456 MainConsole.Instance.Output("Usage: show caps stats by user [<first-name> <last-name>]");
457 return;
458 }
459
460 StringBuilder sb = new StringBuilder();
461 sb.AppendFormat("Region {0}:\n", m_scene.Name);
462
463 if (cmdParams.Length == 5)
464 {
465 BuildSummaryStatsByUserReport(sb);
466 }
467 else if (cmdParams.Length == 7)
468 {
469 string firstName = cmdParams[5];
470 string lastName = cmdParams[6];
471
472 ScenePresence sp = m_scene.GetScenePresence(firstName, lastName);
473
474 if (sp == null)
475 return;
248 476
249 foreach (KeyValuePair<string, string> kvp3 in kvp.Value.ExternalCapsHandlers) 477 BuildDetailedStatsByUserReport(sb, sp);
250 caps.AppendFormat(m_showCapsCommandFormat, kvp3.Key, kvp3.Value);
251 } 478 }
252 479
253 MainConsole.Instance.Output(caps.ToString()); 480 MainConsole.Instance.Output(sb.ToString());
481 }
482
483 private void BuildDetailedStatsByUserReport(StringBuilder sb, ScenePresence sp)
484 {
485 sb.AppendFormat("Avatar name {0}, type {1}\n", sp.Name, sp.IsChildAgent ? "child" : "root");
486
487 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
488 cdt.AddColumn("Cap Name", 34);
489 cdt.AddColumn("Req Received", 12);
490 cdt.AddColumn("Req Handled", 12);
491 cdt.Indent = 2;
492
493 Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID);
494
495 if (caps == null)
496 return;
497
498 List<CapTableRow> capRows = new List<CapTableRow>();
499
500 foreach (IRequestHandler reqHandler in caps.CapsHandlers.GetCapsHandlers().Values)
501 capRows.Add(new CapTableRow(reqHandler.Name, reqHandler.RequestsReceived, reqHandler.RequestsHandled));
502
503 foreach (KeyValuePair<string, PollServiceEventArgs> kvp in caps.GetPollHandlers())
504 capRows.Add(new CapTableRow(kvp.Key, kvp.Value.RequestsReceived, kvp.Value.RequestsHandled));
505
506 foreach (CapTableRow ctr in capRows.OrderByDescending(ctr => ctr.RequestsReceived))
507 cdt.AddRow(ctr.Name, ctr.RequestsReceived, ctr.RequestsHandled);
508
509 sb.Append(cdt.ToString());
510 }
511
512 private void BuildSummaryStatsByUserReport(StringBuilder sb)
513 {
514 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
515 cdt.AddColumn("Name", 32);
516 cdt.AddColumn("Type", 5);
517 cdt.AddColumn("Req Received", 12);
518 cdt.AddColumn("Req Handled", 12);
519 cdt.Indent = 2;
520
521 m_scene.ForEachScenePresence(
522 sp =>
523 {
524 Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID);
525
526 if (caps == null)
527 return;
528
529 Dictionary<string, IRequestHandler> capsHandlers = caps.CapsHandlers.GetCapsHandlers();
530
531 int totalRequestsReceived = 0;
532 int totalRequestsHandled = 0;
533
534 foreach (IRequestHandler reqHandler in capsHandlers.Values)
535 {
536 totalRequestsReceived += reqHandler.RequestsReceived;
537 totalRequestsHandled += reqHandler.RequestsHandled;
538 }
539
540 Dictionary<string, PollServiceEventArgs> capsPollHandlers = caps.GetPollHandlers();
541
542 foreach (PollServiceEventArgs handler in capsPollHandlers.Values)
543 {
544 totalRequestsReceived += handler.RequestsReceived;
545 totalRequestsHandled += handler.RequestsHandled;
546 }
547
548 cdt.AddRow(sp.Name, sp.IsChildAgent ? "child" : "root", totalRequestsReceived, totalRequestsHandled);
549 }
550 );
551
552 sb.Append(cdt.ToString());
553 }
554
555 private class CapTableRow
556 {
557 public string Name { get; set; }
558 public int RequestsReceived { get; set; }
559 public int RequestsHandled { get; set; }
560
561 public CapTableRow(string name, int requestsReceived, int requestsHandled)
562 {
563 Name = name;
564 RequestsReceived = requestsReceived;
565 RequestsHandled = requestsHandled;
566 }
254 } 567 }
255 } 568 }
256} 569} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs
new file mode 100644
index 0000000..0c632b1
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs
@@ -0,0 +1,124 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using log4net;
32using Mono.Addins;
33using Nini.Config;
34using OpenMetaverse;
35using OpenMetaverse.Packets;
36using OpenMetaverse.StructuredData;
37using OpenSim.Framework;
38using OpenSim.Region.Framework;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41
42namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule
43{
44 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DAExampleModule")]
45 public class DAExampleModule : INonSharedRegionModule
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private readonly bool ENABLED = false; // enable for testing
50
51 public const string Namespace = "Example";
52 public const string StoreName = "DA";
53
54 protected Scene m_scene;
55 protected IDialogModule m_dialogMod;
56
57 public string Name { get { return "DAExample Module"; } }
58 public Type ReplaceableInterface { get { return null; } }
59
60 public void Initialise(IConfigSource source) {}
61
62 public void AddRegion(Scene scene)
63 {
64 if (ENABLED)
65 {
66 m_scene = scene;
67 m_scene.EventManager.OnSceneGroupMove += OnSceneGroupMove;
68 m_dialogMod = m_scene.RequestModuleInterface<IDialogModule>();
69
70 m_log.DebugFormat("[DA EXAMPLE MODULE]: Added region {0}", m_scene.Name);
71 }
72 }
73
74 public void RemoveRegion(Scene scene)
75 {
76 if (ENABLED)
77 {
78 m_scene.EventManager.OnSceneGroupMove -= OnSceneGroupMove;
79 }
80 }
81
82 public void RegionLoaded(Scene scene) {}
83
84 public void Close()
85 {
86 RemoveRegion(m_scene);
87 }
88
89 protected bool OnSceneGroupMove(UUID groupId, Vector3 delta)
90 {
91 OSDMap attrs = null;
92 SceneObjectPart sop = m_scene.GetSceneObjectPart(groupId);
93
94 if (sop == null)
95 return true;
96
97 if (!sop.DynAttrs.TryGetStore(Namespace, StoreName, out attrs))
98 attrs = new OSDMap();
99
100 OSDInteger newValue;
101
102 // We have to lock on the entire dynamic attributes map to avoid race conditions with serialization code.
103 lock (sop.DynAttrs)
104 {
105 if (!attrs.ContainsKey("moves"))
106 newValue = new OSDInteger(1);
107 else
108 newValue = new OSDInteger(attrs["moves"].AsInteger() + 1);
109
110 attrs["moves"] = newValue;
111
112 sop.DynAttrs.SetStore(Namespace, StoreName, attrs);
113 }
114
115 sop.ParentGroup.HasGroupChanged = true;
116
117 string msg = string.Format("{0} {1} moved {2} times", sop.Name, sop.UUID, newValue);
118 m_log.DebugFormat("[DA EXAMPLE MODULE]: {0}", msg);
119 m_dialogMod.SendGeneralAlert(msg);
120
121 return true;
122 }
123 }
124} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs
new file mode 100644
index 0000000..166a994
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs
@@ -0,0 +1,139 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using log4net;
32using Mono.Addins;
33using Nini.Config;
34using OpenMetaverse;
35using OpenMetaverse.Packets;
36using OpenMetaverse.StructuredData;
37using OpenSim.Framework;
38using OpenSim.Region.Framework;
39using OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes;
42
43namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule
44{
45 /// <summary>
46 /// Example module for experimenting with and demonstrating dynamic object ideas.
47 /// </summary>
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DOExampleModule")]
49 public class DOExampleModule : INonSharedRegionModule
50 {
51 public class MyObject
52 {
53 public int Moves { get; set; }
54
55 public MyObject(int moves)
56 {
57 Moves = moves;
58 }
59 }
60
61 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
62
63 private static readonly bool ENABLED = false; // enable for testing
64
65 private Scene m_scene;
66 private IDialogModule m_dialogMod;
67
68 public string Name { get { return "DO"; } }
69 public Type ReplaceableInterface { get { return null; } }
70
71 public void Initialise(IConfigSource source) {}
72
73 public void AddRegion(Scene scene)
74 {
75 if (ENABLED)
76 {
77 m_scene = scene;
78 m_scene.EventManager.OnObjectAddedToScene += OnObjectAddedToScene;
79 m_scene.EventManager.OnSceneGroupMove += OnSceneGroupMove;
80 m_dialogMod = m_scene.RequestModuleInterface<IDialogModule>();
81 }
82 }
83
84 public void RemoveRegion(Scene scene)
85 {
86 if (ENABLED)
87 {
88 m_scene.EventManager.OnSceneGroupMove -= OnSceneGroupMove;
89 }
90 }
91
92 public void RegionLoaded(Scene scene) {}
93
94 public void Close()
95 {
96 RemoveRegion(m_scene);
97 }
98
99 private void OnObjectAddedToScene(SceneObjectGroup so)
100 {
101 SceneObjectPart rootPart = so.RootPart;
102
103 OSDMap attrs;
104
105 int movesSoFar = 0;
106
107// Console.WriteLine("Here for {0}", so.Name);
108
109 if (rootPart.DynAttrs.TryGetStore(DAExampleModule.Namespace, DAExampleModule.StoreName, out attrs))
110 {
111 movesSoFar = attrs["moves"].AsInteger();
112
113 m_log.DebugFormat(
114 "[DO EXAMPLE MODULE]: Found saved moves {0} for {1} in {2}", movesSoFar, so.Name, m_scene.Name);
115 }
116
117 rootPart.DynObjs.Add(DAExampleModule.Namespace, Name, new MyObject(movesSoFar));
118 }
119
120 private bool OnSceneGroupMove(UUID groupId, Vector3 delta)
121 {
122 SceneObjectGroup so = m_scene.GetSceneObjectGroup(groupId);
123
124 if (so == null)
125 return true;
126
127 object rawObj = so.RootPart.DynObjs.Get(Name);
128
129 if (rawObj != null)
130 {
131 MyObject myObj = (MyObject)rawObj;
132
133 m_dialogMod.SendGeneralAlert(string.Format("{0} {1} moved {2} times", so.Name, so.UUID, ++myObj.Moves));
134 }
135
136 return true;
137 }
138 }
139} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index c43edd2..a2417c4 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -33,9 +33,10 @@ using System.Threading;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Framework.Capabilities; 34using OpenSim.Framework.Capabilities;
35using OpenSim.Framework.Client; 35using OpenSim.Framework.Client;
36using OpenSim.Framework.Monitoring;
36using OpenSim.Region.Framework.Interfaces; 37using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes; 38using OpenSim.Region.Framework.Scenes;
38using OpenSim.Region.Physics.Manager; 39using OpenSim.Region.PhysicsModules.SharedBase;
39using OpenSim.Services.Interfaces; 40using OpenSim.Services.Interfaces;
40 41
41using GridRegion = OpenSim.Services.Interfaces.GridRegion; 42using GridRegion = OpenSim.Services.Interfaces.GridRegion;
@@ -51,15 +52,61 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
51 public class EntityTransferModule : INonSharedRegionModule, IEntityTransferModule 52 public class EntityTransferModule : INonSharedRegionModule, IEntityTransferModule
52 { 53 {
53 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55 private static readonly string LogHeader = "[ENTITY TRANSFER MODULE]";
54 56
57 public const int DefaultMaxTransferDistance = 4095;
55 public const bool WaitForAgentArrivedAtDestinationDefault = true; 58 public const bool WaitForAgentArrivedAtDestinationDefault = true;
56 59
57 /// <summary> 60 /// <summary>
61 /// The maximum distance, in standard region units (256m) that an agent is allowed to transfer.
62 /// </summary>
63 public int MaxTransferDistance { get; set; }
64
65 /// <summary>
58 /// If true then on a teleport, the source region waits for a callback from the destination region. If 66 /// If true then on a teleport, the source region waits for a callback from the destination region. If
59 /// a callback fails to arrive within a set time then the user is pulled back into the source region. 67 /// a callback fails to arrive within a set time then the user is pulled back into the source region.
60 /// </summary> 68 /// </summary>
61 public bool WaitForAgentArrivedAtDestination { get; set; } 69 public bool WaitForAgentArrivedAtDestination { get; set; }
62 70
71 /// <summary>
72 /// If true then we ask the viewer to disable teleport cancellation and ignore teleport requests.
73 /// </summary>
74 /// <remarks>
75 /// This is useful in situations where teleport is very likely to always succeed and we want to avoid a
76 /// situation where avatars can be come 'stuck' due to a failed teleport cancellation. Unfortunately, the
77 /// nature of the teleport protocol makes it extremely difficult (maybe impossible) to make teleport
78 /// cancellation consistently suceed.
79 /// </remarks>
80 public bool DisableInterRegionTeleportCancellation { get; set; }
81
82 /// <summary>
83 /// Number of times inter-region teleport was attempted.
84 /// </summary>
85 private Stat m_interRegionTeleportAttempts;
86
87 /// <summary>
88 /// Number of times inter-region teleport was aborted (due to simultaneous client logout).
89 /// </summary>
90 private Stat m_interRegionTeleportAborts;
91
92 /// <summary>
93 /// Number of times inter-region teleport was successfully cancelled by the client.
94 /// </summary>
95 private Stat m_interRegionTeleportCancels;
96
97 /// <summary>
98 /// Number of times inter-region teleport failed due to server/client/network problems (e.g. viewer failed to
99 /// connect with destination region).
100 /// </summary>
101 /// <remarks>
102 /// This is not necessarily a problem for this simulator - in open-grid/hg conditions, viewer connectivity to
103 /// destination simulator is unknown.
104 /// </remarks>
105 private Stat m_interRegionTeleportFailures;
106
107 protected string m_ThisHomeURI;
108 protected string m_GatekeeperURI;
109
63 protected bool m_Enabled = false; 110 protected bool m_Enabled = false;
64 111
65 public Scene Scene { get; private set; } 112 public Scene Scene { get; private set; }
@@ -70,10 +117,56 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
70 /// </summary> 117 /// </summary>
71 private EntityTransferStateMachine m_entityTransferStateMachine; 118 private EntityTransferStateMachine m_entityTransferStateMachine;
72 119
73 private ExpiringCache<UUID, ExpiringCache<ulong, DateTime>> m_bannedRegions = 120 // For performance, we keed a cached of banned regions so we don't keep going
74 new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>(); 121 // to the grid service.
122 private class BannedRegionCache
123 {
124 private ExpiringCache<UUID, ExpiringCache<ulong, DateTime>> m_bannedRegions =
125 new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>();
126 ExpiringCache<ulong, DateTime> m_idCache;
127 DateTime m_banUntil;
128 public BannedRegionCache()
129 {
130 }
131 // Return 'true' if there is a valid ban entry for this agent in this region
132 public bool IfBanned(ulong pRegionHandle, UUID pAgentID)
133 {
134 bool ret = false;
135 if (m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
136 {
137 if (m_idCache.TryGetValue(pRegionHandle, out m_banUntil))
138 {
139 if (DateTime.Now < m_banUntil)
140 {
141 ret = true;
142 }
143 }
144 }
145 return ret;
146 }
147 // Add this agent in this region as a banned person
148 public void Add(ulong pRegionHandle, UUID pAgentID)
149 {
150 if (!m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
151 {
152 m_idCache = new ExpiringCache<ulong, DateTime>();
153 m_bannedRegions.Add(pAgentID, m_idCache, TimeSpan.FromSeconds(45));
154 }
155 m_idCache.Add(pRegionHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15));
156 }
157 // Remove the agent from the region's banned list
158 public void Remove(ulong pRegionHandle, UUID pAgentID)
159 {
160 if (m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
161 {
162 m_idCache.Remove(pRegionHandle);
163 }
164 }
165 }
166 private BannedRegionCache m_bannedRegionCache = new BannedRegionCache();
75 167
76 private IEventQueue m_eqModule; 168 private IEventQueue m_eqModule;
169 private IRegionCombinerModule m_regionCombinerModule;
77 170
78 #region ISharedRegionModule 171 #region ISharedRegionModule
79 172
@@ -107,11 +200,32 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
107 /// <param name="source"></param> 200 /// <param name="source"></param>
108 protected virtual void InitialiseCommon(IConfigSource source) 201 protected virtual void InitialiseCommon(IConfigSource source)
109 { 202 {
203 IConfig hypergridConfig = source.Configs["Hypergrid"];
204 if (hypergridConfig != null)
205 {
206 m_ThisHomeURI = hypergridConfig.GetString("HomeURI", string.Empty);
207 if (m_ThisHomeURI != string.Empty && !m_ThisHomeURI.EndsWith("/"))
208 m_ThisHomeURI += '/';
209
210 m_GatekeeperURI = hypergridConfig.GetString("GatekeeperURI", string.Empty);
211 if (m_GatekeeperURI != string.Empty && !m_GatekeeperURI.EndsWith("/"))
212 m_GatekeeperURI += '/';
213 }
214
110 IConfig transferConfig = source.Configs["EntityTransfer"]; 215 IConfig transferConfig = source.Configs["EntityTransfer"];
111 if (transferConfig != null) 216 if (transferConfig != null)
112 { 217 {
218 DisableInterRegionTeleportCancellation
219 = transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false);
220
113 WaitForAgentArrivedAtDestination 221 WaitForAgentArrivedAtDestination
114 = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault); 222 = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault);
223
224 MaxTransferDistance = transferConfig.GetInt("max_distance", DefaultMaxTransferDistance);
225 }
226 else
227 {
228 MaxTransferDistance = DefaultMaxTransferDistance;
115 } 229 }
116 230
117 m_entityTransferStateMachine = new EntityTransferStateMachine(this); 231 m_entityTransferStateMachine = new EntityTransferStateMachine(this);
@@ -130,19 +244,87 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
130 244
131 Scene = scene; 245 Scene = scene;
132 246
247 m_interRegionTeleportAttempts =
248 new Stat(
249 "InterRegionTeleportAttempts",
250 "Number of inter-region teleports attempted.",
251 "This does not count attempts which failed due to pre-conditions (e.g. target simulator refused access).\n"
252 + "You can get successfully teleports by subtracting aborts, cancels and teleport failures from this figure.",
253 "",
254 "entitytransfer",
255 Scene.Name,
256 StatType.Push,
257 null,
258 StatVerbosity.Debug);
259
260 m_interRegionTeleportAborts =
261 new Stat(
262 "InterRegionTeleportAborts",
263 "Number of inter-region teleports aborted due to client actions.",
264 "The chief action is simultaneous logout whilst teleporting.",
265 "",
266 "entitytransfer",
267 Scene.Name,
268 StatType.Push,
269 null,
270 StatVerbosity.Debug);
271
272 m_interRegionTeleportCancels =
273 new Stat(
274 "InterRegionTeleportCancels",
275 "Number of inter-region teleports cancelled by the client.",
276 null,
277 "",
278 "entitytransfer",
279 Scene.Name,
280 StatType.Push,
281 null,
282 StatVerbosity.Debug);
283
284 m_interRegionTeleportFailures =
285 new Stat(
286 "InterRegionTeleportFailures",
287 "Number of inter-region teleports that failed due to server/client/network issues.",
288 "This number may not be very helpful in open-grid/hg situations as the network connectivity/quality of destinations is uncontrollable.",
289 "",
290 "entitytransfer",
291 Scene.Name,
292 StatType.Push,
293 null,
294 StatVerbosity.Debug);
295
296 StatsManager.RegisterStat(m_interRegionTeleportAttempts);
297 StatsManager.RegisterStat(m_interRegionTeleportAborts);
298 StatsManager.RegisterStat(m_interRegionTeleportCancels);
299 StatsManager.RegisterStat(m_interRegionTeleportFailures);
300
133 scene.RegisterModuleInterface<IEntityTransferModule>(this); 301 scene.RegisterModuleInterface<IEntityTransferModule>(this);
134 scene.EventManager.OnNewClient += OnNewClient; 302 scene.EventManager.OnNewClient += OnNewClient;
135 } 303 }
136 304
137 protected virtual void OnNewClient(IClientAPI client) 305 protected virtual void OnNewClient(IClientAPI client)
138 { 306 {
139 client.OnTeleportHomeRequest += TeleportHome; 307 client.OnTeleportHomeRequest += TriggerTeleportHome;
140 client.OnTeleportLandmarkRequest += RequestTeleportLandmark; 308 client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
309
310 if (!DisableInterRegionTeleportCancellation)
311 client.OnTeleportCancel += OnClientCancelTeleport;
312
313 client.OnConnectionClosed += OnConnectionClosed;
141 } 314 }
142 315
143 public virtual void Close() {} 316 public virtual void Close() {}
144 317
145 public virtual void RemoveRegion(Scene scene) {} 318 public virtual void RemoveRegion(Scene scene)
319 {
320 if (m_Enabled)
321 {
322 StatsManager.DeregisterStat(m_interRegionTeleportAttempts);
323 StatsManager.DeregisterStat(m_interRegionTeleportAborts);
324 StatsManager.DeregisterStat(m_interRegionTeleportCancels);
325 StatsManager.DeregisterStat(m_interRegionTeleportFailures);
326 }
327 }
146 328
147 public virtual void RegionLoaded(Scene scene) 329 public virtual void RegionLoaded(Scene scene)
148 { 330 {
@@ -150,12 +332,32 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
150 return; 332 return;
151 333
152 m_eqModule = Scene.RequestModuleInterface<IEventQueue>(); 334 m_eqModule = Scene.RequestModuleInterface<IEventQueue>();
335 m_regionCombinerModule = Scene.RequestModuleInterface<IRegionCombinerModule>();
153 } 336 }
154 337
155 #endregion 338 #endregion
156 339
157 #region Agent Teleports 340 #region Agent Teleports
158 341
342 private void OnConnectionClosed(IClientAPI client)
343 {
344 if (client.IsLoggingOut && m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting))
345 {
346 m_log.DebugFormat(
347 "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout",
348 client.Name, Scene.Name);
349 }
350 }
351
352 private void OnClientCancelTeleport(IClientAPI client)
353 {
354 m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Cancelling);
355
356 m_log.DebugFormat(
357 "[ENTITY TRANSFER MODULE]: Received teleport cancel request from {0} in {1}", client.Name, Scene.Name);
358 }
359
360 // Attempt to teleport the ScenePresence to the specified position in the specified region (spec'ed by its handle).
159 public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) 361 public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags)
160 { 362 {
161 if (sp.Scene.Permissions.IsGridGod(sp.UUID)) 363 if (sp.Scene.Permissions.IsGridGod(sp.UUID))
@@ -167,13 +369,26 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
167 if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) 369 if (!sp.Scene.Permissions.CanTeleport(sp.UUID))
168 return; 370 return;
169 371
170 // Reset animations; the viewer does that in teleports.
171 sp.Animator.ResetAnimations();
172
173 string destinationRegionName = "(not found)"; 372 string destinationRegionName = "(not found)";
174 373
374 // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection
375 // of whether the destination region completes the teleport.
376 if (!m_entityTransferStateMachine.SetInTransit(sp.UUID))
377 {
378 m_log.DebugFormat(
379 "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2}@{3} - agent is already in transit.",
380 sp.Name, sp.UUID, position, regionHandle);
381
382 sp.ControllingClient.SendTeleportFailed("Previous teleport process incomplete. Please retry shortly.");
383
384 return;
385 }
386
175 try 387 try
176 { 388 {
389 // Reset animations; the viewer does that in teleports.
390 sp.Animator.ResetAnimations();
391
177 if (regionHandle == sp.Scene.RegionInfo.RegionHandle) 392 if (regionHandle == sp.Scene.RegionInfo.RegionHandle)
178 { 393 {
179 destinationRegionName = sp.Scene.RegionInfo.RegionName; 394 destinationRegionName = sp.Scene.RegionInfo.RegionName;
@@ -182,12 +397,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
182 } 397 }
183 else // Another region possibly in another simulator 398 else // Another region possibly in another simulator
184 { 399 {
185 GridRegion finalDestination; 400 GridRegion finalDestination = null;
186 TeleportAgentToDifferentRegion( 401 try
187 sp, regionHandle, position, lookAt, teleportFlags, out finalDestination); 402 {
188 403 TeleportAgentToDifferentRegion(
189 if (finalDestination != null) 404 sp, regionHandle, position, lookAt, teleportFlags, out finalDestination);
190 destinationRegionName = finalDestination.RegionName; 405 }
406 finally
407 {
408 if (finalDestination != null)
409 destinationRegionName = finalDestination.RegionName;
410 }
191 } 411 }
192 } 412 }
193 catch (Exception e) 413 catch (Exception e)
@@ -197,11 +417,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
197 sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName, 417 sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName,
198 e.Message, e.StackTrace); 418 e.Message, e.StackTrace);
199 419
200 // Make sure that we clear the in-transit flag so that future teleport attempts don't always fail.
201 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
202
203 sp.ControllingClient.SendTeleportFailed("Internal error"); 420 sp.ControllingClient.SendTeleportFailed("Internal error");
204 } 421 }
422 finally
423 {
424 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
425 }
205 } 426 }
206 427
207 /// <summary> 428 /// <summary>
@@ -210,30 +431,21 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
210 /// <param name="sp"></param> 431 /// <param name="sp"></param>
211 /// <param name="position"></param> 432 /// <param name="position"></param>
212 /// <param name="lookAt"></param> 433 /// <param name="lookAt"></param>
213 /// <param name="teleportFlags"></param 434 /// <param name="teleportFlags"></param>
214 private void TeleportAgentWithinRegion(ScenePresence sp, Vector3 position, Vector3 lookAt, uint teleportFlags) 435 private void TeleportAgentWithinRegion(ScenePresence sp, Vector3 position, Vector3 lookAt, uint teleportFlags)
215 { 436 {
216 m_log.DebugFormat( 437 m_log.DebugFormat(
217 "[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}", 438 "[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}",
218 sp.Name, position, sp.Scene.RegionInfo.RegionName); 439 sp.Name, position, sp.Scene.RegionInfo.RegionName);
219 440
220 if (!m_entityTransferStateMachine.SetInTransit(sp.UUID))
221 {
222 m_log.DebugFormat(
223 "[ENTITY TRANSFER MODULE]: Ignoring within region teleport request of {0} {1} to {2} - agent is already in transit.",
224 sp.Name, sp.UUID, position);
225
226 return;
227 }
228
229 // Teleport within the same region 441 // Teleport within the same region
230 if (IsOutsideRegion(sp.Scene, position) || position.Z < 0) 442 if (!sp.Scene.PositionIsInCurrentRegion(position) || position.Z < 0)
231 { 443 {
232 Vector3 emergencyPos = new Vector3(128, 128, 128); 444 Vector3 emergencyPos = new Vector3(128, 128, 128);
233 445
234 m_log.WarnFormat( 446 m_log.WarnFormat(
235 "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", 447 "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2} in {3}. Substituting {4}",
236 position, sp.Name, sp.UUID, emergencyPos); 448 position, sp.Name, sp.UUID, Scene.Name, emergencyPos);
237 449
238 position = emergencyPos; 450 position = emergencyPos;
239 } 451 }
@@ -243,10 +455,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
243 float posZLimit = 22; 455 float posZLimit = 22;
244 456
245 // TODO: Check other Scene HeightField 457 // TODO: Check other Scene HeightField
246 if (position.X > 0 && position.X <= (int)Constants.RegionSize && position.Y > 0 && position.Y <= (int)Constants.RegionSize) 458 posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y];
247 {
248 posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y];
249 }
250 459
251 float newPosZ = posZLimit + localAVHeight; 460 float newPosZ = posZLimit + localAVHeight;
252 if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) 461 if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ)))
@@ -254,11 +463,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
254 position.Z = newPosZ; 463 position.Z = newPosZ;
255 } 464 }
256 465
466 if (sp.Flying)
467 teleportFlags |= (uint)TeleportFlags.IsFlying;
468
257 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); 469 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
258 470
259 sp.ControllingClient.SendTeleportStart(teleportFlags); 471 sp.ControllingClient.SendTeleportStart(teleportFlags);
260 472
261 sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); 473 sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags);
474 sp.TeleportFlags = (Constants.TeleportFlags)teleportFlags;
262 sp.Velocity = Vector3.Zero; 475 sp.Velocity = Vector3.Zero;
263 sp.Teleport(position); 476 sp.Teleport(position);
264 477
@@ -270,7 +483,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
270 } 483 }
271 484
272 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); 485 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
273 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
274 } 486 }
275 487
276 /// <summary> 488 /// <summary>
@@ -286,21 +498,23 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
286 ScenePresence sp, ulong regionHandle, Vector3 position, 498 ScenePresence sp, ulong regionHandle, Vector3 position,
287 Vector3 lookAt, uint teleportFlags, out GridRegion finalDestination) 499 Vector3 lookAt, uint teleportFlags, out GridRegion finalDestination)
288 { 500 {
289 uint x = 0, y = 0; 501 // Get destination region taking into account that the address could be an offset
290 Utils.LongToUInts(regionHandle, out x, out y); 502 // region inside a varregion.
291 GridRegion reg = Scene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); 503 GridRegion reg = GetTeleportDestinationRegion(sp.Scene.GridService, sp.Scene.RegionInfo.ScopeID, regionHandle, ref position);
292 504
293 if (reg != null) 505 if (reg != null)
294 { 506 {
295 finalDestination = GetFinalDestination(reg); 507 string homeURI = Scene.GetAgentHomeURI(sp.ControllingClient.AgentId);
508
509 string message;
510 finalDestination = GetFinalDestination(reg, sp.ControllingClient.AgentId, homeURI, out message);
296 511
297 if (finalDestination == null) 512 if (finalDestination == null)
298 { 513 {
299 m_log.WarnFormat( 514 m_log.WarnFormat( "{0} Final destination is having problems. Unable to teleport {1} {2}: {3}",
300 "[ENTITY TRANSFER MODULE]: Final destination is having problems. Unable to teleport {0} {1}", 515 LogHeader, sp.Name, sp.UUID, message);
301 sp.Name, sp.UUID);
302 516
303 sp.ControllingClient.SendTeleportFailed("Problem at destination"); 517 sp.ControllingClient.SendTeleportFailed(message);
304 return; 518 return;
305 } 519 }
306 520
@@ -321,10 +535,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
321 return; 535 return;
322 } 536 }
323 537
538 if (message != null)
539 sp.ControllingClient.SendAgentAlertMessage(message, true);
540
324 // 541 //
325 // This is it 542 // This is it
326 // 543 //
327 DoTeleport(sp, reg, finalDestination, position, lookAt, teleportFlags); 544 DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags);
328 // 545 //
329 // 546 //
330 // 547 //
@@ -339,12 +556,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
339 556
340 // and set the map-tile to '(Offline)' 557 // and set the map-tile to '(Offline)'
341 uint regX, regY; 558 uint regX, regY;
342 Utils.LongToUInts(regionHandle, out regX, out regY); 559 Util.RegionHandleToRegionLoc(regionHandle, out regX, out regY);
343 560
344 MapBlockData block = new MapBlockData(); 561 MapBlockData block = new MapBlockData();
345 block.X = (ushort)(regX / Constants.RegionSize); 562 block.X = (ushort)regX;
346 block.Y = (ushort)(regY / Constants.RegionSize); 563 block.Y = (ushort)regY;
347 block.Access = 254; // == not there 564 block.Access = (byte)SimAccess.Down;
348 565
349 List<MapBlockData> blocks = new List<MapBlockData>(); 566 List<MapBlockData> blocks = new List<MapBlockData>();
350 blocks.Add(block); 567 blocks.Add(block);
@@ -352,6 +569,31 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
352 } 569 }
353 } 570 }
354 571
572 // The teleport address could be an address in a subregion of a larger varregion.
573 // Find the real base region and adjust the teleport location to account for the
574 // larger region.
575 private GridRegion GetTeleportDestinationRegion(IGridService gridService, UUID scope, ulong regionHandle, ref Vector3 position)
576 {
577 uint x = 0, y = 0;
578 Util.RegionHandleToWorldLoc(regionHandle, out x, out y);
579
580 // Compute the world location we're teleporting to
581 double worldX = (double)x + position.X;
582 double worldY = (double)y + position.Y;
583
584 // Find the region that contains the position
585 GridRegion reg = GetRegionContainingWorldLocation(gridService, scope, worldX, worldY);
586
587 if (reg != null)
588 {
589 // modify the position for the offset into the actual region returned
590 position.X += x - reg.RegionLocX;
591 position.Y += y - reg.RegionLocY;
592 }
593
594 return reg;
595 }
596
355 // Nothing to validate here 597 // Nothing to validate here
356 protected virtual bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason) 598 protected virtual bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason)
357 { 599 {
@@ -359,6 +601,32 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
359 return true; 601 return true;
360 } 602 }
361 603
604 /// <summary>
605 /// Determines whether this instance is within the max transfer distance.
606 /// </summary>
607 /// <param name="sourceRegion"></param>
608 /// <param name="destRegion"></param>
609 /// <returns>
610 /// <c>true</c> if this instance is within max transfer distance; otherwise, <c>false</c>.
611 /// </returns>
612 private bool IsWithinMaxTeleportDistance(RegionInfo sourceRegion, GridRegion destRegion)
613 {
614 if(MaxTransferDistance == 0)
615 return true;
616
617// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY);
618//
619// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}",
620// destRegionX, destRegionY, finalDestination.RegionID, finalDestination.ServerURI);
621
622 // Insanely, RegionLoc on RegionInfo is the 256m map co-ord whilst GridRegion.RegionLoc is the raw meters position.
623 return Math.Abs(sourceRegion.RegionLocX - destRegion.RegionCoordX) <= MaxTransferDistance
624 && Math.Abs(sourceRegion.RegionLocY - destRegion.RegionCoordY) <= MaxTransferDistance;
625 }
626
627 /// <summary>
628 /// Wraps DoTeleportInternal() and manages the transfer state.
629 /// </summary>
362 public void DoTeleport( 630 public void DoTeleport(
363 ScenePresence sp, GridRegion reg, GridRegion finalDestination, 631 ScenePresence sp, GridRegion reg, GridRegion finalDestination,
364 Vector3 position, Vector3 lookAt, uint teleportFlags) 632 Vector3 position, Vector3 lookAt, uint teleportFlags)
@@ -370,18 +638,45 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
370 m_log.DebugFormat( 638 m_log.DebugFormat(
371 "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.", 639 "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.",
372 sp.Name, sp.UUID, reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position); 640 sp.Name, sp.UUID, reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position);
373 641 sp.ControllingClient.SendTeleportFailed("Agent is already in transit.");
374 return; 642 return;
375 } 643 }
644
645 try
646 {
647 DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags);
648 }
649 catch (Exception e)
650 {
651 m_log.ErrorFormat(
652 "[ENTITY TRANSFER MODULE]: Exception on teleport of {0} from {1}@{2} to {3}@{4}: {5}{6}",
653 sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, finalDestination.RegionName,
654 e.Message, e.StackTrace);
376 655
377 if (reg == null || finalDestination == null) 656 sp.ControllingClient.SendTeleportFailed("Internal error");
657 }
658 finally
378 { 659 {
379 sp.ControllingClient.SendTeleportFailed("Unable to locate destination");
380 m_entityTransferStateMachine.ResetFromTransit(sp.UUID); 660 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
661 }
662 }
381 663
664 /// <summary>
665 /// Teleports the agent to another region.
666 /// This method doesn't manage the transfer state; the caller must do that.
667 /// </summary>
668 private void DoTeleportInternal(
669 ScenePresence sp, GridRegion reg, GridRegion finalDestination,
670 Vector3 position, Vector3 lookAt, uint teleportFlags)
671 {
672 if (reg == null || finalDestination == null)
673 {
674 sp.ControllingClient.SendTeleportFailed("Unable to locate destination");
382 return; 675 return;
383 } 676 }
384 677
678 string homeURI = Scene.GetAgentHomeURI(sp.ControllingClient.AgentId);
679
385 m_log.DebugFormat( 680 m_log.DebugFormat(
386 "[ENTITY TRANSFER MODULE]: Teleporting {0} {1} from {2} to {3} ({4}) {5}/{6}", 681 "[ENTITY TRANSFER MODULE]: Teleporting {0} {1} from {2} to {3} ({4}) {5}/{6}",
387 sp.Name, sp.UUID, sp.Scene.RegionInfo.RegionName, 682 sp.Name, sp.UUID, sp.Scene.RegionInfo.RegionName,
@@ -389,10 +684,21 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
389 684
390 RegionInfo sourceRegion = sp.Scene.RegionInfo; 685 RegionInfo sourceRegion = sp.Scene.RegionInfo;
391 686
392 uint newRegionX = (uint)(reg.RegionHandle >> 40); 687 if (!IsWithinMaxTeleportDistance(sourceRegion, finalDestination))
393 uint newRegionY = (((uint)(reg.RegionHandle)) >> 8); 688 {
394 uint oldRegionX = (uint)(sp.Scene.RegionInfo.RegionHandle >> 40); 689 sp.ControllingClient.SendTeleportFailed(
395 uint oldRegionY = (((uint)(sp.Scene.RegionInfo.RegionHandle)) >> 8); 690 string.Format(
691 "Can't teleport to {0} ({1},{2}) from {3} ({4},{5}), destination is more than {6} regions way",
692 finalDestination.RegionName, finalDestination.RegionCoordX, finalDestination.RegionCoordY,
693 sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY,
694 MaxTransferDistance));
695
696 return;
697 }
698
699 uint newRegionX, newRegionY, oldRegionX, oldRegionY;
700 Util.RegionHandleToRegionLoc(reg.RegionHandle, out newRegionX, out newRegionY);
701 Util.RegionHandleToRegionLoc(sp.Scene.RegionInfo.RegionHandle, out oldRegionX, out oldRegionY);
396 702
397 ulong destinationHandle = finalDestination.RegionHandle; 703 ulong destinationHandle = finalDestination.RegionHandle;
398 704
@@ -400,11 +706,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
400 // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field, 706 // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field,
401 // it's actually doing a lot of work. 707 // it's actually doing a lot of work.
402 IPEndPoint endPoint = finalDestination.ExternalEndPoint; 708 IPEndPoint endPoint = finalDestination.ExternalEndPoint;
403 709 if (endPoint == null || endPoint.Address == null)
404 if (endPoint.Address == null)
405 { 710 {
406 sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); 711 sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down");
407 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
408 712
409 return; 713 return;
410 } 714 }
@@ -412,35 +716,41 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
412 if (!sp.ValidateAttachments()) 716 if (!sp.ValidateAttachments())
413 m_log.DebugFormat( 717 m_log.DebugFormat(
414 "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.", 718 "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.",
415 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName); 719 sp.Name, sp.Scene.Name, finalDestination.RegionName);
416
417// if (!sp.ValidateAttachments())
418// {
419// sp.ControllingClient.SendTeleportFailed("Inconsistent attachment state");
420// return;
421// }
422 720
423 string reason; 721 string reason;
424 string version; 722 EntityTransferContext ctx = new EntityTransferContext();
723
425 if (!Scene.SimulationService.QueryAccess( 724 if (!Scene.SimulationService.QueryAccess(
426 finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason)) 725 finalDestination, sp.ControllingClient.AgentId, homeURI, true, position, sp.Scene.GetFormatsOffered(), ctx, out reason))
427 { 726 {
428 sp.ControllingClient.SendTeleportFailed(reason); 727 sp.ControllingClient.SendTeleportFailed(reason);
429 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
430 728
431 m_log.DebugFormat( 729 m_log.DebugFormat(
432 "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}", 730 "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because: {3}",
433 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); 731 sp.Name, sp.Scene.Name, finalDestination.RegionName, reason);
434 732
435 return; 733 return;
436 } 734 }
437 735
438 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version); 736 // Before this point, teleport 'failure' is due to checkable pre-conditions such as whether the target
737 // simulator can be found and is explicitly prepared to allow access. Therefore, we will not count these
738 // as server attempts.
739 m_interRegionTeleportAttempts.Value++;
740
741 m_log.DebugFormat(
742 "[ENTITY TRANSFER MODULE]: {0} transfer protocol version to {1} is {2} / {3}",
743 sp.Scene.Name, finalDestination.RegionName, ctx.OutboundVersion, ctx.InboundVersion);
439 744
440 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from 745 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from
441 // both regions 746 // both regions
442 if (sp.ParentID != (uint)0) 747 if (sp.ParentID != (uint)0)
443 sp.StandUp(); 748 sp.StandUp();
749 else if (sp.Flying)
750 teleportFlags |= (uint)TeleportFlags.IsFlying;
751
752 if (DisableInterRegionTeleportCancellation)
753 teleportFlags |= (uint)TeleportFlags.DisableCancel;
444 754
445 // At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to 755 // At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to
446 // the viewer. However, it might mean that the viewer does not see the black teleport screen (untested). 756 // the viewer. However, it might mean that the viewer does not see the black teleport screen (untested).
@@ -454,13 +764,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
454 // once we reach here... 764 // once we reach here...
455 //avatar.Scene.RemoveCapsHandler(avatar.UUID); 765 //avatar.Scene.RemoveCapsHandler(avatar.UUID);
456 766
457 string capsPath = String.Empty;
458
459 AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); 767 AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
460 AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo(); 768 AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo();
461 agentCircuit.startpos = position; 769 agentCircuit.startpos = position;
462 agentCircuit.child = true; 770 agentCircuit.child = true;
463 agentCircuit.Appearance = sp.Appearance; 771 agentCircuit.Appearance = new AvatarAppearance();
772 agentCircuit.Appearance.PackLegacyWearables = true;
464 if (currentAgentCircuit != null) 773 if (currentAgentCircuit != null)
465 { 774 {
466 agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs; 775 agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs;
@@ -471,23 +780,66 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
471 agentCircuit.Id0 = currentAgentCircuit.Id0; 780 agentCircuit.Id0 = currentAgentCircuit.Id0;
472 } 781 }
473 782
474 if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) 783 // if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY))
784 float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance,
785 (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY));
786 if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY))
475 { 787 {
476 // brand new agent, let's create a new caps seed 788 // brand new agent, let's create a new caps seed
477 agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); 789 agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath();
478 } 790 }
479 791
480 // Let's create an agent there if one doesn't exist yet. 792 // We're going to fallback to V1 if the destination gives us anything smaller than 0.2
793 if (ctx.OutboundVersion >= 0.2f)
794 TransferAgent_V2(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, ctx, out reason);
795 else
796 TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, ctx, out reason);
797 }
798
799 private void TransferAgent_V1(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination,
800 IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, EntityTransferContext ctx, out string reason)
801 {
802 ulong destinationHandle = finalDestination.RegionHandle;
803 AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
804
805 m_log.DebugFormat(
806 "[ENTITY TRANSFER MODULE]: Using TP V1 for {0} going from {1} to {2}",
807 sp.Name, Scene.Name, finalDestination.RegionName);
808
809 // Let's create an agent there if one doesn't exist yet.
810 // NOTE: logout will always be false for a non-HG teleport.
481 bool logout = false; 811 bool logout = false;
482 if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) 812 if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout))
483 { 813 {
484 sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason)); 814 m_interRegionTeleportFailures.Value++;
485 m_entityTransferStateMachine.ResetFromTransit(sp.UUID);
486 815
487 m_log.DebugFormat( 816 m_log.DebugFormat(
488 "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}", 817 "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}",
489 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); 818 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason);
490 819
820 sp.ControllingClient.SendTeleportFailed(reason);
821
822 return;
823 }
824
825 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
826 {
827 m_interRegionTeleportCancels.Value++;
828
829 m_log.DebugFormat(
830 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request",
831 sp.Name, finalDestination.RegionName, sp.Scene.Name);
832
833 return;
834 }
835 else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
836 {
837 m_interRegionTeleportAborts.Value++;
838
839 m_log.DebugFormat(
840 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.",
841 sp.Name, finalDestination.RegionName, sp.Scene.Name);
842
491 return; 843 return;
492 } 844 }
493 845
@@ -497,9 +849,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
497 // OK, it got this agent. Let's close some child agents 849 // OK, it got this agent. Let's close some child agents
498 sp.CloseChildAgents(newRegionX, newRegionY); 850 sp.CloseChildAgents(newRegionX, newRegionY);
499 851
500 IClientIPEndpoint ipepClient; 852 IClientIPEndpoint ipepClient;
501 if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) 853 string capsPath = String.Empty;
854 float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance,
855 (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY));
856 if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY))
502 { 857 {
858 m_log.DebugFormat(
859 "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for incoming agent {3} from {4}",
860 finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name);
861
503 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); 862 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent...");
504 #region IP Translation for NAT 863 #region IP Translation for NAT
505 // Uses ipepClient above 864 // Uses ipepClient above
@@ -512,21 +871,30 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
512 871
513 if (m_eqModule != null) 872 if (m_eqModule != null)
514 { 873 {
515 m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID); 874 // The EnableSimulator message makes the client establish a connection with the destination
516 875 // simulator by sending the initial UseCircuitCode UDP packet to the destination containing the
517 // ES makes the client send a UseCircuitCode message to the destination, 876 // correct circuit code.
518 // which triggers a bunch of things there. 877 m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID,
519 // So let's wait 878 finalDestination.RegionSizeX, finalDestination.RegionSizeY);
879 m_log.DebugFormat("{0} Sent EnableSimulator. regName={1}, size=<{2},{3}>", LogHeader,
880 finalDestination.RegionName, finalDestination.RegionSizeX, finalDestination.RegionSizeY);
881
882 // XXX: Is this wait necessary? We will always end up waiting on UpdateAgent for the destination
883 // simulator to confirm that it has established communication with the viewer.
520 Thread.Sleep(200); 884 Thread.Sleep(200);
521 885
522 // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears 886 // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears
523 // unnecessary - teleport will succeed and SEED caps will be requested without it (though possibly 887 // unnecessary - teleport will succeed and SEED caps will be requested without it (though possibly
524 // only on TeleportFinish). This is untested for region teleport between different simulators 888 // only on TeleportFinish). This is untested for region teleport between different simulators
525 // though this probably also works. 889 // though this probably also works.
526 m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); 890 m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath, finalDestination.RegionHandle,
891 finalDestination.RegionSizeX, finalDestination.RegionSizeY);
527 } 892 }
528 else 893 else
529 { 894 {
895 // XXX: This is a little misleading since we're information the client of its avatar destination,
896 // which may or may not be a neighbour region of the source region. This path is probably little
897 // used anyway (with EQ being the one used). But it is currently being used for test code.
530 sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); 898 sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint);
531 } 899 }
532 } 900 }
@@ -539,31 +907,77 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
539 // Let's send a full update of the agent. This is a synchronous call. 907 // Let's send a full update of the agent. This is a synchronous call.
540 AgentData agent = new AgentData(); 908 AgentData agent = new AgentData();
541 sp.CopyTo(agent); 909 sp.CopyTo(agent);
542 agent.Position = position; 910 if (ctx.OutboundVersion < 0.5f)
911 agent.Appearance.PackLegacyWearables = true;
912 agent.Position = agentCircuit.startpos;
543 SetCallbackURL(agent, sp.Scene.RegionInfo); 913 SetCallbackURL(agent, sp.Scene.RegionInfo);
544 914
545 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent...");
546 915
916 // We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to
917 // establish th econnection to the destination which makes it return true.
918 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
919 {
920 m_interRegionTeleportAborts.Value++;
921
922 m_log.DebugFormat(
923 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent",
924 sp.Name, finalDestination.RegionName, sp.Scene.Name);
925
926 return;
927 }
928
929 // A common teleport failure occurs when we can send CreateAgent to the
930 // destination region but the viewer cannot establish the connection (e.g. due to network issues between
931 // the viewer and the destination). In this case, UpdateAgent timesout after 10 seconds, although then
932 // there's a further 10 second wait whilst we attempt to tell the destination to delete the agent in Fail().
547 if (!UpdateAgent(reg, finalDestination, agent, sp)) 933 if (!UpdateAgent(reg, finalDestination, agent, sp))
548 { 934 {
549 // Region doesn't take it 935 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
936 {
937 m_interRegionTeleportAborts.Value++;
938
939 m_log.DebugFormat(
940 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.",
941 sp.Name, finalDestination.RegionName, sp.Scene.Name);
942
943 return;
944 }
945
550 m_log.WarnFormat( 946 m_log.WarnFormat(
551 "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Returning avatar to source region.", 947 "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}",
552 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); 948 sp.Name, finalDestination.RegionName, sp.Scene.Name);
553 949
554 Fail(sp, finalDestination, logout); 950 Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established.");
555 return; 951 return;
556 } 952 }
557 953
558 sp.ControllingClient.SendTeleportProgress(teleportFlags | (uint)TeleportFlags.DisableCancel, "sending_dest"); 954 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
955 {
956 m_interRegionTeleportCancels.Value++;
957
958 m_log.DebugFormat(
959 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request",
960 sp.Name, finalDestination.RegionName, sp.Scene.Name);
961
962 CleanupFailedInterRegionTeleport(sp, currentAgentCircuit.SessionID.ToString(), finalDestination);
963
964 return;
965 }
559 966
560 m_log.DebugFormat( 967 m_log.DebugFormat(
561 "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", 968 "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
562 capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); 969 capsPath, sp.Scene.RegionInfo.RegionName, sp.Name);
563 970
971 // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator,
972 // where that neighbour simulator could otherwise request a child agent create on the source which then
973 // closes our existing agent which is still signalled as root.
974 sp.IsChildAgent = true;
975
976 // OK, send TPFinish to the client, so that it starts the process of contacting the destination region
564 if (m_eqModule != null) 977 if (m_eqModule != null)
565 { 978 {
566 m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); 979 m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID,
980 finalDestination.RegionSizeX, finalDestination.RegionSizeY);
567 } 981 }
568 else 982 else
569 { 983 {
@@ -571,31 +985,43 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
571 teleportFlags, capsPath); 985 teleportFlags, capsPath);
572 } 986 }
573 987
574 // Let's set this to true tentatively. This does not trigger OnChildAgent
575 sp.IsChildAgent = true;
576
577 // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which 988 // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
578 // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation 989 // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation
579 // that the client contacted the destination before we close things here. 990 // that the client contacted the destination before we close things here.
580 if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID)) 991 if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID))
581 { 992 {
993 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
994 {
995 m_interRegionTeleportAborts.Value++;
996
997 m_log.DebugFormat(
998 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.",
999 sp.Name, finalDestination.RegionName, sp.Scene.Name);
1000
1001 return;
1002 }
1003
582 m_log.WarnFormat( 1004 m_log.WarnFormat(
583 "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", 1005 "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.",
584 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); 1006 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
585 1007
586 Fail(sp, finalDestination, logout); 1008 Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Destination region did not signal teleport completion.");
1009
587 return; 1010 return;
588 } 1011 }
589 1012
590 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); 1013 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
591 1014
1015/*
1016 // TODO: This may be 0.6. Check if still needed
592 // For backwards compatibility 1017 // For backwards compatibility
593 if (version == "Unknown" || version == string.Empty) 1018 if (version == 0f)
594 { 1019 {
595 // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it 1020 // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it
596 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Old simulator, sending attachments one by one..."); 1021 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Old simulator, sending attachments one by one...");
597 CrossAttachmentsIntoNewRegion(finalDestination, sp, true); 1022 CrossAttachmentsIntoNewRegion(finalDestination, sp, true);
598 } 1023 }
1024*/
599 1025
600 // May need to logout or other cleanup 1026 // May need to logout or other cleanup
601 AgentHasMovedAway(sp, logout); 1027 AgentHasMovedAway(sp, logout);
@@ -606,12 +1032,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
606 // Now let's make it officially a child agent 1032 // Now let's make it officially a child agent
607 sp.MakeChildAgent(); 1033 sp.MakeChildAgent();
608 1034
609// sp.Scene.CleanDroppedAttachments();
610
611 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone 1035 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
612 1036
613 if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) 1037 if (NeedsClosing(sp.Scene.DefaultDrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
614 { 1038 {
1039 if (!sp.Scene.IncomingPreCloseClient(sp))
1040 return;
1041
615 // We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before 1042 // We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before
616 // they regard the new region as the current region after receiving the AgentMovementComplete 1043 // they regard the new region as the current region after receiving the AgentMovementComplete
617 // response. If close is sent before then, it will cause the viewer to quit instead. 1044 // response. If close is sent before then, it will cause the viewer to quit instead.
@@ -620,51 +1047,243 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
620 // an agent cannot teleport back to this region if it has teleported away. 1047 // an agent cannot teleport back to this region if it has teleported away.
621 Thread.Sleep(2000); 1048 Thread.Sleep(2000);
622 1049
623 sp.Scene.IncomingCloseAgent(sp.UUID, false); 1050 sp.Scene.CloseAgent(sp.UUID, false);
624 } 1051 }
625 else 1052 else
626 { 1053 {
627 // now we have a child agent in this region. 1054 // now we have a child agent in this region.
628 sp.Reset(); 1055 sp.Reset();
629 } 1056 }
1057 }
630 1058
631 // Commented pending deletion since this method no longer appears to do anything at all 1059 private void TransferAgent_V2(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination,
632// // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! 1060 IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, EntityTransferContext ctx, out string reason)
633// if (sp.Scene.NeedSceneCacheClear(sp.UUID)) 1061 {
634// { 1062 ulong destinationHandle = finalDestination.RegionHandle;
635// m_log.DebugFormat( 1063 AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
636// "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed", 1064
637// sp.UUID); 1065 // Let's create an agent there if one doesn't exist yet.
638// } 1066 // NOTE: logout will always be false for a non-HG teleport.
1067 bool logout = false;
1068 if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout))
1069 {
1070 m_interRegionTeleportFailures.Value++;
1071
1072 m_log.DebugFormat(
1073 "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}",
1074 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason);
1075
1076 sp.ControllingClient.SendTeleportFailed(reason);
1077
1078 return;
1079 }
1080
1081 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
1082 {
1083 m_interRegionTeleportCancels.Value++;
1084
1085 m_log.DebugFormat(
1086 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request",
1087 sp.Name, finalDestination.RegionName, sp.Scene.Name);
1088
1089 return;
1090 }
1091 else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
1092 {
1093 m_interRegionTeleportAborts.Value++;
1094
1095 m_log.DebugFormat(
1096 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.",
1097 sp.Name, finalDestination.RegionName, sp.Scene.Name);
1098
1099 return;
1100 }
1101
1102 // Past this point we have to attempt clean up if the teleport fails, so update transfer state.
1103 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
1104
1105 IClientIPEndpoint ipepClient;
1106 string capsPath = String.Empty;
1107 float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance,
1108 (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY));
1109 if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY))
1110 {
1111 m_log.DebugFormat(
1112 "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for agent {3} from {4}",
1113 finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name);
1114
1115 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent...");
1116 #region IP Translation for NAT
1117 // Uses ipepClient above
1118 if (sp.ClientView.TryGet(out ipepClient))
1119 {
1120 endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address);
1121 }
1122 #endregion
1123 capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
1124 }
1125 else
1126 {
1127 agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle);
1128 capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
1129 }
1130
1131 // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator,
1132 // where that neighbour simulator could otherwise request a child agent create on the source which then
1133 // closes our existing agent which is still signalled as root.
1134 //sp.IsChildAgent = true;
1135
1136 // New protocol: send TP Finish directly, without prior ES or EAC. That's what happens in the Linden grid
1137 if (m_eqModule != null)
1138 m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID,
1139 finalDestination.RegionSizeX, finalDestination.RegionSizeY);
1140 else
1141 sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4,
1142 teleportFlags, capsPath);
1143
1144 m_log.DebugFormat(
1145 "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
1146 capsPath, sp.Scene.RegionInfo.RegionName, sp.Name);
1147
1148 // Let's send a full update of the agent.
1149 AgentData agent = new AgentData();
1150 sp.CopyTo(agent);
1151 if (ctx.OutboundVersion < 0.5f)
1152 agent.Appearance.PackLegacyWearables = true;
1153 agent.Position = agentCircuit.startpos;
1154 agent.SenderWantsToWaitForRoot = true;
1155 //SetCallbackURL(agent, sp.Scene.RegionInfo);
1156
1157 // Reset the do not close flag. This must be done before the destination opens child connections (here
1158 // triggered by UpdateAgent) to avoid race conditions. However, we also want to reset it as late as possible
1159 // to avoid a situation where an unexpectedly early call to Scene.NewUserConnection() wrongly results
1160 // in no close.
1161 sp.DoNotCloseAfterTeleport = false;
1162
1163 // Send the Update. If this returns true, we know the client has contacted the destination
1164 // via CompleteMovementIntoRegion, so we can let go.
1165 // If it returns false, something went wrong, and we need to abort.
1166 if (!UpdateAgent(reg, finalDestination, agent, sp))
1167 {
1168 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
1169 {
1170 m_interRegionTeleportAborts.Value++;
1171
1172 m_log.DebugFormat(
1173 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.",
1174 sp.Name, finalDestination.RegionName, sp.Scene.Name);
1175
1176 return;
1177 }
1178
1179 m_log.WarnFormat(
1180 "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}",
1181 sp.Name, finalDestination.RegionName, sp.Scene.Name);
1182
1183 Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established.");
1184 return;
1185 }
1186
1187 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
1188
1189 // Need to signal neighbours whether child agents may need closing irrespective of whether this
1190 // one needed closing. We also need to close child agents as quickly as possible to avoid complicated
1191 // race conditions with rapid agent releporting (e.g. from A1 to a non-neighbour B, back
1192 // to a neighbour A2 then off to a non-neighbour C). Closing child agents any later requires complex
1193 // distributed checks to avoid problems in rapid reteleporting scenarios and where child agents are
1194 // abandoned without proper close by viewer but then re-used by an incoming connection.
1195 sp.CloseChildAgents(newRegionX, newRegionY);
1196
1197 // May need to logout or other cleanup
1198 AgentHasMovedAway(sp, logout);
1199
1200 // Well, this is it. The agent is over there.
1201 KillEntity(sp.Scene, sp.LocalId);
639 1202
640 m_entityTransferStateMachine.ResetFromTransit(sp.UUID); 1203 // Now let's make it officially a child agent
1204 sp.MakeChildAgent();
1205
1206 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
1207 if (NeedsClosing(sp.Scene.DefaultDrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
1208 {
1209 if (!sp.Scene.IncomingPreCloseClient(sp))
1210 return;
1211
1212 // RED ALERT!!!!
1213 // PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES.
1214 // THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion
1215 // BEFORE THEY SETTLE IN THE NEW REGION.
1216 // DECREASING THE WAIT TIME HERE WILL EITHER RESULT IN A VIEWER CRASH OR
1217 // IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS.
1218 Thread.Sleep(15000);
1219
1220 // OK, it got this agent. Let's close everything
1221 // If we shouldn't close the agent due to some other region renewing the connection
1222 // then this will be handled in IncomingCloseAgent under lock conditions
1223 m_log.DebugFormat(
1224 "[ENTITY TRANSFER MODULE]: Closing agent {0} in {1} after teleport", sp.Name, Scene.Name);
1225
1226 sp.Scene.CloseAgent(sp.UUID, false);
1227 }
1228 else
1229 {
1230 // now we have a child agent in this region.
1231 sp.Reset();
1232 }
641 } 1233 }
642 1234
643 protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout) 1235 /// <summary>
1236 /// Clean up an inter-region teleport that did not complete, either because of simulator failure or cancellation.
1237 /// </summary>
1238 /// <remarks>
1239 /// All operations here must be idempotent so that we can call this method at any point in the teleport process
1240 /// up until we send the TeleportFinish event quene event to the viewer.
1241 /// <remarks>
1242 /// <param name='sp'> </param>
1243 /// <param name='finalDestination'></param>
1244 protected virtual void CleanupFailedInterRegionTeleport(ScenePresence sp, string auth_token, GridRegion finalDestination)
644 { 1245 {
645 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); 1246 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
646 1247
647 // Client never contacted destination. Let's restore everything back 1248 if (sp.IsChildAgent) // We had set it to child before attempted TP (V1)
648 sp.ControllingClient.SendTeleportFailed("Problems connecting to destination."); 1249 {
1250 sp.IsChildAgent = false;
1251 ReInstantiateScripts(sp);
649 1252
650 // Fail. Reset it back 1253 EnableChildAgents(sp);
651 sp.IsChildAgent = false; 1254 }
652 ReInstantiateScripts(sp); 1255 // Finally, kill the agent we just created at the destination.
1256 // XXX: Possibly this should be done asynchronously.
1257 Scene.SimulationService.CloseAgent(finalDestination, sp.UUID, auth_token);
1258 }
653 1259
654 EnableChildAgents(sp); 1260 /// <summary>
1261 /// Signal that the inter-region teleport failed and perform cleanup.
1262 /// </summary>
1263 /// <param name='sp'></param>
1264 /// <param name='finalDestination'></param>
1265 /// <param name='logout'></param>
1266 /// <param name='reason'>Human readable reason for teleport failure. Will be sent to client.</param>
1267 protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout, string auth_code, string reason)
1268 {
1269 CleanupFailedInterRegionTeleport(sp, auth_code, finalDestination);
655 1270
656 // Finally, kill the agent we just created at the destination. 1271 m_interRegionTeleportFailures.Value++;
657 Scene.SimulationService.CloseAgent(finalDestination, sp.UUID);
658 1272
659 sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); 1273 sp.ControllingClient.SendTeleportFailed(
1274 string.Format(
1275 "Problems connecting to destination {0}, reason: {1}", finalDestination.RegionName, reason));
660 1276
661 m_entityTransferStateMachine.ResetFromTransit(sp.UUID); 1277 sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout);
662 } 1278 }
663 1279
664 protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout) 1280 protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout)
665 { 1281 {
1282 GridRegion source = new GridRegion(Scene.RegionInfo);
1283 source.RawServerURI = m_GatekeeperURI;
1284
666 logout = false; 1285 logout = false;
667 bool success = Scene.SimulationService.CreateAgent(finalDestination, agentCircuit, teleportFlags, out reason); 1286 bool success = Scene.SimulationService.CreateAgent(source, finalDestination, agentCircuit, teleportFlags, out reason);
668 1287
669 if (success) 1288 if (success)
670 sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout); 1289 sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout);
@@ -702,14 +1321,32 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
702 scene.SendKillObject(new List<uint> { localID }); 1321 scene.SendKillObject(new List<uint> { localID });
703 } 1322 }
704 1323
705 protected virtual GridRegion GetFinalDestination(GridRegion region) 1324 protected virtual GridRegion GetFinalDestination(GridRegion region, UUID agentID, string agentHomeURI, out string message)
706 { 1325 {
1326 message = null;
707 return region; 1327 return region;
708 } 1328 }
709 1329
1330 // This returns 'true' if the new region already has a child agent for our
1331 // incoming agent. The implication is that, if 'false', we have to create the
1332 // child and then teleport into the region.
710 protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY) 1333 protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY)
711 { 1334 {
712 return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY); 1335 if (m_regionCombinerModule != null && m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID))
1336 {
1337 Vector2 swCorner, neCorner;
1338 GetMegaregionViewRange(out swCorner, out neCorner);
1339
1340 m_log.DebugFormat(
1341 "[ENTITY TRANSFER MODULE]: Megaregion view of {0} is from {1} to {2} with new agent check for {3},{4}",
1342 Scene.Name, swCorner, neCorner, newRegionX, newRegionY);
1343
1344 return !(newRegionX >= swCorner.X && newRegionX <= neCorner.X && newRegionY >= swCorner.Y && newRegionY <= neCorner.Y);
1345 }
1346 else
1347 {
1348 return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY);
1349 }
713 } 1350 }
714 1351
715 protected virtual bool NeedsClosing(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg) 1352 protected virtual bool NeedsClosing(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg)
@@ -717,20 +1354,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
717 return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY); 1354 return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY);
718 } 1355 }
719 1356
720 protected virtual bool IsOutsideRegion(Scene s, Vector3 pos)
721 {
722 if (s.TestBorderCross(pos, Cardinals.N))
723 return true;
724 if (s.TestBorderCross(pos, Cardinals.S))
725 return true;
726 if (s.TestBorderCross(pos, Cardinals.E))
727 return true;
728 if (s.TestBorderCross(pos, Cardinals.W))
729 return true;
730
731 return false;
732 }
733
734 #endregion 1357 #endregion
735 1358
736 #region Landmark Teleport 1359 #region Landmark Teleport
@@ -758,7 +1381,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
758 1381
759 #region Teleport Home 1382 #region Teleport Home
760 1383
761 public virtual void TeleportHome(UUID id, IClientAPI client) 1384 public virtual void TriggerTeleportHome(UUID id, IClientAPI client)
1385 {
1386 TeleportHome(id, client);
1387 }
1388
1389 public virtual bool TeleportHome(UUID id, IClientAPI client)
762 { 1390 {
763 m_log.DebugFormat( 1391 m_log.DebugFormat(
764 "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId); 1392 "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId);
@@ -768,12 +1396,20 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
768 1396
769 if (uinfo != null) 1397 if (uinfo != null)
770 { 1398 {
1399 if (uinfo.HomeRegionID == UUID.Zero)
1400 {
1401 // can't find the Home region: Tell viewer and abort
1402 m_log.ErrorFormat("{0} No grid user info found for {1} {2}. Cannot send home.",
1403 LogHeader, client.Name, client.AgentId);
1404 client.SendTeleportFailed("You don't have a home position set.");
1405 return false;
1406 }
771 GridRegion regionInfo = Scene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID); 1407 GridRegion regionInfo = Scene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID);
772 if (regionInfo == null) 1408 if (regionInfo == null)
773 { 1409 {
774 // can't find the Home region: Tell viewer and abort 1410 // can't find the Home region: Tell viewer and abort
775 client.SendTeleportFailed("Your home region could not be found."); 1411 client.SendTeleportFailed("Your home region could not be found.");
776 return; 1412 return false;
777 } 1413 }
778 1414
779 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Home region of {0} is {1} ({2}-{3})", 1415 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Home region of {0} is {1} ({2}-{3})",
@@ -783,13 +1419,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
783 ((Scene)(client.Scene)).RequestTeleportLocation( 1419 ((Scene)(client.Scene)).RequestTeleportLocation(
784 client, regionInfo.RegionHandle, uinfo.HomePosition, uinfo.HomeLookAt, 1420 client, regionInfo.RegionHandle, uinfo.HomePosition, uinfo.HomeLookAt,
785 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); 1421 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome));
1422 return true;
786 } 1423 }
787 else 1424 else
788 { 1425 {
789 m_log.ErrorFormat( 1426 // can't find the Home region: Tell viewer and abort
790 "[ENTITY TRANSFER MODULE]: No grid user information found for {0} {1}. Cannot send home.", 1427 client.SendTeleportFailed("Your home region could not be found.");
791 client.Name, client.AgentId);
792 } 1428 }
1429 return false;
793 } 1430 }
794 1431
795 #endregion 1432 #endregion
@@ -797,230 +1434,112 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
797 1434
798 #region Agent Crossings 1435 #region Agent Crossings
799 1436
800 public bool Cross(ScenePresence agent, bool isFlying) 1437 // Given a position relative to the current region (which has previously been tested to
1438 // see that it is actually outside the current region), find the new region that the
1439 // point is actually in.
1440 // Returns the coordinates and information of the new region or 'null' of it doesn't exist.
1441 public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos,
1442 EntityTransferContext ctx, out Vector3 newpos, out string failureReason)
801 { 1443 {
802 Scene scene = agent.Scene; 1444 newpos = pos;
803 Vector3 pos = agent.AbsolutePosition; 1445 failureReason = string.Empty;
804 Vector3 newpos = new Vector3(pos.X, pos.Y, pos.Z); 1446 string homeURI = scene.GetAgentHomeURI(agentID);
805 uint neighbourx = scene.RegionInfo.RegionLocX;
806 uint neighboury = scene.RegionInfo.RegionLocY;
807 const float boundaryDistance = 1.7f;
808 Vector3 northCross = new Vector3(0, boundaryDistance, 0);
809 Vector3 southCross = new Vector3(0, -1 * boundaryDistance, 0);
810 Vector3 eastCross = new Vector3(boundaryDistance, 0, 0);
811 Vector3 westCross = new Vector3(-1 * boundaryDistance, 0, 0);
812
813 // distance into new region to place avatar
814 const float enterDistance = 0.5f;
815 1447
816 if (scene.TestBorderCross(pos + westCross, Cardinals.W)) 1448// m_log.DebugFormat(
817 { 1449// "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name);
818 if (scene.TestBorderCross(pos + northCross, Cardinals.N))
819 {
820 Border b = scene.GetCrossedBorder(pos + northCross, Cardinals.N);
821 neighboury += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize);
822 }
823 else if (scene.TestBorderCross(pos + southCross, Cardinals.S))
824 {
825 Border b = scene.GetCrossedBorder(pos + southCross, Cardinals.S);
826 if (b.TriggerRegionX == 0 && b.TriggerRegionY == 0)
827 {
828 neighboury--;
829 newpos.Y = Constants.RegionSize - enterDistance;
830 }
831 else
832 {
833 agent.IsInTransit = true;
834
835 neighboury = b.TriggerRegionY;
836 neighbourx = b.TriggerRegionX;
837
838 Vector3 newposition = pos;
839 newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize;
840 newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize;
841 agent.ControllingClient.SendAgentAlertMessage(
842 String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false);
843 InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene);
844 return true;
845 }
846 }
847
848 Border ba = scene.GetCrossedBorder(pos + westCross, Cardinals.W);
849 if (ba.TriggerRegionX == 0 && ba.TriggerRegionY == 0)
850 {
851 neighbourx--;
852 newpos.X = Constants.RegionSize - enterDistance;
853 }
854 else
855 {
856 agent.IsInTransit = true;
857 1450
858 neighboury = ba.TriggerRegionY; 1451 // Compute world location of the object's position
859 neighbourx = ba.TriggerRegionX; 1452 double presenceWorldX = (double)scene.RegionInfo.WorldLocX + pos.X;
1453 double presenceWorldY = (double)scene.RegionInfo.WorldLocY + pos.Y;
860 1454
861 Vector3 newposition = pos; 1455 // Call the grid service to lookup the region containing the new position.
862 newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize; 1456 GridRegion neighbourRegion = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID,
863 newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize; 1457 presenceWorldX, presenceWorldY,
864 agent.ControllingClient.SendAgentAlertMessage( 1458 Math.Max(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY));
865 String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false);
866 InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene);
867 1459
868 return true; 1460 if (neighbourRegion != null)
869 }
870
871 }
872 else if (scene.TestBorderCross(pos + eastCross, Cardinals.E))
873 { 1461 {
874 Border b = scene.GetCrossedBorder(pos + eastCross, Cardinals.E); 1462 // Compute the entity's position relative to the new region
875 neighbourx += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize); 1463 newpos = new Vector3((float)(presenceWorldX - (double)neighbourRegion.RegionLocX),
876 newpos.X = enterDistance; 1464 (float)(presenceWorldY - (double)neighbourRegion.RegionLocY),
1465 pos.Z);
877 1466
878 if (scene.TestBorderCross(pos + southCross, Cardinals.S)) 1467 if (m_bannedRegionCache.IfBanned(neighbourRegion.RegionHandle, agentID))
879 {
880 Border ba = scene.GetCrossedBorder(pos + southCross, Cardinals.S);
881 if (ba.TriggerRegionX == 0 && ba.TriggerRegionY == 0)
882 {
883 neighboury--;
884 newpos.Y = Constants.RegionSize - enterDistance;
885 }
886 else
887 {
888 agent.IsInTransit = true;
889
890 neighboury = ba.TriggerRegionY;
891 neighbourx = ba.TriggerRegionX;
892 Vector3 newposition = pos;
893 newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize;
894 newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize;
895 agent.ControllingClient.SendAgentAlertMessage(
896 String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false);
897 InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene);
898 return true;
899 }
900 }
901 else if (scene.TestBorderCross(pos + northCross, Cardinals.N))
902 { 1468 {
903 Border c = scene.GetCrossedBorder(pos + northCross, Cardinals.N); 1469 failureReason = "Cannot region cross into banned parcel";
904 neighboury += (uint)(int)(c.BorderLine.Z / (int)Constants.RegionSize); 1470 neighbourRegion = null;
905 newpos.Y = enterDistance;
906 }
907 }
908 else if (scene.TestBorderCross(pos + southCross, Cardinals.S))
909 {
910 Border b = scene.GetCrossedBorder(pos + southCross, Cardinals.S);
911 if (b.TriggerRegionX == 0 && b.TriggerRegionY == 0)
912 {
913 neighboury--;
914 newpos.Y = Constants.RegionSize - enterDistance;
915 } 1471 }
916 else 1472 else
917 { 1473 {
918 agent.IsInTransit = true; 1474 // If not banned, make sure this agent is not in the list.
919 1475 m_bannedRegionCache.Remove(neighbourRegion.RegionHandle, agentID);
920 neighboury = b.TriggerRegionY;
921 neighbourx = b.TriggerRegionX;
922 Vector3 newposition = pos;
923 newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize;
924 newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize;
925 agent.ControllingClient.SendAgentAlertMessage(
926 String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false);
927 InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene);
928 return true;
929 } 1476 }
930 }
931 else if (scene.TestBorderCross(pos + northCross, Cardinals.N))
932 {
933 Border b = scene.GetCrossedBorder(pos + northCross, Cardinals.N);
934 neighboury += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize);
935 newpos.Y = enterDistance;
936 }
937
938 /*
939
940 if (pos.X < boundaryDistance) //West
941 {
942 neighbourx--;
943 newpos.X = Constants.RegionSize - enterDistance;
944 }
945 else if (pos.X > Constants.RegionSize - boundaryDistance) // East
946 {
947 neighbourx++;
948 newpos.X = enterDistance;
949 }
950 1477
951 if (pos.Y < boundaryDistance) // South 1478 // Check to see if we have access to the target region.
952 { 1479 if (neighbourRegion != null
953 neighboury--; 1480 && !scene.SimulationService.QueryAccess(neighbourRegion, agentID, homeURI, false, newpos, scene.GetFormatsOffered(), ctx, out failureReason))
954 newpos.Y = Constants.RegionSize - enterDistance;
955 }
956 else if (pos.Y > Constants.RegionSize - boundaryDistance) // North
957 {
958 neighboury++;
959 newpos.Y = enterDistance;
960 }
961 */
962
963 ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize));
964
965 int x = (int)(neighbourx * Constants.RegionSize), y = (int)(neighboury * Constants.RegionSize);
966
967 ExpiringCache<ulong, DateTime> r;
968 DateTime banUntil;
969
970 if (m_bannedRegions.TryGetValue(agent.ControllingClient.AgentId, out r))
971 {
972 if (r.TryGetValue(neighbourHandle, out banUntil))
973 { 1481 {
974 if (DateTime.Now < banUntil) 1482 // remember banned
975 return false; 1483 m_bannedRegionCache.Add(neighbourRegion.RegionHandle, agentID);
976 r.Remove(neighbourHandle); 1484 neighbourRegion = null;
977 } 1485 }
978 } 1486 }
979 else 1487 else
980 { 1488 {
981 r = null; 1489 // The destination region just doesn't exist
1490 failureReason = "Cannot cross into non-existent region";
982 } 1491 }
983 1492
984 GridRegion neighbourRegion = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID, (int)x, (int)y); 1493 if (neighbourRegion == null)
1494 m_log.DebugFormat("{0} GetDestination: region not found. Old region name={1} at <{2},{3}> of size <{4},{5}>. Old pos={6}",
1495 LogHeader, scene.RegionInfo.RegionName,
1496 scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY,
1497 scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY,
1498 pos);
1499 else
1500 m_log.DebugFormat("{0} GetDestination: new region={1} at <{2},{3}> of size <{4},{5}>, newpos=<{6},{7}>",
1501 LogHeader, neighbourRegion.RegionName,
1502 neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY,
1503 newpos.X, newpos.Y);
985 1504
986 string reason; 1505 return neighbourRegion;
987 string version; 1506 }
988 if (!scene.SimulationService.QueryAccess(neighbourRegion, agent.ControllingClient.AgentId, newpos, out version, out reason))
989 {
990 agent.ControllingClient.SendAlertMessage("Cannot region cross into banned parcel");
991 if (r == null)
992 {
993 r = new ExpiringCache<ulong, DateTime>();
994 r.Add(neighbourHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15));
995 1507
996 m_bannedRegions.Add(agent.ControllingClient.AgentId, r, TimeSpan.FromSeconds(45)); 1508 public bool Cross(ScenePresence agent, bool isFlying)
997 } 1509 {
998 else 1510 Vector3 newpos;
999 { 1511 EntityTransferContext ctx = new EntityTransferContext();
1000 r.Add(neighbourHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15)); 1512 string failureReason;
1001 } 1513
1514 GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, agent.AbsolutePosition,
1515 ctx, out newpos, out failureReason);
1516 if (neighbourRegion == null)
1517 {
1518 agent.ControllingClient.SendAlertMessage(failureReason);
1002 return false; 1519 return false;
1003 } 1520 }
1004 1521
1005 agent.IsInTransit = true; 1522 agent.IsInTransit = true;
1006 1523
1007 CrossAgentToNewRegionDelegate d = CrossAgentToNewRegionAsync; 1524 CrossAgentToNewRegionDelegate d = CrossAgentToNewRegionAsync;
1008 d.BeginInvoke(agent, newpos, neighbourx, neighboury, neighbourRegion, isFlying, version, CrossAgentToNewRegionCompleted, d); 1525 d.BeginInvoke(agent, newpos, neighbourRegion, isFlying, ctx, CrossAgentToNewRegionCompleted, d);
1526
1527 Scene.EventManager.TriggerCrossAgentToNewRegion(agent, isFlying, neighbourRegion);
1009 1528
1010 return true; 1529 return true;
1011 } 1530 }
1012 1531
1013 1532
1014 public delegate void InformClientToInitateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY, 1533 public delegate void InformClientToInitiateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY,
1015 Vector3 position, 1534 Vector3 position,
1016 Scene initiatingScene); 1535 Scene initiatingScene);
1017 1536
1018 private void InformClientToInitateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene) 1537 private void InformClientToInitiateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene)
1019 { 1538 {
1020 1539
1021 // This assumes that we know what our neighbours are. 1540 // This assumes that we know what our neighbours are.
1022 1541
1023 InformClientToInitateTeleportToLocationDelegate d = InformClientToInitiateTeleportToLocationAsync; 1542 InformClientToInitiateTeleportToLocationDelegate d = InformClientToInitiateTeleportToLocationAsync;
1024 d.BeginInvoke(agent, regionX, regionY, position, initiatingScene, 1543 d.BeginInvoke(agent, regionX, regionY, position, initiatingScene,
1025 InformClientToInitiateTeleportToLocationCompleted, 1544 InformClientToInitiateTeleportToLocationCompleted,
1026 d); 1545 d);
@@ -1030,16 +1549,24 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1030 Scene initiatingScene) 1549 Scene initiatingScene)
1031 { 1550 {
1032 Thread.Sleep(10000); 1551 Thread.Sleep(10000);
1033 1552
1553 m_log.DebugFormat(
1554 "[ENTITY TRANSFER MODULE]: Auto-reteleporting {0} to correct megaregion location {1},{2},{3} from {4}",
1555 agent.Name, regionX, regionY, position, initiatingScene.Name);
1556
1557 agent.Scene.RequestTeleportLocation(
1558 agent.ControllingClient,
1559 Util.RegionLocToHandle(regionX, regionY),
1560 position,
1561 agent.Lookat,
1562 (uint)Constants.TeleportFlags.ViaLocation);
1563
1564 /*
1034 IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>(); 1565 IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>();
1035 if (im != null) 1566 if (im != null)
1036 { 1567 {
1037 UUID gotoLocation = Util.BuildFakeParcelID( 1568 UUID gotoLocation = Util.BuildFakeParcelID(
1038 Util.UIntsToLong( 1569 Util.RegionLocToHandle(regionX, regionY),
1039 (regionX *
1040 (uint)Constants.RegionSize),
1041 (regionY *
1042 (uint)Constants.RegionSize)),
1043 (uint)(int)position.X, 1570 (uint)(int)position.X,
1044 (uint)(int)position.Y, 1571 (uint)(int)position.Y,
1045 (uint)(int)position.Z); 1572 (uint)(int)position.Z);
@@ -1065,53 +1592,73 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1065 }); 1592 });
1066 1593
1067 } 1594 }
1595 */
1068 } 1596 }
1069 1597
1070 private void InformClientToInitiateTeleportToLocationCompleted(IAsyncResult iar) 1598 private void InformClientToInitiateTeleportToLocationCompleted(IAsyncResult iar)
1071 { 1599 {
1072 InformClientToInitateTeleportToLocationDelegate icon = 1600 InformClientToInitiateTeleportToLocationDelegate icon =
1073 (InformClientToInitateTeleportToLocationDelegate)iar.AsyncState; 1601 (InformClientToInitiateTeleportToLocationDelegate)iar.AsyncState;
1074 icon.EndInvoke(iar); 1602 icon.EndInvoke(iar);
1075 } 1603 }
1076 1604
1077 public delegate ScenePresence CrossAgentToNewRegionDelegate(ScenePresence agent, Vector3 pos, uint neighbourx, uint neighboury, GridRegion neighbourRegion, bool isFlying, string version); 1605 public bool CrossAgentToNewRegionPrep(ScenePresence agent, GridRegion neighbourRegion)
1606 {
1607 if (neighbourRegion == null)
1608 return false;
1609
1610 m_entityTransferStateMachine.SetInTransit(agent.UUID);
1611
1612 agent.RemoveFromPhysicalScene();
1613
1614 return true;
1615 }
1078 1616
1079 /// <summary> 1617 /// <summary>
1080 /// This Closes child agents on neighbouring regions 1618 /// This Closes child agents on neighbouring regions
1081 /// Calls an asynchronous method to do so.. so it doesn't lag the sim. 1619 /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
1082 /// </summary> 1620 /// </summary>
1083 protected ScenePresence CrossAgentToNewRegionAsync( 1621 public ScenePresence CrossAgentToNewRegionAsync(
1084 ScenePresence agent, Vector3 pos, uint neighbourx, uint neighboury, GridRegion neighbourRegion, 1622 ScenePresence agent, Vector3 pos, GridRegion neighbourRegion,
1085 bool isFlying, string version) 1623 bool isFlying, EntityTransferContext ctx)
1086 { 1624 {
1087 if (neighbourRegion == null)
1088 return agent;
1089
1090 try 1625 try
1091 { 1626 {
1092 m_entityTransferStateMachine.SetInTransit(agent.UUID); 1627 m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: new region={1} at <{2},{3}>. newpos={4}",
1628 LogHeader, neighbourRegion.RegionName, neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, pos);
1093 1629
1094 ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize)); 1630 if (!CrossAgentToNewRegionPrep(agent, neighbourRegion))
1095 1631 {
1096 m_log.DebugFormat( 1632 m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: prep failed. Resetting transfer state", LogHeader);
1097 "[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} to {2}-{3} running version {4}", 1633 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1098 agent.Firstname, agent.Lastname, neighbourx, neighboury, version); 1634 }
1099
1100 Scene m_scene = agent.Scene;
1101 1635
1102 if (!agent.ValidateAttachments()) 1636 if (!CrossAgentIntoNewRegionMain(agent, pos, neighbourRegion, isFlying, ctx))
1103 m_log.DebugFormat( 1637 {
1104 "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for region crossing of {0} from {1} to {2}. Continuing.", 1638 m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: cross main failed. Resetting transfer state", LogHeader);
1105 agent.Name, agent.Scene.RegionInfo.RegionName, neighbourRegion.RegionName); 1639 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1640 }
1106 1641
1107 pos = pos + agent.Velocity; 1642 CrossAgentToNewRegionPost(agent, pos, neighbourRegion, isFlying, ctx);
1108 Vector3 vel2 = new Vector3(agent.Velocity.X, agent.Velocity.Y, 0); 1643 }
1644 catch (Exception e)
1645 {
1646 m_log.Error(string.Format("{0}: CrossAgentToNewRegionAsync: failed with exception ", LogHeader), e);
1647 }
1109 1648
1110 agent.RemoveFromPhysicalScene(); 1649 return agent;
1650 }
1111 1651
1652 public bool CrossAgentIntoNewRegionMain(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, bool isFlying, EntityTransferContext ctx)
1653 {
1654 try
1655 {
1112 AgentData cAgent = new AgentData(); 1656 AgentData cAgent = new AgentData();
1113 agent.CopyTo(cAgent); 1657 agent.CopyTo(cAgent);
1658 if (ctx.OutboundVersion < 0.5f)
1659 cAgent.Appearance.PackLegacyWearables = true;
1114 cAgent.Position = pos; 1660 cAgent.Position = pos;
1661
1115 if (isFlying) 1662 if (isFlying)
1116 cAgent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; 1663 cAgent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY;
1117 1664
@@ -1121,102 +1668,121 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1121 // Beyond this point, extra cleanup is needed beyond removing transit state 1668 // Beyond this point, extra cleanup is needed beyond removing transit state
1122 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.Transferring); 1669 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.Transferring);
1123 1670
1124 if (!m_scene.SimulationService.UpdateAgent(neighbourRegion, cAgent)) 1671 if (!agent.Scene.SimulationService.UpdateAgent(neighbourRegion, cAgent))
1125 { 1672 {
1126 // region doesn't take it 1673 // region doesn't take it
1127 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); 1674 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
1128 1675
1676 m_log.WarnFormat(
1677 "[ENTITY TRANSFER MODULE]: Region {0} would not accept update for agent {1} on cross attempt. Returning to original region.",
1678 neighbourRegion.RegionName, agent.Name);
1679
1129 ReInstantiateScripts(agent); 1680 ReInstantiateScripts(agent);
1130 agent.AddToPhysicalScene(isFlying); 1681 agent.AddToPhysicalScene(isFlying);
1131 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1132 1682
1133 return agent; 1683 return false;
1134 } 1684 }
1135 1685
1136 //AgentCircuitData circuitdata = m_controllingClient.RequestClientInfo(); 1686 }
1137 agent.ControllingClient.RequestClientInfo(); 1687 catch (Exception e)
1688 {
1689 m_log.ErrorFormat(
1690 "[ENTITY TRANSFER MODULE]: Problem crossing user {0} to new region {1} from {2}. Exception {3}{4}",
1691 agent.Name, neighbourRegion.RegionName, agent.Scene.RegionInfo.RegionName, e.Message, e.StackTrace);
1692
1693 // TODO: Might be worth attempting other restoration here such as reinstantiation of scripts, etc.
1694 return false;
1695 }
1138 1696
1139 //m_log.Debug("BEFORE CROSS"); 1697 return true;
1140 //Scene.DumpChildrenSeeds(UUID); 1698 }
1141 //DumpKnownRegions();
1142 string agentcaps;
1143 if (!agent.KnownRegions.TryGetValue(neighbourRegion.RegionHandle, out agentcaps))
1144 {
1145 m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: No ENTITY TRANSFER MODULE information for region handle {0}, exiting CrossToNewRegion.",
1146 neighbourRegion.RegionHandle);
1147 return agent;
1148 }
1149 // No turning back
1150 agent.IsChildAgent = true;
1151 1699
1152 string capsPath = neighbourRegion.ServerURI + CapsUtil.GetCapsSeedPath(agentcaps); 1700 public void CrossAgentToNewRegionPost(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion,
1701 bool isFlying, EntityTransferContext ctx)
1702 {
1703 agent.ControllingClient.RequestClientInfo();
1153 1704
1154 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID); 1705 string agentcaps;
1706 if (!agent.KnownRegions.TryGetValue(neighbourRegion.RegionHandle, out agentcaps))
1707 {
1708 m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: No ENTITY TRANSFER MODULE information for region handle {0}, exiting CrossToNewRegion.",
1709 neighbourRegion.RegionHandle);
1710 return;
1711 }
1155 1712
1156 if (m_eqModule != null) 1713 // No turning back
1157 { 1714 agent.IsChildAgent = true;
1158 m_eqModule.CrossRegion( 1715
1159 neighbourHandle, pos, vel2 /* agent.Velocity */, neighbourRegion.ExternalEndPoint, 1716 string capsPath = neighbourRegion.ServerURI + CapsUtil.GetCapsSeedPath(agentcaps);
1160 capsPath, agent.UUID, agent.ControllingClient.SessionId);
1161 }
1162 else
1163 {
1164 agent.ControllingClient.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourRegion.ExternalEndPoint,
1165 capsPath);
1166 }
1167 1717
1168 // SUCCESS! 1718 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID);
1169 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.ReceivedAtDestination);
1170 1719
1171 // Unlike a teleport, here we do not wait for the destination region to confirm the receipt. 1720 Vector3 vel2 = new Vector3(agent.Velocity.X, agent.Velocity.Y, 0);
1172 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
1173 1721
1174 agent.MakeChildAgent(); 1722 if (m_eqModule != null)
1723 {
1724 m_eqModule.CrossRegion(
1725 neighbourRegion.RegionHandle, pos + agent.Velocity, vel2 /* agent.Velocity */,
1726 neighbourRegion.ExternalEndPoint,
1727 capsPath, agent.UUID, agent.ControllingClient.SessionId,
1728 neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY);
1729 }
1730 else
1731 {
1732 m_log.ErrorFormat("{0} Using old CrossRegion packet. Varregion will not work!!", LogHeader);
1733 agent.ControllingClient.CrossRegion(neighbourRegion.RegionHandle, pos + agent.Velocity, agent.Velocity, neighbourRegion.ExternalEndPoint,
1734 capsPath);
1735 }
1175 1736
1176 // FIXME: Possibly this should occur lower down after other commands to close other agents, 1737 // SUCCESS!
1177 // but not sure yet what the side effects would be. 1738 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.ReceivedAtDestination);
1178 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1179 1739
1180 // now we have a child agent in this region. Request all interesting data about other (root) agents 1740 // Unlike a teleport, here we do not wait for the destination region to confirm the receipt.
1181 agent.SendOtherAgentsAvatarDataToMe(); 1741 m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
1182 agent.SendOtherAgentsAppearanceToMe();
1183 1742
1184 // Backwards compatibility. Best effort 1743 agent.MakeChildAgent();
1185 if (version == "Unknown" || version == string.Empty)
1186 {
1187 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: neighbor with old version, passing attachments one by one...");
1188 Thread.Sleep(3000); // wait a little now that we're not waiting for the callback
1189 CrossAttachmentsIntoNewRegion(neighbourRegion, agent, true);
1190 }
1191 1744
1192 // Next, let's close the child agent connections that are too far away. 1745 // FIXME: Possibly this should occur lower down after other commands to close other agents,
1193 agent.CloseChildAgents(neighbourx, neighboury); 1746 // but not sure yet what the side effects would be.
1747 m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
1194 1748
1195 AgentHasMovedAway(agent, false); 1749 // now we have a child agent in this region. Request all interesting data about other (root) agents
1750 agent.SendOtherAgentsAvatarDataToClient();
1751 agent.SendOtherAgentsAppearanceToClient();
1196 1752
1197// // the user may change their profile information in other region, 1753 // TODO: Check since what version this wasn't needed anymore. May be as old as 0.6
1198// // so the userinfo in UserProfileCache is not reliable any more, delete it 1754/*
1199// // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! 1755 // Backwards compatibility. Best effort
1200// if (agent.Scene.NeedSceneCacheClear(agent.UUID)) 1756 if (version == 0f)
1201// {
1202// m_log.DebugFormat(
1203// "[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID);
1204// }
1205
1206 //m_log.Debug("AFTER CROSS");
1207 //Scene.DumpChildrenSeeds(UUID);
1208 //DumpKnownRegions();
1209 }
1210 catch (Exception e)
1211 { 1757 {
1212 m_log.ErrorFormat( 1758 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: neighbor with old version, passing attachments one by one...");
1213 "[ENTITY TRANSFER MODULE]: Problem crossing user {0} to new region {1} from {2}. Exception {3}{4}", 1759 Thread.Sleep(3000); // wait a little now that we're not waiting for the callback
1214 agent.Name, neighbourRegion.RegionName, agent.Scene.RegionInfo.RegionName, e.Message, e.StackTrace); 1760 CrossAttachmentsIntoNewRegion(neighbourRegion, agent, true);
1215
1216 // TODO: Might be worth attempting other restoration here such as reinstantiation of scripts, etc.
1217 } 1761 }
1762*/
1763 // Next, let's close the child agent connections that are too far away.
1764 uint neighbourx;
1765 uint neighboury;
1766 Util.RegionHandleToRegionLoc(neighbourRegion.RegionHandle, out neighbourx, out neighboury);
1218 1767
1219 return agent; 1768 agent.CloseChildAgents(neighbourx, neighboury);
1769
1770 AgentHasMovedAway(agent, false);
1771
1772 // the user may change their profile information in other region,
1773 // so the userinfo in UserProfileCache is not reliable any more, delete it
1774 // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
1775// if (agent.Scene.NeedSceneCacheClear(agent.UUID))
1776// {
1777// m_log.DebugFormat(
1778// "[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID);
1779// }
1780
1781 //m_log.Debug("AFTER CROSS");
1782 //Scene.DumpChildrenSeeds(UUID);
1783 //DumpKnownRegions();
1784
1785 return;
1220 } 1786 }
1221 1787
1222 private void CrossAgentToNewRegionCompleted(IAsyncResult iar) 1788 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
@@ -1256,7 +1822,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1256 agent.InventoryFolder = UUID.Zero; 1822 agent.InventoryFolder = UUID.Zero;
1257 agent.startpos = new Vector3(128, 128, 70); 1823 agent.startpos = new Vector3(128, 128, 70);
1258 agent.child = true; 1824 agent.child = true;
1259 agent.Appearance = sp.Appearance; 1825 agent.Appearance = new AvatarAppearance();
1826 agent.Appearance.PackLegacyWearables = true;
1260 agent.CapsPath = CapsUtil.GetRandomCapsObjectPath(); 1827 agent.CapsPath = CapsUtil.GetRandomCapsObjectPath();
1261 1828
1262 agent.ChildrenCapSeeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID)); 1829 agent.ChildrenCapSeeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID));
@@ -1270,7 +1837,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1270 //foreach (ulong h in agent.ChildrenCapSeeds.Keys) 1837 //foreach (ulong h in agent.ChildrenCapSeeds.Keys)
1271 // m_log.DebugFormat("[XXX] --> {0}", h); 1838 // m_log.DebugFormat("[XXX] --> {0}", h);
1272 //m_log.DebugFormat("[XXX] Adding {0}", region.RegionHandle); 1839 //m_log.DebugFormat("[XXX] Adding {0}", region.RegionHandle);
1273 agent.ChildrenCapSeeds.Add(region.RegionHandle, agent.CapsPath); 1840 if (agent.ChildrenCapSeeds.ContainsKey(region.RegionHandle))
1841 {
1842 m_log.WarnFormat(
1843 "[ENTITY TRANSFER]: Overwriting caps seed {0} with {1} for region {2} (handle {3}) for {4} in {5}",
1844 agent.ChildrenCapSeeds[region.RegionHandle], agent.CapsPath,
1845 region.RegionName, region.RegionHandle, sp.Name, Scene.Name);
1846 }
1847
1848 agent.ChildrenCapSeeds[region.RegionHandle] = agent.CapsPath;
1274 1849
1275 if (sp.Scene.CapsModule != null) 1850 if (sp.Scene.CapsModule != null)
1276 { 1851 {
@@ -1287,10 +1862,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1287 agent.Id0 = currentAgentCircuit.Id0; 1862 agent.Id0 = currentAgentCircuit.Id0;
1288 } 1863 }
1289 1864
1290 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync; 1865 IPEndPoint external = region.ExternalEndPoint;
1291 d.BeginInvoke(sp, agent, region, region.ExternalEndPoint, true, 1866 if (external != null)
1867 {
1868 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
1869 d.BeginInvoke(sp, agent, region, external, true,
1292 InformClientOfNeighbourCompleted, 1870 InformClientOfNeighbourCompleted,
1293 d); 1871 d);
1872 }
1294 } 1873 }
1295 #endregion 1874 #endregion
1296 1875
@@ -1310,7 +1889,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1310 1889
1311 if (m_regionInfo != null) 1890 if (m_regionInfo != null)
1312 { 1891 {
1313 neighbours = RequestNeighbours(sp, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY); 1892 neighbours = GetNeighbours(sp, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY);
1314 } 1893 }
1315 else 1894 else
1316 { 1895 {
@@ -1336,10 +1915,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1336 List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles); 1915 List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles);
1337 List<ulong> oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles); 1916 List<ulong> oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles);
1338 1917
1339 //Dump("Current Neighbors", neighbourHandles); 1918// Dump("Current Neighbors", neighbourHandles);
1340 //Dump("Previous Neighbours", previousRegionNeighbourHandles); 1919// Dump("Previous Neighbours", previousRegionNeighbourHandles);
1341 //Dump("New Neighbours", newRegions); 1920// Dump("New Neighbours", newRegions);
1342 //Dump("Old Neighbours", oldRegions); 1921// Dump("Old Neighbours", oldRegions);
1343 1922
1344 /// Update the scene presence's known regions here on this region 1923 /// Update the scene presence's known regions here on this region
1345 sp.DropOldNeighbours(oldRegions); 1924 sp.DropOldNeighbours(oldRegions);
@@ -1347,8 +1926,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1347 /// Collect as many seeds as possible 1926 /// Collect as many seeds as possible
1348 Dictionary<ulong, string> seeds; 1927 Dictionary<ulong, string> seeds;
1349 if (sp.Scene.CapsModule != null) 1928 if (sp.Scene.CapsModule != null)
1350 seeds 1929 seeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID));
1351 = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID));
1352 else 1930 else
1353 seeds = new Dictionary<ulong, string>(); 1931 seeds = new Dictionary<ulong, string>();
1354 1932
@@ -1368,7 +1946,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1368 agent.InventoryFolder = UUID.Zero; 1946 agent.InventoryFolder = UUID.Zero;
1369 agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, neighbour); 1947 agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, neighbour);
1370 agent.child = true; 1948 agent.child = true;
1371 agent.Appearance = sp.Appearance; 1949 agent.Appearance = new AvatarAppearance();
1950 agent.Appearance.PackLegacyWearables = true;
1372 if (currentAgentCircuit != null) 1951 if (currentAgentCircuit != null)
1373 { 1952 {
1374 agent.ServiceURLs = currentAgentCircuit.ServiceURLs; 1953 agent.ServiceURLs = currentAgentCircuit.ServiceURLs;
@@ -1418,6 +1997,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1418 newAgent = true; 1997 newAgent = true;
1419 else 1998 else
1420 newAgent = false; 1999 newAgent = false;
2000// continue;
1421 2001
1422 if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) 2002 if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle)
1423 { 2003 {
@@ -1464,15 +2044,195 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1464 } 2044 }
1465 } 2045 }
1466 2046
2047 // Computes the difference between two region bases.
2048 // Returns a vector of world coordinates (meters) from base of first region to the second.
2049 // The first region is the home region of the passed scene presence.
1467 Vector3 CalculateOffset(ScenePresence sp, GridRegion neighbour) 2050 Vector3 CalculateOffset(ScenePresence sp, GridRegion neighbour)
1468 { 2051 {
1469 int rRegionX = (int)sp.Scene.RegionInfo.RegionLocX; 2052 /*
1470 int rRegionY = (int)sp.Scene.RegionInfo.RegionLocY; 2053 int rRegionX = (int)sp.Scene.RegionInfo.LegacyRegionLocX;
2054 int rRegionY = (int)sp.Scene.RegionInfo.LegacyRegionLocY;
1471 int tRegionX = neighbour.RegionLocX / (int)Constants.RegionSize; 2055 int tRegionX = neighbour.RegionLocX / (int)Constants.RegionSize;
1472 int tRegionY = neighbour.RegionLocY / (int)Constants.RegionSize; 2056 int tRegionY = neighbour.RegionLocY / (int)Constants.RegionSize;
1473 int shiftx = (rRegionX - tRegionX) * (int)Constants.RegionSize; 2057 int shiftx = (rRegionX - tRegionX) * (int)Constants.RegionSize;
1474 int shifty = (rRegionY - tRegionY) * (int)Constants.RegionSize; 2058 int shifty = (rRegionY - tRegionY) * (int)Constants.RegionSize;
1475 return new Vector3(shiftx, shifty, 0f); 2059 return new Vector3(shiftx, shifty, 0f);
2060 */
2061 return new Vector3( sp.Scene.RegionInfo.WorldLocX - neighbour.RegionLocX,
2062 sp.Scene.RegionInfo.WorldLocY - neighbour.RegionLocY,
2063 0f);
2064 }
2065
2066 public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py)
2067 {
2068 // Since we don't know how big the regions could be, we have to search a very large area
2069 // to find possible regions.
2070 return GetRegionContainingWorldLocation(pGridService, pScopeID, px, py, Constants.MaximumRegionSize);
2071 }
2072
2073 #region NotFoundLocationCache class
2074 // A collection of not found locations to make future lookups 'not found' lookups quick.
2075 // A simple expiring cache that keeps not found locations for some number of seconds.
2076 // A 'not found' location is presumed to be anywhere in the minimum sized region that
2077 // contains that point. A conservitive estimate.
2078 private class NotFoundLocationCache
2079 {
2080 private struct NotFoundLocation
2081 {
2082 public double minX, maxX, minY, maxY;
2083 public DateTime expireTime;
2084 }
2085 private List<NotFoundLocation> m_notFoundLocations = new List<NotFoundLocation>();
2086 public NotFoundLocationCache()
2087 {
2088 }
2089 // Add an area to the list of 'not found' places. The area is the snapped region
2090 // area around the added point.
2091 public void Add(double pX, double pY)
2092 {
2093 lock (m_notFoundLocations)
2094 {
2095 if (!LockedContains(pX, pY))
2096 {
2097 NotFoundLocation nfl = new NotFoundLocation();
2098 // A not found location is not found for at least a whole region sized area
2099 nfl.minX = pX - (pX % (double)Constants.RegionSize);
2100 nfl.minY = pY - (pY % (double)Constants.RegionSize);
2101 nfl.maxX = nfl.minX + (double)Constants.RegionSize;
2102 nfl.maxY = nfl.minY + (double)Constants.RegionSize;
2103 nfl.expireTime = DateTime.Now + TimeSpan.FromSeconds(30);
2104 m_notFoundLocations.Add(nfl);
2105 }
2106 }
2107
2108 }
2109 // Test to see of this point is in any of the 'not found' areas.
2110 // Return 'true' if the point is found inside the 'not found' areas.
2111 public bool Contains(double pX, double pY)
2112 {
2113 bool ret = false;
2114 lock (m_notFoundLocations)
2115 ret = LockedContains(pX, pY);
2116 return ret;
2117 }
2118 private bool LockedContains(double pX, double pY)
2119 {
2120 bool ret = false;
2121 this.DoExpiration();
2122 foreach (NotFoundLocation nfl in m_notFoundLocations)
2123 {
2124 if (pX >= nfl.minX && pX < nfl.maxX && pY >= nfl.minY && pY < nfl.maxY)
2125 {
2126 ret = true;
2127 break;
2128 }
2129 }
2130 return ret;
2131 }
2132 private void DoExpiration()
2133 {
2134 List<NotFoundLocation> m_toRemove = null;
2135 DateTime now = DateTime.Now;
2136 foreach (NotFoundLocation nfl in m_notFoundLocations)
2137 {
2138 if (nfl.expireTime < now)
2139 {
2140 if (m_toRemove == null)
2141 m_toRemove = new List<NotFoundLocation>();
2142 m_toRemove.Add(nfl);
2143 }
2144 }
2145 if (m_toRemove != null)
2146 {
2147 foreach (NotFoundLocation nfl in m_toRemove)
2148 m_notFoundLocations.Remove(nfl);
2149 m_toRemove.Clear();
2150 }
2151 }
2152 }
2153 #endregion // NotFoundLocationCache class
2154 private NotFoundLocationCache m_notFoundLocationCache = new NotFoundLocationCache();
2155
2156 // Given a world position (fractional meter coordinate), get the GridRegion info for
2157 // the region containing that point.
2158 // Someday this should be a method on GridService.
2159 // 'pSizeHint' is the size of the source region but since the destination point can be anywhere
2160 // the size of the target region is unknown thus the search area might have to be very large.
2161 // Return 'null' if no such region exists.
2162 public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID,
2163 double px, double py, uint pSizeHint)
2164 {
2165 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: query, loc=<{1},{2}>", LogHeader, px, py);
2166 GridRegion ret = null;
2167 const double fudge = 2.0;
2168
2169 // One problem with this routine is negative results. That is, this can be called lots of times
2170 // for regions that don't exist. m_notFoundLocationCache remembers 'not found' results so they
2171 // will be quick 'not found's next time.
2172 // NotFoundLocationCache is an expiring cache so it will eventually forget about 'not found' and
2173 // thus re-ask the GridService about the location.
2174 if (m_notFoundLocationCache.Contains(px, py))
2175 {
2176 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found via cache. loc=<{1},{2}>", LogHeader, px, py);
2177 return null;
2178 }
2179
2180 // As an optimization, since most regions will be legacy sized regions (256x256), first try to get
2181 // the region at the appropriate legacy region location.
2182 uint possibleX = (uint)Math.Floor(px);
2183 possibleX -= possibleX % Constants.RegionSize;
2184 uint possibleY = (uint)Math.Floor(py);
2185 possibleY -= possibleY % Constants.RegionSize;
2186 ret = pGridService.GetRegionByPosition(pScopeID, (int)possibleX, (int)possibleY);
2187 if (ret != null)
2188 {
2189 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Found region using legacy size. rloc=<{1},{2}>. Rname={3}",
2190 LogHeader, possibleX, possibleY, ret.RegionName);
2191 }
2192
2193 if (ret == null)
2194 {
2195 // If the simple lookup failed, search the larger area for a region that contains this point
2196 double range = (double)pSizeHint + fudge;
2197 while (ret == null && range <= (Constants.MaximumRegionSize + Constants.RegionSize))
2198 {
2199 // Get from the grid service a list of regions that might contain this point.
2200 // The region origin will be in the zero direction so only subtract the range.
2201 List<GridRegion> possibleRegions = pGridService.GetRegionRange(pScopeID,
2202 (int)(px - range), (int)(px),
2203 (int)(py - range), (int)(py));
2204 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegions cnt={1}, range={2}",
2205 LogHeader, possibleRegions.Count, range);
2206 if (possibleRegions != null && possibleRegions.Count > 0)
2207 {
2208 // If we found some regions, check to see if the point is within
2209 foreach (GridRegion gr in possibleRegions)
2210 {
2211 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegion nm={1}, regionLoc=<{2},{3}>, regionSize=<{4},{5}>",
2212 LogHeader, gr.RegionName, gr.RegionLocX, gr.RegionLocY, gr.RegionSizeX, gr.RegionSizeY);
2213 if (px >= (double)gr.RegionLocX && px < (double)(gr.RegionLocX + gr.RegionSizeX)
2214 && py >= (double)gr.RegionLocY && py < (double)(gr.RegionLocY + gr.RegionSizeY))
2215 {
2216 // Found a region that contains the point
2217 ret = gr;
2218 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: found. RegionName={1}", LogHeader, ret.RegionName);
2219 break;
2220 }
2221 }
2222 }
2223 // Larger search area for next time around if not found
2224 range *= 2;
2225 }
2226 }
2227
2228 if (ret == null)
2229 {
2230 // remember this location was not found so we can quickly not find it next time
2231 m_notFoundLocationCache.Add(px, py);
2232 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found. Remembering loc=<{1},{2}>", LogHeader, px, py);
2233 }
2234
2235 return ret;
1476 } 2236 }
1477 2237
1478 private void InformClientOfNeighbourCompleted(IAsyncResult iar) 2238 private void InformClientOfNeighbourCompleted(IAsyncResult iar)
@@ -1500,7 +2260,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1500 Thread.Sleep(500); 2260 Thread.Sleep(500);
1501 2261
1502 Scene scene = sp.Scene; 2262 Scene scene = sp.Scene;
1503 2263
1504 m_log.DebugFormat( 2264 m_log.DebugFormat(
1505 "[ENTITY TRANSFER MODULE]: Informing {0} {1} about neighbour {2} {3} at ({4},{5})", 2265 "[ENTITY TRANSFER MODULE]: Informing {0} {1} about neighbour {2} {3} at ({4},{5})",
1506 sp.Name, sp.UUID, reg.RegionName, endPoint, reg.RegionCoordX, reg.RegionCoordY); 2266 sp.Name, sp.UUID, reg.RegionName, endPoint, reg.RegionCoordX, reg.RegionCoordY);
@@ -1509,7 +2269,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1509 2269
1510 string reason = String.Empty; 2270 string reason = String.Empty;
1511 2271
1512 bool regionAccepted = scene.SimulationService.CreateAgent(reg, a, (uint)TeleportFlags.Default, out reason); 2272 bool regionAccepted = scene.SimulationService.CreateAgent(null, reg, a, (uint)TeleportFlags.Default, out reason);
1513 2273
1514 if (regionAccepted && newAgent) 2274 if (regionAccepted && newAgent)
1515 { 2275 {
@@ -1523,12 +2283,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1523 } 2283 }
1524 #endregion 2284 #endregion
1525 2285
1526 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: {0} is sending {1} EnableSimulator for neighbour region {2} @ {3} " + 2286 m_log.DebugFormat("{0} {1} is sending {2} EnableSimulator for neighbour region {3}(loc=<{4},{5}>,siz=<{6},{7}>) " +
1527 "and EstablishAgentCommunication with seed cap {4}", 2287 "and EstablishAgentCommunication with seed cap {8}", LogHeader,
1528 scene.RegionInfo.RegionName, sp.Name, reg.RegionName, reg.RegionHandle, capsPath); 2288 scene.RegionInfo.RegionName, sp.Name,
2289 reg.RegionName, reg.RegionLocX, reg.RegionLocY, reg.RegionSizeX, reg.RegionSizeY , capsPath);
1529 2290
1530 m_eqModule.EnableSimulator(reg.RegionHandle, endPoint, sp.UUID); 2291 m_eqModule.EnableSimulator(reg.RegionHandle, endPoint, sp.UUID, reg.RegionSizeX, reg.RegionSizeY);
1531 m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); 2292 m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath, reg.RegionHandle, reg.RegionSizeX, reg.RegionSizeY);
1532 } 2293 }
1533 else 2294 else
1534 { 2295 {
@@ -1546,68 +2307,86 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1546 } 2307 }
1547 2308
1548 /// <summary> 2309 /// <summary>
1549 /// Return the list of regions that are considered to be neighbours to the given scene. 2310 /// Gets the range considered in view of this megaregion (assuming this is a megaregion).
2311 /// </summary>
2312 /// <remarks>Expressed in 256m units</remarks>
2313 /// <param name='swCorner'></param>
2314 /// <param name='neCorner'></param>
2315 private void GetMegaregionViewRange(out Vector2 swCorner, out Vector2 neCorner)
2316 {
2317 Vector2 extent = Vector2.Zero;
2318
2319 if (m_regionCombinerModule != null)
2320 {
2321 Vector2 megaRegionSize = m_regionCombinerModule.GetSizeOfMegaregion(Scene.RegionInfo.RegionID);
2322 extent.X = (float)Util.WorldToRegionLoc((uint)megaRegionSize.X);
2323 extent.Y = (float)Util.WorldToRegionLoc((uint)megaRegionSize.Y);
2324 }
2325
2326 swCorner.X = Scene.RegionInfo.RegionLocX - 1;
2327 swCorner.Y = Scene.RegionInfo.RegionLocY - 1;
2328 neCorner.X = Scene.RegionInfo.RegionLocX + extent.X;
2329 neCorner.Y = Scene.RegionInfo.RegionLocY + extent.Y;
2330 }
2331
2332 /// <summary>
2333 /// Return the list of online regions that are considered to be neighbours to the given scene.
1550 /// </summary> 2334 /// </summary>
1551 /// <param name="pScene"></param> 2335 /// <param name="avatar"></param>
1552 /// <param name="pRegionLocX"></param> 2336 /// <param name="pRegionLocX"></param>
1553 /// <param name="pRegionLocY"></param> 2337 /// <param name="pRegionLocY"></param>
1554 /// <returns></returns> 2338 /// <returns></returns>
1555 protected List<GridRegion> RequestNeighbours(ScenePresence avatar, uint pRegionLocX, uint pRegionLocY) 2339 protected List<GridRegion> GetNeighbours(ScenePresence avatar, uint pRegionLocX, uint pRegionLocY)
1556 { 2340 {
1557 Scene pScene = avatar.Scene; 2341 Scene pScene = avatar.Scene;
1558 RegionInfo m_regionInfo = pScene.RegionInfo; 2342 RegionInfo m_regionInfo = pScene.RegionInfo;
1559 2343 List<GridRegion> neighbours;
1560 Border[] northBorders = pScene.NorthBorders.ToArray();
1561 Border[] southBorders = pScene.SouthBorders.ToArray();
1562 Border[] eastBorders = pScene.EastBorders.ToArray();
1563 Border[] westBorders = pScene.WestBorders.ToArray();
1564 2344
1565 // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't 2345 // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't
1566 // clear what should be done with a "far view" given that megaregions already extended the 2346 // clear what should be done with a "far view" given that megaregions already extended the
1567 // view to include everything in the megaregion 2347 // view to include everything in the megaregion
1568 if (northBorders.Length <= 1 && southBorders.Length <= 1 && eastBorders.Length <= 1 && westBorders.Length <= 1) 2348 if (m_regionCombinerModule == null || !m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID))
1569 { 2349 {
1570 int dd = avatar.DrawDistance < Constants.RegionSize ? (int)Constants.RegionSize : (int)avatar.DrawDistance; 2350 // The area to check is as big as the current region.
1571 2351 // We presume all adjacent regions are the same size as this region.
1572 int startX = (int)pRegionLocX * (int)Constants.RegionSize - dd + (int)(Constants.RegionSize/2); 2352 uint dd = Math.Max((uint)avatar.Scene.DefaultDrawDistance,
1573 int startY = (int)pRegionLocY * (int)Constants.RegionSize - dd + (int)(Constants.RegionSize/2); 2353 Math.Max(Scene.RegionInfo.RegionSizeX, Scene.RegionInfo.RegionSizeY));
1574 2354
1575 int endX = (int)pRegionLocX * (int)Constants.RegionSize + dd + (int)(Constants.RegionSize/2); 2355 uint startX = Util.RegionToWorldLoc(pRegionLocX) - dd + Constants.RegionSize/2;
1576 int endY = (int)pRegionLocY * (int)Constants.RegionSize + dd + (int)(Constants.RegionSize/2); 2356 uint startY = Util.RegionToWorldLoc(pRegionLocY) - dd + Constants.RegionSize/2;
1577 2357
1578 List<GridRegion> neighbours = 2358 uint endX = Util.RegionToWorldLoc(pRegionLocX) + dd + Constants.RegionSize/2;
1579 avatar.Scene.GridService.GetRegionRange(m_regionInfo.ScopeID, startX, endX, startY, endY); 2359 uint endY = Util.RegionToWorldLoc(pRegionLocY) + dd + Constants.RegionSize/2;
1580 2360
1581 neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; }); 2361 neighbours
1582 return neighbours; 2362 = avatar.Scene.GridService.GetRegionRange(
2363 m_regionInfo.ScopeID, (int)startX, (int)endX, (int)startY, (int)endY);
1583 } 2364 }
1584 else 2365 else
1585 { 2366 {
1586 Vector2 extent = Vector2.Zero; 2367 Vector2 swCorner, neCorner;
1587 for (int i = 0; i < eastBorders.Length; i++) 2368 GetMegaregionViewRange(out swCorner, out neCorner);
1588 {
1589 extent.X = (eastBorders[i].BorderLine.Z > extent.X) ? eastBorders[i].BorderLine.Z : extent.X;
1590 }
1591 for (int i = 0; i < northBorders.Length; i++)
1592 {
1593 extent.Y = (northBorders[i].BorderLine.Z > extent.Y) ? northBorders[i].BorderLine.Z : extent.Y;
1594 }
1595 2369
1596 // Loss of fraction on purpose 2370 neighbours
1597 extent.X = ((int)extent.X / (int)Constants.RegionSize) + 1; 2371 = pScene.GridService.GetRegionRange(
1598 extent.Y = ((int)extent.Y / (int)Constants.RegionSize) + 1; 2372 m_regionInfo.ScopeID,
1599 2373 (int)Util.RegionToWorldLoc((uint)swCorner.X), (int)Util.RegionToWorldLoc((uint)neCorner.X),
1600 int startX = (int)(pRegionLocX - 1) * (int)Constants.RegionSize; 2374 (int)Util.RegionToWorldLoc((uint)swCorner.Y), (int)Util.RegionToWorldLoc((uint)neCorner.Y));
1601 int startY = (int)(pRegionLocY - 1) * (int)Constants.RegionSize; 2375 }
1602 2376
1603 int endX = ((int)pRegionLocX + (int)extent.X) * (int)Constants.RegionSize; 2377// neighbours.ForEach(
1604 int endY = ((int)pRegionLocY + (int)extent.Y) * (int)Constants.RegionSize; 2378// n =>
2379// m_log.DebugFormat(
2380// "[ENTITY TRANSFER MODULE]: Region flags for {0} as seen by {1} are {2}",
2381// n.RegionName, Scene.Name, n.RegionFlags != null ? n.RegionFlags.ToString() : "not present"));
1605 2382
1606 List<GridRegion> neighbours = pScene.GridService.GetRegionRange(m_regionInfo.ScopeID, startX, endX, startY, endY); 2383 // The r.RegionFlags == null check only needs to be made for simulators before 2015-01-14 (pre 0.8.1).
1607 neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; }); 2384 neighbours.RemoveAll(
2385 r =>
2386 r.RegionID == m_regionInfo.RegionID
2387 || (r.RegionFlags != null && (r.RegionFlags & OpenSim.Framework.RegionFlags.RegionOnline) == 0));
1608 2388
1609 return neighbours; 2389 return neighbours;
1610 }
1611 } 2390 }
1612 2391
1613 private List<ulong> NewNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours) 2392 private List<ulong> NewNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours)
@@ -1665,10 +2444,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1665 /// Move the given scene object into a new region depending on which region its absolute position has moved 2444 /// Move the given scene object into a new region depending on which region its absolute position has moved
1666 /// into. 2445 /// into.
1667 /// 2446 ///
1668 /// This method locates the new region handle and offsets the prim position for the new region 2447 /// Using the objects new world location, ask the grid service for a the new region and adjust the prim
2448 /// position to be relative to the new region.
1669 /// </summary> 2449 /// </summary>
1670 /// <param name="attemptedPosition">the attempted out of region position of the scene object</param>
1671 /// <param name="grp">the scene object that we're crossing</param> 2450 /// <param name="grp">the scene object that we're crossing</param>
2451 /// <param name="attemptedPosition">the attempted out of region position of the scene object. This position is
2452 /// relative to the region the object currently is in.</param>
2453 /// <param name="silent">if 'true', the deletion of the client from the region is not broadcast to the clients</param>
1672 public void Cross(SceneObjectGroup grp, Vector3 attemptedPosition, bool silent) 2454 public void Cross(SceneObjectGroup grp, Vector3 attemptedPosition, bool silent)
1673 { 2455 {
1674 if (grp == null) 2456 if (grp == null)
@@ -1694,204 +2476,49 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1694 return; 2476 return;
1695 } 2477 }
1696 2478
1697 int thisx = (int)scene.RegionInfo.RegionLocX; 2479 // Remember the old group position in case the region lookup fails so position can be restored.
1698 int thisy = (int)scene.RegionInfo.RegionLocY; 2480 Vector3 oldGroupPosition = grp.RootPart.GroupPosition;
1699 Vector3 EastCross = new Vector3(0.1f, 0, 0);
1700 Vector3 WestCross = new Vector3(-0.1f, 0, 0);
1701 Vector3 NorthCross = new Vector3(0, 0.1f, 0);
1702 Vector3 SouthCross = new Vector3(0, -0.1f, 0);
1703
1704
1705 // use this if no borders were crossed!
1706 ulong newRegionHandle
1707 = Util.UIntsToLong((uint)((thisx) * Constants.RegionSize),
1708 (uint)((thisy) * Constants.RegionSize));
1709
1710 Vector3 pos = attemptedPosition;
1711
1712 int changeX = 1;
1713 int changeY = 1;
1714
1715 if (scene.TestBorderCross(attemptedPosition + WestCross, Cardinals.W))
1716 {
1717 if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
1718 {
1719
1720 Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
1721
1722 if (crossedBorderx.BorderLine.Z > 0)
1723 {
1724 pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
1725 changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize);
1726 }
1727 else
1728 pos.X = ((pos.X + Constants.RegionSize));
1729
1730 Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
1731 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
1732
1733 if (crossedBordery.BorderLine.Z > 0)
1734 {
1735 pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
1736 changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
1737 }
1738 else
1739 pos.Y = ((pos.Y + Constants.RegionSize));
1740
1741
1742
1743 newRegionHandle
1744 = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
1745 (uint)((thisy - changeY) * Constants.RegionSize));
1746 // x - 1
1747 // y - 1
1748 }
1749 else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
1750 {
1751 Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
1752
1753 if (crossedBorderx.BorderLine.Z > 0)
1754 {
1755 pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
1756 changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize);
1757 }
1758 else
1759 pos.X = ((pos.X + Constants.RegionSize));
1760
1761
1762 Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
1763 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
1764
1765 if (crossedBordery.BorderLine.Z > 0)
1766 {
1767 pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
1768 changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
1769 }
1770 else
1771 pos.Y = ((pos.Y + Constants.RegionSize));
1772
1773 newRegionHandle
1774 = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
1775 (uint)((thisy + changeY) * Constants.RegionSize));
1776 // x - 1
1777 // y + 1
1778 }
1779 else
1780 {
1781 Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
1782
1783 if (crossedBorderx.BorderLine.Z > 0)
1784 {
1785 pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
1786 changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize);
1787 }
1788 else
1789 pos.X = ((pos.X + Constants.RegionSize));
1790
1791 newRegionHandle
1792 = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
1793 (uint)(thisy * Constants.RegionSize));
1794 // x - 1
1795 }
1796 }
1797 else if (scene.TestBorderCross(attemptedPosition + EastCross, Cardinals.E))
1798 {
1799 if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
1800 {
1801
1802 pos.X = ((pos.X - Constants.RegionSize));
1803 Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
1804 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
1805
1806 if (crossedBordery.BorderLine.Z > 0)
1807 {
1808 pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
1809 changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
1810 }
1811 else
1812 pos.Y = ((pos.Y + Constants.RegionSize));
1813
1814 2481
1815 newRegionHandle 2482 // Compute the absolute position of the object.
1816 = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize), 2483 double objectWorldLocX = (double)scene.RegionInfo.WorldLocX + attemptedPosition.X;
1817 (uint)((thisy - changeY) * Constants.RegionSize)); 2484 double objectWorldLocY = (double)scene.RegionInfo.WorldLocY + attemptedPosition.Y;
1818 // x + 1
1819 // y - 1
1820 }
1821 else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
1822 {
1823 pos.X = ((pos.X - Constants.RegionSize));
1824 pos.Y = ((pos.Y - Constants.RegionSize));
1825 newRegionHandle
1826 = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize),
1827 (uint)((thisy + changeY) * Constants.RegionSize));
1828 // x + 1
1829 // y + 1
1830 }
1831 else
1832 {
1833 pos.X = ((pos.X - Constants.RegionSize));
1834 newRegionHandle
1835 = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize),
1836 (uint)(thisy * Constants.RegionSize));
1837 // x + 1
1838 }
1839 }
1840 else if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
1841 {
1842 Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
1843 //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
1844 2485
1845 if (crossedBordery.BorderLine.Z > 0) 2486 // Ask the grid service for the region that contains the passed address
1846 { 2487 GridRegion destination = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID,
1847 pos.Y = ((pos.Y + crossedBordery.BorderLine.Z)); 2488 objectWorldLocX, objectWorldLocY);
1848 changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
1849 }
1850 else
1851 pos.Y = ((pos.Y + Constants.RegionSize));
1852 2489
1853 newRegionHandle 2490 Vector3 pos = Vector3.Zero;
1854 = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy - changeY) * Constants.RegionSize)); 2491 if (destination != null)
1855 // y - 1
1856 }
1857 else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
1858 { 2492 {
1859 2493 // Adjust the object's relative position from the old region (attemptedPosition)
1860 pos.Y = ((pos.Y - Constants.RegionSize)); 2494 // to be relative to the new region (pos).
1861 newRegionHandle 2495 pos = new Vector3( (float)(objectWorldLocX - (double)destination.RegionLocX),
1862 = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy + changeY) * Constants.RegionSize)); 2496 (float)(objectWorldLocY - (double)destination.RegionLocY),
1863 // y + 1 2497 attemptedPosition.Z);
1864 } 2498 }
1865 2499
1866 // Offset the positions for the new region across the border
1867 Vector3 oldGroupPosition = grp.RootPart.GroupPosition;
1868
1869 // If we fail to cross the border, then reset the position of the scene object on that border.
1870 uint x = 0, y = 0;
1871 Utils.LongToUInts(newRegionHandle, out x, out y);
1872 GridRegion destination = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID, (int)x, (int)y);
1873
1874 if (destination == null || !CrossPrimGroupIntoNewRegion(destination, pos, grp, silent)) 2500 if (destination == null || !CrossPrimGroupIntoNewRegion(destination, pos, grp, silent))
1875 { 2501 {
1876 m_log.InfoFormat("[ENTITY TRANSFER MODULE] cross region transfer failed for object {0}",grp.UUID); 2502 m_log.InfoFormat("[ENTITY TRANSFER MODULE] cross region transfer failed for object {0}", grp.UUID);
1877 2503
1878 // We are going to move the object back to the old position so long as the old position 2504 // We are going to move the object back to the old position so long as the old position
1879 // is in the region 2505 // is in the region
1880 oldGroupPosition.X = Util.Clamp<float>(oldGroupPosition.X,1.0f,(float)Constants.RegionSize-1); 2506 oldGroupPosition.X = Util.Clamp<float>(oldGroupPosition.X, 1.0f, (float)(scene.RegionInfo.RegionSizeX - 1));
1881 oldGroupPosition.Y = Util.Clamp<float>(oldGroupPosition.Y,1.0f,(float)Constants.RegionSize-1); 2507 oldGroupPosition.Y = Util.Clamp<float>(oldGroupPosition.Y, 1.0f, (float)(scene.RegionInfo.RegionSizeY - 1));
1882 oldGroupPosition.Z = Util.Clamp<float>(oldGroupPosition.Z,1.0f,4096.0f); 2508 oldGroupPosition.Z = Util.Clamp<float>(oldGroupPosition.Z, 1.0f, Constants.RegionHeight);
1883 2509
1884 grp.RootPart.GroupPosition = oldGroupPosition; 2510 grp.AbsolutePosition = oldGroupPosition;
2511 grp.Velocity = Vector3.Zero;
2512 if (grp.RootPart.PhysActor != null)
2513 grp.RootPart.PhysActor.CrossingFailure();
1885 2514
1886 // Need to turn off the physics flags, otherwise the object will continue to attempt to 2515 if (grp.RootPart.KeyframeMotion != null)
1887 // move out of the region creating an infinite loop of failed attempts to cross 2516 grp.RootPart.KeyframeMotion.CrossingFailure();
1888 grp.UpdatePrimFlags(grp.RootPart.LocalId,false,grp.IsTemporary,grp.IsPhantom,false);
1889 2517
1890 grp.ScheduleGroupForFullUpdate(); 2518 grp.ScheduleGroupForFullUpdate();
1891 } 2519 }
1892 } 2520 }
1893 2521
1894
1895 /// <summary> 2522 /// <summary>
1896 /// Move the given scene object into a new region 2523 /// Move the given scene object into a new region
1897 /// </summary> 2524 /// </summary>
@@ -1942,17 +2569,30 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1942 grp, e); 2569 grp, e);
1943 } 2570 }
1944 } 2571 }
2572/*
2573 * done on caller ( not in attachments crossing for now)
1945 else 2574 else
1946 { 2575 {
2576
1947 if (!grp.IsDeleted) 2577 if (!grp.IsDeleted)
1948 { 2578 {
1949 PhysicsActor pa = grp.RootPart.PhysActor; 2579 PhysicsActor pa = grp.RootPart.PhysActor;
1950 if (pa != null) 2580 if (pa != null)
2581 {
1951 pa.CrossingFailure(); 2582 pa.CrossingFailure();
2583 if (grp.RootPart.KeyframeMotion != null)
2584 {
2585 // moved to KeyframeMotion.CrossingFailure
2586// grp.RootPart.Velocity = Vector3.Zero;
2587 grp.RootPart.KeyframeMotion.CrossingFailure();
2588// grp.SendGroupRootTerseUpdate();
2589 }
2590 }
1952 } 2591 }
1953 2592
1954 m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: Prim crossing failed for {0}", grp); 2593 m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: Prim crossing failed for {0}", grp);
1955 } 2594 }
2595 */
1956 } 2596 }
1957 else 2597 else
1958 { 2598 {
@@ -2007,7 +2647,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
2007 2647
2008 public bool IsInTransit(UUID id) 2648 public bool IsInTransit(UUID id)
2009 { 2649 {
2010 return m_entityTransferStateMachine.IsInTransit(id); 2650 return m_entityTransferStateMachine.GetAgentTransferState(id) != null;
2011 } 2651 }
2012 2652
2013 protected void ReInstantiateScripts(ScenePresence sp) 2653 protected void ReInstantiateScripts(ScenePresence sp)
@@ -2036,5 +2676,69 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
2036 } 2676 }
2037 #endregion 2677 #endregion
2038 2678
2679 public virtual bool HandleIncomingSceneObject(SceneObjectGroup so, Vector3 newPosition)
2680 {
2681 // If the user is banned, we won't let any of their objects
2682 // enter. Period.
2683 //
2684 if (Scene.RegionInfo.EstateSettings.IsBanned(so.OwnerID))
2685 {
2686 m_log.DebugFormat(
2687 "[ENTITY TRANSFER MODULE]: Denied prim crossing of {0} {1} into {2} for banned avatar {3}",
2688 so.Name, so.UUID, Scene.Name, so.OwnerID);
2689
2690 return false;
2691 }
2692
2693 if (newPosition != Vector3.Zero)
2694 so.RootPart.GroupPosition = newPosition;
2695
2696 if (!Scene.AddSceneObject(so))
2697 {
2698 m_log.DebugFormat(
2699 "[ENTITY TRANSFER MODULE]: Problem adding scene object {0} {1} into {2} ",
2700 so.Name, so.UUID, Scene.Name);
2701
2702 return false;
2703 }
2704
2705 if (!so.IsAttachment)
2706 {
2707 // FIXME: It would be better to never add the scene object at all rather than add it and then delete
2708 // it
2709 if (!Scene.Permissions.CanObjectEntry(so.UUID, true, so.AbsolutePosition))
2710 {
2711 // Deny non attachments based on parcel settings
2712 //
2713 m_log.Info("[ENTITY TRANSFER MODULE]: Denied prim crossing because of parcel settings");
2714
2715 Scene.DeleteSceneObject(so, false);
2716
2717 return false;
2718 }
2719
2720 // For attachments, we need to wait until the agent is root
2721 // before we restart the scripts, or else some functions won't work.
2722 so.RootPart.ParentGroup.CreateScriptInstances(
2723 0, false, Scene.DefaultScriptEngine, GetStateSource(so));
2724
2725 so.ResumeScripts();
2726
2727 if (so.RootPart.KeyframeMotion != null)
2728 so.RootPart.KeyframeMotion.UpdateSceneObject(so);
2729 }
2730
2731 return true;
2732 }
2733
2734 private int GetStateSource(SceneObjectGroup sog)
2735 {
2736 ScenePresence sp = Scene.GetScenePresence(sog.OwnerID);
2737
2738 if (sp != null)
2739 return sp.GetStateSource();
2740
2741 return 2; // StateSource.PrimCrossing
2742 }
2039 } 2743 }
2040} \ No newline at end of file 2744}
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
index d0cab49..a3109e0 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
@@ -38,7 +38,7 @@ using OpenSim.Framework.Capabilities;
38using OpenSim.Framework.Client; 38using OpenSim.Framework.Client;
39using OpenSim.Region.Framework.Interfaces; 39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
41using OpenSim.Region.Physics.Manager; 41using OpenSim.Region.PhysicsModules.SharedBase;
42using OpenSim.Services.Interfaces; 42using OpenSim.Services.Interfaces;
43using GridRegion = OpenSim.Services.Interfaces.GridRegion; 43using GridRegion = OpenSim.Services.Interfaces.GridRegion;
44 44
@@ -51,10 +51,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
51 /// This is a state machine. 51 /// This is a state machine.
52 /// 52 ///
53 /// [Entry] => Preparing 53 /// [Entry] => Preparing
54 /// Preparing => { Transferring || CleaningUp || [Exit] } 54 /// Preparing => { Transferring || Cancelling || CleaningUp || Aborting || [Exit] }
55 /// Transferring => { ReceivedAtDestination || CleaningUp } 55 /// Transferring => { ReceivedAtDestination || Cancelling || CleaningUp || Aborting }
56 /// ReceivedAtDestination => CleaningUp 56 /// Cancelling => CleaningUp || Aborting
57 /// ReceivedAtDestination => CleaningUp || Aborting
57 /// CleaningUp => [Exit] 58 /// CleaningUp => [Exit]
59 /// Aborting => [Exit]
58 /// 60 ///
59 /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp 61 /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp
60 /// However, any state can transition to CleaningUp if the teleport has failed. 62 /// However, any state can transition to CleaningUp if the teleport has failed.
@@ -64,7 +66,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
64 Preparing, // The agent is being prepared for transfer 66 Preparing, // The agent is being prepared for transfer
65 Transferring, // The agent is in the process of being transferred to a destination 67 Transferring, // The agent is in the process of being transferred to a destination
66 ReceivedAtDestination, // The destination has notified us that the agent has been successfully received 68 ReceivedAtDestination, // The destination has notified us that the agent has been successfully received
67 CleaningUp // The agent is being changed to child/removed after a transfer 69 CleaningUp, // The agent is being changed to child/removed after a transfer
70 Cancelling, // The user has cancelled the teleport but we have yet to act upon this.
71 Aborting // The transfer is aborting. Unlike Cancelling, no compensating actions should be performed
68 } 72 }
69 73
70 /// <summary> 74 /// <summary>
@@ -73,6 +77,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
73 public class EntityTransferStateMachine 77 public class EntityTransferStateMachine
74 { 78 {
75 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 79 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
80 private static readonly string LogHeader = "[ENTITY TRANSFER STATE MACHINE]";
76 81
77 /// <summary> 82 /// <summary>
78 /// If true then on a teleport, the source region waits for a callback from the destination region. If 83 /// If true then on a teleport, the source region waits for a callback from the destination region. If
@@ -96,6 +101,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
96 /// <returns>true if the agent was not already in transit, false if it was</returns> 101 /// <returns>true if the agent was not already in transit, false if it was</returns>
97 internal bool SetInTransit(UUID id) 102 internal bool SetInTransit(UUID id)
98 { 103 {
104 m_log.DebugFormat("{0} SetInTransit. agent={1}, newState=Preparing", LogHeader, id);
99 lock (m_agentsInTransit) 105 lock (m_agentsInTransit)
100 { 106 {
101 if (!m_agentsInTransit.ContainsKey(id)) 107 if (!m_agentsInTransit.ContainsKey(id))
@@ -115,42 +121,117 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
115 /// <param name='newState'></param> 121 /// <param name='newState'></param>
116 /// <returns></returns> 122 /// <returns></returns>
117 /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception> 123 /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception>
118 internal void UpdateInTransit(UUID id, AgentTransferState newState) 124 internal bool UpdateInTransit(UUID id, AgentTransferState newState)
119 { 125 {
126 m_log.DebugFormat("{0} UpdateInTransit. agent={1}, newState={2}", LogHeader, id, newState);
127
128 bool transitionOkay = false;
129
130 // We don't want to throw an exception on cancel since this can come it at any time.
131 bool failIfNotOkay = true;
132
133 // Should be a failure message if failure is not okay.
134 string failureMessage = null;
135
136 AgentTransferState? oldState = null;
137
120 lock (m_agentsInTransit) 138 lock (m_agentsInTransit)
121 { 139 {
122 // Illegal to try and update an agent that's not actually in transit. 140 // Illegal to try and update an agent that's not actually in transit.
123 if (!m_agentsInTransit.ContainsKey(id)) 141 if (!m_agentsInTransit.ContainsKey(id))
124 throw new Exception( 142 {
125 string.Format( 143 if (newState != AgentTransferState.Cancelling && newState != AgentTransferState.Aborting)
126 "Agent with ID {0} is not registered as in transit in {1}", 144 failureMessage = string.Format(
127 id, m_mod.Scene.RegionInfo.RegionName)); 145 "Agent with ID {0} is not registered as in transit in {1}",
128 146 id, m_mod.Scene.RegionInfo.RegionName);
129 AgentTransferState oldState = m_agentsInTransit[id]; 147 else
148 failIfNotOkay = false;
149 }
150 else
151 {
152 oldState = m_agentsInTransit[id];
130 153
131 bool transitionOkay = false; 154 if (newState == AgentTransferState.Aborting)
155 {
156 transitionOkay = true;
157 }
158 else if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp)
159 {
160 transitionOkay = true;
161 }
162 else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing)
163 {
164 transitionOkay = true;
165 }
166 else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring)
167 {
168 transitionOkay = true;
169 }
170 else
171 {
172 if (newState == AgentTransferState.Cancelling
173 && (oldState == AgentTransferState.Preparing || oldState == AgentTransferState.Transferring))
174 {
175 transitionOkay = true;
176 }
177 else
178 {
179 failIfNotOkay = false;
180 }
181 }
132 182
133 if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) 183 if (!transitionOkay)
134 transitionOkay = true; 184 failureMessage
135 else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing) 185 = string.Format(
136 transitionOkay = true; 186 "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}",
137 else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring) 187 id, oldState, newState, m_mod.Scene.RegionInfo.RegionName);
138 transitionOkay = true; 188 }
139 189
140 if (transitionOkay) 190 if (transitionOkay)
191 {
141 m_agentsInTransit[id] = newState; 192 m_agentsInTransit[id] = newState;
142 else 193
143 throw new Exception( 194// m_log.DebugFormat(
144 string.Format( 195// "[ENTITY TRANSFER STATE MACHINE]: Changed agent with id {0} from state {1} to {2} in {3}",
145 "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}", 196// id, oldState, newState, m_mod.Scene.Name);
146 id, oldState, newState, m_mod.Scene.RegionInfo.RegionName)); 197 }
198 else if (failIfNotOkay)
199 {
200 m_log.DebugFormat("{0} UpdateInTransit. Throwing transition failure = {1}", LogHeader, failureMessage);
201 throw new Exception(failureMessage);
202 }
203// else
204// {
205// if (oldState != null)
206// m_log.DebugFormat(
207// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} from state {1} to {2} in {3}",
208// id, oldState, newState, m_mod.Scene.Name);
209// else
210// m_log.DebugFormat(
211// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} to state {1} in {2} since agent not in transit",
212// id, newState, m_mod.Scene.Name);
213// }
147 } 214 }
215
216 return transitionOkay;
148 } 217 }
149 218
150 internal bool IsInTransit(UUID id) 219 /// <summary>
220 /// Gets the current agent transfer state.
221 /// </summary>
222 /// <returns>Null if the agent is not in transit</returns>
223 /// <param name='id'>
224 /// Identifier.
225 /// </param>
226 internal AgentTransferState? GetAgentTransferState(UUID id)
151 { 227 {
152 lock (m_agentsInTransit) 228 lock (m_agentsInTransit)
153 return m_agentsInTransit.ContainsKey(id); 229 {
230 if (!m_agentsInTransit.ContainsKey(id))
231 return null;
232 else
233 return m_agentsInTransit[id];
234 }
154 } 235 }
155 236
156 /// <summary> 237 /// <summary>
@@ -203,14 +284,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
203 284
204 lock (m_agentsInTransit) 285 lock (m_agentsInTransit)
205 { 286 {
206 if (!IsInTransit(id)) 287 AgentTransferState? currentState = GetAgentTransferState(id);
288
289 if (currentState == null)
207 throw new Exception( 290 throw new Exception(
208 string.Format( 291 string.Format(
209 "Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit", 292 "Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit",
210 id, m_mod.Scene.RegionInfo.RegionName)); 293 id, m_mod.Scene.RegionInfo.RegionName));
211 294
212 AgentTransferState currentState = m_agentsInTransit[id];
213
214 if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination) 295 if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination)
215 throw new Exception( 296 throw new Exception(
216 string.Format( 297 string.Format(
@@ -222,8 +303,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
222 303
223 // There should be no race condition here since no other code should be removing the agent transfer or 304 // There should be no race condition here since no other code should be removing the agent transfer or
224 // changing the state to another other than Transferring => ReceivedAtDestination. 305 // changing the state to another other than Transferring => ReceivedAtDestination.
225 while (m_agentsInTransit[id] != AgentTransferState.ReceivedAtDestination && count-- > 0) 306
307 while (count-- > 0)
226 { 308 {
309 lock (m_agentsInTransit)
310 {
311 if (m_agentsInTransit[id] == AgentTransferState.ReceivedAtDestination)
312 break;
313 }
314
227// m_log.Debug(" >>> Waiting... " + count); 315// m_log.Debug(" >>> Waiting... " + count);
228 Thread.Sleep(100); 316 Thread.Sleep(100);
229 } 317 }
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
index b188741..fa23590 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -31,6 +31,7 @@ using System.Reflection;
31 31
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Framework.Client; 33using OpenSim.Framework.Client;
34using OpenSim.Framework.Monitoring;
34using OpenSim.Region.Framework.Interfaces; 35using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Region.Framework.Scenes; 36using OpenSim.Region.Framework.Scenes;
36using OpenSim.Services.Connectors.Hypergrid; 37using OpenSim.Services.Connectors.Hypergrid;
@@ -55,6 +56,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
55 private int m_levelHGTeleport = 0; 56 private int m_levelHGTeleport = 0;
56 57
57 private GatekeeperServiceConnector m_GatekeeperConnector; 58 private GatekeeperServiceConnector m_GatekeeperConnector;
59 private IUserAgentService m_UAS;
58 60
59 protected bool m_RestrictAppearanceAbroad; 61 protected bool m_RestrictAppearanceAbroad;
60 protected string m_AccountName; 62 protected string m_AccountName;
@@ -109,6 +111,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
109 } 111 }
110 } 112 }
111 113
114 /// <summary>
115 /// Used for processing analysis of incoming attachments in a controlled fashion.
116 /// </summary>
117 private JobEngine m_incomingSceneObjectEngine;
118
112 #region ISharedRegionModule 119 #region ISharedRegionModule
113 120
114 public override string Name 121 public override string Name
@@ -152,39 +159,33 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
152 if (m_Enabled) 159 if (m_Enabled)
153 { 160 {
154 scene.RegisterModuleInterface<IUserAgentVerificationModule>(this); 161 scene.RegisterModuleInterface<IUserAgentVerificationModule>(this);
155 scene.EventManager.OnIncomingSceneObject += OnIncomingSceneObject; 162 //scene.EventManager.OnIncomingSceneObject += OnIncomingSceneObject;
156 } 163
157 } 164 m_incomingSceneObjectEngine
158 165 = new JobEngine(
159 void OnIncomingSceneObject(SceneObjectGroup so) 166 string.Format("HG Incoming Scene Object Engine ({0})", scene.Name),
160 { 167 "HG INCOMING SCENE OBJECT ENGINE");
161 if (!so.IsAttachment) 168
162 return; 169 StatsManager.RegisterStat(
163 170 new Stat(
164 if (so.Scene.UserManagementModule.IsLocalGridUser(so.AttachedAvatar)) 171 "HGIncomingAttachmentsWaiting",
165 return; 172 "Number of incoming attachments waiting for processing.",
166 173 "",
167 // foreign user 174 "",
168 AgentCircuitData aCircuit = so.Scene.AuthenticateHandler.GetAgentCircuitData(so.AttachedAvatar); 175 "entitytransfer",
169 if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0) 176 Name,
170 { 177 StatType.Pull,
171 if (aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI")) 178 MeasuresOfInterest.None,
172 { 179 stat => stat.Value = m_incomingSceneObjectEngine.JobsWaiting,
173 string url = aCircuit.ServiceURLs["AssetServerURI"].ToString(); 180 StatVerbosity.Debug));
174 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Incoming attachement {0} for HG user {1} with asset server {2}", so.Name, so.AttachedAvatar, url); 181
175 Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>(); 182 m_incomingSceneObjectEngine.Start();
176 HGUuidGatherer uuidGatherer = new HGUuidGatherer(so.Scene.AssetService, url);
177 uuidGatherer.GatherAssetUuids(so, ids);
178
179 foreach (KeyValuePair<UUID, AssetType> kvp in ids)
180 uuidGatherer.FetchAsset(kvp.Key);
181 }
182 } 183 }
183 } 184 }
184 185
185 protected override void OnNewClient(IClientAPI client) 186 protected override void OnNewClient(IClientAPI client)
186 { 187 {
187 client.OnTeleportHomeRequest += TeleportHome; 188 client.OnTeleportHomeRequest += TriggerTeleportHome;
188 client.OnTeleportLandmarkRequest += RequestTeleportLandmark; 189 client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
189 client.OnConnectionClosed += new Action<IClientAPI>(OnConnectionClosed); 190 client.OnConnectionClosed += new Action<IClientAPI>(OnConnectionClosed);
190 } 191 }
@@ -194,34 +195,44 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
194 base.RegionLoaded(scene); 195 base.RegionLoaded(scene);
195 196
196 if (m_Enabled) 197 if (m_Enabled)
198 {
197 m_GatekeeperConnector = new GatekeeperServiceConnector(scene.AssetService); 199 m_GatekeeperConnector = new GatekeeperServiceConnector(scene.AssetService);
200 m_UAS = scene.RequestModuleInterface<IUserAgentService>();
201 if (m_UAS == null)
202 m_UAS = new UserAgentServiceConnector(m_ThisHomeURI);
203
204 }
198 } 205 }
199 206
200 public override void RemoveRegion(Scene scene) 207 public override void RemoveRegion(Scene scene)
201 { 208 {
202 base.AddRegion(scene); 209 base.RemoveRegion(scene);
203 210
204 if (m_Enabled) 211 if (m_Enabled)
212 {
205 scene.UnregisterModuleInterface<IUserAgentVerificationModule>(this); 213 scene.UnregisterModuleInterface<IUserAgentVerificationModule>(this);
214 m_incomingSceneObjectEngine.Stop();
215 }
206 } 216 }
207 217
208 #endregion 218 #endregion
209 219
210 #region HG overrides of IEntiryTransferModule 220 #region HG overrides of IEntityTransferModule
211 221
212 protected override GridRegion GetFinalDestination(GridRegion region) 222 protected override GridRegion GetFinalDestination(GridRegion region, UUID agentID, string agentHomeURI, out string message)
213 { 223 {
214 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID); 224 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID);
215 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionName, flags); 225 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionName, flags);
226 message = null;
216 227
217 if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0) 228 if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
218 { 229 {
219 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region is hyperlink"); 230 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region is hyperlink");
220 GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID); 231 GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID, agentID, agentHomeURI, out message);
221 if (real_destination != null) 232 if (real_destination != null)
222 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: GetFinalDestination serveruri -> {0}", real_destination.ServerURI); 233 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: GetFinalDestination: ServerURI={0}", real_destination.ServerURI);
223 else 234 else
224 m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: GetHyperlinkRegion to Gatekeeper {0} failed", region.ServerURI); 235 m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: GetHyperlinkRegion of region {0} from Gatekeeper {1} failed: {2}", region.RegionID, region.ServerURI, message);
225 return real_destination; 236 return real_destination;
226 } 237 }
227 238
@@ -272,12 +283,21 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
272 if (agentCircuit.ServiceURLs.ContainsKey("HomeURI")) 283 if (agentCircuit.ServiceURLs.ContainsKey("HomeURI"))
273 { 284 {
274 string userAgentDriver = agentCircuit.ServiceURLs["HomeURI"].ToString(); 285 string userAgentDriver = agentCircuit.ServiceURLs["HomeURI"].ToString();
275 IUserAgentService connector = new UserAgentServiceConnector(userAgentDriver); 286 IUserAgentService connector;
276 bool success = connector.LoginAgentToGrid(agentCircuit, reg, finalDestination, out reason); 287
288 if (userAgentDriver.Equals(m_ThisHomeURI) && m_UAS != null)
289 connector = m_UAS;
290 else
291 connector = new UserAgentServiceConnector(userAgentDriver);
292
293 GridRegion source = new GridRegion(Scene.RegionInfo);
294 source.RawServerURI = m_GatekeeperURI;
295
296 bool success = connector.LoginAgentToGrid(source, agentCircuit, reg, finalDestination, false, out reason);
277 logout = success; // flag for later logout from this grid; this is an HG TP 297 logout = success; // flag for later logout from this grid; this is an HG TP
278 298
279 if (success) 299 if (success)
280 sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout); 300 Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout);
281 301
282 return success; 302 return success;
283 } 303 }
@@ -409,7 +429,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
409 // return base.UpdateAgent(reg, finalDestination, agentData, sp); 429 // return base.UpdateAgent(reg, finalDestination, agentData, sp);
410 //} 430 //}
411 431
412 public override void TeleportHome(UUID id, IClientAPI client) 432 public override void TriggerTeleportHome(UUID id, IClientAPI client)
433 {
434 TeleportHome(id, client);
435 }
436
437 public override bool TeleportHome(UUID id, IClientAPI client)
413 { 438 {
414 m_log.DebugFormat( 439 m_log.DebugFormat(
415 "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId); 440 "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId);
@@ -420,8 +445,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
420 { 445 {
421 // local grid user 446 // local grid user
422 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: User is local"); 447 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: User is local");
423 base.TeleportHome(id, client); 448 return base.TeleportHome(id, client);
424 return;
425 } 449 }
426 450
427 // Foreign user wants to go home 451 // Foreign user wants to go home
@@ -431,17 +455,27 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
431 { 455 {
432 client.SendTeleportFailed("Your information has been lost"); 456 client.SendTeleportFailed("Your information has been lost");
433 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Unable to locate agent's gateway information"); 457 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Unable to locate agent's gateway information");
434 return; 458 return false;
435 } 459 }
436 460
437 IUserAgentService userAgentService = new UserAgentServiceConnector(aCircuit.ServiceURLs["HomeURI"].ToString()); 461 IUserAgentService userAgentService = new UserAgentServiceConnector(aCircuit.ServiceURLs["HomeURI"].ToString());
438 Vector3 position = Vector3.UnitY, lookAt = Vector3.UnitY; 462 Vector3 position = Vector3.UnitY, lookAt = Vector3.UnitY;
439 GridRegion finalDestination = userAgentService.GetHomeRegion(aCircuit.AgentID, out position, out lookAt); 463
464 GridRegion finalDestination = null;
465 try
466 {
467 finalDestination = userAgentService.GetHomeRegion(aCircuit.AgentID, out position, out lookAt);
468 }
469 catch (Exception e)
470 {
471 m_log.Debug("[HG ENTITY TRANSFER MODULE]: GetHomeRegion call failed ", e);
472 }
473
440 if (finalDestination == null) 474 if (finalDestination == null)
441 { 475 {
442 client.SendTeleportFailed("Your home region could not be found"); 476 client.SendTeleportFailed("Your home region could not be found");
443 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent's home region not found"); 477 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent's home region not found");
444 return; 478 return false;
445 } 479 }
446 480
447 ScenePresence sp = ((Scene)(client.Scene)).GetScenePresence(client.AgentId); 481 ScenePresence sp = ((Scene)(client.Scene)).GetScenePresence(client.AgentId);
@@ -449,7 +483,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
449 { 483 {
450 client.SendTeleportFailed("Internal error"); 484 client.SendTeleportFailed("Internal error");
451 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent not found in the scene where it is supposed to be"); 485 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent not found in the scene where it is supposed to be");
452 return; 486 return false;
453 } 487 }
454 488
455 GridRegion homeGatekeeper = MakeRegion(aCircuit); 489 GridRegion homeGatekeeper = MakeRegion(aCircuit);
@@ -460,6 +494,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
460 DoTeleport( 494 DoTeleport(
461 sp, homeGatekeeper, finalDestination, 495 sp, homeGatekeeper, finalDestination,
462 position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); 496 position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome));
497 return true;
463 } 498 }
464 499
465 /// <summary> 500 /// <summary>
@@ -484,35 +519,174 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
484 // Local region? 519 // Local region?
485 if (info != null) 520 if (info != null)
486 { 521 {
487 ((Scene)(remoteClient.Scene)).RequestTeleportLocation(remoteClient, info.RegionHandle, lm.Position, 522 Scene.RequestTeleportLocation(
523 remoteClient, info.RegionHandle, lm.Position,
488 Vector3.Zero, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark)); 524 Vector3.Zero, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark));
489
490 return;
491 } 525 }
492 else 526 else
493 { 527 {
494 // Foreign region 528 // Foreign region
495 Scene scene = (Scene)(remoteClient.Scene);
496 GatekeeperServiceConnector gConn = new GatekeeperServiceConnector(); 529 GatekeeperServiceConnector gConn = new GatekeeperServiceConnector();
497 GridRegion gatekeeper = new GridRegion(); 530 GridRegion gatekeeper = new GridRegion();
498 gatekeeper.ServerURI = lm.Gatekeeper; 531 gatekeeper.ServerURI = lm.Gatekeeper;
499 GridRegion finalDestination = gConn.GetHyperlinkRegion(gatekeeper, new UUID(lm.RegionID)); 532 string homeURI = Scene.GetAgentHomeURI(remoteClient.AgentId);
533
534 string message;
535 GridRegion finalDestination = gConn.GetHyperlinkRegion(gatekeeper, new UUID(lm.RegionID), remoteClient.AgentId, homeURI, out message);
500 536
501 if (finalDestination != null) 537 if (finalDestination != null)
502 { 538 {
503 ScenePresence sp = scene.GetScenePresence(remoteClient.AgentId); 539 ScenePresence sp = Scene.GetScenePresence(remoteClient.AgentId);
504 IEntityTransferModule transferMod = scene.RequestModuleInterface<IEntityTransferModule>();
505 540
506 if (transferMod != null && sp != null) 541 if (sp != null)
507 transferMod.DoTeleport( 542 {
543 if (message != null)
544 sp.ControllingClient.SendAgentAlertMessage(message, true);
545
546 // Validate assorted conditions
547 string reason = string.Empty;
548 if (!ValidateGenericConditions(sp, gatekeeper, finalDestination, 0, out reason))
549 {
550 sp.ControllingClient.SendTeleportFailed(reason);
551 return;
552 }
553
554 DoTeleport(
508 sp, gatekeeper, finalDestination, lm.Position, Vector3.UnitX, 555 sp, gatekeeper, finalDestination, lm.Position, Vector3.UnitX,
509 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark)); 556 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark));
557 }
558 }
559 else
560 {
561 remoteClient.SendTeleportFailed(message);
510 } 562 }
511 563
512 } 564 }
565 }
566
567 private void RemoveIncomingSceneObjectJobs(string commonIdToRemove)
568 {
569 List<JobEngine.Job> jobsToReinsert = new List<JobEngine.Job>();
570 int jobsRemoved = 0;
513 571
514 // can't find the region: Tell viewer and abort 572 JobEngine.Job job;
515 remoteClient.SendTeleportFailed("The teleport destination could not be found."); 573 while ((job = m_incomingSceneObjectEngine.RemoveNextJob()) != null)
574 {
575 if (job.CommonId != commonIdToRemove)
576 jobsToReinsert.Add(job);
577 else
578 jobsRemoved++;
579 }
580
581 m_log.DebugFormat(
582 "[HG ENTITY TRANSFER]: Removing {0} jobs with common ID {1} and reinserting {2} other jobs",
583 jobsRemoved, commonIdToRemove, jobsToReinsert.Count);
584
585 if (jobsToReinsert.Count > 0)
586 {
587 foreach (JobEngine.Job jobToReinsert in jobsToReinsert)
588 m_incomingSceneObjectEngine.QueueJob(jobToReinsert);
589 }
590 }
591
592 public override bool HandleIncomingSceneObject(SceneObjectGroup so, Vector3 newPosition)
593 {
594 // FIXME: We must make it so that we can use SOG.IsAttachment here. At the moment it is always null!
595 if (!so.IsAttachmentCheckFull())
596 return base.HandleIncomingSceneObject(so, newPosition);
597
598 // Equally, we can't use so.AttachedAvatar here.
599 if (so.OwnerID == UUID.Zero || Scene.UserManagementModule.IsLocalGridUser(so.OwnerID))
600 return base.HandleIncomingSceneObject(so, newPosition);
601
602 // foreign user
603 AgentCircuitData aCircuit = Scene.AuthenticateHandler.GetAgentCircuitData(so.OwnerID);
604 if (aCircuit != null)
605 {
606 if ((aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) == 0)
607 {
608 // We have already pulled the necessary attachments from the source grid.
609 base.HandleIncomingSceneObject(so, newPosition);
610 }
611 else
612 {
613 if (aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI"))
614 {
615 m_incomingSceneObjectEngine.QueueJob(
616 string.Format("HG UUID Gather for attachment {0} for {1}", so.Name, aCircuit.Name),
617 () =>
618 {
619 string url = aCircuit.ServiceURLs["AssetServerURI"].ToString();
620 // m_log.DebugFormat(
621 // "[HG ENTITY TRANSFER MODULE]: Incoming attachment {0} for HG user {1} with asset service {2}",
622 // so.Name, so.AttachedAvatar, url);
623
624 IDictionary<UUID, sbyte> ids = new Dictionary<UUID, sbyte>();
625 HGUuidGatherer uuidGatherer
626 = new HGUuidGatherer(Scene.AssetService, url, ids);
627 uuidGatherer.AddForInspection(so);
628
629 while (!uuidGatherer.Complete)
630 {
631 int tickStart = Util.EnvironmentTickCount();
632
633 UUID? nextUuid = uuidGatherer.NextUuidToInspect;
634 uuidGatherer.GatherNext();
635
636 // m_log.DebugFormat(
637 // "[HG ENTITY TRANSFER]: Gathered attachment asset uuid {0} for object {1} for HG user {2} took {3} ms with asset service {4}",
638 // nextUuid, so.Name, so.OwnerID, Util.EnvironmentTickCountSubtract(tickStart), url);
639
640 int ticksElapsed = Util.EnvironmentTickCountSubtract(tickStart);
641
642 if (ticksElapsed > 30000)
643 {
644 m_log.WarnFormat(
645 "[HG ENTITY TRANSFER]: Removing incoming scene object jobs for HG user {0} as gather of {1} from {2} took {3} ms to respond (> {4} ms)",
646 so.OwnerID, so.Name, url, ticksElapsed, 30000);
647
648 RemoveIncomingSceneObjectJobs(so.OwnerID.ToString());
649
650 return;
651 }
652 }
653
654 // m_log.DebugFormat(
655 // "[HG ENTITY TRANSFER]: Fetching {0} assets for attachment {1} for HG user {2} with asset service {3}",
656 // ids.Count, so.Name, so.OwnerID, url);
657
658 foreach (KeyValuePair<UUID, sbyte> kvp in ids)
659 {
660 int tickStart = Util.EnvironmentTickCount();
661
662 uuidGatherer.FetchAsset(kvp.Key);
663
664 int ticksElapsed = Util.EnvironmentTickCountSubtract(tickStart);
665
666 if (ticksElapsed > 30000)
667 {
668 m_log.WarnFormat(
669 "[HG ENTITY TRANSFER]: Removing incoming scene object jobs for HG user {0} as fetch of {1} from {2} took {3} ms to respond (> {4} ms)",
670 so.OwnerID, kvp.Key, url, ticksElapsed, 30000);
671
672 RemoveIncomingSceneObjectJobs(so.OwnerID.ToString());
673
674 return;
675 }
676 }
677
678 base.HandleIncomingSceneObject(so, newPosition);
679
680 // m_log.DebugFormat(
681 // "[HG ENTITY TRANSFER MODULE]: Completed incoming attachment {0} for HG user {1} with asset server {2}",
682 // so.Name, so.OwnerID, url);
683 },
684 so.OwnerID.ToString());
685 }
686 }
687 }
688
689 return true;
516 } 690 }
517 691
518 #endregion 692 #endregion
@@ -549,12 +723,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
549 if (uMan != null && uMan.IsLocalGridUser(obj.AgentId)) 723 if (uMan != null && uMan.IsLocalGridUser(obj.AgentId))
550 { 724 {
551 // local grid user 725 // local grid user
726 m_UAS.LogoutAgent(obj.AgentId, obj.SessionId);
552 return; 727 return;
553 } 728 }
554 729
555 AgentCircuitData aCircuit = ((Scene)(obj.Scene)).AuthenticateHandler.GetAgentCircuitData(obj.CircuitCode); 730 AgentCircuitData aCircuit = ((Scene)(obj.Scene)).AuthenticateHandler.GetAgentCircuitData(obj.CircuitCode);
556 731 if (aCircuit != null && aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("HomeURI"))
557 if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
558 { 732 {
559 string url = aCircuit.ServiceURLs["HomeURI"].ToString(); 733 string url = aCircuit.ServiceURLs["HomeURI"].ToString();
560 IUserAgentService security = new UserAgentServiceConnector(url); 734 IUserAgentService security = new UserAgentServiceConnector(url);
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
index 7871eda..f54298c 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
@@ -35,6 +35,7 @@ using System.Xml;
35using log4net; 35using log4net;
36using OpenMetaverse; 36using OpenMetaverse;
37using OpenSim.Framework; 37using OpenSim.Framework;
38using OpenSim.Framework.Serialization.External;
38 39
39using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
40using OpenSim.Region.Framework.Scenes.Serialization; 41using OpenSim.Region.Framework.Scenes.Serialization;
@@ -73,6 +74,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
73 74
74 private AssetMetadata FetchMetadata(string url, UUID assetID) 75 private AssetMetadata FetchMetadata(string url, UUID assetID)
75 { 76 {
77 if (string.IsNullOrEmpty(url))
78 return null;
79
76 if (!url.EndsWith("/") && !url.EndsWith("=")) 80 if (!url.EndsWith("/") && !url.EndsWith("="))
77 url = url + "/"; 81 url = url + "/";
78 82
@@ -92,6 +96,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
92 AssetBase asset = m_scene.AssetService.Get(assetID.ToString()); 96 AssetBase asset = m_scene.AssetService.Get(assetID.ToString());
93 if (asset == null) 97 if (asset == null)
94 { 98 {
99 if (string.IsNullOrEmpty(url))
100 return null;
101
95 if (!url.EndsWith("/") && !url.EndsWith("=")) 102 if (!url.EndsWith("/") && !url.EndsWith("="))
96 url = url + "/"; 103 url = url + "/";
97 104
@@ -109,45 +116,47 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
109 116
110 public bool PostAsset(string url, AssetBase asset) 117 public bool PostAsset(string url, AssetBase asset)
111 { 118 {
112 if (asset != null) 119 if (string.IsNullOrEmpty(url))
113 { 120 return false;
114 if (!url.EndsWith("/") && !url.EndsWith("="))
115 url = url + "/";
116 121
117 bool success = true; 122 if (!url.EndsWith("/") && !url.EndsWith("="))
118 // See long comment in AssetCache.AddAsset 123 url = url + "/";
119 if (!asset.Temporary || asset.Local)
120 {
121 // We need to copy the asset into a new asset, because
122 // we need to set its ID to be URL+UUID, so that the
123 // HGAssetService dispatches it to the remote grid.
124 // It's not pretty, but the best that can be done while
125 // not having a global naming infrastructure
126 AssetBase asset1 = new AssetBase(asset.FullID, asset.Name, asset.Type, asset.Metadata.CreatorID);
127 Copy(asset, asset1);
128 asset1.ID = url + asset.ID;
129
130 AdjustIdentifiers(asset1.Metadata);
131 if (asset1.Metadata.Type == (sbyte)AssetType.Object)
132 asset1.Data = AdjustIdentifiers(asset.Data);
133 else
134 asset1.Data = asset.Data;
135 124
136 string id = m_scene.AssetService.Store(asset1); 125 if (asset == null)
137 if (id == string.Empty) 126 {
138 { 127 m_log.Warn("[HG ASSET MAPPER]: Tried to post asset to remote server, but asset not in local cache.");
139 m_log.DebugFormat("[HG ASSET MAPPER]: Asset server {0} did not accept {1}", url, asset.ID); 128 return false;
140 success = false;
141 }
142 else
143 m_log.DebugFormat("[HG ASSET MAPPER]: Posted copy of asset {0} from local asset server to {1}", asset1.ID, url);
144 }
145 return success;
146 } 129 }
130
131 // See long comment in AssetCache.AddAsset
132 if (asset.Temporary || asset.Local)
133 return true;
134
135 // We need to copy the asset into a new asset, because
136 // we need to set its ID to be URL+UUID, so that the
137 // HGAssetService dispatches it to the remote grid.
138 // It's not pretty, but the best that can be done while
139 // not having a global naming infrastructure
140 AssetBase asset1 = new AssetBase(asset.FullID, asset.Name, asset.Type, asset.Metadata.CreatorID);
141 Copy(asset, asset1);
142 asset1.ID = url + asset.ID;
143
144 AdjustIdentifiers(asset1.Metadata);
145 if (asset1.Metadata.Type == (sbyte)AssetType.Object)
146 asset1.Data = AdjustIdentifiers(asset.Data);
147 else 147 else
148 m_log.Warn("[HG ASSET MAPPER]: Tried to post asset to remote server, but asset not in local cache."); 148 asset1.Data = asset.Data;
149 149
150 return false; 150 string id = m_scene.AssetService.Store(asset1);
151 if (String.IsNullOrEmpty(id))
152 {
153 m_log.DebugFormat("[HG ASSET MAPPER]: Asset server {0} did not accept {1}", url, asset.ID);
154 return false;
155 }
156 else {
157 m_log.DebugFormat("[HG ASSET MAPPER]: Posted copy of asset {0} from local asset server to {1}", asset1.ID, url);
158 return true;
159 }
151 } 160 }
152 161
153 private void Copy(AssetBase from, AssetBase to) 162 private void Copy(AssetBase from, AssetBase to)
@@ -165,7 +174,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
165 174
166 private void AdjustIdentifiers(AssetMetadata meta) 175 private void AdjustIdentifiers(AssetMetadata meta)
167 { 176 {
168 if (meta.CreatorID != null && meta.CreatorID != string.Empty) 177 if (!string.IsNullOrEmpty(meta.CreatorID))
169 { 178 {
170 UUID uuid = UUID.Zero; 179 UUID uuid = UUID.Zero;
171 UUID.TryParse(meta.CreatorID, out uuid); 180 UUID.TryParse(meta.CreatorID, out uuid);
@@ -181,49 +190,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
181 return Utils.StringToBytes(RewriteSOP(xml)); 190 return Utils.StringToBytes(RewriteSOP(xml));
182 } 191 }
183 192
184 protected string RewriteSOP(string xml) 193 protected string RewriteSOP(string xmlData)
185 { 194 {
186 XmlDocument doc = new XmlDocument(); 195// Console.WriteLine("Input XML [{0}]", xmlData);
187 doc.LoadXml(xml); 196 return ExternalRepresentationUtils.RewriteSOP(xmlData, m_scene.Name, m_HomeURI, m_scene.UserAccountService, m_scene.RegionInfo.ScopeID);
188 XmlNodeList sops = doc.GetElementsByTagName("SceneObjectPart");
189
190 foreach (XmlNode sop in sops)
191 {
192 UserAccount creator = null;
193 bool hasCreatorData = false;
194 XmlNodeList nodes = sop.ChildNodes;
195 foreach (XmlNode node in nodes)
196 {
197 if (node.Name == "CreatorID")
198 {
199 UUID uuid = UUID.Zero;
200 UUID.TryParse(node.InnerText, out uuid);
201 creator = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid);
202 }
203 if (node.Name == "CreatorData" && node.InnerText != null && node.InnerText != string.Empty)
204 hasCreatorData = true;
205
206 //if (node.Name == "OwnerID")
207 //{
208 // UserAccount owner = GetUser(node.InnerText);
209 // if (owner != null)
210 // node.InnerText = m_ProfileServiceURL + "/" + node.InnerText + "/" + owner.FirstName + " " + owner.LastName;
211 //}
212 }
213
214 if (!hasCreatorData && creator != null)
215 {
216 XmlElement creatorData = doc.CreateElement("CreatorData");
217 creatorData.InnerText = m_HomeURI + ";" + creator.FirstName + " " + creator.LastName;
218 sop.AppendChild(creatorData);
219 }
220 }
221
222 using (StringWriter wr = new StringWriter())
223 {
224 doc.Save(wr);
225 return wr.ToString();
226 }
227 197
228 } 198 }
229 199
@@ -251,12 +221,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
251 221
252 // The act of gathering UUIDs downloads some assets from the remote server 222 // The act of gathering UUIDs downloads some assets from the remote server
253 // but not all... 223 // but not all...
254 Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
255 HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL); 224 HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL);
256 uuidGatherer.GatherAssetUuids(assetID, (AssetType)meta.Type, ids); 225 uuidGatherer.AddForInspection(assetID);
257 m_log.DebugFormat("[HG ASSET MAPPER]: Preparing to get {0} assets", ids.Count); 226 uuidGatherer.GatherAll();
227
228 m_log.DebugFormat("[HG ASSET MAPPER]: Preparing to get {0} assets", uuidGatherer.GatheredUuids.Count);
258 bool success = true; 229 bool success = true;
259 foreach (UUID uuid in ids.Keys) 230 foreach (UUID uuid in uuidGatherer.GatheredUuids.Keys)
260 if (FetchAsset(userAssetURL, uuid) == null) 231 if (FetchAsset(userAssetURL, uuid) == null)
261 success = false; 232 success = false;
262 233
@@ -267,39 +238,92 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
267 m_log.DebugFormat("[HG ASSET MAPPER]: Successfully got item {0} from asset server {1}", assetID, userAssetURL); 238 m_log.DebugFormat("[HG ASSET MAPPER]: Successfully got item {0} from asset server {1}", assetID, userAssetURL);
268 } 239 }
269 240
270
271 public void Post(UUID assetID, UUID ownerID, string userAssetURL) 241 public void Post(UUID assetID, UUID ownerID, string userAssetURL)
272 { 242 {
273 // Post the item from the local AssetCache onto the remote asset server 243 m_log.DebugFormat("[HG ASSET MAPPER]: Starting to send asset {0} with children to asset server {1}", assetID, userAssetURL);
274 // and place an entry in m_assetMap 244
245 // Find all the embedded assets
275 246
276 m_log.Debug("[HG ASSET MAPPER]: Posting object " + assetID + " to asset server " + userAssetURL);
277 AssetBase asset = m_scene.AssetService.Get(assetID.ToString()); 247 AssetBase asset = m_scene.AssetService.Get(assetID.ToString());
278 if (asset != null) 248 if (asset == null)
249 {
250 m_log.DebugFormat("[HG ASSET MAPPER]: Something wrong with asset {0}, it could not be found", assetID);
251 return;
252 }
253
254 HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, string.Empty);
255 uuidGatherer.AddForInspection(asset.FullID);
256 uuidGatherer.GatherAll();
257
258 // Check which assets already exist in the destination server
259
260 string url = userAssetURL;
261 if (!url.EndsWith("/") && !url.EndsWith("="))
262 url = url + "/";
263
264 string[] remoteAssetIDs = new string[uuidGatherer.GatheredUuids.Count];
265 int i = 0;
266 foreach (UUID id in uuidGatherer.GatheredUuids.Keys)
267 remoteAssetIDs[i++] = url + id.ToString();
268
269 bool[] exist = m_scene.AssetService.AssetsExist(remoteAssetIDs);
270
271 var existSet = new HashSet<string>();
272 i = 0;
273 foreach (UUID id in uuidGatherer.GatheredUuids.Keys)
274 {
275 if (exist[i])
276 existSet.Add(id.ToString());
277 ++i;
278 }
279
280 // Send only those assets which don't already exist in the destination server
281
282 bool success = true;
283
284 foreach (UUID uuid in uuidGatherer.GatheredUuids.Keys)
279 { 285 {
280 Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>(); 286 if (!existSet.Contains(uuid.ToString()))
281 HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, string.Empty);
282 uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids);
283 bool success = false;
284 foreach (UUID uuid in ids.Keys)
285 { 287 {
286 asset = m_scene.AssetService.Get(uuid.ToString()); 288 asset = m_scene.AssetService.Get(uuid.ToString());
287 if (asset == null) 289 if (asset == null)
290 {
288 m_log.DebugFormat("[HG ASSET MAPPER]: Could not find asset {0}", uuid); 291 m_log.DebugFormat("[HG ASSET MAPPER]: Could not find asset {0}", uuid);
292 }
289 else 293 else
290 success = PostAsset(userAssetURL, asset); 294 {
295 try
296 {
297 success &= PostAsset(userAssetURL, asset);
298 }
299 catch (Exception e)
300 {
301 m_log.Error(
302 string.Format(
303 "[HG ASSET MAPPER]: Failed to post asset {0} (type {1}, length {2}) referenced from {3} to {4} with exception ",
304 asset.ID, asset.Type, asset.Data.Length, assetID, userAssetURL),
305 e);
306
307 // For debugging purposes for now we will continue to throw the exception up the stack as was already happening. However, after
308 // debugging we may want to simply report the failure if we can tell this is due to a failure
309 // with a particular asset and not a destination network failure where all asset posts will fail (and
310 // generate large amounts of log spam).
311 throw e;
312 }
313 }
291 } 314 }
292
293 // maybe all pieces got there...
294 if (!success)
295 m_log.DebugFormat("[HG ASSET MAPPER]: Problems posting item {0} to asset server {1}", assetID, userAssetURL);
296 else 315 else
297 m_log.DebugFormat("[HG ASSET MAPPER]: Successfully posted item {0} to asset server {1}", assetID, userAssetURL); 316 {
298 317 m_log.DebugFormat(
318 "[HG ASSET MAPPER]: Didn't post asset {0} referenced from {1} because it already exists in asset server {2}",
319 uuid, assetID, userAssetURL);
320 }
299 } 321 }
300 else
301 m_log.DebugFormat("[HG ASSET MAPPER]: Something wrong with asset {0}, it could not be found", assetID);
302 322
323 if (!success)
324 m_log.DebugFormat("[HG ASSET MAPPER]: Problems sending asset {0} with children to asset server {1}", assetID, userAssetURL);
325 else
326 m_log.DebugFormat("[HG ASSET MAPPER]: Successfully sent asset {0} with children to asset server {1}", assetID, userAssetURL);
303 } 327 }
304 328
305 #endregion 329 #endregion
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs
index 964efda..582b267 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs
@@ -62,6 +62,17 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
62 private string m_ThisGatekeeper; 62 private string m_ThisGatekeeper;
63 private bool m_RestrictInventoryAccessAbroad; 63 private bool m_RestrictInventoryAccessAbroad;
64 64
65 private bool m_bypassPermissions = true;
66
67 // This simple check makes it possible to support grids in which all the simulators
68 // share all central services of the Robust server EXCEPT assets. In other words,
69 // grids where the simulators' assets are kept in one DB and the users' inventory assets
70 // are kept on another. When users rez items from inventory or take objects from world,
71 // an HG-like asset copy takes place between the 2 servers, the world asset server and
72 // the user's asset server.
73 private bool m_CheckSeparateAssets = false;
74 private string m_LocalAssetsURL = string.Empty;
75
65// private bool m_Initialized = false; 76// private bool m_Initialized = false;
66 77
67 #region INonSharedRegionModule 78 #region INonSharedRegionModule
@@ -88,16 +99,26 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
88 IConfig thisModuleConfig = source.Configs["HGInventoryAccessModule"]; 99 IConfig thisModuleConfig = source.Configs["HGInventoryAccessModule"];
89 if (thisModuleConfig != null) 100 if (thisModuleConfig != null)
90 { 101 {
91 // legacy configuration [obsolete] 102 m_HomeURI = Util.GetConfigVarFromSections<string>(source, "HomeURI",
92 m_HomeURI = thisModuleConfig.GetString("ProfileServerURI", string.Empty); 103 new string[] { "Startup", "Hypergrid", "HGInventoryAccessModule" }, String.Empty);
93 // preferred 104 m_ThisGatekeeper = Util.GetConfigVarFromSections<string>(source, "GatekeeperURI",
94 m_HomeURI = thisModuleConfig.GetString("HomeURI", m_HomeURI); 105 new string[] { "Startup", "Hypergrid", "HGInventoryAccessModule" }, String.Empty);
106 // Legacy. Renove soon!
107 m_ThisGatekeeper = thisModuleConfig.GetString("Gatekeeper", m_ThisGatekeeper);
108
95 m_OutboundPermission = thisModuleConfig.GetBoolean("OutboundPermission", true); 109 m_OutboundPermission = thisModuleConfig.GetBoolean("OutboundPermission", true);
96 m_ThisGatekeeper = thisModuleConfig.GetString("Gatekeeper", string.Empty);
97 m_RestrictInventoryAccessAbroad = thisModuleConfig.GetBoolean("RestrictInventoryAccessAbroad", true); 110 m_RestrictInventoryAccessAbroad = thisModuleConfig.GetBoolean("RestrictInventoryAccessAbroad", true);
111 m_CheckSeparateAssets = thisModuleConfig.GetBoolean("CheckSeparateAssets", false);
112 m_LocalAssetsURL = thisModuleConfig.GetString("RegionHGAssetServerURI", string.Empty);
113 m_LocalAssetsURL = m_LocalAssetsURL.Trim(new char[] { '/' });
114
98 } 115 }
99 else 116 else
100 m_log.Warn("[HG INVENTORY ACCESS MODULE]: HGInventoryAccessModule configs not found. ProfileServerURI not set!"); 117 m_log.Warn("[HG INVENTORY ACCESS MODULE]: HGInventoryAccessModule configs not found. ProfileServerURI not set!");
118
119 m_bypassPermissions = !Util.GetConfigVarFromSections<bool>(source, "serverside_object_permissions",
120 new string[] { "Startup", "Permissions" }, true);
121
101 } 122 }
102 } 123 }
103 } 124 }
@@ -109,9 +130,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
109 130
110 base.AddRegion(scene); 131 base.AddRegion(scene);
111 m_assMapper = new HGAssetMapper(scene, m_HomeURI); 132 m_assMapper = new HGAssetMapper(scene, m_HomeURI);
112 scene.EventManager.OnNewInventoryItemUploadComplete += UploadInventoryItem; 133 scene.EventManager.OnNewInventoryItemUploadComplete += PostInventoryAsset;
113 scene.EventManager.OnTeleportStart += TeleportStart; 134 scene.EventManager.OnTeleportStart += TeleportStart;
114 scene.EventManager.OnTeleportFail += TeleportFail; 135 scene.EventManager.OnTeleportFail += TeleportFail;
136
137 // We're fgoing to enforce some stricter permissions if Outbound is false
138 scene.Permissions.OnTakeObject += CanTakeObject;
139 scene.Permissions.OnTakeCopyObject += CanTakeObject;
140 scene.Permissions.OnTransferUserInventory += OnTransferUserInventory;
115 } 141 }
116 142
117 #endregion 143 #endregion
@@ -133,7 +159,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
133 if (sp is ScenePresence) 159 if (sp is ScenePresence)
134 { 160 {
135 AgentCircuitData aCircuit = ((ScenePresence)sp).Scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId); 161 AgentCircuitData aCircuit = ((ScenePresence)sp).Scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId);
136 if ((aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0) 162 if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0)
137 { 163 {
138 if (m_RestrictInventoryAccessAbroad) 164 if (m_RestrictInventoryAccessAbroad)
139 { 165 {
@@ -183,8 +209,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
183 } 209 }
184 } 210 }
185 211
186 public void UploadInventoryItem(UUID avatarID, UUID assetID, string name, int userlevel) 212 public void PostInventoryAsset(UUID avatarID, AssetType type, UUID assetID, string name, int userlevel)
187 { 213 {
214 if (type == AssetType.Link)
215 return;
216
188 string userAssetServer = string.Empty; 217 string userAssetServer = string.Empty;
189 if (IsForeignUser(avatarID, out userAssetServer) && userAssetServer != string.Empty && m_OutboundPermission) 218 if (IsForeignUser(avatarID, out userAssetServer) && userAssetServer != string.Empty && m_OutboundPermission)
190 { 219 {
@@ -219,18 +248,32 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
219 { 248 {
220 UUID newAssetID = base.CapsUpdateInventoryItemAsset(remoteClient, itemID, data); 249 UUID newAssetID = base.CapsUpdateInventoryItemAsset(remoteClient, itemID, data);
221 250
222 UploadInventoryItem(remoteClient.AgentId, newAssetID, "", 0); 251 PostInventoryAsset(remoteClient.AgentId, AssetType.Unknown, newAssetID, "", 0);
223 252
224 return newAssetID; 253 return newAssetID;
225 } 254 }
226 255
256 ///
257 /// UpdateInventoryItemAsset
258 ///
259 public override bool UpdateInventoryItemAsset(UUID ownerID, InventoryItemBase item, AssetBase asset)
260 {
261 if (base.UpdateInventoryItemAsset(ownerID, item, asset))
262 {
263 PostInventoryAsset(ownerID, (AssetType)asset.Type, asset.FullID, asset.Name, 0);
264 return true;
265 }
266
267 return false;
268 }
269
227 /// 270 ///
228 /// Used in DeleteToInventory 271 /// Used in DeleteToInventory
229 /// 272 ///
230 protected override void ExportAsset(UUID agentID, UUID assetID) 273 protected override void ExportAsset(UUID agentID, UUID assetID)
231 { 274 {
232 if (!assetID.Equals(UUID.Zero)) 275 if (!assetID.Equals(UUID.Zero))
233 UploadInventoryItem(agentID, assetID, "", 0); 276 PostInventoryAsset(agentID, AssetType.Unknown, assetID, "", 0);
234 else 277 else
235 m_log.Debug("[HGScene]: Scene.Inventory did not create asset"); 278 m_log.Debug("[HGScene]: Scene.Inventory did not create asset");
236 } 279 }
@@ -242,7 +285,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
242 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, 285 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
243 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) 286 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment)
244 { 287 {
245 m_log.DebugFormat("[HGScene] RezObject itemID={0} fromTaskID={1}", itemID, fromTaskID); 288 m_log.DebugFormat("[HGScene]: RezObject itemID={0} fromTaskID={1}", itemID, fromTaskID);
246 289
247 //if (fromTaskID.Equals(UUID.Zero)) 290 //if (fromTaskID.Equals(UUID.Zero))
248 //{ 291 //{
@@ -268,50 +311,98 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
268 SceneObjectGroup sog = base.RezObject(remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection, 311 SceneObjectGroup sog = base.RezObject(remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection,
269 RezSelected, RemoveItem, fromTaskID, attachment); 312 RezSelected, RemoveItem, fromTaskID, attachment);
270 313
271 if (sog == null)
272 remoteClient.SendAgentAlertMessage("Unable to rez: problem accessing inventory or locating assets", false);
273
274 return sog; 314 return sog;
275 315
276 } 316 }
277 317
278 public override void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver) 318 public override void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver)
279 { 319 {
280 string userAssetServer = string.Empty; 320 string senderAssetServer = string.Empty;
281 if (IsForeignUser(sender, out userAssetServer) && userAssetServer != string.Empty) 321 string receiverAssetServer = string.Empty;
282 m_assMapper.Get(item.AssetID, sender, userAssetServer); 322 bool isForeignSender, isForeignReceiver;
323 isForeignSender = IsForeignUser(sender, out senderAssetServer);
324 isForeignReceiver = IsForeignUser(receiver, out receiverAssetServer);
325
326 // They're both local. Nothing to do.
327 if (!isForeignSender && !isForeignReceiver)
328 return;
329
330 // At least one of them is foreign.
331 // If both users have the same asset server, no need to transfer the asset
332 if (senderAssetServer.Equals(receiverAssetServer))
333 {
334 m_log.DebugFormat("[HGScene]: Asset transfer between foreign users, but they have the same server. No transfer.");
335 return;
336 }
337
338 if (isForeignSender && senderAssetServer != string.Empty)
339 m_assMapper.Get(item.AssetID, sender, senderAssetServer);
283 340
284 if (IsForeignUser(receiver, out userAssetServer) && userAssetServer != string.Empty && m_OutboundPermission) 341 if (isForeignReceiver && receiverAssetServer != string.Empty && m_OutboundPermission)
285 m_assMapper.Post(item.AssetID, receiver, userAssetServer); 342 m_assMapper.Post(item.AssetID, receiver, receiverAssetServer);
286 } 343 }
287 344
288 public override bool IsForeignUser(UUID userID, out string assetServerURL) 345 public override bool IsForeignUser(UUID userID, out string assetServerURL)
289 { 346 {
290 assetServerURL = string.Empty; 347 assetServerURL = string.Empty;
291 348
292 if (UserManagementModule != null && !UserManagementModule.IsLocalGridUser(userID)) 349 if (UserManagementModule != null)
293 { // foreign 350 {
294 ScenePresence sp = null; 351 if (!m_CheckSeparateAssets)
295 if (m_Scene.TryGetScenePresence(userID, out sp))
296 { 352 {
297 AgentCircuitData aCircuit = m_Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); 353 if (!UserManagementModule.IsLocalGridUser(userID))
298 if (aCircuit.ServiceURLs.ContainsKey("AssetServerURI")) 354 { // foreign
299 { 355 ScenePresence sp = null;
300 assetServerURL = aCircuit.ServiceURLs["AssetServerURI"].ToString(); 356 if (m_Scene.TryGetScenePresence(userID, out sp))
301 assetServerURL = assetServerURL.Trim(new char[] { '/' }); 357 {
358 AgentCircuitData aCircuit = m_Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
359 if (aCircuit != null && aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI"))
360 {
361 assetServerURL = aCircuit.ServiceURLs["AssetServerURI"].ToString();
362 assetServerURL = assetServerURL.Trim(new char[] { '/' });
363 }
364 }
365 else
366 {
367 assetServerURL = UserManagementModule.GetUserServerURL(userID, "AssetServerURI");
368 assetServerURL = assetServerURL.Trim(new char[] { '/' });
369 }
370 return true;
302 } 371 }
303 } 372 }
304 else 373 else
305 { 374 {
306 assetServerURL = UserManagementModule.GetUserServerURL(userID, "AssetServerURI"); 375 if (IsLocalInventoryAssetsUser(userID, out assetServerURL))
307 assetServerURL = assetServerURL.Trim(new char[] { '/' }); 376 {
377 m_log.DebugFormat("[HGScene]: user {0} has local assets {1}", userID, assetServerURL);
378 return false;
379 }
380 else
381 {
382 m_log.DebugFormat("[HGScene]: user {0} has foreign assets {1}", userID, assetServerURL);
383 return true;
384 }
308 } 385 }
309 return true;
310 } 386 }
311
312 return false; 387 return false;
313 } 388 }
314 389
390 private bool IsLocalInventoryAssetsUser(UUID uuid, out string assetsURL)
391 {
392 assetsURL = UserManagementModule.GetUserServerURL(uuid, "AssetServerURI");
393 if (assetsURL == string.Empty)
394 {
395 AgentCircuitData agent = m_Scene.AuthenticateHandler.GetAgentCircuitData(uuid);
396 if (agent != null)
397 {
398 assetsURL = agent.ServiceURLs["AssetServerURI"].ToString();
399 assetsURL = assetsURL.Trim(new char[] { '/' });
400 }
401 }
402 return m_LocalAssetsURL.Equals(assetsURL);
403 }
404
405
315 protected override InventoryItemBase GetItem(UUID agentID, UUID itemID) 406 protected override InventoryItemBase GetItem(UUID agentID, UUID itemID)
316 { 407 {
317 InventoryItemBase item = base.GetItem(agentID, itemID); 408 InventoryItemBase item = base.GetItem(agentID, itemID);
@@ -346,7 +437,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
346 InventoryFolderBase root = m_Scene.InventoryService.GetRootFolder(client.AgentId); 437 InventoryFolderBase root = m_Scene.InventoryService.GetRootFolder(client.AgentId);
347 InventoryCollection content = m_Scene.InventoryService.GetFolderContent(client.AgentId, root.ID); 438 InventoryCollection content = m_Scene.InventoryService.GetFolderContent(client.AgentId, root.ID);
348 439
349 inv.SendBulkUpdateInventory(content.Folders.ToArray(), content.Items.ToArray()); 440 List<InventoryFolderBase> keep = new List<InventoryFolderBase>();
441
442 foreach (InventoryFolderBase f in content.Folders)
443 {
444 if (f.Name != "My Suitcase" && f.Name != "Current Outfit")
445 keep.Add(f);
446 }
447
448 inv.SendBulkUpdateInventory(keep.ToArray(), content.Items.ToArray());
350 } 449 }
351 } 450 }
352 } 451 }
@@ -379,7 +478,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
379 478
380 foreach (InventoryFolderBase f in content.Folders) 479 foreach (InventoryFolderBase f in content.Folders)
381 { 480 {
382 if (f.Name != "My Suitcase") 481 if (f.Name != "My Suitcase" && f.Name != "Current Outfit")
383 { 482 {
384 f.Name = f.Name + " (Unavailable)"; 483 f.Name = f.Name + " (Unavailable)";
385 keep.Add(f); 484 keep.Add(f);
@@ -404,5 +503,36 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
404 } 503 }
405 504
406 #endregion 505 #endregion
506
507 #region Permissions
508
509 private bool CanTakeObject(UUID objectID, UUID stealer, Scene scene)
510 {
511 if (m_bypassPermissions) return true;
512
513 if (!m_OutboundPermission && !UserManagementModule.IsLocalGridUser(stealer))
514 {
515 SceneObjectGroup sog = null;
516 if (m_Scene.TryGetSceneObjectGroup(objectID, out sog) && sog.OwnerID == stealer)
517 return true;
518
519 return false;
520 }
521
522 return true;
523 }
524
525 private bool OnTransferUserInventory(UUID itemID, UUID userID, UUID recipientID)
526 {
527 if (m_bypassPermissions) return true;
528
529 if (!m_OutboundPermission && !UserManagementModule.IsLocalGridUser(recipientID))
530 return false;
531
532 return true;
533 }
534
535
536 #endregion
407 } 537 }
408} \ No newline at end of file 538} \ 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 8b7c16e..5a9efb8 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
@@ -47,6 +47,7 @@ using OpenMetaverse;
47using log4net; 47using log4net;
48using Nini.Config; 48using Nini.Config;
49using Mono.Addins; 49using Mono.Addins;
50using PermissionMask = OpenSim.Framework.PermissionMask;
50 51
51namespace OpenSim.Region.CoreModules.Framework.InventoryAccess 52namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
52{ 53{
@@ -202,7 +203,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
202 m_Scene.AssetService.Store(asset); 203 m_Scene.AssetService.Store(asset);
203 m_Scene.CreateNewInventoryItem( 204 m_Scene.CreateNewInventoryItem(
204 remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID, 205 remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID,
205 name, description, 0, callbackID, asset, invType, nextOwnerMask, creationDate); 206 name, description, 0, callbackID, asset.FullID, asset.Type, invType, nextOwnerMask, creationDate);
206 } 207 }
207 else 208 else
208 { 209 {
@@ -259,7 +260,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
259 return UUID.Zero; 260 return UUID.Zero;
260 } 261 }
261 262
262 remoteClient.SendAgentAlertMessage("Notecard saved", false); 263 remoteClient.SendAlertMessage("Notecard saved");
263 } 264 }
264 else if ((InventoryType)item.InvType == InventoryType.LSL) 265 else if ((InventoryType)item.InvType == InventoryType.LSL)
265 { 266 {
@@ -269,7 +270,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
269 return UUID.Zero; 270 return UUID.Zero;
270 } 271 }
271 272
272 remoteClient.SendAgentAlertMessage("Script saved", false); 273 remoteClient.SendAlertMessage("Script saved");
273 } 274 }
274 275
275 AssetBase asset = 276 AssetBase asset =
@@ -291,7 +292,34 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
291 292
292 return UUID.Zero; 293 return UUID.Zero;
293 } 294 }
294 295
296 public virtual bool UpdateInventoryItemAsset(UUID ownerID, InventoryItemBase item, AssetBase asset)
297 {
298 if (item != null && item.Owner == ownerID && asset != null)
299 {
300// m_log.DebugFormat(
301// "[INVENTORY ACCESS MODULE]: Updating item {0} {1} with new asset {2}",
302// item.Name, item.ID, asset.ID);
303
304 item.AssetID = asset.FullID;
305 item.Description = asset.Description;
306 item.Name = asset.Name;
307 item.AssetType = asset.Type;
308 item.InvType = (int)InventoryType.Object;
309
310 m_Scene.AssetService.Store(asset);
311 m_Scene.InventoryService.UpdateItem(item);
312
313 return true;
314 }
315 else
316 {
317 m_log.ErrorFormat("[INVENTORY ACCESS MODULE]: Given invalid item for inventory update: {0}",
318 (item == null || asset == null? "null item or asset" : "wrong owner"));
319 return false;
320 }
321 }
322
295 public virtual List<InventoryItemBase> CopyToInventory( 323 public virtual List<InventoryItemBase> CopyToInventory(
296 DeRezAction action, UUID folderID, 324 DeRezAction action, UUID folderID,
297 List<SceneObjectGroup> objectGroups, IClientAPI remoteClient, bool asAttachment) 325 List<SceneObjectGroup> objectGroups, IClientAPI remoteClient, bool asAttachment)
@@ -352,23 +380,32 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
352 bool asAttachment) 380 bool asAttachment)
353 { 381 {
354 CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); 382 CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero);
355 Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>(); 383// Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>();
384
385 Dictionary<SceneObjectGroup, KeyframeMotion> group2Keyframe = new Dictionary<SceneObjectGroup, KeyframeMotion>();
356 386
357 foreach (SceneObjectGroup objectGroup in objlist) 387 foreach (SceneObjectGroup objectGroup in objlist)
358 { 388 {
359 Vector3 inventoryStoredPosition = new Vector3 389 if (objectGroup.RootPart.KeyframeMotion != null)
360 (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize) 390 {
361 ? 250 391 objectGroup.RootPart.KeyframeMotion.Pause();
362 : objectGroup.AbsolutePosition.X) 392 group2Keyframe.Add(objectGroup, objectGroup.RootPart.KeyframeMotion);
363 , 393 objectGroup.RootPart.KeyframeMotion = null;
364 (objectGroup.AbsolutePosition.Y > (int)Constants.RegionSize) 394 }
365 ? 250
366 : objectGroup.AbsolutePosition.Y,
367 objectGroup.AbsolutePosition.Z);
368
369 originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition;
370 395
371 objectGroup.AbsolutePosition = inventoryStoredPosition; 396// Vector3 inventoryStoredPosition = new Vector3
397// (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize)
398// ? 250
399// : objectGroup.AbsolutePosition.X)
400// ,
401// (objectGroup.AbsolutePosition.Y > (int)Constants.RegionSize)
402// ? 250
403// : objectGroup.AbsolutePosition.Y,
404// objectGroup.AbsolutePosition.Z);
405//
406// originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition;
407//
408// objectGroup.AbsolutePosition = inventoryStoredPosition;
372 409
373 // Make sure all bits but the ones we want are clear 410 // Make sure all bits but the ones we want are clear
374 // on take. 411 // on take.
@@ -377,7 +414,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
377 objectGroup.RootPart.NextOwnerMask &= 414 objectGroup.RootPart.NextOwnerMask &=
378 ((uint)PermissionMask.Copy | 415 ((uint)PermissionMask.Copy |
379 (uint)PermissionMask.Transfer | 416 (uint)PermissionMask.Transfer |
380 (uint)PermissionMask.Modify); 417 (uint)PermissionMask.Modify |
418 (uint)PermissionMask.Export);
381 objectGroup.RootPart.NextOwnerMask |= 419 objectGroup.RootPart.NextOwnerMask |=
382 (uint)PermissionMask.Move; 420 (uint)PermissionMask.Move;
383 421
@@ -395,9 +433,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
395 else 433 else
396 itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment); 434 itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment);
397 435
398 // Restore the position of each group now that it has been stored to inventory. 436// // Restore the position of each group now that it has been stored to inventory.
399 foreach (SceneObjectGroup objectGroup in objlist) 437// foreach (SceneObjectGroup objectGroup in objlist)
400 objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; 438// objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID];
401 439
402 InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); 440 InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID);
403 441
@@ -407,17 +445,28 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
407 445
408 if (item == null) 446 if (item == null)
409 return null; 447 return null;
448
449 item.CreatorId = objlist[0].RootPart.CreatorID.ToString();
450 item.CreatorData = objlist[0].RootPart.CreatorData;
410 451
411 // Can't know creator is the same, so null it in inventory
412 if (objlist.Count > 1) 452 if (objlist.Count > 1)
413 { 453 {
414 item.CreatorId = UUID.Zero.ToString();
415 item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems; 454 item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems;
455
456 // If the objects have different creators then don't specify a creator at all
457 foreach (SceneObjectGroup objectGroup in objlist)
458 {
459 if ((objectGroup.RootPart.CreatorID.ToString() != item.CreatorId)
460 || (objectGroup.RootPart.CreatorData.ToString() != item.CreatorData))
461 {
462 item.CreatorId = UUID.Zero.ToString();
463 item.CreatorData = string.Empty;
464 break;
465 }
466 }
416 } 467 }
417 else 468 else
418 { 469 {
419 item.CreatorId = objlist[0].RootPart.CreatorID.ToString();
420 item.CreatorData = objlist[0].RootPart.CreatorData;
421 item.SaleType = objlist[0].RootPart.ObjectSaleType; 470 item.SaleType = objlist[0].RootPart.ObjectSaleType;
422 item.SalePrice = objlist[0].RootPart.SalePrice; 471 item.SalePrice = objlist[0].RootPart.SalePrice;
423 } 472 }
@@ -438,13 +487,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
438 } 487 }
439 else 488 else
440 { 489 {
441 AddPermissions(item, objlist[0], objlist, remoteClient);
442
443 item.CreationDate = Util.UnixTimeSinceEpoch(); 490 item.CreationDate = Util.UnixTimeSinceEpoch();
444 item.Description = asset.Description; 491 item.Description = asset.Description;
445 item.Name = asset.Name; 492 item.Name = asset.Name;
446 item.AssetType = asset.Type; 493 item.AssetType = asset.Type;
447 494
495 AddPermissions(item, objlist[0], objlist, remoteClient);
496
448 m_Scene.AddInventoryItem(item); 497 m_Scene.AddInventoryItem(item);
449 498
450 if (remoteClient != null && item.Owner == remoteClient.AgentId) 499 if (remoteClient != null && item.Owner == remoteClient.AgentId)
@@ -461,6 +510,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
461 } 510 }
462 } 511 }
463 512
513 // Restore KeyframeMotion
514 foreach (SceneObjectGroup objectGroup in group2Keyframe.Keys)
515 {
516 objectGroup.RootPart.KeyframeMotion = group2Keyframe[objectGroup];
517 objectGroup.RootPart.KeyframeMotion.Start();
518 }
519
464 // This is a hook to do some per-asset post-processing for subclasses that need that 520 // This is a hook to do some per-asset post-processing for subclasses that need that
465 if (remoteClient != null) 521 if (remoteClient != null)
466 ExportAsset(remoteClient.AgentId, asset.FullID); 522 ExportAsset(remoteClient.AgentId, asset.FullID);
@@ -485,49 +541,65 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
485 InventoryItemBase item, SceneObjectGroup so, List<SceneObjectGroup> objsForEffectivePermissions, 541 InventoryItemBase item, SceneObjectGroup so, List<SceneObjectGroup> objsForEffectivePermissions,
486 IClientAPI remoteClient) 542 IClientAPI remoteClient)
487 { 543 {
488 uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move) | 7; 544 uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move | PermissionMask.Export) | 7;
545 uint allObjectsNextOwnerPerms = 0x7fffffff;
546 uint allObjectsEveryOnePerms = 0x7fffffff;
547 uint allObjectsGroupPerms = 0x7fffffff;
548
489 foreach (SceneObjectGroup grp in objsForEffectivePermissions) 549 foreach (SceneObjectGroup grp in objsForEffectivePermissions)
550 {
490 effectivePerms &= grp.GetEffectivePermissions(); 551 effectivePerms &= grp.GetEffectivePermissions();
552 allObjectsNextOwnerPerms &= grp.RootPart.NextOwnerMask;
553 allObjectsEveryOnePerms &= grp.RootPart.EveryoneMask;
554 allObjectsGroupPerms &= grp.RootPart.GroupMask;
555 }
491 effectivePerms |= (uint)PermissionMask.Move; 556 effectivePerms |= (uint)PermissionMask.Move;
492 557
558 //PermissionsUtil.LogPermissions(item.Name, "Before AddPermissions", item.BasePermissions, item.CurrentPermissions, item.NextPermissions);
559
493 if (remoteClient != null && (remoteClient.AgentId != so.RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions()) 560 if (remoteClient != null && (remoteClient.AgentId != so.RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions())
494 { 561 {
562 // Changing ownership, so apply the "Next Owner" permissions to all of the
563 // inventory item's permissions.
564
495 uint perms = effectivePerms; 565 uint perms = effectivePerms;
496 uint nextPerms = (perms & 7) << 13; 566 PermissionsUtil.ApplyFoldedPermissions(effectivePerms, ref perms);
497 if ((nextPerms & (uint)PermissionMask.Copy) == 0) 567
498 perms &= ~(uint)PermissionMask.Copy; 568 item.BasePermissions = perms & allObjectsNextOwnerPerms;
499 if ((nextPerms & (uint)PermissionMask.Transfer) == 0)
500 perms &= ~(uint)PermissionMask.Transfer;
501 if ((nextPerms & (uint)PermissionMask.Modify) == 0)
502 perms &= ~(uint)PermissionMask.Modify;
503
504 item.BasePermissions = perms & so.RootPart.NextOwnerMask;
505 item.CurrentPermissions = item.BasePermissions; 569 item.CurrentPermissions = item.BasePermissions;
506 item.NextPermissions = perms & so.RootPart.NextOwnerMask; 570 item.NextPermissions = perms & allObjectsNextOwnerPerms;
507 item.EveryOnePermissions = so.RootPart.EveryoneMask & so.RootPart.NextOwnerMask; 571 item.EveryOnePermissions = allObjectsEveryOnePerms & allObjectsNextOwnerPerms;
508 item.GroupPermissions = so.RootPart.GroupMask & so.RootPart.NextOwnerMask; 572 item.GroupPermissions = allObjectsGroupPerms & allObjectsNextOwnerPerms;
509 573
510 // Magic number badness. Maybe this deserves an enum. 574 // apply next owner perms on rez
511 // bit 4 (16) is the "Slam" bit, it means treat as passed 575 item.CurrentPermissions |= SceneObjectGroup.SLAM;
512 // and apply next owner perms on rez
513 item.CurrentPermissions |= 16; // Slam!
514 } 576 }
515 else 577 else
516 { 578 {
579 // Not changing ownership.
580 // In this case we apply the permissions in the object's items ONLY to the inventory
581 // item's "Next Owner" permissions, but NOT to its "Current", "Base", etc. permissions.
582 // E.g., if the object contains a No-Transfer item then the item's "Next Owner"
583 // permissions are also No-Transfer.
584 PermissionsUtil.ApplyFoldedPermissions(effectivePerms, ref allObjectsNextOwnerPerms);
585
517 item.BasePermissions = effectivePerms; 586 item.BasePermissions = effectivePerms;
518 item.CurrentPermissions = effectivePerms; 587 item.CurrentPermissions = effectivePerms;
519 item.NextPermissions = so.RootPart.NextOwnerMask & effectivePerms; 588 item.NextPermissions = allObjectsNextOwnerPerms & effectivePerms;
520 item.EveryOnePermissions = so.RootPart.EveryoneMask & effectivePerms; 589 item.EveryOnePermissions = allObjectsEveryOnePerms & effectivePerms;
521 item.GroupPermissions = so.RootPart.GroupMask & effectivePerms; 590 item.GroupPermissions = allObjectsGroupPerms & effectivePerms;
522 591
523 item.CurrentPermissions &= 592 item.CurrentPermissions &=
524 ((uint)PermissionMask.Copy | 593 ((uint)PermissionMask.Copy |
525 (uint)PermissionMask.Transfer | 594 (uint)PermissionMask.Transfer |
526 (uint)PermissionMask.Modify | 595 (uint)PermissionMask.Modify |
527 (uint)PermissionMask.Move | 596 (uint)PermissionMask.Move |
597 (uint)PermissionMask.Export |
528 7); // Preserve folded permissions 598 7); // Preserve folded permissions
529 } 599 }
530 600
601 //PermissionsUtil.LogPermissions(item.Name, "After AddPermissions", item.BasePermissions, item.CurrentPermissions, item.NextPermissions);
602
531 return item; 603 return item;
532 } 604 }
533 605
@@ -542,6 +614,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
542 protected InventoryItemBase CreateItemForObject( 614 protected InventoryItemBase CreateItemForObject(
543 DeRezAction action, IClientAPI remoteClient, SceneObjectGroup so, UUID folderID) 615 DeRezAction action, IClientAPI remoteClient, SceneObjectGroup so, UUID folderID)
544 { 616 {
617// m_log.DebugFormat(
618// "[BASIC INVENTORY ACCESS MODULE]: Creating item for object {0} {1} for folder {2}, action {3}",
619// so.Name, so.UUID, folderID, action);
620//
545 // Get the user info of the item destination 621 // Get the user info of the item destination
546 // 622 //
547 UUID userID = UUID.Zero; 623 UUID userID = UUID.Zero;
@@ -619,18 +695,18 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
619 if (remoteClient == null || 695 if (remoteClient == null ||
620 so.OwnerID != remoteClient.AgentId) 696 so.OwnerID != remoteClient.AgentId)
621 { 697 {
622 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); 698 folder = m_Scene.InventoryService.GetFolderForType(userID, FolderType.LostAndFound);
623 } 699 }
624 else 700 else
625 { 701 {
626 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder); 702 folder = m_Scene.InventoryService.GetFolderForType(userID, FolderType.Trash);
627 } 703 }
628 } 704 }
629 else if (action == DeRezAction.Return) 705 else if (action == DeRezAction.Return)
630 { 706 {
631 // Dump to lost + found unconditionally 707 // Dump to lost + found unconditionally
632 // 708 //
633 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); 709 folder = m_Scene.InventoryService.GetFolderForType(userID, FolderType.LostAndFound);
634 } 710 }
635 711
636 if (folderID == UUID.Zero && folder == null) 712 if (folderID == UUID.Zero && folder == null)
@@ -639,21 +715,22 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
639 { 715 {
640 // Deletes go to trash by default 716 // Deletes go to trash by default
641 // 717 //
642 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder); 718 folder = m_Scene.InventoryService.GetFolderForType(userID, FolderType.Trash);
643 } 719 }
644 else 720 else
645 { 721 {
646 if (remoteClient == null || so.OwnerID != remoteClient.AgentId) 722 if (remoteClient == null || so.RootPart.OwnerID != remoteClient.AgentId)
647 { 723 {
648 // Taking copy of another person's item. Take to 724 // Taking copy of another person's item. Take to
649 // Objects folder. 725 // Objects folder.
650 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object); 726 folder = m_Scene.InventoryService.GetFolderForType(userID, FolderType.Object);
727 so.FromFolderID = UUID.Zero;
651 } 728 }
652 else 729 else
653 { 730 {
654 // Catch all. Use lost & found 731 // Catch all. Use lost & found
655 // 732 //
656 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); 733 folder = m_Scene.InventoryService.GetFolderForType(userID, FolderType.LostAndFound);
657 } 734 }
658 } 735 }
659 } 736 }
@@ -663,10 +740,16 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
663 // 740 //
664 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy) 741 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy)
665 { 742 {
666 if (so.FromFolderID != UUID.Zero && userID == remoteClient.AgentId) 743 if (so.FromFolderID != UUID.Zero && so.RootPart.OwnerID == remoteClient.AgentId)
667 { 744 {
668 InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID); 745 InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID);
669 folder = m_Scene.InventoryService.GetFolder(f); 746 folder = m_Scene.InventoryService.GetFolder(f);
747
748 if(folder.Type == 14 || folder.Type == 16)
749 {
750 // folder.Type = 6;
751 folder = m_Scene.InventoryService.GetFolderForType(userID, FolderType.Object);
752 }
670 } 753 }
671 } 754 }
672 755
@@ -722,7 +805,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
722 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, 805 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
723 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) 806 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment)
724 { 807 {
725 AssetBase rezAsset = m_Scene.AssetService.Get(assetID.ToString()); 808 AssetBase rezAsset = m_Scene.AssetService.Get(assetID.ToString());
726 809
727 if (rezAsset == null) 810 if (rezAsset == null)
728 { 811 {
@@ -731,12 +814,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
731 m_log.WarnFormat( 814 m_log.WarnFormat(
732 "[InventoryAccessModule]: Could not find asset {0} for item {1} {2} for {3} in RezObject()", 815 "[InventoryAccessModule]: Could not find asset {0} for item {1} {2} for {3} in RezObject()",
733 assetID, item.Name, item.ID, remoteClient.Name); 816 assetID, item.Name, item.ID, remoteClient.Name);
817 remoteClient.SendAgentAlertMessage(string.Format("Unable to rez: could not find asset {0} for item {1}.", assetID, item.Name), false);
734 } 818 }
735 else 819 else
736 { 820 {
737 m_log.WarnFormat( 821 m_log.WarnFormat(
738 "[INVENTORY ACCESS MODULE]: Could not find asset {0} for {1} in RezObject()", 822 "[INVENTORY ACCESS MODULE]: Could not find asset {0} for {1} in RezObject()",
739 assetID, remoteClient.Name); 823 assetID, remoteClient.Name);
824 remoteClient.SendAgentAlertMessage(string.Format("Unable to rez: could not find asset {0}.", assetID), false);
740 } 825 }
741 826
742 return null; 827 return null;
@@ -744,67 +829,34 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
744 829
745 SceneObjectGroup group = null; 830 SceneObjectGroup group = null;
746 831
747 string xmlData = Utils.BytesToString(rezAsset.Data); 832 List<SceneObjectGroup> objlist;
748 List<SceneObjectGroup> objlist = new List<SceneObjectGroup>(); 833 List<Vector3> veclist;
749 List<Vector3> veclist = new List<Vector3>(); 834 Vector3 bbox;
835 float offsetHeight;
750 byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0); 836 byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0);
751 Vector3 pos; 837 Vector3 pos;
752 838
753 XmlDocument doc = new XmlDocument(); 839 bool single
754 doc.LoadXml(xmlData); 840 = m_Scene.GetObjectsToRez(
755 XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject"); 841 rezAsset.Data, attachment, out objlist, out veclist, out bbox, out offsetHeight);
756 if (e == null || attachment) // Single
757 {
758 SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
759
760 objlist.Add(g);
761 veclist.Add(new Vector3(0, 0, 0));
762 842
763 float offsetHeight = 0; 843 if (single)
844 {
764 pos = m_Scene.GetNewRezLocation( 845 pos = m_Scene.GetNewRezLocation(
765 RayStart, RayEnd, RayTargetID, Quaternion.Identity, 846 RayStart, RayEnd, RayTargetID, Quaternion.Identity,
766 BypassRayCast, bRayEndIsIntersection, true, g.GetAxisAlignedBoundingBox(out offsetHeight), false); 847 BypassRayCast, bRayEndIsIntersection, true, bbox, false);
767 pos.Z += offsetHeight; 848 pos.Z += offsetHeight;
768 } 849 }
769 else 850 else
770 { 851 {
771 XmlElement coll = (XmlElement)e;
772 float bx = Convert.ToSingle(coll.GetAttribute("x"));
773 float by = Convert.ToSingle(coll.GetAttribute("y"));
774 float bz = Convert.ToSingle(coll.GetAttribute("z"));
775 Vector3 bbox = new Vector3(bx, by, bz);
776
777 pos = m_Scene.GetNewRezLocation(RayStart, RayEnd, 852 pos = m_Scene.GetNewRezLocation(RayStart, RayEnd,
778 RayTargetID, Quaternion.Identity, 853 RayTargetID, Quaternion.Identity,
779 BypassRayCast, bRayEndIsIntersection, true, 854 BypassRayCast, bRayEndIsIntersection, true,
780 bbox, false); 855 bbox, false);
781
782 pos -= bbox / 2; 856 pos -= bbox / 2;
783
784 XmlNodeList groups = e.SelectNodes("SceneObjectGroup");
785 foreach (XmlNode n in groups)
786 {
787 SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(n.OuterXml);
788
789 objlist.Add(g);
790 XmlElement el = (XmlElement)n;
791
792 string rawX = el.GetAttribute("offsetx");
793 string rawY = el.GetAttribute("offsety");
794 string rawZ = el.GetAttribute("offsetz");
795//
796// m_log.DebugFormat(
797// "[INVENTORY ACCESS MODULE]: Converting coalesced object {0} offset <{1}, {2}, {3}>",
798// g.Name, rawX, rawY, rawZ);
799
800 float x = Convert.ToSingle(rawX);
801 float y = Convert.ToSingle(rawY);
802 float z = Convert.ToSingle(rawZ);
803 veclist.Add(new Vector3(x, y, z));
804 }
805 } 857 }
806 858
807 if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, attachment)) 859 if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, veclist, attachment))
808 return null; 860 return null;
809 861
810 for (int i = 0; i < objlist.Count; i++) 862 for (int i = 0; i < objlist.Count; i++)
@@ -823,11 +875,23 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
823 m_log.Debug("[INVENTORY ACCESS MODULE]: Object has UUID.Zero! Position 3"); 875 m_log.Debug("[INVENTORY ACCESS MODULE]: Object has UUID.Zero! Position 3");
824 } 876 }
825 877
826 foreach (SceneObjectPart part in group.Parts) 878 // if this was previously an attachment and is now being rezzed,
879 // save the old attachment info.
880 if (group.IsAttachment == false && group.RootPart.Shape.State != 0)
827 { 881 {
828 // Make the rezzer the owner, as this is not necessarily set correctly in the serialized asset. 882 group.RootPart.AttachedPos = group.AbsolutePosition;
829 part.LastOwnerID = part.OwnerID; 883 group.RootPart.Shape.LastAttachPoint = (byte)group.AttachmentPoint;
830 part.OwnerID = remoteClient.AgentId; 884 }
885
886 if (item == null)
887 {
888 // Change ownership. Normally this is done in DoPreRezWhenFromItem(), but in this case we must do it here.
889 foreach (SceneObjectPart part in group.Parts)
890 {
891 // Make the rezzer the owner, as this is not necessarily set correctly in the serialized asset.
892 part.LastOwnerID = part.OwnerID;
893 part.OwnerID = remoteClient.AgentId;
894 }
831 } 895 }
832 896
833 if (!attachment) 897 if (!attachment)
@@ -855,7 +919,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
855 // one full update during the attachment 919 // one full update during the attachment
856 // process causes some clients to fail to display the 920 // process causes some clients to fail to display the
857 // attachment properly. 921 // attachment properly.
858 m_Scene.AddNewSceneObject(group, true, false); 922 m_Scene.AddNewSceneObject(group, !attachment, false);
859 923
860 // if attachment we set it's asset id so object updates 924 // if attachment we set it's asset id so object updates
861 // can reflect that, if not, we set it's position in world. 925 // can reflect that, if not, we set it's position in world.
@@ -902,10 +966,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
902 /// <param name="item"></param> 966 /// <param name="item"></param>
903 /// <param name="objlist"></param> 967 /// <param name="objlist"></param>
904 /// <param name="pos"></param> 968 /// <param name="pos"></param>
969 /// <param name="veclist">
970 /// List of vector position adjustments for a coalesced objects. For ordinary objects
971 /// this list will contain just Vector3.Zero. The order of adjustments must match the order of objlist
972 /// </param>
905 /// <param name="isAttachment"></param> 973 /// <param name="isAttachment"></param>
906 /// <returns>true if we can processed with rezzing, false if we need to abort</returns> 974 /// <returns>true if we can processed with rezzing, false if we need to abort</returns>
907 private bool DoPreRezWhenFromItem( 975 private bool DoPreRezWhenFromItem(
908 IClientAPI remoteClient, InventoryItemBase item, List<SceneObjectGroup> objlist, Vector3 pos, bool isAttachment) 976 IClientAPI remoteClient, InventoryItemBase item, List<SceneObjectGroup> objlist,
977 Vector3 pos, List<Vector3> veclist, bool isAttachment)
909 { 978 {
910 UUID fromUserInventoryItemId = UUID.Zero; 979 UUID fromUserInventoryItemId = UUID.Zero;
911 980
@@ -928,28 +997,29 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
928 } 997 }
929 } 998 }
930 999
931 int primcount = 0; 1000 for (int i = 0; i < objlist.Count; i++)
932 foreach (SceneObjectGroup g in objlist)
933 primcount += g.PrimCount;
934
935 if (!m_Scene.Permissions.CanRezObject(
936 primcount, remoteClient.AgentId, pos)
937 && !isAttachment)
938 { 1001 {
939 // The client operates in no fail mode. It will 1002 SceneObjectGroup g = objlist[i];
940 // have already removed the item from the folder
941 // if it's no copy.
942 // Put it back if it's not an attachment
943 //
944 if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment))
945 remoteClient.SendBulkUpdateInventory(item);
946 1003
947 ILandObject land = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y); 1004 if (!m_Scene.Permissions.CanRezObject(
948 remoteClient.SendAlertMessage(string.Format( 1005 g.PrimCount, remoteClient.AgentId, pos + veclist[i])
949 "Can't rez object '{0}' at <{1:F3}, {2:F3}, {3:F3}> on parcel '{4}' in region {5}.", 1006 && !isAttachment)
950 item.Name, pos.X, pos.Y, pos.Z, land != null ? land.LandData.Name : "Unknown", m_Scene.RegionInfo.RegionName)); 1007 {
1008 // The client operates in no fail mode. It will
1009 // have already removed the item from the folder
1010 // if it's no copy.
1011 // Put it back if it's not an attachment
1012 //
1013 if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment))
1014 remoteClient.SendBulkUpdateInventory(item);
951 1015
952 return false; 1016 ILandObject land = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y);
1017 remoteClient.SendAlertMessage(string.Format(
1018 "Can't rez object '{0}' at <{1:F3}, {2:F3}, {3:F3}> on parcel '{4}' in region {5}.",
1019 item.Name, pos.X, pos.Y, pos.Z, land != null ? land.LandData.Name : "Unknown", m_Scene.Name));
1020
1021 return false;
1022 }
953 } 1023 }
954 1024
955 for (int i = 0; i < objlist.Count; i++) 1025 for (int i = 0; i < objlist.Count; i++)
@@ -977,44 +1047,19 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
977// "[INVENTORY ACCESS MODULE]: rootPart.OwnedID {0}, item.Owner {1}, item.CurrentPermissions {2:X}", 1047// "[INVENTORY ACCESS MODULE]: rootPart.OwnedID {0}, item.Owner {1}, item.CurrentPermissions {2:X}",
978// rootPart.OwnerID, item.Owner, item.CurrentPermissions); 1048// rootPart.OwnerID, item.Owner, item.CurrentPermissions);
979 1049
980 if ((rootPart.OwnerID != item.Owner) || 1050 if ((rootPart.OwnerID != item.Owner) || (item.CurrentPermissions & SceneObjectGroup.SLAM) != 0)
981 (item.CurrentPermissions & 16) != 0)
982 { 1051 {
983 //Need to kill the for sale here 1052 //Need to kill the for sale here
984 rootPart.ObjectSaleType = 0; 1053 rootPart.ObjectSaleType = 0;
985 rootPart.SalePrice = 10; 1054 rootPart.SalePrice = 10;
986
987 if (m_Scene.Permissions.PropagatePermissions())
988 {
989 foreach (SceneObjectPart part in so.Parts)
990 {
991 if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
992 {
993 part.EveryoneMask = item.EveryOnePermissions;
994 part.NextOwnerMask = item.NextPermissions;
995 }
996 part.GroupMask = 0; // DO NOT propagate here
997 }
998
999 so.ApplyNextOwnerPermissions();
1000 }
1001 } 1055 }
1002 1056
1003 foreach (SceneObjectPart part in so.Parts) 1057 foreach (SceneObjectPart part in so.Parts)
1004 { 1058 {
1005 part.FromUserInventoryItemID = fromUserInventoryItemId; 1059 part.FromUserInventoryItemID = fromUserInventoryItemId;
1006 1060 part.ApplyPermissionsOnRez(item, true, m_Scene);
1007 if ((part.OwnerID != item.Owner) ||
1008 (item.CurrentPermissions & 16) != 0)
1009 {
1010 part.Inventory.ChangeInventoryOwner(item.Owner);
1011 part.GroupMask = 0; // DO NOT propagate here
1012 }
1013
1014 part.EveryoneMask = item.EveryOnePermissions;
1015 part.NextOwnerMask = item.NextPermissions;
1016 } 1061 }
1017 1062
1018 rootPart.TrimPermissions(); 1063 rootPart.TrimPermissions();
1019 1064
1020 if (isAttachment) 1065 if (isAttachment)
@@ -1150,4 +1195,4 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
1150 1195
1151 #endregion 1196 #endregion
1152 } 1197 }
1153} \ No newline at end of file 1198}
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs
new file mode 100644
index 0000000..007ff63
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs
@@ -0,0 +1,146 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Threading;
30using System.Xml;
31using Nini.Config;
32using NUnit.Framework;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.CoreModules.Framework.InventoryAccess;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Region.ScriptEngine.XEngine;
38using OpenSim.Services.Interfaces;
39using OpenSim.Tests.Common;
40
41namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests
42{
43 [TestFixture]
44 public class HGAssetMapperTests : OpenSimTestCase
45 {
46 [Test]
47 public void TestPostAssetRewrite()
48 {
49 TestHelpers.InMethod();
50// TestHelpers.EnableLogging();
51
52 XEngine xengine = new OpenSim.Region.ScriptEngine.XEngine.XEngine();
53 xengine.DebugLevel = 1;
54
55 IniConfigSource configSource = new IniConfigSource();
56
57 IConfig startupConfig = configSource.AddConfig("Startup");
58 startupConfig.Set("DefaultScriptEngine", "XEngine");
59
60 IConfig xEngineConfig = configSource.AddConfig("XEngine");
61 xEngineConfig.Set("Enabled", "true");
62 xEngineConfig.Set("StartDelay", "0");
63 xEngineConfig.Set("AppDomainLoading", "false");
64
65 string homeUrl = "http://hg.HomeTestPostAssetRewriteGrid.com";
66 string foreignUrl = "http://hg.ForeignTestPostAssetRewriteGrid.com";
67 int soIdTail = 0x1;
68 UUID assetId = TestHelpers.ParseTail(0x10);
69 UUID userId = TestHelpers.ParseTail(0x100);
70 UUID sceneId = TestHelpers.ParseTail(0x1000);
71 string userFirstName = "TestPostAsset";
72 string userLastName = "Rewrite";
73 int soPartsCount = 3;
74
75 Scene scene = new SceneHelpers().SetupScene("TestPostAssetRewriteScene", sceneId, 1000, 1000, configSource);
76 SceneHelpers.SetupSceneModules(scene, configSource, xengine);
77 scene.StartScripts();
78
79 HGAssetMapper hgam = new HGAssetMapper(scene, homeUrl);
80 UserAccount ua
81 = UserAccountHelpers.CreateUserWithInventory(scene, userFirstName, userLastName, userId, "password");
82
83 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, soPartsCount, ua.PrincipalID, "part", soIdTail);
84 RezScript(
85 scene, so.UUID, "default { state_entry() { llSay(0, \"Hello World\"); } }", "item1", ua.PrincipalID);
86
87 AssetBase asset = AssetHelpers.CreateAsset(assetId, so);
88 asset.CreatorID = foreignUrl;
89 hgam.PostAsset(foreignUrl, asset);
90
91 // Check transformed asset.
92 AssetBase ncAssetGet = scene.AssetService.Get(assetId.ToString());
93 Assert.AreEqual(foreignUrl, ncAssetGet.CreatorID);
94 string xmlData = Utils.BytesToString(ncAssetGet.Data);
95 XmlDocument ncAssetGetXmlDoc = new XmlDocument();
96 ncAssetGetXmlDoc.LoadXml(xmlData);
97
98// Console.WriteLine(ncAssetGetXmlDoc.OuterXml);
99
100 XmlNodeList creatorDataNodes = ncAssetGetXmlDoc.GetElementsByTagName("CreatorData");
101
102 Assert.AreEqual(soPartsCount, creatorDataNodes.Count);
103 //Console.WriteLine("creatorDataNodes {0}", creatorDataNodes.Count);
104
105 foreach (XmlNode creatorDataNode in creatorDataNodes)
106 {
107 Assert.AreEqual(
108 string.Format("{0};{1} {2}", homeUrl, ua.FirstName, ua.LastName), creatorDataNode.InnerText);
109 }
110
111 // Check that saved script nodes have attributes
112 XmlNodeList savedScriptStateNodes = ncAssetGetXmlDoc.GetElementsByTagName("SavedScriptState");
113
114 Assert.AreEqual(1, savedScriptStateNodes.Count);
115 Assert.AreEqual(1, savedScriptStateNodes[0].Attributes.Count);
116 XmlNode uuidAttribute = savedScriptStateNodes[0].Attributes.GetNamedItem("UUID");
117 Assert.NotNull(uuidAttribute);
118 // XXX: To check the actual UUID attribute we would have to do some work to retreive the UUID of the task
119 // item created earlier.
120 }
121
122 private void RezScript(Scene scene, UUID soId, string script, string itemName, UUID userId)
123 {
124 InventoryItemBase itemTemplate = new InventoryItemBase();
125 // itemTemplate.ID = itemId;
126 itemTemplate.Name = itemName;
127 itemTemplate.Folder = soId;
128 itemTemplate.InvType = (int)InventoryType.LSL;
129
130 // XXX: Ultimately it would be better to be able to directly manipulate the script engine to rez a script
131 // immediately for tests rather than chunter through it's threaded mechanisms.
132 AutoResetEvent chatEvent = new AutoResetEvent(false);
133
134 scene.EventManager.OnChatFromWorld += (s, c) =>
135 {
136// Console.WriteLine("Got chat [{0}]", c.Message);
137 chatEvent.Set();
138 };
139
140 scene.RezNewScript(userId, itemTemplate, script);
141
142// Console.WriteLine("HERE");
143 Assert.IsTrue(chatEvent.WaitOne(60000), "Chat event in HGAssetMapperTests.RezScript not received");
144 }
145 }
146} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs
index ac25a93..1d91165 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs
@@ -37,14 +37,12 @@ using OpenSim.Data;
37using OpenSim.Framework; 37using OpenSim.Framework;
38using OpenSim.Framework.Serialization; 38using OpenSim.Framework.Serialization;
39using OpenSim.Framework.Serialization.External; 39using OpenSim.Framework.Serialization.External;
40using OpenSim.Framework.Communications;
41using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; 40using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver;
42using OpenSim.Region.CoreModules.Framework.InventoryAccess; 41using OpenSim.Region.CoreModules.Framework.InventoryAccess;
43using OpenSim.Region.Framework.Scenes; 42using OpenSim.Region.Framework.Scenes;
44using OpenSim.Region.Framework.Scenes.Serialization; 43using OpenSim.Region.Framework.Scenes.Serialization;
45using OpenSim.Services.Interfaces; 44using OpenSim.Services.Interfaces;
46using OpenSim.Tests.Common; 45using OpenSim.Tests.Common;
47using OpenSim.Tests.Common.Mock;
48 46
49namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests 47namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests
50{ 48{
@@ -109,8 +107,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests
109 item1.AssetID = asset1.FullID; 107 item1.AssetID = asset1.FullID;
110 item1.ID = item1Id; 108 item1.ID = item1Id;
111 InventoryFolderBase objsFolder 109 InventoryFolderBase objsFolder
112 = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, m_userId, "Objects")[0]; 110 = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, m_userId, "Objects")[0];
113 item1.Folder = objsFolder.ID; 111 item1.Folder = objsFolder.ID;
112 item1.Flags |= (uint)InventoryItemFlags.ObjectHasMultipleItems;
114 m_scene.AddInventoryItem(item1); 113 m_scene.AddInventoryItem(item1);
115 114
116 SceneObjectGroup so 115 SceneObjectGroup so
@@ -159,7 +158,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests
159 item1.AssetID = asset1.FullID; 158 item1.AssetID = asset1.FullID;
160 item1.ID = item1Id; 159 item1.ID = item1Id;
161 InventoryFolderBase objsFolder 160 InventoryFolderBase objsFolder
162 = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, m_userId, "Objects")[0]; 161 = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, m_userId, "Objects")[0];
163 item1.Folder = objsFolder.ID; 162 item1.Folder = objsFolder.ID;
164 m_scene.AddInventoryItem(item1); 163 m_scene.AddInventoryItem(item1);
165 164
diff --git a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs
index ec22146..862f0b7 100644
--- a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs
@@ -30,7 +30,6 @@ using System.IO;
30using System.Reflection; 30using System.Reflection;
31 31
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Framework.Communications;
34 33
35using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; 34using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver;
36using OpenSim.Region.Framework; 35using OpenSim.Region.Framework;
@@ -43,6 +42,7 @@ using OpenMetaverse;
43using log4net; 42using log4net;
44using Mono.Addins; 43using Mono.Addins;
45using Nini.Config; 44using Nini.Config;
45using PermissionMask = OpenSim.Framework.PermissionMask;
46 46
47namespace OpenSim.Region.CoreModules.Framework.Library 47namespace OpenSim.Region.CoreModules.Framework.Library
48{ 48{
@@ -175,7 +175,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library
175 m_log.InfoFormat("[LIBRARY MODULE]: Loading library archive {0} ({1})...", iarFileName, simpleName); 175 m_log.InfoFormat("[LIBRARY MODULE]: Loading library archive {0} ({1})...", iarFileName, simpleName);
176 simpleName = GetInventoryPathFromName(simpleName); 176 simpleName = GetInventoryPathFromName(simpleName);
177 177
178 InventoryArchiveReadRequest archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, simpleName, iarFileName, false); 178 InventoryArchiveReadRequest archread = new InventoryArchiveReadRequest(m_MockScene.InventoryService, m_MockScene.AssetService, m_MockScene.UserAccountService, uinfo, simpleName, iarFileName, false);
179 try 179 try
180 { 180 {
181 HashSet<InventoryNodeBase> nodes = archread.Execute(); 181 HashSet<InventoryNodeBase> nodes = archread.Execute();
@@ -184,7 +184,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library
184 // didn't find the subfolder with the given name; place it on the top 184 // didn't find the subfolder with the given name; place it on the top
185 m_log.InfoFormat("[LIBRARY MODULE]: Didn't find {0} in library. Placing archive on the top level", simpleName); 185 m_log.InfoFormat("[LIBRARY MODULE]: Didn't find {0} in library. Placing archive on the top level", simpleName);
186 archread.Close(); 186 archread.Close();
187 archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, "/", iarFileName, false); 187 archread = new InventoryArchiveReadRequest(m_MockScene.InventoryService, m_MockScene.AssetService, m_MockScene.UserAccountService, uinfo, "/", iarFileName, false);
188 archread.Execute(); 188 archread.Execute();
189 } 189 }
190 190
diff --git a/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs b/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs
index 49589fd..e1e1838 100644
--- a/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs
+++ b/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs
@@ -65,7 +65,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library
65 { 65 {
66 InventoryFolderImpl folder = null; 66 InventoryFolderImpl folder = null;
67 InventoryCollection inv = new InventoryCollection(); 67 InventoryCollection inv = new InventoryCollection();
68 inv.UserID = m_Library.Owner; 68 inv.OwnerID = m_Library.Owner;
69 69
70 if (folderID != m_Library.ID) 70 if (folderID != m_Library.ID)
71 { 71 {
@@ -87,6 +87,34 @@ namespace OpenSim.Region.CoreModules.Framework.Library
87 return inv; 87 return inv;
88 } 88 }
89 89
90 public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs)
91 {
92 InventoryCollection[] invColl = new InventoryCollection[folderIDs.Length];
93 int i = 0;
94 foreach (UUID fid in folderIDs)
95 {
96 invColl[i++] = GetFolderContent(principalID, fid);
97 }
98
99 return invColl;
100 }
101
102 public virtual InventoryItemBase[] GetMultipleItems(UUID principalID, UUID[] itemIDs)
103 {
104 InventoryItemBase[] itemColl = new InventoryItemBase[itemIDs.Length];
105 int i = 0;
106 InventoryItemBase item = new InventoryItemBase();
107 item.Owner = principalID;
108 foreach (UUID fid in itemIDs)
109 {
110 item.ID = fid;
111 itemColl[i++] = GetItem(item);
112 }
113
114 return itemColl;
115 }
116
117
90 /// <summary> 118 /// <summary>
91 /// Add a new folder to the user's inventory 119 /// Add a new folder to the user's inventory
92 /// </summary> 120 /// </summary>
@@ -142,28 +170,12 @@ namespace OpenSim.Region.CoreModules.Framework.Library
142 public List<InventoryFolderBase> GetInventorySkeleton(UUID userId) { return null; } 170 public List<InventoryFolderBase> GetInventorySkeleton(UUID userId) { return null; }
143 171
144 /// <summary> 172 /// <summary>
145 /// Synchronous inventory fetch.
146 /// </summary>
147 /// <param name="userID"></param>
148 /// <returns></returns>
149 public InventoryCollection GetUserInventory(UUID userID) { return null; }
150
151 /// <summary>
152 /// Request the inventory for a user. This is an asynchronous operation that will call the callback when the
153 /// inventory has been received
154 /// </summary>
155 /// <param name="userID"></param>
156 /// <param name="callback"></param>
157 public void GetUserInventory(UUID userID, InventoryReceiptCallback callback) { }
158
159
160 /// <summary>
161 /// Gets the user folder for the given folder-type 173 /// Gets the user folder for the given folder-type
162 /// </summary> 174 /// </summary>
163 /// <param name="userID"></param> 175 /// <param name="userID"></param>
164 /// <param name="type"></param> 176 /// <param name="type"></param>
165 /// <returns></returns> 177 /// <returns></returns>
166 public InventoryFolderBase GetFolderForType(UUID userID, AssetType type) { return null; } 178 public InventoryFolderBase GetFolderForType(UUID userID, FolderType type) { return null; }
167 179
168 180
169 /// <summary> 181 /// <summary>
diff --git a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs
index d84460a..64feec1 100644
--- a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs
@@ -33,6 +33,7 @@ using log4net;
33using Nini.Config; 33using Nini.Config;
34using OpenMetaverse; 34using OpenMetaverse;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Framework.Monitoring;
36using OpenSim.Framework.Servers; 37using OpenSim.Framework.Servers;
37using OpenSim.Region.CoreModules.Framework.Monitoring.Alerts; 38using OpenSim.Region.CoreModules.Framework.Monitoring.Alerts;
38using OpenSim.Region.CoreModules.Framework.Monitoring.Monitors; 39using OpenSim.Region.CoreModules.Framework.Monitoring.Monitors;
@@ -100,6 +101,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
100 "/monitorstats/" + Uri.EscapeDataString(m_scene.RegionInfo.RegionName), StatsPage); 101 "/monitorstats/" + Uri.EscapeDataString(m_scene.RegionInfo.RegionName), StatsPage);
101 102
102 AddMonitors(); 103 AddMonitors();
104 RegisterStatsManagerRegionStatistics();
103 } 105 }
104 106
105 public void RemoveRegion(Scene scene) 107 public void RemoveRegion(Scene scene)
@@ -109,6 +111,9 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
109 111
110 MainServer.Instance.RemoveHTTPHandler("GET", "/monitorstats/" + m_scene.RegionInfo.RegionID); 112 MainServer.Instance.RemoveHTTPHandler("GET", "/monitorstats/" + m_scene.RegionInfo.RegionID);
111 MainServer.Instance.RemoveHTTPHandler("GET", "/monitorstats/" + Uri.EscapeDataString(m_scene.RegionInfo.RegionName)); 113 MainServer.Instance.RemoveHTTPHandler("GET", "/monitorstats/" + Uri.EscapeDataString(m_scene.RegionInfo.RegionName));
114
115 UnRegisterStatsManagerRegionStatistics();
116
112 m_scene = null; 117 m_scene = null;
113 } 118 }
114 119
@@ -399,6 +404,45 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
399 { 404 {
400 m_log.Error("[Monitor] " + reporter.Name + " for " + m_scene.RegionInfo.RegionName + " reports " + reason + " (Fatal: " + fatal + ")"); 405 m_log.Error("[Monitor] " + reporter.Name + " for " + m_scene.RegionInfo.RegionName + " reports " + reason + " (Fatal: " + fatal + ")");
401 } 406 }
407
408 private List<Stat> registeredStats = new List<Stat>();
409 private void MakeStat(string pName, string pUnitName, Action<Stat> act)
410 {
411 Stat tempStat = new Stat(pName, pName, pName, pUnitName, "scene", m_scene.RegionInfo.RegionName, StatType.Pull, act, StatVerbosity.Info);
412 StatsManager.RegisterStat(tempStat);
413 registeredStats.Add(tempStat);
414 }
415 private void RegisterStatsManagerRegionStatistics()
416 {
417 MakeStat("RootAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetRootAgentCount(); });
418 MakeStat("ChildAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetChildAgentCount(); });
419 MakeStat("TotalPrims", "objects", (s) => { s.Value = m_scene.SceneGraph.GetTotalObjectsCount(); });
420 MakeStat("ActivePrims", "objects", (s) => { s.Value = m_scene.SceneGraph.GetActiveObjectsCount(); });
421 MakeStat("ActiveScripts", "scripts", (s) => { s.Value = m_scene.SceneGraph.GetActiveScriptsCount(); });
422
423 MakeStat("TimeDilation", "sec/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[0]; });
424 MakeStat("SimFPS", "fps", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[1]; });
425 MakeStat("PhysicsFPS", "fps", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[2]; });
426 MakeStat("AgentUpdates", "updates/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[3]; });
427 MakeStat("FrameTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[8]; });
428 MakeStat("NetTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[9]; });
429 MakeStat("OtherTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[12]; });
430 MakeStat("PhysicsTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[10]; });
431 MakeStat("AgentTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[16]; });
432 MakeStat("ImageTime", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[11]; });
433 MakeStat("ScriptLines", "lines/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[20]; });
434 MakeStat("SimSpareMS", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[21]; });
435 }
436
437 private void UnRegisterStatsManagerRegionStatistics()
438 {
439 foreach (Stat stat in registeredStats)
440 {
441 StatsManager.DeregisterStat(stat);
442 stat.Dispose();
443 }
444 registeredStats.Clear();
445 }
402 446
403 } 447 }
404} 448} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs b/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs
new file mode 100644
index 0000000..3849996
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs
@@ -0,0 +1,199 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.IO;
30using System.Reflection;
31using System.Threading;
32
33using OpenSim.Framework;
34using OpenSim.Framework.Console;
35using OpenSim.Framework.Monitoring;
36using OpenSim.Region.ClientStack.LindenUDP;
37using OpenSim.Region.Framework;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using OpenSim.Services.Connectors.Hypergrid;
42
43using OpenMetaverse;
44using OpenMetaverse.Packets;
45using log4net;
46using Nini.Config;
47using Mono.Addins;
48
49using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags;
50
51namespace OpenSim.Region.CoreModules.Framework.Search
52{
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "BasicSearchModule")]
54 public class BasicSearchModule : ISharedRegionModule
55 {
56 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
57
58 protected bool m_Enabled;
59 protected List<Scene> m_Scenes = new List<Scene>();
60
61 private IGroupsModule m_GroupsService = null;
62
63 #region ISharedRegionModule
64
65 public void Initialise(IConfigSource config)
66 {
67 string umanmod = config.Configs["Modules"].GetString("SearchModule", Name);
68 if (umanmod == Name)
69 {
70 m_Enabled = true;
71 m_log.DebugFormat("[BASIC SEARCH MODULE]: {0} is enabled", Name);
72 }
73 }
74
75 public bool IsSharedModule
76 {
77 get { return true; }
78 }
79
80 public virtual string Name
81 {
82 get { return "BasicSearchModule"; }
83 }
84
85 public Type ReplaceableInterface
86 {
87 get { return null; }
88 }
89
90 public void AddRegion(Scene scene)
91 {
92 if (m_Enabled)
93 {
94 m_Scenes.Add(scene);
95
96 scene.EventManager.OnMakeRootAgent += new Action<ScenePresence>(EventManager_OnMakeRootAgent);
97 scene.EventManager.OnMakeChildAgent += new EventManager.OnMakeChildAgentDelegate(EventManager_OnMakeChildAgent);
98 }
99 }
100
101 public void RemoveRegion(Scene scene)
102 {
103 if (m_Enabled)
104 {
105 m_Scenes.Remove(scene);
106
107 scene.EventManager.OnMakeRootAgent -= new Action<ScenePresence>(EventManager_OnMakeRootAgent);
108 scene.EventManager.OnMakeChildAgent -= new EventManager.OnMakeChildAgentDelegate(EventManager_OnMakeChildAgent);
109 }
110 }
111
112 public void RegionLoaded(Scene s)
113 {
114 if (!m_Enabled)
115 return;
116
117 if (m_GroupsService == null)
118 {
119 m_GroupsService = s.RequestModuleInterface<IGroupsModule>();
120
121 // No Groups Service Connector, then group search won't work...
122 if (m_GroupsService == null)
123 m_log.Warn("[BASIC SEARCH MODULE]: Could not get IGroupsModule");
124 }
125 }
126
127 public void PostInitialise()
128 {
129 }
130
131 public void Close()
132 {
133 m_Scenes.Clear();
134 }
135
136 #endregion ISharedRegionModule
137
138
139 #region Event Handlers
140
141 void EventManager_OnMakeRootAgent(ScenePresence sp)
142 {
143 sp.ControllingClient.OnDirFindQuery += OnDirFindQuery;
144 }
145
146 void EventManager_OnMakeChildAgent(ScenePresence sp)
147 {
148 sp.ControllingClient.OnDirFindQuery -= OnDirFindQuery;
149 }
150
151 void OnDirFindQuery(IClientAPI remoteClient, UUID queryID, string queryText, uint queryFlags, int queryStart)
152 {
153 queryText = queryText.Trim();
154
155 if (((DirFindFlags)queryFlags & DirFindFlags.People) == DirFindFlags.People)
156 {
157 if (string.IsNullOrEmpty(queryText))
158 remoteClient.SendDirPeopleReply(queryID, new DirPeopleReplyData[0]);
159
160 List<UserAccount> accounts = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, queryText);
161 DirPeopleReplyData[] hits = new DirPeopleReplyData[accounts.Count];
162 int i = 0;
163 foreach (UserAccount acc in accounts)
164 {
165 DirPeopleReplyData d = new DirPeopleReplyData();
166 d.agentID = acc.PrincipalID;
167 d.firstName = acc.FirstName;
168 d.lastName = acc.LastName;
169 d.online = false;
170
171 hits[i++] = d;
172 }
173
174 // TODO: This currently ignores pretty much all the query flags including Mature and sort order
175 remoteClient.SendDirPeopleReply(queryID, hits);
176 }
177 else if (((DirFindFlags)queryFlags & DirFindFlags.Groups) == DirFindFlags.Groups)
178 {
179 if (m_GroupsService == null)
180 {
181 m_log.Warn("[BASIC SEARCH MODULE]: Groups service is not available. Unable to search groups.");
182 remoteClient.SendAlertMessage("Groups search is not enabled");
183 return;
184 }
185
186 if (string.IsNullOrEmpty(queryText))
187 remoteClient.SendDirGroupsReply(queryID, new DirGroupsReplyData[0]);
188
189 // TODO: This currently ignores pretty much all the query flags including Mature and sort order
190 remoteClient.SendDirGroupsReply(queryID, m_GroupsService.FindGroups(remoteClient, queryText).ToArray());
191 }
192
193 }
194
195 #endregion Event Handlers
196
197 }
198
199}
diff --git a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs
new file mode 100644
index 0000000..3abacbd
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs
@@ -0,0 +1,256 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Threading;
32using log4net;
33using Mono.Addins;
34using Nini.Config;
35using OpenMetaverse;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Framework.Monitoring;
39using OpenSim.Region.Framework.Scenes;
40using GridRegion = OpenSim.Services.Interfaces.GridRegion;
41
42namespace OpenSim.Region.CoreModules.Framework
43{
44 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GridServiceThrottleModule")]
45 public class ServiceThrottleModule : ISharedRegionModule, IServiceThrottleModule
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(
48 MethodBase.GetCurrentMethod().DeclaringType);
49
50 private readonly List<Scene> m_scenes = new List<Scene>();
51 private System.Timers.Timer m_timer = new System.Timers.Timer();
52
53 private Queue<Action> m_RequestQueue = new Queue<Action>();
54 private Dictionary<string, List<string>> m_Pending = new Dictionary<string, List<string>>();
55 private int m_Interval;
56
57 #region ISharedRegionModule
58
59 public void Initialise(IConfigSource config)
60 {
61 m_Interval = Util.GetConfigVarFromSections<int>(config, "Interval", new string[] { "ServiceThrottle" }, 5000);
62
63 m_timer = new System.Timers.Timer();
64 m_timer.AutoReset = false;
65 m_timer.Enabled = true;
66 m_timer.Interval = 15000; // 15 secs at first
67 m_timer.Elapsed += ProcessQueue;
68 m_timer.Start();
69
70 //WorkManager.StartThread(
71 // ProcessQueue,
72 // "GridServiceRequestThread",
73 // ThreadPriority.BelowNormal,
74 // true,
75 // false);
76 }
77
78 public void AddRegion(Scene scene)
79 {
80 lock (m_scenes)
81 {
82 m_scenes.Add(scene);
83 scene.RegisterModuleInterface<IServiceThrottleModule>(this);
84 scene.EventManager.OnNewClient += OnNewClient;
85 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
86 }
87 }
88
89 public void RegionLoaded(Scene scene)
90 {
91 }
92
93 public void RemoveRegion(Scene scene)
94 {
95 lock (m_scenes)
96 {
97 m_scenes.Remove(scene);
98 scene.EventManager.OnNewClient -= OnNewClient;
99 }
100 }
101
102 public void PostInitialise()
103 {
104 }
105
106 public void Close()
107 {
108 }
109
110 public string Name
111 {
112 get { return "ServiceThrottleModule"; }
113 }
114
115 public Type ReplaceableInterface
116 {
117 get { return null; }
118 }
119
120 #endregion ISharedRegionMOdule
121
122 #region Events
123
124 void OnNewClient(IClientAPI client)
125 {
126 client.OnRegionHandleRequest += OnRegionHandleRequest;
127 }
128
129 void OnMakeRootAgent(ScenePresence obj)
130 {
131 lock (m_timer)
132 {
133 if (!m_timer.Enabled)
134 {
135 m_timer.Interval = m_Interval;
136 m_timer.Enabled = true;
137 m_timer.Start();
138 }
139 }
140 }
141
142 public void OnRegionHandleRequest(IClientAPI client, UUID regionID)
143 {
144 //m_log.DebugFormat("[SERVICE THROTTLE]: RegionHandleRequest {0}", regionID);
145 ulong handle = 0;
146 if (IsLocalRegionHandle(regionID, out handle))
147 {
148 client.SendRegionHandle(regionID, handle);
149 return;
150 }
151
152 Action action = delegate
153 {
154 GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, regionID);
155
156 if (r != null && r.RegionHandle != 0)
157 client.SendRegionHandle(regionID, r.RegionHandle);
158 };
159
160 Enqueue("region", regionID.ToString(), action);
161 }
162
163 #endregion Events
164
165 #region IServiceThrottleModule
166
167 public void Enqueue(string category, string itemid, Action continuation)
168 {
169 lock (m_RequestQueue)
170 {
171 if (m_Pending.ContainsKey(category))
172 {
173 if (m_Pending[category].Contains(itemid))
174 // Don't enqueue, it's already pending
175 return;
176 }
177 else
178 m_Pending.Add(category, new List<string>());
179
180 m_Pending[category].Add(itemid);
181
182 m_RequestQueue.Enqueue(delegate
183 {
184 lock (m_RequestQueue)
185 m_Pending[category].Remove(itemid);
186
187 continuation();
188 });
189 }
190 }
191
192 #endregion IServiceThrottleModule
193
194 #region Process Continuation Queue
195
196 private void ProcessQueue(object sender, System.Timers.ElapsedEventArgs e)
197 {
198 //m_log.DebugFormat("[YYY]: Process queue with {0} continuations", m_RequestQueue.Count);
199
200 while (m_RequestQueue.Count > 0)
201 {
202 Action continuation = null;
203 lock (m_RequestQueue)
204 continuation = m_RequestQueue.Dequeue();
205
206 if (continuation != null)
207 continuation();
208 }
209
210 if (AreThereRootAgents())
211 {
212 lock (m_timer)
213 {
214 m_timer.Interval = 1000; // 1 sec
215 m_timer.Enabled = true;
216 m_timer.Start();
217 }
218 }
219 else
220 lock (m_timer)
221 m_timer.Enabled = false;
222
223 }
224
225 #endregion Process Continuation Queue
226
227 #region Misc
228
229 private bool IsLocalRegionHandle(UUID regionID, out ulong regionHandle)
230 {
231 regionHandle = 0;
232 foreach (Scene s in m_scenes)
233 if (s.RegionInfo.RegionID == regionID)
234 {
235 regionHandle = s.RegionInfo.RegionHandle;
236 return true;
237 }
238 return false;
239 }
240
241 private bool AreThereRootAgents()
242 {
243 foreach (Scene s in m_scenes)
244 {
245 foreach (ScenePresence sp in s.GetScenePresences())
246 if (!sp.IsChildAgent)
247 return true;
248 }
249
250 return false;
251 }
252
253 #endregion Misc
254 }
255
256}
diff --git a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
index fb74cc6..f3436d1 100644
--- a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
@@ -57,7 +57,7 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
57 try 57 try
58 { 58 {
59 IConfig statConfig = source.Configs["Statistics.Binary"]; 59 IConfig statConfig = source.Configs["Statistics.Binary"];
60 if (statConfig.Contains("enabled") && statConfig.GetBoolean("enabled")) 60 if (statConfig != null && statConfig.Contains("enabled") && statConfig.GetBoolean("enabled"))
61 { 61 {
62 if (statConfig.Contains("collect_region_stats")) 62 if (statConfig.Contains("collect_region_stats"))
63 { 63 {
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs
index 4ef57fe..7b89c2c 100644
--- a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs
@@ -50,16 +50,15 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
50 { 50 {
51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52 52
53
54 #region ISharedRegionModule 53 #region ISharedRegionModule
55 54
56 public new void Initialise(IConfigSource config) 55 public new void Initialise(IConfigSource config)
57 { 56 {
58 string umanmod = config.Configs["Modules"].GetString("UserManagementModule", base.Name); 57 string umanmod = config.Configs["Modules"].GetString("UserManagementModule", null);
59 if (umanmod == Name) 58 if (umanmod == Name)
60 { 59 {
61 m_Enabled = true; 60 m_Enabled = true;
62 RegisterConsoleCmds(); 61 Init();
63 m_log.DebugFormat("[USER MANAGEMENT MODULE]: {0} is enabled", Name); 62 m_log.DebugFormat("[USER MANAGEMENT MODULE]: {0} is enabled", Name);
64 } 63 }
65 } 64 }
@@ -71,7 +70,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
71 70
72 #endregion ISharedRegionModule 71 #endregion ISharedRegionModule
73 72
74 protected override void AddAdditionalUsers(UUID avatarID, string query, List<UserData> users) 73 protected override void AddAdditionalUsers(string query, List<UserData> users)
75 { 74 {
76 if (query.Contains("@")) // First.Last@foo.com, maybe? 75 if (query.Contains("@")) // First.Last@foo.com, maybe?
77 { 76 {
@@ -131,7 +130,17 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
131 } 130 }
132 131
133 UserAgentServiceConnector uasConn = new UserAgentServiceConnector(uriStr); 132 UserAgentServiceConnector uasConn = new UserAgentServiceConnector(uriStr);
134 UUID userID = uasConn.GetUUID(names[0], names[1]); 133
134 UUID userID = UUID.Zero;
135 try
136 {
137 userID = uasConn.GetUUID(names[0], names[1]);
138 }
139 catch (Exception e)
140 {
141 m_log.Debug("[USER MANAGEMENT MODULE]: GetUUID call failed ", e);
142 }
143
135 if (!userID.Equals(UUID.Zero)) 144 if (!userID.Equals(UUID.Zero))
136 { 145 {
137 UserData ud = new UserData(); 146 UserData ud = new UserData();
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs
index 119a677..4e3b7e5 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs
+++ b/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs
@@ -25,54 +25,51 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System.Net; 28using System;
29using Nini.Config;
30using NUnit.Framework;
29using OpenMetaverse; 31using OpenMetaverse;
30using OpenSim.Framework; 32using OpenSim.Framework;
31using OpenSim.Region.Framework.Scenes; 33using OpenSim.Region.CoreModules.Framework.UserManagement;
32using GridRegion = OpenSim.Services.Interfaces.GridRegion; 34using OpenSim.Tests.Common;
33 35
34namespace OpenSim.Region.ClientStack.LindenUDP.Tests 36namespace OpenSim.Region.CoreModules.Framework.UserManagement.Tests
35{ 37{
36 /// <summary> 38 [TestFixture]
37 /// Mock scene for unit tests 39 public class HGUserManagementModuleTests : OpenSimTestCase
38 /// </summary> 40 {
39 public class MockScene : SceneBase
40 {
41 public int ObjectNameCallsReceived
42 {
43 get { return m_objectNameCallsReceived; }
44 }
45 protected int m_objectNameCallsReceived;
46
47 public MockScene() : base(new RegionInfo(1000, 1000, null, null))
48 {
49 m_regStatus = RegionStatus.Up;
50 }
51
52 public override void Update(int frames) {}
53 public override void LoadWorldMap() {}
54
55 public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type)
56 {
57 client.OnObjectName += RecordObjectNameCall;
58
59 // FIXME
60 return null;
61 }
62
63 public override void RemoveClient(UUID agentID, bool someReason) {}
64// public override void CloseAllAgents(uint circuitcode) {}
65 public override bool CheckClient(UUID clientId, IPEndPoint endPoint) { return true; }
66 public override void OtherRegionUp(GridRegion otherRegion) { }
67
68 public override bool TryGetScenePresence(UUID uuid, out ScenePresence sp) { sp = null; return false; }
69
70 /// <summary> 41 /// <summary>
71 /// Doesn't really matter what the call is - we're using this to test that a packet has actually been received 42 /// Test that a new HG agent (i.e. one without a user account) has their name cached in the UMM upon creation.
72 /// </summary> 43 /// </summary>
73 protected void RecordObjectNameCall(IClientAPI remoteClient, uint localID, string message) 44 [Test]
45 public void TestCachedUserNameForNewAgent()
74 { 46 {
75 m_objectNameCallsReceived++; 47 TestHelpers.InMethod();
48// TestHelpers.EnableLogging();
49
50 HGUserManagementModule hgumm = new HGUserManagementModule();
51 UUID userId = TestHelpers.ParseStem("11");
52 string firstName = "Fred";
53 string lastName = "Astaire";
54 string homeUri = "example.com";
55
56 IConfigSource config = new IniConfigSource();
57 config.AddConfig("Modules");
58 config.Configs["Modules"].Set("UserManagementModule", hgumm.Name);
59
60 SceneHelpers sceneHelpers = new SceneHelpers();
61 TestScene scene = sceneHelpers.SetupScene();
62 SceneHelpers.SetupSceneModules(scene, config, hgumm);
63
64 AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
65 acd.firstname = firstName;
66 acd.lastname = lastName;
67 acd.ServiceURLs["HomeURI"] = "http://" + homeUri;
68
69 SceneHelpers.AddScenePresence(scene, acd);
70
71 string name = hgumm.GetUserName(userId);
72 Assert.That(name, Is.EqualTo(string.Format("{0}.{1} @{2}", firstName, lastName, homeUri)));
76 } 73 }
77 } 74 }
78} 75} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
index 77e8b00..7ecbd26 100644
--- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
@@ -28,9 +28,11 @@ using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.IO; 29using System.IO;
30using System.Reflection; 30using System.Reflection;
31using System.Threading;
31 32
32using OpenSim.Framework; 33using OpenSim.Framework;
33using OpenSim.Framework.Console; 34using OpenSim.Framework.Console;
35using OpenSim.Framework.Monitoring;
34using OpenSim.Region.ClientStack.LindenUDP; 36using OpenSim.Region.ClientStack.LindenUDP;
35using OpenSim.Region.Framework; 37using OpenSim.Region.Framework;
36using OpenSim.Region.Framework.Interfaces; 38using OpenSim.Region.Framework.Interfaces;
@@ -44,28 +46,24 @@ using log4net;
44using Nini.Config; 46using Nini.Config;
45using Mono.Addins; 47using Mono.Addins;
46 48
49using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags;
50
47namespace OpenSim.Region.CoreModules.Framework.UserManagement 51namespace OpenSim.Region.CoreModules.Framework.UserManagement
48{ 52{
49 public class UserData
50 {
51 public UUID Id { get; set; }
52 public string FirstName { get; set; }
53 public string LastName { get; set; }
54 public string HomeURL { get; set; }
55 public Dictionary<string, object> ServerURLs { get; set; }
56 }
57
58 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserManagementModule")] 53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserManagementModule")]
59 public class UserManagementModule : ISharedRegionModule, IUserManagement 54 public class UserManagementModule : ISharedRegionModule, IUserManagement, IPeople
60 { 55 {
61 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 56 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
62 57
63 protected bool m_Enabled; 58 protected bool m_Enabled;
64 protected List<Scene> m_Scenes = new List<Scene>(); 59 protected List<Scene> m_Scenes = new List<Scene>();
65 60
61 protected IServiceThrottleModule m_ServiceThrottle;
66 // The cache 62 // The cache
67 protected Dictionary<UUID, UserData> m_UserCache = new Dictionary<UUID, UserData>(); 63 protected Dictionary<UUID, UserData> m_UserCache = new Dictionary<UUID, UserData>();
68 64
65 protected bool m_DisplayChangingHomeURI = false;
66
69 #region ISharedRegionModule 67 #region ISharedRegionModule
70 68
71 public void Initialise(IConfigSource config) 69 public void Initialise(IConfigSource config)
@@ -74,9 +72,20 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
74 if (umanmod == Name) 72 if (umanmod == Name)
75 { 73 {
76 m_Enabled = true; 74 m_Enabled = true;
77 RegisterConsoleCmds(); 75 Init();
78 m_log.DebugFormat("[USER MANAGEMENT MODULE]: {0} is enabled", Name); 76 m_log.DebugFormat("[USER MANAGEMENT MODULE]: {0} is enabled", Name);
79 } 77 }
78
79 if(!m_Enabled)
80 {
81 return;
82 }
83
84 IConfig userManagementConfig = config.Configs["UserManagement"];
85 if (userManagementConfig == null)
86 return;
87
88 m_DisplayChangingHomeURI = userManagementConfig.GetBoolean("DisplayChangingHomeURI", false);
80 } 89 }
81 90
82 public bool IsSharedModule 91 public bool IsSharedModule
@@ -98,9 +107,13 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
98 { 107 {
99 if (m_Enabled) 108 if (m_Enabled)
100 { 109 {
101 m_Scenes.Add(scene); 110 lock (m_Scenes)
111 {
112 m_Scenes.Add(scene);
113 }
102 114
103 scene.RegisterModuleInterface<IUserManagement>(this); 115 scene.RegisterModuleInterface<IUserManagement>(this);
116 scene.RegisterModuleInterface<IPeople>(this);
104 scene.EventManager.OnNewClient += new EventManager.OnNewClientDelegate(EventManager_OnNewClient); 117 scene.EventManager.OnNewClient += new EventManager.OnNewClientDelegate(EventManager_OnNewClient);
105 scene.EventManager.OnPrimsLoaded += new EventManager.PrimsLoaded(EventManager_OnPrimsLoaded); 118 scene.EventManager.OnPrimsLoaded += new EventManager.PrimsLoaded(EventManager_OnPrimsLoaded);
106 } 119 }
@@ -111,12 +124,17 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
111 if (m_Enabled) 124 if (m_Enabled)
112 { 125 {
113 scene.UnregisterModuleInterface<IUserManagement>(this); 126 scene.UnregisterModuleInterface<IUserManagement>(this);
114 m_Scenes.Remove(scene); 127 lock (m_Scenes)
128 {
129 m_Scenes.Remove(scene);
130 }
115 } 131 }
116 } 132 }
117 133
118 public void RegionLoaded(Scene s) 134 public void RegionLoaded(Scene s)
119 { 135 {
136 if (m_Enabled && m_ServiceThrottle == null)
137 m_ServiceThrottle = s.RequestModuleInterface<IServiceThrottleModule>();
120 } 138 }
121 139
122 public void PostInitialise() 140 public void PostInitialise()
@@ -125,7 +143,10 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
125 143
126 public void Close() 144 public void Close()
127 { 145 {
128 m_Scenes.Clear(); 146 lock (m_Scenes)
147 {
148 m_Scenes.Clear();
149 }
129 150
130 lock (m_UserCache) 151 lock (m_UserCache)
131 m_UserCache.Clear(); 152 m_UserCache.Clear();
@@ -133,7 +154,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
133 154
134 #endregion ISharedRegionModule 155 #endregion ISharedRegionModule
135 156
136 157
137 #region Event Handlers 158 #region Event Handlers
138 159
139 void EventManager_OnPrimsLoaded(Scene s) 160 void EventManager_OnPrimsLoaded(Scene s)
@@ -143,7 +164,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
143 s.ForEachSOG(delegate(SceneObjectGroup sog) { CacheCreators(sog); }); 164 s.ForEachSOG(delegate(SceneObjectGroup sog) { CacheCreators(sog); });
144 } 165 }
145 166
146
147 void EventManager_OnNewClient(IClientAPI client) 167 void EventManager_OnNewClient(IClientAPI client)
148 { 168 {
149 client.OnConnectionClosed += new Action<IClientAPI>(HandleConnectionClosed); 169 client.OnConnectionClosed += new Action<IClientAPI>(HandleConnectionClosed);
@@ -157,21 +177,52 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
157 client.OnAvatarPickerRequest -= new AvatarPickerRequest(HandleAvatarPickerRequest); 177 client.OnAvatarPickerRequest -= new AvatarPickerRequest(HandleAvatarPickerRequest);
158 } 178 }
159 179
160 void HandleUUIDNameRequest(UUID uuid, IClientAPI remote_client) 180 void HandleUUIDNameRequest(UUID uuid, IClientAPI client)
161 { 181 {
182// m_log.DebugFormat(
183// "[USER MANAGEMENT MODULE]: Handling request for name binding of UUID {0} from {1}",
184// uuid, remote_client.Name);
185
162 if (m_Scenes[0].LibraryService != null && (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid)) 186 if (m_Scenes[0].LibraryService != null && (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid))
163 { 187 {
164 remote_client.SendNameReply(uuid, "Mr", "OpenSim"); 188 client.SendNameReply(uuid, "Mr", "OpenSim");
165 } 189 }
166 else 190 else
167 { 191 {
168 string[] names = GetUserNames(uuid); 192 UserData user;
169 if (names.Length == 2) 193 /* bypass that continuation here when entry is already available */
194 lock (m_UserCache)
170 { 195 {
171 //m_log.DebugFormat("[XXX] HandleUUIDNameRequest {0} is {1} {2}", uuid, names[0], names[1]); 196 if (m_UserCache.TryGetValue(uuid, out user))
172 remote_client.SendNameReply(uuid, names[0], names[1]); 197 {
198 if (!user.IsUnknownUser && user.HasGridUserTried)
199 {
200 client.SendNameReply(uuid, user.FirstName, user.LastName);
201 return;
202 }
203 }
173 } 204 }
174 205
206 // Not found in cache, queue continuation
207 m_ServiceThrottle.Enqueue("name", uuid.ToString(), delegate
208 {
209 //m_log.DebugFormat("[YYY]: Name request {0}", uuid);
210
211 // As least upto September 2013, clients permanently cache UUID -> Name bindings. Some clients
212 // appear to clear this when the user asks it to clear the cache, but others may not.
213 //
214 // So to avoid clients
215 // (particularly Hypergrid clients) permanently binding "Unknown User" to a given UUID, we will
216 // instead drop the request entirely.
217 if (GetUser(uuid, out user))
218 {
219 client.SendNameReply(uuid, user.FirstName, user.LastName);
220 }
221// else
222// m_log.DebugFormat(
223// "[USER MANAGEMENT MODULE]: No bound name for {0} found, ignoring request from {1}",
224// uuid, client.Name);
225 });
175 } 226 }
176 } 227 }
177 228
@@ -181,29 +232,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
181 232
182 m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query); 233 m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query);
183 234
184 // searhc the user accounts service 235 List<UserData> users = GetUserData(query, 500, 1);
185 List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query);
186
187 List<UserData> users = new List<UserData>();
188 if (accs != null)
189 {
190 foreach (UserAccount acc in accs)
191 {
192 UserData ud = new UserData();
193 ud.FirstName = acc.FirstName;
194 ud.LastName = acc.LastName;
195 ud.Id = acc.PrincipalID;
196 users.Add(ud);
197 }
198 }
199
200 // search the local cache
201 foreach (UserData data in m_UserCache.Values)
202 if (users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null &&
203 (data.FirstName.StartsWith(query) || data.LastName.StartsWith(query)))
204 users.Add(data);
205
206 AddAdditionalUsers(avatarID, query, users);
207 236
208 AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply); 237 AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply);
209 // TODO: don't create new blocks if recycling an old packet 238 // TODO: don't create new blocks if recycling an old packet
@@ -249,60 +278,62 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
249 client.SendAvatarPickerReply(agent_data, data_args); 278 client.SendAvatarPickerReply(agent_data, data_args);
250 } 279 }
251 280
252 protected virtual void AddAdditionalUsers(UUID avatarID, string query, List<UserData> users) 281 protected virtual void AddAdditionalUsers(string query, List<UserData> users)
253 { 282 {
254 } 283 }
255 284
256 #endregion Event Handlers 285 #endregion Event Handlers
257 286
258 private void CacheCreators(SceneObjectGroup sog) 287 #region IPeople
259 {
260 //m_log.DebugFormat("[USER MANAGEMENT MODULE]: processing {0} {1}; {2}", sog.RootPart.Name, sog.RootPart.CreatorData, sog.RootPart.CreatorIdentification);
261 AddUser(sog.RootPart.CreatorID, sog.RootPart.CreatorData);
262
263 foreach (SceneObjectPart sop in sog.Parts)
264 {
265 AddUser(sop.CreatorID, sop.CreatorData);
266 foreach (TaskInventoryItem item in sop.TaskInventory.Values)
267 AddUser(item.CreatorID, item.CreatorData);
268 }
269 }
270 288
271 private string[] GetUserNames(UUID uuid) 289 public List<UserData> GetUserData(string query, int page_size, int page_number)
272 { 290 {
273 string[] returnstring = new string[2]; 291 // search the user accounts service
292 List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query);
274 293
275 lock (m_UserCache) 294 List<UserData> users = new List<UserData>();
295 if (accs != null)
276 { 296 {
277 if (m_UserCache.ContainsKey(uuid)) 297 foreach (UserAccount acc in accs)
278 { 298 {
279 returnstring[0] = m_UserCache[uuid].FirstName; 299 UserData ud = new UserData();
280 returnstring[1] = m_UserCache[uuid].LastName; 300 ud.FirstName = acc.FirstName;
281 return returnstring; 301 ud.LastName = acc.LastName;
302 ud.Id = acc.PrincipalID;
303 ud.HasGridUserTried = true;
304 ud.IsUnknownUser = false;
305 users.Add(ud);
282 } 306 }
283 } 307 }
284 308
285 UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(UUID.Zero, uuid); 309 // search the local cache
286 310 foreach (UserData data in m_UserCache.Values)
287 if (account != null)
288 { 311 {
289 returnstring[0] = account.FirstName; 312 if (data.Id != UUID.Zero && !data.IsUnknownUser &&
290 returnstring[1] = account.LastName; 313 users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null &&
314 (data.FirstName.ToLower().StartsWith(query.ToLower()) || data.LastName.ToLower().StartsWith(query.ToLower())))
315 users.Add(data);
316 }
291 317
292 UserData user = new UserData(); 318 AddAdditionalUsers(query, users);
293 user.FirstName = account.FirstName;
294 user.LastName = account.LastName;
295 319
296 lock (m_UserCache) 320 return users;
297 m_UserCache[uuid] = user; 321
298 } 322 }
299 else 323
324 #endregion IPeople
325
326 private void CacheCreators(SceneObjectGroup sog)
327 {
328 //m_log.DebugFormat("[USER MANAGEMENT MODULE]: processing {0} {1}; {2}", sog.RootPart.Name, sog.RootPart.CreatorData, sog.RootPart.CreatorIdentification);
329 AddUser(sog.RootPart.CreatorID, sog.RootPart.CreatorData);
330
331 foreach (SceneObjectPart sop in sog.Parts)
300 { 332 {
301 returnstring[0] = "Unknown"; 333 AddUser(sop.CreatorID, sop.CreatorData);
302 returnstring[1] = "User"; 334 foreach (TaskInventoryItem item in sop.TaskInventory.Values)
335 AddUser(item.CreatorID, item.CreatorData);
303 } 336 }
304
305 return returnstring;
306 } 337 }
307 338
308 #region IUserManagement 339 #region IUserManagement
@@ -338,55 +369,56 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
338 369
339 public string GetUserName(UUID uuid) 370 public string GetUserName(UUID uuid)
340 { 371 {
341 string[] names = GetUserNames(uuid); 372 UserData user;
342 if (names.Length == 2) 373 GetUser(uuid, out user);
343 { 374 return user.FirstName + " " + user.LastName;
344 string firstname = names[0];
345 string lastname = names[1];
346
347 return firstname + " " + lastname;
348
349 }
350 return "(hippos)";
351 } 375 }
352 376
353 public string GetUserHomeURL(UUID userID) 377 public string GetUserHomeURL(UUID userID)
354 { 378 {
355 lock (m_UserCache) 379 UserData user;
380 if(GetUser(userID, out user))
356 { 381 {
357 if (m_UserCache.ContainsKey(userID)) 382 return user.HomeURL;
358 return m_UserCache[userID].HomeURL;
359 } 383 }
360
361 return string.Empty; 384 return string.Empty;
362 } 385 }
363 386
364 public string GetUserServerURL(UUID userID, string serverType) 387 public string GetUserServerURL(UUID userID, string serverType)
365 { 388 {
366 UserData userdata; 389 UserData userdata;
367 lock (m_UserCache) 390 if(!GetUser(userID, out userdata))
368 m_UserCache.TryGetValue(userID, out userdata); 391 {
392 return string.Empty;
393 }
394
395 if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null)
396 {
397 return userdata.ServerURLs[serverType].ToString();
398 }
369 399
370 if (userdata != null) 400 if (!string.IsNullOrEmpty(userdata.HomeURL))
371 { 401 {
372// m_log.DebugFormat("[USER MANAGEMENT MODULE]: Requested url type {0} for {1}", serverType, userID); 402// m_log.DebugFormat("[USER MANAGEMENT MODULE]: Requested url type {0} for {1}", serverType, userID);
373 403
374 if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null) 404 UserAgentServiceConnector uConn = new UserAgentServiceConnector(userdata.HomeURL);
405 try
375 { 406 {
376 return userdata.ServerURLs[serverType].ToString(); 407 userdata.ServerURLs = uConn.GetServerURLs(userID);
377 } 408 }
378 409 catch(System.Net.WebException e)
379 if (userdata.HomeURL != null && userdata.HomeURL != string.Empty)
380 { 410 {
381 //m_log.DebugFormat( 411 m_log.DebugFormat("[USER MANAGEMENT MODULE]: GetServerURLs call failed {0}", e.Message);
382 // "[USER MANAGEMENT MODULE]: Did not find url type {0} so requesting urls from '{1}' for {2}", 412 userdata.ServerURLs = new Dictionary<string, object>();
383 // serverType, userdata.HomeURL, userID);
384
385 UserAgentServiceConnector uConn = new UserAgentServiceConnector(userdata.HomeURL);
386 userdata.ServerURLs = uConn.GetServerURLs(userID);
387 if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null)
388 return userdata.ServerURLs[serverType].ToString();
389 } 413 }
414 catch (Exception e)
415 {
416 m_log.Debug("[USER MANAGEMENT MODULE]: GetServerURLs call failed ", e);
417 userdata.ServerURLs = new Dictionary<string, object>();
418 }
419
420 if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null)
421 return userdata.ServerURLs[serverType].ToString();
390 } 422 }
391 423
392 return string.Empty; 424 return string.Empty;
@@ -394,13 +426,15 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
394 426
395 public string GetUserUUI(UUID userID) 427 public string GetUserUUI(UUID userID)
396 { 428 {
397 UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, userID); 429 string uui;
398 if (account != null) 430 GetUserUUI(userID, out uui);
399 return userID.ToString(); 431 return uui;
432 }
400 433
434 public bool GetUserUUI(UUID userID, out string uui)
435 {
401 UserData ud; 436 UserData ud;
402 lock (m_UserCache) 437 bool result = GetUser(userID, out ud);
403 m_UserCache.TryGetValue(userID, out ud);
404 438
405 if (ud != null) 439 if (ud != null)
406 { 440 {
@@ -414,121 +448,251 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
414 first = parts[0]; 448 first = parts[0];
415 last = parts[1]; 449 last = parts[1];
416 } 450 }
417 return userID + ";" + homeURL + ";" + first + " " + last; 451 uui = userID + ";" + homeURL + ";" + first + " " + last;
418 } 452 }
419 } 453 }
420 454
421 return userID.ToString(); 455 uui = userID.ToString();
456 return result;
422 } 457 }
423 458
424 public void AddUser(UUID uuid, string first, string last) 459 #region Cache Management
460 public bool GetUser(UUID uuid, out UserData userdata)
425 { 461 {
426 lock (m_UserCache) 462 lock (m_UserCache)
427 { 463 {
428 if (m_UserCache.ContainsKey(uuid)) 464 if (m_UserCache.TryGetValue(uuid, out userdata))
429 return; 465 {
466 if (userdata.HasGridUserTried)
467 {
468 return true;
469 }
470 }
471 else
472 {
473 userdata = new UserData();
474 userdata.HasGridUserTried = false;
475 userdata.Id = uuid;
476 userdata.FirstName = "Unknown";
477 userdata.LastName = "UserUMMAU42";
478 userdata.HomeURL = string.Empty;
479 userdata.IsUnknownUser = true;
480 userdata.HasGridUserTried = false;
481 }
482 }
483
484 /* BEGIN: do not wrap this code in any lock here
485 * There are HTTP calls in here.
486 */
487 if (!userdata.HasGridUserTried)
488 {
489 /* rewrite here */
490 UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, uuid);
491 if (account != null)
492 {
493 userdata.FirstName = account.FirstName;
494 userdata.LastName = account.LastName;
495 userdata.HomeURL = string.Empty;
496 userdata.IsUnknownUser = false;
497 userdata.HasGridUserTried = true;
498 }
430 } 499 }
431 500
432 UserData user = new UserData(); 501 if (!userdata.HasGridUserTried)
433 user.Id = uuid; 502 {
434 user.FirstName = first; 503 GridUserInfo uInfo = null;
435 user.LastName = last; 504 if (null != m_Scenes[0].GridUserService)
505 {
506 uInfo = m_Scenes[0].GridUserService.GetGridUserInfo(uuid.ToString());
507 }
508 if (uInfo != null)
509 {
510 string url, first, last, tmp;
511 UUID u;
512 if(uInfo.UserID.Length <= 36)
513 {
514 /* not a UUI */
515 }
516 else if (Util.ParseUniversalUserIdentifier(uInfo.UserID, out u, out url, out first, out last, out tmp))
517 {
518 if (url != string.Empty)
519 {
520 userdata.FirstName = first.Replace(" ", ".") + "." + last.Replace(" ", ".");
521 userdata.HomeURL = url;
522 try
523 {
524 userdata.LastName = "@" + new Uri(url).Authority;
525 userdata.IsUnknownUser = false;
526 }
527 catch
528 {
529 userdata.LastName = "@unknown";
530 }
531 userdata.HasGridUserTried = true;
532 }
533 }
534 else
535 m_log.DebugFormat("[USER MANAGEMENT MODULE]: Unable to parse UUI {0}", uInfo.UserID);
536 }
537 }
538 /* END: do not wrap this code in any lock here */
436 539
437 AddUserInternal(user); 540 lock (m_UserCache)
541 {
542 m_UserCache[uuid] = userdata;
543 }
544 return !userdata.IsUnknownUser;
438 } 545 }
439 546
440 public void AddUser(UUID uuid, string first, string last, string homeURL) 547 public void AddUser(UUID uuid, string first, string last)
441 { 548 {
442 //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL); 549 lock(m_UserCache)
443 if (homeURL == string.Empty) 550 {
444 return; 551 if(!m_UserCache.ContainsKey(uuid))
445 552 {
446 AddUser(uuid, homeURL + ";" + first + " " + last); 553 UserData user = new UserData();
554 user.Id = uuid;
555 user.FirstName = first;
556 user.LastName = last;
557 user.IsUnknownUser = false;
558 user.HasGridUserTried = false;
559 m_UserCache.Add(uuid, user);
560 }
561 }
447 } 562 }
448 563
449 public void AddUser (UUID id, string creatorData) 564 public void AddUser(UUID uuid, string first, string last, string homeURL)
450 { 565 {
451 //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, creatorData {1}", id, creatorData); 566 //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL);
452 567
453 UserData oldUser; 568 UserData oldUser;
454 //lock the whole block - prevent concurrent update
455 lock (m_UserCache) 569 lock (m_UserCache)
456 { 570 {
457 m_UserCache.TryGetValue (id, out oldUser); 571 if (m_UserCache.TryGetValue(uuid, out oldUser))
458 if (oldUser != null)
459 { 572 {
460 if (creatorData == null || creatorData == String.Empty) 573 if (!oldUser.IsUnknownUser)
461 { 574 {
462 //ignore updates without creator data 575 if (homeURL != oldUser.HomeURL && m_DisplayChangingHomeURI)
576 {
577 m_log.DebugFormat("[USER MANAGEMENT MODULE]: Different HomeURI for {0} {1} ({2}): {3} and {4}",
578 first, last, uuid.ToString(), homeURL, oldUser.HomeURL);
579 }
580 /* no update needed */
463 return; 581 return;
464 } 582 }
465 //try update unknown users 583 }
466 //and creator's home URL's 584 else if(!m_UserCache.ContainsKey(uuid))
467 if ((oldUser.FirstName == "Unknown" && !creatorData.Contains ("Unknown")) || (oldUser.HomeURL != null && !creatorData.StartsWith (oldUser.HomeURL))) 585 {
586 oldUser = new UserData();
587 oldUser.HasGridUserTried = false;
588 oldUser.IsUnknownUser = false;
589 if (homeURL != string.Empty)
468 { 590 {
469 m_UserCache.Remove (id); 591 oldUser.FirstName = first.Replace(" ", ".") + "." + last.Replace(" ", ".");
470// m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData,oldUser.HomeURL); 592 try
593 {
594 oldUser.LastName = "@" + new Uri(homeURL).Authority;
595 oldUser.IsUnknownUser = false;
596 }
597 catch
598 {
599 oldUser.LastName = "@unknown";
600 }
471 } 601 }
472 else 602 else
473 { 603 {
474 //we have already a valid user within the cache 604 oldUser.FirstName = first;
475 return; 605 oldUser.LastName = last;
476 } 606 }
607 oldUser.HomeURL = homeURL;
608 oldUser.Id = uuid;
609 m_UserCache.Add(uuid, oldUser);
477 } 610 }
611 }
612 }
478 613
479 UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount (m_Scenes [0].RegionInfo.ScopeID, id); 614 public void AddUser(UUID id, string creatorData)
615 {
616 // m_log.InfoFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, creatorData {1}", id, creatorData);
480 617
481 if (account != null) 618 if(string.IsNullOrEmpty(creatorData))
619 {
620 AddUser(id, string.Empty, string.Empty, string.Empty);
621 }
622 else
623 {
624 string homeURL;
625 string firstname = string.Empty;
626 string lastname = string.Empty;
627
628 //creatorData = <endpoint>;<name>
629
630 string[] parts = creatorData.Split(';');
631 if(parts.Length > 1)
482 { 632 {
483 AddUser (id, account.FirstName, account.LastName); 633 string[] nameparts = parts[1].Split(' ');
634 firstname = nameparts[0];
635 for(int xi = 1; xi < nameparts.Length; ++xi)
636 {
637 if(xi != 1)
638 {
639 lastname += " ";
640 }
641 lastname += nameparts[xi];
642 }
484 } 643 }
485 else 644 else
486 { 645 {
487 UserData user = new UserData (); 646 firstname = "Unknown";
488 user.Id = id; 647 lastname = "UserUMMAU5";
489 648 }
490 if (creatorData != null && creatorData != string.Empty) 649 if (parts.Length >= 1)
650 {
651 homeURL = parts[0];
652 if(Uri.IsWellFormedUriString(homeURL, UriKind.Absolute))
653 {
654 AddUser(id, firstname, lastname, homeURL);
655 }
656 else
491 { 657 {
492 //creatorData = <endpoint>;<name> 658 m_log.DebugFormat("[SCENE]: Unable to parse Uri {0} for CreatorID {1}", parts[0], creatorData);
493 659
494 string[] parts = creatorData.Split (';'); 660 lock (m_UserCache)
495 if (parts.Length >= 1)
496 { 661 {
497 user.HomeURL = parts [0]; 662 if(!m_UserCache.ContainsKey(id))
498 try
499 {
500 Uri uri = new Uri (parts [0]);
501 user.LastName = "@" + uri.Authority;
502 }
503 catch (UriFormatException)
504 { 663 {
505 m_log.DebugFormat ("[SCENE]: Unable to parse Uri {0}", parts [0]); 664 UserData newUser = new UserData();
506 user.LastName = "@unknown"; 665 newUser.Id = id;
666 newUser.FirstName = firstname + "." + lastname.Replace(' ', '.');
667 newUser.LastName = "@unknown";
668 newUser.HomeURL = string.Empty;
669 newUser.HasGridUserTried = false;
670 newUser.IsUnknownUser = true; /* we mark those users as Unknown user so a re-retrieve may be activated */
671 m_UserCache.Add(id, newUser);
507 } 672 }
508 } 673 }
509 if (parts.Length >= 2)
510 user.FirstName = parts [1].Replace (' ', '.');
511 } 674 }
512 else 675 }
676 else
677 {
678 lock(m_UserCache)
513 { 679 {
514 user.FirstName = "Unknown"; 680 if(!m_UserCache.ContainsKey(id))
515 user.LastName = "User"; 681 {
682 UserData newUser = new UserData();
683 newUser.Id = id;
684 newUser.FirstName = "Unknown";
685 newUser.LastName = "UserUMMAU4";
686 newUser.HomeURL = string.Empty;
687 newUser.IsUnknownUser = true;
688 newUser.HasGridUserTried = false;
689 m_UserCache.Add(id, newUser);
690 }
516 } 691 }
517
518 AddUserInternal (user);
519 } 692 }
520 } 693 }
521 } 694 }
522 695 #endregion
523 void AddUserInternal(UserData user)
524 {
525 lock (m_UserCache)
526 m_UserCache[user.Id] = user;
527
528 //m_log.DebugFormat(
529 // "[USER MANAGEMENT MODULE]: Added user {0} {1} {2} {3}",
530 // user.Id, user.FirstName, user.LastName, user.HomeURL);
531 }
532 696
533 public bool IsLocalGridUser(UUID uuid) 697 public bool IsLocalGridUser(UUID uuid)
534 { 698 {
@@ -541,36 +705,95 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
541 705
542 #endregion IUserManagement 706 #endregion IUserManagement
543 707
708 protected void Init()
709 {
710 AddUser(UUID.Zero, "Unknown", "User");
711 RegisterConsoleCmds();
712 }
713
544 protected void RegisterConsoleCmds() 714 protected void RegisterConsoleCmds()
545 { 715 {
546 MainConsole.Instance.Commands.AddCommand("Users", true, 716 MainConsole.Instance.Commands.AddCommand("Users", true,
717 "show name",
718 "show name <uuid>",
719 "Show the bindings between a single user UUID and a user name",
720 String.Empty,
721 HandleShowUser);
722
723 MainConsole.Instance.Commands.AddCommand("Users", true,
547 "show names", 724 "show names",
548 "show names", 725 "show names",
549 "Show the bindings between user UUIDs and user names", 726 "Show the bindings between user UUIDs and user names",
550 String.Empty, 727 String.Empty,
551 HandleShowUsers); 728 HandleShowUsers);
729
730 MainConsole.Instance.Commands.AddCommand("Users", true,
731 "reset user cache",
732 "reset user cache",
733 "reset user cache to allow changed settings to be applied",
734 String.Empty,
735 HandleResetUserCache);
552 } 736 }
553 737
554 private void HandleShowUsers(string module, string[] cmd) 738 private void HandleResetUserCache(string module, string[] cmd)
555 { 739 {
556 lock (m_UserCache) 740 lock(m_UserCache)
557 { 741 {
558 if (m_UserCache.Count == 0) 742 m_UserCache.Clear();
559 { 743 }
560 MainConsole.Instance.Output("No users found"); 744 }
561 return; 745
562 } 746 private void HandleShowUser(string module, string[] cmd)
563 747 {
564 MainConsole.Instance.Output("UUID User Name"); 748 if (cmd.Length < 3)
565 MainConsole.Instance.Output("-----------------------------------------------------------------------------"); 749 {
566 foreach (KeyValuePair<UUID, UserData> kvp in m_UserCache) 750 MainConsole.Instance.OutputFormat("Usage: show name <uuid>");
567 {
568 MainConsole.Instance.Output(String.Format("{0} {1} {2} ({3})",
569 kvp.Key, kvp.Value.FirstName, kvp.Value.LastName, kvp.Value.HomeURL));
570 }
571
572 return; 751 return;
573 } 752 }
753
754 UUID userId;
755 if (!ConsoleUtil.TryParseConsoleUuid(MainConsole.Instance, cmd[2], out userId))
756 return;
757
758 UserData ud;
759
760 if(!GetUser(userId, out ud))
761 {
762 MainConsole.Instance.OutputFormat("No name known for user with id {0}", userId);
763 return;
764 }
765
766 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
767 cdt.AddColumn("UUID", 36);
768 cdt.AddColumn("Name", 30);
769 cdt.AddColumn("HomeURL", 40);
770 cdt.AddRow(userId, string.Format("{0} {1}", ud.FirstName, ud.LastName), ud.HomeURL);
771
772 MainConsole.Instance.Output(cdt.ToString());
574 } 773 }
774
775 private void HandleShowUsers(string module, string[] cmd)
776 {
777 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
778 cdt.AddColumn("UUID", 36);
779 cdt.AddColumn("Name", 30);
780 cdt.AddColumn("HomeURL", 40);
781 cdt.AddColumn("Checked", 10);
782
783 Dictionary<UUID, UserData> copyDict;
784 lock(m_UserCache)
785 {
786 copyDict = new Dictionary<UUID, UserData>(m_UserCache);
787 }
788
789 foreach(KeyValuePair<UUID, UserData> kvp in copyDict)
790 {
791 cdt.AddRow(kvp.Key, string.Format("{0} {1}", kvp.Value.FirstName, kvp.Value.LastName), kvp.Value.HomeURL, kvp.Value.HasGridUserTried ? "yes" : "no");
792 }
793
794 MainConsole.Instance.Output(cdt.ToString());
795 }
796
575 } 797 }
576} \ No newline at end of file 798
799}
diff --git a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs
index e0921ad..ea5b34e 100644
--- a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs
+++ b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs
@@ -31,11 +31,13 @@ using System.Reflection;
31using log4net; 31using log4net;
32using Nini.Config; 32using Nini.Config;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenMetaverse.StructuredData;
34using Mono.Addins; 35using Mono.Addins;
35using OpenSim.Framework; 36using OpenSim.Framework;
36using OpenSim.Region.CoreModules.World.WorldMap; 37using OpenSim.Region.CoreModules.World.WorldMap;
37using OpenSim.Region.Framework.Interfaces; 38using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
39using GridRegion = OpenSim.Services.Interfaces.GridRegion; 41using GridRegion = OpenSim.Services.Interfaces.GridRegion;
40 42
41namespace OpenSim.Region.CoreModules.Hypergrid 43namespace OpenSim.Region.CoreModules.Hypergrid
@@ -48,20 +50,63 @@ namespace OpenSim.Region.CoreModules.Hypergrid
48 // Remember the map area that each client has been exposed to in this region 50 // Remember the map area that each client has been exposed to in this region
49 private Dictionary<UUID, List<MapBlockData>> m_SeenMapBlocks = new Dictionary<UUID, List<MapBlockData>>(); 51 private Dictionary<UUID, List<MapBlockData>> m_SeenMapBlocks = new Dictionary<UUID, List<MapBlockData>>();
50 52
53 private string m_MapImageServerURL = string.Empty;
54
55 private IUserManagement m_UserManagement;
56
51 #region INonSharedRegionModule Members 57 #region INonSharedRegionModule Members
52 58
53 public override void Initialise(IConfigSource config) 59 public override void Initialise(IConfigSource source)
54 { 60 {
55 IConfig startupConfig = config.Configs["Startup"]; 61 if (Util.GetConfigVarFromSections<string>(
56 if (startupConfig.GetString("WorldMapModule", "WorldMap") == "HGWorldMap") 62 source, "WorldMapModule", new string[] { "Map", "Startup" }, "WorldMap") == "HGWorldMap")
63 {
57 m_Enabled = true; 64 m_Enabled = true;
65
66 m_MapImageServerURL = Util.GetConfigVarFromSections<string>(source, "MapTileURL", new string[] {"LoginService", "HGWorldMap", "SimulatorFeatures"});
67
68 if (!string.IsNullOrEmpty(m_MapImageServerURL))
69 {
70 m_MapImageServerURL = m_MapImageServerURL.Trim();
71 if (!m_MapImageServerURL.EndsWith("/"))
72 m_MapImageServerURL = m_MapImageServerURL + "/";
73 }
74
75
76 }
58 } 77 }
59 78
60 public override void AddRegion(Scene scene) 79 public override void AddRegion(Scene scene)
61 { 80 {
81 if (!m_Enabled)
82 return;
83
62 base.AddRegion(scene); 84 base.AddRegion(scene);
63 85
64 scene.EventManager.OnClientClosed += new EventManager.ClientClosed(EventManager_OnClientClosed); 86 scene.EventManager.OnClientClosed += EventManager_OnClientClosed;
87 }
88
89 public override void RegionLoaded(Scene scene)
90 {
91 if (!m_Enabled)
92 return;
93
94 base.RegionLoaded(scene);
95 ISimulatorFeaturesModule featuresModule = m_scene.RequestModuleInterface<ISimulatorFeaturesModule>();
96
97 if (featuresModule != null)
98 featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest;
99
100 m_UserManagement = m_scene.RequestModuleInterface<IUserManagement>();
101
102 }
103
104 public override void RemoveRegion(Scene scene)
105 {
106 if (!m_Enabled)
107 return;
108
109 scene.EventManager.OnClientClosed -= EventManager_OnClientClosed;
65 } 110 }
66 111
67 public override string Name 112 public override string Name
@@ -82,10 +127,11 @@ namespace OpenSim.Region.CoreModules.Hypergrid
82 foreach (MapBlockData b in mapBlocks) 127 foreach (MapBlockData b in mapBlocks)
83 { 128 {
84 b.Name = string.Empty; 129 b.Name = string.Empty;
85 b.Access = 254; // means 'simulator is offline'. We need this because the viewer ignores 255's 130 // Set 'simulator is offline'. We need this because the viewer ignores SimAccess.Unknown (255)
131 b.Access = (byte)SimAccess.Down;
86 } 132 }
87 133
88 m_log.DebugFormat("[HG MAP]: Reseting {0} blocks", mapBlocks.Count); 134 m_log.DebugFormat("[HG MAP]: Resetting {0} blocks", mapBlocks.Count);
89 sp.ControllingClient.SendMapBlock(mapBlocks, 0); 135 sp.ControllingClient.SendMapBlock(mapBlocks, 0);
90 m_SeenMapBlocks.Remove(clientID); 136 m_SeenMapBlocks.Remove(clientID);
91 } 137 }
@@ -115,6 +161,20 @@ namespace OpenSim.Region.CoreModules.Hypergrid
115 return mapBlocks; 161 return mapBlocks;
116 } 162 }
117 163
164 private void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features)
165 {
166 if (m_UserManagement != null && !string.IsNullOrEmpty(m_MapImageServerURL) && !m_UserManagement.IsLocalGridUser(agentID))
167 {
168 OSD extras = new OSDMap();
169 if (features.ContainsKey("OpenSimExtras"))
170 extras = features["OpenSimExtras"];
171 else
172 features["OpenSimExtras"] = extras;
173
174 ((OSDMap)extras)["map-server-url"] = m_MapImageServerURL;
175
176 }
177 }
118 } 178 }
119 179
120 class MapArea 180 class MapArea
diff --git a/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs b/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs
index 5a8c4a2..63e3c92 100644
--- a/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs
@@ -30,9 +30,9 @@ using Mono.Addins;
30// Build Number 30// Build Number
31// Revision 31// Revision
32// 32//
33[assembly: AssemblyVersion("0.7.5.*")] 33[assembly: AssemblyVersion("0.8.3.*")]
34[assembly: AssemblyFileVersion("1.0.0.0")]
35 34
36[assembly: Addin("OpenSim.Region.CoreModules", "0.1")] 35
37[assembly: AddinDependency("OpenSim", "0.5")] 36[assembly: Addin("OpenSim.Region.CoreModules", OpenSim.VersionInfo.VersionNumber)]
37[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
38 38
diff --git a/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs
index 9d77b19..a686a4d 100644
--- a/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/DynamicTexture/DynamicTextureModule.cs
@@ -514,9 +514,11 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
514 scene.RegionInfo.RegionID.ToString()); 514 scene.RegionInfo.RegionID.ToString());
515 asset.Data = assetData; 515 asset.Data = assetData;
516 asset.Description = String.Format("URL image : {0}", Url); 516 asset.Description = String.Format("URL image : {0}", Url);
517 asset.Local = false; 517 if (asset.Description.Length > 128)
518 asset.Description = asset.Description.Substring(0, 128);
519 asset.Local = true; // dynamic images aren't saved in the assets server
518 asset.Temporary = ((Disp & DISP_TEMP) != 0); 520 asset.Temporary = ((Disp & DISP_TEMP) != 0);
519 scene.AssetService.Store(asset); 521 scene.AssetService.Store(asset); // this will only save the asset in the local asset cache
520 522
521 IJ2KDecoder cacheLayerDecode = scene.RequestModuleInterface<IJ2KDecoder>(); 523 IJ2KDecoder cacheLayerDecode = scene.RequestModuleInterface<IJ2KDecoder>();
522 if (cacheLayerDecode != null) 524 if (cacheLayerDecode != null)
diff --git a/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs b/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs
index d943b20..4e7ad75 100644
--- a/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs
@@ -213,8 +213,8 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules
213 if (part != null) 213 if (part != null)
214 { 214 {
215 ObjectRegionName = s.RegionInfo.RegionName; 215 ObjectRegionName = s.RegionInfo.RegionName;
216 uint localX = (s.RegionInfo.RegionLocX * (int)Constants.RegionSize); 216 uint localX = s.RegionInfo.WorldLocX;
217 uint localY = (s.RegionInfo.RegionLocY * (int)Constants.RegionSize); 217 uint localY = s.RegionInfo.WorldLocY;
218 ObjectRegionName = ObjectRegionName + " (" + localX + ", " + localY + ")"; 218 ObjectRegionName = ObjectRegionName + " (" + localX + ", " + localY + ")";
219 return part; 219 return part;
220 } 220 }
diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
index a676971..9dfeb96 100644
--- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
+++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
@@ -28,12 +28,15 @@
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.IO; 30using System.IO;
31using System.Linq;
31using System.Net; 32using System.Net;
32using System.Net.Mail; 33using System.Net.Mail;
33using System.Net.Security; 34using System.Net.Security;
35using System.Reflection;
34using System.Text; 36using System.Text;
35using System.Threading; 37using System.Threading;
36using System.Security.Cryptography.X509Certificates; 38using System.Security.Cryptography.X509Certificates;
39using log4net;
37using Nini.Config; 40using Nini.Config;
38using OpenMetaverse; 41using OpenMetaverse;
39using OpenSim.Framework; 42using OpenSim.Framework;
@@ -91,10 +94,13 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
91 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "HttpRequestModule")] 94 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "HttpRequestModule")]
92 public class HttpRequestModule : ISharedRegionModule, IHttpRequestModule 95 public class HttpRequestModule : ISharedRegionModule, IHttpRequestModule
93 { 96 {
97// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
98
94 private object HttpListLock = new object(); 99 private object HttpListLock = new object();
95 private int httpTimeout = 30000; 100 private int httpTimeout = 30000;
96 private string m_name = "HttpScriptRequests"; 101 private string m_name = "HttpScriptRequests";
97 102
103 private OutboundUrlFilter m_outboundUrlFilter;
98 private string m_proxyurl = ""; 104 private string m_proxyurl = "";
99 private string m_proxyexcepts = ""; 105 private string m_proxyexcepts = "";
100 106
@@ -132,10 +138,12 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
132 return false; 138 return false;
133 139
134 // Check for policy and execute it if defined 140 // Check for policy and execute it if defined
141#pragma warning disable 0618
135 if (ServicePointManager.CertificatePolicy != null) 142 if (ServicePointManager.CertificatePolicy != null)
136 { 143 {
137 return ServicePointManager.CertificatePolicy.CheckValidationResult (sp, certificate, Request, 0); 144 return ServicePointManager.CertificatePolicy.CheckValidationResult (sp, certificate, Request, 0);
138 } 145 }
146#pragma warning restore 0618
139 147
140 return true; 148 return true;
141 } 149 }
@@ -153,7 +161,9 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
153 return UUID.Zero; 161 return UUID.Zero;
154 } 162 }
155 163
156 public UUID StartHttpRequest(uint localID, UUID itemID, string url, List<string> parameters, Dictionary<string, string> headers, string body) 164 public UUID StartHttpRequest(
165 uint localID, UUID itemID, string url, List<string> parameters, Dictionary<string, string> headers, string body,
166 out HttpInitialRequestStatus status)
157 { 167 {
158 UUID reqID = UUID.Random(); 168 UUID reqID = UUID.Random();
159 HttpRequestClass htc = new HttpRequestClass(); 169 HttpRequestClass htc = new HttpRequestClass();
@@ -187,10 +197,50 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
187 case (int)HttpRequestConstants.HTTP_VERIFY_CERT: 197 case (int)HttpRequestConstants.HTTP_VERIFY_CERT:
188 htc.HttpVerifyCert = (int.Parse(parms[i + 1]) != 0); 198 htc.HttpVerifyCert = (int.Parse(parms[i + 1]) != 0);
189 break; 199 break;
200
201 case (int)HttpRequestConstants.HTTP_VERBOSE_THROTTLE:
202
203 // TODO implement me
204 break;
205
206 case (int)HttpRequestConstants.HTTP_CUSTOM_HEADER:
207 //Parameters are in pairs and custom header takes
208 //arguments in pairs so adjust for header marker.
209 ++i;
210
211 //Maximum of 8 headers are allowed based on the
212 //Second Life documentation for llHTTPRequest.
213 for (int count = 1; count <= 8; ++count)
214 {
215 //Not enough parameters remaining for a header?
216 if (parms.Length - i < 2)
217 break;
218
219 //Have we reached the end of the list of headers?
220 //End is marked by a string with a single digit.
221 //We already know we have at least one parameter
222 //so it is safe to do this check at top of loop.
223 if (Char.IsDigit(parms[i][0]))
224 break;
225
226 if (htc.HttpCustomHeaders == null)
227 htc.HttpCustomHeaders = new List<string>();
228
229 htc.HttpCustomHeaders.Add(parms[i]);
230 htc.HttpCustomHeaders.Add(parms[i+1]);
231
232 i += 2;
233 }
234 break;
235
236 case (int)HttpRequestConstants.HTTP_PRAGMA_NO_CACHE:
237 htc.HttpPragmaNoCache = (int.Parse(parms[i + 1]) != 0);
238 break;
190 } 239 }
191 } 240 }
192 } 241 }
193 242
243 htc.RequestModule = this;
194 htc.LocalID = localID; 244 htc.LocalID = localID;
195 htc.ItemID = itemID; 245 htc.ItemID = itemID;
196 htc.Url = url; 246 htc.Url = url;
@@ -201,28 +251,68 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
201 htc.proxyurl = m_proxyurl; 251 htc.proxyurl = m_proxyurl;
202 htc.proxyexcepts = m_proxyexcepts; 252 htc.proxyexcepts = m_proxyexcepts;
203 253
254 // Same number as default HttpWebRequest.MaximumAutomaticRedirections
255 htc.MaxRedirects = 50;
256
257 if (StartHttpRequest(htc))
258 {
259 status = HttpInitialRequestStatus.OK;
260 return htc.ReqID;
261 }
262 else
263 {
264 status = HttpInitialRequestStatus.DISALLOWED_BY_FILTER;
265 return UUID.Zero;
266 }
267 }
268
269 /// <summary>
270 /// Would a caller to this module be allowed to make a request to the given URL?
271 /// </summary>
272 /// <returns></returns>
273 public bool CheckAllowed(Uri url)
274 {
275 return m_outboundUrlFilter.CheckAllowed(url);
276 }
277
278 public bool StartHttpRequest(HttpRequestClass req)
279 {
280 if (!CheckAllowed(new Uri(req.Url)))
281 return false;
282
204 lock (HttpListLock) 283 lock (HttpListLock)
205 { 284 {
206 m_pendingRequests.Add(reqID, htc); 285 m_pendingRequests.Add(req.ReqID, req);
207 } 286 }
208 287
209 htc.Process(); 288 req.Process();
210 289
211 return reqID; 290 return true;
212 } 291 }
213 292
214 public void StopHttpRequest(uint m_localID, UUID m_itemID) 293 public void StopHttpRequestsForScript(UUID id)
215 { 294 {
216 if (m_pendingRequests != null) 295 if (m_pendingRequests != null)
217 { 296 {
297 List<UUID> keysToRemove = null;
298
218 lock (HttpListLock) 299 lock (HttpListLock)
219 { 300 {
220 HttpRequestClass tmpReq; 301 foreach (HttpRequestClass req in m_pendingRequests.Values)
221 if (m_pendingRequests.TryGetValue(m_itemID, out tmpReq))
222 { 302 {
223 tmpReq.Stop(); 303 if (req.ItemID == id)
224 m_pendingRequests.Remove(m_itemID); 304 {
305 req.Stop();
306
307 if (keysToRemove == null)
308 keysToRemove = new List<UUID>();
309
310 keysToRemove.Add(req.ReqID);
311 }
225 } 312 }
313
314 if (keysToRemove != null)
315 keysToRemove.ForEach(keyToRemove => m_pendingRequests.Remove(keyToRemove));
226 } 316 }
227 } 317 }
228 } 318 }
@@ -240,19 +330,13 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
240 { 330 {
241 lock (HttpListLock) 331 lock (HttpListLock)
242 { 332 {
243 foreach (UUID luid in m_pendingRequests.Keys) 333 foreach (HttpRequestClass req in m_pendingRequests.Values)
244 { 334 {
245 HttpRequestClass tmpReq; 335 if (req.Finished)
246 336 return req;
247 if (m_pendingRequests.TryGetValue(luid, out tmpReq))
248 {
249 if (tmpReq.Finished)
250 {
251 return tmpReq;
252 }
253 }
254 } 337 }
255 } 338 }
339
256 return null; 340 return null;
257 } 341 }
258 342
@@ -279,6 +363,8 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
279 m_proxyurl = config.Configs["Startup"].GetString("HttpProxy"); 363 m_proxyurl = config.Configs["Startup"].GetString("HttpProxy");
280 m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions"); 364 m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions");
281 365
366 m_outboundUrlFilter = new OutboundUrlFilter("Script HTTP request module", config);
367
282 m_pendingRequests = new Dictionary<UUID, HttpRequestClass>(); 368 m_pendingRequests = new Dictionary<UUID, HttpRequestClass>();
283 } 369 }
284 370
@@ -321,16 +407,27 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
321 #endregion 407 #endregion
322 } 408 }
323 409
324 public class HttpRequestClass: IServiceRequest 410 public class HttpRequestClass : IServiceRequest
325 { 411 {
412// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
413
326 // Constants for parameters 414 // Constants for parameters
327 // public const int HTTP_BODY_MAXLENGTH = 2; 415 // public const int HTTP_BODY_MAXLENGTH = 2;
328 // public const int HTTP_METHOD = 0; 416 // public const int HTTP_METHOD = 0;
329 // public const int HTTP_MIMETYPE = 1; 417 // public const int HTTP_MIMETYPE = 1;
330 // public const int HTTP_VERIFY_CERT = 3; 418 // public const int HTTP_VERIFY_CERT = 3;
419 // public const int HTTP_VERBOSE_THROTTLE = 4;
420 // public const int HTTP_CUSTOM_HEADER = 5;
421 // public const int HTTP_PRAGMA_NO_CACHE = 6;
422
423 /// <summary>
424 /// Module that made this request.
425 /// </summary>
426 public HttpRequestModule RequestModule { get; set; }
427
331 private bool _finished; 428 private bool _finished;
332 public bool Finished 429 public bool Finished
333 { 430 {
334 get { return _finished; } 431 get { return _finished; }
335 } 432 }
336 // public int HttpBodyMaxLen = 2048; // not implemented 433 // public int HttpBodyMaxLen = 2048; // not implemented
@@ -340,11 +437,13 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
340 public string HttpMIMEType = "text/plain;charset=utf-8"; 437 public string HttpMIMEType = "text/plain;charset=utf-8";
341 public int HttpTimeout; 438 public int HttpTimeout;
342 public bool HttpVerifyCert = true; 439 public bool HttpVerifyCert = true;
343 private Thread httpThread; 440 //public bool HttpVerboseThrottle = true; // not implemented
441 public List<string> HttpCustomHeaders = null;
442 public bool HttpPragmaNoCache = true;
344 443
345 // Request info 444 // Request info
346 private UUID _itemID; 445 private UUID _itemID;
347 public UUID ItemID 446 public UUID ItemID
348 { 447 {
349 get { return _itemID; } 448 get { return _itemID; }
350 set { _itemID = value; } 449 set { _itemID = value; }
@@ -358,9 +457,20 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
358 public DateTime Next; 457 public DateTime Next;
359 public string proxyurl; 458 public string proxyurl;
360 public string proxyexcepts; 459 public string proxyexcepts;
460
461 /// <summary>
462 /// Number of HTTP redirects that this request has been through.
463 /// </summary>
464 public int Redirects { get; private set; }
465
466 /// <summary>
467 /// Maximum number of HTTP redirects allowed for this request.
468 /// </summary>
469 public int MaxRedirects { get; set; }
470
361 public string OutboundBody; 471 public string OutboundBody;
362 private UUID _reqID; 472 private UUID _reqID;
363 public UUID ReqID 473 public UUID ReqID
364 { 474 {
365 get { return _reqID; } 475 get { return _reqID; }
366 set { _reqID = value; } 476 set { _reqID = value; }
@@ -374,34 +484,19 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
374 484
375 public void Process() 485 public void Process()
376 { 486 {
377 httpThread = new Thread(SendRequest); 487 SendRequest();
378 httpThread.Name = "HttpRequestThread";
379 httpThread.Priority = ThreadPriority.BelowNormal;
380 httpThread.IsBackground = true;
381 _finished = false;
382 httpThread.Start();
383 } 488 }
384 489
385 /*
386 * TODO: More work on the response codes. Right now
387 * returning 200 for success or 499 for exception
388 */
389
390 public void SendRequest() 490 public void SendRequest()
391 { 491 {
392 HttpWebResponse response = null;
393 StringBuilder sb = new StringBuilder();
394 byte[] buf = new byte[8192];
395 string tempString = null;
396 int count = 0;
397
398 try 492 try
399 { 493 {
400 Request = (HttpWebRequest) WebRequest.Create(Url); 494 Request = (HttpWebRequest)WebRequest.Create(Url);
495 Request.AllowAutoRedirect = false;
401 Request.Method = HttpMethod; 496 Request.Method = HttpMethod;
402 Request.ContentType = HttpMIMEType; 497 Request.ContentType = HttpMIMEType;
403 498
404 if(!HttpVerifyCert) 499 if (!HttpVerifyCert)
405 { 500 {
406 // We could hijack Connection Group Name to identify 501 // We could hijack Connection Group Name to identify
407 // a desired security exception. But at the moment we'll use a dummy header instead. 502 // a desired security exception. But at the moment we'll use a dummy header instead.
@@ -412,41 +507,57 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
412// { 507// {
413// Request.ConnectionGroupName="Verify"; 508// Request.ConnectionGroupName="Verify";
414// } 509// }
415 if (proxyurl != null && proxyurl.Length > 0) 510
511 if (!HttpPragmaNoCache)
512 {
513 Request.Headers.Add("Pragma", "no-cache");
514 }
515
516 if (HttpCustomHeaders != null)
517 {
518 for (int i = 0; i < HttpCustomHeaders.Count; i += 2)
519 Request.Headers.Add(HttpCustomHeaders[i],
520 HttpCustomHeaders[i+1]);
521 }
522
523 if (!string.IsNullOrEmpty(proxyurl))
416 { 524 {
417 if (proxyexcepts != null && proxyexcepts.Length > 0) 525 if (!string.IsNullOrEmpty(proxyexcepts))
418 { 526 {
419 string[] elist = proxyexcepts.Split(';'); 527 string[] elist = proxyexcepts.Split(';');
420 Request.Proxy = new WebProxy(proxyurl, true, elist); 528 Request.Proxy = new WebProxy(proxyurl, true, elist);
421 } 529 }
422 else 530 else
423 { 531 {
424 Request.Proxy = new WebProxy(proxyurl, true); 532 Request.Proxy = new WebProxy(proxyurl, true);
425 } 533 }
426 } 534 }
427 535
428 foreach (KeyValuePair<string, string> entry in ResponseHeaders) 536 if (ResponseHeaders != null)
429 if (entry.Key.ToLower().Equals("user-agent")) 537 {
430 Request.UserAgent = entry.Value; 538 foreach (KeyValuePair<string, string> entry in ResponseHeaders)
431 else 539 if (entry.Key.ToLower().Equals("user-agent") && Request is HttpWebRequest)
432 Request.Headers[entry.Key] = entry.Value; 540 ((HttpWebRequest)Request).UserAgent = entry.Value;
541 else
542 Request.Headers[entry.Key] = entry.Value;
543 }
433 544
434 // Encode outbound data 545 // Encode outbound data
435 if (OutboundBody.Length > 0) 546 if (!string.IsNullOrEmpty(OutboundBody))
436 { 547 {
437 byte[] data = Util.UTF8.GetBytes(OutboundBody); 548 byte[] data = Util.UTF8.GetBytes(OutboundBody);
438 549
439 Request.ContentLength = data.Length; 550 Request.ContentLength = data.Length;
440 Stream bstream = Request.GetRequestStream(); 551 using (Stream bstream = Request.GetRequestStream())
441 bstream.Write(data, 0, data.Length); 552 bstream.Write(data, 0, data.Length);
442 bstream.Close();
443 } 553 }
444 554
445 Request.Timeout = HttpTimeout;
446 try 555 try
447 { 556 {
448 // execute the request 557 IAsyncResult result = (IAsyncResult)Request.BeginGetResponse(ResponseCallback, null);
449 response = (HttpWebResponse) Request.GetResponse(); 558
559 ThreadPool.RegisterWaitForSingleObject(
560 result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), null, HttpTimeout, true);
450 } 561 }
451 catch (WebException e) 562 catch (WebException e)
452 { 563 {
@@ -454,57 +565,127 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
454 { 565 {
455 throw; 566 throw;
456 } 567 }
457 response = (HttpWebResponse)e.Response; 568
569 HttpWebResponse response = (HttpWebResponse)e.Response;
570
571 Status = (int)response.StatusCode;
572 ResponseBody = response.StatusDescription;
573 _finished = true;
458 } 574 }
575 }
576 catch (Exception e)
577 {
578// m_log.Debug(
579// string.Format("[SCRIPTS HTTP REQUESTS]: Exception on request to {0} for {1} ", Url, ItemID), e);
459 580
460 Status = (int)response.StatusCode; 581 Status = (int)OSHttpStatusCode.ClientErrorJoker;
582 ResponseBody = e.Message;
583 _finished = true;
584 }
585 }
461 586
462 Stream resStream = response.GetResponseStream(); 587 private void ResponseCallback(IAsyncResult ar)
588 {
589 HttpWebResponse response = null;
463 590
464 do 591 try
592 {
593 try
465 { 594 {
466 // fill the buffer with data 595 response = (HttpWebResponse)Request.EndGetResponse(ar);
467 count = resStream.Read(buf, 0, buf.Length); 596 }
468 597 catch (WebException e)
469 // make sure we read some data 598 {
470 if (count != 0) 599 if (e.Status != WebExceptionStatus.ProtocolError)
471 { 600 {
472 // translate from bytes to ASCII text 601 throw;
473 tempString = Util.UTF8.GetString(buf, 0, count);
474
475 // continue building the string
476 sb.Append(tempString);
477 } 602 }
478 } while (count > 0); // any more data to read?
479 603
480 ResponseBody = sb.ToString(); 604 response = (HttpWebResponse)e.Response;
605 }
606
607 Status = (int)response.StatusCode;
608
609 using (Stream stream = response.GetResponseStream())
610 {
611 StreamReader reader = new StreamReader(stream, Encoding.UTF8);
612 ResponseBody = reader.ReadToEnd();
613 }
481 } 614 }
482 catch (Exception e) 615 catch (Exception e)
483 { 616 {
484 Status = (int)OSHttpStatusCode.ClientErrorJoker; 617 Status = (int)OSHttpStatusCode.ClientErrorJoker;
485 ResponseBody = e.Message; 618 ResponseBody = e.Message;
486 619
487 _finished = true; 620// m_log.Debug(
488 return; 621// string.Format("[SCRIPTS HTTP REQUESTS]: Exception on response to {0} for {1} ", Url, ItemID), e);
489 } 622 }
490 finally 623 finally
491 { 624 {
492 if (response != null) 625 if (response != null)
493 response.Close(); 626 response.Close();
627
628 // We need to resubmit
629 if (
630 (Status == (int)HttpStatusCode.MovedPermanently
631 || Status == (int)HttpStatusCode.Found
632 || Status == (int)HttpStatusCode.SeeOther
633 || Status == (int)HttpStatusCode.TemporaryRedirect))
634 {
635 if (Redirects >= MaxRedirects)
636 {
637 Status = (int)OSHttpStatusCode.ClientErrorJoker;
638 ResponseBody = "Number of redirects exceeded max redirects";
639 _finished = true;
640 }
641 else
642 {
643 string location = response.Headers["Location"];
644
645 if (location == null)
646 {
647 Status = (int)OSHttpStatusCode.ClientErrorJoker;
648 ResponseBody = "HTTP redirect code but no location header";
649 _finished = true;
650 }
651 else if (!RequestModule.CheckAllowed(new Uri(location)))
652 {
653 Status = (int)OSHttpStatusCode.ClientErrorJoker;
654 ResponseBody = "URL from HTTP redirect blocked: " + location;
655 _finished = true;
656 }
657 else
658 {
659 Status = 0;
660 Url = response.Headers["Location"];
661 Redirects++;
662 ResponseBody = null;
663
664// m_log.DebugFormat("Redirecting to [{0}]", Url);
665
666 Process();
667 }
668 }
669 }
670 else
671 {
672 _finished = true;
673 }
494 } 674 }
675 }
495 676
496 _finished = true; 677 private void TimeoutCallback(object state, bool timedOut)
678 {
679 if (timedOut)
680 Request.Abort();
497 } 681 }
498 682
499 public void Stop() 683 public void Stop()
500 { 684 {
501 try 685// m_log.DebugFormat("[SCRIPTS HTTP REQUESTS]: Stopping request to {0} for {1} ", Url, ItemID);
502 { 686
503 httpThread.Abort(); 687 if (Request != null)
504 } 688 Request.Abort();
505 catch (Exception)
506 {
507 }
508 } 689 }
509 } 690 }
510} 691} \ 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
new file mode 100644
index 0000000..d22487e
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs
@@ -0,0 +1,199 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Net;
32using System.Reflection;
33using System.Runtime.Serialization;
34using System.Text;
35using System.Threading;
36using log4net.Config;
37using NUnit.Framework;
38using OpenMetaverse;
39using OpenMetaverse.Assets;
40using OpenSim.Framework;
41using OpenSim.Region.CoreModules.Scripting.HttpRequest;
42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Tests.Common;
44
45namespace OpenSim.Region.CoreModules.Scripting.HttpRequest.Tests
46{
47 class TestWebRequestCreate : IWebRequestCreate
48 {
49 public TestWebRequest NextRequest { get; set; }
50
51 public WebRequest Create(Uri uri)
52 {
53// NextRequest.RequestUri = uri;
54
55 return NextRequest;
56
57// return new TestWebRequest(new SerializationInfo(typeof(TestWebRequest), new FormatterConverter()), new StreamingContext());
58 }
59 }
60
61 class TestWebRequest : WebRequest
62 {
63 public override string ContentType { get; set; }
64 public override string Method { get; set; }
65
66 public Func<IAsyncResult, WebResponse> OnEndGetResponse { get; set; }
67
68 public TestWebRequest() : base()
69 {
70// Console.WriteLine("created");
71 }
72
73// public TestWebRequest(SerializationInfo serializationInfo, StreamingContext streamingContext)
74// : base(serializationInfo, streamingContext)
75// {
76// Console.WriteLine("created");
77// }
78
79 public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state)
80 {
81// Console.WriteLine("bish");
82 TestAsyncResult tasr = new TestAsyncResult();
83 callback(tasr);
84
85 return tasr;
86 }
87
88 public override WebResponse EndGetResponse(IAsyncResult asyncResult)
89 {
90// Console.WriteLine("bosh");
91 return OnEndGetResponse(asyncResult);
92 }
93 }
94
95 class TestHttpWebResponse : HttpWebResponse
96 {
97 public string Response { get; set; }
98
99#pragma warning disable 0618
100 public TestHttpWebResponse(SerializationInfo serializationInfo, StreamingContext streamingContext)
101 : base(serializationInfo, streamingContext) {}
102#pragma warning restore 0618
103
104 public override Stream GetResponseStream()
105 {
106 return new MemoryStream(Encoding.UTF8.GetBytes(Response));
107 }
108 }
109
110 class TestAsyncResult : IAsyncResult
111 {
112 WaitHandle m_wh = new ManualResetEvent(true);
113
114 object IAsyncResult.AsyncState
115 {
116 get {
117 throw new System.NotImplementedException ();
118 }
119 }
120
121 WaitHandle IAsyncResult.AsyncWaitHandle
122 {
123 get { return m_wh; }
124 }
125
126 bool IAsyncResult.CompletedSynchronously
127 {
128 get { return false; }
129 }
130
131 bool IAsyncResult.IsCompleted
132 {
133 get { return true; }
134 }
135 }
136
137 /// <summary>
138 /// Test script http request code.
139 /// </summary>
140 /// <remarks>
141 /// This class uses some very hacky workarounds in order to mock HttpWebResponse which are Mono dependent (though
142 /// alternative code can be written to make this work for Windows). However, the value of being able to
143 /// regression test this kind of code is very high.
144 /// </remarks>
145 [TestFixture]
146 public class ScriptsHttpRequestsTests : OpenSimTestCase
147 {
148 /// <summary>
149 /// Test what happens when we get a 404 response from a call.
150 /// </summary>
151// [Test]
152 public void Test404Response()
153 {
154 TestHelpers.InMethod();
155 TestHelpers.EnableLogging();
156
157 if (!Util.IsPlatformMono)
158 Assert.Ignore("Ignoring test since can only currently run on Mono");
159
160 string rawResponse = "boom";
161
162 TestWebRequestCreate twrc = new TestWebRequestCreate();
163
164 TestWebRequest twr = new TestWebRequest();
165 //twr.OnEndGetResponse += ar => new TestHttpWebResponse(null, new StreamingContext());
166 twr.OnEndGetResponse += ar =>
167 {
168 SerializationInfo si = new SerializationInfo(typeof(HttpWebResponse), new FormatterConverter());
169 StreamingContext sc = new StreamingContext();
170// WebHeaderCollection headers = new WebHeaderCollection();
171// si.AddValue("m_HttpResponseHeaders", headers);
172 si.AddValue("uri", new Uri("test://arrg"));
173// si.AddValue("m_Certificate", null);
174 si.AddValue("version", HttpVersion.Version11);
175 si.AddValue("statusCode", HttpStatusCode.NotFound);
176 si.AddValue("contentLength", 0);
177 si.AddValue("method", "GET");
178 si.AddValue("statusDescription", "Not Found");
179 si.AddValue("contentType", null);
180 si.AddValue("cookieCollection", new CookieCollection());
181
182 TestHttpWebResponse thwr = new TestHttpWebResponse(si, sc);
183 thwr.Response = rawResponse;
184
185 throw new WebException("no message", null, WebExceptionStatus.ProtocolError, thwr);
186 };
187
188 twrc.NextRequest = twr;
189
190 WebRequest.RegisterPrefix("test", twrc);
191 HttpRequestClass hr = new HttpRequestClass();
192 hr.Url = "test://something";
193 hr.SendRequest();
194
195 Assert.That(hr.Status, Is.EqualTo((int)HttpStatusCode.NotFound));
196 Assert.That(hr.ResponseBody, Is.EqualTo(rawResponse));
197 }
198 }
199} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
index a654477..99a3122 100644
--- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
@@ -117,20 +117,21 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
117 /// </summary> 117 /// </summary>
118 private Dictionary<string, UrlData> m_UrlMap = new Dictionary<string, UrlData>(); 118 private Dictionary<string, UrlData> m_UrlMap = new Dictionary<string, UrlData>();
119 119
120 /// <summary> 120 private uint m_HttpsPort = 0;
121 /// Maximum number of external urls that can be set up by this module.
122 /// </summary>
123 private int m_TotalUrls = 100;
124
125 private uint https_port = 0;
126 private IHttpServer m_HttpServer = null; 121 private IHttpServer m_HttpServer = null;
127 private IHttpServer m_HttpsServer = null; 122 private IHttpServer m_HttpsServer = null;
128 123
129 private string m_ExternalHostNameForLSL = ""; 124 public string ExternalHostNameForLSL { get; private set; }
130 public string ExternalHostNameForLSL 125
131 { 126 /// <summary>
132 get { return m_ExternalHostNameForLSL; } 127 /// The default maximum number of urls
133 } 128 /// </summary>
129 public const int DefaultTotalUrls = 100;
130
131 /// <summary>
132 /// Maximum number of external urls that can be set up by this module.
133 /// </summary>
134 public int TotalUrls { get; set; }
134 135
135 public Type ReplaceableInterface 136 public Type ReplaceableInterface
136 { 137 {
@@ -144,16 +145,27 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
144 145
145 public void Initialise(IConfigSource config) 146 public void Initialise(IConfigSource config)
146 { 147 {
147 m_ExternalHostNameForLSL = config.Configs["Network"].GetString("ExternalHostNameForLSL", System.Environment.MachineName); 148 IConfig networkConfig = config.Configs["Network"];
148 bool ssl_enabled = config.Configs["Network"].GetBoolean("https_listener",false); 149
150 if (networkConfig != null)
151 {
152 ExternalHostNameForLSL = config.Configs["Network"].GetString("ExternalHostNameForLSL", null);
153
154 bool ssl_enabled = config.Configs["Network"].GetBoolean("https_listener", false);
155
156 if (ssl_enabled)
157 m_HttpsPort = (uint)config.Configs["Network"].GetInt("https_port", (int)m_HttpsPort);
158 }
149 159
150 if (ssl_enabled) 160 if (ExternalHostNameForLSL == null)
151 https_port = (uint) config.Configs["Network"].GetInt("https_port",0); 161 ExternalHostNameForLSL = System.Environment.MachineName;
152 162
153 IConfig llFunctionsConfig = config.Configs["LL-Functions"]; 163 IConfig llFunctionsConfig = config.Configs["LL-Functions"];
154 164
155 if (llFunctionsConfig != null) 165 if (llFunctionsConfig != null)
156 m_TotalUrls = llFunctionsConfig.GetInt("max_external_urls_per_simulator", m_TotalUrls); 166 TotalUrls = llFunctionsConfig.GetInt("max_external_urls_per_simulator", DefaultTotalUrls);
167 else
168 TotalUrls = DefaultTotalUrls;
157 } 169 }
158 170
159 public void PostInitialise() 171 public void PostInitialise()
@@ -169,9 +181,9 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
169 m_HttpServer = MainServer.Instance; 181 m_HttpServer = MainServer.Instance;
170 // 182 //
171 // We can use the https if it is enabled 183 // We can use the https if it is enabled
172 if (https_port > 0) 184 if (m_HttpsPort > 0)
173 { 185 {
174 m_HttpsServer = MainServer.GetHttpServer(https_port); 186 m_HttpsServer = MainServer.GetHttpServer(m_HttpsPort);
175 } 187 }
176 } 188 }
177 189
@@ -204,12 +216,12 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
204 216
205 lock (m_UrlMap) 217 lock (m_UrlMap)
206 { 218 {
207 if (m_UrlMap.Count >= m_TotalUrls) 219 if (m_UrlMap.Count >= TotalUrls)
208 { 220 {
209 engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" }); 221 engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" });
210 return urlcode; 222 return urlcode;
211 } 223 }
212 string url = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + "/lslhttp/" + urlcode.ToString() + "/"; 224 string url = "http://" + ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + "/lslhttp/" + urlcode.ToString() + "/";
213 225
214 UrlData urlData = new UrlData(); 226 UrlData urlData = new UrlData();
215 urlData.hostID = host.UUID; 227 urlData.hostID = host.UUID;
@@ -223,9 +235,10 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
223 235
224 string uri = "/lslhttp/" + urlcode.ToString() + "/"; 236 string uri = "/lslhttp/" + urlcode.ToString() + "/";
225 237
226 m_HttpServer.AddPollServiceHTTPHandler( 238 PollServiceEventArgs args
227 uri, 239 = new PollServiceEventArgs(HttpRequestHandler, uri, HasEvents, GetEvents, NoEvents, urlcode, 25000);
228 new PollServiceEventArgs(HttpRequestHandler, HasEvents, GetEvents, NoEvents, urlcode)); 240 args.Type = PollServiceEventArgs.EventType.LslHttp;
241 m_HttpServer.AddPollServiceHTTPHandler(uri, args);
229 242
230 m_log.DebugFormat( 243 m_log.DebugFormat(
231 "[URL MODULE]: Set up incoming request url {0} for {1} in {2} {3}", 244 "[URL MODULE]: Set up incoming request url {0} for {1} in {2} {3}",
@@ -249,12 +262,12 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
249 262
250 lock (m_UrlMap) 263 lock (m_UrlMap)
251 { 264 {
252 if (m_UrlMap.Count >= m_TotalUrls) 265 if (m_UrlMap.Count >= TotalUrls)
253 { 266 {
254 engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" }); 267 engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" });
255 return urlcode; 268 return urlcode;
256 } 269 }
257 string url = "https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + "/lslhttps/" + urlcode.ToString() + "/"; 270 string url = "https://" + ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + "/lslhttps/" + urlcode.ToString() + "/";
258 271
259 UrlData urlData = new UrlData(); 272 UrlData urlData = new UrlData();
260 urlData.hostID = host.UUID; 273 urlData.hostID = host.UUID;
@@ -268,9 +281,10 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
268 281
269 string uri = "/lslhttps/" + urlcode.ToString() + "/"; 282 string uri = "/lslhttps/" + urlcode.ToString() + "/";
270 283
271 m_HttpsServer.AddPollServiceHTTPHandler( 284 PollServiceEventArgs args
272 uri, 285 = new PollServiceEventArgs(HttpRequestHandler, uri, HasEvents, GetEvents, NoEvents, urlcode, 25000);
273 new PollServiceEventArgs(HttpRequestHandler, HasEvents, GetEvents, NoEvents, urlcode)); 286 args.Type = PollServiceEventArgs.EventType.LslHttp;
287 m_HttpsServer.AddPollServiceHTTPHandler(uri, args);
274 288
275 m_log.DebugFormat( 289 m_log.DebugFormat(
276 "[URL MODULE]: Set up incoming secure request url {0} for {1} in {2} {3}", 290 "[URL MODULE]: Set up incoming secure request url {0} for {1} in {2} {3}",
@@ -328,8 +342,22 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
328 if (m_RequestMap.ContainsKey(request)) 342 if (m_RequestMap.ContainsKey(request))
329 { 343 {
330 UrlData urlData = m_RequestMap[request]; 344 UrlData urlData = m_RequestMap[request];
345 string responseBody = body;
346 if (urlData.requests[request].responseType.Equals("text/plain"))
347 {
348 string value;
349 if (urlData.requests[request].headers.TryGetValue("user-agent", out value))
350 {
351 if (value != null && value.IndexOf("MSIE") >= 0)
352 {
353 // wrap the html escaped response if the target client is IE
354 // It ignores "text/plain" if the body is html
355 responseBody = "<html>" + System.Web.HttpUtility.HtmlEncode(body) + "</html>";
356 }
357 }
358 }
331 urlData.requests[request].responseCode = status; 359 urlData.requests[request].responseCode = status;
332 urlData.requests[request].responseBody = body; 360 urlData.requests[request].responseBody = responseBody;
333 //urlData.requests[request].ev.Set(); 361 //urlData.requests[request].ev.Set();
334 urlData.requests[request].requestDone =true; 362 urlData.requests[request].requestDone =true;
335 } 363 }
@@ -363,7 +391,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
363 public int GetFreeUrls() 391 public int GetFreeUrls()
364 { 392 {
365 lock (m_UrlMap) 393 lock (m_UrlMap)
366 return m_TotalUrls - m_UrlMap.Count; 394 return TotalUrls - m_UrlMap.Count;
367 } 395 }
368 396
369 public void ScriptRemoved(UUID itemID) 397 public void ScriptRemoved(UUID itemID)
@@ -490,7 +518,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
490 } 518 }
491 } 519 }
492 520
493 private Hashtable GetEvents(UUID requestID, UUID sessionID, string request) 521 private Hashtable GetEvents(UUID requestID, UUID sessionID)
494 { 522 {
495 Hashtable response; 523 Hashtable response;
496 524
@@ -565,9 +593,9 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
565 string url; 593 string url;
566 594
567 if (is_ssl) 595 if (is_ssl)
568 url = "https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp; 596 url = "https://" + ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp;
569 else 597 else
570 url = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp; 598 url = "http://" + ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp;
571 599
572 // Avoid a race - the request URL may have been released via llRequestUrl() whilst this 600 // Avoid a race - the request URL may have been released via llRequestUrl() whilst this
573 // request was being processed. 601 // request was being processed.
@@ -642,4 +670,4 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
642 ScriptRemoved(itemID); 670 ScriptRemoved(itemID);
643 } 671 }
644 } 672 }
645} \ No newline at end of file 673}
diff --git a/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs b/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs
index 65737fa..d45962f 100644
--- a/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs
@@ -32,6 +32,7 @@ using System.Net;
32using Nini.Config; 32using Nini.Config;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenMetaverse.Imaging; 34using OpenMetaverse.Imaging;
35using OpenSim.Framework;
35using OpenSim.Region.CoreModules.Scripting.DynamicTexture; 36using OpenSim.Region.CoreModules.Scripting.DynamicTexture;
36using OpenSim.Region.Framework.Interfaces; 37using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes; 38using OpenSim.Region.Framework.Scenes;
@@ -50,6 +51,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
50 private Scene m_scene; 51 private Scene m_scene;
51 private IDynamicTextureManager m_textureManager; 52 private IDynamicTextureManager m_textureManager;
52 53
54 private OutboundUrlFilter m_outboundUrlFilter;
53 private string m_proxyurl = ""; 55 private string m_proxyurl = "";
54 private string m_proxyexcepts = ""; 56 private string m_proxyexcepts = "";
55 57
@@ -88,8 +90,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
88 90
89 public bool AsyncConvertUrl(UUID id, string url, string extraParams) 91 public bool AsyncConvertUrl(UUID id, string url, string extraParams)
90 { 92 {
91 MakeHttpRequest(url, id); 93 return MakeHttpRequest(url, id);
92 return true;
93 } 94 }
94 95
95 public bool AsyncConvertData(UUID id, string bodyData, string extraParams) 96 public bool AsyncConvertData(UUID id, string bodyData, string extraParams)
@@ -110,6 +111,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
110 111
111 public void Initialise(IConfigSource config) 112 public void Initialise(IConfigSource config)
112 { 113 {
114 m_outboundUrlFilter = new OutboundUrlFilter("Script dynamic texture image module", config);
113 m_proxyurl = config.Configs["Startup"].GetString("HttpProxy"); 115 m_proxyurl = config.Configs["Startup"].GetString("HttpProxy");
114 m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions"); 116 m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions");
115 } 117 }
@@ -157,13 +159,17 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
157 159
158 #endregion 160 #endregion
159 161
160 private void MakeHttpRequest(string url, UUID requestID) 162 private bool MakeHttpRequest(string url, UUID requestID)
161 { 163 {
162 WebRequest request = HttpWebRequest.Create(url); 164 if (!m_outboundUrlFilter.CheckAllowed(new Uri(url)))
165 return false;
166
167 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
168 request.AllowAutoRedirect = false;
163 169
164 if (m_proxyurl != null && m_proxyurl.Length > 0) 170 if (!string.IsNullOrEmpty(m_proxyurl))
165 { 171 {
166 if (m_proxyexcepts != null && m_proxyexcepts.Length > 0) 172 if (!string.IsNullOrEmpty(m_proxyexcepts))
167 { 173 {
168 string[] elist = m_proxyexcepts.Split(';'); 174 string[] elist = m_proxyexcepts.Split(';');
169 request.Proxy = new WebProxy(m_proxyurl, true, elist); 175 request.Proxy = new WebProxy(m_proxyurl, true, elist);
@@ -174,12 +180,14 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
174 } 180 }
175 } 181 }
176 182
177 RequestState state = new RequestState((HttpWebRequest) request, requestID); 183 RequestState state = new RequestState(request, requestID);
178 // IAsyncResult result = request.BeginGetResponse(new AsyncCallback(HttpRequestReturn), state); 184 // IAsyncResult result = request.BeginGetResponse(new AsyncCallback(HttpRequestReturn), state);
179 request.BeginGetResponse(new AsyncCallback(HttpRequestReturn), state); 185 request.BeginGetResponse(new AsyncCallback(HttpRequestReturn), state);
180 186
181 TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1)); 187 TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1));
182 state.TimeOfRequest = (int) t.TotalSeconds; 188 state.TimeOfRequest = (int) t.TotalSeconds;
189
190 return true;
183 } 191 }
184 192
185 private void HttpRequestReturn(IAsyncResult result) 193 private void HttpRequestReturn(IAsyncResult result)
@@ -195,10 +203,11 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
195 Stream stream = null; 203 Stream stream = null;
196 byte[] imageJ2000 = new byte[0]; 204 byte[] imageJ2000 = new byte[0];
197 Size newSize = new Size(0, 0); 205 Size newSize = new Size(0, 0);
206 HttpWebResponse response = null;
198 207
199 try 208 try
200 { 209 {
201 HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result); 210 response = (HttpWebResponse)request.EndGetResponse(result);
202 if (response != null && response.StatusCode == HttpStatusCode.OK) 211 if (response != null && response.StatusCode == HttpStatusCode.OK)
203 { 212 {
204 stream = response.GetResponseStream(); 213 stream = response.GetResponseStream();
@@ -262,18 +271,32 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
262 finally 271 finally
263 { 272 {
264 if (stream != null) 273 if (stream != null)
265 {
266 stream.Close(); 274 stream.Close();
267 }
268 }
269 275
270 m_log.DebugFormat("[LOADIMAGEURLMODULE]: Returning {0} bytes of image data for request {1}", 276 if (response != null)
271 imageJ2000.Length, state.RequestID); 277 response.Close();
272 278
273 m_textureManager.ReturnData( 279 if (
274 state.RequestID, 280 response.StatusCode == HttpStatusCode.MovedPermanently
275 new OpenSim.Region.CoreModules.Scripting.DynamicTexture.DynamicTexture( 281 || response.StatusCode == HttpStatusCode.Found
276 request.RequestUri, null, imageJ2000, newSize, false)); 282 || response.StatusCode == HttpStatusCode.SeeOther
283 || response.StatusCode == HttpStatusCode.TemporaryRedirect)
284 {
285 string redirectedUrl = response.Headers["Location"];
286
287 MakeHttpRequest(redirectedUrl, state.RequestID);
288 }
289 else
290 {
291 m_log.DebugFormat("[LOADIMAGEURLMODULE]: Returning {0} bytes of image data for request {1}",
292 imageJ2000.Length, state.RequestID);
293
294 m_textureManager.ReturnData(
295 state.RequestID,
296 new OpenSim.Region.CoreModules.Scripting.DynamicTexture.DynamicTexture(
297 request.RequestUri, null, imageJ2000, newSize, false));
298 }
299 }
277 } 300 }
278 301
279 #region Nested type: RequestState 302 #region Nested type: RequestState
diff --git a/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs b/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs
index f6e1d39..6da2222 100644
--- a/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs
@@ -41,10 +41,11 @@ using System.Linq.Expressions;
41namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms 41namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms
42{ 42{
43 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ScriptModuleCommsModule")] 43 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ScriptModuleCommsModule")]
44 class ScriptModuleCommsModule : INonSharedRegionModule, IScriptModuleComms 44 public class ScriptModuleCommsModule : INonSharedRegionModule, IScriptModuleComms
45 { 45 {
46 private static readonly ILog m_log = 46 private static readonly ILog m_log =
47 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 47 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 private static string LogHeader = "[MODULE COMMS]";
48 49
49 private Dictionary<string,object> m_constants = new Dictionary<string,object>(); 50 private Dictionary<string,object> m_constants = new Dictionary<string,object>();
50 51
@@ -148,7 +149,7 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms
148 MethodInfo mi = GetMethodInfoFromType(target.GetType(), meth, true); 149 MethodInfo mi = GetMethodInfoFromType(target.GetType(), meth, true);
149 if (mi == null) 150 if (mi == null)
150 { 151 {
151 m_log.WarnFormat("[MODULE COMMANDS] Failed to register method {0}", meth); 152 m_log.WarnFormat("{0} Failed to register method {1}", LogHeader, meth);
152 return; 153 return;
153 } 154 }
154 155
@@ -163,9 +164,9 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms
163 164
164 public void RegisterScriptInvocation(object target, MethodInfo mi) 165 public void RegisterScriptInvocation(object target, MethodInfo mi)
165 { 166 {
166 m_log.DebugFormat("[MODULE COMMANDS] Register method {0} from type {1}", mi.Name, (target is Type) ? ((Type)target).Name : target.GetType().Name); 167// m_log.DebugFormat("[MODULE COMMANDS] Register method {0} from type {1}", mi.Name, (target is Type) ? ((Type)target).Name : target.GetType().Name);
167 168
168 Type delegateType; 169 Type delegateType = typeof(void);
169 List<Type> typeArgs = mi.GetParameters() 170 List<Type> typeArgs = mi.GetParameters()
170 .Select(p => p.ParameterType) 171 .Select(p => p.ParameterType)
171 .ToList(); 172 .ToList();
@@ -176,8 +177,16 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms
176 } 177 }
177 else 178 else
178 { 179 {
179 typeArgs.Add(mi.ReturnType); 180 try
180 delegateType = Expression.GetFuncType(typeArgs.ToArray()); 181 {
182 typeArgs.Add(mi.ReturnType);
183 delegateType = Expression.GetFuncType(typeArgs.ToArray());
184 }
185 catch (Exception e)
186 {
187 m_log.ErrorFormat("{0} Failed to create function signature. Most likely more than 5 parameters. Method={1}. Error={2}",
188 LogHeader, mi.Name, e);
189 }
181 } 190 }
182 191
183 Delegate fcall; 192 Delegate fcall;
@@ -323,7 +332,7 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms
323 /// </summary> 332 /// </summary>
324 public void RegisterConstant(string cname, object value) 333 public void RegisterConstant(string cname, object value)
325 { 334 {
326 m_log.DebugFormat("[MODULE COMMANDS] register constant <{0}> with value {1}",cname,value.ToString()); 335// m_log.DebugFormat("[MODULE COMMANDS] register constant <{0}> with value {1}",cname,value.ToString());
327 lock (m_constants) 336 lock (m_constants)
328 { 337 {
329 m_constants.Add(cname,value); 338 m_constants.Add(cname,value);
diff --git a/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs b/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs
index 41baccc..ed255bf 100644
--- a/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs
@@ -40,7 +40,6 @@ using OpenSim.Region.CoreModules.Scripting.VectorRender;
40using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
41using OpenSim.Region.Framework.Scenes.Serialization; 41using OpenSim.Region.Framework.Scenes.Serialization;
42using OpenSim.Tests.Common; 42using OpenSim.Tests.Common;
43using OpenSim.Tests.Common.Mock;
44 43
45namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests 44namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
46{ 45{
@@ -152,7 +151,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
152 TestHelpers.InMethod(); 151 TestHelpers.InMethod();
153 152
154 string dtText 153 string dtText
155 = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://localhost/shouldnotexist.png"; 154 = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://0.0.0.0/shouldnotexist.png";
156 155
157 SetupScene(false); 156 SetupScene(false);
158 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); 157 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
@@ -307,7 +306,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
307 TestHelpers.InMethod(); 306 TestHelpers.InMethod();
308 307
309 string dtText 308 string dtText
310 = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://localhost/shouldnotexist.png"; 309 = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://0.0.0.0/shouldnotexist.png";
311 310
312 SetupScene(true); 311 SetupScene(true);
313 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); 312 SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
diff --git a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
index 689e8a7..4cecd85 100644
--- a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
@@ -516,6 +516,9 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
516 foreach (string line in GetLines(data, dataDelim)) 516 foreach (string line in GetLines(data, dataDelim))
517 { 517 {
518 string nextLine = line.Trim(); 518 string nextLine = line.Trim();
519
520// m_log.DebugFormat("[VECTOR RENDER MODULE]: Processing line '{0}'", nextLine);
521
519 //replace with switch, or even better, do some proper parsing 522 //replace with switch, or even better, do some proper parsing
520 if (nextLine.StartsWith("MoveTo")) 523 if (nextLine.StartsWith("MoveTo"))
521 { 524 {
@@ -829,6 +832,8 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
829 float y = Convert.ToSingle(yVal, CultureInfo.InvariantCulture); 832 float y = Convert.ToSingle(yVal, CultureInfo.InvariantCulture);
830 PointF point = new PointF(x, y); 833 PointF point = new PointF(x, y);
831 points[i / 2] = point; 834 points[i / 2] = point;
835
836// m_log.DebugFormat("[VECTOR RENDER MODULE]: Got point {0}", points[i / 2]);
832 } 837 }
833 } 838 }
834 } 839 }
@@ -838,13 +843,17 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
838 try 843 try
839 { 844 {
840 WebRequest request = HttpWebRequest.Create(url); 845 WebRequest request = HttpWebRequest.Create(url);
841//Ckrinke: Comment out for now as 'str' is unused. Bring it back into play later when it is used. 846
842//Ckrinke Stream str = null; 847 using (HttpWebResponse response = (HttpWebResponse)(request).GetResponse())
843 HttpWebResponse response = (HttpWebResponse)(request).GetResponse();
844 if (response.StatusCode == HttpStatusCode.OK)
845 { 848 {
846 Bitmap image = new Bitmap(response.GetResponseStream()); 849 if (response.StatusCode == HttpStatusCode.OK)
847 return image; 850 {
851 using (Stream s = response.GetResponseStream())
852 {
853 Bitmap image = new Bitmap(s);
854 return image;
855 }
856 }
848 } 857 }
849 } 858 }
850 catch { } 859 catch { }
diff --git a/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs b/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs
index 2c2c99c..3484387 100644
--- a/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs
@@ -379,15 +379,9 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
379 if (sp.IsChildAgent) 379 if (sp.IsChildAgent)
380 return; 380 return;
381 381
382 // Send message to the avatar.
383 // Channel zero only goes to the avatar 382 // Channel zero only goes to the avatar
384 // non zero channel messages only go to the attachments 383 // non zero channel messages only go to the attachments of the avatar.
385 if (channel == 0) 384 if (channel != 0)
386 {
387 m_scene.SimChatToAgent(target, Utils.StringToBytes(msg),
388 pos, name, id, false);
389 }
390 else
391 { 385 {
392 List<SceneObjectGroup> attachments = sp.GetAttachments(); 386 List<SceneObjectGroup> attachments = sp.GetAttachments();
393 if (attachments.Count == 0) 387 if (attachments.Count == 0)
diff --git a/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs b/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs
index 385f5ad..87f4277 100644
--- a/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs
@@ -36,6 +36,7 @@ using Nini.Config;
36using Nwc.XmlRpc; 36using Nwc.XmlRpc;
37using OpenMetaverse; 37using OpenMetaverse;
38using OpenSim.Framework; 38using OpenSim.Framework;
39using OpenSim.Framework.Monitoring;
39using OpenSim.Framework.Servers; 40using OpenSim.Framework.Servers;
40using OpenSim.Framework.Servers.HttpServer; 41using OpenSim.Framework.Servers.HttpServer;
41using OpenSim.Region.Framework.Interfaces; 42using OpenSim.Region.Framework.Interfaces;
@@ -111,13 +112,15 @@ namespace OpenSim.Region.CoreModules.Scripting.XMLRPC
111 m_rpcPending = new Dictionary<UUID, RPCRequestInfo>(); 112 m_rpcPending = new Dictionary<UUID, RPCRequestInfo>();
112 m_rpcPendingResponses = new Dictionary<UUID, RPCRequestInfo>(); 113 m_rpcPendingResponses = new Dictionary<UUID, RPCRequestInfo>();
113 m_pendingSRDResponses = new Dictionary<UUID, SendRemoteDataRequest>(); 114 m_pendingSRDResponses = new Dictionary<UUID, SendRemoteDataRequest>();
114 115 if (config.Configs["XMLRPC"] != null)
115 try
116 {
117 m_remoteDataPort = config.Configs["XMLRPC"].GetInt("XmlRpcPort", m_remoteDataPort);
118 }
119 catch (Exception)
120 { 116 {
117 try
118 {
119 m_remoteDataPort = config.Configs["XMLRPC"].GetInt("XmlRpcPort", m_remoteDataPort);
120 }
121 catch (Exception)
122 {
123 }
121 } 124 }
122 } 125 }
123 126
@@ -654,12 +657,8 @@ namespace OpenSim.Region.CoreModules.Scripting.XMLRPC
654 657
655 public void Process() 658 public void Process()
656 { 659 {
657 httpThread = new Thread(SendRequest);
658 httpThread.Name = "HttpRequestThread";
659 httpThread.Priority = ThreadPriority.BelowNormal;
660 httpThread.IsBackground = true;
661 _finished = false; 660 _finished = false;
662 httpThread.Start(); 661 httpThread = WorkManager.StartThread(SendRequest, "HttpRequestThread", ThreadPriority.BelowNormal, true, false);
663 } 662 }
664 663
665 /* 664 /*
@@ -675,7 +674,7 @@ namespace OpenSim.Region.CoreModules.Scripting.XMLRPC
675 // if not, use as method name 674 // if not, use as method name
676 UUID parseUID; 675 UUID parseUID;
677 string mName = "llRemoteData"; 676 string mName = "llRemoteData";
678 if ((Channel != null) && (Channel != "")) 677 if (!string.IsNullOrEmpty(Channel))
679 if (!UUID.TryParse(Channel, out parseUID)) 678 if (!UUID.TryParse(Channel, out parseUID))
680 mName = Channel; 679 mName = Channel;
681 else 680 else
@@ -731,13 +730,19 @@ namespace OpenSim.Region.CoreModules.Scripting.XMLRPC
731 } 730 }
732 731
733 _finished = true; 732 _finished = true;
733
734 Watchdog.RemoveThread();
734 } 735 }
735 736
736 public void Stop() 737 public void Stop()
737 { 738 {
738 try 739 try
739 { 740 {
740 httpThread.Abort(); 741 if (httpThread != null)
742 {
743 Watchdog.AbortThread(httpThread.ManagedThreadId);
744 httpThread = null;
745 }
741 } 746 }
742 catch (Exception) 747 catch (Exception)
743 { 748 {
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs
new file mode 100644
index 0000000..4701ee6
--- /dev/null
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs
@@ -0,0 +1,228 @@
1
2/*
3 * Copyright (c) Contributors, http://opensimulator.org/
4 * See CONTRIBUTORS.TXT for a full list of copyright holders.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the OpenSimulator Project nor the
14 * names of its contributors may be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29using log4net;
30using Mono.Addins;
31using Nini.Config;
32using System;
33using System.Collections.Generic;
34using System.Reflection;
35using OpenSim.Framework;
36using OpenSim.Framework.Console;
37using OpenSim.Server.Base;
38using OpenSim.Server.Handlers;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Framework.Servers.HttpServer;
41using OpenSim.Framework.Servers;
42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Services.Interfaces;
44using GridRegion = OpenSim.Services.Interfaces.GridRegion;
45using OpenMetaverse;
46
47namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Profile
48{
49 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LocalUserProfilesServicesConnector")]
50 public class LocalUserProfilesServicesConnector : ISharedRegionModule
51 {
52 private static readonly ILog m_log =
53 LogManager.GetLogger(
54 MethodBase.GetCurrentMethod().DeclaringType);
55
56 private Dictionary<UUID, Scene> regions = new Dictionary<UUID, Scene>();
57
58 public IUserProfilesService ServiceModule
59 {
60 get; private set;
61 }
62
63 public bool Enabled
64 {
65 get; private set;
66 }
67
68 public string Name
69 {
70 get
71 {
72 return "LocalUserProfilesServicesConnector";
73 }
74 }
75
76 public string ConfigName
77 {
78 get; private set;
79 }
80
81 public Type ReplaceableInterface
82 {
83 get { return null; }
84 }
85
86 public LocalUserProfilesServicesConnector()
87 {
88 m_log.Debug("[LOCAL USERPROFILES SERVICE CONNECTOR]: LocalUserProfileServicesConnector no params");
89 }
90
91 public LocalUserProfilesServicesConnector(IConfigSource source)
92 {
93 m_log.Debug("[LOCAL USERPROFILES SERVICE CONNECTOR]: LocalUserProfileServicesConnector instantiated directly.");
94 InitialiseService(source);
95 }
96
97 public void InitialiseService(IConfigSource source)
98 {
99 ConfigName = "UserProfilesService";
100
101 // Instantiate the request handler
102 IHttpServer Server = MainServer.Instance;
103
104 IConfig config = source.Configs[ConfigName];
105 if (config == null)
106 {
107 m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: UserProfilesService missing from OpenSim.ini");
108 return;
109 }
110
111 if(!config.GetBoolean("Enabled",false))
112 {
113 Enabled = false;
114 return;
115 }
116
117 Enabled = true;
118
119 string serviceDll = config.GetString("LocalServiceModule",
120 String.Empty);
121
122 if (serviceDll == String.Empty)
123 {
124 m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: No LocalServiceModule named in section UserProfilesService");
125 return;
126 }
127
128 Object[] args = new Object[] { source, ConfigName };
129 ServiceModule =
130 ServerUtils.LoadPlugin<IUserProfilesService>(serviceDll,
131 args);
132
133 if (ServiceModule == null)
134 {
135 m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: Can't load user profiles service");
136 return;
137 }
138
139 Enabled = true;
140
141 JsonRpcProfileHandlers handler = new JsonRpcProfileHandlers(ServiceModule);
142
143 Server.AddJsonRPCHandler("avatarclassifiedsrequest", handler.AvatarClassifiedsRequest);
144 Server.AddJsonRPCHandler("classified_update", handler.ClassifiedUpdate);
145 Server.AddJsonRPCHandler("classifieds_info_query", handler.ClassifiedInfoRequest);
146 Server.AddJsonRPCHandler("classified_delete", handler.ClassifiedDelete);
147 Server.AddJsonRPCHandler("avatarpicksrequest", handler.AvatarPicksRequest);
148 Server.AddJsonRPCHandler("pickinforequest", handler.PickInfoRequest);
149 Server.AddJsonRPCHandler("picks_update", handler.PicksUpdate);
150 Server.AddJsonRPCHandler("picks_delete", handler.PicksDelete);
151 Server.AddJsonRPCHandler("avatarnotesrequest", handler.AvatarNotesRequest);
152 Server.AddJsonRPCHandler("avatar_notes_update", handler.NotesUpdate);
153 Server.AddJsonRPCHandler("avatar_properties_request", handler.AvatarPropertiesRequest);
154 Server.AddJsonRPCHandler("avatar_properties_update", handler.AvatarPropertiesUpdate);
155 Server.AddJsonRPCHandler("avatar_interests_update", handler.AvatarInterestsUpdate);
156 Server.AddJsonRPCHandler("user_preferences_update", handler.UserPreferenecesUpdate);
157 Server.AddJsonRPCHandler("user_preferences_request", handler.UserPreferencesRequest);
158 Server.AddJsonRPCHandler("image_assets_request", handler.AvatarImageAssetsRequest);
159 Server.AddJsonRPCHandler("user_data_request", handler.RequestUserAppData);
160 Server.AddJsonRPCHandler("user_data_update", handler.UpdateUserAppData);
161
162 }
163
164 #region ISharedRegionModule implementation
165
166 void ISharedRegionModule.PostInitialise()
167 {
168 if(!Enabled)
169 return;
170 }
171
172 #endregion
173
174 #region IRegionModuleBase implementation
175
176 void IRegionModuleBase.Initialise(IConfigSource source)
177 {
178 IConfig moduleConfig = source.Configs["Modules"];
179 if (moduleConfig != null)
180 {
181 string name = moduleConfig.GetString("UserProfilesServices", "");
182 if (name == Name)
183 {
184 InitialiseService(source);
185 m_log.Info("[LOCAL USERPROFILES SERVICE CONNECTOR]: Local user profiles connector enabled");
186 }
187 }
188 }
189
190 void IRegionModuleBase.Close()
191 {
192 return;
193 }
194
195 void IRegionModuleBase.AddRegion(Scene scene)
196 {
197 if (!Enabled)
198 return;
199
200 lock (regions)
201 {
202 if (regions.ContainsKey(scene.RegionInfo.RegionID))
203 m_log.ErrorFormat("[LOCAL USERPROFILES SERVICE CONNECTOR]: simulator seems to have more than one region with the same UUID. Please correct this!");
204 else
205 regions.Add(scene.RegionInfo.RegionID, scene);
206 }
207 }
208
209 void IRegionModuleBase.RemoveRegion(Scene scene)
210 {
211 if (!Enabled)
212 return;
213
214 lock (regions)
215 {
216 if (regions.ContainsKey(scene.RegionInfo.RegionID))
217 regions.Remove(scene.RegionInfo.RegionID);
218 }
219 }
220
221 void IRegionModuleBase.RegionLoaded(Scene scene)
222 {
223 if (!Enabled)
224 return;
225 }
226 #endregion
227 }
228} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/LocalAgentPreferencesServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/LocalAgentPreferencesServiceConnector.cs
new file mode 100644
index 0000000..41ae53f
--- /dev/null
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/LocalAgentPreferencesServiceConnector.cs
@@ -0,0 +1,153 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using log4net;
32using Mono.Addins;
33using Nini.Config;
34using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Region.Framework.Scenes;
36using OpenSim.Server.Base;
37using OpenSim.Services.Interfaces;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.AgentPreferences
42{
43 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LocalAgentPreferencesServicesConnector")]
44 public class LocalAgentPreferencesServicesConnector : ISharedRegionModule, IAgentPreferencesService
45 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 private IAgentPreferencesService m_AgentPreferencesService;
49 private bool m_Enabled = false;
50
51 #region ISharedRegionModule
52
53 public Type ReplaceableInterface
54 {
55 get { return null; }
56 }
57
58 public string Name
59 {
60 get { return "LocalAgentPreferencesServicesConnector"; }
61 }
62
63 public void Initialise(IConfigSource source)
64 {
65 IConfig moduleConfig = source.Configs["Modules"];
66 if (moduleConfig != null)
67 {
68 string name = moduleConfig.GetString("AgentPreferencesServices", "");
69 if (name == Name)
70 {
71 IConfig userConfig = source.Configs["AgentPreferencesService"];
72 if (userConfig == null)
73 {
74 m_log.Error("[AGENT PREFERENCES CONNECTOR]: AgentPreferencesService missing from OpenSim.ini");
75 return;
76 }
77
78 string serviceDll = userConfig.GetString("LocalServiceModule", String.Empty);
79
80 if (String.IsNullOrEmpty(serviceDll))
81 {
82 m_log.Error("[AGENT PREFERENCES CONNECTOR]: No AgentPreferencesModule named in section AgentPreferencesService");
83 return;
84 }
85
86 Object[] args = new Object[] { source };
87 m_AgentPreferencesService = ServerUtils.LoadPlugin<IAgentPreferencesService>(serviceDll, args);
88
89 if (m_AgentPreferencesService == null)
90 {
91 m_log.Error("[AGENT PREFERENCES CONNECTOR]: Can't load agent preferences service");
92 return;
93 }
94 m_Enabled = true;
95 m_log.Info("[AGENT PREFERENCES CONNECTOR]: Local agent preferences connector enabled");
96 }
97 }
98 }
99
100 public void PostInitialise()
101 {
102 if (!m_Enabled)
103 return;
104 }
105
106 public void Close()
107 {
108 if (!m_Enabled)
109 return;
110 }
111
112 public void AddRegion(Scene scene)
113 {
114 if (!m_Enabled)
115 return;
116
117 scene.RegisterModuleInterface<IAgentPreferencesService>(this);
118 }
119
120 public void RemoveRegion(Scene scene)
121 {
122 if (!m_Enabled)
123 return;
124 }
125
126 public void RegionLoaded(Scene scene)
127 {
128 if (!m_Enabled)
129 return;
130 }
131
132 #endregion ISharedRegionModule
133
134 #region IAgentPreferencesService
135
136 public AgentPrefs GetAgentPreferences(UUID principalID)
137 {
138 return m_AgentPreferencesService.GetAgentPreferences(principalID);
139 }
140
141 public bool StoreAgentPreferences(AgentPrefs data)
142 {
143 return m_AgentPreferencesService.StoreAgentPreferences(data);
144 }
145
146 public string GetLang(UUID principalID)
147 {
148 return m_AgentPreferencesService.GetLang(principalID);
149 }
150
151 #endregion IAgentPreferencesService
152 }
153}
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/RemoteAgentPreferencesServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/RemoteAgentPreferencesServiceConnector.cs
new file mode 100644
index 0000000..ad9544a
--- /dev/null
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/RemoteAgentPreferencesServiceConnector.cs
@@ -0,0 +1,116 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28
29using System;
30using System.Collections.Generic;
31using System.Reflection;
32
33using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes;
35using OpenSim.Server.Base;
36using OpenSim.Services.Interfaces;
37using OpenSim.Services.Connectors;
38
39using OpenMetaverse;
40using log4net;
41using Mono.Addins;
42using Nini.Config;
43
44namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.AgentPreferences
45{
46 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RemoteAgentPreferencesServicesConnector")]
47 public class RemoteAgentPreferencesServicesConnector : AgentPreferencesServicesConnector,
48 ISharedRegionModule, IAgentPreferencesService
49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
52 private bool m_Enabled = false;
53
54 public Type ReplaceableInterface
55 {
56 get { return null; }
57 }
58
59 public string Name
60 {
61 get { return "RemoteAgentPreferencesServicesConnector"; }
62 }
63
64 public override void Initialise(IConfigSource source)
65 {
66 IConfig moduleConfig = source.Configs["Modules"];
67 if (moduleConfig != null)
68 {
69 string name = moduleConfig.GetString("AgentPreferencesServices", "");
70 if (name == Name)
71 {
72 IConfig userConfig = source.Configs["AgentPreferencesService"];
73 if (userConfig == null)
74 {
75 m_log.Error("[AGENT PREFERENCES CONNECTOR]: AgentPreferencesService missing from OpenSim.ini");
76 return;
77 }
78
79 m_Enabled = true;
80
81 base.Initialise(source);
82
83 m_log.Info("[AGENT PREFERENCES CONNECTOR]: Remote agent preferences enabled");
84 }
85 }
86 }
87
88 public void PostInitialise()
89 {
90 /* no op */
91 }
92
93 public void Close()
94 {
95 /* no op */
96 }
97
98 public void AddRegion(Scene scene)
99 {
100 if (!m_Enabled)
101 return;
102
103 scene.RegisterModuleInterface<IAgentPreferencesService>(this);
104 }
105
106 public void RemoveRegion(Scene scene)
107 {
108 /* no op */
109 }
110
111 public void RegionLoaded(Scene scene)
112 {
113 /* no op */
114 }
115 }
116} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs
index d221d68..7fcfc74 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs
@@ -69,6 +69,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
69 get { return "HGAssetBroker"; } 69 get { return "HGAssetBroker"; }
70 } 70 }
71 71
72 public HGAssetBroker() {}
73
74 public HGAssetBroker(IConfigSource config)
75 {
76 Initialise(config);
77 }
78
72 public void Initialise(IConfigSource source) 79 public void Initialise(IConfigSource source)
73 { 80 {
74 IConfig moduleConfig = source.Configs["Modules"]; 81 IConfig moduleConfig = source.Configs["Modules"];
@@ -288,7 +295,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
288 295
289 if (asset != null) 296 if (asset != null)
290 { 297 {
291 Util.FireAndForget(delegate { handler(id, sender, asset); }); 298 Util.FireAndForget(delegate { handler(id, sender, asset); }, null, "HGAssetBroker.GotFromCache");
292 return true; 299 return true;
293 } 300 }
294 301
@@ -312,6 +319,23 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
312 } 319 }
313 } 320 }
314 321
322 public virtual bool[] AssetsExist(string[] ids)
323 {
324 int numHG = 0;
325 foreach (string id in ids)
326 {
327 if (IsHG(id))
328 ++numHG;
329 }
330
331 if (numHG == 0)
332 return m_GridService.AssetsExist(ids);
333 else if (numHG == ids.Length)
334 return m_HGService.AssetsExist(ids);
335 else
336 throw new Exception("[HG ASSET CONNECTOR]: AssetsExist: all the assets must be either local or foreign");
337 }
338
315 public string Store(AssetBase asset) 339 public string Store(AssetBase asset)
316 { 340 {
317 bool isHG = IsHG(asset.ID); 341 bool isHG = IsHG(asset.ID);
@@ -322,14 +346,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
322 // a copy of the local asset. 346 // a copy of the local asset.
323 m_Cache.Cache(asset); 347 m_Cache.Cache(asset);
324 348
325 if (asset.Temporary || asset.Local) 349 if (asset.Local)
326 { 350 {
327 if (m_Cache != null) 351 if (m_Cache != null)
328 m_Cache.Cache(asset); 352 m_Cache.Cache(asset);
329 return asset.ID; 353 return asset.ID;
330 } 354 }
331 355
332 string id = string.Empty; 356 string id;
333 if (IsHG(asset.ID)) 357 if (IsHG(asset.ID))
334 { 358 {
335 if (m_AssetPerms.AllowedExport(asset.Type)) 359 if (m_AssetPerms.AllowedExport(asset.Type))
@@ -340,18 +364,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
340 else 364 else
341 id = m_GridService.Store(asset); 365 id = m_GridService.Store(asset);
342 366
343 if (id != String.Empty) 367 if (String.IsNullOrEmpty(id))
344 { 368 return string.Empty;
345 // Placing this here, so that this work with old asset servers that don't send any reply back 369
346 // SynchronousRestObjectRequester returns somethins that is not an empty string 370 asset.ID = id;
347 if (id != null)
348 asset.ID = id;
349 371
350 if (m_Cache != null) 372 if (m_Cache != null)
351 m_Cache.Cache(asset); 373 m_Cache.Cache(asset);
352 }
353 return id;
354 374
375 return id;
355 } 376 }
356 377
357 public bool UpdateContent(string id, byte[] data) 378 public bool UpdateContent(string id, byte[] data)
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs
index 480cd69..5f34450 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs
@@ -236,7 +236,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
236 236
237 if (asset != null) 237 if (asset != null)
238 { 238 {
239 Util.FireAndForget(delegate { handler(id, sender, asset); }); 239 Util.FireAndForget(
240 o => handler(id, sender, asset), null, "LocalAssetServiceConnector.GotFromCacheCallback");
240 return true; 241 return true;
241 } 242 }
242 } 243 }
@@ -249,16 +250,22 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
249// if (null == a) 250// if (null == a)
250// m_log.WarnFormat("[LOCAL ASSET SERVICES CONNECTOR]: Could not asynchronously find asset with id {0}", id); 251// m_log.WarnFormat("[LOCAL ASSET SERVICES CONNECTOR]: Could not asynchronously find asset with id {0}", id);
251 252
252 Util.FireAndForget(delegate { handler(assetID, s, a); }); 253 Util.FireAndForget(
254 o => handler(assetID, s, a), null, "LocalAssetServiceConnector.GotFromServiceCallback");
253 }); 255 });
254 } 256 }
255 257
258 public bool[] AssetsExist(string[] ids)
259 {
260 return m_AssetService.AssetsExist(ids);
261 }
262
256 public string Store(AssetBase asset) 263 public string Store(AssetBase asset)
257 { 264 {
258 if (m_Cache != null) 265 if (m_Cache != null)
259 m_Cache.Cache(asset); 266 m_Cache.Cache(asset);
260 267
261 if (asset.Temporary || asset.Local) 268 if (asset.Local)
262 { 269 {
263// m_log.DebugFormat( 270// m_log.DebugFormat(
264// "[LOCAL ASSET SERVICE CONNECTOR]: Returning asset {0} {1} without querying database since status Temporary = {2}, Local = {3}", 271// "[LOCAL ASSET SERVICE CONNECTOR]: Returning asset {0} {1} without querying database since status Temporary = {2}, Local = {3}",
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs
index 1982473..4f75191 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs
@@ -42,7 +42,7 @@ using OpenSim.Tests.Common;
42namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests 42namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests
43{ 43{
44 [TestFixture] 44 [TestFixture]
45 public class AssetConnectorsTests : OpenSimTestCase 45 public class AssetConnectorTests : OpenSimTestCase
46 { 46 {
47 [Test] 47 [Test]
48 public void TestAddAsset() 48 public void TestAddAsset()
@@ -77,7 +77,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests
77 // TODO: Add cache and check that this does receive a copy of the asset 77 // TODO: Add cache and check that this does receive a copy of the asset
78 } 78 }
79 79
80 [Test]
81 public void TestAddTemporaryAsset() 80 public void TestAddTemporaryAsset()
82 { 81 {
83 TestHelpers.InMethod(); 82 TestHelpers.InMethod();
@@ -93,8 +92,45 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests
93 LocalAssetServicesConnector lasc = new LocalAssetServicesConnector(); 92 LocalAssetServicesConnector lasc = new LocalAssetServicesConnector();
94 lasc.Initialise(config); 93 lasc.Initialise(config);
95 94
95 // If it is remote, it should be stored
96 AssetBase a2 = AssetHelpers.CreateNotecardAsset();
97 a2.Local = false;
98 a2.Temporary = true;
99
100 lasc.Store(a2);
101
102 AssetBase retreivedA2 = lasc.Get(a2.ID);
103 Assert.That(retreivedA2.ID, Is.EqualTo(a2.ID));
104 Assert.That(retreivedA2.Metadata.ID, Is.EqualTo(a2.Metadata.ID));
105 Assert.That(retreivedA2.Data.Length, Is.EqualTo(a2.Data.Length));
106
107 AssetMetadata retrievedA2Metadata = lasc.GetMetadata(a2.ID);
108 Assert.That(retrievedA2Metadata.ID, Is.EqualTo(a2.ID));
109
110 byte[] retrievedA2Data = lasc.GetData(a2.ID);
111 Assert.That(retrievedA2Data.Length, Is.EqualTo(a2.Data.Length));
112
113 // TODO: Add cache and check that this does receive a copy of the asset
114 }
115
116 [Test]
117 public void TestAddLocalAsset()
118 {
119 TestHelpers.InMethod();
120// TestHelpers.EnableLogging();
121
122 IConfigSource config = new IniConfigSource();
123 config.AddConfig("Modules");
124 config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector");
125 config.AddConfig("AssetService");
126 config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService");
127 config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll");
128
129 LocalAssetServicesConnector lasc = new LocalAssetServicesConnector();
130 lasc.Initialise(config);
131
96 AssetBase a1 = AssetHelpers.CreateNotecardAsset(); 132 AssetBase a1 = AssetHelpers.CreateNotecardAsset();
97 a1.Temporary = true; 133 a1.Local = true;
98 134
99 lasc.Store(a1); 135 lasc.Store(a1);
100 136
@@ -106,7 +142,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests
106 } 142 }
107 143
108 [Test] 144 [Test]
109 public void TestAddLocalAsset() 145 public void TestAddTemporaryLocalAsset()
110 { 146 {
111 TestHelpers.InMethod(); 147 TestHelpers.InMethod();
112// TestHelpers.EnableLogging(); 148// TestHelpers.EnableLogging();
@@ -121,8 +157,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests
121 LocalAssetServicesConnector lasc = new LocalAssetServicesConnector(); 157 LocalAssetServicesConnector lasc = new LocalAssetServicesConnector();
122 lasc.Initialise(config); 158 lasc.Initialise(config);
123 159
160 // If it is local, it should not be stored
124 AssetBase a1 = AssetHelpers.CreateNotecardAsset(); 161 AssetBase a1 = AssetHelpers.CreateNotecardAsset();
125 a1.Local = true; 162 a1.Local = true;
163 a1.Temporary = true;
126 164
127 lasc.Store(a1); 165 lasc.Store(a1);
128 166
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/AuthorizationService.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/AuthorizationService.cs
index 4470799..93dff1f 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/AuthorizationService.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/AuthorizationService.cs
@@ -89,35 +89,43 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization
89 public bool IsAuthorizedForRegion( 89 public bool IsAuthorizedForRegion(
90 string user, string firstName, string lastName, string regionID, out string message) 90 string user, string firstName, string lastName, string regionID, out string message)
91 { 91 {
92 message = "authorized";
93
94 // This should not happen 92 // This should not happen
95 if (m_Scene.RegionInfo.RegionID.ToString() != regionID) 93 if (m_Scene.RegionInfo.RegionID.ToString() != regionID)
96 { 94 {
97 m_log.WarnFormat("[AuthorizationService]: Service for region {0} received request to authorize for region {1}", 95 m_log.WarnFormat("[AuthorizationService]: Service for region {0} received request to authorize for region {1}",
98 m_Scene.RegionInfo.RegionID, regionID); 96 m_Scene.RegionInfo.RegionID, regionID);
99 return true; 97 message = string.Format("Region {0} received request to authorize for region {1}", m_Scene.RegionInfo.RegionID, regionID);
98 return false;
100 } 99 }
101 100
102 if (m_accessValue == AccessFlags.None) 101 if (m_accessValue == AccessFlags.None)
102 {
103 message = "Authorized";
103 return true; 104 return true;
105 }
104 106
105 UUID userID = new UUID(user); 107 UUID userID = new UUID(user);
106 bool authorized = true; 108
107 if ((m_accessValue & AccessFlags.DisallowForeigners) == AccessFlags.DisallowForeigners) 109 if ((m_accessValue & AccessFlags.DisallowForeigners) != 0)
108 { 110 {
109 authorized = m_UserManagement.IsLocalGridUser(userID); 111 if (!m_UserManagement.IsLocalGridUser(userID))
110 if (!authorized) 112 {
111 message = "no foreigner users allowed in this region"; 113 message = "No foreign users allowed in this region";
114 return false;
115 }
112 } 116 }
113 if (authorized && (m_accessValue & AccessFlags.DisallowResidents) == AccessFlags.DisallowResidents) 117
118 if ((m_accessValue & AccessFlags.DisallowResidents) != 0)
114 { 119 {
115 authorized = m_Scene.Permissions.IsGod(userID) | m_Scene.Permissions.IsAdministrator(userID); 120 if (!(m_Scene.Permissions.IsGod(userID) || m_Scene.Permissions.IsAdministrator(userID)))
116 if (!authorized) 121 {
117 message = "only Admins and Managers allowed in this region"; 122 message = "Only Admins and Managers allowed in this region";
123 return false;
124 }
118 } 125 }
119 126
120 return authorized; 127 message = "Authorized";
128 return true;
121 } 129 }
122 130
123 } 131 }
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs
index c0c2ca7..1f782f5 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs
@@ -48,6 +48,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
48 private static readonly ILog m_log = 48 private static readonly ILog m_log =
49 LogManager.GetLogger( 49 LogManager.GetLogger(
50 MethodBase.GetCurrentMethod().DeclaringType); 50 MethodBase.GetCurrentMethod().DeclaringType);
51 private static string LogHeader = "[LOCAL GRID SERVICE CONNECTOR]";
51 52
52 private IGridService m_GridService; 53 private IGridService m_GridService;
53 private Dictionary<UUID, RegionCache> m_LocalCache = new Dictionary<UUID, RegionCache>(); 54 private Dictionary<UUID, RegionCache> m_LocalCache = new Dictionary<UUID, RegionCache>();
@@ -56,11 +57,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
56 57
57 public LocalGridServicesConnector() 58 public LocalGridServicesConnector()
58 { 59 {
60 m_log.DebugFormat("{0} LocalGridServicesConnector no parms.", LogHeader);
59 } 61 }
60 62
61 public LocalGridServicesConnector(IConfigSource source) 63 public LocalGridServicesConnector(IConfigSource source)
62 { 64 {
63 m_log.Debug("[LOCAL GRID SERVICE CONNECTOR]: LocalGridServicesConnector instantiated directly."); 65 m_log.DebugFormat("{0} LocalGridServicesConnector instantiated directly.", LogHeader);
64 InitialiseService(source); 66 InitialiseService(source);
65 } 67 }
66 68
@@ -92,15 +94,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
92 94
93 private void InitialiseService(IConfigSource source) 95 private void InitialiseService(IConfigSource source)
94 { 96 {
95 IConfig assetConfig = source.Configs["GridService"]; 97 IConfig config = source.Configs["GridService"];
96 if (assetConfig == null) 98 if (config == null)
97 { 99 {
98 m_log.Error("[LOCAL GRID SERVICE CONNECTOR]: GridService missing from OpenSim.ini"); 100 m_log.Error("[LOCAL GRID SERVICE CONNECTOR]: GridService missing from OpenSim.ini");
99 return; 101 return;
100 } 102 }
101 103
102 string serviceDll = assetConfig.GetString("LocalServiceModule", 104 string serviceDll = config.GetString("LocalServiceModule", String.Empty);
103 String.Empty);
104 105
105 if (serviceDll == String.Empty) 106 if (serviceDll == String.Empty)
106 { 107 {
@@ -142,10 +143,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
142 143
143 scene.RegisterModuleInterface<IGridService>(this); 144 scene.RegisterModuleInterface<IGridService>(this);
144 145
145 if (m_LocalCache.ContainsKey(scene.RegionInfo.RegionID)) 146 lock (m_LocalCache)
146 m_log.ErrorFormat("[LOCAL GRID SERVICE CONNECTOR]: simulator seems to have more than one region with the same UUID. Please correct this!"); 147 {
147 else 148 if (m_LocalCache.ContainsKey(scene.RegionInfo.RegionID))
148 m_LocalCache.Add(scene.RegionInfo.RegionID, new RegionCache(scene)); 149 m_log.ErrorFormat("[LOCAL GRID SERVICE CONNECTOR]: simulator seems to have more than one region with the same UUID. Please correct this!");
150 else
151 m_LocalCache.Add(scene.RegionInfo.RegionID, new RegionCache(scene));
152 }
149 } 153 }
150 154
151 public void RemoveRegion(Scene scene) 155 public void RemoveRegion(Scene scene)
@@ -153,8 +157,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
153 if (!m_Enabled) 157 if (!m_Enabled)
154 return; 158 return;
155 159
156 m_LocalCache[scene.RegionInfo.RegionID].Clear(); 160 lock (m_LocalCache)
157 m_LocalCache.Remove(scene.RegionInfo.RegionID); 161 {
162 m_LocalCache[scene.RegionInfo.RegionID].Clear();
163 m_LocalCache.Remove(scene.RegionInfo.RegionID);
164 }
158 } 165 }
159 166
160 public void RegionLoaded(Scene scene) 167 public void RegionLoaded(Scene scene)
@@ -185,23 +192,59 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
185 return m_GridService.GetRegionByUUID(scopeID, regionID); 192 return m_GridService.GetRegionByUUID(scopeID, regionID);
186 } 193 }
187 194
195 // Get a region given its base coordinates.
196 // NOTE: this is NOT 'get a region by some point in the region'. The coordinate MUST
197 // be the base coordinate of the region.
188 public GridRegion GetRegionByPosition(UUID scopeID, int x, int y) 198 public GridRegion GetRegionByPosition(UUID scopeID, int x, int y)
189 { 199 {
190 GridRegion region = null; 200 GridRegion region = null;
201 uint regionX = Util.WorldToRegionLoc((uint)x);
202 uint regionY = Util.WorldToRegionLoc((uint)y);
203
204 // Sanity check
205 if ((Util.RegionToWorldLoc(regionX) != (uint)x) || (Util.RegionToWorldLoc(regionY) != (uint)y))
206 {
207 m_log.WarnFormat("{0} GetRegionByPosition. Bad position requested: not the base of the region. Requested Pos=<{1},{2}>, Should Be=<{3},{4}>",
208 LogHeader, x, y, Util.RegionToWorldLoc(regionX), Util.RegionToWorldLoc(regionY));
209 }
191 210
192 // First see if it's a neighbour, even if it isn't on this sim. 211 // First see if it's a neighbour, even if it isn't on this sim.
193 // Neighbour data is cached in memory, so this is fast 212 // Neighbour data is cached in memory, so this is fast
194 foreach (RegionCache rcache in m_LocalCache.Values) 213
214 lock (m_LocalCache)
195 { 215 {
196 region = rcache.GetRegionByPosition(x, y); 216 foreach (RegionCache rcache in m_LocalCache.Values)
197 if (region != null)
198 { 217 {
199 return region; 218 region = rcache.GetRegionByPosition(x, y);
219 if (region != null)
220 {
221 m_log.DebugFormat("{0} GetRegionByPosition. Found region {1} in cache (of region {2}). Pos=<{3},{4}>",
222 LogHeader, region.RegionName, rcache.RegionName,
223 Util.WorldToRegionLoc((uint)region.RegionLocX), Util.WorldToRegionLoc((uint)region.RegionLocY));
224 break;
225 }
200 } 226 }
201 } 227 }
202 228
203 // Then try on this sim (may be a lookup in DB if this is using MySql). 229 // Then try on this sim (may be a lookup in DB if this is using MySql).
204 return m_GridService.GetRegionByPosition(scopeID, x, y); 230 if (region == null)
231 {
232 region = m_GridService.GetRegionByPosition(scopeID, x, y);
233
234 if (region == null)
235 {
236 m_log.DebugFormat("{0} GetRegionByPosition. Region not found by grid service. Pos=<{1},{2}>",
237 LogHeader, regionX, regionY);
238 }
239 else
240 {
241 m_log.DebugFormat("{0} GetRegionByPosition. Got region {1} from grid service. Pos=<{2},{3}>",
242 LogHeader, region.RegionName,
243 Util.WorldToRegionLoc((uint)region.RegionLocX), Util.WorldToRegionLoc((uint)region.RegionLocY));
244 }
245 }
246
247 return region;
205 } 248 }
206 249
207 public GridRegion GetRegionByName(UUID scopeID, string regionName) 250 public GridRegion GetRegionByName(UUID scopeID, string regionName)
@@ -224,6 +267,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
224 return m_GridService.GetDefaultRegions(scopeID); 267 return m_GridService.GetDefaultRegions(scopeID);
225 } 268 }
226 269
270 public List<GridRegion> GetDefaultHypergridRegions(UUID scopeID)
271 {
272 return m_GridService.GetDefaultHypergridRegions(scopeID);
273 }
274
227 public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y) 275 public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y)
228 { 276 {
229 return m_GridService.GetFallbackRegions(scopeID, x, y); 277 return m_GridService.GetFallbackRegions(scopeID, x, y);
@@ -239,21 +287,29 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
239 return m_GridService.GetRegionFlags(scopeID, regionID); 287 return m_GridService.GetRegionFlags(scopeID, regionID);
240 } 288 }
241 289
290 public Dictionary<string, object> GetExtraFeatures()
291 {
292 return m_GridService.GetExtraFeatures();
293 }
294
242 #endregion 295 #endregion
243 296
244 public void HandleShowNeighboursCommand(string module, string[] cmdparams) 297 public void HandleShowNeighboursCommand(string module, string[] cmdparams)
245 { 298 {
246 System.Text.StringBuilder caps = new System.Text.StringBuilder(); 299 System.Text.StringBuilder caps = new System.Text.StringBuilder();
247 300
248 foreach (KeyValuePair<UUID, RegionCache> kvp in m_LocalCache) 301 lock (m_LocalCache)
249 { 302 {
250 caps.AppendFormat("*** Neighbours of {0} ({1}) ***\n", kvp.Value.RegionName, kvp.Key); 303 foreach (KeyValuePair<UUID, RegionCache> kvp in m_LocalCache)
251 List<GridRegion> regions = kvp.Value.GetNeighbours(); 304 {
252 foreach (GridRegion r in regions) 305 caps.AppendFormat("*** Neighbours of {0} ({1}) ***\n", kvp.Value.RegionName, kvp.Key);
253 caps.AppendFormat(" {0} @ {1}-{2}\n", r.RegionName, r.RegionLocX / Constants.RegionSize, r.RegionLocY / Constants.RegionSize); 306 List<GridRegion> regions = kvp.Value.GetNeighbours();
307 foreach (GridRegion r in regions)
308 caps.AppendFormat(" {0} @ {1}-{2}\n", r.RegionName, Util.WorldToRegionLoc((uint)r.RegionLocX), Util.WorldToRegionLoc((uint)r.RegionLocY));
309 }
254 } 310 }
255 311
256 MainConsole.Instance.Output(caps.ToString()); 312 MainConsole.Instance.Output(caps.ToString());
257 } 313 }
258 } 314 }
259} \ No newline at end of file 315}
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs
index 9172536..ae76288 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs
@@ -66,7 +66,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
66 return; 66 return;
67 67
68 m_log.DebugFormat("[REGION CACHE]: (on region {0}) Region {1} is up @ {2}-{3}", 68 m_log.DebugFormat("[REGION CACHE]: (on region {0}) Region {1} is up @ {2}-{3}",
69 m_scene.RegionInfo.RegionName, otherRegion.RegionName, otherRegion.RegionLocX / Constants.RegionSize, otherRegion.RegionLocY / Constants.RegionSize); 69 m_scene.RegionInfo.RegionName, otherRegion.RegionName, Util.WorldToRegionLoc((uint)otherRegion.RegionLocX), Util.WorldToRegionLoc((uint)otherRegion.RegionLocY));
70 70
71 m_neighbours[otherRegion.RegionHandle] = otherRegion; 71 m_neighbours[otherRegion.RegionHandle] = otherRegion;
72 } 72 }
@@ -82,11 +82,16 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
82 return new List<GridRegion>(m_neighbours.Values); 82 return new List<GridRegion>(m_neighbours.Values);
83 } 83 }
84 84
85 // Get a region given its base coordinates (in meters).
86 // NOTE: this is NOT 'get a region by some point in the region'. The coordinate MUST
87 // be the base coordinate of the region.
88 // The snapping is technically unnecessary but is harmless because regions are always
89 // multiples of the legacy region size (256).
85 public GridRegion GetRegionByPosition(int x, int y) 90 public GridRegion GetRegionByPosition(int x, int y)
86 { 91 {
87 uint xsnap = (uint)(x / Constants.RegionSize) * Constants.RegionSize; 92 uint xsnap = (uint)(x / Constants.RegionSize) * Constants.RegionSize;
88 uint ysnap = (uint)(y / Constants.RegionSize) * Constants.RegionSize; 93 uint ysnap = (uint)(y / Constants.RegionSize) * Constants.RegionSize;
89 ulong handle = Utils.UIntsToLong(xsnap, ysnap); 94 ulong handle = Util.RegionWorldLocToHandle(xsnap, ysnap);
90 95
91 if (m_neighbours.ContainsKey(handle)) 96 if (m_neighbours.ContainsKey(handle))
92 return m_neighbours[handle]; 97 return m_neighbours[handle];
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs
index b2646ba..85073fc 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs
@@ -28,6 +28,7 @@
28using log4net; 28using log4net;
29using Mono.Addins; 29using Mono.Addins;
30using System; 30using System;
31using System.Collections;
31using System.Collections.Generic; 32using System.Collections.Generic;
32using System.Reflection; 33using System.Reflection;
33using Nini.Config; 34using Nini.Config;
@@ -186,18 +187,41 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
186 return rinfo; 187 return rinfo;
187 } 188 }
188 189
190 // Get a region given its base world coordinates (in meters).
191 // NOTE: this is NOT 'get a region by some point in the region'. The coordinate MUST
192 // be the base coordinate of the region.
193 // The coordinates are world coords (meters), NOT region units.
189 public GridRegion GetRegionByPosition(UUID scopeID, int x, int y) 194 public GridRegion GetRegionByPosition(UUID scopeID, int x, int y)
190 { 195 {
196 ulong regionHandle = Util.RegionWorldLocToHandle((uint)x, (uint)y);
197 uint regionX = Util.WorldToRegionLoc((uint)x);
198 uint regionY = Util.WorldToRegionLoc((uint)y);
199
200 // Sanity check
201 if ((Util.RegionToWorldLoc(regionX) != (uint)x) || (Util.RegionToWorldLoc(regionY) != (uint)y))
202 {
203 m_log.WarnFormat("[REMOTE GRID CONNECTOR]: GetRegionByPosition. Bad position requested: not the base of the region. Requested Pos=<{0},{1}>, Should Be=<{2},{3}>",
204 x, y, Util.RegionToWorldLoc(regionX), Util.RegionToWorldLoc(regionY));
205 }
206
191 bool inCache = false; 207 bool inCache = false;
192 GridRegion rinfo = m_RegionInfoCache.Get(scopeID, Util.UIntsToLong((uint)x, (uint)y), out inCache); 208 GridRegion rinfo = m_RegionInfoCache.Get(scopeID, regionHandle, out inCache);
193 if (inCache) 209 if (inCache)
210 {
211 //m_log.DebugFormat("[REMOTE GRID CONNECTOR]: GetRegionByPosition. Found region {0} in cache. Pos=<{1},{2}>, RegionHandle={3}",
212 // (rinfo == null) ? "<missing>" : rinfo.RegionName, regionX, regionY, (rinfo == null) ? regionHandle : rinfo.RegionHandle);
194 return rinfo; 213 return rinfo;
214 }
195 215
196 rinfo = m_LocalGridService.GetRegionByPosition(scopeID, x, y); 216 rinfo = m_LocalGridService.GetRegionByPosition(scopeID, x, y);
197 if (rinfo == null) 217 if (rinfo == null)
198 rinfo = m_RemoteGridService.GetRegionByPosition(scopeID, x, y); 218 rinfo = m_RemoteGridService.GetRegionByPosition(scopeID, x, y);
199 219
200 m_RegionInfoCache.Cache(rinfo); 220 m_RegionInfoCache.Cache(rinfo);
221
222 //m_log.DebugFormat("[REMOTE GRID CONNECTOR]: GetRegionByPosition. Added region {0} to the cache. Pos=<{1},{2}>, RegionHandle={3}",
223 // (rinfo == null) ? "<missing>" : rinfo.RegionName, regionX, regionY, (rinfo == null) ? regionHandle : rinfo.RegionHandle);
224
201 return rinfo; 225 return rinfo;
202 } 226 }
203 227
@@ -277,6 +301,26 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
277 return rinfo; 301 return rinfo;
278 } 302 }
279 303
304 public List<GridRegion> GetDefaultHypergridRegions(UUID scopeID)
305 {
306 List<GridRegion> rinfo = m_LocalGridService.GetDefaultHypergridRegions(scopeID);
307 //m_log.DebugFormat("[REMOTE GRID CONNECTOR]: Local GetDefaultHypergridRegions {0} found {1} regions", name, rinfo.Count);
308 List<GridRegion> grinfo = m_RemoteGridService.GetDefaultHypergridRegions(scopeID);
309
310 if (grinfo != null)
311 {
312 //m_log.DebugFormat("[REMOTE GRID CONNECTOR]: Remote GetDefaultHypergridRegions {0} found {1} regions", name, grinfo.Count);
313 foreach (GridRegion r in grinfo)
314 {
315 m_RegionInfoCache.Cache(r);
316 if (rinfo.Find(delegate(GridRegion gr) { return gr.RegionID == r.RegionID; }) == null)
317 rinfo.Add(r);
318 }
319 }
320
321 return rinfo;
322 }
323
280 public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y) 324 public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y)
281 { 325 {
282 List<GridRegion> rinfo = m_LocalGridService.GetFallbackRegions(scopeID, x, y); 326 List<GridRegion> rinfo = m_LocalGridService.GetFallbackRegions(scopeID, x, y);
@@ -325,6 +369,17 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
325 369
326 return flags; 370 return flags;
327 } 371 }
372
373 public Dictionary<string, object> GetExtraFeatures()
374 {
375 Dictionary<string, object> extraFeatures;
376 extraFeatures = m_LocalGridService.GetExtraFeatures();
377
378 if (extraFeatures.Count == 0)
379 extraFeatures = m_RemoteGridService.GetExtraFeatures();
380
381 return extraFeatures;
382 }
328 #endregion 383 #endregion
329 } 384 }
330} 385}
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
index 4338133..25ae689 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
@@ -34,6 +34,7 @@ using log4net.Config;
34using Nini.Config; 34using Nini.Config;
35using NUnit.Framework; 35using NUnit.Framework;
36using OpenMetaverse; 36using OpenMetaverse;
37
37using OpenSim.Framework; 38using OpenSim.Framework;
38using OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid; 39using OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid;
39using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
@@ -141,7 +142,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
141 Assert.IsNotNull(result, "Retrieved GetRegionByUUID is null"); 142 Assert.IsNotNull(result, "Retrieved GetRegionByUUID is null");
142 Assert.That(result.RegionID, Is.EqualTo(new UUID(1)), "Retrieved region's UUID does not match"); 143 Assert.That(result.RegionID, Is.EqualTo(new UUID(1)), "Retrieved region's UUID does not match");
143 144
144 result = m_LocalConnector.GetRegionByPosition(UUID.Zero, 1000 * (int)Constants.RegionSize, 1000 * (int)Constants.RegionSize); 145 result = m_LocalConnector.GetRegionByPosition(UUID.Zero, (int)Util.RegionToWorldLoc(1000), (int)Util.RegionToWorldLoc(1000));
145 Assert.IsNotNull(result, "Retrieved GetRegionByPosition is null"); 146 Assert.IsNotNull(result, "Retrieved GetRegionByPosition is null");
146 Assert.That(result.RegionLocX, Is.EqualTo(1000 * (int)Constants.RegionSize), "Retrieved region's position does not match"); 147 Assert.That(result.RegionLocX, Is.EqualTo(1000 * (int)Constants.RegionSize), "Retrieved region's position does not match");
147 148
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs
index 221f815..2238c90 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs
@@ -67,10 +67,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
67 { 67 {
68 if (sp.PresenceType != PresenceType.Npc) 68 if (sp.PresenceType != PresenceType.Npc)
69 { 69 {
70 string userid = sp.Scene.UserManagementModule.GetUserUUI(sp.UUID); 70 string userid;
71 //m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected root presence {0} in {1}", userid, sp.Scene.RegionInfo.RegionName); 71 //m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected root presence {0} in {1}", userid, sp.Scene.RegionInfo.RegionName);
72 m_GridUserService.SetLastPosition( 72 if (sp.Scene.UserManagementModule.GetUserUUI(sp.UUID, out userid))
73 userid, UUID.Zero, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); 73 {
74 /* we only setposition on known agents that have a valid lookup */
75 m_GridUserService.SetLastPosition(
76 userid, UUID.Zero, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat);
77 }
74 } 78 }
75 } 79 }
76 80
@@ -81,20 +85,28 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
81 85
82 public void OnConnectionClose(IClientAPI client) 86 public void OnConnectionClose(IClientAPI client)
83 { 87 {
88 if (client == null)
89 return;
90 if (client.SceneAgent == null)
91 return;
92
84 if (client.SceneAgent.IsChildAgent) 93 if (client.SceneAgent.IsChildAgent)
85 return; 94 return;
86 95
87 string userId = client.AgentId.ToString(); 96 string userId;
97 /* without scene we cannot logout correctly at all since we do not know how to send the loggedout message then */
88 if (client.Scene is Scene) 98 if (client.Scene is Scene)
89 { 99 {
90 Scene s = (Scene)client.Scene; 100 Scene s = (Scene)client.Scene;
91 userId = s.UserManagementModule.GetUserUUI(client.AgentId); 101 userId = s.UserManagementModule.GetUserUUI(client.AgentId);
102 if(s.UserManagementModule.GetUserUUI(client.AgentId, out userId))
103 {
104 m_GridUserService.LoggedOut(
105 userId, client.SessionId, client.Scene.RegionInfo.RegionID,
106 client.SceneAgent.AbsolutePosition, client.SceneAgent.Lookat);
107 }
92 } 108 }
93 //m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected client logout {0} in {1}", userId, client.Scene.RegionInfo.RegionName);
94 109
95 m_GridUserService.LoggedOut(
96 userId, client.SessionId, client.Scene.RegionInfo.RegionID,
97 client.SceneAgent.AbsolutePosition, client.SceneAgent.Lookat);
98 } 110 }
99 } 111 }
100} 112}
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs
index e474ef6..48f228a 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs
@@ -62,6 +62,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
62 62
63 private InventoryCache m_Cache = new InventoryCache(); 63 private InventoryCache m_Cache = new InventoryCache();
64 64
65 /// <summary>
66 /// Used to serialize inventory requests.
67 /// </summary>
68 private object m_Lock = new object();
69
65 protected IUserManagement m_UserManagement; 70 protected IUserManagement m_UserManagement;
66 protected IUserManagement UserManagementModule 71 protected IUserManagement UserManagementModule
67 { 72 {
@@ -233,13 +238,18 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
233 if (sp != null) 238 if (sp != null)
234 { 239 {
235 AgentCircuitData aCircuit = scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); 240 AgentCircuitData aCircuit = scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
241 if (aCircuit == null)
242 return;
243 if (aCircuit.ServiceURLs == null)
244 return;
245
236 if (aCircuit.ServiceURLs.ContainsKey("InventoryServerURI")) 246 if (aCircuit.ServiceURLs.ContainsKey("InventoryServerURI"))
237 { 247 {
238 inventoryURL = aCircuit.ServiceURLs["InventoryServerURI"].ToString(); 248 inventoryURL = aCircuit.ServiceURLs["InventoryServerURI"].ToString();
239 if (inventoryURL != null && inventoryURL != string.Empty) 249 if (inventoryURL != null && inventoryURL != string.Empty)
240 { 250 {
241 inventoryURL = inventoryURL.Trim(new char[] { '/' }); 251 inventoryURL = inventoryURL.Trim(new char[] { '/' });
242 m_InventoryURLs.Add(userID, inventoryURL); 252 m_InventoryURLs[userID] = inventoryURL;
243 m_log.DebugFormat("[HG INVENTORY CONNECTOR]: Added {0} to the cache of inventory URLs", inventoryURL); 253 m_log.DebugFormat("[HG INVENTORY CONNECTOR]: Added {0} to the cache of inventory URLs", inventoryURL);
244 return; 254 return;
245 } 255 }
@@ -254,7 +264,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
254 if (sp == null) 264 if (sp == null)
255 { 265 {
256 inventoryURL = UserManagementModule.GetUserServerURL(userID, "InventoryServerURI"); 266 inventoryURL = UserManagementModule.GetUserServerURL(userID, "InventoryServerURI");
257 if (inventoryURL != null && inventoryURL != string.Empty) 267 if (!string.IsNullOrEmpty(inventoryURL))
258 { 268 {
259 inventoryURL = inventoryURL.Trim(new char[] { '/' }); 269 inventoryURL = inventoryURL.Trim(new char[] { '/' });
260 m_InventoryURLs.Add(userID, inventoryURL); 270 m_InventoryURLs.Add(userID, inventoryURL);
@@ -296,7 +306,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
296 306
297 public bool CreateUserInventory(UUID userID) 307 public bool CreateUserInventory(UUID userID)
298 { 308 {
299 return m_LocalGridInventoryService.CreateUserInventory(userID); 309 lock (m_Lock)
310 return m_LocalGridInventoryService.CreateUserInventory(userID);
300 } 311 }
301 312
302 public List<InventoryFolderBase> GetInventorySkeleton(UUID userID) 313 public List<InventoryFolderBase> GetInventorySkeleton(UUID userID)
@@ -304,36 +315,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
304 string invURL = GetInventoryServiceURL(userID); 315 string invURL = GetInventoryServiceURL(userID);
305 316
306 if (invURL == null) // not there, forward to local inventory connector to resolve 317 if (invURL == null) // not there, forward to local inventory connector to resolve
307 return m_LocalGridInventoryService.GetInventorySkeleton(userID); 318 lock (m_Lock)
319 return m_LocalGridInventoryService.GetInventorySkeleton(userID);
308 320
309 IInventoryService connector = GetConnector(invURL); 321 IInventoryService connector = GetConnector(invURL);
310 322
311 return connector.GetInventorySkeleton(userID); 323 return connector.GetInventorySkeleton(userID);
312 } 324 }
313 325
314 public InventoryCollection GetUserInventory(UUID userID)
315 {
316 string invURL = GetInventoryServiceURL(userID);
317 m_log.DebugFormat("[HG INVENTORY CONNECTOR]: GetUserInventory for {0} {1}", userID, invURL);
318
319 if (invURL == null) // not there, forward to local inventory connector to resolve
320 return m_LocalGridInventoryService.GetUserInventory(userID);
321
322 InventoryCollection c = m_Cache.GetUserInventory(userID);
323 if (c != null)
324 return c;
325
326 IInventoryService connector = GetConnector(invURL);
327 c = connector.GetUserInventory(userID);
328
329 m_Cache.Cache(userID, c);
330 return c;
331 }
332
333 public void GetUserInventory(UUID userID, InventoryReceiptCallback callback)
334 {
335 }
336
337 public InventoryFolderBase GetRootFolder(UUID userID) 326 public InventoryFolderBase GetRootFolder(UUID userID)
338 { 327 {
339 //m_log.DebugFormat("[HG INVENTORY CONNECTOR]: GetRootFolder for {0}", userID); 328 //m_log.DebugFormat("[HG INVENTORY CONNECTOR]: GetRootFolder for {0}", userID);
@@ -344,7 +333,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
344 string invURL = GetInventoryServiceURL(userID); 333 string invURL = GetInventoryServiceURL(userID);
345 334
346 if (invURL == null) // not there, forward to local inventory connector to resolve 335 if (invURL == null) // not there, forward to local inventory connector to resolve
347 return m_LocalGridInventoryService.GetRootFolder(userID); 336 lock (m_Lock)
337 return m_LocalGridInventoryService.GetRootFolder(userID);
348 338
349 IInventoryService connector = GetConnector(invURL); 339 IInventoryService connector = GetConnector(invURL);
350 340
@@ -355,7 +345,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
355 return root; 345 return root;
356 } 346 }
357 347
358 public InventoryFolderBase GetFolderForType(UUID userID, AssetType type) 348 public InventoryFolderBase GetFolderForType(UUID userID, FolderType type)
359 { 349 {
360 //m_log.DebugFormat("[HG INVENTORY CONNECTOR]: GetFolderForType {0} type {1}", userID, type); 350 //m_log.DebugFormat("[HG INVENTORY CONNECTOR]: GetFolderForType {0} type {1}", userID, type);
361 InventoryFolderBase f = m_Cache.GetFolderForType(userID, type); 351 InventoryFolderBase f = m_Cache.GetFolderForType(userID, type);
@@ -365,7 +355,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
365 string invURL = GetInventoryServiceURL(userID); 355 string invURL = GetInventoryServiceURL(userID);
366 356
367 if (invURL == null) // not there, forward to local inventory connector to resolve 357 if (invURL == null) // not there, forward to local inventory connector to resolve
368 return m_LocalGridInventoryService.GetFolderForType(userID, type); 358 lock (m_Lock)
359 return m_LocalGridInventoryService.GetFolderForType(userID, type);
369 360
370 IInventoryService connector = GetConnector(invURL); 361 IInventoryService connector = GetConnector(invURL);
371 362
@@ -383,7 +374,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
383 string invURL = GetInventoryServiceURL(userID); 374 string invURL = GetInventoryServiceURL(userID);
384 375
385 if (invURL == null) // not there, forward to local inventory connector to resolve 376 if (invURL == null) // not there, forward to local inventory connector to resolve
386 return m_LocalGridInventoryService.GetFolderContent(userID, folderID); 377 lock (m_Lock)
378 return m_LocalGridInventoryService.GetFolderContent(userID, folderID);
387 379
388 InventoryCollection c = m_Cache.GetFolderContent(userID, folderID); 380 InventoryCollection c = m_Cache.GetFolderContent(userID, folderID);
389 if (c != null) 381 if (c != null)
@@ -393,8 +385,27 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
393 } 385 }
394 386
395 IInventoryService connector = GetConnector(invURL); 387 IInventoryService connector = GetConnector(invURL);
388
396 return connector.GetFolderContent(userID, folderID); 389 return connector.GetFolderContent(userID, folderID);
390 }
397 391
392 public InventoryCollection[] GetMultipleFoldersContent(UUID userID, UUID[] folderIDs)
393 {
394 string invURL = GetInventoryServiceURL(userID);
395
396 if (invURL == null) // not there, forward to local inventory connector to resolve
397 lock (m_Lock)
398 return m_LocalGridInventoryService.GetMultipleFoldersContent(userID, folderIDs);
399
400 else
401 {
402 InventoryCollection[] coll = new InventoryCollection[folderIDs.Length];
403 int i = 0;
404 foreach (UUID fid in folderIDs)
405 coll[i++] = GetFolderContent(userID, fid);
406
407 return coll;
408 }
398 } 409 }
399 410
400 public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID) 411 public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID)
@@ -404,7 +415,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
404 string invURL = GetInventoryServiceURL(userID); 415 string invURL = GetInventoryServiceURL(userID);
405 416
406 if (invURL == null) // not there, forward to local inventory connector to resolve 417 if (invURL == null) // not there, forward to local inventory connector to resolve
407 return m_LocalGridInventoryService.GetFolderItems(userID, folderID); 418 lock (m_Lock)
419 return m_LocalGridInventoryService.GetFolderItems(userID, folderID);
408 420
409 List<InventoryItemBase> items = m_Cache.GetFolderItems(userID, folderID); 421 List<InventoryItemBase> items = m_Cache.GetFolderItems(userID, folderID);
410 if (items != null) 422 if (items != null)
@@ -414,8 +426,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
414 } 426 }
415 427
416 IInventoryService connector = GetConnector(invURL); 428 IInventoryService connector = GetConnector(invURL);
417 return connector.GetFolderItems(userID, folderID);
418 429
430 return connector.GetFolderItems(userID, folderID);
419 } 431 }
420 432
421 public bool AddFolder(InventoryFolderBase folder) 433 public bool AddFolder(InventoryFolderBase folder)
@@ -428,7 +440,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
428 string invURL = GetInventoryServiceURL(folder.Owner); 440 string invURL = GetInventoryServiceURL(folder.Owner);
429 441
430 if (invURL == null) // not there, forward to local inventory connector to resolve 442 if (invURL == null) // not there, forward to local inventory connector to resolve
431 return m_LocalGridInventoryService.AddFolder(folder); 443 lock (m_Lock)
444 return m_LocalGridInventoryService.AddFolder(folder);
432 445
433 IInventoryService connector = GetConnector(invURL); 446 IInventoryService connector = GetConnector(invURL);
434 447
@@ -445,7 +458,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
445 string invURL = GetInventoryServiceURL(folder.Owner); 458 string invURL = GetInventoryServiceURL(folder.Owner);
446 459
447 if (invURL == null) // not there, forward to local inventory connector to resolve 460 if (invURL == null) // not there, forward to local inventory connector to resolve
448 return m_LocalGridInventoryService.UpdateFolder(folder); 461 lock (m_Lock)
462 return m_LocalGridInventoryService.UpdateFolder(folder);
449 463
450 IInventoryService connector = GetConnector(invURL); 464 IInventoryService connector = GetConnector(invURL);
451 465
@@ -464,7 +478,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
464 string invURL = GetInventoryServiceURL(ownerID); 478 string invURL = GetInventoryServiceURL(ownerID);
465 479
466 if (invURL == null) // not there, forward to local inventory connector to resolve 480 if (invURL == null) // not there, forward to local inventory connector to resolve
467 return m_LocalGridInventoryService.DeleteFolders(ownerID, folderIDs); 481 lock (m_Lock)
482 return m_LocalGridInventoryService.DeleteFolders(ownerID, folderIDs);
468 483
469 IInventoryService connector = GetConnector(invURL); 484 IInventoryService connector = GetConnector(invURL);
470 485
@@ -481,7 +496,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
481 string invURL = GetInventoryServiceURL(folder.Owner); 496 string invURL = GetInventoryServiceURL(folder.Owner);
482 497
483 if (invURL == null) // not there, forward to local inventory connector to resolve 498 if (invURL == null) // not there, forward to local inventory connector to resolve
484 return m_LocalGridInventoryService.MoveFolder(folder); 499 lock (m_Lock)
500 return m_LocalGridInventoryService.MoveFolder(folder);
485 501
486 IInventoryService connector = GetConnector(invURL); 502 IInventoryService connector = GetConnector(invURL);
487 503
@@ -498,7 +514,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
498 string invURL = GetInventoryServiceURL(folder.Owner); 514 string invURL = GetInventoryServiceURL(folder.Owner);
499 515
500 if (invURL == null) // not there, forward to local inventory connector to resolve 516 if (invURL == null) // not there, forward to local inventory connector to resolve
501 return m_LocalGridInventoryService.PurgeFolder(folder); 517 lock (m_Lock)
518 return m_LocalGridInventoryService.PurgeFolder(folder);
502 519
503 IInventoryService connector = GetConnector(invURL); 520 IInventoryService connector = GetConnector(invURL);
504 521
@@ -515,7 +532,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
515 string invURL = GetInventoryServiceURL(item.Owner); 532 string invURL = GetInventoryServiceURL(item.Owner);
516 533
517 if (invURL == null) // not there, forward to local inventory connector to resolve 534 if (invURL == null) // not there, forward to local inventory connector to resolve
518 return m_LocalGridInventoryService.AddItem(item); 535 lock (m_Lock)
536 return m_LocalGridInventoryService.AddItem(item);
519 537
520 IInventoryService connector = GetConnector(invURL); 538 IInventoryService connector = GetConnector(invURL);
521 539
@@ -532,7 +550,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
532 string invURL = GetInventoryServiceURL(item.Owner); 550 string invURL = GetInventoryServiceURL(item.Owner);
533 551
534 if (invURL == null) // not there, forward to local inventory connector to resolve 552 if (invURL == null) // not there, forward to local inventory connector to resolve
535 return m_LocalGridInventoryService.UpdateItem(item); 553 lock (m_Lock)
554 return m_LocalGridInventoryService.UpdateItem(item);
536 555
537 IInventoryService connector = GetConnector(invURL); 556 IInventoryService connector = GetConnector(invURL);
538 557
@@ -551,7 +570,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
551 string invURL = GetInventoryServiceURL(ownerID); 570 string invURL = GetInventoryServiceURL(ownerID);
552 571
553 if (invURL == null) // not there, forward to local inventory connector to resolve 572 if (invURL == null) // not there, forward to local inventory connector to resolve
554 return m_LocalGridInventoryService.MoveItems(ownerID, items); 573 lock (m_Lock)
574 return m_LocalGridInventoryService.MoveItems(ownerID, items);
555 575
556 IInventoryService connector = GetConnector(invURL); 576 IInventoryService connector = GetConnector(invURL);
557 577
@@ -570,7 +590,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
570 string invURL = GetInventoryServiceURL(ownerID); 590 string invURL = GetInventoryServiceURL(ownerID);
571 591
572 if (invURL == null) // not there, forward to local inventory connector to resolve 592 if (invURL == null) // not there, forward to local inventory connector to resolve
573 return m_LocalGridInventoryService.DeleteItems(ownerID, itemIDs); 593 lock (m_Lock)
594 return m_LocalGridInventoryService.DeleteItems(ownerID, itemIDs);
574 595
575 IInventoryService connector = GetConnector(invURL); 596 IInventoryService connector = GetConnector(invURL);
576 597
@@ -586,13 +607,31 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
586 string invURL = GetInventoryServiceURL(item.Owner); 607 string invURL = GetInventoryServiceURL(item.Owner);
587 608
588 if (invURL == null) // not there, forward to local inventory connector to resolve 609 if (invURL == null) // not there, forward to local inventory connector to resolve
589 return m_LocalGridInventoryService.GetItem(item); 610 lock (m_Lock)
611 return m_LocalGridInventoryService.GetItem(item);
590 612
591 IInventoryService connector = GetConnector(invURL); 613 IInventoryService connector = GetConnector(invURL);
592 614
593 return connector.GetItem(item); 615 return connector.GetItem(item);
594 } 616 }
595 617
618 public InventoryItemBase[] GetMultipleItems(UUID userID, UUID[] itemIDs)
619 {
620 if (itemIDs == null)
621 return new InventoryItemBase[0];
622 //m_log.Debug("[HG INVENTORY CONNECTOR]: GetItem " + item.ID);
623
624 string invURL = GetInventoryServiceURL(userID);
625
626 if (invURL == null) // not there, forward to local inventory connector to resolve
627 lock (m_Lock)
628 return m_LocalGridInventoryService.GetMultipleItems(userID, itemIDs);
629
630 IInventoryService connector = GetConnector(invURL);
631
632 return connector.GetMultipleItems(userID, itemIDs);
633 }
634
596 public InventoryFolderBase GetFolder(InventoryFolderBase folder) 635 public InventoryFolderBase GetFolder(InventoryFolderBase folder)
597 { 636 {
598 if (folder == null) 637 if (folder == null)
@@ -603,7 +642,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
603 string invURL = GetInventoryServiceURL(folder.Owner); 642 string invURL = GetInventoryServiceURL(folder.Owner);
604 643
605 if (invURL == null) // not there, forward to local inventory connector to resolve 644 if (invURL == null) // not there, forward to local inventory connector to resolve
606 return m_LocalGridInventoryService.GetFolder(folder); 645 lock (m_Lock)
646 return m_LocalGridInventoryService.GetFolder(folder);
607 647
608 IInventoryService connector = GetConnector(invURL); 648 IInventoryService connector = GetConnector(invURL);
609 649
@@ -627,7 +667,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
627 string invURL = GetInventoryServiceURL(userID); 667 string invURL = GetInventoryServiceURL(userID);
628 668
629 if (invURL == null) // not there, forward to local inventory connector to resolve 669 if (invURL == null) // not there, forward to local inventory connector to resolve
630 return m_LocalGridInventoryService.GetAssetPermissions(userID, assetID); 670 lock (m_Lock)
671 return m_LocalGridInventoryService.GetAssetPermissions(userID, assetID);
631 672
632 IInventoryService connector = GetConnector(invURL); 673 IInventoryService connector = GetConnector(invURL);
633 674
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs
index 1e434b9..3195e6b 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs
@@ -1,23 +1,52 @@
1using System; 1/*
2using System.Collections.Generic; 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
3 27
28using System;
29using System.Collections.Generic;
30using System.Threading;
4using OpenSim.Framework; 31using OpenSim.Framework;
5using OpenMetaverse; 32using OpenMetaverse;
6 33
7namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory 34namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
8{ 35{
36 /// <summary>
37 /// Cache root and system inventory folders to reduce number of potentially remote inventory calls and associated holdups.
38 /// </summary>
9 public class InventoryCache 39 public class InventoryCache
10 { 40 {
11 private const double CACHE_EXPIRATION_SECONDS = 3600.0; // 1 hour 41 private const double CACHE_EXPIRATION_SECONDS = 3600.0; // 1 hour
12 42
13 private static ExpiringCache<UUID, InventoryFolderBase> m_RootFolders = new ExpiringCache<UUID, InventoryFolderBase>(); 43 private static ExpiringCache<UUID, InventoryFolderBase> m_RootFolders = new ExpiringCache<UUID, InventoryFolderBase>();
14 private static ExpiringCache<UUID, Dictionary<AssetType, InventoryFolderBase>> m_FolderTypes = new ExpiringCache<UUID, Dictionary<AssetType, InventoryFolderBase>>(); 44 private static ExpiringCache<UUID, Dictionary<FolderType, InventoryFolderBase>> m_FolderTypes = new ExpiringCache<UUID, Dictionary<FolderType, InventoryFolderBase>>();
15 private static ExpiringCache<UUID, InventoryCollection> m_Inventories = new ExpiringCache<UUID, InventoryCollection>(); 45 private static ExpiringCache<UUID, InventoryCollection> m_Inventories = new ExpiringCache<UUID, InventoryCollection>();
16 46
17 public void Cache(UUID userID, InventoryFolderBase root) 47 public void Cache(UUID userID, InventoryFolderBase root)
18 { 48 {
19 lock (m_RootFolders) 49 m_RootFolders.AddOrUpdate(userID, root, CACHE_EXPIRATION_SECONDS);
20 m_RootFolders.AddOrUpdate(userID, root, CACHE_EXPIRATION_SECONDS);
21 } 50 }
22 51
23 public InventoryFolderBase GetRootFolder(UUID userID) 52 public InventoryFolderBase GetRootFolder(UUID userID)
@@ -29,29 +58,37 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
29 return null; 58 return null;
30 } 59 }
31 60
32 public void Cache(UUID userID, AssetType type, InventoryFolderBase folder) 61 public void Cache(UUID userID, FolderType type, InventoryFolderBase folder)
33 { 62 {
34 lock (m_FolderTypes) 63 Dictionary<FolderType, InventoryFolderBase> ff = null;
64 if (!m_FolderTypes.TryGetValue(userID, out ff))
65 {
66 ff = new Dictionary<FolderType, InventoryFolderBase>();
67 m_FolderTypes.Add(userID, ff, CACHE_EXPIRATION_SECONDS);
68 }
69
70 // We need to lock here since two threads could potentially retrieve the same dictionary
71 // and try to add a folder for that type simultaneously. Dictionary<>.Add() is not described as thread-safe in the SDK
72 // even if the folders are identical.
73 lock (ff)
35 { 74 {
36 Dictionary<AssetType, InventoryFolderBase> ff = null;
37 if (!m_FolderTypes.TryGetValue(userID, out ff))
38 {
39 ff = new Dictionary<AssetType, InventoryFolderBase>();
40 m_FolderTypes.Add(userID, ff, CACHE_EXPIRATION_SECONDS);
41 }
42 if (!ff.ContainsKey(type)) 75 if (!ff.ContainsKey(type))
43 ff.Add(type, folder); 76 ff.Add(type, folder);
44 } 77 }
45 } 78 }
46 79
47 public InventoryFolderBase GetFolderForType(UUID userID, AssetType type) 80 public InventoryFolderBase GetFolderForType(UUID userID, FolderType type)
48 { 81 {
49 Dictionary<AssetType, InventoryFolderBase> ff = null; 82 Dictionary<FolderType, InventoryFolderBase> ff = null;
50 if (m_FolderTypes.TryGetValue(userID, out ff)) 83 if (m_FolderTypes.TryGetValue(userID, out ff))
51 { 84 {
52 InventoryFolderBase f = null; 85 InventoryFolderBase f = null;
53 if (ff.TryGetValue(type, out f)) 86
54 return f; 87 lock (ff)
88 {
89 if (ff.TryGetValue(type, out f))
90 return f;
91 }
55 } 92 }
56 93
57 return null; 94 return null;
@@ -59,16 +96,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
59 96
60 public void Cache(UUID userID, InventoryCollection inv) 97 public void Cache(UUID userID, InventoryCollection inv)
61 { 98 {
62 lock (m_Inventories) 99 m_Inventories.AddOrUpdate(userID, inv, 120);
63 m_Inventories.AddOrUpdate(userID, inv, 120);
64 }
65
66 public InventoryCollection GetUserInventory(UUID userID)
67 {
68 InventoryCollection inv = null;
69 if (m_Inventories.TryGetValue(userID, out inv))
70 return inv;
71 return null;
72 } 100 }
73 101
74 public InventoryCollection GetFolderContent(UUID userID, UUID folderID) 102 public InventoryCollection GetFolderContent(UUID userID, UUID folderID)
@@ -78,7 +106,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
78 if (m_Inventories.TryGetValue(userID, out inv)) 106 if (m_Inventories.TryGetValue(userID, out inv))
79 { 107 {
80 c = new InventoryCollection(); 108 c = new InventoryCollection();
81 c.UserID = userID; 109 c.OwnerID = userID;
82 110
83 c.Folders = inv.Folders.FindAll(delegate(InventoryFolderBase f) 111 c.Folders = inv.Folders.FindAll(delegate(InventoryFolderBase f)
84 { 112 {
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs
index ec5751d..20d4e02 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs
@@ -33,6 +33,7 @@ using System;
33using System.Collections.Generic; 33using System.Collections.Generic;
34using System.Reflection; 34using System.Reflection;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Framework.Monitoring;
36using OpenSim.Data; 37using OpenSim.Data;
37using OpenSim.Server.Base; 38using OpenSim.Server.Base;
38using OpenSim.Region.Framework.Interfaces; 39using OpenSim.Region.Framework.Interfaces;
@@ -164,22 +165,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
164 return m_InventoryService.GetInventorySkeleton(userId); 165 return m_InventoryService.GetInventorySkeleton(userId);
165 } 166 }
166 167
167 public InventoryCollection GetUserInventory(UUID id)
168 {
169 return m_InventoryService.GetUserInventory(id);
170 }
171
172 public void GetUserInventory(UUID userID, InventoryReceiptCallback callback)
173 {
174 m_InventoryService.GetUserInventory(userID, callback);
175 }
176
177 public InventoryFolderBase GetRootFolder(UUID userID) 168 public InventoryFolderBase GetRootFolder(UUID userID)
178 { 169 {
179 return m_InventoryService.GetRootFolder(userID); 170 return m_InventoryService.GetRootFolder(userID);
180 } 171 }
181 172
182 public InventoryFolderBase GetFolderForType(UUID userID, AssetType type) 173 public InventoryFolderBase GetFolderForType(UUID userID, FolderType type)
183 { 174 {
184 return m_InventoryService.GetFolderForType(userID, type); 175 return m_InventoryService.GetFolderForType(userID, type);
185 } 176 }
@@ -193,16 +184,30 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
193 // Protect ourselves against the caller subsequently modifying the items list 184 // Protect ourselves against the caller subsequently modifying the items list
194 List<InventoryItemBase> items = new List<InventoryItemBase>(invCol.Items); 185 List<InventoryItemBase> items = new List<InventoryItemBase>(invCol.Items);
195 186
196 Util.FireAndForget(delegate 187 WorkManager.RunInThread(delegate
197 { 188 {
198 foreach (InventoryItemBase item in items) 189 foreach (InventoryItemBase item in items)
199 UserManager.AddUser(item.CreatorIdAsUuid, item.CreatorData); 190 if (!string.IsNullOrEmpty(item.CreatorData))
200 }); 191 UserManager.AddUser(item.CreatorIdAsUuid, item.CreatorData);
192 }, null, string.Format("GetFolderContent (user {0}, folder {1})", userID, folderID));
201 } 193 }
202 194
203 return invCol; 195 return invCol;
204 } 196 }
205 197
198 public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs)
199 {
200 InventoryCollection[] invColl = new InventoryCollection[folderIDs.Length];
201 int i = 0;
202 foreach (UUID fid in folderIDs)
203 {
204 invColl[i++] = GetFolderContent(principalID, fid);
205 }
206
207 return invColl;
208
209 }
210
206 public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID) 211 public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID)
207 { 212 {
208 return m_InventoryService.GetFolderItems(userID, folderID); 213 return m_InventoryService.GetFolderItems(userID, folderID);
@@ -302,6 +307,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
302 return item; 307 return item;
303 } 308 }
304 309
310 public InventoryItemBase[] GetMultipleItems(UUID userID, UUID[] itemIDs)
311 {
312 return m_InventoryService.GetMultipleItems(userID, itemIDs);
313 }
314
305 public InventoryFolderBase GetFolder(InventoryFolderBase folder) 315 public InventoryFolderBase GetFolder(InventoryFolderBase folder)
306 { 316 {
307 return m_InventoryService.GetFolder(folder); 317 return m_InventoryService.GetFolder(folder);
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs
index 2d3ba82..978b9d9 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs
@@ -172,21 +172,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
172 return m_RemoteConnector.GetInventorySkeleton(userId); 172 return m_RemoteConnector.GetInventorySkeleton(userId);
173 } 173 }
174 174
175 public InventoryCollection GetUserInventory(UUID userID)
176 {
177 return m_RemoteConnector.GetUserInventory(userID);
178 }
179
180 public void GetUserInventory(UUID userID, InventoryReceiptCallback callback)
181 {
182 }
183
184 public InventoryFolderBase GetRootFolder(UUID userID) 175 public InventoryFolderBase GetRootFolder(UUID userID)
185 { 176 {
186 return m_RemoteConnector.GetRootFolder(userID); 177 return m_RemoteConnector.GetRootFolder(userID);
187 } 178 }
188 179
189 public InventoryFolderBase GetFolderForType(UUID userID, AssetType type) 180 public InventoryFolderBase GetFolderForType(UUID userID, FolderType type)
190 { 181 {
191 return m_RemoteConnector.GetFolderForType(userID, type); 182 return m_RemoteConnector.GetFolderForType(userID, type);
192 } 183 }
@@ -195,22 +186,29 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
195 { 186 {
196 InventoryCollection invCol = m_RemoteConnector.GetFolderContent(userID, folderID); 187 InventoryCollection invCol = m_RemoteConnector.GetFolderContent(userID, folderID);
197 188
198 if (invCol != null && UserManager != null) 189 // Commenting this for now, because it's causing more grief than good
199 { 190 //if (invCol != null && UserManager != null)
200 // Protect ourselves against the caller subsequently modifying the items list 191 //{
201 List<InventoryItemBase> items = new List<InventoryItemBase>(invCol.Items); 192 // // Protect ourselves against the caller subsequently modifying the items list
202 193 // List<InventoryItemBase> items = new List<InventoryItemBase>(invCol.Items);
203 if (items != null && items.Count > 0) 194
204 Util.FireAndForget(delegate 195 // if (items != null && items.Count > 0)
205 { 196 // //Util.FireAndForget(delegate
206 foreach (InventoryItemBase item in items) 197 // //{
207 UserManager.AddUser(item.CreatorIdAsUuid, item.CreatorData); 198 // foreach (InventoryItemBase item in items)
208 }); 199 // if (!string.IsNullOrEmpty(item.CreatorData))
209 } 200 // UserManager.AddUser(item.CreatorIdAsUuid, item.CreatorData);
201 // //});
202 //}
210 203
211 return invCol; 204 return invCol;
212 } 205 }
213 206
207 public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs)
208 {
209 return m_RemoteConnector.GetMultipleFoldersContent(principalID, folderIDs);
210 }
211
214 public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID) 212 public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID)
215 { 213 {
216 return m_RemoteConnector.GetFolderItems(userID, folderID); 214 return m_RemoteConnector.GetFolderItems(userID, folderID);
@@ -305,6 +303,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
305 return m_RemoteConnector.GetItem(item); 303 return m_RemoteConnector.GetItem(item);
306 } 304 }
307 305
306 public InventoryItemBase[] GetMultipleItems(UUID userID, UUID[] itemIDs)
307 {
308 if (itemIDs == null)
309 return new InventoryItemBase[0];
310
311 return m_RemoteConnector.GetMultipleItems(userID, itemIDs);
312 }
313
308 public InventoryFolderBase GetFolder(InventoryFolderBase folder) 314 public InventoryFolderBase GetFolder(InventoryFolderBase folder)
309 { 315 {
310 //m_log.DebugFormat("[XINVENTORY CONNECTOR]: GetFolder {0}", folder.ID); 316 //m_log.DebugFormat("[XINVENTORY CONNECTOR]: GetFolder {0}", folder.ID);
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs
index a839086..08d6bdd 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs
@@ -53,10 +53,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
53 /// </remarks> 53 /// </remarks>
54 54
55 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MapImageServiceModule")] 55 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MapImageServiceModule")]
56 public class MapImageServiceModule : ISharedRegionModule 56 public class MapImageServiceModule : IMapImageUploadModule, ISharedRegionModule
57 { 57 {
58 private static readonly ILog m_log = 58 private static readonly ILog m_log =
59 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 59 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
60 private static string LogHeader = "[MAP IMAGE SERVICE MODULE]:";
60 61
61 private bool m_enabled = false; 62 private bool m_enabled = false;
62 private IMapImageService m_MapService; 63 private IMapImageService m_MapService;
@@ -65,7 +66,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
65 66
66 private int m_refreshtime = 0; 67 private int m_refreshtime = 0;
67 private int m_lastrefresh = 0; 68 private int m_lastrefresh = 0;
68 private System.Timers.Timer m_refreshTimer = new System.Timers.Timer(); 69 private System.Timers.Timer m_refreshTimer;
69 70
70 #region ISharedRegionModule 71 #region ISharedRegionModule
71 72
@@ -75,7 +76,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
75 public void Close() { } 76 public void Close() { }
76 public void PostInitialise() { } 77 public void PostInitialise() { }
77 78
78
79 ///<summary> 79 ///<summary>
80 /// 80 ///
81 ///</summary> 81 ///</summary>
@@ -94,14 +94,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
94 return; 94 return;
95 95
96 int refreshminutes = Convert.ToInt32(config.GetString("RefreshTime")); 96 int refreshminutes = Convert.ToInt32(config.GetString("RefreshTime"));
97 if (refreshminutes <= 0) 97
98 // if refresh is less than zero, disable the module
99 if (refreshminutes < 0)
98 { 100 {
99 m_log.WarnFormat("[MAP IMAGE SERVICE MODULE]: No refresh time given in config. Module disabled."); 101 m_log.WarnFormat("[MAP IMAGE SERVICE MODULE]: Negative refresh time given in config. Module disabled.");
100 return; 102 return;
101 } 103 }
102 104
103 m_refreshtime = refreshminutes * 60 * 1000; // convert from minutes to ms
104
105 string service = config.GetString("LocalServiceModule", string.Empty); 105 string service = config.GetString("LocalServiceModule", string.Empty);
106 if (service == string.Empty) 106 if (service == string.Empty)
107 { 107 {
@@ -116,15 +116,25 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
116 m_log.WarnFormat("[MAP IMAGE SERVICE MODULE]: Unable to load LocalServiceModule from {0}. MapService module disabled. Please fix the configuration.", service); 116 m_log.WarnFormat("[MAP IMAGE SERVICE MODULE]: Unable to load LocalServiceModule from {0}. MapService module disabled. Please fix the configuration.", service);
117 return; 117 return;
118 } 118 }
119
120 // we don't want the timer if the interval is zero, but we still want this module enables
121 if(refreshminutes > 0)
122 {
123 m_refreshtime = refreshminutes * 60 * 1000; // convert from minutes to ms
124
125 m_refreshTimer = new System.Timers.Timer();
126 m_refreshTimer.Enabled = true;
127 m_refreshTimer.AutoReset = true;
128 m_refreshTimer.Interval = m_refreshtime;
129 m_refreshTimer.Elapsed += new ElapsedEventHandler(HandleMaptileRefresh);
119 130
120 m_refreshTimer.Enabled = true; 131 m_log.InfoFormat("[MAP IMAGE SERVICE MODULE]: enabled with refresh time {0} min and service object {1}",
121 m_refreshTimer.AutoReset = true;
122 m_refreshTimer.Interval = m_refreshtime;
123 m_refreshTimer.Elapsed += new ElapsedEventHandler(HandleMaptileRefresh);
124
125 m_log.InfoFormat("[MAP IMAGE SERVICE MODULE]: enabled with refresh time {0}min and service object {1}",
126 refreshminutes, service); 132 refreshminutes, service);
127 133 }
134 else
135 {
136 m_log.InfoFormat("[MAP IMAGE SERVICE MODULE]: enabled with no refresh and service object {0}", service);
137 }
128 m_enabled = true; 138 m_enabled = true;
129 } 139 }
130 140
@@ -133,7 +143,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
133 ///</summary> 143 ///</summary>
134 public void AddRegion(Scene scene) 144 public void AddRegion(Scene scene)
135 { 145 {
136 if (! m_enabled) 146 if (!m_enabled)
137 return; 147 return;
138 148
139 // Every shared region module has to maintain an indepedent list of 149 // Every shared region module has to maintain an indepedent list of
@@ -141,7 +151,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
141 lock (m_scenes) 151 lock (m_scenes)
142 m_scenes[scene.RegionInfo.RegionID] = scene; 152 m_scenes[scene.RegionInfo.RegionID] = scene;
143 153
144 scene.EventManager.OnRegionReadyStatusChange += s => { if (s.Ready) UploadMapTile(s); }; 154 // v2 Map generation on startup is now handled by scene to allow bmp to be shared with
155 // v1 service and not generate map tiles twice as was previous behavior
156 //scene.EventManager.OnRegionReadyStatusChange += s => { if (s.Ready) UploadMapTile(s); };
157
158 scene.RegisterModuleInterface<IMapImageUploadModule>(this);
145 } 159 }
146 160
147 ///<summary> 161 ///<summary>
@@ -188,42 +202,101 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
188 m_lastrefresh = Util.EnvironmentTickCount(); 202 m_lastrefresh = Util.EnvironmentTickCount();
189 } 203 }
190 204
205 public void UploadMapTile(IScene scene, Bitmap mapTile)
206 {
207 if (mapTile == null)
208 {
209 m_log.WarnFormat("{0} Cannot upload null image", LogHeader);
210 return;
211 }
212
213 m_log.DebugFormat("{0} Upload maptile for {1}", LogHeader, scene.Name);
214
215 // mapTile.Save( // DEBUG DEBUG
216 // String.Format("maptiles/raw-{0}-{1}-{2}.jpg", regionName, scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY),
217 // ImageFormat.Jpeg);
218 // If the region/maptile is legacy sized, just upload the one tile like it has always been done
219 if (mapTile.Width == Constants.RegionSize && mapTile.Height == Constants.RegionSize)
220 {
221 ConvertAndUploadMaptile(mapTile,
222 scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY,
223 scene.RegionInfo.RegionName);
224 }
225 else
226 {
227 // For larger regions (varregion) we must cut the region image into legacy sized
228 // pieces since that is how the maptile system works.
229 // Note the assumption that varregions are always a multiple of legacy size.
230 for (uint xx = 0; xx < mapTile.Width; xx += Constants.RegionSize)
231 {
232 for (uint yy = 0; yy < mapTile.Height; yy += Constants.RegionSize)
233 {
234 // Images are addressed from the upper left corner so have to do funny
235 // math to pick out the sub-tile since regions are numbered from
236 // the lower left.
237 Rectangle rect = new Rectangle(
238 (int)xx,
239 mapTile.Height - (int)yy - (int)Constants.RegionSize,
240 (int)Constants.RegionSize, (int)Constants.RegionSize);
241 using (Bitmap subMapTile = mapTile.Clone(rect, mapTile.PixelFormat))
242 {
243 ConvertAndUploadMaptile(subMapTile,
244 scene.RegionInfo.RegionLocX + (xx / Constants.RegionSize),
245 scene.RegionInfo.RegionLocY + (yy / Constants.RegionSize),
246 scene.Name);
247 }
248 }
249 }
250 }
251 }
252
191 ///<summary> 253 ///<summary>
192 /// 254 ///
193 ///</summary> 255 ///</summary>
194 private void UploadMapTile(IScene scene) 256 private void UploadMapTile(IScene scene)
195 { 257 {
196 m_log.DebugFormat("[MAP IMAGE SERVICE MODULE]: upload maptile for {0}", scene.RegionInfo.RegionName);
197
198 // Create a JPG map tile and upload it to the AddMapTile API 258 // Create a JPG map tile and upload it to the AddMapTile API
199 byte[] jpgData = Utils.EmptyBytes;
200 IMapImageGenerator tileGenerator = scene.RequestModuleInterface<IMapImageGenerator>(); 259 IMapImageGenerator tileGenerator = scene.RequestModuleInterface<IMapImageGenerator>();
201 if (tileGenerator == null) 260 if (tileGenerator == null)
202 { 261 {
203 m_log.Warn("[MAP IMAGE SERVICE MODULE]: Cannot upload PNG map tile without an ImageGenerator"); 262 m_log.WarnFormat("{0} Cannot upload map tile without an ImageGenerator", LogHeader);
204 return; 263 return;
205 } 264 }
206 265
207 using (Image mapTile = tileGenerator.CreateMapTile()) 266 using (Bitmap mapTile = tileGenerator.CreateMapTile())
208 { 267 {
209 using (MemoryStream stream = new MemoryStream()) 268 if (mapTile != null)
269 {
270 UploadMapTile(scene, mapTile);
271 }
272 else
210 { 273 {
211 mapTile.Save(stream, ImageFormat.Jpeg); 274 m_log.WarnFormat("{0} Tile image generation failed", LogHeader);
212 jpgData = stream.ToArray();
213 } 275 }
214 } 276 }
277 }
215 278
216 if (jpgData == Utils.EmptyBytes) 279 private void ConvertAndUploadMaptile(Image tileImage, uint locX, uint locY, string regionName)
280 {
281 byte[] jpgData = Utils.EmptyBytes;
282
283 using (MemoryStream stream = new MemoryStream())
217 { 284 {
218 m_log.WarnFormat("[MAP IMAGE SERVICE MODULE]: Tile image generation failed"); 285 tileImage.Save(stream, ImageFormat.Jpeg);
219 return; 286 jpgData = stream.ToArray();
220 } 287 }
221 288 if (jpgData != Utils.EmptyBytes)
222 string reason = string.Empty; 289 {
223 if (!m_MapService.AddMapTile((int)scene.RegionInfo.RegionLocX, (int)scene.RegionInfo.RegionLocY, jpgData, out reason)) 290 string reason = string.Empty;
291 if (!m_MapService.AddMapTile((int)locX, (int)locY, jpgData, out reason))
292 {
293 m_log.DebugFormat("{0} Unable to upload tile image for {1} at {2}-{3}: {4}", LogHeader,
294 regionName, locX, locY, reason);
295 }
296 }
297 else
224 { 298 {
225 m_log.DebugFormat("[MAP IMAGE SERVICE MODULE]: Unable to upload tile image for {0} at {1}-{2}: {3}", 299 m_log.WarnFormat("{0} Tile image generation failed for region {1}", LogHeader, regionName);
226 scene.RegionInfo.RegionName, scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY, reason);
227 } 300 }
228 } 301 }
229 } 302 }
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs
index fd89428..bda354f 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs
@@ -125,14 +125,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Neighbour
125 public OpenSim.Services.Interfaces.GridRegion HelloNeighbour(ulong regionHandle, RegionInfo thisRegion) 125 public OpenSim.Services.Interfaces.GridRegion HelloNeighbour(ulong regionHandle, RegionInfo thisRegion)
126 { 126 {
127 uint x, y; 127 uint x, y;
128 Utils.LongToUInts(regionHandle, out x, out y); 128 Util.RegionHandleToRegionLoc(regionHandle, out x, out y);
129 129
130 foreach (Scene s in m_Scenes) 130 foreach (Scene s in m_Scenes)
131 { 131 {
132 if (s.RegionInfo.RegionHandle == regionHandle) 132 if (s.RegionInfo.RegionHandle == regionHandle)
133 { 133 {
134 m_log.DebugFormat("[LOCAL NEIGHBOUR SERVICE CONNECTOR]: HelloNeighbour from region {0} to neighbour {1} at {2}-{3}", 134 m_log.DebugFormat("[LOCAL NEIGHBOUR SERVICE CONNECTOR]: HelloNeighbour from region {0} to neighbour {1} at {2}-{3}",
135 thisRegion.RegionName, s.Name, x / Constants.RegionSize, y / Constants.RegionSize); 135 thisRegion.RegionName, s.Name, x, y );
136 136
137 //m_log.Debug("[NEIGHBOUR CONNECTOR]: Found region to SendHelloNeighbour"); 137 //m_log.Debug("[NEIGHBOUR CONNECTOR]: Found region to SendHelloNeighbour");
138 return s.IncomingHelloNeighbour(thisRegion); 138 return s.IncomingHelloNeighbour(thisRegion);
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs
index 172bea1..50c252c 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs
@@ -69,7 +69,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
69 public void OnMakeRootAgent(ScenePresence sp) 69 public void OnMakeRootAgent(ScenePresence sp)
70 { 70 {
71// m_log.DebugFormat("[PRESENCE DETECTOR]: Detected root presence {0} in {1}", sp.UUID, sp.Scene.RegionInfo.RegionName); 71// m_log.DebugFormat("[PRESENCE DETECTOR]: Detected root presence {0} in {1}", sp.UUID, sp.Scene.RegionInfo.RegionName);
72 m_PresenceService.ReportAgent(sp.ControllingClient.SessionId, sp.Scene.RegionInfo.RegionID); 72 if (sp.PresenceType != PresenceType.Npc)
73 m_PresenceService.ReportAgent(sp.ControllingClient.SessionId, sp.Scene.RegionInfo.RegionID);
73 } 74 }
74 75
75 public void OnNewClient(IClientAPI client) 76 public void OnNewClient(IClientAPI client)
@@ -79,7 +80,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
79 80
80 public void OnConnectionClose(IClientAPI client) 81 public void OnConnectionClose(IClientAPI client)
81 { 82 {
82 if (!client.SceneAgent.IsChildAgent) 83 if (client != null && client.SceneAgent != null && !client.SceneAgent.IsChildAgent)
83 { 84 {
84// m_log.DebugFormat("[PRESENCE DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName); 85// m_log.DebugFormat("[PRESENCE DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName);
85 m_PresenceService.LogoutAgent(client.SessionId); 86 m_PresenceService.LogoutAgent(client.SessionId);
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
index 3c18074..cc8203e 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
@@ -46,11 +46,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47 47
48 /// <summary> 48 /// <summary>
49 /// Version of this service
50 /// </summary>
51 private const string m_Version = "SIMULATION/0.1";
52
53 /// <summary>
54 /// Map region ID to scene. 49 /// Map region ID to scene.
55 /// </summary> 50 /// </summary>
56 private Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>(); 51 private Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>();
@@ -62,28 +57,27 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
62 57
63 #region Region Module interface 58 #region Region Module interface
64 59
65 public void Initialise(IConfigSource config) 60 public void Initialise(IConfigSource configSource)
66 { 61 {
67 IConfig moduleConfig = config.Configs["Modules"]; 62 IConfig moduleConfig = configSource.Configs["Modules"];
68 if (moduleConfig != null) 63 if (moduleConfig != null)
69 { 64 {
70 string name = moduleConfig.GetString("SimulationServices", ""); 65 string name = moduleConfig.GetString("SimulationServices", "");
71 if (name == Name) 66 if (name == Name)
72 { 67 {
73 //IConfig userConfig = config.Configs["SimulationService"]; 68 InitialiseService(configSource);
74 //if (userConfig == null)
75 //{
76 // m_log.Error("[AVATAR CONNECTOR]: SimulationService missing from OpenSim.ini");
77 // return;
78 //}
79 69
80 m_ModuleEnabled = true; 70 m_ModuleEnabled = true;
81 71
82 m_log.Info("[SIMULATION CONNECTOR]: Local simulation enabled"); 72 m_log.Info("[LOCAL SIMULATION CONNECTOR]: Local simulation enabled.");
83 } 73 }
84 } 74 }
85 } 75 }
86 76
77 public void InitialiseService(IConfigSource configSource)
78 {
79 }
80
87 public void PostInitialise() 81 public void PostInitialise()
88 { 82 {
89 } 83 }
@@ -160,7 +154,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
160 154
161 #endregion 155 #endregion
162 156
163 #region ISimulation 157 #region ISimulationService
164 158
165 public IScene GetScene(UUID regionId) 159 public IScene GetScene(UUID regionId)
166 { 160 {
@@ -191,7 +185,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
191 * Agent-related communications 185 * Agent-related communications
192 */ 186 */
193 187
194 public bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, out string reason) 188 public bool CreateAgent(GridRegion source, GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, out string reason)
195 { 189 {
196 if (destination == null) 190 if (destination == null)
197 { 191 {
@@ -203,7 +197,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
203 if (m_scenes.ContainsKey(destination.RegionID)) 197 if (m_scenes.ContainsKey(destination.RegionID))
204 { 198 {
205// m_log.DebugFormat("[LOCAL SIMULATION CONNECTOR]: Found region {0} to send SendCreateChildAgent", destination.RegionName); 199// m_log.DebugFormat("[LOCAL SIMULATION CONNECTOR]: Found region {0} to send SendCreateChildAgent", destination.RegionName);
206 return m_scenes[destination.RegionID].NewUserConnection(aCircuit, teleportFlags, out reason); 200 return m_scenes[destination.RegionID].NewUserConnection(aCircuit, teleportFlags, source, out reason);
207 } 201 }
208 202
209 reason = "Did not find region " + destination.RegionName; 203 reason = "Did not find region " + destination.RegionName;
@@ -219,16 +213,19 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
219 { 213 {
220// m_log.DebugFormat( 214// m_log.DebugFormat(
221// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", 215// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate",
222// s.RegionInfo.RegionName, destination.RegionHandle); 216// destination.RegionName, destination.RegionID);
223 217
224 return m_scenes[destination.RegionID].IncomingChildAgentDataUpdate(cAgentData); 218 return m_scenes[destination.RegionID].IncomingUpdateChildAgent(cAgentData);
225 } 219 }
226 220
227// m_log.DebugFormat("[LOCAL COMMS]: Did not find region {0} for ChildAgentUpdate", regionHandle); 221// m_log.DebugFormat(
222// "[LOCAL COMMS]: Did not find region {0} {1} for ChildAgentUpdate",
223// destination.RegionName, destination.RegionID);
224
228 return false; 225 return false;
229 } 226 }
230 227
231 public bool UpdateAgent(GridRegion destination, AgentPosition cAgentData) 228 public bool UpdateAgent(GridRegion destination, AgentPosition agentPosition)
232 { 229 {
233 if (destination == null) 230 if (destination == null)
234 return false; 231 return false;
@@ -239,38 +236,17 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
239 // note that we really don't need the GridRegion for this call 236 // note that we really don't need the GridRegion for this call
240 foreach (Scene s in m_scenes.Values) 237 foreach (Scene s in m_scenes.Values)
241 { 238 {
242 //m_log.Debug("[LOCAL COMMS]: Found region to send ChildAgentUpdate"); 239// m_log.Debug("[LOCAL COMMS]: Found region to send ChildAgentUpdate");
243 s.IncomingChildAgentDataUpdate(cAgentData); 240 s.IncomingUpdateChildAgent(agentPosition);
244 } 241 }
245 242
246 //m_log.Debug("[LOCAL COMMS]: region not found for ChildAgentUpdate"); 243 //m_log.Debug("[LOCAL COMMS]: region not found for ChildAgentUpdate");
247 return true; 244 return true;
248 } 245 }
249 246
250 public bool RetrieveAgent(GridRegion destination, UUID id, out IAgentData agent) 247 public bool QueryAccess(GridRegion destination, UUID agentID, string agentHomeURI, bool viaTeleport, Vector3 position, List<UUID> features, EntityTransferContext ctx, out string reason)
251 {
252 agent = null;
253
254 if (destination == null)
255 return false;
256
257 if (m_scenes.ContainsKey(destination.RegionID))
258 {
259// m_log.DebugFormat(
260// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate",
261// s.RegionInfo.RegionName, destination.RegionHandle);
262
263 return m_scenes[destination.RegionID].IncomingRetrieveRootAgent(id, out agent);
264 }
265
266 //m_log.Debug("[LOCAL COMMS]: region not found for ChildAgentUpdate");
267 return false;
268 }
269
270 public bool QueryAccess(GridRegion destination, UUID id, Vector3 position, out string version, out string reason)
271 { 248 {
272 reason = "Communications failure"; 249 reason = "Communications failure";
273 version = m_Version;
274 if (destination == null) 250 if (destination == null)
275 return false; 251 return false;
276 252
@@ -279,8 +255,20 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
279// m_log.DebugFormat( 255// m_log.DebugFormat(
280// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", 256// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate",
281// s.RegionInfo.RegionName, destination.RegionHandle); 257// s.RegionInfo.RegionName, destination.RegionHandle);
258 uint sizeX = m_scenes[destination.RegionID].RegionInfo.RegionSizeX;
259 uint sizeY = m_scenes[destination.RegionID].RegionInfo.RegionSizeY;
282 260
283 return m_scenes[destination.RegionID].QueryAccess(id, position, out reason); 261 // Var regions here, and the requesting simulator is in an older version.
262 // We will forbide this, because it crashes the viewers
263 if (ctx.OutboundVersion < 0.3f && (sizeX != 256 || sizeY != 256))
264 {
265 reason = "Destination is a variable-sized region, and source is an old simulator. Consider upgrading.";
266 m_log.DebugFormat("[LOCAL SIMULATION CONNECTOR]: Request to access this variable-sized region from older simulator was denied");
267 return false;
268
269 }
270
271 return m_scenes[destination.RegionID].QueryAccess(agentID, agentHomeURI, viaTeleport, position, features, out reason);
284 } 272 }
285 273
286 //m_log.Debug("[LOCAL COMMS]: region not found for QueryAccess"); 274 //m_log.Debug("[LOCAL COMMS]: region not found for QueryAccess");
@@ -303,7 +291,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
303 return false; 291 return false;
304 } 292 }
305 293
306 public bool CloseAgent(GridRegion destination, UUID id) 294 public bool CloseAgent(GridRegion destination, UUID id, string auth_token)
307 { 295 {
308 if (destination == null) 296 if (destination == null)
309 return false; 297 return false;
@@ -314,7 +302,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
314// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", 302// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate",
315// s.RegionInfo.RegionName, destination.RegionHandle); 303// s.RegionInfo.RegionName, destination.RegionHandle);
316 304
317 Util.FireAndForget(delegate { m_scenes[destination.RegionID].IncomingCloseAgent(id, false); }); 305 m_scenes[destination.RegionID].CloseAgent(id, false, auth_token);
318 return true; 306 return true;
319 } 307 }
320 308
@@ -356,7 +344,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
356 return false; 344 return false;
357 } 345 }
358 346
359 #endregion /* IInterregionComms */ 347 #endregion
360 348
361 #region Misc 349 #region Misc
362 350
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs
index b2a1b23..1e095ca 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
30using System.IO; 31using System.IO;
31using System.Net; 32using System.Net;
32using System.Reflection; 33using System.Reflection;
@@ -37,7 +38,6 @@ using Nini.Config;
37using OpenMetaverse; 38using OpenMetaverse;
38using OpenMetaverse.StructuredData; 39using OpenMetaverse.StructuredData;
39using OpenSim.Framework; 40using OpenSim.Framework;
40using OpenSim.Framework.Communications;
41using OpenSim.Region.Framework.Interfaces; 41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes; 42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Region.Framework.Scenes.Serialization; 43using OpenSim.Region.Framework.Scenes.Serialization;
@@ -50,9 +50,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RemoteSimulationConnectorModule")] 50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RemoteSimulationConnectorModule")]
51 public class RemoteSimulationConnectorModule : ISharedRegionModule, ISimulationService 51 public class RemoteSimulationConnectorModule : ISharedRegionModule, ISimulationService
52 { 52 {
53 private bool initialized = false;
54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 53 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55 54
55 private bool initialized = false;
56 protected bool m_enabled = false; 56 protected bool m_enabled = false;
57 protected Scene m_aScene; 57 protected Scene m_aScene;
58 // RemoteSimulationConnector does not care about local regions; it delegates that to the Local module 58 // RemoteSimulationConnector does not care about local regions; it delegates that to the Local module
@@ -60,31 +60,26 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
60 protected SimulationServiceConnector m_remoteConnector; 60 protected SimulationServiceConnector m_remoteConnector;
61 61
62 protected bool m_safemode; 62 protected bool m_safemode;
63 protected IPAddress m_thisIP;
64 63
65 #region Region Module interface 64 #region Region Module interface
66 65
67 public virtual void Initialise(IConfigSource config) 66 public virtual void Initialise(IConfigSource configSource)
68 { 67 {
69 68 IConfig moduleConfig = configSource.Configs["Modules"];
70 IConfig moduleConfig = config.Configs["Modules"];
71 if (moduleConfig != null) 69 if (moduleConfig != null)
72 { 70 {
73 string name = moduleConfig.GetString("SimulationServices", ""); 71 string name = moduleConfig.GetString("SimulationServices", "");
74 if (name == Name) 72 if (name == Name)
75 { 73 {
76 //IConfig userConfig = config.Configs["SimulationService"]; 74 m_localBackend = new LocalSimulationConnectorModule();
77 //if (userConfig == null) 75
78 //{ 76 m_localBackend.InitialiseService(configSource);
79 // m_log.Error("[AVATAR CONNECTOR]: SimulationService missing from OpenSim.ini");
80 // return;
81 //}
82 77
83 m_remoteConnector = new SimulationServiceConnector(); 78 m_remoteConnector = new SimulationServiceConnector();
84 79
85 m_enabled = true; 80 m_enabled = true;
86 81
87 m_log.Info("[SIMULATION CONNECTOR]: Remote simulation enabled"); 82 m_log.Info("[REMOTE SIMULATION CONNECTOR]: Remote simulation enabled.");
88 } 83 }
89 } 84 }
90 } 85 }
@@ -142,16 +137,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
142 } 137 }
143 138
144 protected virtual void InitOnce(Scene scene) 139 protected virtual void InitOnce(Scene scene)
145 { 140 {
146 m_localBackend = new LocalSimulationConnectorModule();
147 m_aScene = scene; 141 m_aScene = scene;
148 //m_regionClient = new RegionToRegionClient(m_aScene, m_hyperlinkService); 142 //m_regionClient = new RegionToRegionClient(m_aScene, m_hyperlinkService);
149 m_thisIP = Util.GetHostFromDNS(scene.RegionInfo.ExternalHostName);
150 } 143 }
151 144
152 #endregion 145 #endregion
153 146
154 #region IInterregionComms 147 #region ISimulationService
155 148
156 public IScene GetScene(UUID regionId) 149 public IScene GetScene(UUID regionId)
157 { 150 {
@@ -167,7 +160,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
167 * Agent-related communications 160 * Agent-related communications
168 */ 161 */
169 162
170 public bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, out string reason) 163 public bool CreateAgent(GridRegion source, GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, out string reason)
171 { 164 {
172 if (destination == null) 165 if (destination == null)
173 { 166 {
@@ -177,13 +170,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
177 } 170 }
178 171
179 // Try local first 172 // Try local first
180 if (m_localBackend.CreateAgent(destination, aCircuit, teleportFlags, out reason)) 173 if (m_localBackend.CreateAgent(source, destination, aCircuit, teleportFlags, out reason))
181 return true; 174 return true;
182 175
183 // else do the remote thing 176 // else do the remote thing
184 if (!m_localBackend.IsLocalRegion(destination.RegionID)) 177 if (!m_localBackend.IsLocalRegion(destination.RegionID))
185 { 178 {
186 return m_remoteConnector.CreateAgent(destination, aCircuit, teleportFlags, out reason); 179 return m_remoteConnector.CreateAgent(source, destination, aCircuit, teleportFlags, out reason);
187 } 180 }
188 return false; 181 return false;
189 } 182 }
@@ -194,7 +187,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
194 return false; 187 return false;
195 188
196 // Try local first 189 // Try local first
197 if (m_localBackend.IsLocalRegion(destination.RegionHandle)) 190 if (m_localBackend.IsLocalRegion(destination.RegionID))
198 return m_localBackend.UpdateAgent(destination, cAgentData); 191 return m_localBackend.UpdateAgent(destination, cAgentData);
199 192
200 return m_remoteConnector.UpdateAgent(destination, cAgentData); 193 return m_remoteConnector.UpdateAgent(destination, cAgentData);
@@ -206,45 +199,26 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
206 return false; 199 return false;
207 200
208 // Try local first 201 // Try local first
209 if (m_localBackend.IsLocalRegion(destination.RegionHandle)) 202 if (m_localBackend.IsLocalRegion(destination.RegionID))
210 return m_localBackend.UpdateAgent(destination, cAgentData); 203 return m_localBackend.UpdateAgent(destination, cAgentData);
211 204
212 return m_remoteConnector.UpdateAgent(destination, cAgentData); 205 return m_remoteConnector.UpdateAgent(destination, cAgentData);
213 } 206 }
214 207
215 public bool RetrieveAgent(GridRegion destination, UUID id, out IAgentData agent) 208 public bool QueryAccess(GridRegion destination, UUID agentID, string agentHomeURI, bool viaTeleport, Vector3 position, List<UUID> features, EntityTransferContext ctx, out string reason)
216 {
217 agent = null;
218
219 if (destination == null)
220 return false;
221
222 // Try local first
223 if (m_localBackend.RetrieveAgent(destination, id, out agent))
224 return true;
225
226 // else do the remote thing
227 if (!m_localBackend.IsLocalRegion(destination.RegionHandle))
228 return m_remoteConnector.RetrieveAgent(destination, id, out agent);
229
230 return false;
231 }
232
233 public bool QueryAccess(GridRegion destination, UUID id, Vector3 position, out string version, out string reason)
234 { 209 {
235 reason = "Communications failure"; 210 reason = "Communications failure";
236 version = "Unknown";
237 211
238 if (destination == null) 212 if (destination == null)
239 return false; 213 return false;
240 214
241 // Try local first 215 // Try local first
242 if (m_localBackend.QueryAccess(destination, id, position, out version, out reason)) 216 if (m_localBackend.QueryAccess(destination, agentID, agentHomeURI, viaTeleport, position, features, ctx, out reason))
243 return true; 217 return true;
244 218
245 // else do the remote thing 219 // else do the remote thing
246 if (!m_localBackend.IsLocalRegion(destination.RegionID)) 220 if (!m_localBackend.IsLocalRegion(destination.RegionID))
247 return m_remoteConnector.QueryAccess(destination, id, position, out version, out reason); 221 return m_remoteConnector.QueryAccess(destination, agentID, agentHomeURI, viaTeleport, position, features, ctx, out reason);
248 222
249 return false; 223 return false;
250 } 224 }
@@ -263,18 +237,18 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
263 } 237 }
264 238
265 239
266 public bool CloseAgent(GridRegion destination, UUID id) 240 public bool CloseAgent(GridRegion destination, UUID id, string auth_token)
267 { 241 {
268 if (destination == null) 242 if (destination == null)
269 return false; 243 return false;
270 244
271 // Try local first 245 // Try local first
272 if (m_localBackend.CloseAgent(destination, id)) 246 if (m_localBackend.CloseAgent(destination, id, auth_token))
273 return true; 247 return true;
274 248
275 // else do the remote thing 249 // else do the remote thing
276 if (!m_localBackend.IsLocalRegion(destination.RegionHandle)) 250 if (!m_localBackend.IsLocalRegion(destination.RegionID))
277 return m_remoteConnector.CloseAgent(destination, id); 251 return m_remoteConnector.CloseAgent(destination, id, auth_token);
278 252
279 return false; 253 return false;
280 } 254 }
@@ -296,12 +270,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
296 } 270 }
297 271
298 // else do the remote thing 272 // else do the remote thing
299 if (!m_localBackend.IsLocalRegion(destination.RegionHandle)) 273 if (!m_localBackend.IsLocalRegion(destination.RegionID))
300 return m_remoteConnector.CreateObject(destination, newPosition, sog, isLocalCall); 274 return m_remoteConnector.CreateObject(destination, newPosition, sog, isLocalCall);
301 275
302 return false; 276 return false;
303 } 277 }
304 278
305 #endregion /* IInterregionComms */ 279 #endregion
306 } 280 }
307} 281}
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs
index 529bfd7..6d4ac39 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs
@@ -190,7 +190,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts
190 // 190 //
191 public bool StoreUserAccount(UserAccount data) 191 public bool StoreUserAccount(UserAccount data)
192 { 192 {
193 return UserAccountService.StoreUserAccount(data); 193 bool ret = UserAccountService.StoreUserAccount(data);
194 if (ret)
195 m_Cache.Cache(data.PrincipalID, data);
196 return ret;
197 }
198
199 public void InvalidateCache(UUID userID)
200 {
201 m_Cache.Invalidate(userID);
194 } 202 }
195 203
196 #endregion 204 #endregion
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs
index ddef75f..ed52e48 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -61,6 +61,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts
61 //m_log.DebugFormat("[USER CACHE]: cached user {0}", userID); 61 //m_log.DebugFormat("[USER CACHE]: cached user {0}", userID);
62 } 62 }
63 63
64 public void Invalidate(UUID userID)
65 {
66 m_UUIDCache.Remove(userID);
67 }
68
64 public UserAccount Get(UUID userID, out bool inCache) 69 public UserAccount Get(UUID userID, out bool inCache)
65 { 70 {
66 UserAccount account = null; 71 UserAccount account = null;
diff --git a/OpenSim/Region/CoreModules/World/Access/AccessModule.cs b/OpenSim/Region/CoreModules/World/Access/AccessModule.cs
index 1599f15..f567cab 100644
--- a/OpenSim/Region/CoreModules/World/Access/AccessModule.cs
+++ b/OpenSim/Region/CoreModules/World/Access/AccessModule.cs
@@ -91,13 +91,17 @@ namespace OpenSim.Region.CoreModules.World
91 91
92 public void AddRegion(Scene scene) 92 public void AddRegion(Scene scene)
93 { 93 {
94 if (!m_SceneList.Contains(scene)) 94 lock (m_SceneList)
95 m_SceneList.Add(scene); 95 {
96 if (!m_SceneList.Contains(scene))
97 m_SceneList.Add(scene);
98 }
96 } 99 }
97 100
98 public void RemoveRegion(Scene scene) 101 public void RemoveRegion(Scene scene)
99 { 102 {
100 m_SceneList.Remove(scene); 103 lock (m_SceneList)
104 m_SceneList.Remove(scene);
101 } 105 }
102 106
103 public void RegionLoaded(Scene scene) 107 public void RegionLoaded(Scene scene)
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
index c810242..9c6706f 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
@@ -36,6 +36,7 @@ using System.Xml;
36using log4net; 36using log4net;
37using OpenMetaverse; 37using OpenMetaverse;
38using OpenSim.Framework; 38using OpenSim.Framework;
39using OpenSim.Framework.Monitoring;
39using OpenSim.Framework.Serialization; 40using OpenSim.Framework.Serialization;
40using OpenSim.Framework.Serialization.External; 41using OpenSim.Framework.Serialization.External;
41using OpenSim.Region.CoreModules.World.Terrain; 42using OpenSim.Region.CoreModules.World.Terrain;
@@ -96,14 +97,42 @@ namespace OpenSim.Region.CoreModules.World.Archiver
96 97
97 /// <value> 98 /// <value>
98 /// Should the archive being loaded be merged with what is already on the region? 99 /// Should the archive being loaded be merged with what is already on the region?
100 /// Merging usually suppresses terrain and parcel loading
99 /// </value> 101 /// </value>
100 protected bool m_merge; 102 protected bool m_merge;
101 103
102 /// <value> 104 /// <value>
105 /// If true, force the loading of terrain from the oar file
106 /// </value>
107 protected bool m_forceTerrain;
108
109 /// <value>
110 /// If true, force the loading of parcels from the oar file
111 /// </value>
112 protected bool m_forceParcels;
113
114 /// <value>
103 /// Should we ignore any assets when reloading the archive? 115 /// Should we ignore any assets when reloading the archive?
104 /// </value> 116 /// </value>
105 protected bool m_skipAssets; 117 protected bool m_skipAssets;
106 118
119 /// <value>
120 /// Displacement added to each object as it is added to the world
121 /// </value>
122 protected Vector3 m_displacement = Vector3.Zero;
123
124 /// <value>
125 /// Rotation (in radians) to apply to the objects as they are loaded.
126 /// </value>
127 protected float m_rotation = 0f;
128
129 /// <value>
130 /// Center around which to apply the rotation relative to the origional oar position
131 /// </value>
132 protected Vector3 m_rotationCenter = new Vector3(Constants.RegionSize / 2f, Constants.RegionSize / 2f, 0f);
133
134 protected bool m_noObjects = false;
135
107 /// <summary> 136 /// <summary>
108 /// Used to cache lookups for valid uuids. 137 /// Used to cache lookups for valid uuids.
109 /// </summary> 138 /// </summary>
@@ -132,10 +161,22 @@ namespace OpenSim.Region.CoreModules.World.Archiver
132 private IAssetService m_assetService = null; 161 private IAssetService m_assetService = null;
133 162
134 163
135 public ArchiveReadRequest(Scene scene, string loadPath, bool merge, bool skipAssets, Guid requestId) 164 private UUID m_defaultUser;
165
166 public ArchiveReadRequest(Scene scene, string loadPath, Guid requestId, Dictionary<string,object>options)
136 { 167 {
137 m_rootScene = scene; 168 m_rootScene = scene;
138 169
170 if (options.ContainsKey("default-user"))
171 {
172 m_defaultUser = (UUID)options["default-user"];
173 m_log.InfoFormat("Using User {0} as default user", m_defaultUser.ToString());
174 }
175 else
176 {
177 m_defaultUser = scene.RegionInfo.EstateSettings.EstateOwner;
178 }
179
139 m_loadPath = loadPath; 180 m_loadPath = loadPath;
140 try 181 try
141 { 182 {
@@ -150,26 +191,36 @@ namespace OpenSim.Region.CoreModules.World.Archiver
150 } 191 }
151 192
152 m_errorMessage = String.Empty; 193 m_errorMessage = String.Empty;
153 m_merge = merge; 194 m_merge = options.ContainsKey("merge");
154 m_skipAssets = skipAssets; 195 m_forceTerrain = options.ContainsKey("force-terrain");
196 m_forceParcels = options.ContainsKey("force-parcels");
197 m_noObjects = options.ContainsKey("no-objects");
198 m_skipAssets = options.ContainsKey("skipAssets");
155 m_requestId = requestId; 199 m_requestId = requestId;
200 m_displacement = options.ContainsKey("displacement") ? (Vector3)options["displacement"] : Vector3.Zero;
201 m_rotation = options.ContainsKey("rotation") ? (float)options["rotation"] : 0f;
202 m_rotationCenter = options.ContainsKey("rotation-center") ? (Vector3)options["rotation-center"]
203 : new Vector3(scene.RegionInfo.RegionSizeX / 2f, scene.RegionInfo.RegionSizeY / 2f, 0f);
156 204
157 // Zero can never be a valid user id 205 // Zero can never be a valid user or group id
158 m_validUserUuids[UUID.Zero] = false; 206 m_validUserUuids[UUID.Zero] = false;
207 m_validGroupUuids[UUID.Zero] = false;
159 208
160 m_groupsModule = m_rootScene.RequestModuleInterface<IGroupsModule>(); 209 m_groupsModule = m_rootScene.RequestModuleInterface<IGroupsModule>();
161 m_assetService = m_rootScene.AssetService; 210 m_assetService = m_rootScene.AssetService;
162 } 211 }
163 212
164 public ArchiveReadRequest(Scene scene, Stream loadStream, bool merge, bool skipAssets, Guid requestId) 213 public ArchiveReadRequest(Scene scene, Stream loadStream, Guid requestId, Dictionary<string, object>options)
165 { 214 {
166 m_rootScene = scene; 215 m_rootScene = scene;
167 m_loadPath = null; 216 m_loadPath = null;
168 m_loadStream = loadStream; 217 m_loadStream = loadStream;
169 m_merge = merge; 218 m_skipAssets = options.ContainsKey("skipAssets");
170 m_skipAssets = skipAssets; 219 m_merge = options.ContainsKey("merge");
171 m_requestId = requestId; 220 m_requestId = requestId;
172 221
222 m_defaultUser = scene.RegionInfo.EstateSettings.EstateOwner;
223
173 // Zero can never be a valid user id 224 // Zero can never be a valid user id
174 m_validUserUuids[UUID.Zero] = false; 225 m_validUserUuids[UUID.Zero] = false;
175 226
@@ -229,7 +280,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
229 280
230 // Process the file 281 // Process the file
231 282
232 if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH)) 283 if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH) && !m_noObjects)
233 { 284 {
234 sceneContext.SerialisedSceneObjects.Add(Encoding.UTF8.GetString(data)); 285 sceneContext.SerialisedSceneObjects.Add(Encoding.UTF8.GetString(data));
235 } 286 }
@@ -243,7 +294,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
243 if ((successfulAssetRestores + failedAssetRestores) % 250 == 0) 294 if ((successfulAssetRestores + failedAssetRestores) % 250 == 0)
244 m_log.Debug("[ARCHIVER]: Loaded " + successfulAssetRestores + " assets and failed to load " + failedAssetRestores + " assets..."); 295 m_log.Debug("[ARCHIVER]: Loaded " + successfulAssetRestores + " assets and failed to load " + failedAssetRestores + " assets...");
245 } 296 }
246 else if (!m_merge && filePath.StartsWith(ArchiveConstants.TERRAINS_PATH)) 297 else if (filePath.StartsWith(ArchiveConstants.TERRAINS_PATH) && (!m_merge || m_forceTerrain))
247 { 298 {
248 LoadTerrain(scene, filePath, data); 299 LoadTerrain(scene, filePath, data);
249 } 300 }
@@ -251,7 +302,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
251 { 302 {
252 LoadRegionSettings(scene, filePath, data, dearchivedScenes); 303 LoadRegionSettings(scene, filePath, data, dearchivedScenes);
253 } 304 }
254 else if (!m_merge && filePath.StartsWith(ArchiveConstants.LANDDATA_PATH)) 305 else if (filePath.StartsWith(ArchiveConstants.LANDDATA_PATH) && (!m_merge || m_forceParcels))
255 { 306 {
256 sceneContext.SerialisedParcels.Add(Encoding.UTF8.GetString(data)); 307 sceneContext.SerialisedParcels.Add(Encoding.UTF8.GetString(data));
257 } 308 }
@@ -321,7 +372,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
321 // Start the scripts. We delayed this because we want the OAR to finish loading ASAP, so 372 // Start the scripts. We delayed this because we want the OAR to finish loading ASAP, so
322 // that users can enter the scene. If we allow the scripts to start in the loop above 373 // that users can enter the scene. If we allow the scripts to start in the loop above
323 // then they significantly increase the time until the OAR finishes loading. 374 // then they significantly increase the time until the OAR finishes loading.
324 Util.FireAndForget(delegate(object o) 375 WorkManager.RunInThread(o =>
325 { 376 {
326 Thread.Sleep(15000); 377 Thread.Sleep(15000);
327 m_log.Info("[ARCHIVER]: Starting scripts in scene objects"); 378 m_log.Info("[ARCHIVER]: Starting scripts in scene objects");
@@ -336,7 +387,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
336 387
337 sceneContext.SceneObjects.Clear(); 388 sceneContext.SceneObjects.Clear();
338 } 389 }
339 }); 390 }, null, string.Format("ReadArchiveStartScripts (request {0})", m_requestId));
340 391
341 m_log.InfoFormat("[ARCHIVER]: Successfully loaded archive"); 392 m_log.InfoFormat("[ARCHIVER]: Successfully loaded archive");
342 393
@@ -422,6 +473,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
422 // Reload serialized prims 473 // Reload serialized prims
423 m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count); 474 m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count);
424 475
476 OpenMetaverse.Quaternion rot = OpenMetaverse.Quaternion.CreateFromAxisAngle(0, 0, 1, m_rotation);
477
425 UUID oldTelehubUUID = scene.RegionInfo.RegionSettings.TelehubObject; 478 UUID oldTelehubUUID = scene.RegionInfo.RegionSettings.TelehubObject;
426 479
427 IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>(); 480 IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>();
@@ -445,6 +498,32 @@ namespace OpenSim.Region.CoreModules.World.Archiver
445 498
446 SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject); 499 SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject);
447 500
501 // Happily this does not do much to the object since it hasn't been added to the scene yet
502 if (!sceneObject.IsAttachment)
503 {
504 if (m_displacement != Vector3.Zero || m_rotation != 0f)
505 {
506 Vector3 pos = sceneObject.AbsolutePosition;
507 if (m_rotation != 0f)
508 {
509 // Rotate the object
510 sceneObject.RootPart.RotationOffset = rot * sceneObject.GroupRotation;
511 // Get object position relative to rotation axis
512 Vector3 offset = pos - m_rotationCenter;
513 // Rotate the object position
514 offset *= rot;
515 // Restore the object position back to relative to the region
516 pos = m_rotationCenter + offset;
517 }
518 if (m_displacement != Vector3.Zero)
519 {
520 pos += m_displacement;
521 }
522 sceneObject.AbsolutePosition = pos;
523 }
524 }
525
526
448 bool isTelehub = (sceneObject.UUID == oldTelehubUUID) && (oldTelehubUUID != UUID.Zero); 527 bool isTelehub = (sceneObject.UUID == oldTelehubUUID) && (oldTelehubUUID != UUID.Zero);
449 528
450 // For now, give all incoming scene objects new uuids. This will allow scenes to be cloned 529 // For now, give all incoming scene objects new uuids. This will allow scenes to be cloned
@@ -460,58 +539,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
460 oldTelehubUUID = UUID.Zero; 539 oldTelehubUUID = UUID.Zero;
461 } 540 }
462 541
463 // Try to retain the original creator/owner/lastowner if their uuid is present on this grid 542 ModifySceneObject(scene, sceneObject);
464 // or creator data is present. Otherwise, use the estate owner instead.
465 foreach (SceneObjectPart part in sceneObject.Parts)
466 {
467 if (part.CreatorData == null || part.CreatorData == string.Empty)
468 {
469 if (!ResolveUserUuid(scene, part.CreatorID))
470 part.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner;
471 }
472 if (UserManager != null)
473 UserManager.AddUser(part.CreatorID, part.CreatorData);
474
475 if (!ResolveUserUuid(scene, part.OwnerID))
476 part.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner;
477
478 if (!ResolveUserUuid(scene, part.LastOwnerID))
479 part.LastOwnerID = scene.RegionInfo.EstateSettings.EstateOwner;
480
481 if (!ResolveGroupUuid(part.GroupID))
482 part.GroupID = UUID.Zero;
483
484 // And zap any troublesome sit target information
485// part.SitTargetOrientation = new Quaternion(0, 0, 0, 1);
486// part.SitTargetPosition = new Vector3(0, 0, 0);
487
488 // Fix ownership/creator of inventory items
489 // Not doing so results in inventory items
490 // being no copy/no mod for everyone
491 lock (part.TaskInventory)
492 {
493 TaskInventoryDictionary inv = part.TaskInventory;
494 foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv)
495 {
496 if (!ResolveUserUuid(scene, kvp.Value.OwnerID))
497 {
498 kvp.Value.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner;
499 }
500
501 if (kvp.Value.CreatorData == null || kvp.Value.CreatorData == string.Empty)
502 {
503 if (!ResolveUserUuid(scene, kvp.Value.CreatorID))
504 kvp.Value.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner;
505 }
506
507 if (UserManager != null)
508 UserManager.AddUser(kvp.Value.CreatorID, kvp.Value.CreatorData);
509
510 if (!ResolveGroupUuid(kvp.Value.GroupID))
511 kvp.Value.GroupID = UUID.Zero;
512 }
513 }
514 }
515 543
516 if (scene.AddRestoredSceneObject(sceneObject, true, false)) 544 if (scene.AddRestoredSceneObject(sceneObject, true, false))
517 { 545 {
@@ -535,6 +563,67 @@ namespace OpenSim.Region.CoreModules.World.Archiver
535 scene.RegionInfo.RegionSettings.ClearSpawnPoints(); 563 scene.RegionInfo.RegionSettings.ClearSpawnPoints();
536 } 564 }
537 } 565 }
566
567 /// <summary>
568 /// Optionally modify a loaded SceneObjectGroup. Currently this just ensures that the
569 /// User IDs and Group IDs are valid, but other manipulations could be done as well.
570 /// </summary>
571 private void ModifySceneObject(Scene scene, SceneObjectGroup sceneObject)
572 {
573 // Try to retain the original creator/owner/lastowner if their uuid is present on this grid
574 // or creator data is present. Otherwise, use the estate owner instead.
575 foreach (SceneObjectPart part in sceneObject.Parts)
576 {
577 if (string.IsNullOrEmpty(part.CreatorData))
578 {
579 if (!ResolveUserUuid(scene, part.CreatorID))
580 part.CreatorID = m_defaultUser;
581 }
582 if (UserManager != null)
583 UserManager.AddUser(part.CreatorID, part.CreatorData);
584
585 if (!(ResolveUserUuid(scene, part.OwnerID) || ResolveGroupUuid(part.OwnerID)))
586 part.OwnerID = m_defaultUser;
587
588 if (!(ResolveUserUuid(scene, part.LastOwnerID) || ResolveGroupUuid(part.LastOwnerID)))
589 part.LastOwnerID = m_defaultUser;
590
591 if (!ResolveGroupUuid(part.GroupID))
592 part.GroupID = UUID.Zero;
593
594 // And zap any troublesome sit target information
595 // part.SitTargetOrientation = new Quaternion(0, 0, 0, 1);
596 // part.SitTargetPosition = new Vector3(0, 0, 0);
597
598 // Fix ownership/creator of inventory items
599 // Not doing so results in inventory items
600 // being no copy/no mod for everyone
601 lock (part.TaskInventory)
602 {
603 TaskInventoryDictionary inv = part.TaskInventory;
604 foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv)
605 {
606 if (!(ResolveUserUuid(scene, kvp.Value.OwnerID) || ResolveGroupUuid(kvp.Value.OwnerID)))
607 {
608 kvp.Value.OwnerID = m_defaultUser;
609 }
610
611 if (string.IsNullOrEmpty(kvp.Value.CreatorData))
612 {
613 if (!ResolveUserUuid(scene, kvp.Value.CreatorID))
614 kvp.Value.CreatorID = m_defaultUser;
615 }
616
617 if (UserManager != null)
618 UserManager.AddUser(kvp.Value.CreatorID, kvp.Value.CreatorData);
619
620 if (!ResolveGroupUuid(kvp.Value.GroupID))
621 kvp.Value.GroupID = UUID.Zero;
622 }
623 }
624 }
625 }
626
538 627
539 /// <summary> 628 /// <summary>
540 /// Load serialized parcels. 629 /// Load serialized parcels.
@@ -549,15 +638,29 @@ namespace OpenSim.Region.CoreModules.World.Archiver
549 foreach (string serialisedParcel in serialisedParcels) 638 foreach (string serialisedParcel in serialisedParcels)
550 { 639 {
551 LandData parcel = LandDataSerializer.Deserialize(serialisedParcel); 640 LandData parcel = LandDataSerializer.Deserialize(serialisedParcel);
641
642 if (m_displacement != Vector3.Zero)
643 {
644 Vector3 parcelDisp = new Vector3(m_displacement.X, m_displacement.Y, 0f);
645 parcel.AABBMin += parcelDisp;
646 parcel.AABBMax += parcelDisp;
647 }
552 648
553 // Validate User and Group UUID's 649 // Validate User and Group UUID's
554 650
651 if (!ResolveGroupUuid(parcel.GroupID))
652 parcel.GroupID = UUID.Zero;
653
555 if (parcel.IsGroupOwned) 654 if (parcel.IsGroupOwned)
556 { 655 {
557 if (!ResolveGroupUuid(parcel.GroupID)) 656 if (parcel.GroupID != UUID.Zero)
657 {
658 // In group-owned parcels, OwnerID=GroupID. This should already be the case, but let's make sure.
659 parcel.OwnerID = parcel.GroupID;
660 }
661 else
558 { 662 {
559 parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; 663 parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner;
560 parcel.GroupID = UUID.Zero;
561 parcel.IsGroupOwned = false; 664 parcel.IsGroupOwned = false;
562 } 665 }
563 } 666 }
@@ -565,9 +668,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
565 { 668 {
566 if (!ResolveUserUuid(scene, parcel.OwnerID)) 669 if (!ResolveUserUuid(scene, parcel.OwnerID))
567 parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; 670 parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner;
568
569 if (!ResolveGroupUuid(parcel.GroupID))
570 parcel.GroupID = UUID.Zero;
571 } 671 }
572 672
573 List<LandAccessEntry> accessList = new List<LandAccessEntry>(); 673 List<LandAccessEntry> accessList = new List<LandAccessEntry>();
@@ -604,13 +704,18 @@ namespace OpenSim.Region.CoreModules.World.Archiver
604 /// <returns></returns> 704 /// <returns></returns>
605 private bool ResolveUserUuid(Scene scene, UUID uuid) 705 private bool ResolveUserUuid(Scene scene, UUID uuid)
606 { 706 {
607 if (!m_validUserUuids.ContainsKey(uuid)) 707 lock (m_validUserUuids)
608 { 708 {
609 UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, uuid); 709 if (!m_validUserUuids.ContainsKey(uuid))
610 m_validUserUuids.Add(uuid, account != null); 710 {
611 } 711 // Note: we call GetUserAccount() inside the lock because this UserID is likely
712 // to occur many times, and we only want to query the users service once.
713 UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, uuid);
714 m_validUserUuids.Add(uuid, account != null);
715 }
612 716
613 return m_validUserUuids[uuid]; 717 return m_validUserUuids[uuid];
718 }
614 } 719 }
615 720
616 /// <summary> 721 /// <summary>
@@ -620,22 +725,26 @@ namespace OpenSim.Region.CoreModules.World.Archiver
620 /// <returns></returns> 725 /// <returns></returns>
621 private bool ResolveGroupUuid(UUID uuid) 726 private bool ResolveGroupUuid(UUID uuid)
622 { 727 {
623 if (uuid == UUID.Zero) 728 lock (m_validGroupUuids)
624 return true; // this means the object has no group
625
626 if (!m_validGroupUuids.ContainsKey(uuid))
627 { 729 {
628 bool exists; 730 if (!m_validGroupUuids.ContainsKey(uuid))
629 731 {
630 if (m_groupsModule == null) 732 bool exists;
631 exists = false; 733 if (m_groupsModule == null)
632 else 734 {
633 exists = (m_groupsModule.GetGroupRecord(uuid) != null); 735 exists = false;
736 }
737 else
738 {
739 // Note: we call GetGroupRecord() inside the lock because this GroupID is likely
740 // to occur many times, and we only want to query the groups service once.
741 exists = (m_groupsModule.GetGroupRecord(uuid) != null);
742 }
743 m_validGroupUuids.Add(uuid, exists);
744 }
634 745
635 m_validGroupUuids.Add(uuid, exists); 746 return m_validGroupUuids[uuid];
636 } 747 }
637
638 return m_validGroupUuids[uuid];
639 } 748 }
640 749
641 /// Load an asset 750 /// Load an asset
@@ -672,7 +781,21 @@ namespace OpenSim.Region.CoreModules.World.Archiver
672 sbyte assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension]; 781 sbyte assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension];
673 782
674 if (assetType == (sbyte)AssetType.Unknown) 783 if (assetType == (sbyte)AssetType.Unknown)
784 {
675 m_log.WarnFormat("[ARCHIVER]: Importing {0} byte asset {1} with unknown type", data.Length, uuid); 785 m_log.WarnFormat("[ARCHIVER]: Importing {0} byte asset {1} with unknown type", data.Length, uuid);
786 }
787 else if (assetType == (sbyte)AssetType.Object)
788 {
789 data = SceneObjectSerializer.ModifySerializedObject(UUID.Parse(uuid), data,
790 sog =>
791 {
792 ModifySceneObject(m_rootScene, sog);
793 return true;
794 });
795
796 if (data == null)
797 return false;
798 }
676 799
677 //m_log.DebugFormat("[ARCHIVER]: Importing asset {0}, type {1}", uuid, assetType); 800 //m_log.DebugFormat("[ARCHIVER]: Importing asset {0}, type {1}", uuid, assetType);
678 801
@@ -796,9 +919,18 @@ namespace OpenSim.Region.CoreModules.World.Archiver
796 { 919 {
797 ITerrainModule terrainModule = scene.RequestModuleInterface<ITerrainModule>(); 920 ITerrainModule terrainModule = scene.RequestModuleInterface<ITerrainModule>();
798 921
799 MemoryStream ms = new MemoryStream(data); 922 using (MemoryStream ms = new MemoryStream(data))
800 terrainModule.LoadFromStream(terrainPath, ms); 923 {
801 ms.Close(); 924 if (m_displacement != Vector3.Zero || m_rotation != 0f)
925 {
926 Vector2 rotationCenter = new Vector2(m_rotationCenter.X, m_rotationCenter.Y);
927 terrainModule.LoadFromStream(terrainPath, m_displacement, m_rotation, rotationCenter, ms);
928 }
929 else
930 {
931 terrainModule.LoadFromStream(terrainPath, ms);
932 }
933 }
802 934
803 m_log.DebugFormat("[ARCHIVER]: Restored terrain {0}", terrainPath); 935 m_log.DebugFormat("[ARCHIVER]: Restored terrain {0}", terrainPath);
804 936
@@ -887,4 +1019,4 @@ namespace OpenSim.Region.CoreModules.World.Archiver
887 return dearchivedScenes; 1019 return dearchivedScenes;
888 } 1020 }
889 } 1021 }
890} \ No newline at end of file 1022}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
index 7bdd65c..cb2c7f1 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
@@ -36,6 +36,7 @@ using System.Xml;
36using log4net; 36using log4net;
37using OpenMetaverse; 37using OpenMetaverse;
38using OpenSim.Framework; 38using OpenSim.Framework;
39using OpenSim.Framework.Monitoring;
39using OpenSim.Framework.Serialization; 40using OpenSim.Framework.Serialization;
40using OpenSim.Region.CoreModules.World.Terrain; 41using OpenSim.Region.CoreModules.World.Terrain;
41using OpenSim.Region.Framework.Interfaces; 42using OpenSim.Region.Framework.Interfaces;
@@ -43,7 +44,9 @@ using OpenSim.Region.Framework.Scenes;
43using Ionic.Zlib; 44using Ionic.Zlib;
44using GZipStream = Ionic.Zlib.GZipStream; 45using GZipStream = Ionic.Zlib.GZipStream;
45using CompressionMode = Ionic.Zlib.CompressionMode; 46using CompressionMode = Ionic.Zlib.CompressionMode;
47using CompressionLevel = Ionic.Zlib.CompressionLevel;
46using OpenSim.Framework.Serialization.External; 48using OpenSim.Framework.Serialization.External;
49using PermissionMask = OpenSim.Framework.PermissionMask;
47 50
48namespace OpenSim.Region.CoreModules.World.Archiver 51namespace OpenSim.Region.CoreModules.World.Archiver
49{ 52{
@@ -78,7 +81,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
78 /// Determines which objects will be included in the archive, according to their permissions. 81 /// Determines which objects will be included in the archive, according to their permissions.
79 /// Default is null, meaning no permission checks. 82 /// Default is null, meaning no permission checks.
80 /// </summary> 83 /// </summary>
81 public string CheckPermissions { get; set; } 84 public string FilterContent { get; set; }
82 85
83 protected Scene m_rootScene; 86 protected Scene m_rootScene;
84 protected Stream m_saveStream; 87 protected Stream m_saveStream;
@@ -129,7 +132,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
129 132
130 MultiRegionFormat = false; 133 MultiRegionFormat = false;
131 SaveAssets = true; 134 SaveAssets = true;
132 CheckPermissions = null; 135 FilterContent = null;
133 } 136 }
134 137
135 /// <summary> 138 /// <summary>
@@ -148,7 +151,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
148 151
149 Object temp; 152 Object temp;
150 if (options.TryGetValue("checkPermissions", out temp)) 153 if (options.TryGetValue("checkPermissions", out temp))
151 CheckPermissions = (string)temp; 154 FilterContent = (string)temp;
152 155
153 156
154 // Find the regions to archive 157 // Find the regions to archive
@@ -177,7 +180,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
177 180
178 // Archive the regions 181 // Archive the regions
179 182
180 Dictionary<UUID, AssetType> assetUuids = new Dictionary<UUID, AssetType>(); 183 Dictionary<UUID, sbyte> assetUuids = new Dictionary<UUID, sbyte>();
181 184
182 scenesGroup.ForEachScene(delegate(Scene scene) 185 scenesGroup.ForEachScene(delegate(Scene scene)
183 { 186 {
@@ -198,7 +201,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
198 m_rootScene.AssetService, m_rootScene.UserAccountService, 201 m_rootScene.AssetService, m_rootScene.UserAccountService,
199 m_rootScene.RegionInfo.ScopeID, options, ReceivedAllAssets); 202 m_rootScene.RegionInfo.ScopeID, options, ReceivedAllAssets);
200 203
201 Util.FireAndForget(o => ar.Execute()); 204 WorkManager.RunInThread(o => ar.Execute(), null, "Archive Assets Request");
202 205
203 // CloseArchive() will be called from ReceivedAllAssets() 206 // CloseArchive() will be called from ReceivedAllAssets()
204 } 207 }
@@ -215,9 +218,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver
215 } 218 }
216 } 219 }
217 220
218 private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, AssetType> assetUuids) 221 private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, sbyte> assetUuids)
219 { 222 {
220 m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName); 223 m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.Name);
221 224
222 EntityBase[] entities = scene.GetEntities(); 225 EntityBase[] entities = scene.GetEntities();
223 List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>(); 226 List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>();
@@ -236,7 +239,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
236 239
237 if (!sceneObject.IsDeleted && !sceneObject.IsAttachment) 240 if (!sceneObject.IsDeleted && !sceneObject.IsAttachment)
238 { 241 {
239 if (!CanUserArchiveObject(scene.RegionInfo.EstateSettings.EstateOwner, sceneObject, CheckPermissions, permissionsModule)) 242 if (!CanUserArchiveObject(scene.RegionInfo.EstateSettings.EstateOwner, sceneObject, FilterContent, permissionsModule))
240 { 243 {
241 // The user isn't allowed to copy/transfer this object, so it will not be included in the OAR. 244 // The user isn't allowed to copy/transfer this object, so it will not be included in the OAR.
242 ++numObjectsSkippedPermissions; 245 ++numObjectsSkippedPermissions;
@@ -251,13 +254,13 @@ namespace OpenSim.Region.CoreModules.World.Archiver
251 254
252 if (SaveAssets) 255 if (SaveAssets)
253 { 256 {
254 UuidGatherer assetGatherer = new UuidGatherer(scene.AssetService); 257 UuidGatherer assetGatherer = new UuidGatherer(scene.AssetService, assetUuids);
255 int prevAssets = assetUuids.Count; 258 int prevAssets = assetUuids.Count;
256 259
257 foreach (SceneObjectGroup sceneObject in sceneObjects) 260 foreach (SceneObjectGroup sceneObject in sceneObjects)
258 { 261 assetGatherer.AddForInspection(sceneObject);
259 assetGatherer.GatherAssetUuids(sceneObject, assetUuids); 262
260 } 263 assetGatherer.GatherAll();
261 264
262 m_log.DebugFormat( 265 m_log.DebugFormat(
263 "[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets", 266 "[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets",
@@ -275,16 +278,16 @@ namespace OpenSim.Region.CoreModules.World.Archiver
275 RegionSettings regionSettings = scene.RegionInfo.RegionSettings; 278 RegionSettings regionSettings = scene.RegionInfo.RegionSettings;
276 279
277 if (regionSettings.TerrainTexture1 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_1) 280 if (regionSettings.TerrainTexture1 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_1)
278 assetUuids[regionSettings.TerrainTexture1] = AssetType.Texture; 281 assetUuids[regionSettings.TerrainTexture1] = (sbyte)AssetType.Texture;
279 282
280 if (regionSettings.TerrainTexture2 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_2) 283 if (regionSettings.TerrainTexture2 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_2)
281 assetUuids[regionSettings.TerrainTexture2] = AssetType.Texture; 284 assetUuids[regionSettings.TerrainTexture2] = (sbyte)AssetType.Texture;
282 285
283 if (regionSettings.TerrainTexture3 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_3) 286 if (regionSettings.TerrainTexture3 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_3)
284 assetUuids[regionSettings.TerrainTexture3] = AssetType.Texture; 287 assetUuids[regionSettings.TerrainTexture3] = (sbyte)AssetType.Texture;
285 288
286 if (regionSettings.TerrainTexture4 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_4) 289 if (regionSettings.TerrainTexture4 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_4)
287 assetUuids[regionSettings.TerrainTexture4] = AssetType.Texture; 290 assetUuids[regionSettings.TerrainTexture4] = (sbyte)AssetType.Texture;
288 291
289 Save(scene, sceneObjects, regionDir); 292 Save(scene, sceneObjects, regionDir);
290 } 293 }
@@ -294,12 +297,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver
294 /// </summary> 297 /// </summary>
295 /// <param name="user">The user</param> 298 /// <param name="user">The user</param>
296 /// <param name="objGroup">The object group</param> 299 /// <param name="objGroup">The object group</param>
297 /// <param name="checkPermissions">Which permissions to check: "C" = Copy, "T" = Transfer</param> 300 /// <param name="filterContent">Which permissions to check: "C" = Copy, "T" = Transfer</param>
298 /// <param name="permissionsModule">The scene's permissions module</param> 301 /// <param name="permissionsModule">The scene's permissions module</param>
299 /// <returns>Whether the user is allowed to export the object to an OAR</returns> 302 /// <returns>Whether the user is allowed to export the object to an OAR</returns>
300 private bool CanUserArchiveObject(UUID user, SceneObjectGroup objGroup, string checkPermissions, IPermissionsModule permissionsModule) 303 private bool CanUserArchiveObject(UUID user, SceneObjectGroup objGroup, string filterContent, IPermissionsModule permissionsModule)
301 { 304 {
302 if (checkPermissions == null) 305 if (filterContent == null)
303 return true; 306 return true;
304 307
305 if (permissionsModule == null) 308 if (permissionsModule == null)
@@ -341,9 +344,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver
341 canTransfer |= (obj.EveryoneMask & (uint)PermissionMask.Copy) != 0; 344 canTransfer |= (obj.EveryoneMask & (uint)PermissionMask.Copy) != 0;
342 345
343 bool partPermitted = true; 346 bool partPermitted = true;
344 if (checkPermissions.Contains("C") && !canCopy) 347 if (filterContent.Contains("C") && !canCopy)
345 partPermitted = false; 348 partPermitted = false;
346 if (checkPermissions.Contains("T") && !canTransfer) 349 if (filterContent.Contains("T") && !canTransfer)
347 partPermitted = false; 350 partPermitted = false;
348 351
349 // If the user is the Creator of the object then it can always be included in the OAR 352 // If the user is the Creator of the object then it can always be included in the OAR
@@ -532,7 +535,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
532 if (isMegaregion) 535 if (isMegaregion)
533 size = rcMod.GetSizeOfMegaregion(scene.RegionInfo.RegionID); 536 size = rcMod.GetSizeOfMegaregion(scene.RegionInfo.RegionID);
534 else 537 else
535 size = new Vector2((float)Constants.RegionSize, (float)Constants.RegionSize); 538 size = new Vector2((float)scene.RegionInfo.RegionSizeX, (float)scene.RegionInfo.RegionSizeY);
536 539
537 xtw.WriteElementString("is_megaregion", isMegaregion.ToString()); 540 xtw.WriteElementString("is_megaregion", isMegaregion.ToString());
538 xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y)); 541 xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y));
@@ -568,10 +571,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver
568 string terrainPath = String.Format("{0}{1}{2}.r32", 571 string terrainPath = String.Format("{0}{1}{2}.r32",
569 regionDir, ArchiveConstants.TERRAINS_PATH, scene.RegionInfo.RegionName); 572 regionDir, ArchiveConstants.TERRAINS_PATH, scene.RegionInfo.RegionName);
570 573
571 MemoryStream ms = new MemoryStream(); 574 using (MemoryStream ms = new MemoryStream())
572 scene.RequestModuleInterface<ITerrainModule>().SaveToStream(terrainPath, ms); 575 {
573 m_archiveWriter.WriteFile(terrainPath, ms.ToArray()); 576 scene.RequestModuleInterface<ITerrainModule>().SaveToStream(terrainPath, ms);
574 ms.Close(); 577 m_archiveWriter.WriteFile(terrainPath, ms.ToArray());
578 }
575 579
576 m_log.InfoFormat("[ARCHIVER]: Adding scene objects to archive."); 580 m_log.InfoFormat("[ARCHIVER]: Adding scene objects to archive.");
577 581
@@ -587,19 +591,29 @@ namespace OpenSim.Region.CoreModules.World.Archiver
587 } 591 }
588 } 592 }
589 593
590 protected void ReceivedAllAssets( 594 protected void ReceivedAllAssets(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids, bool timedOut)
591 ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids)
592 { 595 {
593 foreach (UUID uuid in assetsNotFoundUuids) 596 string errorMessage;
597
598 if (timedOut)
594 { 599 {
595 m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid); 600 errorMessage = "Loading assets timed out";
596 } 601 }
602 else
603 {
604 foreach (UUID uuid in assetsNotFoundUuids)
605 {
606 m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid);
607 }
597 608
598 // m_log.InfoFormat( 609 // m_log.InfoFormat(
599 // "[ARCHIVER]: Received {0} of {1} assets requested", 610 // "[ARCHIVER]: Received {0} of {1} assets requested",
600 // assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count); 611 // assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count);
601 612
602 CloseArchive(String.Empty); 613 errorMessage = String.Empty;
614 }
615
616 CloseArchive(errorMessage);
603 } 617 }
604 618
605 /// <summary> 619 /// <summary>
@@ -626,4 +640,4 @@ namespace OpenSim.Region.CoreModules.World.Archiver
626 m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage); 640 m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage);
627 } 641 }
628 } 642 }
629} \ No newline at end of file 643}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs
index 1be6386..6a09caf 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs
@@ -33,11 +33,14 @@ using log4net;
33using NDesk.Options; 33using NDesk.Options;
34using Nini.Config; 34using Nini.Config;
35using Mono.Addins; 35using Mono.Addins;
36
36using OpenSim.Framework; 37using OpenSim.Framework;
37using OpenSim.Framework.Console; 38using OpenSim.Framework.Console;
38using OpenSim.Region.Framework.Interfaces; 39using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
40 41
42using OpenMetaverse;
43
41namespace OpenSim.Region.CoreModules.World.Archiver 44namespace OpenSim.Region.CoreModules.World.Archiver
42{ 45{
43 /// <summary> 46 /// <summary>
@@ -101,9 +104,62 @@ namespace OpenSim.Region.CoreModules.World.Archiver
101 { 104 {
102 bool mergeOar = false; 105 bool mergeOar = false;
103 bool skipAssets = false; 106 bool skipAssets = false;
107 bool forceTerrain = false;
108 bool forceParcels = false;
109 bool noObjects = false;
110 Vector3 displacement = new Vector3(0f, 0f, 0f);
111 String defaultUser = "";
112 float rotation = 0f;
113 Vector3 rotationCenter = new Vector3(Constants.RegionSize / 2f, Constants.RegionSize / 2f, 0);
104 114
105 OptionSet options = new OptionSet().Add("m|merge", delegate (string v) { mergeOar = v != null; }); 115 OptionSet options = new OptionSet();
106 options.Add("s|skip-assets", delegate (string v) { skipAssets = v != null; }); 116 options.Add("m|merge", delegate (string v) { mergeOar = (v != null); });
117 options.Add("s|skip-assets", delegate (string v) { skipAssets = (v != null); });
118 options.Add("force-terrain", delegate (string v) { forceTerrain = (v != null); });
119 options.Add("forceterrain", delegate (string v) { forceTerrain = (v != null); }); // downward compatibility
120 options.Add("force-parcels", delegate (string v) { forceParcels = (v != null); });
121 options.Add("forceparcels", delegate (string v) { forceParcels = (v != null); }); // downward compatibility
122 options.Add("no-objects", delegate (string v) { noObjects = (v != null); });
123 options.Add("default-user=", delegate(string v) { defaultUser = (v == null) ? "" : v; });
124 options.Add("displacement=", delegate (string v) {
125 try
126 {
127 displacement = v == null ? Vector3.Zero : Vector3.Parse(v);
128 }
129 catch
130 {
131 m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing displacement");
132 m_log.ErrorFormat("[ARCHIVER MODULE] Must be represented as vector3: --displacement \"<128,128,0>\"");
133 return;
134 }
135 });
136 options.Add("rotation=", delegate(string v)
137 {
138 try
139 {
140 rotation = v == null ? 0f : float.Parse(v);
141 }
142 catch
143 {
144 m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing rotation");
145 m_log.ErrorFormat("[ARCHIVER MODULE] Must be an angle in degrees between -360 and +360: --rotation 45");
146 return;
147 }
148 // Convert to radians for internals
149 rotation = Util.Clamp<float>(rotation, -359f, 359f) / 180f * (float)Math.PI;
150 });
151 options.Add("rotation-center=", delegate (string v) {
152 try
153 {
154 rotationCenter = v == null ? Vector3.Zero : Vector3.Parse(v);
155 }
156 catch
157 {
158 m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing rotation displacement");
159 m_log.ErrorFormat("[ARCHIVER MODULE] Must be represented as vector3: --rotation-center \"<128,128,0>\"");
160 return;
161 }
162 });
107 163
108 // Send a message to the region ready module 164 // Send a message to the region ready module
109 /* bluewall* Disable this for the time being 165 /* bluewall* Disable this for the time being
@@ -122,13 +178,44 @@ namespace OpenSim.Region.CoreModules.World.Archiver
122// foreach (string param in mainParams) 178// foreach (string param in mainParams)
123// m_log.DebugFormat("GOT PARAM [{0}]", param); 179// m_log.DebugFormat("GOT PARAM [{0}]", param);
124 180
181 Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
182 if (mergeOar) archiveOptions.Add("merge", null);
183 if (skipAssets) archiveOptions.Add("skipAssets", null);
184 if (forceTerrain) archiveOptions.Add("force-terrain", null);
185 if (forceParcels) archiveOptions.Add("force-parcels", null);
186 if (noObjects) archiveOptions.Add("no-objects", null);
187 if (defaultUser != "")
188 {
189 UUID defaultUserUUID = UUID.Zero;
190 try
191 {
192 defaultUserUUID = Scene.UserManagementModule.GetUserIdByName(defaultUser);
193 }
194 catch
195 {
196 m_log.ErrorFormat("[ARCHIVER MODULE] default user must be in format \"First Last\"", defaultUser);
197 }
198 if (defaultUserUUID == UUID.Zero)
199 {
200 m_log.ErrorFormat("[ARCHIVER MODULE] cannot find specified default user {0}", defaultUser);
201 return;
202 }
203 else
204 {
205 archiveOptions.Add("default-user", defaultUserUUID);
206 }
207 }
208 archiveOptions.Add("displacement", displacement);
209 archiveOptions.Add("rotation", rotation);
210 archiveOptions.Add("rotation-center", rotationCenter);
211
125 if (mainParams.Count > 2) 212 if (mainParams.Count > 2)
126 { 213 {
127 DearchiveRegion(mainParams[2], mergeOar, skipAssets, Guid.Empty); 214 DearchiveRegion(mainParams[2], Guid.Empty, archiveOptions);
128 } 215 }
129 else 216 else
130 { 217 {
131 DearchiveRegion(DEFAULT_OAR_BACKUP_FILENAME, mergeOar, skipAssets, Guid.Empty); 218 DearchiveRegion(DEFAULT_OAR_BACKUP_FILENAME, Guid.Empty, archiveOptions);
132 } 219 }
133 } 220 }
134 221
@@ -198,25 +285,27 @@ namespace OpenSim.Region.CoreModules.World.Archiver
198 285
199 public void DearchiveRegion(string loadPath) 286 public void DearchiveRegion(string loadPath)
200 { 287 {
201 DearchiveRegion(loadPath, false, false, Guid.Empty); 288 Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
289 DearchiveRegion(loadPath, Guid.Empty, archiveOptions);
202 } 290 }
203 291
204 public void DearchiveRegion(string loadPath, bool merge, bool skipAssets, Guid requestId) 292 public void DearchiveRegion(string loadPath, Guid requestId, Dictionary<string,object> options)
205 { 293 {
206 m_log.InfoFormat( 294 m_log.InfoFormat(
207 "[ARCHIVER]: Loading archive to region {0} from {1}", Scene.RegionInfo.RegionName, loadPath); 295 "[ARCHIVER]: Loading archive to region {0} from {1}", Scene.RegionInfo.RegionName, loadPath);
208 296
209 new ArchiveReadRequest(Scene, loadPath, merge, skipAssets, requestId).DearchiveRegion(); 297 new ArchiveReadRequest(Scene, loadPath, requestId, options).DearchiveRegion();
210 } 298 }
211 299
212 public void DearchiveRegion(Stream loadStream) 300 public void DearchiveRegion(Stream loadStream)
213 { 301 {
214 DearchiveRegion(loadStream, false, false, Guid.Empty); 302 Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
303 DearchiveRegion(loadStream, Guid.Empty, archiveOptions);
215 } 304 }
216 305
217 public void DearchiveRegion(Stream loadStream, bool merge, bool skipAssets, Guid requestId) 306 public void DearchiveRegion(Stream loadStream, Guid requestId, Dictionary<string, object> options)
218 { 307 {
219 new ArchiveReadRequest(Scene, loadStream, merge, skipAssets, requestId).DearchiveRegion(); 308 new ArchiveReadRequest(Scene, loadStream, requestId, options).DearchiveRegion();
220 } 309 }
221 } 310 }
222} 311}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs
index 95d109c..a8eae56 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsArchiver.cs
@@ -145,17 +145,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver
145 m_assetsWritten++; 145 m_assetsWritten++;
146 146
147 //m_log.DebugFormat("[ARCHIVER]: Added asset {0}", m_assetsWritten); 147 //m_log.DebugFormat("[ARCHIVER]: Added asset {0}", m_assetsWritten);
148 148
149 if (m_assetsWritten % LOG_ASSET_LOAD_NOTIFICATION_INTERVAL == 0) 149 if (m_assetsWritten % LOG_ASSET_LOAD_NOTIFICATION_INTERVAL == 0)
150 m_log.InfoFormat("[ARCHIVER]: Added {0} assets to archive", m_assetsWritten); 150 m_log.InfoFormat("[ARCHIVER]: Added {0} assets to archive", m_assetsWritten);
151 } 151 }
152 152
153 /// <summary>
154 /// Only call this if you need to force a close on the underlying writer.
155 /// </summary>
156 public void ForceClose()
157 {
158 m_archiveWriter.Close();
159 }
160 } 153 }
161} 154}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
index 103eb47..db66c83 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
@@ -33,6 +33,7 @@ using System.Timers;
33using log4net; 33using log4net;
34using OpenMetaverse; 34using OpenMetaverse;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Framework.Monitoring;
36using OpenSim.Framework.Serialization; 37using OpenSim.Framework.Serialization;
37using OpenSim.Framework.Serialization.External; 38using OpenSim.Framework.Serialization.External;
38using OpenSim.Services.Interfaces; 39using OpenSim.Services.Interfaces;
@@ -50,7 +51,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
50 /// Method called when all the necessary assets for an archive request have been received. 51 /// Method called when all the necessary assets for an archive request have been received.
51 /// </summary> 52 /// </summary>
52 public delegate void AssetsRequestCallback( 53 public delegate void AssetsRequestCallback(
53 ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids); 54 ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids, bool timedOut);
54 55
55 enum RequestState 56 enum RequestState
56 { 57 {
@@ -81,7 +82,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
81 /// <value> 82 /// <value>
82 /// uuids to request 83 /// uuids to request
83 /// </value> 84 /// </value>
84 protected IDictionary<UUID, AssetType> m_uuids; 85 protected IDictionary<UUID, sbyte> m_uuids;
85 86
86 /// <value> 87 /// <value>
87 /// Callback used when all the assets requested have been received. 88 /// Callback used when all the assets requested have been received.
@@ -115,7 +116,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
115 protected Dictionary<string, object> m_options; 116 protected Dictionary<string, object> m_options;
116 117
117 protected internal AssetsRequest( 118 protected internal AssetsRequest(
118 AssetsArchiver assetsArchiver, IDictionary<UUID, AssetType> uuids, 119 AssetsArchiver assetsArchiver, IDictionary<UUID, sbyte> uuids,
119 IAssetService assetService, IUserAccountService userService, 120 IAssetService assetService, IUserAccountService userService,
120 UUID scope, Dictionary<string, object> options, 121 UUID scope, Dictionary<string, object> options,
121 AssetsRequestCallback assetsRequestCallback) 122 AssetsRequestCallback assetsRequestCallback)
@@ -143,19 +144,21 @@ namespace OpenSim.Region.CoreModules.World.Archiver
143 m_requestState = RequestState.Running; 144 m_requestState = RequestState.Running;
144 145
145 m_log.DebugFormat("[ARCHIVER]: AssetsRequest executed looking for {0} possible assets", m_repliesRequired); 146 m_log.DebugFormat("[ARCHIVER]: AssetsRequest executed looking for {0} possible assets", m_repliesRequired);
146 147
147 // We can stop here if there are no assets to fetch 148 // We can stop here if there are no assets to fetch
148 if (m_repliesRequired == 0) 149 if (m_repliesRequired == 0)
149 { 150 {
150 m_requestState = RequestState.Completed; 151 m_requestState = RequestState.Completed;
151 PerformAssetsRequestCallback(null); 152 PerformAssetsRequestCallback(false);
152 return; 153 return;
153 } 154 }
154 155
155 m_requestCallbackTimer.Enabled = true; 156 m_requestCallbackTimer.Enabled = true;
156 157
157 foreach (KeyValuePair<UUID, AssetType> kvp in m_uuids) 158 foreach (KeyValuePair<UUID, sbyte> kvp in m_uuids)
158 { 159 {
160// m_log.DebugFormat("[ARCHIVER]: Requesting asset {0}", kvp.Key);
161
159// m_assetService.Get(kvp.Key.ToString(), kvp.Value, PreAssetRequestCallback); 162// m_assetService.Get(kvp.Key.ToString(), kvp.Value, PreAssetRequestCallback);
160 AssetBase asset = m_assetService.Get(kvp.Key.ToString()); 163 AssetBase asset = m_assetService.Get(kvp.Key.ToString());
161 PreAssetRequestCallback(kvp.Key.ToString(), kvp.Value, asset); 164 PreAssetRequestCallback(kvp.Key.ToString(), kvp.Value, asset);
@@ -164,7 +167,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
164 167
165 protected void OnRequestCallbackTimeout(object source, ElapsedEventArgs args) 168 protected void OnRequestCallbackTimeout(object source, ElapsedEventArgs args)
166 { 169 {
167 bool close = true; 170 bool timedOut = true;
168 171
169 try 172 try
170 { 173 {
@@ -174,7 +177,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
174 // the final request came in (assuming that such a thing is possible) 177 // the final request came in (assuming that such a thing is possible)
175 if (m_requestState == RequestState.Completed) 178 if (m_requestState == RequestState.Completed)
176 { 179 {
177 close = false; 180 timedOut = false;
178 return; 181 return;
179 } 182 }
180 183
@@ -223,8 +226,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
223 } 226 }
224 finally 227 finally
225 { 228 {
226 if (close) 229 if (timedOut)
227 m_assetsArchiver.ForceClose(); 230 WorkManager.RunInThread(PerformAssetsRequestCallback, true, "Archive Assets Request Callback");
228 } 231 }
229 } 232 }
230 233
@@ -233,9 +236,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
233 // Check for broken asset types and fix them with the AssetType gleaned by UuidGatherer 236 // Check for broken asset types and fix them with the AssetType gleaned by UuidGatherer
234 if (fetchedAsset != null && fetchedAsset.Type == (sbyte)AssetType.Unknown) 237 if (fetchedAsset != null && fetchedAsset.Type == (sbyte)AssetType.Unknown)
235 { 238 {
236 AssetType type = (AssetType)assetType; 239 m_log.InfoFormat("[ARCHIVER]: Rewriting broken asset type for {0} to {1}", fetchedAsset.ID, SLUtil.AssetTypeFromCode((sbyte)assetType));
237 m_log.InfoFormat("[ARCHIVER]: Rewriting broken asset type for {0} to {1}", fetchedAsset.ID, type); 240 fetchedAsset.Type = (sbyte)assetType;
238 fetchedAsset.Type = (sbyte)type;
239 } 241 }
240 242
241 AssetRequestCallback(fetchedAssetID, this, fetchedAsset); 243 AssetRequestCallback(fetchedAssetID, this, fetchedAsset);
@@ -294,7 +296,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
294 296
295 // We want to stop using the asset cache thread asap 297 // We want to stop using the asset cache thread asap
296 // as we now need to do the work of producing the rest of the archive 298 // as we now need to do the work of producing the rest of the archive
297 Util.FireAndForget(PerformAssetsRequestCallback); 299 WorkManager.RunInThread(PerformAssetsRequestCallback, false, "Archive Assets Request Callback");
298 } 300 }
299 else 301 else
300 { 302 {
@@ -315,9 +317,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver
315 { 317 {
316 Culture.SetCurrentCulture(); 318 Culture.SetCurrentCulture();
317 319
320 Boolean timedOut = (Boolean)o;
321
318 try 322 try
319 { 323 {
320 m_assetsRequestCallback(m_foundAssetUuids, m_notFoundAssetUuids); 324 m_assetsRequestCallback(m_foundAssetUuids, m_notFoundAssetUuids, timedOut);
321 } 325 }
322 catch (Exception e) 326 catch (Exception e)
323 { 327 {
@@ -331,7 +335,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
331 if (asset.Type == (sbyte)AssetType.Object && asset.Data != null && m_options.ContainsKey("home")) 335 if (asset.Type == (sbyte)AssetType.Object && asset.Data != null && m_options.ContainsKey("home"))
332 { 336 {
333 //m_log.DebugFormat("[ARCHIVER]: Rewriting object data for {0}", asset.ID); 337 //m_log.DebugFormat("[ARCHIVER]: Rewriting object data for {0}", asset.ID);
334 string xml = ExternalRepresentationUtils.RewriteSOP(Utils.BytesToString(asset.Data), m_options["home"].ToString(), m_userAccountService, m_scopeID); 338 string xml = ExternalRepresentationUtils.RewriteSOP(Utils.BytesToString(asset.Data), string.Empty, m_options["home"].ToString(), m_userAccountService, m_scopeID);
335 asset.Data = Utils.StringToBytes(xml); 339 asset.Data = Utils.StringToBytes(xml);
336 } 340 }
337 return asset; 341 return asset;
diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
index eec1cec..9f197f5 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
@@ -45,7 +45,6 @@ using OpenSim.Region.Framework.Scenes;
45using OpenSim.Region.Framework.Scenes.Serialization; 45using OpenSim.Region.Framework.Scenes.Serialization;
46using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups; 46using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups;
47using OpenSim.Tests.Common; 47using OpenSim.Tests.Common;
48using OpenSim.Tests.Common.Mock;
49using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants; 48using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants;
50using TarArchiveReader = OpenSim.Framework.Serialization.TarArchiveReader; 49using TarArchiveReader = OpenSim.Framework.Serialization.TarArchiveReader;
51using TarArchiveWriter = OpenSim.Framework.Serialization.TarArchiveWriter; 50using TarArchiveWriter = OpenSim.Framework.Serialization.TarArchiveWriter;
@@ -224,8 +223,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
224 223
225 byte[] data = tar.ReadEntry(out filePath, out tarEntryType); 224 byte[] data = tar.ReadEntry(out filePath, out tarEntryType);
226 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); 225 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
227 226
228 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); 227 Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
228 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions);
229 arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); 229 arr.LoadControlFile(filePath, data, new DearchiveScenesInfo());
230 230
231 Assert.That(arr.ControlFileLoaded, Is.True); 231 Assert.That(arr.ControlFileLoaded, Is.True);
@@ -308,8 +308,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
308 308
309 byte[] data = tar.ReadEntry(out filePath, out tarEntryType); 309 byte[] data = tar.ReadEntry(out filePath, out tarEntryType);
310 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); 310 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
311 311
312 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); 312 Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
313 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions);
313 arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); 314 arr.LoadControlFile(filePath, data, new DearchiveScenesInfo());
314 315
315 Assert.That(arr.ControlFileLoaded, Is.True); 316 Assert.That(arr.ControlFileLoaded, Is.True);
@@ -577,13 +578,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
577 ArchiveConstants.CONTROL_FILE_PATH, 578 ArchiveConstants.CONTROL_FILE_PATH,
578 new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup())); 579 new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
579 580
580 LandObject lo = new LandObject(groupID, true, null); 581 LandObject lo = new LandObject(groupID, true, m_scene);
581 lo.SetLandBitmap(lo.BasicFullRegionLandBitmap()); 582 lo.SetLandBitmap(lo.BasicFullRegionLandBitmap());
582 LandData ld = lo.LandData; 583 LandData ld = lo.LandData;
583 ld.GlobalID = landID; 584 ld.GlobalID = landID;
584 585
585 string ldPath = ArchiveConstants.CreateOarLandDataPath(ld); 586 string ldPath = ArchiveConstants.CreateOarLandDataPath(ld);
586 tar.WriteFile(ldPath, LandDataSerializer.Serialize(ld, null)); 587 Dictionary<string, object> options = new Dictionary<string, object>();
588 tar.WriteFile(ldPath, LandDataSerializer.Serialize(ld, options));
587 tar.Close(); 589 tar.Close();
588 590
589 oarStream = new MemoryStream(oarStream.ToArray()); 591 oarStream = new MemoryStream(oarStream.ToArray());
@@ -752,7 +754,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
752 byte[] archive = archiveWriteStream.ToArray(); 754 byte[] archive = archiveWriteStream.ToArray();
753 MemoryStream archiveReadStream = new MemoryStream(archive); 755 MemoryStream archiveReadStream = new MemoryStream(archive);
754 756
755 m_archiverModule.DearchiveRegion(archiveReadStream, true, false, Guid.Empty); 757 Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
758 archiveOptions.Add("merge", null);
759 m_archiverModule.DearchiveRegion(archiveReadStream, Guid.Empty, archiveOptions);
756 760
757 SceneObjectPart object1Existing = m_scene.GetSceneObjectPart(part1.Name); 761 SceneObjectPart object1Existing = m_scene.GetSceneObjectPart(part1.Name);
758 Assert.That(object1Existing, Is.Not.Null, "object1 was not present after merge"); 762 Assert.That(object1Existing, Is.Not.Null, "object1 was not present after merge");
@@ -860,7 +864,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
860 byte[] data = tar.ReadEntry(out filePath, out tarEntryType); 864 byte[] data = tar.ReadEntry(out filePath, out tarEntryType);
861 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); 865 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
862 866
863 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); 867 Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
868 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions);
864 arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); 869 arr.LoadControlFile(filePath, data, new DearchiveScenesInfo());
865 870
866 Assert.That(arr.ControlFileLoaded, Is.True); 871 Assert.That(arr.ControlFileLoaded, Is.True);
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs
index 4d49794..702b503 100644
--- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs
+++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs
@@ -39,6 +39,7 @@ using OpenSim.Framework.Console;
39using OpenSim.Region.CoreModules.Framework.InterfaceCommander; 39using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
40using OpenSim.Region.Framework.Interfaces; 40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Services.Interfaces;
42 43
43namespace OpenSim.Region.CoreModules.World.Estate 44namespace OpenSim.Region.CoreModules.World.Estate
44{ 45{
@@ -50,9 +51,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51 52
52 protected EstateManagementModule m_module; 53 protected EstateManagementModule m_module;
53 54
54 protected Commander m_commander = new Commander("estate");
55
56 public EstateManagementCommands(EstateManagementModule module) 55 public EstateManagementCommands(EstateManagementModule module)
57 { 56 {
58 m_module = module; 57 m_module = module;
@@ -60,7 +59,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
60 59
61 public void Initialise() 60 public void Initialise()
62 { 61 {
63 m_log.DebugFormat("[ESTATE MODULE]: Setting up estate commands for region {0}", m_module.Scene.RegionInfo.RegionName); 62// m_log.DebugFormat("[ESTATE MODULE]: Setting up estate commands for region {0}", m_module.Scene.RegionInfo.RegionName);
64 63
65 m_module.Scene.AddCommand("Regions", m_module, "set terrain texture", 64 m_module.Scene.AddCommand("Regions", m_module, "set terrain texture",
66 "set terrain texture <number> <uuid> [<x>] [<y>]", 65 "set terrain texture <number> <uuid> [<x>] [<y>]",
@@ -76,12 +75,19 @@ namespace OpenSim.Region.CoreModules.World.Estate
76 " that coordinate. Corner # SW = 0, NW = 1, SE = 2, NE = 3, all corners = -1.", 75 " that coordinate. Corner # SW = 0, NW = 1, SE = 2, NE = 3, all corners = -1.",
77 consoleSetTerrainHeights); 76 consoleSetTerrainHeights);
78 77
78 m_module.Scene.AddCommand("Regions", m_module, "set water height",
79 "set water height <height> [<x>] [<y>]",
80 "Sets the water height in meters. If <x> and <y> are specified, it will only set it on regions with a matching coordinate. " +
81 "Specify -1 in <x> or <y> to wildcard that coordinate.",
82 consoleSetWaterHeight);
83
79 m_module.Scene.AddCommand( 84 m_module.Scene.AddCommand(
80 "Estates", m_module, "estate show", "estate show", "Shows all estates on the simulator.", ShowEstatesCommand); 85 "Estates", m_module, "estate show", "estate show", "Shows all estates on the simulator.", ShowEstatesCommand);
81 } 86 }
82 87
83 public void Close() {} 88 public void Close() {}
84 89
90 #region CommandHandlers
85 protected void consoleSetTerrainTexture(string module, string[] args) 91 protected void consoleSetTerrainTexture(string module, string[] args)
86 { 92 {
87 string num = args[3]; 93 string num = args[3];
@@ -121,7 +127,29 @@ namespace OpenSim.Region.CoreModules.World.Estate
121 } 127 }
122 } 128 }
123 } 129 }
124 130 protected void consoleSetWaterHeight(string module, string[] args)
131 {
132 string heightstring = args[3];
133
134 int x = (args.Length > 4 ? int.Parse(args[4]) : -1);
135 int y = (args.Length > 5 ? int.Parse(args[5]) : -1);
136
137 if (x == -1 || m_module.Scene.RegionInfo.RegionLocX == x)
138 {
139 if (y == -1 || m_module.Scene.RegionInfo.RegionLocY == y)
140 {
141 double selectedheight = double.Parse(heightstring);
142
143 m_log.Debug("[ESTATEMODULE]: Setting water height in " + m_module.Scene.RegionInfo.RegionName + " to " +
144 string.Format(" {0}", selectedheight));
145 m_module.Scene.RegionInfo.RegionSettings.WaterHeight = selectedheight;
146
147 m_module.Scene.RegionInfo.RegionSettings.Save();
148 m_module.TriggerRegionInfoChange();
149 m_module.sendRegionHandshakeToAll();
150 }
151 }
152 }
125 protected void consoleSetTerrainHeights(string module, string[] args) 153 protected void consoleSetTerrainHeights(string module, string[] args)
126 { 154 {
127 string num = args[3]; 155 string num = args[3];
@@ -196,6 +224,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
196 es.EstateName, es.EstateID, m_module.UserManager.GetUserName(es.EstateOwner)); 224 es.EstateName, es.EstateID, m_module.UserManager.GetUserName(es.EstateOwner));
197 225
198 MainConsole.Instance.Output(report.ToString()); 226 MainConsole.Instance.Output(report.ToString());
199 } 227 }
228 #endregion
200 } 229 }
201} \ No newline at end of file 230} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
index 311707b..80fa08a 100644
--- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
@@ -32,6 +32,7 @@ using System.IO;
32using System.Linq; 32using System.Linq;
33using System.Reflection; 33using System.Reflection;
34using System.Security; 34using System.Security;
35using System.Timers;
35using log4net; 36using log4net;
36using Mono.Addins; 37using Mono.Addins;
37using Nini.Config; 38using Nini.Config;
@@ -39,6 +40,7 @@ using OpenMetaverse;
39using OpenSim.Framework; 40using OpenSim.Framework;
40using OpenSim.Region.Framework.Interfaces; 41using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes; 42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Services.Interfaces;
42using RegionFlags = OpenMetaverse.RegionFlags; 44using RegionFlags = OpenMetaverse.RegionFlags;
43 45
44namespace OpenSim.Region.CoreModules.World.Estate 46namespace OpenSim.Region.CoreModules.World.Estate
@@ -48,6 +50,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
48 { 50 {
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50 52
53 private Timer m_regionChangeTimer = new Timer();
51 public Scene Scene { get; private set; } 54 public Scene Scene { get; private set; }
52 public IUserManagement UserManager { get; private set; } 55 public IUserManagement UserManager { get; private set; }
53 56
@@ -112,13 +115,287 @@ namespace OpenSim.Region.CoreModules.World.Estate
112 115
113 #endregion 116 #endregion
114 117
118 #region IEstateModule Functions
119 public uint GetRegionFlags()
120 {
121 RegionFlags flags = RegionFlags.None;
122
123 // Fully implemented
124 //
125 if (Scene.RegionInfo.RegionSettings.AllowDamage)
126 flags |= RegionFlags.AllowDamage;
127 if (Scene.RegionInfo.RegionSettings.BlockTerraform)
128 flags |= RegionFlags.BlockTerraform;
129 if (!Scene.RegionInfo.RegionSettings.AllowLandResell)
130 flags |= RegionFlags.BlockLandResell;
131 if (Scene.RegionInfo.RegionSettings.DisableCollisions)
132 flags |= RegionFlags.SkipCollisions;
133 if (Scene.RegionInfo.RegionSettings.DisableScripts)
134 flags |= RegionFlags.SkipScripts;
135 if (Scene.RegionInfo.RegionSettings.DisablePhysics)
136 flags |= RegionFlags.SkipPhysics;
137 if (Scene.RegionInfo.RegionSettings.BlockFly)
138 flags |= RegionFlags.NoFly;
139 if (Scene.RegionInfo.RegionSettings.RestrictPushing)
140 flags |= RegionFlags.RestrictPushObject;
141 if (Scene.RegionInfo.RegionSettings.AllowLandJoinDivide)
142 flags |= RegionFlags.AllowParcelChanges;
143 if (Scene.RegionInfo.RegionSettings.BlockShowInSearch)
144 flags |= RegionFlags.BlockParcelSearch;
145
146 if (Scene.RegionInfo.RegionSettings.FixedSun)
147 flags |= RegionFlags.SunFixed;
148 if (Scene.RegionInfo.RegionSettings.Sandbox)
149 flags |= RegionFlags.Sandbox;
150 if (Scene.RegionInfo.EstateSettings.AllowVoice)
151 flags |= RegionFlags.AllowVoice;
152 if (Scene.RegionInfo.EstateSettings.AllowLandmark)
153 flags |= RegionFlags.AllowLandmark;
154 if (Scene.RegionInfo.EstateSettings.AllowSetHome)
155 flags |= RegionFlags.AllowSetHome;
156 if (Scene.RegionInfo.EstateSettings.BlockDwell)
157 flags |= RegionFlags.BlockDwell;
158 if (Scene.RegionInfo.EstateSettings.ResetHomeOnTeleport)
159 flags |= RegionFlags.ResetHomeOnTeleport;
160
161
162 // TODO: SkipUpdateInterestList
163
164 // Omitted
165 //
166 // Omitted: NullLayer (what is that?)
167 // Omitted: SkipAgentAction (what does it do?)
168
169 return (uint)flags;
170 }
171
172 public bool IsManager(UUID avatarID)
173 {
174 if (avatarID == Scene.RegionInfo.EstateSettings.EstateOwner)
175 return true;
176
177 List<UUID> ems = new List<UUID>(Scene.RegionInfo.EstateSettings.EstateManagers);
178 if (ems.Contains(avatarID))
179 return true;
180
181 return false;
182 }
183
184 public void sendRegionHandshakeToAll()
185 {
186 Scene.ForEachClient(sendRegionHandshake);
187 }
188
189 public void TriggerEstateInfoChange()
190 {
191 ChangeDelegate change = OnEstateInfoChange;
192
193 if (change != null)
194 change(Scene.RegionInfo.RegionID);
195 }
196
197 public void TriggerRegionInfoChange()
198 {
199 m_regionChangeTimer.Stop();
200 m_regionChangeTimer.Start();
201
202 ChangeDelegate change = OnRegionInfoChange;
203
204 if (change != null)
205 change(Scene.RegionInfo.RegionID);
206 }
207
208 public void setEstateTerrainBaseTexture(int level, UUID texture)
209 {
210 setEstateTerrainBaseTexture(null, level, texture);
211 sendRegionHandshakeToAll();
212 }
213
214 public void setEstateTerrainTextureHeights(int corner, float lowValue, float highValue)
215 {
216 setEstateTerrainTextureHeights(null, corner, lowValue, highValue);
217 }
218
219 public bool IsTerrainXfer(ulong xferID)
220 {
221 lock (this)
222 {
223 if (TerrainUploader == null)
224 return false;
225 else
226 return TerrainUploader.XferID == xferID;
227 }
228 }
229
230 public string SetEstateOwner(int estateID, UserAccount account)
231 {
232 string response;
233
234 // get the current settings from DB
235 EstateSettings dbSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
236 if (dbSettings.EstateID == 0)
237 {
238 response = String.Format("No estate found with ID {0}", estateID);
239 }
240 else if (account.PrincipalID == dbSettings.EstateOwner)
241 {
242 response = String.Format("Estate already belongs to {0} ({1} {2})", account.PrincipalID, account.FirstName, account.LastName);
243 }
244 else
245 {
246 dbSettings.EstateOwner = account.PrincipalID;
247 Scene.EstateDataService.StoreEstateSettings(dbSettings);
248 response = String.Empty;
249
250 // make sure there's a log entry to document the change
251 m_log.InfoFormat("[ESTATE]: Estate Owner for {0} changed to {1} ({2} {3})", dbSettings.EstateName,
252 account.PrincipalID, account.FirstName, account.LastName);
253
254 // propagate the change
255 List<UUID> regions = Scene.GetEstateRegions(estateID);
256 UUID regionId = (regions.Count() > 0) ? regions.ElementAt(0) : UUID.Zero;
257 if (regionId != UUID.Zero)
258 {
259 ChangeDelegate change = OnEstateInfoChange;
260
261 if (change != null)
262 change(regionId);
263 }
264
265 }
266 return response;
267 }
268
269 public string SetEstateName(int estateID, string newName)
270 {
271 string response;
272
273 // get the current settings from DB
274 EstateSettings dbSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
275
276 if (dbSettings.EstateID == 0)
277 {
278 response = String.Format("No estate found with ID {0}", estateID);
279 }
280 else if (newName == dbSettings.EstateName)
281 {
282 response = String.Format("Estate {0} is already named \"{1}\"", estateID, newName);
283 }
284 else
285 {
286 List<int> estates = Scene.EstateDataService.GetEstates(newName);
287 if (estates.Count() > 0)
288 {
289 response = String.Format("An estate named \"{0}\" already exists.", newName);
290 }
291 else
292 {
293 string oldName = dbSettings.EstateName;
294 dbSettings.EstateName = newName;
295 Scene.EstateDataService.StoreEstateSettings(dbSettings);
296 response = String.Empty;
297
298 // make sure there's a log entry to document the change
299 m_log.InfoFormat("[ESTATE]: Estate {0} renamed from \"{1}\" to \"{2}\"", estateID, oldName, newName);
300
301 // propagate the change
302 List<UUID> regions = Scene.GetEstateRegions(estateID);
303 UUID regionId = (regions.Count() > 0) ? regions.ElementAt(0) : UUID.Zero;
304 if (regionId != UUID.Zero)
305 {
306 ChangeDelegate change = OnEstateInfoChange;
307
308 if (change != null)
309 change(regionId);
310 }
311 }
312 }
313 return response;
314 }
315
316 public string SetRegionEstate(RegionInfo regionInfo, int estateID)
317 {
318 string response;
319
320 if (regionInfo.EstateSettings.EstateID == estateID)
321 {
322 response = String.Format("\"{0}\" is already part of estate {1}", regionInfo.RegionName, estateID);
323 }
324 else
325 {
326 // get the current settings from DB
327 EstateSettings dbSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
328 if (dbSettings.EstateID == 0)
329 {
330 response = String.Format("No estate found with ID {0}", estateID);
331 }
332 else if (Scene.EstateDataService.LinkRegion(regionInfo.RegionID, estateID))
333 {
334 // make sure there's a log entry to document the change
335 m_log.InfoFormat("[ESTATE]: Region {0} ({1}) moved to Estate {2} ({3}).", regionInfo.RegionID, regionInfo.RegionName, estateID, dbSettings.EstateName);
336
337 // propagate the change
338 ChangeDelegate change = OnEstateInfoChange;
339
340 if (change != null)
341 change(regionInfo.RegionID);
342
343 response = String.Empty;
344 }
345 else
346 {
347 response = String.Format("Could not move \"{0}\" to estate {1}", regionInfo.RegionName, estateID);
348 }
349 }
350 return response;
351 }
352
353 public string CreateEstate(string estateName, UUID ownerID)
354 {
355 string response;
356 if (string.IsNullOrEmpty(estateName))
357 {
358 response = "No estate name specified.";
359 }
360 else
361 {
362 List<int> estates = Scene.EstateDataService.GetEstates(estateName);
363 if (estates.Count() > 0)
364 {
365 response = String.Format("An estate named \"{0}\" already exists.", estateName);
366 }
367 else
368 {
369 EstateSettings settings = Scene.EstateDataService.CreateNewEstate();
370 if (settings == null)
371 response = String.Format("Unable to create estate \"{0}\" at this simulator", estateName);
372 else
373 {
374 settings.EstateOwner = ownerID;
375 settings.EstateName = estateName;
376 Scene.EstateDataService.StoreEstateSettings(settings);
377 response = String.Empty;
378 }
379 }
380 }
381 return response;
382 }
383
384 #endregion
385
115 #region Packet Data Responders 386 #region Packet Data Responders
116 387
388 private void clientSendDetailedEstateData(IClientAPI remote_client, UUID invoice)
389 {
390 sendDetailedEstateData(remote_client, invoice);
391 sendEstateLists(remote_client, invoice);
392 }
393
117 private void sendDetailedEstateData(IClientAPI remote_client, UUID invoice) 394 private void sendDetailedEstateData(IClientAPI remote_client, UUID invoice)
118 { 395 {
119 uint sun = 0; 396 uint sun = 0;
120 397
121 if (!Scene.RegionInfo.EstateSettings.UseGlobalTime) 398 if (Scene.RegionInfo.EstateSettings.FixedSun)
122 sun = (uint)(Scene.RegionInfo.EstateSettings.SunPosition * 1024.0) + 0x1800; 399 sun = (uint)(Scene.RegionInfo.EstateSettings.SunPosition * 1024.0) + 0x1800;
123 UUID estateOwner; 400 UUID estateOwner;
124 estateOwner = Scene.RegionInfo.EstateSettings.EstateOwner; 401 estateOwner = Scene.RegionInfo.EstateSettings.EstateOwner;
@@ -136,7 +413,10 @@ namespace OpenSim.Region.CoreModules.World.Estate
136 (uint) Scene.RegionInfo.RegionSettings.CovenantChangedDateTime, 413 (uint) Scene.RegionInfo.RegionSettings.CovenantChangedDateTime,
137 Scene.RegionInfo.EstateSettings.AbuseEmail, 414 Scene.RegionInfo.EstateSettings.AbuseEmail,
138 estateOwner); 415 estateOwner);
416 }
139 417
418 private void sendEstateLists(IClientAPI remote_client, UUID invoice)
419 {
140 remote_client.SendEstateList(invoice, 420 remote_client.SendEstateList(invoice,
141 (int)Constants.EstateAccessCodex.EstateManagers, 421 (int)Constants.EstateAccessCodex.EstateManagers,
142 Scene.RegionInfo.EstateSettings.EstateManagers, 422 Scene.RegionInfo.EstateSettings.EstateManagers,
@@ -210,12 +490,6 @@ namespace OpenSim.Region.CoreModules.World.Estate
210 sendRegionInfoPacketToAll(); 490 sendRegionInfoPacketToAll();
211 } 491 }
212 492
213 public void setEstateTerrainBaseTexture(int level, UUID texture)
214 {
215 setEstateTerrainBaseTexture(null, level, texture);
216 sendRegionHandshakeToAll();
217 }
218
219 public void setEstateTerrainBaseTexture(IClientAPI remoteClient, int level, UUID texture) 493 public void setEstateTerrainBaseTexture(IClientAPI remoteClient, int level, UUID texture)
220 { 494 {
221 if (texture == UUID.Zero) 495 if (texture == UUID.Zero)
@@ -242,11 +516,6 @@ namespace OpenSim.Region.CoreModules.World.Estate
242 sendRegionInfoPacketToAll(); 516 sendRegionInfoPacketToAll();
243 } 517 }
244 518
245 public void setEstateTerrainTextureHeights(int corner, float lowValue, float highValue)
246 {
247 setEstateTerrainTextureHeights(null, corner, lowValue, highValue);
248 }
249
250 public void setEstateTerrainTextureHeights(IClientAPI client, int corner, float lowValue, float highValue) 519 public void setEstateTerrainTextureHeights(IClientAPI client, int corner, float lowValue, float highValue)
251 { 520 {
252 switch (corner) 521 switch (corner)
@@ -330,7 +599,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
330 timeInSeconds -= 15; 599 timeInSeconds -= 15;
331 } 600 }
332 601
333 restartModule.ScheduleRestart(UUID.Zero, "Region will restart in {0}", times.ToArray(), true); 602 restartModule.ScheduleRestart(UUID.Zero, "Region will restart in {0}", times.ToArray(), false);
334 603
335 m_log.InfoFormat( 604 m_log.InfoFormat(
336 "User {0} requested restart of region {1} in {2} seconds", 605 "User {0} requested restart of region {1} in {2} seconds",
@@ -372,13 +641,13 @@ namespace OpenSim.Region.CoreModules.World.Estate
372 { 641 {
373 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); 642 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
374 estateSettings.AddEstateUser(user); 643 estateSettings.AddEstateUser(user);
375 estateSettings.Save(); 644 Scene.EstateDataService.StoreEstateSettings(estateSettings);
376 } 645 }
377 } 646 }
378 } 647 }
379 648
380 Scene.RegionInfo.EstateSettings.AddEstateUser(user); 649 Scene.RegionInfo.EstateSettings.AddEstateUser(user);
381 Scene.RegionInfo.EstateSettings.Save(); 650 Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings);
382 651
383 TriggerEstateInfoChange(); 652 TriggerEstateInfoChange();
384 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AccessOptions, Scene.RegionInfo.EstateSettings.EstateAccess, Scene.RegionInfo.EstateSettings.EstateID); 653 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AccessOptions, Scene.RegionInfo.EstateSettings.EstateAccess, Scene.RegionInfo.EstateSettings.EstateID);
@@ -405,13 +674,13 @@ namespace OpenSim.Region.CoreModules.World.Estate
405 { 674 {
406 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); 675 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
407 estateSettings.RemoveEstateUser(user); 676 estateSettings.RemoveEstateUser(user);
408 estateSettings.Save(); 677 Scene.EstateDataService.StoreEstateSettings(estateSettings);
409 } 678 }
410 } 679 }
411 } 680 }
412 681
413 Scene.RegionInfo.EstateSettings.RemoveEstateUser(user); 682 Scene.RegionInfo.EstateSettings.RemoveEstateUser(user);
414 Scene.RegionInfo.EstateSettings.Save(); 683 Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings);
415 684
416 TriggerEstateInfoChange(); 685 TriggerEstateInfoChange();
417 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AccessOptions, Scene.RegionInfo.EstateSettings.EstateAccess, Scene.RegionInfo.EstateSettings.EstateID); 686 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AccessOptions, Scene.RegionInfo.EstateSettings.EstateAccess, Scene.RegionInfo.EstateSettings.EstateID);
@@ -437,13 +706,13 @@ namespace OpenSim.Region.CoreModules.World.Estate
437 { 706 {
438 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); 707 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
439 estateSettings.AddEstateGroup(user); 708 estateSettings.AddEstateGroup(user);
440 estateSettings.Save(); 709 Scene.EstateDataService.StoreEstateSettings(estateSettings);
441 } 710 }
442 } 711 }
443 } 712 }
444 713
445 Scene.RegionInfo.EstateSettings.AddEstateGroup(user); 714 Scene.RegionInfo.EstateSettings.AddEstateGroup(user);
446 Scene.RegionInfo.EstateSettings.Save(); 715 Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings);
447 716
448 TriggerEstateInfoChange(); 717 TriggerEstateInfoChange();
449 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AllowedGroups, Scene.RegionInfo.EstateSettings.EstateGroups, Scene.RegionInfo.EstateSettings.EstateID); 718 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AllowedGroups, Scene.RegionInfo.EstateSettings.EstateGroups, Scene.RegionInfo.EstateSettings.EstateID);
@@ -469,13 +738,13 @@ namespace OpenSim.Region.CoreModules.World.Estate
469 { 738 {
470 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); 739 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
471 estateSettings.RemoveEstateGroup(user); 740 estateSettings.RemoveEstateGroup(user);
472 estateSettings.Save(); 741 Scene.EstateDataService.StoreEstateSettings(estateSettings);
473 } 742 }
474 } 743 }
475 } 744 }
476 745
477 Scene.RegionInfo.EstateSettings.RemoveEstateGroup(user); 746 Scene.RegionInfo.EstateSettings.RemoveEstateGroup(user);
478 Scene.RegionInfo.EstateSettings.Save(); 747 Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings);
479 748
480 TriggerEstateInfoChange(); 749 TriggerEstateInfoChange();
481 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AllowedGroups, Scene.RegionInfo.EstateSettings.EstateGroups, Scene.RegionInfo.EstateSettings.EstateID); 750 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.AllowedGroups, Scene.RegionInfo.EstateSettings.EstateGroups, Scene.RegionInfo.EstateSettings.EstateID);
@@ -524,7 +793,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
524 793
525 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); 794 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
526 estateSettings.AddBan(bitem); 795 estateSettings.AddBan(bitem);
527 estateSettings.Save(); 796 Scene.EstateDataService.StoreEstateSettings(estateSettings);
528 } 797 }
529 } 798 }
530 } 799 }
@@ -537,7 +806,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
537 item.BannedHostIPMask = "0.0.0.0"; 806 item.BannedHostIPMask = "0.0.0.0";
538 807
539 Scene.RegionInfo.EstateSettings.AddBan(item); 808 Scene.RegionInfo.EstateSettings.AddBan(item);
540 Scene.RegionInfo.EstateSettings.Save(); 809 Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings);
541 810
542 TriggerEstateInfoChange(); 811 TriggerEstateInfoChange();
543 812
@@ -546,7 +815,11 @@ namespace OpenSim.Region.CoreModules.World.Estate
546 { 815 {
547 if (!s.IsChildAgent) 816 if (!s.IsChildAgent)
548 { 817 {
549 Scene.TeleportClientHome(user, s.ControllingClient); 818 if (!Scene.TeleportClientHome(user, s.ControllingClient))
819 {
820 s.ControllingClient.Kick("Your access to the region was revoked and TP home failed - you have been logged out.");
821 Scene.CloseAgent(s.UUID, false);
822 }
550 } 823 }
551 } 824 }
552 825
@@ -555,7 +828,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
555 { 828 {
556 remote_client.SendAlertMessage("User is already on the region ban list"); 829 remote_client.SendAlertMessage("User is already on the region ban list");
557 } 830 }
558 //m_scene.RegionInfo.regionBanlist.Add(Manager(user); 831 //Scene.RegionInfo.regionBanlist.Add(Manager(user);
559 remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID); 832 remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID);
560 } 833 }
561 else 834 else
@@ -596,13 +869,13 @@ namespace OpenSim.Region.CoreModules.World.Estate
596 { 869 {
597 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); 870 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
598 estateSettings.RemoveBan(user); 871 estateSettings.RemoveBan(user);
599 estateSettings.Save(); 872 Scene.EstateDataService.StoreEstateSettings(estateSettings);
600 } 873 }
601 } 874 }
602 } 875 }
603 876
604 Scene.RegionInfo.EstateSettings.RemoveBan(listitem.BannedUserID); 877 Scene.RegionInfo.EstateSettings.RemoveBan(listitem.BannedUserID);
605 Scene.RegionInfo.EstateSettings.Save(); 878 Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings);
606 879
607 TriggerEstateInfoChange(); 880 TriggerEstateInfoChange();
608 } 881 }
@@ -611,7 +884,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
611 remote_client.SendAlertMessage("User is not on the region ban list"); 884 remote_client.SendAlertMessage("User is not on the region ban list");
612 } 885 }
613 886
614 //m_scene.RegionInfo.regionBanlist.Add(Manager(user); 887 //Scene.RegionInfo.regionBanlist.Add(Manager(user);
615 remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID); 888 remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID);
616 } 889 }
617 else 890 else
@@ -635,13 +908,13 @@ namespace OpenSim.Region.CoreModules.World.Estate
635 { 908 {
636 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); 909 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
637 estateSettings.AddEstateManager(user); 910 estateSettings.AddEstateManager(user);
638 estateSettings.Save(); 911 Scene.EstateDataService.StoreEstateSettings(estateSettings);
639 } 912 }
640 } 913 }
641 } 914 }
642 915
643 Scene.RegionInfo.EstateSettings.AddEstateManager(user); 916 Scene.RegionInfo.EstateSettings.AddEstateManager(user);
644 Scene.RegionInfo.EstateSettings.Save(); 917 Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings);
645 918
646 TriggerEstateInfoChange(); 919 TriggerEstateInfoChange();
647 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.EstateManagers, Scene.RegionInfo.EstateSettings.EstateManagers, Scene.RegionInfo.EstateSettings.EstateID); 920 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.EstateManagers, Scene.RegionInfo.EstateSettings.EstateManagers, Scene.RegionInfo.EstateSettings.EstateID);
@@ -667,13 +940,13 @@ namespace OpenSim.Region.CoreModules.World.Estate
667 { 940 {
668 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID); 941 estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
669 estateSettings.RemoveEstateManager(user); 942 estateSettings.RemoveEstateManager(user);
670 estateSettings.Save(); 943 Scene.EstateDataService.StoreEstateSettings(estateSettings);
671 } 944 }
672 } 945 }
673 } 946 }
674 947
675 Scene.RegionInfo.EstateSettings.RemoveEstateManager(user); 948 Scene.RegionInfo.EstateSettings.RemoveEstateManager(user);
676 Scene.RegionInfo.EstateSettings.Save(); 949 Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings);
677 950
678 TriggerEstateInfoChange(); 951 TriggerEstateInfoChange();
679 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.EstateManagers, Scene.RegionInfo.EstateSettings.EstateManagers, Scene.RegionInfo.EstateSettings.EstateID); 952 remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.EstateManagers, Scene.RegionInfo.EstateSettings.EstateManagers, Scene.RegionInfo.EstateSettings.EstateID);
@@ -685,7 +958,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
685 } 958 }
686 } 959 }
687 960
688 public void handleOnEstateManageTelehub(IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1) 961 public void HandleOnEstateManageTelehub(IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1)
689 { 962 {
690 SceneObjectPart part; 963 SceneObjectPart part;
691 964
@@ -725,7 +998,9 @@ namespace OpenSim.Region.CoreModules.World.Estate
725 default: 998 default:
726 break; 999 break;
727 } 1000 }
728 SendTelehubInfo(client); 1001
1002 if (client != null)
1003 SendTelehubInfo(client);
729 } 1004 }
730 1005
731 private void SendSimulatorBlueBoxMessage( 1006 private void SendSimulatorBlueBoxMessage(
@@ -777,7 +1052,11 @@ namespace OpenSim.Region.CoreModules.World.Estate
777 ScenePresence s = Scene.GetScenePresence(prey); 1052 ScenePresence s = Scene.GetScenePresence(prey);
778 if (s != null) 1053 if (s != null)
779 { 1054 {
780 Scene.TeleportClientHome(prey, s.ControllingClient); 1055 if (!Scene.TeleportClientHome(prey, s.ControllingClient))
1056 {
1057 s.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out.");
1058 Scene.CloseAgent(s.UUID, false);
1059 }
781 } 1060 }
782 } 1061 }
783 } 1062 }
@@ -795,33 +1074,36 @@ namespace OpenSim.Region.CoreModules.World.Estate
795 // Also make sure they are actually in the region 1074 // Also make sure they are actually in the region
796 ScenePresence p; 1075 ScenePresence p;
797 if(Scene.TryGetScenePresence(client.AgentId, out p)) 1076 if(Scene.TryGetScenePresence(client.AgentId, out p))
798 Scene.TeleportClientHome(p.UUID, p.ControllingClient); 1077 {
1078 if (!Scene.TeleportClientHome(p.UUID, p.ControllingClient))
1079 {
1080 p.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out.");
1081 Scene.CloseAgent(p.UUID, false);
1082 }
1083 }
799 } 1084 }
800 }); 1085 });
801 } 1086 }
802 1087
803 private void AbortTerrainXferHandler(IClientAPI remoteClient, ulong XferID) 1088 private void AbortTerrainXferHandler(IClientAPI remoteClient, ulong XferID)
804 { 1089 {
805 if (TerrainUploader != null) 1090 lock (this)
806 { 1091 {
807 lock (TerrainUploader) 1092 if ((TerrainUploader != null) && (XferID == TerrainUploader.XferID))
808 { 1093 {
809 if (XferID == TerrainUploader.XferID) 1094 remoteClient.OnXferReceive -= TerrainUploader.XferReceive;
810 { 1095 remoteClient.OnAbortXfer -= AbortTerrainXferHandler;
811 remoteClient.OnXferReceive -= TerrainUploader.XferReceive; 1096 TerrainUploader.TerrainUploadDone -= HandleTerrainApplication;
812 remoteClient.OnAbortXfer -= AbortTerrainXferHandler;
813 TerrainUploader.TerrainUploadDone -= HandleTerrainApplication;
814 1097
815 TerrainUploader = null; 1098 TerrainUploader = null;
816 remoteClient.SendAlertMessage("Terrain Upload aborted by the client"); 1099 remoteClient.SendAlertMessage("Terrain Upload aborted by the client");
817 }
818 } 1100 }
819 } 1101 }
820
821 } 1102 }
1103
822 private void HandleTerrainApplication(string filename, byte[] terrainData, IClientAPI remoteClient) 1104 private void HandleTerrainApplication(string filename, byte[] terrainData, IClientAPI remoteClient)
823 { 1105 {
824 lock (TerrainUploader) 1106 lock (this)
825 { 1107 {
826 remoteClient.OnXferReceive -= TerrainUploader.XferReceive; 1108 remoteClient.OnXferReceive -= TerrainUploader.XferReceive;
827 remoteClient.OnAbortXfer -= AbortTerrainXferHandler; 1109 remoteClient.OnAbortXfer -= AbortTerrainXferHandler;
@@ -829,18 +1111,18 @@ namespace OpenSim.Region.CoreModules.World.Estate
829 1111
830 TerrainUploader = null; 1112 TerrainUploader = null;
831 } 1113 }
1114
1115 m_log.DebugFormat("[CLIENT]: Terrain upload from {0} to {1} complete.", remoteClient.Name, Scene.Name);
832 remoteClient.SendAlertMessage("Terrain Upload Complete. Loading...."); 1116 remoteClient.SendAlertMessage("Terrain Upload Complete. Loading....");
1117
833 ITerrainModule terr = Scene.RequestModuleInterface<ITerrainModule>(); 1118 ITerrainModule terr = Scene.RequestModuleInterface<ITerrainModule>();
834 1119
835 if (terr != null) 1120 if (terr != null)
836 { 1121 {
837 m_log.Warn("[CLIENT]: Got Request to Send Terrain in region " + Scene.RegionInfo.RegionName);
838
839 try 1122 try
840 { 1123 {
841 MemoryStream terrainStream = new MemoryStream(terrainData); 1124 using (MemoryStream terrainStream = new MemoryStream(terrainData))
842 terr.LoadFromStream(filename, terrainStream); 1125 terr.LoadFromStream(filename, terrainStream);
843 terrainStream.Close();
844 1126
845 FileInfo x = new FileInfo(filename); 1127 FileInfo x = new FileInfo(filename);
846 remoteClient.SendAlertMessage("Your terrain was loaded as a " + x.Extension + " file. It may take a few moments to appear."); 1128 remoteClient.SendAlertMessage("Your terrain was loaded as a " + x.Extension + " file. It may take a few moments to appear.");
@@ -880,25 +1162,27 @@ namespace OpenSim.Region.CoreModules.World.Estate
880 1162
881 private void handleUploadTerrain(IClientAPI remote_client, string clientFileName) 1163 private void handleUploadTerrain(IClientAPI remote_client, string clientFileName)
882 { 1164 {
883 if (TerrainUploader == null) 1165 lock (this)
884 { 1166 {
885 1167 if (TerrainUploader == null)
886 TerrainUploader = new EstateTerrainXferHandler(remote_client, clientFileName);
887 lock (TerrainUploader)
888 { 1168 {
1169 m_log.DebugFormat(
1170 "[TERRAIN]: Started receiving terrain upload for region {0} from {1}",
1171 Scene.Name, remote_client.Name);
1172
1173 TerrainUploader = new EstateTerrainXferHandler(remote_client, clientFileName);
889 remote_client.OnXferReceive += TerrainUploader.XferReceive; 1174 remote_client.OnXferReceive += TerrainUploader.XferReceive;
890 remote_client.OnAbortXfer += AbortTerrainXferHandler; 1175 remote_client.OnAbortXfer += AbortTerrainXferHandler;
891 TerrainUploader.TerrainUploadDone += HandleTerrainApplication; 1176 TerrainUploader.TerrainUploadDone += HandleTerrainApplication;
1177 TerrainUploader.RequestStartXfer(remote_client);
1178 }
1179 else
1180 {
1181 remote_client.SendAlertMessage("Another Terrain Upload is in progress. Please wait your turn!");
892 } 1182 }
893 TerrainUploader.RequestStartXfer(remote_client);
894
895 }
896 else
897 {
898 remote_client.SendAlertMessage("Another Terrain Upload is in progress. Please wait your turn!");
899 } 1183 }
900 } 1184 }
901 1185
902 private void handleTerrainRequest(IClientAPI remote_client, string clientFileName) 1186 private void handleTerrainRequest(IClientAPI remote_client, string clientFileName)
903 { 1187 {
904 // Save terrain here 1188 // Save terrain here
@@ -906,7 +1190,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
906 1190
907 if (terr != null) 1191 if (terr != null)
908 { 1192 {
909 m_log.Warn("[CLIENT]: Got Request to Send Terrain in region " + Scene.RegionInfo.RegionName); 1193// m_log.Warn("[CLIENT]: Got Request to Send Terrain in region " + Scene.RegionInfo.RegionName);
910 if (File.Exists(Util.dataDir() + "/terrain.raw")) 1194 if (File.Exists(Util.dataDir() + "/terrain.raw"))
911 { 1195 {
912 File.Delete(Util.dataDir() + "/terrain.raw"); 1196 File.Delete(Util.dataDir() + "/terrain.raw");
@@ -918,8 +1202,9 @@ namespace OpenSim.Region.CoreModules.World.Estate
918 input.Read(bdata, 0, (int)input.Length); 1202 input.Read(bdata, 0, (int)input.Length);
919 remote_client.SendAlertMessage("Terrain file written, starting download..."); 1203 remote_client.SendAlertMessage("Terrain file written, starting download...");
920 Scene.XferManager.AddNewFile("terrain.raw", bdata); 1204 Scene.XferManager.AddNewFile("terrain.raw", bdata);
921 // Tell client about it 1205
922 m_log.Warn("[CLIENT]: Sending Terrain to " + remote_client.Name); 1206 m_log.DebugFormat("[CLIENT]: Sending terrain for region {0} to {1}", Scene.Name, remote_client.Name);
1207
923 remote_client.SendInitiateDownload("terrain.raw", clientFileName); 1208 remote_client.SendInitiateDownload("terrain.raw", clientFileName);
924 } 1209 }
925 } 1210 }
@@ -1080,11 +1365,6 @@ namespace OpenSim.Region.CoreModules.World.Estate
1080 remoteClient.SendRegionHandshake(Scene.RegionInfo,args); 1365 remoteClient.SendRegionHandshake(Scene.RegionInfo,args);
1081 } 1366 }
1082 1367
1083 public void sendRegionHandshakeToAll()
1084 {
1085 Scene.ForEachClient(sendRegionHandshake);
1086 }
1087
1088 public void handleEstateChangeInfo(IClientAPI remoteClient, UUID invoice, UUID senderID, UInt32 parms1, UInt32 parms2) 1368 public void handleEstateChangeInfo(IClientAPI remoteClient, UUID invoice, UUID senderID, UInt32 parms1, UInt32 parms2)
1089 { 1369 {
1090 if (parms2 == 0) 1370 if (parms2 == 0)
@@ -1096,6 +1376,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
1096 { 1376 {
1097 Scene.RegionInfo.EstateSettings.UseGlobalTime = false; 1377 Scene.RegionInfo.EstateSettings.UseGlobalTime = false;
1098 Scene.RegionInfo.EstateSettings.SunPosition = (parms2 - 0x1800)/1024.0; 1378 Scene.RegionInfo.EstateSettings.SunPosition = (parms2 - 0x1800)/1024.0;
1379 // Warning: FixedSun should be set to True, otherwise this sun position won't be used.
1099 } 1380 }
1100 1381
1101 if ((parms1 & 0x00000010) != 0) 1382 if ((parms1 & 0x00000010) != 0)
@@ -1138,7 +1419,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
1138 else 1419 else
1139 Scene.RegionInfo.EstateSettings.DenyMinors = false; 1420 Scene.RegionInfo.EstateSettings.DenyMinors = false;
1140 1421
1141 Scene.RegionInfo.EstateSettings.Save(); 1422 Scene.EstateDataService.StoreEstateSettings(Scene.RegionInfo.EstateSettings);
1142 TriggerEstateInfoChange(); 1423 TriggerEstateInfoChange();
1143 1424
1144 Scene.TriggerEstateSunUpdate(); 1425 Scene.TriggerEstateSunUpdate();
@@ -1165,11 +1446,12 @@ namespace OpenSim.Region.CoreModules.World.Estate
1165 sendRegionInfoPacketToAll(); 1446 sendRegionInfoPacketToAll();
1166 } 1447 }
1167 1448
1168 #endregion 1449
1450 #endregion
1169 1451
1170 private void EventManager_OnNewClient(IClientAPI client) 1452 private void EventManager_OnNewClient(IClientAPI client)
1171 { 1453 {
1172 client.OnDetailedEstateDataRequest += sendDetailedEstateData; 1454 client.OnDetailedEstateDataRequest += clientSendDetailedEstateData;
1173 client.OnSetEstateFlagsRequest += estateSetRegionInfoHandler; 1455 client.OnSetEstateFlagsRequest += estateSetRegionInfoHandler;
1174// client.OnSetEstateTerrainBaseTexture += setEstateTerrainBaseTexture; 1456// client.OnSetEstateTerrainBaseTexture += setEstateTerrainBaseTexture;
1175 client.OnSetEstateTerrainDetailTexture += setEstateTerrainBaseTexture; 1457 client.OnSetEstateTerrainDetailTexture += setEstateTerrainBaseTexture;
@@ -1179,7 +1461,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
1179 client.OnEstateRestartSimRequest += handleEstateRestartSimRequest; 1461 client.OnEstateRestartSimRequest += handleEstateRestartSimRequest;
1180 client.OnEstateChangeCovenantRequest += handleChangeEstateCovenantRequest; 1462 client.OnEstateChangeCovenantRequest += handleChangeEstateCovenantRequest;
1181 client.OnEstateChangeInfo += handleEstateChangeInfo; 1463 client.OnEstateChangeInfo += handleEstateChangeInfo;
1182 client.OnEstateManageTelehub += handleOnEstateManageTelehub; 1464 client.OnEstateManageTelehub += HandleOnEstateManageTelehub;
1183 client.OnUpdateEstateAccessDeltaRequest += handleEstateAccessDeltaRequest; 1465 client.OnUpdateEstateAccessDeltaRequest += handleEstateAccessDeltaRequest;
1184 client.OnSimulatorBlueBoxMessageRequest += SendSimulatorBlueBoxMessage; 1466 client.OnSimulatorBlueBoxMessageRequest += SendSimulatorBlueBoxMessage;
1185 client.OnEstateBlueBoxMessageRequest += SendEstateBlueBoxMessage; 1467 client.OnEstateBlueBoxMessageRequest += SendEstateBlueBoxMessage;
@@ -1195,56 +1477,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
1195 sendRegionHandshake(client); 1477 sendRegionHandshake(client);
1196 } 1478 }
1197 1479
1198 public uint GetRegionFlags() 1480 private uint GetEstateFlags()
1199 {
1200 RegionFlags flags = RegionFlags.None;
1201
1202 // Fully implemented
1203 //
1204 if (Scene.RegionInfo.RegionSettings.AllowDamage)
1205 flags |= RegionFlags.AllowDamage;
1206 if (Scene.RegionInfo.RegionSettings.BlockTerraform)
1207 flags |= RegionFlags.BlockTerraform;
1208 if (!Scene.RegionInfo.RegionSettings.AllowLandResell)
1209 flags |= RegionFlags.BlockLandResell;
1210 if (Scene.RegionInfo.RegionSettings.DisableCollisions)
1211 flags |= RegionFlags.SkipCollisions;
1212 if (Scene.RegionInfo.RegionSettings.DisableScripts)
1213 flags |= RegionFlags.SkipScripts;
1214 if (Scene.RegionInfo.RegionSettings.DisablePhysics)
1215 flags |= RegionFlags.SkipPhysics;
1216 if (Scene.RegionInfo.RegionSettings.BlockFly)
1217 flags |= RegionFlags.NoFly;
1218 if (Scene.RegionInfo.RegionSettings.RestrictPushing)
1219 flags |= RegionFlags.RestrictPushObject;
1220 if (Scene.RegionInfo.RegionSettings.AllowLandJoinDivide)
1221 flags |= RegionFlags.AllowParcelChanges;
1222 if (Scene.RegionInfo.RegionSettings.BlockShowInSearch)
1223 flags |= RegionFlags.BlockParcelSearch;
1224
1225 if (Scene.RegionInfo.RegionSettings.FixedSun)
1226 flags |= RegionFlags.SunFixed;
1227 if (Scene.RegionInfo.RegionSettings.Sandbox)
1228 flags |= RegionFlags.Sandbox;
1229 if (Scene.RegionInfo.EstateSettings.AllowVoice)
1230 flags |= RegionFlags.AllowVoice;
1231
1232 // Fudge these to always on, so the menu options activate
1233 //
1234 flags |= RegionFlags.AllowLandmark;
1235 flags |= RegionFlags.AllowSetHome;
1236
1237 // TODO: SkipUpdateInterestList
1238
1239 // Omitted
1240 //
1241 // Omitted: NullLayer (what is that?)
1242 // Omitted: SkipAgentAction (what does it do?)
1243
1244 return (uint)flags;
1245 }
1246
1247 public uint GetEstateFlags()
1248 { 1481 {
1249 RegionFlags flags = RegionFlags.None; 1482 RegionFlags flags = RegionFlags.None;
1250 1483
@@ -1273,40 +1506,18 @@ namespace OpenSim.Region.CoreModules.World.Estate
1273 flags |= RegionFlags.ResetHomeOnTeleport; 1506 flags |= RegionFlags.ResetHomeOnTeleport;
1274 if (Scene.RegionInfo.EstateSettings.TaxFree) 1507 if (Scene.RegionInfo.EstateSettings.TaxFree)
1275 flags |= RegionFlags.TaxFree; 1508 flags |= RegionFlags.TaxFree;
1509 if (Scene.RegionInfo.EstateSettings.AllowLandmark)
1510 flags |= RegionFlags.AllowLandmark;
1511 if (Scene.RegionInfo.EstateSettings.AllowParcelChanges)
1512 flags |= RegionFlags.AllowParcelChanges;
1513 if (Scene.RegionInfo.EstateSettings.AllowSetHome)
1514 flags |= RegionFlags.AllowSetHome;
1276 if (Scene.RegionInfo.EstateSettings.DenyMinors) 1515 if (Scene.RegionInfo.EstateSettings.DenyMinors)
1277 flags |= (RegionFlags)(1 << 30); 1516 flags |= (RegionFlags)(1 << 30);
1278 1517
1279 return (uint)flags; 1518 return (uint)flags;
1280 } 1519 }
1281 1520
1282 public bool IsManager(UUID avatarID)
1283 {
1284 if (avatarID == Scene.RegionInfo.EstateSettings.EstateOwner)
1285 return true;
1286
1287 List<UUID> ems = new List<UUID>(Scene.RegionInfo.EstateSettings.EstateManagers);
1288 if (ems.Contains(avatarID))
1289 return true;
1290
1291 return false;
1292 }
1293
1294 public void TriggerRegionInfoChange()
1295 {
1296 ChangeDelegate change = OnRegionInfoChange;
1297
1298 if (change != null)
1299 change(Scene.RegionInfo.RegionID);
1300 }
1301
1302 public void TriggerEstateInfoChange()
1303 {
1304 ChangeDelegate change = OnEstateInfoChange;
1305
1306 if (change != null)
1307 change(Scene.RegionInfo.RegionID);
1308 }
1309
1310 public void TriggerEstateMessage(UUID fromID, string fromName, string message) 1521 public void TriggerEstateMessage(UUID fromID, string fromName, string message)
1311 { 1522 {
1312 MessageDelegate onmessage = OnEstateMessage; 1523 MessageDelegate onmessage = OnEstateMessage;
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateTerrainXferHandler.cs b/OpenSim/Region/CoreModules/World/Estate/EstateTerrainXferHandler.cs
index b8d8b10..2d74eaf 100644
--- a/OpenSim/Region/CoreModules/World/Estate/EstateTerrainXferHandler.cs
+++ b/OpenSim/Region/CoreModules/World/Estate/EstateTerrainXferHandler.cs
@@ -78,7 +78,10 @@ namespace OpenSim.Region.CoreModules.World.Estate
78 /// <param name="data"></param> 78 /// <param name="data"></param>
79 public void XferReceive(IClientAPI remoteClient, ulong xferID, uint packetID, byte[] data) 79 public void XferReceive(IClientAPI remoteClient, ulong xferID, uint packetID, byte[] data)
80 { 80 {
81 if (mXferID == xferID) 81 if (mXferID != xferID)
82 return;
83
84 lock (this)
82 { 85 {
83 if (m_asset.Data.Length > 1) 86 if (m_asset.Data.Length > 1)
84 { 87 {
@@ -99,7 +102,6 @@ namespace OpenSim.Region.CoreModules.World.Estate
99 if ((packetID & 0x80000000) != 0) 102 if ((packetID & 0x80000000) != 0)
100 { 103 {
101 SendCompleteMessage(remoteClient); 104 SendCompleteMessage(remoteClient);
102
103 } 105 }
104 } 106 }
105 } 107 }
diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs
new file mode 100644
index 0000000..73e706c
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs
@@ -0,0 +1,218 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31
32using OpenSim.Services.Interfaces;
33using GridRegion = OpenSim.Services.Interfaces.GridRegion;
34using OpenSim.Server.Base;
35using OpenSim.Framework.Servers.HttpServer;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Scenes;
38
39using OpenMetaverse;
40using log4net;
41
42namespace OpenSim.Region.CoreModules.World.Estate
43{
44 public class EstateConnector
45 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 protected XEstateModule m_EstateModule;
49
50 public EstateConnector(XEstateModule module)
51 {
52 m_EstateModule = module;
53 }
54
55 public void SendTeleportHomeOneUser(uint EstateID, UUID PreyID)
56 {
57 Dictionary<string, object> sendData = new Dictionary<string, object>();
58 sendData["METHOD"] = "teleport_home_one_user";
59
60 sendData["EstateID"] = EstateID.ToString();
61 sendData["PreyID"] = PreyID.ToString();
62
63 SendToEstate(EstateID, sendData);
64 }
65
66 public void SendTeleportHomeAllUsers(uint EstateID)
67 {
68 Dictionary<string, object> sendData = new Dictionary<string, object>();
69 sendData["METHOD"] = "teleport_home_all_users";
70
71 sendData["EstateID"] = EstateID.ToString();
72
73 SendToEstate(EstateID, sendData);
74 }
75
76 public bool SendUpdateCovenant(uint EstateID, UUID CovenantID)
77 {
78 Dictionary<string, object> sendData = new Dictionary<string, object>();
79 sendData["METHOD"] = "update_covenant";
80
81 sendData["CovenantID"] = CovenantID.ToString();
82 sendData["EstateID"] = EstateID.ToString();
83
84 // Handle local regions locally
85 //
86 foreach (Scene s in m_EstateModule.Scenes)
87 {
88 if (s.RegionInfo.EstateSettings.EstateID == EstateID)
89 s.RegionInfo.RegionSettings.Covenant = CovenantID;
90// s.ReloadEstateData();
91 }
92
93 SendToEstate(EstateID, sendData);
94
95 return true;
96 }
97
98 public bool SendUpdateEstate(uint EstateID)
99 {
100 Dictionary<string, object> sendData = new Dictionary<string, object>();
101 sendData["METHOD"] = "update_estate";
102
103 sendData["EstateID"] = EstateID.ToString();
104
105 // Handle local regions locally
106 //
107 foreach (Scene s in m_EstateModule.Scenes)
108 {
109 if (s.RegionInfo.EstateSettings.EstateID == EstateID)
110 s.ReloadEstateData();
111 }
112
113 SendToEstate(EstateID, sendData);
114
115 return true;
116 }
117
118 public void SendEstateMessage(uint EstateID, UUID FromID, string FromName, string Message)
119 {
120 Dictionary<string, object> sendData = new Dictionary<string, object>();
121 sendData["METHOD"] = "estate_message";
122
123 sendData["EstateID"] = EstateID.ToString();
124 sendData["FromID"] = FromID.ToString();
125 sendData["FromName"] = FromName;
126 sendData["Message"] = Message;
127
128 SendToEstate(EstateID, sendData);
129 }
130
131 private void SendToEstate(uint EstateID, Dictionary<string, object> sendData)
132 {
133 List<UUID> regions = m_EstateModule.Scenes[0].GetEstateRegions((int)EstateID);
134
135 UUID ScopeID = UUID.Zero;
136
137 // Handle local regions locally
138 //
139 lock (m_EstateModule.Scenes)
140 {
141 foreach (Scene s in m_EstateModule.Scenes)
142 {
143 if (regions.Contains(s.RegionInfo.RegionID))
144 {
145 // All regions in one estate are in the same scope.
146 // Use that scope.
147 //
148 ScopeID = s.RegionInfo.ScopeID;
149 regions.Remove(s.RegionInfo.RegionID);
150 }
151 }
152 }
153
154 // Our own region should always be in the above list.
155 // In a standalone this would not be true. But then,
156 // Scope ID is not relevat there. Use first scope.
157 //
158 if (ScopeID == UUID.Zero)
159 ScopeID = m_EstateModule.Scenes[0].RegionInfo.ScopeID;
160
161 // Don't send to the same instance twice
162 //
163 List<string> done = new List<string>();
164
165 // Send to remote regions
166 //
167 foreach (UUID regionID in regions)
168 {
169 GridRegion region = m_EstateModule.Scenes[0].GridService.GetRegionByUUID(ScopeID, regionID);
170 if (region != null)
171 {
172 string url = "http://" + region.ExternalHostName + ":" + region.HttpPort;
173 if (done.Contains(url))
174 continue;
175
176 Call(region, sendData);
177 done.Add(url);
178 }
179 }
180 }
181
182 private bool Call(GridRegion region, Dictionary<string, object> sendData)
183 {
184 string reqString = ServerUtils.BuildQueryString(sendData);
185 // m_log.DebugFormat("[XESTATE CONNECTOR]: queryString = {0}", reqString);
186 try
187 {
188 string url = "http://" + region.ExternalHostName + ":" + region.HttpPort;
189 string reply = SynchronousRestFormsRequester.MakeRequest("POST",
190 url + "/estate",
191 reqString);
192 if (reply != string.Empty)
193 {
194 Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
195
196 if (replyData.ContainsKey("RESULT"))
197 {
198 if (replyData["RESULT"].ToString().ToLower() == "true")
199 return true;
200 else
201 return false;
202 }
203 else
204 m_log.DebugFormat("[XESTATE CONNECTOR]: reply data does not contain result field");
205
206 }
207 else
208 m_log.DebugFormat("[XESTATE CONNECTOR]: received empty reply");
209 }
210 catch (Exception e)
211 {
212 m_log.DebugFormat("[XESTATE CONNECTOR]: Exception when contacting remote sim: {0}", e.Message);
213 }
214
215 return false;
216 }
217 }
218}
diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs
new file mode 100644
index 0000000..4bb3799
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs
@@ -0,0 +1,255 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using log4net;
33using Nini.Config;
34using Nwc.XmlRpc;
35using OpenMetaverse;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Services.Interfaces;
40using OpenSim.Server.Base;
41using OpenSim.Framework.Servers;
42using OpenSim.Framework.Servers.HttpServer;
43using Mono.Addins;
44
45namespace OpenSim.Region.CoreModules.World.Estate
46{
47 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XEstate")]
48 public class XEstateModule : ISharedRegionModule
49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
52 protected List<Scene> m_Scenes = new List<Scene>();
53 protected bool m_InInfoUpdate = false;
54
55 public bool InInfoUpdate
56 {
57 get { return m_InInfoUpdate; }
58 set { m_InInfoUpdate = value; }
59 }
60
61 public List<Scene> Scenes
62 {
63 get { return m_Scenes; }
64 }
65
66 protected EstateConnector m_EstateConnector;
67
68 public void Initialise(IConfigSource config)
69 {
70 int port = 0;
71
72 IConfig estateConfig = config.Configs["Estate"];
73 if (estateConfig != null)
74 {
75 port = estateConfig.GetInt("Port", 0);
76 }
77
78 m_EstateConnector = new EstateConnector(this);
79
80 // Instantiate the request handler
81 IHttpServer server = MainServer.GetHttpServer((uint)port);
82 server.AddStreamHandler(new EstateRequestHandler(this));
83 }
84
85 public void PostInitialise()
86 {
87 }
88
89 public void Close()
90 {
91 }
92
93 public void AddRegion(Scene scene)
94 {
95 lock (m_Scenes)
96 m_Scenes.Add(scene);
97
98 scene.EventManager.OnNewClient += OnNewClient;
99 }
100
101 public void RegionLoaded(Scene scene)
102 {
103 IEstateModule em = scene.RequestModuleInterface<IEstateModule>();
104
105 em.OnRegionInfoChange += OnRegionInfoChange;
106 em.OnEstateInfoChange += OnEstateInfoChange;
107 em.OnEstateMessage += OnEstateMessage;
108 }
109
110 public void RemoveRegion(Scene scene)
111 {
112 scene.EventManager.OnNewClient -= OnNewClient;
113
114 lock (m_Scenes)
115 m_Scenes.Remove(scene);
116 }
117
118 public string Name
119 {
120 get { return "EstateModule"; }
121 }
122
123 public Type ReplaceableInterface
124 {
125 get { return null; }
126 }
127
128 private Scene FindScene(UUID RegionID)
129 {
130 foreach (Scene s in Scenes)
131 {
132 if (s.RegionInfo.RegionID == RegionID)
133 return s;
134 }
135
136 return null;
137 }
138
139 private void OnRegionInfoChange(UUID RegionID)
140 {
141 Scene s = FindScene(RegionID);
142 if (s == null)
143 return;
144
145 if (!m_InInfoUpdate)
146 m_EstateConnector.SendUpdateCovenant(s.RegionInfo.EstateSettings.EstateID, s.RegionInfo.RegionSettings.Covenant);
147 }
148
149 private void OnEstateInfoChange(UUID RegionID)
150 {
151 Scene s = FindScene(RegionID);
152 if (s == null)
153 return;
154
155 if (!m_InInfoUpdate)
156 m_EstateConnector.SendUpdateEstate(s.RegionInfo.EstateSettings.EstateID);
157 }
158
159 private void OnEstateMessage(UUID RegionID, UUID FromID, string FromName, string Message)
160 {
161 Scene senderScenes = FindScene(RegionID);
162 if (senderScenes == null)
163 return;
164
165 uint estateID = senderScenes.RegionInfo.EstateSettings.EstateID;
166
167 foreach (Scene s in Scenes)
168 {
169 if (s.RegionInfo.EstateSettings.EstateID == estateID)
170 {
171 IDialogModule dm = s.RequestModuleInterface<IDialogModule>();
172
173 if (dm != null)
174 {
175 dm.SendNotificationToUsersInRegion(FromID, FromName,
176 Message);
177 }
178 }
179 }
180 if (!m_InInfoUpdate)
181 m_EstateConnector.SendEstateMessage(estateID, FromID, FromName, Message);
182 }
183
184 private void OnNewClient(IClientAPI client)
185 {
186 client.OnEstateTeleportOneUserHomeRequest += OnEstateTeleportOneUserHomeRequest;
187 client.OnEstateTeleportAllUsersHomeRequest += OnEstateTeleportAllUsersHomeRequest;
188
189 }
190
191 private void OnEstateTeleportOneUserHomeRequest(IClientAPI client, UUID invoice, UUID senderID, UUID prey)
192 {
193 if (prey == UUID.Zero)
194 return;
195
196 if (!(client.Scene is Scene))
197 return;
198
199 Scene scene = (Scene)client.Scene;
200
201 uint estateID = scene.RegionInfo.EstateSettings.EstateID;
202
203 if (!scene.Permissions.CanIssueEstateCommand(client.AgentId, false))
204 return;
205
206 foreach (Scene s in Scenes)
207 {
208 if (s == scene)
209 continue; // Already handles by estate module
210 if (s.RegionInfo.EstateSettings.EstateID != estateID)
211 continue;
212
213 ScenePresence p = scene.GetScenePresence(prey);
214 if (p != null && !p.IsChildAgent)
215 {
216 p.ControllingClient.SendTeleportStart(16);
217 scene.TeleportClientHome(prey, p.ControllingClient);
218 }
219 }
220
221 m_EstateConnector.SendTeleportHomeOneUser(estateID, prey);
222 }
223
224 private void OnEstateTeleportAllUsersHomeRequest(IClientAPI client, UUID invoice, UUID senderID)
225 {
226 if (!(client.Scene is Scene))
227 return;
228
229 Scene scene = (Scene)client.Scene;
230
231 uint estateID = scene.RegionInfo.EstateSettings.EstateID;
232
233 if (!scene.Permissions.CanIssueEstateCommand(client.AgentId, false))
234 return;
235
236 foreach (Scene s in Scenes)
237 {
238 if (s == scene)
239 continue; // Already handles by estate module
240 if (s.RegionInfo.EstateSettings.EstateID != estateID)
241 continue;
242
243 scene.ForEachScenePresence(delegate(ScenePresence p) {
244 if (p != null && !p.IsChildAgent)
245 {
246 p.ControllingClient.SendTeleportStart(16);
247 scene.TeleportClientHome(p.ControllingClient.AgentId, p.ControllingClient);
248 }
249 });
250 }
251
252 m_EstateConnector.SendTeleportHomeAllUsers(estateID);
253 }
254 }
255}
diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs
new file mode 100644
index 0000000..ec5af2b
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs
@@ -0,0 +1,288 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Xml;
33
34using OpenSim.Framework;
35using OpenSim.Server.Base;
36using OpenSim.Framework.Servers.HttpServer;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Region.Framework.Interfaces;
39
40using OpenMetaverse;
41using log4net;
42
43namespace OpenSim.Region.CoreModules.World.Estate
44{
45 public class EstateRequestHandler : BaseStreamHandler
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 protected XEstateModule m_EstateModule;
50 protected Object m_RequestLock = new Object();
51
52 public EstateRequestHandler(XEstateModule fmodule)
53 : base("POST", "/estate")
54 {
55 m_EstateModule = fmodule;
56 }
57
58 protected override byte[] ProcessRequest(string path, Stream requestData,
59 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
60 {
61 StreamReader sr = new StreamReader(requestData);
62 string body = sr.ReadToEnd();
63 sr.Close();
64 body = body.Trim();
65
66 m_log.DebugFormat("[XESTATE HANDLER]: query String: {0}", body);
67
68 try
69 {
70 lock (m_RequestLock)
71 {
72 Dictionary<string, object> request =
73 ServerUtils.ParseQueryString(body);
74
75 if (!request.ContainsKey("METHOD"))
76 return FailureResult();
77
78 string method = request["METHOD"].ToString();
79 request.Remove("METHOD");
80
81 try
82 {
83 m_EstateModule.InInfoUpdate = false;
84
85 switch (method)
86 {
87 case "update_covenant":
88 return UpdateCovenant(request);
89 case "update_estate":
90 return UpdateEstate(request);
91 case "estate_message":
92 return EstateMessage(request);
93 case "teleport_home_one_user":
94 return TeleportHomeOneUser(request);
95 case "teleport_home_all_users":
96 return TeleportHomeAllUsers(request);
97 }
98 }
99 finally
100 {
101 m_EstateModule.InInfoUpdate = false;
102 }
103 }
104 }
105 catch (Exception e)
106 {
107 m_log.Debug("[XESTATE]: Exception {0}" + e.ToString());
108 }
109
110 return FailureResult();
111 }
112
113 byte[] TeleportHomeAllUsers(Dictionary<string, object> request)
114 {
115 UUID PreyID = UUID.Zero;
116 int EstateID = 0;
117
118 if (!request.ContainsKey("EstateID"))
119 return FailureResult();
120
121 if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID))
122 return FailureResult();
123
124 foreach (Scene s in m_EstateModule.Scenes)
125 {
126 if (s.RegionInfo.EstateSettings.EstateID == EstateID)
127 {
128 s.ForEachScenePresence(delegate(ScenePresence p) {
129 if (p != null && !p.IsChildAgent)
130 {
131 p.ControllingClient.SendTeleportStart(16);
132 s.TeleportClientHome(p.ControllingClient.AgentId, p.ControllingClient);
133 }
134 });
135 }
136 }
137
138 return SuccessResult();
139 }
140
141 byte[] TeleportHomeOneUser(Dictionary<string, object> request)
142 {
143 UUID PreyID = UUID.Zero;
144 int EstateID = 0;
145
146 if (!request.ContainsKey("PreyID") ||
147 !request.ContainsKey("EstateID"))
148 {
149 return FailureResult();
150 }
151
152 if (!UUID.TryParse(request["PreyID"].ToString(), out PreyID))
153 return FailureResult();
154
155 if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID))
156 return FailureResult();
157
158 foreach (Scene s in m_EstateModule.Scenes)
159 {
160 if (s.RegionInfo.EstateSettings.EstateID == EstateID)
161 {
162 ScenePresence p = s.GetScenePresence(PreyID);
163 if (p != null && !p.IsChildAgent)
164 {
165 p.ControllingClient.SendTeleportStart(16);
166 s.TeleportClientHome(PreyID, p.ControllingClient);
167 }
168 }
169 }
170
171 return SuccessResult();
172 }
173
174 byte[] EstateMessage(Dictionary<string, object> request)
175 {
176 UUID FromID = UUID.Zero;
177 string FromName = String.Empty;
178 string Message = String.Empty;
179 int EstateID = 0;
180
181 if (!request.ContainsKey("FromID") ||
182 !request.ContainsKey("FromName") ||
183 !request.ContainsKey("Message") ||
184 !request.ContainsKey("EstateID"))
185 {
186 return FailureResult();
187 }
188
189 if (!UUID.TryParse(request["FromID"].ToString(), out FromID))
190 return FailureResult();
191
192 if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID))
193 return FailureResult();
194
195 FromName = request["FromName"].ToString();
196 Message = request["Message"].ToString();
197
198 foreach (Scene s in m_EstateModule.Scenes)
199 {
200 if (s.RegionInfo.EstateSettings.EstateID == EstateID)
201 {
202 IDialogModule dm = s.RequestModuleInterface<IDialogModule>();
203
204 if (dm != null)
205 {
206 dm.SendNotificationToUsersInRegion(FromID, FromName,
207 Message);
208 }
209 }
210 }
211
212 return SuccessResult();
213 }
214
215 byte[] UpdateCovenant(Dictionary<string, object> request)
216 {
217 UUID CovenantID = UUID.Zero;
218 int EstateID = 0;
219
220 if (!request.ContainsKey("CovenantID") || !request.ContainsKey("EstateID"))
221 return FailureResult();
222
223 if (!UUID.TryParse(request["CovenantID"].ToString(), out CovenantID))
224 return FailureResult();
225
226 if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID))
227 return FailureResult();
228
229 foreach (Scene s in m_EstateModule.Scenes)
230 {
231 if (s.RegionInfo.EstateSettings.EstateID == (uint)EstateID)
232 s.RegionInfo.RegionSettings.Covenant = CovenantID;
233 }
234
235 return SuccessResult();
236 }
237
238 byte[] UpdateEstate(Dictionary<string, object> request)
239 {
240 int EstateID = 0;
241
242 if (!request.ContainsKey("EstateID"))
243 return FailureResult();
244 if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID))
245 return FailureResult();
246
247 foreach (Scene s in m_EstateModule.Scenes)
248 {
249 if (s.RegionInfo.EstateSettings.EstateID == (uint)EstateID)
250 s.ReloadEstateData();
251 }
252 return SuccessResult();
253 }
254
255 private byte[] FailureResult()
256 {
257 return BoolResult(false);
258 }
259
260 private byte[] SuccessResult()
261 {
262 return BoolResult(true);
263 }
264
265 private byte[] BoolResult(bool value)
266 {
267 XmlDocument doc = new XmlDocument();
268
269 XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration,
270 "", "");
271
272 doc.AppendChild(xmlnode);
273
274 XmlElement rootElement = doc.CreateElement("", "ServerResponse",
275 "");
276
277 doc.AppendChild(rootElement);
278
279 XmlElement result = doc.CreateElement("", "RESULT", "");
280 result.AppendChild(doc.CreateTextNode(value.ToString()));
281
282 rootElement.AppendChild(result);
283
284 return Util.DocToBytes(doc);
285 }
286
287 }
288}
diff --git a/OpenSim/Region/CoreModules/World/Land/DwellModule.cs b/OpenSim/Region/CoreModules/World/Land/DwellModule.cs
index bd22155..70c6028 100644
--- a/OpenSim/Region/CoreModules/World/Land/DwellModule.cs
+++ b/OpenSim/Region/CoreModules/World/Land/DwellModule.cs
@@ -45,17 +45,19 @@ using OpenSim.Framework.Servers.HttpServer;
45using OpenSim.Region.CoreModules.Framework.InterfaceCommander; 45using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
46using OpenSim.Region.Framework.Interfaces; 46using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Region.Framework.Scenes; 47using OpenSim.Region.Framework.Scenes;
48using OpenSim.Region.Physics.Manager; 48using OpenSim.Region.PhysicsModules.SharedBase;
49using OpenSim.Services.Interfaces; 49using OpenSim.Services.Interfaces;
50using Caps = OpenSim.Framework.Capabilities.Caps; 50using Caps = OpenSim.Framework.Capabilities.Caps;
51using GridRegion = OpenSim.Services.Interfaces.GridRegion; 51using GridRegion = OpenSim.Services.Interfaces.GridRegion;
52 52
53namespace OpenSim.Region.CoreModules.World.Land 53namespace OpenSim.Region.CoreModules.World.Land
54{ 54{
55 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DwellModule")] 55 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DefaultDwellModule")]
56 public class DwellModule : IDwellModule, INonSharedRegionModule 56 public class DefaultDwellModule : IDwellModule, INonSharedRegionModule
57 { 57 {
58 private Scene m_scene; 58 private Scene m_scene;
59 private IConfigSource m_Config;
60 private bool m_Enabled = false;
59 61
60 public Type ReplaceableInterface 62 public Type ReplaceableInterface
61 { 63 {
@@ -64,15 +66,27 @@ namespace OpenSim.Region.CoreModules.World.Land
64 66
65 public string Name 67 public string Name
66 { 68 {
67 get { return "DwellModule"; } 69 get { return "DefaultDwellModule"; }
68 } 70 }
69 71
70 public void Initialise(IConfigSource source) 72 public void Initialise(IConfigSource source)
71 { 73 {
74 m_Config = source;
75
76 IConfig DwellConfig = m_Config.Configs ["Dwell"];
77
78 if (DwellConfig == null) {
79 m_Enabled = false;
80 return;
81 }
82 m_Enabled = (DwellConfig.GetString ("DwellModule", "DefaultDwellModule") == "DefaultDwellModule");
72 } 83 }
73 84
74 public void AddRegion(Scene scene) 85 public void AddRegion(Scene scene)
75 { 86 {
87 if (!m_Enabled)
88 return;
89
76 m_scene = scene; 90 m_scene = scene;
77 91
78 m_scene.EventManager.OnNewClient += OnNewClient; 92 m_scene.EventManager.OnNewClient += OnNewClient;
diff --git a/OpenSim/Region/CoreModules/World/Land/LandChannel.cs b/OpenSim/Region/CoreModules/World/Land/LandChannel.cs
index 7fc358d..73c592d 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandChannel.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandChannel.cs
@@ -95,6 +95,11 @@ namespace OpenSim.Region.CoreModules.World.Land
95 return null; 95 return null;
96 } 96 }
97 97
98 public ILandObject GetLandObject(Vector3 position)
99 {
100 return GetLandObject(position.X, position.Y);
101 }
102
98 public ILandObject GetLandObject(int x, int y) 103 public ILandObject GetLandObject(int x, int y)
99 { 104 {
100 if (m_landManagementModule != null) 105 if (m_landManagementModule != null)
diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
index bad7205..92f6c1b 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
@@ -42,10 +42,9 @@ using OpenSim.Framework.Capabilities;
42using OpenSim.Framework.Console; 42using OpenSim.Framework.Console;
43using OpenSim.Framework.Servers; 43using OpenSim.Framework.Servers;
44using OpenSim.Framework.Servers.HttpServer; 44using OpenSim.Framework.Servers.HttpServer;
45using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
46using OpenSim.Region.Framework.Interfaces; 45using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Region.Framework.Scenes; 46using OpenSim.Region.Framework.Scenes;
48using OpenSim.Region.Physics.Manager; 47using OpenSim.Region.PhysicsModules.SharedBase;
49using OpenSim.Services.Interfaces; 48using OpenSim.Services.Interfaces;
50using Caps = OpenSim.Framework.Capabilities.Caps; 49using Caps = OpenSim.Framework.Capabilities.Caps;
51using GridRegion = OpenSim.Services.Interfaces.GridRegion; 50using GridRegion = OpenSim.Services.Interfaces.GridRegion;
@@ -65,25 +64,27 @@ namespace OpenSim.Region.CoreModules.World.Land
65 public class LandManagementModule : INonSharedRegionModule 64 public class LandManagementModule : INonSharedRegionModule
66 { 65 {
67 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 66 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
67 private static readonly string LogHeader = "[LAND MANAGEMENT MODULE]";
68
69 /// <summary>
70 /// Minimum land unit size in region co-ordinates.
71 /// </summary>
72 public const int LandUnit = 4;
68 73
69 private static readonly string remoteParcelRequestPath = "0009/"; 74 private static readonly string remoteParcelRequestPath = "0009/";
70 75
71 private LandChannel landChannel; 76 private LandChannel landChannel;
72 private Scene m_scene; 77 private Scene m_scene;
73 protected Commander m_commander = new Commander("land"); 78
74 79 protected IGroupsModule m_groupManager;
75 protected IUserManagement m_userManager; 80 protected IUserManagement m_userManager;
76 protected IPrimCountModule m_primCountModule; 81 protected IPrimCountModule m_primCountModule;
77 82 protected IDialogModule m_Dialog;
78 // Minimum for parcels to work is 64m even if we don't actually use them.
79 #pragma warning disable 0429
80 private const int landArrayMax = ((int)((int)Constants.RegionSize / 4) >= 64) ? (int)((int)Constants.RegionSize / 4) : 64;
81 #pragma warning restore 0429
82 83
83 /// <value> 84 /// <value>
84 /// Local land ids at specified region co-ordinates (region size / 4) 85 /// Local land ids at specified region co-ordinates (region size / 4)
85 /// </value> 86 /// </value>
86 private readonly int[,] m_landIDList = new int[landArrayMax, landArrayMax]; 87 private int[,] m_landIDList;
87 88
88 /// <value> 89 /// <value>
89 /// Land objects keyed by local id 90 /// Land objects keyed by local id
@@ -97,11 +98,17 @@ namespace OpenSim.Region.CoreModules.World.Land
97 // caches ExtendedLandData 98 // caches ExtendedLandData
98 private Cache parcelInfoCache; 99 private Cache parcelInfoCache;
99 100
101
100 /// <summary> 102 /// <summary>
101 /// Record positions that avatar's are currently being forced to move to due to parcel entry restrictions. 103 /// Record positions that avatar's are currently being forced to move to due to parcel entry restrictions.
102 /// </summary> 104 /// </summary>
103 private Dictionary<UUID, Vector3> forcedPosition = new Dictionary<UUID, Vector3>(); 105 private Dictionary<UUID, Vector3> forcedPosition = new Dictionary<UUID, Vector3>();
104 106
107 // Enables limiting parcel layer info transmission when doing simple updates
108 private bool shouldLimitParcelLayerInfoToViewDistance { get; set; }
109 // "View distance" for sending parcel layer info if asked for from a view point in the region
110 private int parcelLayerViewDistance { get; set; }
111
105 #region INonSharedRegionModule Members 112 #region INonSharedRegionModule Members
106 113
107 public Type ReplaceableInterface 114 public Type ReplaceableInterface
@@ -111,12 +118,20 @@ namespace OpenSim.Region.CoreModules.World.Land
111 118
112 public void Initialise(IConfigSource source) 119 public void Initialise(IConfigSource source)
113 { 120 {
121 shouldLimitParcelLayerInfoToViewDistance = true;
122 parcelLayerViewDistance = 128;
123 IConfig landManagementConfig = source.Configs["LandManagement"];
124 if (landManagementConfig != null)
125 {
126 shouldLimitParcelLayerInfoToViewDistance = landManagementConfig.GetBoolean("LimitParcelLayerUpdateDistance", shouldLimitParcelLayerInfoToViewDistance);
127 parcelLayerViewDistance = landManagementConfig.GetInt("ParcelLayerViewDistance", parcelLayerViewDistance);
128 }
114 } 129 }
115 130
116 public void AddRegion(Scene scene) 131 public void AddRegion(Scene scene)
117 { 132 {
118 m_scene = scene; 133 m_scene = scene;
119 m_landIDList.Initialize(); 134 m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / LandUnit, m_scene.RegionInfo.RegionSizeY / LandUnit];
120 landChannel = new LandChannel(scene, this); 135 landChannel = new LandChannel(scene, this);
121 136
122 parcelInfoCache = new Cache(); 137 parcelInfoCache = new Cache();
@@ -139,28 +154,26 @@ namespace OpenSim.Region.CoreModules.World.Land
139 m_scene.EventManager.OnIncomingLandDataFromStorage += EventManagerOnIncomingLandDataFromStorage; 154 m_scene.EventManager.OnIncomingLandDataFromStorage += EventManagerOnIncomingLandDataFromStorage;
140 m_scene.EventManager.OnSetAllowForcefulBan += EventManagerOnSetAllowedForcefulBan; 155 m_scene.EventManager.OnSetAllowForcefulBan += EventManagerOnSetAllowedForcefulBan;
141 m_scene.EventManager.OnRegisterCaps += EventManagerOnRegisterCaps; 156 m_scene.EventManager.OnRegisterCaps += EventManagerOnRegisterCaps;
142 m_scene.EventManager.OnPluginConsole += EventManagerOnPluginConsole;
143 157
144 lock (m_scene) 158 lock (m_scene)
145 { 159 {
146 m_scene.LandChannel = (ILandChannel)landChannel; 160 m_scene.LandChannel = (ILandChannel)landChannel;
147 } 161 }
148 162
149 InstallInterfaces(); 163 RegisterCommands();
150 } 164 }
151 165
152 public void RegionLoaded(Scene scene) 166 public void RegionLoaded(Scene scene)
153 { 167 {
154 m_userManager = m_scene.RequestModuleInterface<IUserManagement>(); 168 m_userManager = m_scene.RequestModuleInterface<IUserManagement>();
155 m_primCountModule = m_scene.RequestModuleInterface<IPrimCountModule>(); 169 m_groupManager = m_scene.RequestModuleInterface<IGroupsModule>();
170 m_primCountModule = m_scene.RequestModuleInterface<IPrimCountModule>();
171 m_Dialog = m_scene.RequestModuleInterface<IDialogModule>();
156 } 172 }
157 173
158 public void RemoveRegion(Scene scene) 174 public void RemoveRegion(Scene scene)
159 { 175 {
160 // TODO: Also release other event manager listeners here 176 // TODO: Release event manager listeners here
161
162 m_scene.EventManager.OnPluginConsole -= EventManagerOnPluginConsole;
163 m_scene.UnregisterModuleCommander(m_commander.Name);
164 } 177 }
165 178
166// private bool OnVerifyUserConnection(ScenePresence scenePresence, out string reason) 179// private bool OnVerifyUserConnection(ScenePresence scenePresence, out string reason)
@@ -168,30 +181,7 @@ namespace OpenSim.Region.CoreModules.World.Land
168// ILandObject nearestParcel = m_scene.GetNearestAllowedParcel(scenePresence.UUID, scenePresence.AbsolutePosition.X, scenePresence.AbsolutePosition.Y); 181// ILandObject nearestParcel = m_scene.GetNearestAllowedParcel(scenePresence.UUID, scenePresence.AbsolutePosition.X, scenePresence.AbsolutePosition.Y);
169// reason = "You are not allowed to enter this sim."; 182// reason = "You are not allowed to enter this sim.";
170// return nearestParcel != null; 183// return nearestParcel != null;
171// } 184// }
172
173 /// <summary>
174 /// Processes commandline input. Do not call directly.
175 /// </summary>
176 /// <param name="args">Commandline arguments</param>
177 protected void EventManagerOnPluginConsole(string[] args)
178 {
179 if (args[0] == "land")
180 {
181 if (args.Length == 1)
182 {
183 m_commander.ProcessConsoleCommand("help", new string[0]);
184 return;
185 }
186
187 string[] tmpArgs = new string[args.Length - 2];
188 int i;
189 for (i = 2; i < args.Length; i++)
190 tmpArgs[i - 2] = args[i];
191
192 m_commander.ProcessConsoleCommand(args[1], tmpArgs);
193 }
194 }
195 185
196 void EventManagerOnNewClient(IClientAPI client) 186 void EventManagerOnNewClient(IClientAPI client)
197 { 187 {
@@ -210,6 +200,10 @@ namespace OpenSim.Region.CoreModules.World.Land
210 client.OnParcelInfoRequest += ClientOnParcelInfoRequest; 200 client.OnParcelInfoRequest += ClientOnParcelInfoRequest;
211 client.OnParcelDeedToGroup += ClientOnParcelDeedToGroup; 201 client.OnParcelDeedToGroup += ClientOnParcelDeedToGroup;
212 client.OnPreAgentUpdate += ClientOnPreAgentUpdate; 202 client.OnPreAgentUpdate += ClientOnPreAgentUpdate;
203 client.OnParcelEjectUser += ClientOnParcelEjectUser;
204 client.OnParcelFreezeUser += ClientOnParcelFreezeUser;
205 client.OnSetStartLocationRequest += ClientOnSetHome;
206
213 207
214 EntityBase presenceEntity; 208 EntityBase presenceEntity;
215 if (m_scene.Entities.TryGetValue(client.AgentId, out presenceEntity) && presenceEntity is ScenePresence) 209 if (m_scene.Entities.TryGetValue(client.AgentId, out presenceEntity) && presenceEntity is ScenePresence)
@@ -293,14 +287,15 @@ namespace OpenSim.Region.CoreModules.World.Land
293 LandData newData = data.Copy(); 287 LandData newData = data.Copy();
294 newData.LocalID = local_id; 288 newData.LocalID = local_id;
295 289
290 ILandObject land;
296 lock (m_landList) 291 lock (m_landList)
297 { 292 {
298 if (m_landList.ContainsKey(local_id)) 293 if (m_landList.TryGetValue(local_id, out land))
299 { 294 land.LandData = newData;
300 m_landList[local_id].LandData = newData;
301 m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, m_landList[local_id]);
302 }
303 } 295 }
296
297 if (land != null)
298 m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, land);
304 } 299 }
305 300
306 public bool AllowedForcefulBans 301 public bool AllowedForcefulBans
@@ -319,7 +314,7 @@ namespace OpenSim.Region.CoreModules.World.Land
319 { 314 {
320 m_landList.Clear(); 315 m_landList.Clear();
321 m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1; 316 m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1;
322 m_landIDList.Initialize(); 317 m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / LandUnit, m_scene.RegionInfo.RegionSizeY / LandUnit];
323 } 318 }
324 } 319 }
325 320
@@ -333,7 +328,8 @@ namespace OpenSim.Region.CoreModules.World.Land
333 "[LAND MANAGEMENT MODULE]: Creating default parcel for region {0}", m_scene.RegionInfo.RegionName); 328 "[LAND MANAGEMENT MODULE]: Creating default parcel for region {0}", m_scene.RegionInfo.RegionName);
334 329
335 ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene); 330 ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene);
336 fullSimParcel.SetLandBitmap(fullSimParcel.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize)); 331 fullSimParcel.SetLandBitmap(fullSimParcel.GetSquareLandBitmap(0, 0,
332 (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY));
337 fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; 333 fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
338 fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch(); 334 fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
339 335
@@ -460,8 +456,8 @@ namespace OpenSim.Region.CoreModules.World.Land
460 456
461 public void SendLandUpdate(ScenePresence avatar, bool force) 457 public void SendLandUpdate(ScenePresence avatar, bool force)
462 { 458 {
463 ILandObject over = GetLandObject((int)Math.Min(((int)Constants.RegionSize - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.X))), 459 ILandObject over = GetLandObject((int)Math.Min(((int)m_scene.RegionInfo.RegionSizeX - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.X))),
464 (int)Math.Min(((int)Constants.RegionSize - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.Y)))); 460 (int)Math.Min(((int)m_scene.RegionInfo.RegionSizeY - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.Y))));
465 461
466 if (over != null) 462 if (over != null)
467 { 463 {
@@ -543,16 +539,13 @@ namespace OpenSim.Region.CoreModules.World.Land
543 /// </summary> 539 /// </summary>
544 /// <param name="avatar"></param> 540 /// <param name="avatar"></param>
545 public void EventManagerOnClientMovement(ScenePresence avatar) 541 public void EventManagerOnClientMovement(ScenePresence avatar)
546 //
547 { 542 {
548 ILandObject over = GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); 543 Vector3 pos = avatar.AbsolutePosition;
544 ILandObject over = GetLandObject(pos.X, pos.Y);
549 if (over != null) 545 if (over != null)
550 { 546 {
551 if (!over.IsRestrictedFromLand(avatar.UUID) && (!over.IsBannedFromLand(avatar.UUID) || avatar.AbsolutePosition.Z >= LandChannel.BAN_LINE_SAFETY_HIEGHT)) 547 if (!over.IsRestrictedFromLand(avatar.UUID) && (!over.IsBannedFromLand(avatar.UUID) || pos.Z >= LandChannel.BAN_LINE_SAFETY_HIEGHT))
552 { 548 avatar.lastKnownAllowedPosition = pos;
553 avatar.lastKnownAllowedPosition =
554 new Vector3(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, avatar.AbsolutePosition.Z);
555 }
556 } 549 }
557 } 550 }
558 551
@@ -611,7 +604,10 @@ namespace OpenSim.Region.CoreModules.World.Land
611 /// <summary> 604 /// <summary>
612 /// Adds a land object to the stored list and adds them to the landIDList to what they own 605 /// Adds a land object to the stored list and adds them to the landIDList to what they own
613 /// </summary> 606 /// </summary>
614 /// <param name="new_land">The land object being added</param> 607 /// <param name="new_land">
608 /// The land object being added.
609 /// Will return null if this overlaps with an existing parcel that has not had its bitmap adjusted.
610 /// </param>
615 public ILandObject AddLandObject(ILandObject land) 611 public ILandObject AddLandObject(ILandObject land)
616 { 612 {
617 ILandObject new_land = land.Copy(); 613 ILandObject new_land = land.Copy();
@@ -619,34 +615,76 @@ namespace OpenSim.Region.CoreModules.World.Land
619 // Only now can we add the prim counts to the land object - we rely on the global ID which is generated 615 // Only now can we add the prim counts to the land object - we rely on the global ID which is generated
620 // as a random UUID inside LandData initialization 616 // as a random UUID inside LandData initialization
621 if (m_primCountModule != null) 617 if (m_primCountModule != null)
622 new_land.PrimCounts = m_primCountModule.GetPrimCounts(new_land.LandData.GlobalID); 618 new_land.PrimCounts = m_primCountModule.GetPrimCounts(new_land.LandData.GlobalID);
623 619
624 lock (m_landList) 620 lock (m_landList)
625 { 621 {
626 int newLandLocalID = ++m_lastLandLocalID; 622 int newLandLocalID = m_lastLandLocalID + 1;
627 new_land.LandData.LocalID = newLandLocalID; 623 new_land.LandData.LocalID = newLandLocalID;
628 624
629 bool[,] landBitmap = new_land.GetLandBitmap(); 625 bool[,] landBitmap = new_land.GetLandBitmap();
630 for (int x = 0; x < landArrayMax; x++) 626 // m_log.DebugFormat("{0} AddLandObject. new_land.bitmapSize=({1},{2}). newLocalID={3}",
627 // LogHeader, landBitmap.GetLength(0), landBitmap.GetLength(1), newLandLocalID);
628
629 if (landBitmap.GetLength(0) != m_landIDList.GetLength(0) || landBitmap.GetLength(1) != m_landIDList.GetLength(1))
630 {
631 // Going to variable sized regions can cause mismatches
632 m_log.ErrorFormat("{0} AddLandObject. Added land bitmap different size than region ID map. bitmapSize=({1},{2}), landIDSize=({3},{4})",
633 LogHeader, landBitmap.GetLength(0), landBitmap.GetLength(1), m_landIDList.GetLength(0), m_landIDList.GetLength(1) );
634 }
635 else
631 { 636 {
632 for (int y = 0; y < landArrayMax; y++) 637 // If other land objects still believe that they occupy any parts of the same space,
638 // then do not allow the add to proceed.
639 for (int x = 0; x < landBitmap.GetLength(0); x++)
633 { 640 {
634 if (landBitmap[x, y]) 641 for (int y = 0; y < landBitmap.GetLength(1); y++)
635 { 642 {
636// m_log.DebugFormat( 643 if (landBitmap[x, y])
637// "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}", 644 {
638// new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName); 645 int lastRecordedLandId = m_landIDList[x, y];
639 646
640 m_landIDList[x, y] = newLandLocalID; 647 if (lastRecordedLandId > 0)
648 {
649 ILandObject lastRecordedLo = m_landList[lastRecordedLandId];
650
651 if (lastRecordedLo.LandBitmap[x, y])
652 {
653 m_log.ErrorFormat(
654 "{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}",
655 LogHeader, new_land.LandData.Name, new_land.LandData.LocalID, x, y,
656 lastRecordedLo.LandData.Name, lastRecordedLo.LandData.LocalID, m_scene.Name);
657
658 return null;
659 }
660 }
661 }
662 }
663 }
664
665 for (int x = 0; x < landBitmap.GetLength(0); x++)
666 {
667 for (int y = 0; y < landBitmap.GetLength(1); y++)
668 {
669 if (landBitmap[x, y])
670 {
671 // m_log.DebugFormat(
672 // "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}",
673 // new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName);
674
675 m_landIDList[x, y] = newLandLocalID;
676 }
641 } 677 }
642 } 678 }
643 } 679 }
644 680
645 m_landList.Add(newLandLocalID, new_land); 681 m_landList.Add(newLandLocalID, new_land);
682 m_lastLandLocalID++;
646 } 683 }
647 684
648 new_land.ForceUpdateLandInfo(); 685 new_land.ForceUpdateLandInfo();
649 m_scene.EventManager.TriggerLandObjectAdded(new_land); 686 m_scene.EventManager.TriggerLandObjectAdded(new_land);
687
650 return new_land; 688 return new_land;
651 } 689 }
652 690
@@ -656,11 +694,12 @@ namespace OpenSim.Region.CoreModules.World.Land
656 /// <param name="local_id">Land.localID of the peice of land to remove.</param> 694 /// <param name="local_id">Land.localID of the peice of land to remove.</param>
657 public void removeLandObject(int local_id) 695 public void removeLandObject(int local_id)
658 { 696 {
697 ILandObject land;
659 lock (m_landList) 698 lock (m_landList)
660 { 699 {
661 for (int x = 0; x < 64; x++) 700 for (int x = 0; x < m_landIDList.GetLength(0); x++)
662 { 701 {
663 for (int y = 0; y < 64; y++) 702 for (int y = 0; y < m_landIDList.GetLength(1); y++)
664 { 703 {
665 if (m_landIDList[x, y] == local_id) 704 if (m_landIDList[x, y] == local_id)
666 { 705 {
@@ -672,9 +711,11 @@ namespace OpenSim.Region.CoreModules.World.Land
672 } 711 }
673 } 712 }
674 713
675 m_scene.EventManager.TriggerLandObjectRemoved(m_landList[local_id].LandData.GlobalID); 714 land = m_landList[local_id];
676 m_landList.Remove(local_id); 715 m_landList.Remove(local_id);
677 } 716 }
717
718 m_scene.EventManager.TriggerLandObjectRemoved(land.LandData.GlobalID);
678 } 719 }
679 720
680 /// <summary> 721 /// <summary>
@@ -682,21 +723,27 @@ namespace OpenSim.Region.CoreModules.World.Land
682 /// </summary> 723 /// </summary>
683 public void Clear(bool setupDefaultParcel) 724 public void Clear(bool setupDefaultParcel)
684 { 725 {
726 List<ILandObject> parcels;
685 lock (m_landList) 727 lock (m_landList)
686 { 728 {
687 foreach (ILandObject lo in m_landList.Values) 729 parcels = new List<ILandObject>(m_landList.Values);
688 { 730 }
689 //m_scene.SimulationDataService.RemoveLandObject(lo.LandData.GlobalID); 731
690 m_scene.EventManager.TriggerLandObjectRemoved(lo.LandData.GlobalID); 732 foreach (ILandObject lo in parcels)
691 } 733 {
734 //m_scene.SimulationDataService.RemoveLandObject(lo.LandData.GlobalID);
735 m_scene.EventManager.TriggerLandObjectRemoved(lo.LandData.GlobalID);
736 }
692 737
738 lock (m_landList)
739 {
693 m_landList.Clear(); 740 m_landList.Clear();
694 741
695 ResetSimLandObjects(); 742 ResetSimLandObjects();
696
697 if (setupDefaultParcel)
698 CreateDefaultParcel();
699 } 743 }
744
745 if (setupDefaultParcel)
746 CreateDefaultParcel();
700 } 747 }
701 748
702 private void performFinalLandJoin(ILandObject master, ILandObject slave) 749 private void performFinalLandJoin(ILandObject master, ILandObject slave)
@@ -704,9 +751,9 @@ namespace OpenSim.Region.CoreModules.World.Land
704 bool[,] landBitmapSlave = slave.GetLandBitmap(); 751 bool[,] landBitmapSlave = slave.GetLandBitmap();
705 lock (m_landList) 752 lock (m_landList)
706 { 753 {
707 for (int x = 0; x < 64; x++) 754 for (int x = 0; x < landBitmapSlave.GetLength(0); x++)
708 { 755 {
709 for (int y = 0; y < 64; y++) 756 for (int y = 0; y < landBitmapSlave.GetLength(1); y++)
710 { 757 {
711 if (landBitmapSlave[x, y]) 758 if (landBitmapSlave[x, y])
712 { 759 {
@@ -740,23 +787,28 @@ namespace OpenSim.Region.CoreModules.World.Land
740 /// <returns>Land object at the point supplied</returns> 787 /// <returns>Land object at the point supplied</returns>
741 public ILandObject GetLandObject(float x_float, float y_float) 788 public ILandObject GetLandObject(float x_float, float y_float)
742 { 789 {
790 return GetLandObject((int)x_float, (int)y_float, true /* returnNullIfLandObjectNotFound */);
791 /*
743 int x; 792 int x;
744 int y; 793 int y;
745 794
746 if (x_float >= Constants.RegionSize || x_float < 0 || y_float >= Constants.RegionSize || y_float < 0) 795 if (x_float >= m_scene.RegionInfo.RegionSizeX || x_float < 0 || y_float >= m_scene.RegionInfo.RegionSizeX || y_float < 0)
747 return null; 796 return null;
748 797
749 try 798 try
750 { 799 {
751 x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / 4.0)); 800 x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / (float)landUnit));
752 y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / 4.0)); 801 y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / (float)landUnit));
753 } 802 }
754 catch (OverflowException) 803 catch (OverflowException)
755 { 804 {
756 return null; 805 return null;
757 } 806 }
758 807
759 if (x >= 64 || y >= 64 || x < 0 || y < 0) 808 if (x >= (m_scene.RegionInfo.RegionSizeX / landUnit)
809 || y >= (m_scene.RegionInfo.RegionSizeY / landUnit)
810 || x < 0
811 || y < 0)
760 { 812 {
761 return null; 813 return null;
762 } 814 }
@@ -772,38 +824,70 @@ namespace OpenSim.Region.CoreModules.World.Land
772// m_log.DebugFormat( 824// m_log.DebugFormat(
773// "[LAND MANAGEMENT MODULE]: No land object found at ({0}, {1}) on {2}", 825// "[LAND MANAGEMENT MODULE]: No land object found at ({0}, {1}) on {2}",
774// x, y, m_scene.RegionInfo.RegionName); 826// x, y, m_scene.RegionInfo.RegionName);
775 827
776 if (m_landList.ContainsKey(m_landIDList[x, y])) 828 try
777 return m_landList[m_landIDList[x, y]]; 829 {
830 if (m_landList.ContainsKey(m_landIDList[x, y]))
831 return m_landList[m_landIDList[x, y]];
832 }
833 catch (Exception e)
834 {
835 m_log.DebugFormat("{0} GetLandObject exception. x={1}, y={2}, m_landIDList.len=({3},{4})",
836 LogHeader, x, y, m_landIDList.GetLength(0), m_landIDList.GetLength(1));
837 }
778 838
779 return null; 839 return null;
780 } 840 }
841 */
781 } 842 }
782 843
844 // Public entry.
845 // Throws exception if land object is not found
783 public ILandObject GetLandObject(int x, int y) 846 public ILandObject GetLandObject(int x, int y)
784 { 847 {
785 if (x >= Convert.ToInt32(Constants.RegionSize) || y >= Convert.ToInt32(Constants.RegionSize) || x < 0 || y < 0) 848 return GetLandObject(x, y, false /* returnNullIfLandObjectNotFound */);
849 }
850
851 /// <summary>
852 /// Given a region position, return the parcel land object for that location
853 /// </summary>
854 /// <returns>
855 /// The land object.
856 /// </returns>
857 /// <param name='x'></param>
858 /// <param name='y'></param>
859 /// <param name='returnNullIfLandObjectNotFound'>
860 /// Return null if the land object requested is not within the region's bounds.
861 /// </param>
862 private ILandObject GetLandObject(int x, int y, bool returnNullIfLandObjectOutsideBounds)
863 {
864 if (x >= m_scene.RegionInfo.RegionSizeX || y >= m_scene.RegionInfo.RegionSizeY || x < 0 || y < 0)
786 { 865 {
787 // These exceptions here will cause a lot of complaints from the users specifically because 866 // These exceptions here will cause a lot of complaints from the users specifically because
788 // they happen every time at border crossings 867 // they happen every time at border crossings
789 throw new Exception("Error: Parcel not found at point " + x + ", " + y); 868 if (returnNullIfLandObjectOutsideBounds)
790 }
791
792 lock (m_landIDList)
793 {
794 try
795 {
796 return m_landList[m_landIDList[x / 4, y / 4]];
797 }
798 catch (IndexOutOfRangeException)
799 {
800// m_log.WarnFormat(
801// "[LAND MANAGEMENT MODULE]: Tried to retrieve land object from out of bounds co-ordinate ({0},{1}) in {2}",
802// x, y, m_scene.RegionInfo.RegionName);
803
804 return null; 869 return null;
805 } 870 else
871 throw new Exception(
872 String.Format("{0} GetLandObject for non-existent position. Region={1}, pos=<{2},{3}",
873 LogHeader, m_scene.RegionInfo.RegionName, x, y)
874 );
806 } 875 }
876
877 return m_landList[m_landIDList[x / 4, y / 4]];
878 }
879
880 // Create a 'parcel is here' bitmap for the parcel identified by the passed landID
881 private bool[,] CreateBitmapForID(int landID)
882 {
883 bool[,] ret = new bool[m_landIDList.GetLength(0), m_landIDList.GetLength(1)];
884
885 for (int xx = 0; xx < m_landIDList.GetLength(0); xx++)
886 for (int yy = 0; yy < m_landIDList.GetLength(0); yy++)
887 if (m_landIDList[xx, yy] == landID)
888 ret[xx, yy] = true;
889
890 return ret;
807 } 891 }
808 892
809 #endregion 893 #endregion
@@ -973,8 +1057,12 @@ namespace OpenSim.Region.CoreModules.World.Land
973 1057
974 //Now add the new land object 1058 //Now add the new land object
975 ILandObject result = AddLandObject(newLand); 1059 ILandObject result = AddLandObject(newLand);
976 UpdateLandObject(startLandObject.LandData.LocalID, startLandObject.LandData); 1060
977 result.SendLandUpdateToAvatarsOverMe(); 1061 if (result != null)
1062 {
1063 UpdateLandObject(startLandObject.LandData.LocalID, startLandObject.LandData);
1064 result.SendLandUpdateToAvatarsOverMe();
1065 }
978 } 1066 }
979 1067
980 /// <summary> 1068 /// <summary>
@@ -1055,96 +1143,164 @@ namespace OpenSim.Region.CoreModules.World.Land
1055 1143
1056 #region Parcel Updating 1144 #region Parcel Updating
1057 1145
1146 // Send parcel layer info for the whole region
1147 public void SendParcelOverlay(IClientAPI remote_client)
1148 {
1149 SendParcelOverlay(remote_client, 0, 0, (int)Constants.MaximumRegionSize);
1150 }
1151
1058 /// <summary> 1152 /// <summary>
1059 /// Where we send the ParcelOverlay packet to the client 1153 /// Send the parcel overlay blocks to the client. We send the overlay packets
1154 /// around a location and limited by the 'parcelLayerViewDistance'. This number
1155 /// is usually 128 and the code is arranged so it sends all the parcel overlay
1156 /// information for a whole region if the region is legacy sized (256x256). If
1157 /// the region is larger, only the parcel layer information is sent around
1158 /// the point specified. This reduces the problem of parcel layer information
1159 /// blocks increasing exponentially as region size increases.
1060 /// </summary> 1160 /// </summary>
1061 /// <param name="remote_client">The object representing the client</param> 1161 /// <param name="remote_client">The object representing the client</param>
1062 public void SendParcelOverlay(IClientAPI remote_client) 1162 /// <param name="xPlace">X position in the region to send surrounding parcel layer info</param>
1163 /// <param name="yPlace">y position in the region to send surrounding parcel layer info</param>
1164 /// <param name="layerViewDistance">Distance from x,y position to send parcel layer info</param>
1165 private void SendParcelOverlay(IClientAPI remote_client, int xPlace, int yPlace, int layerViewDistance)
1063 { 1166 {
1064 const int LAND_BLOCKS_PER_PACKET = 1024; 1167 const int LAND_BLOCKS_PER_PACKET = 1024;
1065 1168
1066 byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET]; 1169 byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET];
1067 int byteArrayCount = 0; 1170 int byteArrayCount = 0;
1068 int sequenceID = 0; 1171 int sequenceID = 0;
1069 int blockmeters = 4 * (int) Constants.RegionSize/(int)Constants.TerrainPatchSize;
1070 1172
1173 int xLow = 0;
1174 int xHigh = (int)m_scene.RegionInfo.RegionSizeX;
1175 int yLow = 0;
1176 int yHigh = (int)m_scene.RegionInfo.RegionSizeY;
1071 1177
1072 for (int y = 0; y < blockmeters; y++) 1178 if (shouldLimitParcelLayerInfoToViewDistance)
1073 { 1179 {
1074 for (int x = 0; x < blockmeters; x++) 1180 // Compute view distance around the given point
1181 int txLow = xPlace - layerViewDistance;
1182 int txHigh = xPlace + layerViewDistance;
1183 // If the distance is outside the region area, move the view distance to ba all in the region
1184 if (txLow < xLow)
1185 {
1186 txLow = xLow;
1187 txHigh = Math.Min(yLow + (layerViewDistance * 2), xHigh);
1188 }
1189 if (txHigh > xHigh)
1075 { 1190 {
1076 byte tempByte = 0; //This represents the byte for the current 4x4 1191 txLow = Math.Max(xLow, xHigh - (layerViewDistance * 2));
1192 txHigh = xHigh;
1193 }
1194 xLow = txLow;
1195 xHigh = txHigh;
1077 1196
1078 ILandObject currentParcelBlock = GetLandObject(x * 4, y * 4); 1197 int tyLow = yPlace - layerViewDistance;
1198 int tyHigh = yPlace + layerViewDistance;
1199 if (tyLow < yLow)
1200 {
1201 tyLow = yLow;
1202 tyHigh = Math.Min(yLow + (layerViewDistance * 2), yHigh);
1203 }
1204 if (tyHigh > yHigh)
1205 {
1206 tyLow = Math.Max(yLow, yHigh - (layerViewDistance * 2));
1207 tyHigh = yHigh;
1208 }
1209 yLow = tyLow;
1210 yHigh = tyHigh;
1211 }
1212 // m_log.DebugFormat("{0} SendParcelOverlay: place=<{1},{2}>, vDist={3}, xLH=<{4},{5}, yLH=<{6},{7}>",
1213 // LogHeader, xPlace, yPlace, layerViewDistance, xLow, xHigh, yLow, yHigh);
1079 1214
1080 if (currentParcelBlock != null) 1215 // Layer data is in landUnit (4m) chunks
1216 for (int y = yLow; y < yHigh / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); y++)
1217 {
1218 for (int x = xLow; x < xHigh / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); x++)
1219 {
1220 byteArray[byteArrayCount] = BuildLayerByte(GetLandObject(x * LandUnit, y * LandUnit), x, y, remote_client);
1221 byteArrayCount++;
1222 if (byteArrayCount >= LAND_BLOCKS_PER_PACKET)
1081 { 1223 {
1082 if (currentParcelBlock.LandData.OwnerID == remote_client.AgentId) 1224 // m_log.DebugFormat("{0} SendParcelOverlay, sending packet, bytes={1}", LogHeader, byteArray.Length);
1083 { 1225 remote_client.SendLandParcelOverlay(byteArray, sequenceID);
1084 //Owner Flag 1226 byteArrayCount = 0;
1085 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER); 1227 sequenceID++;
1086 } 1228 byteArray = new byte[LAND_BLOCKS_PER_PACKET];
1087 else if (currentParcelBlock.LandData.SalePrice > 0 && 1229 }
1088 (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero ||
1089 currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId))
1090 {
1091 //Sale Flag
1092 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_IS_FOR_SALE);
1093 }
1094 else if (currentParcelBlock.LandData.OwnerID == UUID.Zero)
1095 {
1096 //Public Flag
1097 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_PUBLIC);
1098 }
1099 else
1100 {
1101 //Other Flag
1102 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_OTHER);
1103 }
1104 1230
1105 //Now for border control 1231 }
1232 }
1106 1233
1107 ILandObject westParcel = null; 1234 if (byteArrayCount != 0)
1108 ILandObject southParcel = null; 1235 {
1109 if (x > 0) 1236 remote_client.SendLandParcelOverlay(byteArray, sequenceID);
1110 { 1237 // m_log.DebugFormat("{0} SendParcelOverlay, complete sending packet, bytes={1}", LogHeader, byteArray.Length);
1111 westParcel = GetLandObject((x - 1) * 4, y * 4); 1238 }
1112 } 1239 }
1113 if (y > 0)
1114 {
1115 southParcel = GetLandObject(x * 4, (y - 1) * 4);
1116 }
1117 1240
1118 if (x == 0) 1241 private byte BuildLayerByte(ILandObject currentParcelBlock, int x, int y, IClientAPI remote_client)
1119 { 1242 {
1120 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST); 1243 byte tempByte = 0; //This represents the byte for the current 4x4
1121 }
1122 else if (westParcel != null && westParcel != currentParcelBlock)
1123 {
1124 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST);
1125 }
1126 1244
1127 if (y == 0) 1245 if (currentParcelBlock != null)
1128 { 1246 {
1129 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH); 1247 if (currentParcelBlock.LandData.OwnerID == remote_client.AgentId)
1130 } 1248 {
1131 else if (southParcel != null && southParcel != currentParcelBlock) 1249 //Owner Flag
1132 { 1250 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER);
1133 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH); 1251 }
1134 } 1252 else if (currentParcelBlock.LandData.SalePrice > 0 &&
1253 (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero ||
1254 currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId))
1255 {
1256 //Sale Flag
1257 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_IS_FOR_SALE);
1258 }
1259 else if (currentParcelBlock.LandData.OwnerID == UUID.Zero)
1260 {
1261 //Public Flag
1262 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_PUBLIC);
1263 }
1264 else
1265 {
1266 //Other Flag
1267 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_OTHER);
1268 }
1135 1269
1136 byteArray[byteArrayCount] = tempByte; 1270 //Now for border control
1137 byteArrayCount++; 1271
1138 if (byteArrayCount >= LAND_BLOCKS_PER_PACKET) 1272 ILandObject westParcel = null;
1139 { 1273 ILandObject southParcel = null;
1140 remote_client.SendLandParcelOverlay(byteArray, sequenceID); 1274 if (x > 0)
1141 byteArrayCount = 0; 1275 {
1142 sequenceID++; 1276 westParcel = GetLandObject((x - 1) * LandUnit, y * LandUnit);
1143 byteArray = new byte[LAND_BLOCKS_PER_PACKET]; 1277 }
1144 } 1278 if (y > 0)
1145 } 1279 {
1280 southParcel = GetLandObject(x * LandUnit, (y - 1) * LandUnit);
1281 }
1282
1283 if (x == 0)
1284 {
1285 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST);
1286 }
1287 else if (westParcel != null && westParcel != currentParcelBlock)
1288 {
1289 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST);
1146 } 1290 }
1291
1292 if (y == 0)
1293 {
1294 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH);
1295 }
1296 else if (southParcel != null && southParcel != currentParcelBlock)
1297 {
1298 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH);
1299 }
1300
1147 } 1301 }
1302
1303 return tempByte;
1148 } 1304 }
1149 1305
1150 public void ClientOnParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id, 1306 public void ClientOnParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id,
@@ -1182,7 +1338,8 @@ namespace OpenSim.Region.CoreModules.World.Land
1182 temp[i].SendLandProperties(sequence_id, snap_selection, requestResult, remote_client); 1338 temp[i].SendLandProperties(sequence_id, snap_selection, requestResult, remote_client);
1183 } 1339 }
1184 1340
1185 SendParcelOverlay(remote_client); 1341 // Also send the layer data around the point of interest
1342 SendParcelOverlay(remote_client, (start_x + end_x) / 2, (start_y + end_y) / 2, parcelLayerViewDistance);
1186 } 1343 }
1187 1344
1188 public void ClientOnParcelPropertiesUpdateRequest(LandUpdateArgs args, int localID, IClientAPI remote_client) 1345 public void ClientOnParcelPropertiesUpdateRequest(LandUpdateArgs args, int localID, IClientAPI remote_client)
@@ -1254,6 +1411,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1254 1411
1255 m_scene.ForEachClient(SendParcelOverlay); 1412 m_scene.ForEachClient(SendParcelOverlay);
1256 land.SendLandUpdateToClient(true, remote_client); 1413 land.SendLandUpdateToClient(true, remote_client);
1414 UpdateLandObject(land.LandData.LocalID, land.LandData);
1257 } 1415 }
1258 } 1416 }
1259 } 1417 }
@@ -1274,8 +1432,10 @@ namespace OpenSim.Region.CoreModules.World.Land
1274 land.LandData.GroupID = UUID.Zero; 1432 land.LandData.GroupID = UUID.Zero;
1275 land.LandData.IsGroupOwned = false; 1433 land.LandData.IsGroupOwned = false;
1276 land.LandData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory); 1434 land.LandData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
1435
1277 m_scene.ForEachClient(SendParcelOverlay); 1436 m_scene.ForEachClient(SendParcelOverlay);
1278 land.SendLandUpdateToClient(true, remote_client); 1437 land.SendLandUpdateToClient(true, remote_client);
1438 UpdateLandObject(land.LandData.LocalID, land.LandData);
1279 } 1439 }
1280 } 1440 }
1281 } 1441 }
@@ -1302,6 +1462,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1302 1462
1303 m_scene.ForEachClient(SendParcelOverlay); 1463 m_scene.ForEachClient(SendParcelOverlay);
1304 land.SendLandUpdateToClient(true, remote_client); 1464 land.SendLandUpdateToClient(true, remote_client);
1465 UpdateLandObject(land.LandData.LocalID, land.LandData);
1305 } 1466 }
1306 } 1467 }
1307 } 1468 }
@@ -1382,19 +1543,78 @@ namespace OpenSim.Region.CoreModules.World.Land
1382 1543
1383 #region Land Object From Storage Functions 1544 #region Land Object From Storage Functions
1384 1545
1385 public void EventManagerOnIncomingLandDataFromStorage(List<LandData> data) 1546 private void EventManagerOnIncomingLandDataFromStorage(List<LandData> data)
1386 { 1547 {
1387// m_log.DebugFormat( 1548// m_log.DebugFormat(
1388// "[LAND MANAGMENT MODULE]: Processing {0} incoming parcels on {1}", data.Count, m_scene.Name); 1549// "[LAND MANAGMENT MODULE]: Processing {0} incoming parcels on {1}", data.Count, m_scene.Name);
1389 1550
1390 for (int i = 0; i < data.Count; i++) 1551 // Prevent race conditions from any auto-creation of new parcels for varregions whilst we are still loading
1391 IncomingLandObjectFromStorage(data[i]); 1552 // the existing parcels.
1553 lock (m_landList)
1554 {
1555 for (int i = 0; i < data.Count; i++)
1556 IncomingLandObjectFromStorage(data[i]);
1557
1558 // Layer data is in landUnit (4m) chunks
1559 for (int y = 0; y < m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); y++)
1560 {
1561 for (int x = 0; x < m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); x++)
1562 {
1563 if (m_landIDList[x, y] == 0)
1564 {
1565 if (m_landList.Count == 1)
1566 {
1567 m_log.DebugFormat(
1568 "[{0}]: Auto-extending land parcel as landID at {1},{2} is 0 and only one land parcel is present in {3}",
1569 LogHeader, x, y, m_scene.Name);
1570
1571 int onlyParcelID = 0;
1572 ILandObject onlyLandObject = null;
1573 foreach (KeyValuePair<int, ILandObject> kvp in m_landList)
1574 {
1575 onlyParcelID = kvp.Key;
1576 onlyLandObject = kvp.Value;
1577 break;
1578 }
1579
1580 // There is only one parcel. Grow it to fill all the unallocated spaces.
1581 for (int xx = 0; xx < m_landIDList.GetLength(0); xx++)
1582 for (int yy = 0; yy < m_landIDList.GetLength(1); yy++)
1583 if (m_landIDList[xx, yy] == 0)
1584 m_landIDList[xx, yy] = onlyParcelID;
1585
1586 onlyLandObject.LandBitmap = CreateBitmapForID(onlyParcelID);
1587 }
1588 else if (m_landList.Count > 1)
1589 {
1590 m_log.DebugFormat(
1591 "{0}: Auto-creating land parcel as landID at {1},{2} is 0 and more than one land parcel is present in {3}",
1592 LogHeader, x, y, m_scene.Name);
1593
1594 // There are several other parcels so we must create a new one for the unassigned space
1595 ILandObject newLand = new LandObject(UUID.Zero, false, m_scene);
1596 // Claim all the unclaimed "0" ids
1597 newLand.SetLandBitmap(CreateBitmapForID(0));
1598 newLand.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
1599 newLand.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
1600 newLand = AddLandObject(newLand);
1601 }
1602 else
1603 {
1604 // We should never reach this point as the separate code path when no land data exists should have fired instead.
1605 m_log.WarnFormat(
1606 "{0}: Ignoring request to auto-create parcel in {1} as there are no other parcels present",
1607 LogHeader, m_scene.Name);
1608 }
1609 }
1610 }
1611 }
1612 }
1392 } 1613 }
1393 1614
1394 public void IncomingLandObjectFromStorage(LandData data) 1615 private void IncomingLandObjectFromStorage(LandData data)
1395 { 1616 {
1396 ILandObject new_land = new LandObject(data.OwnerID, data.IsGroupOwned, m_scene); 1617 ILandObject new_land = new LandObject(data, m_scene);
1397 new_land.LandData = data.Copy();
1398 new_land.SetLandBitmapFromByteArray(); 1618 new_land.SetLandBitmapFromByteArray();
1399 AddLandObject(new_land); 1619 AddLandObject(new_land);
1400 } 1620 }
@@ -1409,7 +1629,8 @@ namespace OpenSim.Region.CoreModules.World.Land
1409 m_landList.TryGetValue(localID, out selectedParcel); 1629 m_landList.TryGetValue(localID, out selectedParcel);
1410 } 1630 }
1411 1631
1412 if (selectedParcel == null) return; 1632 if (selectedParcel == null)
1633 return;
1413 1634
1414 selectedParcel.ReturnLandObjects(returnType, agentIDs, taskIDs, remoteClient); 1635 selectedParcel.ReturnLandObjects(returnType, agentIDs, taskIDs, remoteClient);
1415 } 1636 }
@@ -1417,7 +1638,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1417 { 1638 {
1418 if (returnType != 1) 1639 if (returnType != 1)
1419 { 1640 {
1420 m_log.WarnFormat("[LAND MANAGEMENT MODULE] ReturnObjectsInParcel: unknown return type {0}", returnType); 1641 m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: unknown return type {0}", returnType);
1421 return; 1642 return;
1422 } 1643 }
1423 1644
@@ -1437,14 +1658,14 @@ namespace OpenSim.Region.CoreModules.World.Land
1437 } 1658 }
1438 else 1659 else
1439 { 1660 {
1440 m_log.WarnFormat("[LAND MANAGEMENT MODULE] ReturnObjectsInParcel: unknown object {0}", groupID); 1661 m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: unknown object {0}", groupID);
1441 } 1662 }
1442 } 1663 }
1443 1664
1444 int num = 0; 1665 int num = 0;
1445 foreach (HashSet<SceneObjectGroup> objs in returns.Values) 1666 foreach (HashSet<SceneObjectGroup> objs in returns.Values)
1446 num += objs.Count; 1667 num += objs.Count;
1447 m_log.DebugFormat("[LAND MANAGEMENT MODULE] Returning {0} specific object(s)", num); 1668 m_log.DebugFormat("[LAND MANAGEMENT MODULE]: Returning {0} specific object(s)", num);
1448 1669
1449 foreach (HashSet<SceneObjectGroup> objs in returns.Values) 1670 foreach (HashSet<SceneObjectGroup> objs in returns.Values)
1450 { 1671 {
@@ -1455,7 +1676,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1455 } 1676 }
1456 else 1677 else
1457 { 1678 {
1458 m_log.WarnFormat("[LAND MANAGEMENT MODULE] ReturnObjectsInParcel: not permitted to return {0} object(s) belonging to user {1}", 1679 m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: not permitted to return {0} object(s) belonging to user {1}",
1459 objs2.Count, objs2[0].OwnerID); 1680 objs2.Count, objs2[0].OwnerID);
1460 } 1681 }
1461 } 1682 }
@@ -1464,11 +1685,8 @@ namespace OpenSim.Region.CoreModules.World.Land
1464 1685
1465 public void EventManagerOnNoLandDataFromStorage() 1686 public void EventManagerOnNoLandDataFromStorage()
1466 { 1687 {
1467 lock (m_landList) 1688 ResetSimLandObjects();
1468 { 1689 CreateDefaultParcel();
1469 ResetSimLandObjects();
1470 CreateDefaultParcel();
1471 }
1472 } 1690 }
1473 1691
1474 #endregion 1692 #endregion
@@ -1694,7 +1912,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1694 { 1912 {
1695 // most likely still cached from building the extLandData entry 1913 // most likely still cached from building the extLandData entry
1696 uint x = 0, y = 0; 1914 uint x = 0, y = 0;
1697 Utils.LongToUInts(data.RegionHandle, out x, out y); 1915 Util.RegionHandleToWorldLoc(data.RegionHandle, out x, out y);
1698 info = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); 1916 info = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y);
1699 } 1917 }
1700 // we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark. 1918 // we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark.
@@ -1730,66 +1948,332 @@ namespace OpenSim.Region.CoreModules.World.Land
1730 UpdateLandObject(localID, land.LandData); 1948 UpdateLandObject(localID, land.LandData);
1731 } 1949 }
1732 1950
1733 protected void InstallInterfaces() 1951 Dictionary<UUID, System.Threading.Timer> Timers = new Dictionary<UUID, System.Threading.Timer>();
1952
1953 public void ClientOnParcelFreezeUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
1954 {
1955 ScenePresence targetAvatar = null;
1956 ((Scene)client.Scene).TryGetScenePresence(target, out targetAvatar);
1957 ScenePresence parcelManager = null;
1958 ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out parcelManager);
1959 System.Threading.Timer Timer;
1960
1961 if (targetAvatar.UserLevel == 0)
1962 {
1963 ILandObject land = ((Scene)client.Scene).LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
1964 if (!((Scene)client.Scene).Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze))
1965 return;
1966 if (flags == 0)
1967 {
1968 targetAvatar.AllowMovement = false;
1969 targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has frozen you for 30 seconds. You cannot move or interact with the world.");
1970 parcelManager.ControllingClient.SendAlertMessage("Avatar Frozen.");
1971 System.Threading.TimerCallback timeCB = new System.Threading.TimerCallback(OnEndParcelFrozen);
1972 Timer = new System.Threading.Timer(timeCB, targetAvatar, 30000, 0);
1973 Timers.Add(targetAvatar.UUID, Timer);
1974 }
1975 else
1976 {
1977 targetAvatar.AllowMovement = true;
1978 targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has unfrozen you.");
1979 parcelManager.ControllingClient.SendAlertMessage("Avatar Unfrozen.");
1980 Timers.TryGetValue(targetAvatar.UUID, out Timer);
1981 Timers.Remove(targetAvatar.UUID);
1982 Timer.Dispose();
1983 }
1984 }
1985 }
1986
1987 private void OnEndParcelFrozen(object avatar)
1734 { 1988 {
1735 Command clearCommand 1989 ScenePresence targetAvatar = (ScenePresence)avatar;
1736 = new Command("clear", CommandIntentions.COMMAND_HAZARDOUS, ClearCommand, "Clears all the parcels from the region."); 1990 targetAvatar.AllowMovement = true;
1737 Command showCommand 1991 System.Threading.Timer Timer;
1738 = new Command("show", CommandIntentions.COMMAND_STATISTICAL, ShowParcelsCommand, "Shows all parcels on the region."); 1992 Timers.TryGetValue(targetAvatar.UUID, out Timer);
1993 Timers.Remove(targetAvatar.UUID);
1994 targetAvatar.ControllingClient.SendAgentAlertMessage("The freeze has worn off; you may go about your business.", false);
1995 }
1996
1997 public void ClientOnParcelEjectUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
1998 {
1999 ScenePresence targetAvatar = null;
2000 ScenePresence parcelManager = null;
2001
2002 // Must have presences
2003 if (!m_scene.TryGetScenePresence(target, out targetAvatar) ||
2004 !m_scene.TryGetScenePresence(client.AgentId, out parcelManager))
2005 return;
2006
2007 // Cannot eject estate managers or gods
2008 if (m_scene.Permissions.IsAdministrator(target))
2009 return;
2010
2011 // Check if you even have permission to do this
2012 ILandObject land = m_scene.LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
2013 if (!m_scene.Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze) &&
2014 !m_scene.Permissions.IsAdministrator(client.AgentId))
2015 return;
2016 Vector3 pos = m_scene.GetNearestAllowedPosition(targetAvatar, land);
2017
2018 targetAvatar.TeleportWithMomentum(pos, null);
2019 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
2020 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
1739 2021
1740 m_commander.RegisterCommand("clear", clearCommand); 2022 if ((flags & 1) != 0) // Ban TODO: Remove magic number
1741 m_commander.RegisterCommand("show", showCommand); 2023 {
2024 LandAccessEntry entry = new LandAccessEntry();
2025 entry.AgentID = targetAvatar.UUID;
2026 entry.Flags = AccessList.Ban;
2027 entry.Expires = 0; // Perm
1742 2028
1743 // Add this to our scene so scripts can call these functions 2029 land.LandData.ParcelAccessList.Add(entry);
1744 m_scene.RegisterModuleCommander(m_commander); 2030 }
2031 }
2032
2033 /// <summary>
2034 /// Sets the Home Point. The LoginService uses this to know where to put a user when they log-in
2035 /// </summary>
2036 /// <param name="remoteClient"></param>
2037 /// <param name="regionHandle"></param>
2038 /// <param name="position"></param>
2039 /// <param name="lookAt"></param>
2040 /// <param name="flags"></param>
2041 public virtual void ClientOnSetHome(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags)
2042 {
2043 // Let's find the parcel in question
2044 ILandObject land = landChannel.GetLandObject(position);
2045 if (land == null || m_scene.GridUserService == null)
2046 {
2047 m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed.");
2048 return;
2049 }
2050
2051 // Gather some data
2052 ulong gpowers = remoteClient.GetGroupPowers(land.LandData.GroupID);
2053 SceneObjectGroup telehub = null;
2054 if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero)
2055 // Does the telehub exist in the scene?
2056 telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject);
2057
2058 // Can the user set home here?
2059 if (// Required: local user; foreign users cannot set home
2060 m_scene.UserManagementModule.IsLocalGridUser(remoteClient.AgentId) &&
2061 (// (a) gods and land managers can set home
2062 m_scene.Permissions.IsAdministrator(remoteClient.AgentId) ||
2063 m_scene.Permissions.IsGod(remoteClient.AgentId) ||
2064 // (b) land owners can set home
2065 remoteClient.AgentId == land.LandData.OwnerID ||
2066 // (c) members of the land-associated group in roles that can set home
2067 ((gpowers & (ulong)GroupPowers.AllowSetHome) == (ulong)GroupPowers.AllowSetHome) ||
2068 // (d) parcels with telehubs can be the home of anyone
2069 (telehub != null && land.ContainsPoint((int)telehub.AbsolutePosition.X, (int)telehub.AbsolutePosition.Y))))
2070 {
2071 string userId;
2072 UUID test;
2073 if (!m_scene.UserManagementModule.GetUserUUI(remoteClient.AgentId, out userId))
2074 {
2075 /* Do not set a home position in this grid for a HG visitor */
2076 m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed. (User Lookup)");
2077 }
2078 else if (!UUID.TryParse(userId, out test))
2079 {
2080 m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed. (HG visitor)");
2081 }
2082 else if (m_scene.GridUserService.SetHome(userId, land.RegionUUID, position, lookAt))
2083 {
2084 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot.
2085 m_Dialog.SendAlertToUser(remoteClient, "Home position set.");
2086 }
2087 else
2088 {
2089 m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed.");
2090 }
2091 }
2092 else
2093 m_Dialog.SendAlertToUser(remoteClient, "You are not allowed to set your home location in this parcel.");
2094 }
2095
2096 protected void RegisterCommands()
2097 {
2098 ICommands commands = MainConsole.Instance.Commands;
2099
2100 commands.AddCommand(
2101 "Land", false, "land clear",
2102 "land clear",
2103 "Clear all the parcels from the region.",
2104 "Command will ask for confirmation before proceeding.",
2105 HandleClearCommand);
2106
2107 commands.AddCommand(
2108 "Land", false, "land show",
2109 "land show [<local-land-id>]",
2110 "Show information about the parcels on the region.",
2111 "If no local land ID is given, then summary information about all the parcels is shown.\n"
2112 + "If a local land ID is given then full information about that parcel is shown.",
2113 HandleShowCommand);
1745 } 2114 }
1746 2115
1747 protected void ClearCommand(Object[] args) 2116 protected void HandleClearCommand(string module, string[] args)
1748 { 2117 {
2118 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene))
2119 return;
2120
1749 string response = MainConsole.Instance.CmdPrompt( 2121 string response = MainConsole.Instance.CmdPrompt(
1750 string.Format( 2122 string.Format(
1751 "Are you sure that you want to clear all land parcels from {0} (y or n)", 2123 "Are you sure that you want to clear all land parcels from {0} (y or n)", m_scene.Name),
1752 m_scene.RegionInfo.RegionName),
1753 "n"); 2124 "n");
1754 2125
1755 if (response.ToLower() == "y") 2126 if (response.ToLower() == "y")
1756 { 2127 {
1757 Clear(true); 2128 Clear(true);
1758 MainConsole.Instance.OutputFormat("Cleared all parcels from {0}", m_scene.RegionInfo.RegionName); 2129 MainConsole.Instance.OutputFormat("Cleared all parcels from {0}", m_scene.Name);
1759 } 2130 }
1760 else 2131 else
1761 { 2132 {
1762 MainConsole.Instance.OutputFormat("Aborting clear of all parcels from {0}", m_scene.RegionInfo.RegionName); 2133 MainConsole.Instance.OutputFormat("Aborting clear of all parcels from {0}", m_scene.Name);
1763 } 2134 }
1764 } 2135 }
1765 2136
1766 protected void ShowParcelsCommand(Object[] args) 2137 protected void HandleShowCommand(string module, string[] args)
1767 { 2138 {
1768 StringBuilder report = new StringBuilder(); 2139 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene))
1769 2140 return;
1770 report.AppendFormat("Land information for {0}\n", m_scene.RegionInfo.RegionName); 2141
1771 report.AppendFormat( 2142 StringBuilder report = new StringBuilder();
1772 "{0,-20} {1,-10} {2,-9} {3,-18} {4,-18} {5,-20}\n", 2143
1773 "Parcel Name", 2144 if (args.Length <= 2)
1774 "Local ID", 2145 {
1775 "Area", 2146 AppendParcelsSummaryReport(report);
1776 "Starts", 2147 }
1777 "Ends", 2148 else
1778 "Owner"); 2149 {
2150 int landLocalId;
2151
2152 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[2], out landLocalId))
2153 return;
2154
2155 ILandObject lo;
2156
2157 lock (m_landList)
2158 {
2159 if (!m_landList.TryGetValue(landLocalId, out lo))
2160 {
2161 MainConsole.Instance.OutputFormat("No parcel found with local ID {0}", landLocalId);
2162 return;
2163 }
2164 }
2165
2166 AppendParcelReport(report, lo);
2167 }
2168
2169 MainConsole.Instance.Output(report.ToString());
2170 }
2171
2172 private void AppendParcelsSummaryReport(StringBuilder report)
2173 {
2174 report.AppendFormat("Land information for {0}\n", m_scene.Name);
2175
2176 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
2177 cdt.AddColumn("Parcel Name", ConsoleDisplayUtil.ParcelNameSize);
2178 cdt.AddColumn("ID", 3);
2179 cdt.AddColumn("Area", 6);
2180 cdt.AddColumn("Starts", ConsoleDisplayUtil.VectorSize);
2181 cdt.AddColumn("Ends", ConsoleDisplayUtil.VectorSize);
2182 cdt.AddColumn("Owner", ConsoleDisplayUtil.UserNameSize);
1779 2183
1780 lock (m_landList) 2184 lock (m_landList)
1781 { 2185 {
1782 foreach (ILandObject lo in m_landList.Values) 2186 foreach (ILandObject lo in m_landList.Values)
1783 { 2187 {
1784 LandData ld = lo.LandData; 2188 LandData ld = lo.LandData;
1785 2189 string ownerName;
1786 report.AppendFormat( 2190 if (ld.IsGroupOwned)
1787 "{0,-20} {1,-10} {2,-9} {3,-18} {4,-18} {5,-20}\n", 2191 {
1788 ld.Name, ld.LocalID, ld.Area, lo.StartPoint, lo.EndPoint, m_userManager.GetUserName(ld.OwnerID)); 2192 GroupRecord rec = m_groupManager.GetGroupRecord(ld.GroupID);
2193 ownerName = (rec != null) ? rec.GroupName : "Unknown Group";
2194 }
2195 else
2196 {
2197 ownerName = m_userManager.GetUserName(ld.OwnerID);
2198 }
2199 cdt.AddRow(
2200 ld.Name, ld.LocalID, ld.Area, lo.StartPoint, lo.EndPoint, ownerName);
1789 } 2201 }
1790 } 2202 }
1791 2203
1792 MainConsole.Instance.Output(report.ToString()); 2204 report.Append(cdt.ToString());
1793 } 2205 }
2206
2207 private void AppendParcelReport(StringBuilder report, ILandObject lo)
2208 {
2209 LandData ld = lo.LandData;
2210
2211 ConsoleDisplayList cdl = new ConsoleDisplayList();
2212 cdl.AddRow("Parcel name", ld.Name);
2213 cdl.AddRow("Local ID", ld.LocalID);
2214 cdl.AddRow("Description", ld.Description);
2215 cdl.AddRow("Snapshot ID", ld.SnapshotID);
2216 cdl.AddRow("Area", ld.Area);
2217 cdl.AddRow("Starts", lo.StartPoint);
2218 cdl.AddRow("Ends", lo.EndPoint);
2219 cdl.AddRow("AABB Min", ld.AABBMin);
2220 cdl.AddRow("AABB Max", ld.AABBMax);
2221 string ownerName;
2222 if (ld.IsGroupOwned)
2223 {
2224 GroupRecord rec = m_groupManager.GetGroupRecord(ld.GroupID);
2225 ownerName = (rec != null) ? rec.GroupName : "Unknown Group";
2226 }
2227 else
2228 {
2229 ownerName = m_userManager.GetUserName(ld.OwnerID);
2230 }
2231 cdl.AddRow("Owner", ownerName);
2232 cdl.AddRow("Is group owned?", ld.IsGroupOwned);
2233 cdl.AddRow("GroupID", ld.GroupID);
2234
2235 cdl.AddRow("Status", ld.Status);
2236 cdl.AddRow("Flags", (ParcelFlags)ld.Flags);
2237
2238 cdl.AddRow("Landing Type", (LandingType)ld.LandingType);
2239 cdl.AddRow("User Location", ld.UserLocation);
2240 cdl.AddRow("User look at", ld.UserLookAt);
2241
2242 cdl.AddRow("Other clean time", ld.OtherCleanTime);
2243
2244 cdl.AddRow("Max Prims", lo.GetParcelMaxPrimCount());
2245 IPrimCounts pc = lo.PrimCounts;
2246 cdl.AddRow("Owner Prims", pc.Owner);
2247 cdl.AddRow("Group Prims", pc.Group);
2248 cdl.AddRow("Other Prims", pc.Others);
2249 cdl.AddRow("Selected Prims", pc.Selected);
2250 cdl.AddRow("Total Prims", pc.Total);
2251
2252 cdl.AddRow("Music URL", ld.MusicURL);
2253 cdl.AddRow("Obscure Music", ld.ObscureMusic);
2254
2255 cdl.AddRow("Media ID", ld.MediaID);
2256 cdl.AddRow("Media Autoscale", Convert.ToBoolean(ld.MediaAutoScale));
2257 cdl.AddRow("Media URL", ld.MediaURL);
2258 cdl.AddRow("Media Type", ld.MediaType);
2259 cdl.AddRow("Media Description", ld.MediaDescription);
2260 cdl.AddRow("Media Width", ld.MediaWidth);
2261 cdl.AddRow("Media Height", ld.MediaHeight);
2262 cdl.AddRow("Media Loop", ld.MediaLoop);
2263 cdl.AddRow("Obscure Media", ld.ObscureMedia);
2264
2265 cdl.AddRow("Parcel Category", ld.Category);
2266
2267 cdl.AddRow("Claim Date", ld.ClaimDate);
2268 cdl.AddRow("Claim Price", ld.ClaimPrice);
2269 cdl.AddRow("Pass Hours", ld.PassHours);
2270 cdl.AddRow("Pass Price", ld.PassPrice);
2271
2272 cdl.AddRow("Auction ID", ld.AuctionID);
2273 cdl.AddRow("Authorized Buyer ID", ld.AuthBuyerID);
2274 cdl.AddRow("Sale Price", ld.SalePrice);
2275
2276 cdl.AddToStringBuilder(report);
2277 }
1794 } 2278 }
1795} 2279}
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
index 5969d45..a0c1b9d 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
@@ -45,14 +45,12 @@ namespace OpenSim.Region.CoreModules.World.Land
45 #region Member Variables 45 #region Member Variables
46 46
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 #pragma warning disable 0429 48 private static readonly string LogHeader = "[LAND OBJECT]";
49 private const int landArrayMax = ((int)((int)Constants.RegionSize / 4) >= 64) ? (int)((int)Constants.RegionSize / 4) : 64;
50 #pragma warning restore 0429
51 private bool[,] m_landBitmap = new bool[landArrayMax,landArrayMax];
52 49
53 private int m_lastSeqId = 0; 50 private readonly int landUnit = 4;
54 51
55 protected LandData m_landData = new LandData(); 52 private int m_lastSeqId = 0;
53
56 protected Scene m_scene; 54 protected Scene m_scene;
57 protected List<SceneObjectGroup> primsOverMe = new List<SceneObjectGroup>(); 55 protected List<SceneObjectGroup> primsOverMe = new List<SceneObjectGroup>();
58 protected Dictionary<uint, UUID> m_listTransactions = new Dictionary<uint, UUID>(); 56 protected Dictionary<uint, UUID> m_listTransactions = new Dictionary<uint, UUID>();
@@ -60,76 +58,83 @@ namespace OpenSim.Region.CoreModules.World.Land
60 protected ExpiringCache<UUID, bool> m_groupMemberCache = new ExpiringCache<UUID, bool>(); 58 protected ExpiringCache<UUID, bool> m_groupMemberCache = new ExpiringCache<UUID, bool>();
61 protected TimeSpan m_groupMemberCacheTimeout = TimeSpan.FromSeconds(30); // cache invalidation after 30 seconds 59 protected TimeSpan m_groupMemberCacheTimeout = TimeSpan.FromSeconds(30); // cache invalidation after 30 seconds
62 60
63 public bool[,] LandBitmap 61 public bool[,] LandBitmap { get; set; }
64 {
65 get { return m_landBitmap; }
66 set { m_landBitmap = value; }
67 }
68 62
69 #endregion 63 #endregion
70 64
71 public int GetPrimsFree() 65 public int GetPrimsFree()
72 { 66 {
73 m_scene.EventManager.TriggerParcelPrimCountUpdate(); 67 m_scene.EventManager.TriggerParcelPrimCountUpdate();
74 int free = GetSimulatorMaxPrimCount() - m_landData.SimwidePrims; 68 int free = GetSimulatorMaxPrimCount() - LandData.SimwidePrims;
75 return free; 69 return free;
76 } 70 }
77 71
78 public LandData LandData 72 public LandData LandData { get; set; }
79 {
80 get { return m_landData; }
81 73
82 set { m_landData = value; }
83 }
84
85 public IPrimCounts PrimCounts { get; set; } 74 public IPrimCounts PrimCounts { get; set; }
86 75
87 public UUID RegionUUID 76 public UUID RegionUUID
88 { 77 {
89 get { return m_scene.RegionInfo.RegionID; } 78 get { return m_scene.RegionInfo.RegionID; }
90 } 79 }
91 80
92 public Vector3 StartPoint 81 public Vector3 StartPoint
93 { 82 {
94 get 83 get
95 { 84 {
96 for (int y = 0; y < landArrayMax; y++) 85 for (int y = 0; y < LandBitmap.GetLength(1); y++)
97 { 86 {
98 for (int x = 0; x < landArrayMax; x++) 87 for (int x = 0; x < LandBitmap.GetLength(0); x++)
99 { 88 {
100 if (LandBitmap[x, y]) 89 if (LandBitmap[x, y])
101 return new Vector3(x * 4, y * 4, 0); 90 return new Vector3(x * landUnit, y * landUnit, 0);
102 } 91 }
103 } 92 }
104 93
94 m_log.ErrorFormat("{0} StartPoint. No start point found. bitmapSize=<{1},{2}>",
95 LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1));
105 return new Vector3(-1, -1, -1); 96 return new Vector3(-1, -1, -1);
106 } 97 }
107 } 98 }
108 99
109 public Vector3 EndPoint 100 public Vector3 EndPoint
110 { 101 {
111 get 102 get
112 { 103 {
113 for (int y = landArrayMax - 1; y >= 0; y--) 104 for (int y = LandBitmap.GetLength(1) - 1; y >= 0; y--)
114 { 105 {
115 for (int x = landArrayMax - 1; x >= 0; x--) 106 for (int x = LandBitmap.GetLength(0) - 1; x >= 0; x--)
116 { 107 {
117 if (LandBitmap[x, y]) 108 if (LandBitmap[x, y])
118 { 109 {
119 return new Vector3(x * 4, y * 4, 0); 110 return new Vector3(x * landUnit + landUnit, y * landUnit + landUnit, 0);
120 } 111 }
121 } 112 }
122 } 113 }
123 114
115 m_log.ErrorFormat("{0} EndPoint. No end point found. bitmapSize=<{1},{2}>",
116 LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1));
124 return new Vector3(-1, -1, -1); 117 return new Vector3(-1, -1, -1);
125 } 118 }
126 } 119 }
127 120
128 #region Constructors 121 #region Constructors
129 122
123 public LandObject(LandData landData, Scene scene)
124 {
125 LandData = landData.Copy();
126 m_scene = scene;
127 }
128
130 public LandObject(UUID owner_id, bool is_group_owned, Scene scene) 129 public LandObject(UUID owner_id, bool is_group_owned, Scene scene)
131 { 130 {
132 m_scene = scene; 131 m_scene = scene;
132 if (m_scene == null)
133 LandBitmap = new bool[Constants.RegionSize / landUnit, Constants.RegionSize / landUnit];
134 else
135 LandBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
136
137 LandData = new LandData();
133 LandData.OwnerID = owner_id; 138 LandData.OwnerID = owner_id;
134 if (is_group_owned) 139 if (is_group_owned)
135 LandData.GroupID = owner_id; 140 LandData.GroupID = owner_id;
@@ -152,9 +157,9 @@ namespace OpenSim.Region.CoreModules.World.Land
152 /// <returns>Returns true if the piece of land contains the specified point</returns> 157 /// <returns>Returns true if the piece of land contains the specified point</returns>
153 public bool ContainsPoint(int x, int y) 158 public bool ContainsPoint(int x, int y)
154 { 159 {
155 if (x >= 0 && y >= 0 && x < Constants.RegionSize && y < Constants.RegionSize) 160 if (x >= 0 && y >= 0 && x < m_scene.RegionInfo.RegionSizeX && y < m_scene.RegionInfo.RegionSizeY)
156 { 161 {
157 return (LandBitmap[x / 4, y / 4] == true); 162 return LandBitmap[x / landUnit, y / landUnit];
158 } 163 }
159 else 164 else
160 { 165 {
@@ -164,12 +169,8 @@ namespace OpenSim.Region.CoreModules.World.Land
164 169
165 public ILandObject Copy() 170 public ILandObject Copy()
166 { 171 {
167 ILandObject newLand = new LandObject(LandData.OwnerID, LandData.IsGroupOwned, m_scene); 172 ILandObject newLand = new LandObject(LandData, m_scene);
168
169 //Place all new variables here!
170 newLand.LandBitmap = (bool[,]) (LandBitmap.Clone()); 173 newLand.LandBitmap = (bool[,]) (LandBitmap.Clone());
171 newLand.LandData = LandData.Copy();
172
173 return newLand; 174 return newLand;
174 } 175 }
175 176
@@ -194,7 +195,7 @@ namespace OpenSim.Region.CoreModules.World.Land
194 else 195 else
195 { 196 {
196 // Normal Calculations 197 // Normal Calculations
197 int parcelMax = (int)(((float)LandData.Area / 65536.0f) 198 int parcelMax = (int)(((float)LandData.Area / (m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY))
198 * (float)m_scene.RegionInfo.ObjectCapacity 199 * (float)m_scene.RegionInfo.ObjectCapacity
199 * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); 200 * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus);
200 // TODO: The calculation of ObjectBonus should be refactored. It does still not work in the same manner as SL! 201 // TODO: The calculation of ObjectBonus should be refactored. It does still not work in the same manner as SL!
@@ -211,7 +212,7 @@ namespace OpenSim.Region.CoreModules.World.Land
211 else 212 else
212 { 213 {
213 //Normal Calculations 214 //Normal Calculations
214 int simMax = (int)(((float)LandData.SimwideArea / 65536.0f) 215 int simMax = (int)(((float)LandData.SimwideArea / (m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY))
215 * (float)m_scene.RegionInfo.ObjectCapacity); 216 * (float)m_scene.RegionInfo.ObjectCapacity);
216 return simMax; 217 return simMax;
217 } 218 }
@@ -224,17 +225,15 @@ namespace OpenSim.Region.CoreModules.World.Land
224 public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client) 225 public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client)
225 { 226 {
226 IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>(); 227 IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>();
227 uint regionFlags = 336723974 & ~((uint)(RegionFlags.AllowLandmark | RegionFlags.AllowSetHome)); 228 // uint regionFlags = 336723974 & ~((uint)(RegionFlags.AllowLandmark | RegionFlags.AllowSetHome));
229 uint regionFlags = (uint)(RegionFlags.PublicAllowed
230 | RegionFlags.AllowDirectTeleport
231 | RegionFlags.AllowParcelChanges
232 | RegionFlags.AllowVoice );
233
228 if (estateModule != null) 234 if (estateModule != null)
229 regionFlags = estateModule.GetRegionFlags(); 235 regionFlags = estateModule.GetRegionFlags();
230 236
231 // In a perfect world, this would have worked.
232 //
233// if ((landData.Flags & (uint)ParcelFlags.AllowLandmark) != 0)
234// regionFlags |= (uint)RegionFlags.AllowLandmark;
235// if (landData.OwnerID == remote_client.AgentId)
236// regionFlags |= (uint)RegionFlags.AllowSetHome;
237
238 int seq_id; 237 int seq_id;
239 if (snap_selection && (sequence_id == 0)) 238 if (snap_selection && (sequence_id == 0))
240 { 239 {
@@ -368,12 +367,14 @@ namespace OpenSim.Region.CoreModules.World.Land
368 ParcelFlags.DenyAgeUnverified); 367 ParcelFlags.DenyAgeUnverified);
369 } 368 }
370 369
371 uint preserve = LandData.Flags & ~allowedDelta; 370 if (allowedDelta != (uint)ParcelFlags.None)
372 newData.Flags = preserve | (args.ParcelFlags & allowedDelta); 371 {
373 372 uint preserve = LandData.Flags & ~allowedDelta;
374 m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData); 373 newData.Flags = preserve | (args.ParcelFlags & allowedDelta);
375 374
376 SendLandUpdateToAvatarsOverMe(snap_selection); 375 m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
376 SendLandUpdateToAvatarsOverMe(snap_selection);
377 }
377 } 378 }
378 379
379 public void UpdateLandSold(UUID avatarID, UUID groupID, bool groupOwned, uint AuctionID, int claimprice, int area) 380 public void UpdateLandSold(UUID avatarID, UUID groupID, bool groupOwned, uint AuctionID, int claimprice, int area)
@@ -388,9 +389,16 @@ namespace OpenSim.Region.CoreModules.World.Land
388 newData.SalePrice = 0; 389 newData.SalePrice = 0;
389 newData.AuthBuyerID = UUID.Zero; 390 newData.AuthBuyerID = UUID.Zero;
390 newData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory); 391 newData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
392
393 bool sellObjects = (LandData.Flags & (uint)(ParcelFlags.SellParcelObjects)) != 0
394 && !LandData.IsGroupOwned && !groupOwned;
395 UUID previousOwner = LandData.OwnerID;
396
391 m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData); 397 m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
392 m_scene.EventManager.TriggerParcelPrimCountUpdate(); 398 m_scene.EventManager.TriggerParcelPrimCountUpdate();
393 SendLandUpdateToAvatarsOverMe(true); 399 SendLandUpdateToAvatarsOverMe(true);
400
401 if (sellObjects) SellLandObjects(previousOwner);
394 } 402 }
395 403
396 public void DeedToGroup(UUID groupID) 404 public void DeedToGroup(UUID groupID)
@@ -421,6 +429,19 @@ namespace OpenSim.Region.CoreModules.World.Land
421 return false; 429 return false;
422 } 430 }
423 431
432 public bool CanBeOnThisLand(UUID avatar, float posHeight)
433 {
434 if (posHeight < LandChannel.BAN_LINE_SAFETY_HIEGHT && IsBannedFromLand(avatar))
435 {
436 return false;
437 }
438 else if (IsRestrictedFromLand(avatar))
439 {
440 return false;
441 }
442 return true;
443 }
444
424 public bool HasGroupAccess(UUID avatar) 445 public bool HasGroupAccess(UUID avatar)
425 { 446 {
426 if (LandData.GroupID != UUID.Zero && (LandData.Flags & (uint)ParcelFlags.UseAccessGroup) == (uint)ParcelFlags.UseAccessGroup) 447 if (LandData.GroupID != UUID.Zero && (LandData.Flags & (uint)ParcelFlags.UseAccessGroup) == (uint)ParcelFlags.UseAccessGroup)
@@ -553,8 +574,8 @@ namespace OpenSim.Region.CoreModules.World.Land
553 try 574 try
554 { 575 {
555 over = 576 over =
556 m_scene.LandChannel.GetLandObject(Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.X), 0, ((int)Constants.RegionSize - 1)), 577 m_scene.LandChannel.GetLandObject(Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.X), 0, ((int)m_scene.RegionInfo.RegionSizeX - 1)),
557 Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.Y), 0, ((int)Constants.RegionSize - 1))); 578 Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.Y), 0, ((int)m_scene.RegionInfo.RegionSizeY - 1)));
558 } 579 }
559 catch (Exception) 580 catch (Exception)
560 { 581 {
@@ -701,15 +722,15 @@ namespace OpenSim.Region.CoreModules.World.Land
701 /// </summary> 722 /// </summary>
702 private void UpdateAABBAndAreaValues() 723 private void UpdateAABBAndAreaValues()
703 { 724 {
704 int min_x = 64; 725 int min_x = 10000;
705 int min_y = 64; 726 int min_y = 10000;
706 int max_x = 0; 727 int max_x = 0;
707 int max_y = 0; 728 int max_y = 0;
708 int tempArea = 0; 729 int tempArea = 0;
709 int x, y; 730 int x, y;
710 for (x = 0; x < 64; x++) 731 for (x = 0; x < LandBitmap.GetLength(0); x++)
711 { 732 {
712 for (y = 0; y < 64; y++) 733 for (y = 0; y < LandBitmap.GetLength(1); y++)
713 { 734 {
714 if (LandBitmap[x, y] == true) 735 if (LandBitmap[x, y] == true)
715 { 736 {
@@ -717,31 +738,31 @@ namespace OpenSim.Region.CoreModules.World.Land
717 if (min_y > y) min_y = y; 738 if (min_y > y) min_y = y;
718 if (max_x < x) max_x = x; 739 if (max_x < x) max_x = x;
719 if (max_y < y) max_y = y; 740 if (max_y < y) max_y = y;
720 tempArea += 16; //16sqm peice of land 741 tempArea += landUnit * landUnit; //16sqm peice of land
721 } 742 }
722 } 743 }
723 } 744 }
724 int tx = min_x * 4; 745 int tx = min_x * landUnit;
725 if (tx > ((int)Constants.RegionSize - 1)) 746 if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1))
726 tx = ((int)Constants.RegionSize - 1); 747 tx = ((int)m_scene.RegionInfo.RegionSizeX - 1);
727 int ty = min_y * 4; 748 int ty = min_y * landUnit;
728 if (ty > ((int)Constants.RegionSize - 1)) 749 if (ty > ((int)m_scene.RegionInfo.RegionSizeY - 1))
729 ty = ((int)Constants.RegionSize - 1); 750 ty = ((int)m_scene.RegionInfo.RegionSizeY - 1);
730 751
731 LandData.AABBMin = 752 LandData.AABBMin =
732 new Vector3( 753 new Vector3(
733 (float)(min_x * 4), (float)(min_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0); 754 (float)(min_x * landUnit), (float)(min_y * landUnit), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0);
734 755
735 tx = max_x * 4; 756 tx = max_x * landUnit;
736 if (tx > ((int)Constants.RegionSize - 1)) 757 if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1))
737 tx = ((int)Constants.RegionSize - 1); 758 tx = ((int)m_scene.RegionInfo.RegionSizeX - 1);
738 ty = max_y * 4; 759 ty = max_y * landUnit;
739 if (ty > ((int)Constants.RegionSize - 1)) 760 if (ty > ((int)m_scene.RegionInfo.RegionSizeY - 1))
740 ty = ((int)Constants.RegionSize - 1); 761 ty = ((int)m_scene.RegionInfo.RegionSizeY - 1);
741 762
742 LandData.AABBMax 763 LandData.AABBMax
743 = new Vector3( 764 = new Vector3(
744 (float)(max_x * 4), (float)(max_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0); 765 (float)(max_x * landUnit), (float)(max_y * landUnit), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0);
745 766
746 LandData.Area = tempArea; 767 LandData.Area = tempArea;
747 } 768 }
@@ -753,20 +774,12 @@ namespace OpenSim.Region.CoreModules.World.Land
753 /// <summary> 774 /// <summary>
754 /// Sets the land's bitmap manually 775 /// Sets the land's bitmap manually
755 /// </summary> 776 /// </summary>
756 /// <param name="bitmap">64x64 block representing where this land is on a map</param> 777 /// <param name="bitmap">block representing where this land is on a map mapped in a 4x4 meter grid</param>
757 public void SetLandBitmap(bool[,] bitmap) 778 public void SetLandBitmap(bool[,] bitmap)
758 { 779 {
759 if (bitmap.GetLength(0) != 64 || bitmap.GetLength(1) != 64 || bitmap.Rank != 2) 780 LandBitmap = bitmap;
760 { 781 // m_log.DebugFormat("{0} SetLandBitmap. BitmapSize=<{1},{2}>", LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1));
761 //Throw an exception - The bitmap is not 64x64 782 ForceUpdateLandInfo();
762 //throw new Exception("Error: Invalid Parcel Bitmap");
763 }
764 else
765 {
766 //Valid: Lets set it
767 LandBitmap = bitmap;
768 ForceUpdateLandInfo();
769 }
770 } 783 }
771 784
772 /// <summary> 785 /// <summary>
@@ -780,15 +793,19 @@ namespace OpenSim.Region.CoreModules.World.Land
780 793
781 public bool[,] BasicFullRegionLandBitmap() 794 public bool[,] BasicFullRegionLandBitmap()
782 { 795 {
783 return GetSquareLandBitmap(0, 0, (int) Constants.RegionSize, (int) Constants.RegionSize); 796 return GetSquareLandBitmap(0, 0, (int)m_scene.RegionInfo.RegionSizeX, (int) m_scene.RegionInfo.RegionSizeY);
784 } 797 }
785 798
786 public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y) 799 public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y)
787 { 800 {
788 bool[,] tempBitmap = new bool[64,64]; 801 // Empty bitmap for the whole region
802 bool[,] tempBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
789 tempBitmap.Initialize(); 803 tempBitmap.Initialize();
790 804
805 // Fill the bitmap square area specified by state and end
791 tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true); 806 tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true);
807 // m_log.DebugFormat("{0} GetSquareLandBitmap. tempBitmapSize=<{1},{2}>",
808 // LogHeader, tempBitmap.GetLength(0), tempBitmap.GetLength(1));
792 return tempBitmap; 809 return tempBitmap;
793 } 810 }
794 811
@@ -805,24 +822,20 @@ namespace OpenSim.Region.CoreModules.World.Land
805 public bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y, 822 public bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y,
806 bool set_value) 823 bool set_value)
807 { 824 {
808 if (land_bitmap.GetLength(0) != 64 || land_bitmap.GetLength(1) != 64 || land_bitmap.Rank != 2)
809 {
810 //Throw an exception - The bitmap is not 64x64
811 //throw new Exception("Error: Invalid Parcel Bitmap in modifyLandBitmapSquare()");
812 }
813
814 int x, y; 825 int x, y;
815 for (y = 0; y < 64; y++) 826 for (y = 0; y < land_bitmap.GetLength(1); y++)
816 { 827 {
817 for (x = 0; x < 64; x++) 828 for (x = 0; x < land_bitmap.GetLength(0); x++)
818 { 829 {
819 if (x >= start_x / 4 && x < end_x / 4 830 if (x >= start_x / landUnit && x < end_x / landUnit
820 && y >= start_y / 4 && y < end_y / 4) 831 && y >= start_y / landUnit && y < end_y / landUnit)
821 { 832 {
822 land_bitmap[x, y] = set_value; 833 land_bitmap[x, y] = set_value;
823 } 834 }
824 } 835 }
825 } 836 }
837 // m_log.DebugFormat("{0} ModifyLandBitmapSquare. startXY=<{1},{2}>, endXY=<{3},{4}>, val={5}, landBitmapSize=<{6},{7}>",
838 // LogHeader, start_x, start_y, end_x, end_y, set_value, land_bitmap.GetLength(0), land_bitmap.GetLength(1));
826 return land_bitmap; 839 return land_bitmap;
827 } 840 }
828 841
@@ -834,21 +847,21 @@ namespace OpenSim.Region.CoreModules.World.Land
834 /// <returns></returns> 847 /// <returns></returns>
835 public bool[,] MergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add) 848 public bool[,] MergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add)
836 { 849 {
837 if (bitmap_base.GetLength(0) != 64 || bitmap_base.GetLength(1) != 64 || bitmap_base.Rank != 2) 850 if (bitmap_base.GetLength(0) != bitmap_add.GetLength(0)
851 || bitmap_base.GetLength(1) != bitmap_add.GetLength(1)
852 || bitmap_add.Rank != 2
853 || bitmap_base.Rank != 2)
838 { 854 {
839 //Throw an exception - The bitmap is not 64x64 855 throw new Exception(
840 throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_base in mergeLandBitmaps"); 856 String.Format("{0} MergeLandBitmaps. merging maps not same size. baseSizeXY=<{1},{2}>, addSizeXY=<{3},{4}>",
841 } 857 LogHeader, bitmap_base.GetLength(0), bitmap_base.GetLength(1), bitmap_add.GetLength(0), bitmap_add.GetLength(1))
842 if (bitmap_add.GetLength(0) != 64 || bitmap_add.GetLength(1) != 64 || bitmap_add.Rank != 2) 858 );
843 {
844 //Throw an exception - The bitmap is not 64x64
845 throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_add in mergeLandBitmaps");
846 } 859 }
847 860
848 int x, y; 861 int x, y;
849 for (y = 0; y < 64; y++) 862 for (y = 0; y < bitmap_base.GetLength(1); y++)
850 { 863 {
851 for (x = 0; x < 64; x++) 864 for (x = 0; x < bitmap_add.GetLength(0); x++)
852 { 865 {
853 if (bitmap_add[x, y]) 866 if (bitmap_add[x, y])
854 { 867 {
@@ -865,13 +878,13 @@ namespace OpenSim.Region.CoreModules.World.Land
865 /// <returns></returns> 878 /// <returns></returns>
866 private byte[] ConvertLandBitmapToBytes() 879 private byte[] ConvertLandBitmapToBytes()
867 { 880 {
868 byte[] tempConvertArr = new byte[512]; 881 byte[] tempConvertArr = new byte[LandBitmap.GetLength(0) * LandBitmap.GetLength(1) / 8];
869 byte tempByte = 0; 882 byte tempByte = 0;
870 int x, y, i, byteNum = 0; 883 int byteNum = 0;
871 i = 0; 884 int i = 0;
872 for (y = 0; y < 64; y++) 885 for (int y = 0; y < LandBitmap.GetLength(1); y++)
873 { 886 {
874 for (x = 0; x < 64; x++) 887 for (int x = 0; x < LandBitmap.GetLength(0); x++)
875 { 888 {
876 tempByte = Convert.ToByte(tempByte | Convert.ToByte(LandBitmap[x, y]) << (i++ % 8)); 889 tempByte = Convert.ToByte(tempByte | Convert.ToByte(LandBitmap[x, y]) << (i++ % 8));
877 if (i % 8 == 0) 890 if (i % 8 == 0)
@@ -883,30 +896,52 @@ namespace OpenSim.Region.CoreModules.World.Land
883 } 896 }
884 } 897 }
885 } 898 }
899 // m_log.DebugFormat("{0} ConvertLandBitmapToBytes. BitmapSize=<{1},{2}>",
900 // LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1));
886 return tempConvertArr; 901 return tempConvertArr;
887 } 902 }
888 903
889 private bool[,] ConvertBytesToLandBitmap() 904 private bool[,] ConvertBytesToLandBitmap()
890 { 905 {
891 bool[,] tempConvertMap = new bool[landArrayMax, landArrayMax]; 906 bool[,] tempConvertMap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
892 tempConvertMap.Initialize(); 907 tempConvertMap.Initialize();
893 byte tempByte = 0; 908 byte tempByte = 0;
894 int x = 0, y = 0, i = 0, bitNum = 0; 909 // Math.Min overcomes an old bug that might have made it into the database. Only use the bytes that fit into convertMap.
895 for (i = 0; i < 512; i++) 910 int bitmapLen = Math.Min(LandData.Bitmap.Length, tempConvertMap.GetLength(0) * tempConvertMap.GetLength(1) / 8);
911 int xLen = (int)(m_scene.RegionInfo.RegionSizeX / landUnit);
912
913 if (bitmapLen == 512)
914 {
915 // Legacy bitmap being passed in. Use the legacy region size
916 // and only set the lower area of the larger region.
917 xLen = (int)(Constants.RegionSize / landUnit);
918 }
919 // m_log.DebugFormat("{0} ConvertBytesToLandBitmap: bitmapLen={1}, xLen={2}", LogHeader, bitmapLen, xLen);
920
921 int x = 0, y = 0;
922 for (int i = 0; i < bitmapLen; i++)
896 { 923 {
897 tempByte = LandData.Bitmap[i]; 924 tempByte = LandData.Bitmap[i];
898 for (bitNum = 0; bitNum < 8; bitNum++) 925 for (int bitNum = 0; bitNum < 8; bitNum++)
899 { 926 {
900 bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1); 927 bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1);
901 tempConvertMap[x, y] = bit; 928 try
929 {
930 tempConvertMap[x, y] = bit;
931 }
932 catch (Exception)
933 {
934 m_log.DebugFormat("{0} ConvertBytestoLandBitmap: i={1}, x={2}, y={3}", LogHeader, i, x, y);
935 }
902 x++; 936 x++;
903 if (x > 63) 937 if (x >= xLen)
904 { 938 {
905 x = 0; 939 x = 0;
906 y++; 940 y++;
907 } 941 }
908 } 942 }
909 } 943 }
944
910 return tempConvertMap; 945 return tempConvertMap;
911 } 946 }
912 947
@@ -1043,6 +1078,43 @@ namespace OpenSim.Region.CoreModules.World.Land
1043 1078
1044 #endregion 1079 #endregion
1045 1080
1081 #region Object Sales
1082
1083 public void SellLandObjects(UUID previousOwner)
1084 {
1085 // m_log.DebugFormat(
1086 // "[LAND OBJECT]: Request to sell objects in {0} from {1}", LandData.Name, previousOwner);
1087
1088 if (LandData.IsGroupOwned)
1089 return;
1090
1091 IBuySellModule m_BuySellModule = m_scene.RequestModuleInterface<IBuySellModule>();
1092 if (m_BuySellModule == null)
1093 {
1094 m_log.Error("[LAND OBJECT]: BuySellModule not found");
1095 return;
1096 }
1097
1098 ScenePresence sp;
1099 if (!m_scene.TryGetScenePresence(LandData.OwnerID, out sp))
1100 {
1101 m_log.Error("[LAND OBJECT]: New owner is not present in scene");
1102 return;
1103 }
1104
1105 lock (primsOverMe)
1106 {
1107 foreach (SceneObjectGroup obj in primsOverMe)
1108 {
1109 if (obj.OwnerID == previousOwner && obj.GroupID == UUID.Zero &&
1110 (obj.GetEffectivePermissions() & (uint)(OpenSim.Framework.PermissionMask.Transfer)) != 0)
1111 m_BuySellModule.BuyObject(sp.ControllingClient, UUID.Zero, obj.LocalId, 1, 0);
1112 }
1113 }
1114 }
1115
1116 #endregion
1117
1046 #region Object Returning 1118 #region Object Returning
1047 1119
1048 public void ReturnObject(SceneObjectGroup obj) 1120 public void ReturnObject(SceneObjectGroup obj)
@@ -1065,7 +1137,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1065 { 1137 {
1066 foreach (SceneObjectGroup obj in primsOverMe) 1138 foreach (SceneObjectGroup obj in primsOverMe)
1067 { 1139 {
1068 if (obj.OwnerID == m_landData.OwnerID) 1140 if (obj.OwnerID == LandData.OwnerID)
1069 { 1141 {
1070 if (!returns.ContainsKey(obj.OwnerID)) 1142 if (!returns.ContainsKey(obj.OwnerID))
1071 returns[obj.OwnerID] = 1143 returns[obj.OwnerID] =
@@ -1074,11 +1146,11 @@ namespace OpenSim.Region.CoreModules.World.Land
1074 } 1146 }
1075 } 1147 }
1076 } 1148 }
1077 else if (type == (uint)ObjectReturnType.Group && m_landData.GroupID != UUID.Zero) 1149 else if (type == (uint)ObjectReturnType.Group && LandData.GroupID != UUID.Zero)
1078 { 1150 {
1079 foreach (SceneObjectGroup obj in primsOverMe) 1151 foreach (SceneObjectGroup obj in primsOverMe)
1080 { 1152 {
1081 if (obj.GroupID == m_landData.GroupID) 1153 if (obj.GroupID == LandData.GroupID)
1082 { 1154 {
1083 if (!returns.ContainsKey(obj.OwnerID)) 1155 if (!returns.ContainsKey(obj.OwnerID))
1084 returns[obj.OwnerID] = 1156 returns[obj.OwnerID] =
@@ -1091,9 +1163,9 @@ namespace OpenSim.Region.CoreModules.World.Land
1091 { 1163 {
1092 foreach (SceneObjectGroup obj in primsOverMe) 1164 foreach (SceneObjectGroup obj in primsOverMe)
1093 { 1165 {
1094 if (obj.OwnerID != m_landData.OwnerID && 1166 if (obj.OwnerID != LandData.OwnerID &&
1095 (obj.GroupID != m_landData.GroupID || 1167 (obj.GroupID != LandData.GroupID ||
1096 m_landData.GroupID == UUID.Zero)) 1168 LandData.GroupID == UUID.Zero))
1097 { 1169 {
1098 if (!returns.ContainsKey(obj.OwnerID)) 1170 if (!returns.ContainsKey(obj.OwnerID))
1099 returns[obj.OwnerID] = 1171 returns[obj.OwnerID] =
diff --git a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs
index f9cc0cf..9b51cc8 100644
--- a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs
+++ b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs
@@ -490,11 +490,14 @@ namespace OpenSim.Region.CoreModules.World.Land
490 490
491 m_Scene.ForEachSOG(AddObject); 491 m_Scene.ForEachSOG(AddObject);
492 492
493 List<UUID> primcountKeys = new List<UUID>(m_PrimCounts.Keys); 493 lock (m_PrimCounts)
494 foreach (UUID k in primcountKeys)
495 { 494 {
496 if (!m_OwnerMap.ContainsKey(k)) 495 List<UUID> primcountKeys = new List<UUID>(m_PrimCounts.Keys);
497 m_PrimCounts.Remove(k); 496 foreach (UUID k in primcountKeys)
497 {
498 if (!m_OwnerMap.ContainsKey(k))
499 m_PrimCounts.Remove(k);
500 }
498 } 501 }
499 502
500 m_Tainted = false; 503 m_Tainted = false;
diff --git a/OpenSim/Region/CoreModules/World/Land/Tests/LandManagementModuleTests.cs b/OpenSim/Region/CoreModules/World/Land/Tests/LandManagementModuleTests.cs
new file mode 100644
index 0000000..4ed67f3
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Land/Tests/LandManagementModuleTests.cs
@@ -0,0 +1,266 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using NUnit.Framework;
30using OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Region.Framework.Scenes;
33using OpenSim.Tests.Common;
34
35namespace OpenSim.Region.CoreModules.World.Land.Tests
36{
37 public class LandManagementModuleTests : OpenSimTestCase
38 {
39 [Test]
40 public void TestAddLandObject()
41 {
42 TestHelpers.InMethod();
43// TestHelpers.EnableLogging();
44
45 UUID userId = TestHelpers.ParseTail(0x1);
46
47 LandManagementModule lmm = new LandManagementModule();
48 Scene scene = new SceneHelpers().SetupScene();
49 SceneHelpers.SetupSceneModules(scene, lmm);
50
51 ILandObject lo = new LandObject(userId, false, scene);
52 lo.LandData.Name = "lo1";
53 lo.SetLandBitmap(
54 lo.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize));
55 lo = lmm.AddLandObject(lo);
56
57 // TODO: Should add asserts to check that land object was added properly.
58
59 // At the moment, this test just makes sure that we can't add a land object that overlaps the areas that
60 // the first still holds.
61 ILandObject lo2 = new LandObject(userId, false, scene);
62 lo2.SetLandBitmap(
63 lo2.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize));
64 lo2.LandData.Name = "lo2";
65 lo2 = lmm.AddLandObject(lo2);
66
67 {
68 ILandObject loAtCoord = lmm.GetLandObject(0, 0);
69 Assert.That(loAtCoord.LandData.LocalID, Is.EqualTo(lo.LandData.LocalID));
70 Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(lo.LandData.GlobalID));
71 }
72
73 {
74 ILandObject loAtCoord = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1));
75 Assert.That(loAtCoord.LandData.LocalID, Is.EqualTo(lo.LandData.LocalID));
76 Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(lo.LandData.GlobalID));
77 }
78 }
79
80 /// <summary>
81 /// Test parcels on region when no land data exists to be loaded.
82 /// </summary>
83 [Test]
84 public void TestLoadWithNoParcels()
85 {
86 TestHelpers.InMethod();
87// TestHelpers.EnableLogging();
88
89 SceneHelpers sh = new SceneHelpers();
90 LandManagementModule lmm = new LandManagementModule();
91 Scene scene = sh.SetupScene();
92 SceneHelpers.SetupSceneModules(scene, lmm);
93
94 scene.loadAllLandObjectsFromStorage(scene.RegionInfo.RegionID);
95
96 ILandObject loAtCoord1 = lmm.GetLandObject(0, 0);
97 Assert.That(loAtCoord1.LandData.LocalID, Is.Not.EqualTo(0));
98 Assert.That(loAtCoord1.LandData.GlobalID, Is.Not.EqualTo(UUID.Zero));
99
100 ILandObject loAtCoord2 = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1));
101 Assert.That(loAtCoord2.LandData.LocalID, Is.EqualTo(loAtCoord1.LandData.LocalID));
102 Assert.That(loAtCoord2.LandData.GlobalID, Is.EqualTo(loAtCoord1.LandData.GlobalID));
103 }
104
105 /// <summary>
106 /// Test parcels on region when a single parcel already exists but it does not cover the whole region.
107 /// </summary>
108 [Test]
109 public void TestLoadWithSinglePartialCoveringParcel()
110 {
111 TestHelpers.InMethod();
112// TestHelpers.EnableLogging();
113
114 UUID userId = TestHelpers.ParseTail(0x1);
115
116 SceneHelpers sh = new SceneHelpers();
117 LandManagementModule lmm = new LandManagementModule();
118 Scene scene = sh.SetupScene();
119 SceneHelpers.SetupSceneModules(scene, lmm);
120
121 ILandObject originalLo1 = new LandObject(userId, false, scene);
122 originalLo1.LandData.Name = "lo1";
123 originalLo1.SetLandBitmap(
124 originalLo1.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize / 2));
125
126 sh.SimDataService.StoreLandObject(originalLo1);
127
128 scene.loadAllLandObjectsFromStorage(scene.RegionInfo.RegionID);
129
130 ILandObject loAtCoord1 = lmm.GetLandObject(0, 0);
131 Assert.That(loAtCoord1.LandData.Name, Is.EqualTo(originalLo1.LandData.Name));
132 Assert.That(loAtCoord1.LandData.GlobalID, Is.EqualTo(originalLo1.LandData.GlobalID));
133
134 ILandObject loAtCoord2 = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1));
135 Assert.That(loAtCoord2.LandData.LocalID, Is.EqualTo(loAtCoord1.LandData.LocalID));
136 Assert.That(loAtCoord2.LandData.GlobalID, Is.EqualTo(loAtCoord1.LandData.GlobalID));
137 }
138
139 /// <summary>
140 /// Test parcels on region when a single parcel already exists but it does not cover the whole region.
141 /// </summary>
142 [Test]
143 public void TestLoadWithMultiplePartialCoveringParcels()
144 {
145 TestHelpers.InMethod();
146// TestHelpers.EnableLogging();
147
148 UUID userId = TestHelpers.ParseTail(0x1);
149
150 SceneHelpers sh = new SceneHelpers();
151 LandManagementModule lmm = new LandManagementModule();
152 Scene scene = sh.SetupScene();
153 SceneHelpers.SetupSceneModules(scene, lmm);
154
155 ILandObject originalLo1 = new LandObject(userId, false, scene);
156 originalLo1.LandData.Name = "lo1";
157 originalLo1.SetLandBitmap(
158 originalLo1.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize / 2));
159
160 sh.SimDataService.StoreLandObject(originalLo1);
161
162 ILandObject originalLo2 = new LandObject(userId, false, scene);
163 originalLo2.LandData.Name = "lo2";
164 originalLo2.SetLandBitmap(
165 originalLo2.GetSquareLandBitmap(
166 0, (int)Constants.RegionSize / 2, (int)Constants.RegionSize, ((int)Constants.RegionSize / 4) * 3));
167
168 sh.SimDataService.StoreLandObject(originalLo2);
169
170 scene.loadAllLandObjectsFromStorage(scene.RegionInfo.RegionID);
171
172 ILandObject loAtCoord1 = lmm.GetLandObject(0, 0);
173 Assert.That(loAtCoord1.LandData.Name, Is.EqualTo(originalLo1.LandData.Name));
174 Assert.That(loAtCoord1.LandData.GlobalID, Is.EqualTo(originalLo1.LandData.GlobalID));
175
176 ILandObject loAtCoord2
177 = lmm.GetLandObject((int)Constants.RegionSize - 1, (((int)Constants.RegionSize / 4) * 3) - 1);
178 Assert.That(loAtCoord2.LandData.Name, Is.EqualTo(originalLo2.LandData.Name));
179 Assert.That(loAtCoord2.LandData.GlobalID, Is.EqualTo(originalLo2.LandData.GlobalID));
180
181 ILandObject loAtCoord3 = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1));
182 Assert.That(loAtCoord3.LandData.LocalID, Is.Not.EqualTo(loAtCoord1.LandData.LocalID));
183 Assert.That(loAtCoord3.LandData.LocalID, Is.Not.EqualTo(loAtCoord2.LandData.LocalID));
184 Assert.That(loAtCoord3.LandData.GlobalID, Is.Not.EqualTo(loAtCoord1.LandData.GlobalID));
185 Assert.That(loAtCoord3.LandData.GlobalID, Is.Not.EqualTo(loAtCoord2.LandData.GlobalID));
186 }
187
188 /// <summary>
189 /// Test parcels on region when whole region is parcelled (which should normally always be the case).
190 /// </summary>
191 [Test]
192 public void TestLoad()
193 {
194 TestHelpers.InMethod();
195// TestHelpers.EnableLogging();
196
197 UUID userId = TestHelpers.ParseTail(0x1);
198
199 SceneHelpers sh = new SceneHelpers();
200 LandManagementModule lmm = new LandManagementModule();
201 Scene scene = sh.SetupScene();
202 SceneHelpers.SetupSceneModules(scene, lmm);
203
204 ILandObject originalLo1 = new LandObject(userId, false, scene);
205 originalLo1.LandData.Name = "lo1";
206 originalLo1.SetLandBitmap(
207 originalLo1.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize / 2));
208
209 sh.SimDataService.StoreLandObject(originalLo1);
210
211 ILandObject originalLo2 = new LandObject(userId, false, scene);
212 originalLo2.LandData.Name = "lo2";
213 originalLo2.SetLandBitmap(
214 originalLo2.GetSquareLandBitmap(0, (int)Constants.RegionSize / 2, (int)Constants.RegionSize, (int)Constants.RegionSize));
215
216 sh.SimDataService.StoreLandObject(originalLo2);
217
218 scene.loadAllLandObjectsFromStorage(scene.RegionInfo.RegionID);
219
220 {
221 ILandObject loAtCoord = lmm.GetLandObject(0, 0);
222 Assert.That(loAtCoord.LandData.Name, Is.EqualTo(originalLo1.LandData.Name));
223 Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(originalLo1.LandData.GlobalID));
224 }
225
226 {
227 ILandObject loAtCoord = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1));
228 Assert.That(loAtCoord.LandData.Name, Is.EqualTo(originalLo2.LandData.Name));
229 Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(originalLo2.LandData.GlobalID));
230 }
231 }
232
233 [Test]
234 public void TestSubdivide()
235 {
236 TestHelpers.InMethod();
237// TestHelpers.EnableLogging();
238
239 UUID userId = TestHelpers.ParseTail(0x1);
240
241 LandManagementModule lmm = new LandManagementModule();
242 Scene scene = new SceneHelpers().SetupScene();
243 SceneHelpers.SetupSceneModules(scene, lmm);
244
245 ILandObject lo = new LandObject(userId, false, scene);
246 lo.LandData.Name = "lo1";
247 lo.SetLandBitmap(
248 lo.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize));
249 lo = lmm.AddLandObject(lo);
250
251 lmm.Subdivide(0, 0, LandManagementModule.LandUnit, LandManagementModule.LandUnit, userId);
252
253 {
254 ILandObject loAtCoord = lmm.GetLandObject(0, 0);
255 Assert.That(loAtCoord.LandData.LocalID, Is.Not.EqualTo(lo.LandData.LocalID));
256 Assert.That(loAtCoord.LandData.GlobalID, Is.Not.EqualTo(lo.LandData.GlobalID));
257 }
258
259 {
260 ILandObject loAtCoord = lmm.GetLandObject(LandManagementModule.LandUnit, LandManagementModule.LandUnit);
261 Assert.That(loAtCoord.LandData.LocalID, Is.EqualTo(lo.LandData.LocalID));
262 Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(lo.LandData.GlobalID));
263 }
264 }
265 }
266} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs b/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs
index 0945b43..949acb6 100644
--- a/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs
+++ b/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs
@@ -36,7 +36,6 @@ using OpenSim.Framework;
36using OpenSim.Region.Framework.Interfaces; 36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes; 37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Tests.Common; 38using OpenSim.Tests.Common;
39using OpenSim.Tests.Common.Mock;
40 39
41namespace OpenSim.Region.CoreModules.World.Land.Tests 40namespace OpenSim.Region.CoreModules.World.Land.Tests
42{ 41{
diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs
index 8a422b0..796a15f 100644
--- a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs
+++ b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs
@@ -55,7 +55,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
55 public struct DrawStruct 55 public struct DrawStruct
56 { 56 {
57 public DrawRoutine dr; 57 public DrawRoutine dr;
58 public Rectangle rect; 58// public Rectangle rect;
59 public SolidBrush brush; 59 public SolidBrush brush;
60 public face[] trns; 60 public face[] trns;
61 } 61 }
@@ -77,40 +77,71 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
77 { 77 {
78 bool drawPrimVolume = true; 78 bool drawPrimVolume = true;
79 bool textureTerrain = false; 79 bool textureTerrain = false;
80 bool generateMaptiles = true;
81 Bitmap mapbmp;
80 82
81 try 83 string[] configSections = new string[] { "Map", "Startup" };
82 {
83 IConfig startupConfig = m_config.Configs["Startup"];
84 drawPrimVolume = startupConfig.GetBoolean("DrawPrimOnMapTile", drawPrimVolume);
85 textureTerrain = startupConfig.GetBoolean("TextureOnMapTile", textureTerrain);
86 }
87 catch
88 {
89 m_log.Warn("[MAPTILE]: Failed to load StartupConfig");
90 }
91 84
92 if (textureTerrain) 85 drawPrimVolume
93 { 86 = Util.GetConfigVarFromSections<bool>(m_config, "DrawPrimOnMapTile", configSections, drawPrimVolume);
94 terrainRenderer = new TexturedMapTileRenderer(); 87 textureTerrain
95 } 88 = Util.GetConfigVarFromSections<bool>(m_config, "TextureOnMapTile", configSections, textureTerrain);
96 else 89 generateMaptiles
90 = Util.GetConfigVarFromSections<bool>(m_config, "GenerateMaptiles", configSections, generateMaptiles);
91
92 if (generateMaptiles)
97 { 93 {
98 terrainRenderer = new ShadedMapTileRenderer(); 94 if (String.IsNullOrEmpty(m_scene.RegionInfo.MaptileStaticFile))
99 } 95 {
100 terrainRenderer.Initialise(m_scene, m_config); 96 if (textureTerrain)
97 {
98 terrainRenderer = new TexturedMapTileRenderer();
99 }
100 else
101 {
102 terrainRenderer = new ShadedMapTileRenderer();
103 }
104
105 terrainRenderer.Initialise(m_scene, m_config);
101 106
102 Bitmap mapbmp = new Bitmap((int)Constants.RegionSize, (int)Constants.RegionSize, System.Drawing.Imaging.PixelFormat.Format24bppRgb); 107 mapbmp = new Bitmap((int)m_scene.Heightmap.Width, (int)m_scene.Heightmap.Height,
103 //long t = System.Environment.TickCount; 108 System.Drawing.Imaging.PixelFormat.Format24bppRgb);
104 //for (int i = 0; i < 10; ++i) { 109 //long t = System.Environment.TickCount;
105 terrainRenderer.TerrainToBitmap(mapbmp); 110 //for (int i = 0; i < 10; ++i) {
106 //} 111 terrainRenderer.TerrainToBitmap(mapbmp);
107 //t = System.Environment.TickCount - t; 112 //}
108 //m_log.InfoFormat("[MAPTILE] generation of 10 maptiles needed {0} ms", t); 113 //t = System.Environment.TickCount - t;
114 //m_log.InfoFormat("[MAPTILE] generation of 10 maptiles needed {0} ms", t);
109 115
116 if (drawPrimVolume)
117 {
118 DrawObjectVolume(m_scene, mapbmp);
119 }
120 }
121 else
122 {
123 try
124 {
125 mapbmp = new Bitmap(m_scene.RegionInfo.MaptileStaticFile);
126 }
127 catch (Exception)
128 {
129 m_log.ErrorFormat(
130 "[MAPTILE]: Failed to load Static map image texture file: {0} for {1}",
131 m_scene.RegionInfo.MaptileStaticFile, m_scene.Name);
132 //mapbmp = new Bitmap((int)m_scene.Heightmap.Width, (int)m_scene.Heightmap.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
133 mapbmp = null;
134 }
110 135
111 if (drawPrimVolume) 136 if (mapbmp != null)
137 m_log.DebugFormat(
138 "[MAPTILE]: Static map image texture file {0} found for {1}",
139 m_scene.RegionInfo.MaptileStaticFile, m_scene.Name);
140 }
141 }
142 else
112 { 143 {
113 DrawObjectVolume(m_scene, mapbmp); 144 mapbmp = FetchTexture(m_scene.RegionInfo.RegionSettings.TerrainImageID);
114 } 145 }
115 146
116 return mapbmp; 147 return mapbmp;
@@ -121,7 +152,10 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
121 try 152 try
122 { 153 {
123 using (Bitmap mapbmp = CreateMapTile()) 154 using (Bitmap mapbmp = CreateMapTile())
124 return OpenJPEG.EncodeFromImage(mapbmp, true); 155 {
156 if (mapbmp != null)
157 return OpenJPEG.EncodeFromImage(mapbmp, true);
158 }
125 } 159 }
126 catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke 160 catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke
127 { 161 {
@@ -139,9 +173,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
139 { 173 {
140 m_config = source; 174 m_config = source;
141 175
142 IConfig startupConfig = m_config.Configs["Startup"]; 176 if (Util.GetConfigVarFromSections<string>(
143 if (startupConfig.GetString("MapImageModule", "MapImageModule") != 177 m_config, "MapImageModule", new string[] { "Startup", "Map" }, "MapImageModule") != "MapImageModule")
144 "MapImageModule")
145 return; 178 return;
146 179
147 m_Enabled = true; 180 m_Enabled = true;
@@ -222,342 +255,395 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
222// } 255// }
223// } 256// }
224 257
258 private Bitmap FetchTexture(UUID id)
259 {
260 AssetBase asset = m_scene.AssetService.Get(id.ToString());
261
262 if (asset != null)
263 {
264 m_log.DebugFormat("[MAPTILE]: Static map image texture {0} found for {1}", id, m_scene.Name);
265 }
266 else
267 {
268 m_log.WarnFormat("[MAPTILE]: Static map image texture {0} not found for {1}", id, m_scene.Name);
269 return null;
270 }
271
272 ManagedImage managedImage;
273 Image image;
274
275 try
276 {
277 if (OpenJPEG.DecodeToImage(asset.Data, out managedImage, out image))
278 return new Bitmap(image);
279 else
280 return null;
281 }
282 catch (DllNotFoundException)
283 {
284 m_log.ErrorFormat("[MAPTILE]: OpenJpeg is not installed correctly on this system. Asset Data is empty for {0}", id);
285
286 }
287 catch (IndexOutOfRangeException)
288 {
289 m_log.ErrorFormat("[MAPTILE]: OpenJpeg was unable to decode this. Asset Data is empty for {0}", id);
290
291 }
292 catch (Exception)
293 {
294 m_log.ErrorFormat("[MAPTILE]: OpenJpeg was unable to decode this. Asset Data is empty for {0}", id);
295
296 }
297 return null;
298
299 }
300
225 private Bitmap DrawObjectVolume(Scene whichScene, Bitmap mapbmp) 301 private Bitmap DrawObjectVolume(Scene whichScene, Bitmap mapbmp)
226 { 302 {
227 int tc = 0; 303 int tc = 0;
228 double[,] hm = whichScene.Heightmap.GetDoubles(); 304 ITerrainChannel hm = whichScene.Heightmap;
229 tc = Environment.TickCount; 305 tc = Environment.TickCount;
230 m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile"); 306 m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile");
231 EntityBase[] objs = whichScene.GetEntities(); 307 EntityBase[] objs = whichScene.GetEntities();
232 Dictionary<uint, DrawStruct> z_sort = new Dictionary<uint, DrawStruct>();
233 //SortedList<float, RectangleDrawStruct> z_sort = new SortedList<float, RectangleDrawStruct>();
234 List<float> z_sortheights = new List<float>(); 308 List<float> z_sortheights = new List<float>();
235 List<uint> z_localIDs = new List<uint>(); 309 List<uint> z_localIDs = new List<uint>();
310 Dictionary<uint, DrawStruct> z_sort = new Dictionary<uint, DrawStruct>();
236 311
237 lock (objs) 312 try
238 { 313 {
239 foreach (EntityBase obj in objs) 314 lock (objs)
240 { 315 {
241 // Only draw the contents of SceneObjectGroup 316 foreach (EntityBase obj in objs)
242 if (obj is SceneObjectGroup)
243 { 317 {
244 SceneObjectGroup mapdot = (SceneObjectGroup)obj; 318 // Only draw the contents of SceneObjectGroup
245 Color mapdotspot = Color.Gray; // Default color when prim color is white 319 if (obj is SceneObjectGroup)
246
247 // Loop over prim in group
248 foreach (SceneObjectPart part in mapdot.Parts)
249 { 320 {
250 if (part == null) 321 SceneObjectGroup mapdot = (SceneObjectGroup)obj;
251 continue; 322 Color mapdotspot = Color.Gray; // Default color when prim color is white
252 323 // Loop over prim in group
253 // Draw if the object is at least 1 meter wide in any direction 324 foreach (SceneObjectPart part in mapdot.Parts)
254 if (part.Scale.X > 1f || part.Scale.Y > 1f || part.Scale.Z > 1f)
255 { 325 {
256 // Try to get the RGBA of the default texture entry.. 326 if (part == null)
257 // 327 continue;
258 try 328
329 // Draw if the object is at least 1 meter wide in any direction
330 if (part.Scale.X > 1f || part.Scale.Y > 1f || part.Scale.Z > 1f)
259 { 331 {
260 // get the null checks out of the way 332 // Try to get the RGBA of the default texture entry..
261 // skip the ones that break 333 //
262 if (part == null) 334 try
263 continue; 335 {
336 // get the null checks out of the way
337 // skip the ones that break
338 if (part == null)
339 continue;
264 340
265 if (part.Shape == null) 341 if (part.Shape == null)
266 continue; 342 continue;
267 343
268 if (part.Shape.PCode == (byte)PCode.Tree || part.Shape.PCode == (byte)PCode.NewTree || part.Shape.PCode == (byte)PCode.Grass) 344 if (part.Shape.PCode == (byte)PCode.Tree || part.Shape.PCode == (byte)PCode.NewTree || part.Shape.PCode == (byte)PCode.Grass)
269 continue; // eliminates trees from this since we don't really have a good tree representation 345 continue; // eliminates trees from this since we don't really have a good tree representation
270 // if you want tree blocks on the map comment the above line and uncomment the below line 346 // if you want tree blocks on the map comment the above line and uncomment the below line
271 //mapdotspot = Color.PaleGreen; 347 //mapdotspot = Color.PaleGreen;
272 348
273 Primitive.TextureEntry textureEntry = part.Shape.Textures; 349 Primitive.TextureEntry textureEntry = part.Shape.Textures;
274 350
275 if (textureEntry == null || textureEntry.DefaultTexture == null) 351 if (textureEntry == null || textureEntry.DefaultTexture == null)
276 continue; 352 continue;
277 353
278 Color4 texcolor = textureEntry.DefaultTexture.RGBA; 354 Color4 texcolor = textureEntry.DefaultTexture.RGBA;
279 355
280 // Not sure why some of these are null, oh well. 356 // Not sure why some of these are null, oh well.
281 357
282 int colorr = 255 - (int)(texcolor.R * 255f); 358 int colorr = 255 - (int)(texcolor.R * 255f);
283 int colorg = 255 - (int)(texcolor.G * 255f); 359 int colorg = 255 - (int)(texcolor.G * 255f);
284 int colorb = 255 - (int)(texcolor.B * 255f); 360 int colorb = 255 - (int)(texcolor.B * 255f);
285 361
286 if (!(colorr == 255 && colorg == 255 && colorb == 255)) 362 if (!(colorr == 255 && colorg == 255 && colorb == 255))
287 {
288 //Try to set the map spot color
289 try
290 {
291 // If the color gets goofy somehow, skip it *shakes fist at Color4
292 mapdotspot = Color.FromArgb(colorr, colorg, colorb);
293 }
294 catch (ArgumentException)
295 { 363 {
364 //Try to set the map spot color
365 try
366 {
367 // If the color gets goofy somehow, skip it *shakes fist at Color4
368 mapdotspot = Color.FromArgb(colorr, colorg, colorb);
369 }
370 catch (ArgumentException)
371 {
372 }
296 } 373 }
297 } 374 }
298 } 375 catch (IndexOutOfRangeException)
299 catch (IndexOutOfRangeException) 376 {
300 { 377 // Windows Array
301 // Windows Array 378 }
302 } 379 catch (ArgumentOutOfRangeException)
303 catch (ArgumentOutOfRangeException) 380 {
304 { 381 // Mono Array
305 // Mono Array 382 }
306 }
307
308 Vector3 pos = part.GetWorldPosition();
309
310 // skip prim outside of retion
311 if (pos.X < 0f || pos.X > 256f || pos.Y < 0f || pos.Y > 256f)
312 continue;
313
314 // skip prim in non-finite position
315 if (Single.IsNaN(pos.X) || Single.IsNaN(pos.Y) ||
316 Single.IsInfinity(pos.X) || Single.IsInfinity(pos.Y))
317 continue;
318
319 // Figure out if object is under 256m above the height of the terrain
320 bool isBelow256AboveTerrain = false;
321 383
322 try 384 Vector3 pos = part.GetWorldPosition();
323 {
324 isBelow256AboveTerrain = (pos.Z < ((float)hm[(int)pos.X, (int)pos.Y] + 256f));
325 }
326 catch (Exception)
327 {
328 }
329 385
330 if (isBelow256AboveTerrain) 386 // skip prim outside of retion
331 { 387 if (!m_scene.PositionIsInCurrentRegion(pos))
332 // Translate scale by rotation so scale is represented properly when object is rotated
333 Vector3 lscale = new Vector3(part.Shape.Scale.X, part.Shape.Scale.Y, part.Shape.Scale.Z);
334 Vector3 scale = new Vector3();
335 Vector3 tScale = new Vector3();
336 Vector3 axPos = new Vector3(pos.X,pos.Y,pos.Z);
337
338 Quaternion llrot = part.GetWorldRotation();
339 Quaternion rot = new Quaternion(llrot.W, llrot.X, llrot.Y, llrot.Z);
340 scale = lscale * rot;
341
342 // negative scales don't work in this situation
343 scale.X = Math.Abs(scale.X);
344 scale.Y = Math.Abs(scale.Y);
345 scale.Z = Math.Abs(scale.Z);
346
347 // This scaling isn't very accurate and doesn't take into account the face rotation :P
348 int mapdrawstartX = (int)(pos.X - scale.X);
349 int mapdrawstartY = (int)(pos.Y - scale.Y);
350 int mapdrawendX = (int)(pos.X + scale.X);
351 int mapdrawendY = (int)(pos.Y + scale.Y);
352
353 // If object is beyond the edge of the map, don't draw it to avoid errors
354 if (mapdrawstartX < 0 || mapdrawstartX > ((int)Constants.RegionSize - 1) || mapdrawendX < 0 || mapdrawendX > ((int)Constants.RegionSize - 1)
355 || mapdrawstartY < 0 || mapdrawstartY > ((int)Constants.RegionSize - 1) || mapdrawendY < 0
356 || mapdrawendY > ((int)Constants.RegionSize - 1))
357 continue; 388 continue;
358 389
359#region obb face reconstruction part duex 390 // skip prim in non-finite position
360 Vector3[] vertexes = new Vector3[8]; 391 if (Single.IsNaN(pos.X) || Single.IsNaN(pos.Y) ||
361 392 Single.IsInfinity(pos.X) || Single.IsInfinity(pos.Y))
362 // float[] distance = new float[6]; 393 continue;
363 Vector3[] FaceA = new Vector3[6]; // vertex A for Facei
364 Vector3[] FaceB = new Vector3[6]; // vertex B for Facei
365 Vector3[] FaceC = new Vector3[6]; // vertex C for Facei
366 Vector3[] FaceD = new Vector3[6]; // vertex D for Facei
367
368 tScale = new Vector3(lscale.X, -lscale.Y, lscale.Z);
369 scale = ((tScale * rot));
370 vertexes[0] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
371 // vertexes[0].x = pos.X + vertexes[0].x;
372 //vertexes[0].y = pos.Y + vertexes[0].y;
373 //vertexes[0].z = pos.Z + vertexes[0].z;
374
375 FaceA[0] = vertexes[0];
376 FaceB[3] = vertexes[0];
377 FaceA[4] = vertexes[0];
378
379 tScale = lscale;
380 scale = ((tScale * rot));
381 vertexes[1] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
382
383 // vertexes[1].x = pos.X + vertexes[1].x;
384 // vertexes[1].y = pos.Y + vertexes[1].y;
385 //vertexes[1].z = pos.Z + vertexes[1].z;
386
387 FaceB[0] = vertexes[1];
388 FaceA[1] = vertexes[1];
389 FaceC[4] = vertexes[1];
390
391 tScale = new Vector3(lscale.X, -lscale.Y, -lscale.Z);
392 scale = ((tScale * rot));
393
394 vertexes[2] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
395
396 //vertexes[2].x = pos.X + vertexes[2].x;
397 //vertexes[2].y = pos.Y + vertexes[2].y;
398 //vertexes[2].z = pos.Z + vertexes[2].z;
399
400 FaceC[0] = vertexes[2];
401 FaceD[3] = vertexes[2];
402 FaceC[5] = vertexes[2];
403
404 tScale = new Vector3(lscale.X, lscale.Y, -lscale.Z);
405 scale = ((tScale * rot));
406 vertexes[3] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
407
408 //vertexes[3].x = pos.X + vertexes[3].x;
409 // vertexes[3].y = pos.Y + vertexes[3].y;
410 // vertexes[3].z = pos.Z + vertexes[3].z;
411
412 FaceD[0] = vertexes[3];
413 FaceC[1] = vertexes[3];
414 FaceA[5] = vertexes[3];
415
416 tScale = new Vector3(-lscale.X, lscale.Y, lscale.Z);
417 scale = ((tScale * rot));
418 vertexes[4] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
419
420 // vertexes[4].x = pos.X + vertexes[4].x;
421 // vertexes[4].y = pos.Y + vertexes[4].y;
422 // vertexes[4].z = pos.Z + vertexes[4].z;
423
424 FaceB[1] = vertexes[4];
425 FaceA[2] = vertexes[4];
426 FaceD[4] = vertexes[4];
427
428 tScale = new Vector3(-lscale.X, lscale.Y, -lscale.Z);
429 scale = ((tScale * rot));
430 vertexes[5] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
431
432 // vertexes[5].x = pos.X + vertexes[5].x;
433 // vertexes[5].y = pos.Y + vertexes[5].y;
434 // vertexes[5].z = pos.Z + vertexes[5].z;
435
436 FaceD[1] = vertexes[5];
437 FaceC[2] = vertexes[5];
438 FaceB[5] = vertexes[5];
439
440 tScale = new Vector3(-lscale.X, -lscale.Y, lscale.Z);
441 scale = ((tScale * rot));
442 vertexes[6] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
443 394
444 // vertexes[6].x = pos.X + vertexes[6].x; 395 // Figure out if object is under 256m above the height of the terrain
445 // vertexes[6].y = pos.Y + vertexes[6].y; 396 bool isBelow256AboveTerrain = false;
446 // vertexes[6].z = pos.Z + vertexes[6].z;
447 397
448 FaceB[2] = vertexes[6]; 398 try
449 FaceA[3] = vertexes[6]; 399 {
450 FaceB[4] = vertexes[6]; 400 isBelow256AboveTerrain = (pos.Z < ((float)hm[(int)pos.X, (int)pos.Y] + 256f));
401 }
402 catch (Exception)
403 {
404 }
451 405
452 tScale = new Vector3(-lscale.X, -lscale.Y, -lscale.Z); 406 if (isBelow256AboveTerrain)
453 scale = ((tScale * rot)); 407 {
454 vertexes[7] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z))); 408 // Translate scale by rotation so scale is represented properly when object is rotated
409 Vector3 lscale = new Vector3(part.Shape.Scale.X, part.Shape.Scale.Y, part.Shape.Scale.Z);
410 Vector3 scale = new Vector3();
411 Vector3 tScale = new Vector3();
412 Vector3 axPos = new Vector3(pos.X, pos.Y, pos.Z);
413
414 Quaternion llrot = part.GetWorldRotation();
415 Quaternion rot = new Quaternion(llrot.W, llrot.X, llrot.Y, llrot.Z);
416 scale = lscale * rot;
417
418 // negative scales don't work in this situation
419 scale.X = Math.Abs(scale.X);
420 scale.Y = Math.Abs(scale.Y);
421 scale.Z = Math.Abs(scale.Z);
422
423 // This scaling isn't very accurate and doesn't take into account the face rotation :P
424 int mapdrawstartX = (int)(pos.X - scale.X);
425 int mapdrawstartY = (int)(pos.Y - scale.Y);
426 int mapdrawendX = (int)(pos.X + scale.X);
427 int mapdrawendY = (int)(pos.Y + scale.Y);
428
429 // If object is beyond the edge of the map, don't draw it to avoid errors
430 if (mapdrawstartX < 0
431 || mapdrawstartX > (hm.Width - 1)
432 || mapdrawendX < 0
433 || mapdrawendX > (hm.Width - 1)
434 || mapdrawstartY < 0
435 || mapdrawstartY > (hm.Height - 1)
436 || mapdrawendY < 0
437 || mapdrawendY > (hm.Height - 1))
438 continue;
439
440 #region obb face reconstruction part duex
441 Vector3[] vertexes = new Vector3[8];
442
443 // float[] distance = new float[6];
444 Vector3[] FaceA = new Vector3[6]; // vertex A for Facei
445 Vector3[] FaceB = new Vector3[6]; // vertex B for Facei
446 Vector3[] FaceC = new Vector3[6]; // vertex C for Facei
447 Vector3[] FaceD = new Vector3[6]; // vertex D for Facei
448
449 tScale = new Vector3(lscale.X, -lscale.Y, lscale.Z);
450 scale = ((tScale * rot));
451 vertexes[0] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
452 // vertexes[0].x = pos.X + vertexes[0].x;
453 //vertexes[0].y = pos.Y + vertexes[0].y;
454 //vertexes[0].z = pos.Z + vertexes[0].z;
455
456 FaceA[0] = vertexes[0];
457 FaceB[3] = vertexes[0];
458 FaceA[4] = vertexes[0];
459
460 tScale = lscale;
461 scale = ((tScale * rot));
462 vertexes[1] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
463
464 // vertexes[1].x = pos.X + vertexes[1].x;
465 // vertexes[1].y = pos.Y + vertexes[1].y;
466 //vertexes[1].z = pos.Z + vertexes[1].z;
467
468 FaceB[0] = vertexes[1];
469 FaceA[1] = vertexes[1];
470 FaceC[4] = vertexes[1];
471
472 tScale = new Vector3(lscale.X, -lscale.Y, -lscale.Z);
473 scale = ((tScale * rot));
474
475 vertexes[2] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
476
477 //vertexes[2].x = pos.X + vertexes[2].x;
478 //vertexes[2].y = pos.Y + vertexes[2].y;
479 //vertexes[2].z = pos.Z + vertexes[2].z;
480
481 FaceC[0] = vertexes[2];
482 FaceD[3] = vertexes[2];
483 FaceC[5] = vertexes[2];
484
485 tScale = new Vector3(lscale.X, lscale.Y, -lscale.Z);
486 scale = ((tScale * rot));
487 vertexes[3] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
488
489 //vertexes[3].x = pos.X + vertexes[3].x;
490 // vertexes[3].y = pos.Y + vertexes[3].y;
491 // vertexes[3].z = pos.Z + vertexes[3].z;
492
493 FaceD[0] = vertexes[3];
494 FaceC[1] = vertexes[3];
495 FaceA[5] = vertexes[3];
496
497 tScale = new Vector3(-lscale.X, lscale.Y, lscale.Z);
498 scale = ((tScale * rot));
499 vertexes[4] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
500
501 // vertexes[4].x = pos.X + vertexes[4].x;
502 // vertexes[4].y = pos.Y + vertexes[4].y;
503 // vertexes[4].z = pos.Z + vertexes[4].z;
504
505 FaceB[1] = vertexes[4];
506 FaceA[2] = vertexes[4];
507 FaceD[4] = vertexes[4];
508
509 tScale = new Vector3(-lscale.X, lscale.Y, -lscale.Z);
510 scale = ((tScale * rot));
511 vertexes[5] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
512
513 // vertexes[5].x = pos.X + vertexes[5].x;
514 // vertexes[5].y = pos.Y + vertexes[5].y;
515 // vertexes[5].z = pos.Z + vertexes[5].z;
516
517 FaceD[1] = vertexes[5];
518 FaceC[2] = vertexes[5];
519 FaceB[5] = vertexes[5];
520
521 tScale = new Vector3(-lscale.X, -lscale.Y, lscale.Z);
522 scale = ((tScale * rot));
523 vertexes[6] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
524
525 // vertexes[6].x = pos.X + vertexes[6].x;
526 // vertexes[6].y = pos.Y + vertexes[6].y;
527 // vertexes[6].z = pos.Z + vertexes[6].z;
528
529 FaceB[2] = vertexes[6];
530 FaceA[3] = vertexes[6];
531 FaceB[4] = vertexes[6];
532
533 tScale = new Vector3(-lscale.X, -lscale.Y, -lscale.Z);
534 scale = ((tScale * rot));
535 vertexes[7] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
455 536
456 // vertexes[7].x = pos.X + vertexes[7].x; 537 // vertexes[7].x = pos.X + vertexes[7].x;
457 // vertexes[7].y = pos.Y + vertexes[7].y; 538 // vertexes[7].y = pos.Y + vertexes[7].y;
458 // vertexes[7].z = pos.Z + vertexes[7].z; 539 // vertexes[7].z = pos.Z + vertexes[7].z;
459 540
460 FaceD[2] = vertexes[7]; 541 FaceD[2] = vertexes[7];
461 FaceC[3] = vertexes[7]; 542 FaceC[3] = vertexes[7];
462 FaceD[5] = vertexes[7]; 543 FaceD[5] = vertexes[7];
463#endregion 544 #endregion
464 545
465 //int wy = 0; 546 //int wy = 0;
466 547
467 //bool breakYN = false; // If we run into an error drawing, break out of the 548 //bool breakYN = false; // If we run into an error drawing, break out of the
468 // loop so we don't lag to death on error handling 549 // loop so we don't lag to death on error handling
469 DrawStruct ds = new DrawStruct(); 550 DrawStruct ds = new DrawStruct();
470 ds.brush = new SolidBrush(mapdotspot); 551 ds.brush = new SolidBrush(mapdotspot);
471 //ds.rect = new Rectangle(mapdrawstartX, (255 - mapdrawstartY), mapdrawendX - mapdrawstartX, mapdrawendY - mapdrawstartY); 552 //ds.rect = new Rectangle(mapdrawstartX, (255 - mapdrawstartY), mapdrawendX - mapdrawstartX, mapdrawendY - mapdrawstartY);
472 553
473 ds.trns = new face[FaceA.Length]; 554 ds.trns = new face[FaceA.Length];
474 555
475 for (int i = 0; i < FaceA.Length; i++) 556 for (int i = 0; i < FaceA.Length; i++)
476 { 557 {
477 Point[] working = new Point[5]; 558 Point[] working = new Point[5];
478 working[0] = project(FaceA[i], axPos); 559 working[0] = project(hm, FaceA[i], axPos);
479 working[1] = project(FaceB[i], axPos); 560 working[1] = project(hm, FaceB[i], axPos);
480 working[2] = project(FaceD[i], axPos); 561 working[2] = project(hm, FaceD[i], axPos);
481 working[3] = project(FaceC[i], axPos); 562 working[3] = project(hm, FaceC[i], axPos);
482 working[4] = project(FaceA[i], axPos); 563 working[4] = project(hm, FaceA[i], axPos);
483 564
484 face workingface = new face(); 565 face workingface = new face();
485 workingface.pts = working; 566 workingface.pts = working;
486 567
487 ds.trns[i] = workingface; 568 ds.trns[i] = workingface;
488 } 569 }
489 570
490 z_sort.Add(part.LocalId, ds); 571 z_sort.Add(part.LocalId, ds);
491 z_localIDs.Add(part.LocalId); 572 z_localIDs.Add(part.LocalId);
492 z_sortheights.Add(pos.Z); 573 z_sortheights.Add(pos.Z);
493 574
494 //for (int wx = mapdrawstartX; wx < mapdrawendX; wx++) 575 // for (int wx = mapdrawstartX; wx < mapdrawendX; wx++)
495 //{ 576 // {
496 //for (wy = mapdrawstartY; wy < mapdrawendY; wy++) 577 // for (wy = mapdrawstartY; wy < mapdrawendY; wy++)
497 //{ 578 // {
498 //m_log.InfoFormat("[MAPDEBUG]: {0},{1}({2})", wx, (255 - wy),wy); 579 // m_log.InfoFormat("[MAPDEBUG]: {0},{1}({2})", wx, (255 - wy),wy);
499 //try 580 // try
500 //{ 581 // {
501 // Remember, flip the y! 582 // // Remember, flip the y!
502 // mapbmp.SetPixel(wx, (255 - wy), mapdotspot); 583 // mapbmp.SetPixel(wx, (255 - wy), mapdotspot);
503 //} 584 // }
504 //catch (ArgumentException) 585 // catch (ArgumentException)
505 //{ 586 // {
506 // breakYN = true; 587 // breakYN = true;
507 //} 588 // }
508 589 // }
509 //if (breakYN) 590 // if (breakYN)
510 // break; 591 // break;
592 // }
593 // }
511 //} 594 //}
595 } // Object is within 256m Z of terrain
596 } // object is at least a meter wide
597 } // loop over group children
598 } // entitybase is sceneobject group
599 } // foreach loop over entities
512 600
513 //if (breakYN) 601 float[] sortedZHeights = z_sortheights.ToArray();
514 // break; 602 uint[] sortedlocalIds = z_localIDs.ToArray();
515 //}
516 } // Object is within 256m Z of terrain
517 } // object is at least a meter wide
518 } // loop over group children
519 } // entitybase is sceneobject group
520 } // foreach loop over entities
521 603
522 float[] sortedZHeights = z_sortheights.ToArray(); 604 // Sort prim by Z position
523 uint[] sortedlocalIds = z_localIDs.ToArray(); 605 Array.Sort(sortedZHeights, sortedlocalIds);
524 606
525 // Sort prim by Z position 607 using (Graphics g = Graphics.FromImage(mapbmp))
526 Array.Sort(sortedZHeights, sortedlocalIds);
527
528 Graphics g = Graphics.FromImage(mapbmp);
529
530 for (int s = 0; s < sortedZHeights.Length; s++)
531 {
532 if (z_sort.ContainsKey(sortedlocalIds[s]))
533 { 608 {
534 DrawStruct rectDrawStruct = z_sort[sortedlocalIds[s]]; 609 for (int s = 0; s < sortedZHeights.Length; s++)
535 for (int r = 0; r < rectDrawStruct.trns.Length; r++)
536 { 610 {
537 g.FillPolygon(rectDrawStruct.brush,rectDrawStruct.trns[r].pts); 611 if (z_sort.ContainsKey(sortedlocalIds[s]))
612 {
613 DrawStruct rectDrawStruct = z_sort[sortedlocalIds[s]];
614 for (int r = 0; r < rectDrawStruct.trns.Length; r++)
615 {
616 g.FillPolygon(rectDrawStruct.brush,rectDrawStruct.trns[r].pts);
617 }
618 //g.FillRectangle(rectDrawStruct.brush , rectDrawStruct.rect);
619 }
538 } 620 }
539 //g.FillRectangle(rectDrawStruct.brush , rectDrawStruct.rect);
540 } 621 }
541 } 622 } // lock entities objs
542 623
543 g.Dispose(); 624 }
544 } // lock entities objs 625 finally
626 {
627 foreach (DrawStruct ds in z_sort.Values)
628 ds.brush.Dispose();
629 }
545 630
546 m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Done in " + (Environment.TickCount - tc) + " ms"); 631 m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Done in " + (Environment.TickCount - tc) + " ms");
632
547 return mapbmp; 633 return mapbmp;
548 } 634 }
549 635
550 private Point project(Vector3 point3d, Vector3 originpos) 636 private Point project(ITerrainChannel hm, Vector3 point3d, Vector3 originpos)
551 { 637 {
552 Point returnpt = new Point(); 638 Point returnpt = new Point();
553 //originpos = point3d; 639 //originpos = point3d;
554 //int d = (int)(256f / 1.5f); 640 //int d = (int)(256f / 1.5f);
555 641
556 //Vector3 topos = new Vector3(0, 0, 0); 642 //Vector3 topos = new Vector3(0, 0, 0);
557 // float z = -point3d.z - topos.z; 643 // float z = -point3d.z - topos.z;
558 644
559 returnpt.X = (int)point3d.X;//(int)((topos.x - point3d.x) / z * d); 645 returnpt.X = (int)point3d.X;//(int)((topos.x - point3d.x) / z * d);
560 returnpt.Y = (int)(((int)Constants.RegionSize - 1) - point3d.Y);//(int)(255 - (((topos.y - point3d.y) / z * d))); 646 returnpt.Y = (int)((hm.Width - 1) - point3d.Y);//(int)(255 - (((topos.y - point3d.y) / z * d)));
561 647
562 return returnpt; 648 return returnpt;
563 } 649 }
diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs b/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs
index 992bff3..708286c 100644
--- a/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs
+++ b/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs
@@ -31,6 +31,7 @@ using System.Reflection;
31using log4net; 31using log4net;
32using Nini.Config; 32using Nini.Config;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes; 35using OpenSim.Region.Framework.Scenes;
35 36
36namespace OpenSim.Region.CoreModules.World.LegacyMap 37namespace OpenSim.Region.CoreModules.World.LegacyMap
@@ -39,8 +40,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
39 { 40 {
40 private static readonly Color WATER_COLOR = Color.FromArgb(29, 71, 95); 41 private static readonly Color WATER_COLOR = Color.FromArgb(29, 71, 95);
41 42
42 private static readonly ILog m_log = 43 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 private static readonly string LogHeader = "[SHADED MAPTILE RENDERER]";
44 45
45 private Scene m_scene; 46 private Scene m_scene;
46 //private IConfigSource m_config; // not used currently 47 //private IConfigSource m_config; // not used currently
@@ -53,19 +54,26 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
53 54
54 public void TerrainToBitmap(Bitmap mapbmp) 55 public void TerrainToBitmap(Bitmap mapbmp)
55 { 56 {
57 m_log.DebugFormat("{0} Generating Maptile Step 1: Terrain", LogHeader);
56 int tc = Environment.TickCount; 58 int tc = Environment.TickCount;
57 m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Terrain");
58 59
59 double[,] hm = m_scene.Heightmap.GetDoubles(); 60 ITerrainChannel hm = m_scene.Heightmap;
61
62 if (mapbmp.Width != hm.Width || mapbmp.Height != hm.Height)
63 {
64 m_log.ErrorFormat("{0} TerrainToBitmap. Passed bitmap wrong dimensions. passed=<{1},{2}>, size=<{3},{4}>",
65 LogHeader, mapbmp.Width, mapbmp.Height, hm.Width, hm.Height);
66 }
67
60 bool ShadowDebugContinue = true; 68 bool ShadowDebugContinue = true;
61 69
62 bool terraincorruptedwarningsaid = false; 70 bool terraincorruptedwarningsaid = false;
63 71
64 float low = 255; 72 float low = 255;
65 float high = 0; 73 float high = 0;
66 for (int x = 0; x < (int)Constants.RegionSize; x++) 74 for (int x = 0; x < hm.Width; x++)
67 { 75 {
68 for (int y = 0; y < (int)Constants.RegionSize; y++) 76 for (int y = 0; y < hm.Height; y++)
69 { 77 {
70 float hmval = (float)hm[x, y]; 78 float hmval = (float)hm[x, y];
71 if (hmval < low) 79 if (hmval < low)
@@ -77,12 +85,12 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
77 85
78 float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight; 86 float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight;
79 87
80 for (int x = 0; x < (int)Constants.RegionSize; x++) 88 for (int x = 0; x < hm.Width; x++)
81 { 89 {
82 for (int y = 0; y < (int)Constants.RegionSize; y++) 90 for (int y = 0; y < hm.Height; y++)
83 { 91 {
84 // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left 92 // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left
85 int yr = ((int)Constants.RegionSize - 1) - y; 93 int yr = ((int)hm.Height - 1) - y;
86 94
87 float heightvalue = (float)hm[x, y]; 95 float heightvalue = (float)hm[x, y];
88 96
@@ -109,12 +117,12 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
109 // . 117 // .
110 // 118 //
111 // Shade the terrain for shadows 119 // Shade the terrain for shadows
112 if (x < ((int)Constants.RegionSize - 1) && yr < ((int)Constants.RegionSize - 1)) 120 if (x < (hm.Width - 1) && yr < (hm.Height - 1))
113 { 121 {
114 float hfvalue = (float)hm[x, y]; 122 float hfvalue = (float)hm[x, y];
115 float hfvaluecompare = 0f; 123 float hfvaluecompare = 0f;
116 124
117 if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize)) 125 if ((x + 1 < hm.Width) && (y + 1 < hm.Height))
118 { 126 {
119 hfvaluecompare = (float)hm[x + 1, y + 1]; // light from north-east => look at land height there 127 hfvaluecompare = (float)hm[x + 1, y + 1]; // light from north-east => look at land height there
120 } 128 }
@@ -179,7 +187,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
179 187
180 if (ShadowDebugContinue) 188 if (ShadowDebugContinue)
181 { 189 {
182 if ((x - 1 > 0) && (yr + 1 < (int)Constants.RegionSize)) 190 if ((x - 1 > 0) && (yr + 1 < hm.Height))
183 { 191 {
184 color = mapbmp.GetPixel(x - 1, yr + 1); 192 color = mapbmp.GetPixel(x - 1, yr + 1);
185 int r = color.R; 193 int r = color.R;
@@ -199,7 +207,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
199 { 207 {
200 if (!terraincorruptedwarningsaid) 208 if (!terraincorruptedwarningsaid)
201 { 209 {
202 m_log.WarnFormat("[MAPIMAGE]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", m_scene.RegionInfo.RegionName); 210 m_log.WarnFormat("[SHADED MAP TILE RENDERER]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", m_scene.RegionInfo.RegionName);
203 terraincorruptedwarningsaid = true; 211 terraincorruptedwarningsaid = true;
204 } 212 }
205 color = Color.Black; 213 color = Color.Black;
@@ -229,16 +237,17 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
229 { 237 {
230 if (!terraincorruptedwarningsaid) 238 if (!terraincorruptedwarningsaid)
231 { 239 {
232 m_log.WarnFormat("[MAPIMAGE]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", m_scene.RegionInfo.RegionName); 240 m_log.WarnFormat("[SHADED MAP TILE RENDERER]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", m_scene.RegionInfo.RegionName);
233 terraincorruptedwarningsaid = true; 241 terraincorruptedwarningsaid = true;
234 } 242 }
235 Color black = Color.Black; 243 Color black = Color.Black;
236 mapbmp.SetPixel(x, ((int)Constants.RegionSize - y) - 1, black); 244 mapbmp.SetPixel(x, (hm.Width - y) - 1, black);
237 } 245 }
238 } 246 }
239 } 247 }
240 } 248 }
241 m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms"); 249
250 m_log.Debug("[SHADED MAP TILE RENDERER]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms");
242 } 251 }
243 } 252 }
244} 253}
diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs b/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs
index d13c2ef..9f23141 100644
--- a/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs
+++ b/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs
@@ -34,6 +34,8 @@ using Nini.Config;
34using OpenMetaverse; 34using OpenMetaverse;
35using OpenMetaverse.Imaging; 35using OpenMetaverse.Imaging;
36using OpenSim.Framework; 36using OpenSim.Framework;
37using OpenSim.Region.Framework;
38using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
38 40
39namespace OpenSim.Region.CoreModules.World.LegacyMap 41namespace OpenSim.Region.CoreModules.World.LegacyMap
@@ -122,8 +124,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
122 { 124 {
123 #region Constants 125 #region Constants
124 126
125 private static readonly ILog m_log = 127 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
126 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 128 private static readonly string LogHeader = "[TEXTURED MAPTILE RENDERER]";
127 129
128 // some hardcoded terrain UUIDs that work with SL 1.20 (the four default textures and "Blank"). 130 // some hardcoded terrain UUIDs that work with SL 1.20 (the four default textures and "Blank").
129 // The color-values were choosen because they "look right" (at least to me) ;-) 131 // The color-values were choosen because they "look right" (at least to me) ;-)
@@ -173,7 +175,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
173 private Bitmap fetchTexture(UUID id) 175 private Bitmap fetchTexture(UUID id)
174 { 176 {
175 AssetBase asset = m_scene.AssetService.Get(id.ToString()); 177 AssetBase asset = m_scene.AssetService.Get(id.ToString());
176 m_log.DebugFormat("[TexturedMapTileRenderer]: Fetched texture {0}, found: {1}", id, asset != null); 178 m_log.DebugFormat("{0} Fetched texture {1}, found: {2}", LogHeader, id, asset != null);
177 if (asset == null) return null; 179 if (asset == null) return null;
178 180
179 ManagedImage managedImage; 181 ManagedImage managedImage;
@@ -188,18 +190,15 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
188 } 190 }
189 catch (DllNotFoundException) 191 catch (DllNotFoundException)
190 { 192 {
191 m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg is not installed correctly on this system. Asset Data is empty for {0}", id); 193 m_log.ErrorFormat("{0} OpenJpeg is not installed correctly on this system. Asset Data is empty for {1}", LogHeader, id);
192
193 } 194 }
194 catch (IndexOutOfRangeException) 195 catch (IndexOutOfRangeException)
195 { 196 {
196 m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg was unable to encode this. Asset Data is empty for {0}", id); 197 m_log.ErrorFormat("{0} OpenJpeg was unable to encode this. Asset Data is empty for {1}", LogHeader, id);
197
198 } 198 }
199 catch (Exception) 199 catch (Exception)
200 { 200 {
201 m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg was unable to encode this. Asset Data is empty for {0}", id); 201 m_log.ErrorFormat("{0} OpenJpeg was unable to encode this. Asset Data is empty for {1}", LogHeader, id);
202
203 } 202 }
204 return null; 203 return null;
205 204
@@ -233,10 +232,14 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
233 if (textureID == UUID.Zero) return defaultColor; // not set 232 if (textureID == UUID.Zero) return defaultColor; // not set
234 if (m_mapping.ContainsKey(textureID)) return m_mapping[textureID]; // one of the predefined textures 233 if (m_mapping.ContainsKey(textureID)) return m_mapping[textureID]; // one of the predefined textures
235 234
236 Bitmap bmp = fetchTexture(textureID); 235 Color color;
237 Color color = bmp == null ? defaultColor : computeAverageColor(bmp); 236
238 // store it for future reference 237 using (Bitmap bmp = fetchTexture(textureID))
239 m_mapping[textureID] = color; 238 {
239 color = bmp == null ? defaultColor : computeAverageColor(bmp);
240 // store it for future reference
241 m_mapping[textureID] = color;
242 }
240 243
241 return color; 244 return color;
242 } 245 }
@@ -267,8 +270,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
267 270
268 // the heigthfield might have some jumps in values. Rendered land is smooth, though, 271 // the heigthfield might have some jumps in values. Rendered land is smooth, though,
269 // as a slope is rendered at that place. So average 4 neighbour values to emulate that. 272 // as a slope is rendered at that place. So average 4 neighbour values to emulate that.
270 private float getHeight(double[,] hm, int x, int y) { 273 private float getHeight(ITerrainChannel hm, int x, int y) {
271 if (x < ((int)Constants.RegionSize - 1) && y < ((int)Constants.RegionSize - 1)) 274 if (x < (hm.Width - 1) && y < (hm.Height - 1))
272 return (float)(hm[x, y] * .444 + (hm[x + 1, y] + hm[x, y + 1]) * .222 + hm[x + 1, y +1] * .112); 275 return (float)(hm[x, y] * .444 + (hm[x + 1, y] + hm[x, y + 1]) * .222 + hm[x + 1, y +1] * .112);
273 else 276 else
274 return (float)hm[x, y]; 277 return (float)hm[x, y];
@@ -278,7 +281,15 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
278 public void TerrainToBitmap(Bitmap mapbmp) 281 public void TerrainToBitmap(Bitmap mapbmp)
279 { 282 {
280 int tc = Environment.TickCount; 283 int tc = Environment.TickCount;
281 m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Terrain"); 284 m_log.DebugFormat("{0} Generating Maptile Step 1: Terrain", LogHeader);
285
286 ITerrainChannel hm = m_scene.Heightmap;
287
288 if (mapbmp.Width != hm.Width || mapbmp.Height != hm.Height)
289 {
290 m_log.ErrorFormat("{0} TerrainToBitmap. Passed bitmap wrong dimensions. passed=<{1},{2}>, size=<{3},{4}>",
291 LogHeader, mapbmp.Width, mapbmp.Height, hm.Width, hm.Height);
292 }
282 293
283 // These textures should be in the AssetCache anyway, as every client conneting to this 294 // These textures should be in the AssetCache anyway, as every client conneting to this
284 // region needs them. Except on start, when the map is recreated (before anyone connected), 295 // region needs them. Except on start, when the map is recreated (before anyone connected),
@@ -306,19 +317,17 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
306 317
307 float waterHeight = (float)settings.WaterHeight; 318 float waterHeight = (float)settings.WaterHeight;
308 319
309 double[,] hm = m_scene.Heightmap.GetDoubles(); 320 for (int x = 0; x < hm.Width; x++)
310
311 for (int x = 0; x < (int)Constants.RegionSize; x++)
312 { 321 {
313 float columnRatio = x / ((float)Constants.RegionSize - 1); // 0 - 1, for interpolation 322 float columnRatio = x / (hm.Width - 1); // 0 - 1, for interpolation
314 for (int y = 0; y < (int)Constants.RegionSize; y++) 323 for (int y = 0; y < hm.Height; y++)
315 { 324 {
316 float rowRatio = y / ((float)Constants.RegionSize - 1); // 0 - 1, for interpolation 325 float rowRatio = y / (hm.Height - 1); // 0 - 1, for interpolation
317 326
318 // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left 327 // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left
319 int yr = ((int)Constants.RegionSize - 1) - y; 328 int yr = (hm.Height - 1) - y;
320 329
321 float heightvalue = getHeight(hm, x, y); 330 float heightvalue = getHeight(m_scene.Heightmap, x, y);
322 if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue)) 331 if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue))
323 heightvalue = 0; 332 heightvalue = 0;
324 333
@@ -368,9 +377,9 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
368 } 377 }
369 378
370 // Shade the terrain for shadows 379 // Shade the terrain for shadows
371 if (x < ((int)Constants.RegionSize - 1) && y < ((int)Constants.RegionSize - 1)) 380 if (x < (hm.Width - 1) && y < (hm.Height - 1))
372 { 381 {
373 float hfvaluecompare = getHeight(hm, x + 1, y + 1); // light from north-east => look at land height there 382 float hfvaluecompare = getHeight(m_scene.Heightmap, x + 1, y + 1); // light from north-east => look at land height there
374 if (Single.IsInfinity(hfvaluecompare) || Single.IsNaN(hfvaluecompare)) 383 if (Single.IsInfinity(hfvaluecompare) || Single.IsNaN(hfvaluecompare))
375 hfvaluecompare = 0f; 384 hfvaluecompare = 0f;
376 385
@@ -412,7 +421,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
412 } 421 }
413 } 422 }
414 } 423 }
415 m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms"); 424
425 m_log.Debug("[TEXTURED MAP TILE RENDERER]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms");
416 } 426 }
417 } 427 }
418} 428}
diff --git a/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs b/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs
index 4e20196..0a4e83e 100644
--- a/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs
+++ b/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs
@@ -195,19 +195,20 @@ namespace OpenSim.Region.CoreModules.World.LightShare
195 if (m_scene.RegionInfo.WindlightSettings.valid) 195 if (m_scene.RegionInfo.WindlightSettings.valid)
196 { 196 {
197 List<byte[]> param = compileWindlightSettings(wl); 197 List<byte[]> param = compileWindlightSettings(wl);
198 client.SendGenericMessage("Windlight", param); 198 client.SendGenericMessage("Windlight", UUID.Random(), param);
199 } 199 }
200 else 200 else
201 { 201 {
202 List<byte[]> param = new List<byte[]>(); 202 List<byte[]> param = new List<byte[]>();
203 client.SendGenericMessage("WindlightReset", param); 203 client.SendGenericMessage("WindlightReset", UUID.Random(), param);
204 } 204 }
205 } 205 }
206 } 206 }
207 207
208 private void EventManager_OnMakeRootAgent(ScenePresence presence) 208 private void EventManager_OnMakeRootAgent(ScenePresence presence)
209 { 209 {
210 m_log.Debug("[WINDLIGHT]: Sending windlight scene to new client"); 210// m_log.Debug("[WINDLIGHT]: Sending windlight scene to new client {0}", presence.Name);
211
211 SendProfileToClient(presence.ControllingClient); 212 SendProfileToClient(presence.ControllingClient);
212 } 213 }
213 214
diff --git a/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs b/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs
index 601e81e..46b0470 100644
--- a/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs
+++ b/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs
@@ -595,6 +595,9 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap
595 /// <returns>true if the url matches an entry on the whitelist, false otherwise</returns> 595 /// <returns>true if the url matches an entry on the whitelist, false otherwise</returns>
596 protected bool CheckUrlAgainstWhitelist(string rawUrl, string[] whitelist) 596 protected bool CheckUrlAgainstWhitelist(string rawUrl, string[] whitelist)
597 { 597 {
598 if (whitelist == null)
599 return false;
600
598 Uri url = new Uri(rawUrl); 601 Uri url = new Uri(rawUrl);
599 602
600 foreach (string origWlUrl in whitelist) 603 foreach (string origWlUrl in whitelist)
diff --git a/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs b/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs
index 03a96a4..ee57aed 100644
--- a/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs
+++ b/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs
@@ -39,7 +39,6 @@ using OpenSim.Region.CoreModules.World.Media.Moap;
39using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Region.Framework.Scenes.Serialization; 40using OpenSim.Region.Framework.Scenes.Serialization;
41using OpenSim.Tests.Common; 41using OpenSim.Tests.Common;
42using OpenSim.Tests.Common.Mock;
43 42
44namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests 43namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests
45{ 44{
diff --git a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs
index 1e4f0a4..2abc910 100644
--- a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs
+++ b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs
@@ -38,6 +38,7 @@ using OpenSim.Region.Framework;
38using OpenSim.Region.Framework.Interfaces; 38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Region.Framework.Scenes.Serialization; 40using OpenSim.Region.Framework.Scenes.Serialization;
41using PermissionMask = OpenSim.Framework.PermissionMask;
41 42
42namespace OpenSim.Region.CoreModules.World.Objects.BuySell 43namespace OpenSim.Region.CoreModules.World.Objects.BuySell
43{ 44{
@@ -140,6 +141,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell
140 141
141 part.ObjectSaleType = 0; 142 part.ObjectSaleType = 0;
142 part.SalePrice = 10; 143 part.SalePrice = 10;
144 part.ClickAction = Convert.ToByte(0);
143 145
144 group.HasGroupChanged = true; 146 group.HasGroupChanged = true;
145 part.SendPropertiesToClient(remoteClient); 147 part.SendPropertiesToClient(remoteClient);
@@ -150,14 +152,9 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell
150 break; 152 break;
151 153
152 case 2: // Sell a copy 154 case 2: // Sell a copy
153 Vector3 inventoryStoredPosition = new Vector3 155 Vector3 inventoryStoredPosition = new Vector3(
154 (((group.AbsolutePosition.X > (int)Constants.RegionSize) 156 Math.Min(group.AbsolutePosition.X, m_scene.RegionInfo.RegionSizeX - 6),
155 ? 250 157 Math.Min(group.AbsolutePosition.Y, m_scene.RegionInfo.RegionSizeY - 6),
156 : group.AbsolutePosition.X)
157 ,
158 (group.AbsolutePosition.X > (int)Constants.RegionSize)
159 ? 250
160 : group.AbsolutePosition.X,
161 group.AbsolutePosition.Z); 158 group.AbsolutePosition.Z);
162 159
163 Vector3 originalPosition = group.AbsolutePosition; 160 Vector3 originalPosition = group.AbsolutePosition;
@@ -197,13 +194,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell
197 item.InvType = (int)InventoryType.Object; 194 item.InvType = (int)InventoryType.Object;
198 item.Folder = categoryID; 195 item.Folder = categoryID;
199 196
200 uint nextPerms=(perms & 7) << 13; 197 PermissionsUtil.ApplyFoldedPermissions(perms, ref perms);
201 if ((nextPerms & (uint)PermissionMask.Copy) == 0)
202 perms &= ~(uint)PermissionMask.Copy;
203 if ((nextPerms & (uint)PermissionMask.Transfer) == 0)
204 perms &= ~(uint)PermissionMask.Transfer;
205 if ((nextPerms & (uint)PermissionMask.Modify) == 0)
206 perms &= ~(uint)PermissionMask.Modify;
207 198
208 item.BasePermissions = perms & part.NextOwnerMask; 199 item.BasePermissions = perms & part.NextOwnerMask;
209 item.CurrentPermissions = perms & part.NextOwnerMask; 200 item.CurrentPermissions = perms & part.NextOwnerMask;
diff --git a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
index 9fc2daf..e77f0aa 100644
--- a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
@@ -416,7 +416,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
416 416
417 if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector)) 417 if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector))
418 { 418 {
419 m_console.OutputFormat("Error: Start vector {0} does not have a valid format", rawConsoleStartVector); 419 m_console.OutputFormat("Error: Start vector '{0}' does not have a valid format", rawConsoleStartVector);
420 return; 420 return;
421 } 421 }
422 422
@@ -425,7 +425,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
425 425
426 if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector)) 426 if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector))
427 { 427 {
428 m_console.OutputFormat("Error: End vector {0} does not have a valid format", rawConsoleEndVector); 428 m_console.OutputFormat("Error: End vector '{0}' does not have a valid format", rawConsoleEndVector);
429 return; 429 return;
430 } 430 }
431 431
@@ -546,7 +546,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
546 { 546 {
547 ConsoleDisplayList cdl = new ConsoleDisplayList(); 547 ConsoleDisplayList cdl = new ConsoleDisplayList();
548 cdl.AddRow("Name", so.Name); 548 cdl.AddRow("Name", so.Name);
549 cdl.AddRow("Descrition", so.Description); 549 cdl.AddRow("Description", so.Description);
550 cdl.AddRow("Local ID", so.LocalId); 550 cdl.AddRow("Local ID", so.LocalId);
551 cdl.AddRow("UUID", so.UUID); 551 cdl.AddRow("UUID", so.UUID);
552 cdl.AddRow("Location", string.Format("{0} @ {1}", so.AbsolutePosition, so.Scene.Name)); 552 cdl.AddRow("Location", string.Format("{0} @ {1}", so.AbsolutePosition, so.Scene.Name));
@@ -597,6 +597,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
597 cdl.AddRow("LightFalloff", s.LightFalloff); 597 cdl.AddRow("LightFalloff", s.LightFalloff);
598 cdl.AddRow("LightIntensity", s.LightIntensity); 598 cdl.AddRow("LightIntensity", s.LightIntensity);
599 cdl.AddRow("LightRadius", s.LightRadius); 599 cdl.AddRow("LightRadius", s.LightRadius);
600 cdl.AddRow("Location (relative)", sop.RelativePosition);
600 cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a")); 601 cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a"));
601 cdl.AddRow("PathBegin", s.PathBegin); 602 cdl.AddRow("PathBegin", s.PathBegin);
602 cdl.AddRow("PathEnd", s.PathEnd); 603 cdl.AddRow("PathEnd", s.PathEnd);
@@ -619,6 +620,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
619 cdl.AddRow("ProjectionFocus", s.ProjectionFocus); 620 cdl.AddRow("ProjectionFocus", s.ProjectionFocus);
620 cdl.AddRow("ProjectionFOV", s.ProjectionFOV); 621 cdl.AddRow("ProjectionFOV", s.ProjectionFOV);
621 cdl.AddRow("ProjectionTextureUUID", s.ProjectionTextureUUID); 622 cdl.AddRow("ProjectionTextureUUID", s.ProjectionTextureUUID);
623 cdl.AddRow("Rotation (Relative)", sop.RotationOffset);
624 cdl.AddRow("Rotation (World)", sop.GetWorldRotation());
622 cdl.AddRow("Scale", s.Scale); 625 cdl.AddRow("Scale", s.Scale);
623 cdl.AddRow( 626 cdl.AddRow(
624 "SculptData", 627 "SculptData",
@@ -628,7 +631,22 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
628 cdl.AddRow("SculptType", s.SculptType); 631 cdl.AddRow("SculptType", s.SculptType);
629 cdl.AddRow("State", s.State); 632 cdl.AddRow("State", s.State);
630 633
631 // TODO, unpack and display texture entries 634 // TODO, need to display more information about textures but in a compact format
635 // to stop output becoming huge.
636 for (int i = 0; i < sop.GetNumberOfSides(); i++)
637 {
638 Primitive.TextureEntryFace teFace = s.Textures.FaceTextures[i];
639
640 UUID textureID;
641
642 if (teFace != null)
643 textureID = teFace.TextureID;
644 else
645 textureID = s.Textures.DefaultTexture.TextureID;
646
647 cdl.AddRow(string.Format("Face {0} texture ID", i), textureID);
648 }
649
632 //cdl.AddRow("Textures", string.Format("{0} entries", s.Textures. 650 //cdl.AddRow("Textures", string.Format("{0} entries", s.Textures.
633 } 651 }
634 652
@@ -896,17 +914,17 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
896 914
897 if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector)) 915 if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector))
898 { 916 {
899 m_console.OutputFormat("Error: Start vector {0} does not have a valid format", rawConsoleStartVector); 917 m_console.OutputFormat("Error: Start vector '{0}' does not have a valid format", rawConsoleStartVector);
900 endVector = Vector3.Zero; 918 endVector = Vector3.Zero;
901 919
902 return false; 920 return false;
903 } 921 }
904 922
905 string rawConsoleEndVector = rawComponents.Skip(1).Take(1).Single(); 923 string rawConsoleEndVector = rawComponents.Skip(2).Take(1).Single();
906 924
907 if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector)) 925 if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector))
908 { 926 {
909 m_console.OutputFormat("Error: End vector {0} does not have a valid format", rawConsoleEndVector); 927 m_console.OutputFormat("Error: End vector '{0}' does not have a valid format", rawConsoleEndVector);
910 return false; 928 return false;
911 } 929 }
912 930
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
index ddaa227..780ec69 100644
--- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Linq;
30using System.Reflection; 31using System.Reflection;
31using log4net; 32using log4net;
32using Nini.Config; 33using Nini.Config;
@@ -38,6 +39,7 @@ using OpenSim.Region.Framework.Scenes;
38using OpenSim.Services.Interfaces; 39using OpenSim.Services.Interfaces;
39 40
40using Mono.Addins; 41using Mono.Addins;
42using PermissionMask = OpenSim.Framework.PermissionMask;
41 43
42namespace OpenSim.Region.CoreModules.World.Permissions 44namespace OpenSim.Region.CoreModules.World.Permissions
43{ 45{
@@ -156,37 +158,44 @@ namespace OpenSim.Region.CoreModules.World.Permissions
156 158
157 public void Initialise(IConfigSource config) 159 public void Initialise(IConfigSource config)
158 { 160 {
159 IConfig myConfig = config.Configs["Startup"]; 161 string permissionModules = Util.GetConfigVarFromSections<string>(config, "permissionmodules",
162 new string[] { "Startup", "Permissions" }, "DefaultPermissionsModule");
160 163
161 string permissionModules = myConfig.GetString("permissionmodules", "DefaultPermissionsModule"); 164 List<string> modules = new List<string>(permissionModules.Split(',').Select(m => m.Trim()));
162
163 List<string> modules = new List<string>(permissionModules.Split(','));
164 165
165 if (!modules.Contains("DefaultPermissionsModule")) 166 if (!modules.Contains("DefaultPermissionsModule"))
166 return; 167 return;
167 168
168 m_Enabled = true; 169 m_Enabled = true;
169 170
170 m_allowGridGods = myConfig.GetBoolean("allow_grid_gods", false); 171 m_allowGridGods = Util.GetConfigVarFromSections<bool>(config, "allow_grid_gods",
171 m_bypassPermissions = !myConfig.GetBoolean("serverside_object_permissions", true); 172 new string[] { "Startup", "Permissions" }, false);
172 m_propagatePermissions = myConfig.GetBoolean("propagate_permissions", true); 173 m_bypassPermissions = !Util.GetConfigVarFromSections<bool>(config, "serverside_object_permissions",
173 m_RegionOwnerIsGod = myConfig.GetBoolean("region_owner_is_god", true); 174 new string[] { "Startup", "Permissions" }, true);
174 m_RegionManagerIsGod = myConfig.GetBoolean("region_manager_is_god", false); 175 m_propagatePermissions = Util.GetConfigVarFromSections<bool>(config, "propagate_permissions",
175 m_ParcelOwnerIsGod = myConfig.GetBoolean("parcel_owner_is_god", true); 176 new string[] { "Startup", "Permissions" }, true);
176 177 m_RegionOwnerIsGod = Util.GetConfigVarFromSections<bool>(config, "region_owner_is_god",
177 m_SimpleBuildPermissions = myConfig.GetBoolean("simple_build_permissions", false); 178 new string[] { "Startup", "Permissions" }, true);
179 m_RegionManagerIsGod = Util.GetConfigVarFromSections<bool>(config, "region_manager_is_god",
180 new string[] { "Startup", "Permissions" }, false);
181 m_ParcelOwnerIsGod = Util.GetConfigVarFromSections<bool>(config, "parcel_owner_is_god",
182 new string[] { "Startup", "Permissions" }, true);
183
184 m_SimpleBuildPermissions = Util.GetConfigVarFromSections<bool>(config, "simple_build_permissions",
185 new string[] { "Startup", "Permissions" }, false);
178 186
179 m_allowedScriptCreators 187 m_allowedScriptCreators
180 = ParseUserSetConfigSetting(myConfig, "allowed_script_creators", m_allowedScriptCreators); 188 = ParseUserSetConfigSetting(config, "allowed_script_creators", m_allowedScriptCreators);
181 m_allowedScriptEditors 189 m_allowedScriptEditors
182 = ParseUserSetConfigSetting(myConfig, "allowed_script_editors", m_allowedScriptEditors); 190 = ParseUserSetConfigSetting(config, "allowed_script_editors", m_allowedScriptEditors);
183 191
184 if (m_bypassPermissions) 192 if (m_bypassPermissions)
185 m_log.Info("[PERMISSIONS]: serverside_object_permissions = false in ini file so disabling all region service permission checks"); 193 m_log.Info("[PERMISSIONS]: serverside_object_permissions = false in ini file so disabling all region service permission checks");
186 else 194 else
187 m_log.Debug("[PERMISSIONS]: Enabling all region service permission checks"); 195 m_log.Debug("[PERMISSIONS]: Enabling all region service permission checks");
188 196
189 string grant = myConfig.GetString("GrantLSL", ""); 197 string grant = Util.GetConfigVarFromSections<string>(config, "GrantLSL",
198 new string[] { "Startup", "Permissions" }, string.Empty);
190 if (grant.Length > 0) 199 if (grant.Length > 0)
191 { 200 {
192 foreach (string uuidl in grant.Split(',')) 201 foreach (string uuidl in grant.Split(','))
@@ -196,7 +205,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions
196 } 205 }
197 } 206 }
198 207
199 grant = myConfig.GetString("GrantCS", ""); 208 grant = Util.GetConfigVarFromSections<string>(config, "GrantCS",
209 new string[] { "Startup", "Permissions" }, string.Empty);
200 if (grant.Length > 0) 210 if (grant.Length > 0)
201 { 211 {
202 foreach (string uuidl in grant.Split(',')) 212 foreach (string uuidl in grant.Split(','))
@@ -206,7 +216,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions
206 } 216 }
207 } 217 }
208 218
209 grant = myConfig.GetString("GrantVB", ""); 219 grant = Util.GetConfigVarFromSections<string>(config, "GrantVB",
220 new string[] { "Startup", "Permissions" }, string.Empty);
210 if (grant.Length > 0) 221 if (grant.Length > 0)
211 { 222 {
212 foreach (string uuidl in grant.Split(',')) 223 foreach (string uuidl in grant.Split(','))
@@ -216,7 +227,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions
216 } 227 }
217 } 228 }
218 229
219 grant = myConfig.GetString("GrantJS", ""); 230 grant = Util.GetConfigVarFromSections<string>(config, "GrantJS",
231 new string[] { "Startup", "Permissions" }, string.Empty);
220 if (grant.Length > 0) 232 if (grant.Length > 0)
221 { 233 {
222 foreach (string uuidl in grant.Split(',')) 234 foreach (string uuidl in grant.Split(','))
@@ -226,7 +238,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions
226 } 238 }
227 } 239 }
228 240
229 grant = myConfig.GetString("GrantYP", ""); 241 grant = Util.GetConfigVarFromSections<string>(config, "GrantYP",
242 new string[] { "Startup", "Permissions" }, string.Empty);
230 if (grant.Length > 0) 243 if (grant.Length > 0)
231 { 244 {
232 foreach (string uuidl in grant.Split(',')) 245 foreach (string uuidl in grant.Split(','))
@@ -456,7 +469,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
456 469
457 return false; 470 return false;
458 } 471 }
459 472
460 /// <summary> 473 /// <summary>
461 /// Parse a user set configuration setting 474 /// Parse a user set configuration setting
462 /// </summary> 475 /// </summary>
@@ -464,11 +477,12 @@ namespace OpenSim.Region.CoreModules.World.Permissions
464 /// <param name="settingName"></param> 477 /// <param name="settingName"></param>
465 /// <param name="defaultValue">The default value for this attribute</param> 478 /// <param name="defaultValue">The default value for this attribute</param>
466 /// <returns>The parsed value</returns> 479 /// <returns>The parsed value</returns>
467 private static UserSet ParseUserSetConfigSetting(IConfig config, string settingName, UserSet defaultValue) 480 private static UserSet ParseUserSetConfigSetting(IConfigSource config, string settingName, UserSet defaultValue)
468 { 481 {
469 UserSet userSet = defaultValue; 482 UserSet userSet = defaultValue;
470 483
471 string rawSetting = config.GetString(settingName, defaultValue.ToString()); 484 string rawSetting = Util.GetConfigVarFromSections<string>(config, settingName,
485 new string[] {"Startup", "Permissions"}, defaultValue.ToString());
472 486
473 // Temporary measure to allow 'gods' to be specified in config for consistency's sake. In the long term 487 // Temporary measure to allow 'gods' to be specified in config for consistency's sake. In the long term
474 // this should disappear. 488 // this should disappear.
@@ -787,8 +801,10 @@ namespace OpenSim.Region.CoreModules.World.Permissions
787 801
788 // Friends with benefits should be able to edit the objects too 802 // Friends with benefits should be able to edit the objects too
789 if (IsFriendWithPerms(currentUser, objectOwner)) 803 if (IsFriendWithPerms(currentUser, objectOwner))
804 {
790 // Return immediately, so that the administrator can share objects with friends 805 // Return immediately, so that the administrator can share objects with friends
791 return true; 806 return true;
807 }
792 808
793 // Users should be able to edit what is over their land. 809 // Users should be able to edit what is over their land.
794 ILandObject parcel = m_scene.LandChannel.GetLandObject(group.AbsolutePosition.X, group.AbsolutePosition.Y); 810 ILandObject parcel = m_scene.LandChannel.GetLandObject(group.AbsolutePosition.X, group.AbsolutePosition.Y);
@@ -887,7 +903,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
887 return permission; 903 return permission;
888 } 904 }
889 905
890 protected bool GenericParcelOwnerPermission(UUID user, ILandObject parcel, ulong groupPowers) 906 protected bool GenericParcelOwnerPermission(UUID user, ILandObject parcel, ulong groupPowers, bool allowEstateManager)
891 { 907 {
892 if (parcel.LandData.OwnerID == user) 908 if (parcel.LandData.OwnerID == user)
893 { 909 {
@@ -902,7 +918,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
902 return true; 918 return true;
903 } 919 }
904 920
905 if (IsEstateManager(user)) 921 if (allowEstateManager && IsEstateManager(user))
906 { 922 {
907 return true; 923 return true;
908 } 924 }
@@ -929,7 +945,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
929 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); 945 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
930 if (m_bypassPermissions) return m_bypassPermissionsValue; 946 if (m_bypassPermissions) return m_bypassPermissionsValue;
931 947
932 return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandRelease); 948 return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandRelease, false);
933 } 949 }
934 950
935 private bool CanReclaimParcel(UUID user, ILandObject parcel, Scene scene) 951 private bool CanReclaimParcel(UUID user, ILandObject parcel, Scene scene)
@@ -937,7 +953,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
937 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); 953 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
938 if (m_bypassPermissions) return m_bypassPermissionsValue; 954 if (m_bypassPermissions) return m_bypassPermissionsValue;
939 955
940 return GenericParcelOwnerPermission(user, parcel, 0); 956 return GenericParcelOwnerPermission(user, parcel, 0,true);
941 } 957 }
942 958
943 private bool CanDeedParcel(UUID user, ILandObject parcel, Scene scene) 959 private bool CanDeedParcel(UUID user, ILandObject parcel, Scene scene)
@@ -954,7 +970,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
954 if ((client.GetGroupPowers(parcel.LandData.GroupID) & (ulong)GroupPowers.LandDeed) == 0) 970 if ((client.GetGroupPowers(parcel.LandData.GroupID) & (ulong)GroupPowers.LandDeed) == 0)
955 return false; 971 return false;
956 972
957 return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandDeed); 973 return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandDeed, false);
958 } 974 }
959 975
960 private bool CanDeedObject(UUID user, UUID group, Scene scene) 976 private bool CanDeedObject(UUID user, UUID group, Scene scene)
@@ -995,9 +1011,11 @@ namespace OpenSim.Region.CoreModules.World.Permissions
995 return false; 1011 return false;
996 1012
997 if (part.OwnerID == owner) 1013 if (part.OwnerID == owner)
998 return ((part.OwnerMask & PERM_COPY) != 0); 1014 {
999 1015 if ((part.OwnerMask & PERM_COPY) == 0)
1000 if (part.GroupID != UUID.Zero) 1016 return false;
1017 }
1018 else if (part.GroupID != UUID.Zero)
1001 { 1019 {
1002 if ((part.OwnerID == part.GroupID) && ((owner != part.LastOwnerID) || ((part.GroupMask & PERM_TRANS) == 0))) 1020 if ((part.OwnerID == part.GroupID) && ((owner != part.LastOwnerID) || ((part.GroupMask & PERM_TRANS) == 0)))
1003 return false; 1021 return false;
@@ -1039,7 +1057,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
1039 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); 1057 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1040 if (m_bypassPermissions) return m_bypassPermissionsValue; 1058 if (m_bypassPermissions) return m_bypassPermissionsValue;
1041 1059
1042 return GenericParcelOwnerPermission(user, parcel, (ulong)p); 1060 return GenericParcelOwnerPermission(user, parcel, (ulong)p, false);
1043 } 1061 }
1044 1062
1045 /// <summary> 1063 /// <summary>
@@ -1438,27 +1456,33 @@ namespace OpenSim.Region.CoreModules.World.Permissions
1438 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); 1456 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1439 if (m_bypassPermissions) return m_bypassPermissionsValue; 1457 if (m_bypassPermissions) return m_bypassPermissionsValue;
1440 1458
1441 bool permission = false; 1459// m_log.DebugFormat("[PERMISSIONS MODULE]: Checking rez object at {0} in {1}", objectPosition, m_scene.Name);
1442
1443 ILandObject land = m_scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y);
1444 if (land == null) return false;
1445 1460
1446 if ((land.LandData.Flags & ((int)ParcelFlags.CreateObjects)) == 1461 ILandObject parcel = m_scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y);
1447 (int)ParcelFlags.CreateObjects) 1462 if (parcel == null)
1448 permission = true; 1463 return false;
1449 1464
1450 if (IsAdministrator(owner)) 1465 if ((parcel.LandData.Flags & (uint)ParcelFlags.CreateObjects) != 0)
1451 { 1466 {
1452 permission = true; 1467 return true;
1453 } 1468 }
1454 1469 else if ((owner == parcel.LandData.OwnerID) || IsAdministrator(owner))
1455 // Powers are zero, because GroupPowers.AllowRez is not a precondition for rezzing objects
1456 if (GenericParcelPermission(owner, objectPosition, 0))
1457 { 1470 {
1458 permission = true; 1471 return true;
1472 }
1473 else if (((parcel.LandData.Flags & (uint)ParcelFlags.CreateGroupObjects) != 0)
1474 && (parcel.LandData.GroupID != UUID.Zero) && IsGroupMember(parcel.LandData.GroupID, owner, 0))
1475 {
1476 return true;
1477 }
1478 else if (parcel.LandData.GroupID != UUID.Zero && IsGroupMember(parcel.LandData.GroupID, owner, (ulong)GroupPowers.AllowRez))
1479 {
1480 return true;
1481 }
1482 else
1483 {
1484 return false;
1459 } 1485 }
1460
1461 return permission;
1462 } 1486 }
1463 1487
1464 private bool CanRunConsoleCommand(UUID user, Scene requestFromScene) 1488 private bool CanRunConsoleCommand(UUID user, Scene requestFromScene)
@@ -1483,7 +1507,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
1483 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); 1507 DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name);
1484 if (m_bypassPermissions) return m_bypassPermissionsValue; 1508 if (m_bypassPermissions) return m_bypassPermissionsValue;
1485 1509
1486 return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandSetSale); 1510 return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandSetSale, false);
1487 } 1511 }
1488 1512
1489 private bool CanTakeObject(UUID objectID, UUID stealer, Scene scene) 1513 private bool CanTakeObject(UUID objectID, UUID stealer, Scene scene)
@@ -1500,6 +1524,9 @@ namespace OpenSim.Region.CoreModules.World.Permissions
1500 if (m_bypassPermissions) return m_bypassPermissionsValue; 1524 if (m_bypassPermissions) return m_bypassPermissionsValue;
1501 1525
1502 bool permission = GenericObjectPermission(userID, objectID, false); 1526 bool permission = GenericObjectPermission(userID, objectID, false);
1527
1528 SceneObjectGroup so = (SceneObjectGroup)m_scene.Entities[objectID];
1529
1503 if (!permission) 1530 if (!permission)
1504 { 1531 {
1505 if (!m_scene.Entities.ContainsKey(objectID)) 1532 if (!m_scene.Entities.ContainsKey(objectID))
@@ -1513,31 +1540,23 @@ namespace OpenSim.Region.CoreModules.World.Permissions
1513 return false; 1540 return false;
1514 } 1541 }
1515 1542
1516 SceneObjectGroup task = (SceneObjectGroup)m_scene.Entities[objectID];
1517 // UUID taskOwner = null; 1543 // UUID taskOwner = null;
1518 // Added this because at this point in time it wouldn't be wise for 1544 // Added this because at this point in time it wouldn't be wise for
1519 // the administrator object permissions to take effect. 1545 // the administrator object permissions to take effect.
1520 // UUID objectOwner = task.OwnerID; 1546 // UUID objectOwner = task.OwnerID;
1521 1547
1522 if ((task.RootPart.EveryoneMask & PERM_COPY) != 0) 1548 if ((so.RootPart.EveryoneMask & PERM_COPY) != 0)
1523 permission = true; 1549 permission = true;
1550 }
1524 1551
1525 if (task.OwnerID != userID) 1552 if (so.OwnerID != userID)
1526 { 1553 {
1527 if ((task.GetEffectivePermissions() & (PERM_COPY | PERM_TRANS)) != (PERM_COPY | PERM_TRANS)) 1554 if ((so.GetEffectivePermissions() & (PERM_COPY | PERM_TRANS)) != (PERM_COPY | PERM_TRANS))
1528 permission = false; 1555 permission = false;
1529 }
1530 else
1531 {
1532 if ((task.GetEffectivePermissions() & PERM_COPY) != PERM_COPY)
1533 permission = false;
1534 }
1535 } 1556 }
1536 else 1557 else
1537 { 1558 {
1538 SceneObjectGroup task = (SceneObjectGroup)m_scene.Entities[objectID]; 1559 if ((so.GetEffectivePermissions() & PERM_COPY) != PERM_COPY)
1539
1540 if ((task.GetEffectivePermissions() & (PERM_COPY | PERM_TRANS)) != (PERM_COPY | PERM_TRANS))
1541 permission = false; 1560 permission = false;
1542 } 1561 }
1543 1562
@@ -1556,10 +1575,10 @@ namespace OpenSim.Region.CoreModules.World.Permissions
1556 float X = position.X; 1575 float X = position.X;
1557 float Y = position.Y; 1576 float Y = position.Y;
1558 1577
1559 if (X > ((int)Constants.RegionSize - 1)) 1578 if (X > ((int)m_scene.RegionInfo.RegionSizeX - 1))
1560 X = ((int)Constants.RegionSize - 1); 1579 X = ((int)m_scene.RegionInfo.RegionSizeX - 1);
1561 if (Y > ((int)Constants.RegionSize - 1)) 1580 if (Y > ((int)m_scene.RegionInfo.RegionSizeY - 1))
1562 Y = ((int)Constants.RegionSize - 1); 1581 Y = ((int)m_scene.RegionInfo.RegionSizeY - 1);
1563 if (X < 0) 1582 if (X < 0)
1564 X = 0; 1583 X = 0;
1565 if (Y < 0) 1584 if (Y < 0)
diff --git a/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs b/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs
index 7d35473..bb4dcce 100644
--- a/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs
@@ -81,7 +81,32 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
81 m_console.Commands.AddCommand( 81 m_console.Commands.AddCommand(
82 "Regions", false, "show scene", 82 "Regions", false, "show scene",
83 "show scene", 83 "show scene",
84 "Show live scene information for the currently selected region.", HandleShowScene); 84 "Show live information for the currently selected scene (fps, prims, etc.).", HandleShowScene);
85
86 m_console.Commands.AddCommand(
87 "Regions", false, "show region",
88 "show region",
89 "Show control information for the currently selected region (host name, max physical prim size, etc).",
90 "A synonym for \"region get\"",
91 HandleShowRegion);
92
93 m_console.Commands.AddCommand(
94 "Regions", false, "region get",
95 "region get",
96 "Show control information for the currently selected region (host name, max physical prim size, etc).",
97 "Some parameters can be set with the \"region set\" command.\n"
98 + "Others must be changed via a viewer (usually via the region/estate dialog box).",
99 HandleShowRegion);
100
101 m_console.Commands.AddCommand(
102 "Regions", false, "region set",
103 "region set",
104 "Set control information for the currently selected region.",
105 "Currently, the following parameters can be set:\n"
106 + "agent-limit <int> - Current root agent limit. This is persisted over restart.\n"
107 + "max-agent-limit <int> - Maximum root agent limit. agent-limit cannot exceed this."
108 + " This is not persisted over restart - to set it every time you must add a MaxAgents entry to your regions file.",
109 HandleRegionSet);
85 } 110 }
86 111
87 public void RemoveRegion(Scene scene) 112 public void RemoveRegion(Scene scene)
@@ -94,6 +119,139 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
94// m_log.DebugFormat("[REGION COMMANDS MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); 119// m_log.DebugFormat("[REGION COMMANDS MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
95 } 120 }
96 121
122 private void HandleShowRegion(string module, string[] cmd)
123 {
124 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene))
125 return;
126
127 RegionInfo ri = m_scene.RegionInfo;
128 RegionSettings rs = ri.RegionSettings;
129
130 StringBuilder sb = new StringBuilder();
131 sb.AppendFormat("Region information for {0}\n", m_scene.Name);
132
133 ConsoleDisplayList dispList = new ConsoleDisplayList();
134 dispList.AddRow("Region ID", ri.RegionID);
135 dispList.AddRow("Region handle", ri.RegionHandle);
136 dispList.AddRow("Region location", string.Format("{0},{1}", ri.RegionLocX, ri.RegionLocY));
137 dispList.AddRow("Region size", string.Format("{0}x{1}", ri.RegionSizeX, ri.RegionSizeY));
138 //dispList.AddRow("Region type", ri.RegionType);
139 dispList.AddRow("Maturity", rs.Maturity);
140 dispList.AddRow("Region address", ri.ServerURI);
141 dispList.AddRow("From region file", ri.RegionFile);
142 dispList.AddRow("External endpoint", ri.ExternalEndPoint);
143 dispList.AddRow("Internal endpoint", ri.InternalEndPoint);
144 dispList.AddRow("Access level", ri.AccessLevel);
145 dispList.AddRow("Agent limit", rs.AgentLimit);
146 dispList.AddRow("Max agent limit", ri.AgentCapacity);
147 dispList.AddRow("Linkset capacity", ri.LinksetCapacity <= 0 ? "not set" : ri.LinksetCapacity.ToString());
148 dispList.AddRow("Prim capacity", ri.ObjectCapacity);
149 dispList.AddRow("Prim bonus", rs.ObjectBonus);
150 dispList.AddRow("Max prims per user", ri.MaxPrimsPerUser < 0 ? "n/a" : ri.MaxPrimsPerUser.ToString());
151 dispList.AddRow("Clamp prim size", ri.ClampPrimSize);
152 dispList.AddRow("Non physical prim min size", ri.NonphysPrimMin <= 0 ? "not set" : string.Format("{0} m", ri.NonphysPrimMin));
153 dispList.AddRow("Non physical prim max size", ri.NonphysPrimMax <= 0 ? "not set" : string.Format("{0} m", ri.NonphysPrimMax));
154 dispList.AddRow("Physical prim min size", ri.PhysPrimMin <= 0 ? "not set" : string.Format("{0} m", ri.PhysPrimMin));
155 dispList.AddRow("Physical prim max size", ri.PhysPrimMax <= 0 ? "not set" : string.Format("{0} m", ri.PhysPrimMax));
156
157 dispList.AddRow("Allow Damage", rs.AllowDamage);
158 dispList.AddRow("Allow Land join/divide", rs.AllowLandJoinDivide);
159 dispList.AddRow("Allow land resell", rs.AllowLandResell);
160 dispList.AddRow("Block fly", rs.BlockFly);
161 dispList.AddRow("Block show in search", rs.BlockShowInSearch);
162 dispList.AddRow("Block terraform", rs.BlockTerraform);
163 dispList.AddRow("Covenant UUID", rs.Covenant);
164 dispList.AddRow("Convenant change Unix time", rs.CovenantChangedDateTime);
165 dispList.AddRow("Disable collisions", rs.DisableCollisions);
166 dispList.AddRow("Disable physics", rs.DisablePhysics);
167 dispList.AddRow("Disable scripts", rs.DisableScripts);
168 dispList.AddRow("Restrict pushing", rs.RestrictPushing);
169 dispList.AddRow("Fixed sun", rs.FixedSun);
170 dispList.AddRow("Sun position", rs.SunPosition);
171 dispList.AddRow("Sun vector", rs.SunVector);
172 dispList.AddRow("Use estate sun", rs.UseEstateSun);
173 dispList.AddRow("Telehub UUID", rs.TelehubObject);
174 dispList.AddRow("Terrain lower limit", string.Format("{0} m", rs.TerrainLowerLimit));
175 dispList.AddRow("Terrain raise limit", string.Format("{0} m", rs.TerrainRaiseLimit));
176 dispList.AddRow("Water height", string.Format("{0} m", rs.WaterHeight));
177
178 dispList.AddRow("Maptile static file", ri.MaptileStaticFile);
179 dispList.AddRow("Maptile static UUID", ri.MaptileStaticUUID);
180 dispList.AddRow("Last map refresh", ri.lastMapRefresh);
181 dispList.AddRow("Last map UUID", ri.lastMapUUID);
182
183 dispList.AddToStringBuilder(sb);
184
185 MainConsole.Instance.Output(sb.ToString());
186 }
187
188 private void HandleRegionSet(string module, string[] args)
189 {
190 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene))
191 return;
192
193 if (args.Length != 4)
194 {
195 MainConsole.Instance.OutputFormat("Usage: region set <param> <value>");
196 return;
197 }
198
199 string param = args[2];
200 string rawValue = args[3];
201
202 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene))
203 return;
204
205 RegionInfo ri = m_scene.RegionInfo;
206 RegionSettings rs = ri.RegionSettings;
207
208 if (param == "agent-limit")
209 {
210 int newValue;
211
212 if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, rawValue, out newValue))
213 return;
214
215 if (newValue > ri.AgentCapacity)
216 {
217 MainConsole.Instance.OutputFormat(
218 "Cannot set {0} to {1} in {2} as max-agent-limit is {3}", "agent-limit",
219 newValue, m_scene.Name, ri.AgentCapacity);
220 }
221 else
222 {
223 rs.AgentLimit = newValue;
224
225 MainConsole.Instance.OutputFormat(
226 "{0} set to {1} in {2}", "agent-limit", newValue, m_scene.Name);
227 }
228
229 rs.Save();
230 }
231 else if (param == "max-agent-limit")
232 {
233 int newValue;
234
235 if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, rawValue, out newValue))
236 return;
237
238 ri.AgentCapacity = newValue;
239
240 MainConsole.Instance.OutputFormat(
241 "{0} set to {1} in {2}", "max-agent-limit", newValue, m_scene.Name);
242
243 if (ri.AgentCapacity < rs.AgentLimit)
244 {
245 rs.AgentLimit = ri.AgentCapacity;
246
247 MainConsole.Instance.OutputFormat(
248 "Reducing {0} to {1} in {2}", "agent-limit", rs.AgentLimit, m_scene.Name);
249 }
250
251 rs.Save();
252 }
253 }
254
97 private void HandleShowScene(string module, string[] cmd) 255 private void HandleShowScene(string module, string[] cmd)
98 { 256 {
99 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene)) 257 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene))
diff --git a/OpenSim/Region/CoreModules/World/Region/RestartModule.cs b/OpenSim/Region/CoreModules/World/Region/RestartModule.cs
index 249a40d..75a8295 100644
--- a/OpenSim/Region/CoreModules/World/Region/RestartModule.cs
+++ b/OpenSim/Region/CoreModules/World/Region/RestartModule.cs
@@ -46,8 +46,8 @@ namespace OpenSim.Region.CoreModules.World.Region
46 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RestartModule")] 46 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RestartModule")]
47 public class RestartModule : INonSharedRegionModule, IRestartModule 47 public class RestartModule : INonSharedRegionModule, IRestartModule
48 { 48 {
49// private static readonly ILog m_log = 49 private static readonly ILog m_log =
50// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 50 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51 51
52 protected Scene m_Scene; 52 protected Scene m_Scene;
53 protected Timer m_CountdownTimer = null; 53 protected Timer m_CountdownTimer = null;
@@ -203,18 +203,30 @@ namespace OpenSim.Region.CoreModules.World.Region
203 203
204 public void SetTimer(int intervalSeconds) 204 public void SetTimer(int intervalSeconds)
205 { 205 {
206 m_CountdownTimer = new Timer(); 206 if (intervalSeconds > 0)
207 m_CountdownTimer.AutoReset = false; 207 {
208 m_CountdownTimer.Interval = intervalSeconds * 1000; 208 m_CountdownTimer = new Timer();
209 m_CountdownTimer.Elapsed += OnTimer; 209 m_CountdownTimer.AutoReset = false;
210 m_CountdownTimer.Start(); 210 m_CountdownTimer.Interval = intervalSeconds * 1000;
211 m_CountdownTimer.Elapsed += OnTimer;
212 m_CountdownTimer.Start();
213 }
214 else if (m_CountdownTimer != null)
215 {
216 m_CountdownTimer.Stop();
217 m_CountdownTimer = null;
218 }
219 else
220 {
221 m_log.WarnFormat(
222 "[RESTART MODULE]: Tried to set restart timer to {0} in {1}, which is not a valid interval",
223 intervalSeconds, m_Scene.Name);
224 }
211 } 225 }
212 226
213 private void OnTimer(object source, ElapsedEventArgs e) 227 private void OnTimer(object source, ElapsedEventArgs e)
214 { 228 {
215 int nextInterval = DoOneNotice(); 229 SetTimer(DoOneNotice());
216
217 SetTimer(nextInterval);
218 } 230 }
219 231
220 public void AbortRestart(string message) 232 public void AbortRestart(string message)
diff --git a/OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs b/OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs
index 328fbf0..65f464a 100644
--- a/OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs
+++ b/OpenSim/Region/CoreModules/World/Serialiser/SerialiseObjects.cs
@@ -54,13 +54,14 @@ namespace OpenSim.Region.CoreModules.World.Serialiser
54 { 54 {
55 string xmlstream = GetObjectXml(scene); 55 string xmlstream = GetObjectXml(scene);
56 56
57 MemoryStream stream = ReformatXmlString(xmlstream); 57 using (MemoryStream stream = ReformatXmlString(xmlstream))
58 58 {
59 stream.Seek(0, SeekOrigin.Begin); 59 stream.Seek(0, SeekOrigin.Begin);
60 CreateXmlFile(stream, fileName); 60 CreateXmlFile(stream, fileName);
61 61
62 stream.Seek(0, SeekOrigin.Begin); 62 stream.Seek(0, SeekOrigin.Begin);
63 CreateCompressedXmlFile(stream, fileName); 63 CreateCompressedXmlFile(stream, fileName);
64 }
64 } 65 }
65 66
66 private static MemoryStream ReformatXmlString(string xmlstream) 67 private static MemoryStream ReformatXmlString(string xmlstream)
@@ -112,13 +113,16 @@ namespace OpenSim.Region.CoreModules.World.Serialiser
112 { 113 {
113 #region GZip Compressed Version 114 #region GZip Compressed Version
114 115
115 FileStream objectsFileCompressed = new FileStream(fileName + ".gzs", FileMode.Create); 116 using (FileStream objectsFileCompressed = new FileStream(fileName + ".gzs", FileMode.Create))
116 MemoryStream gzipMSStream = new MemoryStream(); 117 using (MemoryStream gzipMSStream = new MemoryStream())
117 GZipStream gzipStream = new GZipStream(gzipMSStream, CompressionMode.Compress); 118 {
118 xmlStream.WriteTo(gzipStream); 119 using (GZipStream gzipStream = new GZipStream(gzipMSStream, CompressionMode.Compress, true))
119 gzipMSStream.WriteTo(objectsFileCompressed); 120 {
120 objectsFileCompressed.Flush(); 121 xmlStream.WriteTo(gzipStream);
121 objectsFileCompressed.Close(); 122 }
123
124 gzipMSStream.WriteTo(objectsFileCompressed);
125 }
122 126
123 #endregion 127 #endregion
124 } 128 }
diff --git a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs
index bcb8e2f..a5bb1a7 100644
--- a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs
+++ b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs
@@ -27,6 +27,7 @@
27 27
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.IO; 29using System.IO;
30using System.Text;
30using System.Xml; 31using System.Xml;
31using log4net.Config; 32using log4net.Config;
32using NUnit.Framework; 33using NUnit.Framework;
@@ -35,120 +36,358 @@ using OpenSim.Framework;
35using OpenSim.Region.Framework.Scenes; 36using OpenSim.Region.Framework.Scenes;
36using OpenSim.Region.Framework.Scenes.Serialization; 37using OpenSim.Region.Framework.Scenes.Serialization;
37using OpenSim.Tests.Common; 38using OpenSim.Tests.Common;
39using OpenMetaverse.StructuredData;
38 40
39namespace OpenSim.Region.CoreModules.World.Serialiser.Tests 41namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
40{ 42{
41 [TestFixture] 43 [TestFixture]
42 public class SerialiserTests : OpenSimTestCase 44 public class SerialiserTests : OpenSimTestCase
43 { 45 {
44 private string xml = @" 46 private const string ObjectRootPartStubXml =
45 <SceneObjectGroup> 47@"<SceneObjectGroup>
46 <RootPart> 48 <RootPart>
47 <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> 49 <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
48 <AllowedDrop>false</AllowedDrop> 50 <AllowedDrop>false</AllowedDrop>
49 <CreatorID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></CreatorID> 51 <CreatorID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></CreatorID>
50 <FolderID><Guid>e6a5a05e-e8cc-4816-8701-04165e335790</Guid></FolderID> 52 <FolderID><Guid>e6a5a05e-e8cc-4816-8701-04165e335790</Guid></FolderID>
51 <InventorySerial>1</InventorySerial> 53 <InventorySerial>1</InventorySerial>
52 <TaskInventory /> 54 <TaskInventory />
53 <ObjectFlags>0</ObjectFlags> 55 <ObjectFlags>0</ObjectFlags>
54 <UUID><Guid>e6a5a05e-e8cc-4816-8701-04165e335790</Guid></UUID> 56 <UUID><Guid>e6a5a05e-e8cc-4816-8701-04165e335790</Guid></UUID>
55 <LocalId>2698615125</LocalId> 57 <LocalId>2698615125</LocalId>
56 <Name>PrimMyRide</Name> 58 <Name>PrimMyRide</Name>
57 <Material>0</Material> 59 <Material>0</Material>
58 <PassTouches>false</PassTouches> 60 <PassTouches>false</PassTouches>
59 <RegionHandle>1099511628032000</RegionHandle> 61 <RegionHandle>1099511628032000</RegionHandle>
60 <ScriptAccessPin>0</ScriptAccessPin> 62 <ScriptAccessPin>0</ScriptAccessPin>
61 <GroupPosition><X>147.23</X><Y>92.698</Y><Z>22.78084</Z></GroupPosition> 63 <GroupPosition><X>147.23</X><Y>92.698</Y><Z>22.78084</Z></GroupPosition>
62 <OffsetPosition><X>0</X><Y>0</Y><Z>0</Z></OffsetPosition> 64 <OffsetPosition><X>0</X><Y>0</Y><Z>0</Z></OffsetPosition>
63 <RotationOffset><X>-4.371139E-08</X><Y>-1</Y><Z>-4.371139E-08</Z><W>0</W></RotationOffset> 65 <RotationOffset><X>-4.371139E-08</X><Y>-1</Y><Z>-4.371139E-08</Z><W>0</W></RotationOffset>
64 <Velocity><X>0</X><Y>0</Y><Z>0</Z></Velocity> 66 <Velocity><X>0</X><Y>0</Y><Z>0</Z></Velocity>
65 <RotationalVelocity><X>0</X><Y>0</Y><Z>0</Z></RotationalVelocity> 67 <RotationalVelocity><X>0</X><Y>0</Y><Z>0</Z></RotationalVelocity>
66 <AngularVelocity><X>0</X><Y>0</Y><Z>0</Z></AngularVelocity> 68 <AngularVelocity><X>0</X><Y>0</Y><Z>0</Z></AngularVelocity>
67 <Acceleration><X>0</X><Y>0</Y><Z>0</Z></Acceleration> 69 <Acceleration><X>0</X><Y>0</Y><Z>0</Z></Acceleration>
68 <Description /> 70 <Description />
69 <Color /> 71 <Color />
70 <Text /> 72 <Text />
71 <SitName /> 73 <SitName />
72 <TouchName /> 74 <TouchName />
73 <LinkNum>0</LinkNum> 75 <LinkNum>0</LinkNum>
74 <ClickAction>0</ClickAction> 76 <ClickAction>0</ClickAction>
75 <Shape> 77 <Shape>
76 <ProfileCurve>1</ProfileCurve> 78 <ProfileCurve>1</ProfileCurve>
77 <TextureEntry>AAAAAAAAERGZmQAAAAAABQCVlZUAAAAAQEAAAABAQAAAAAAAAAAAAAAAAAAAAA==</TextureEntry> 79 <TextureEntry>AAAAAAAAERGZmQAAAAAABQCVlZUAAAAAQEAAAABAQAAAAAAAAAAAAAAAAAAAAA==</TextureEntry>
78 <ExtraParams>AA==</ExtraParams> 80 <ExtraParams>AA==</ExtraParams>
79 <PathBegin>0</PathBegin> 81 <PathBegin>0</PathBegin>
80 <PathCurve>16</PathCurve> 82 <PathCurve>16</PathCurve>
81 <PathEnd>0</PathEnd> 83 <PathEnd>0</PathEnd>
82 <PathRadiusOffset>0</PathRadiusOffset> 84 <PathRadiusOffset>0</PathRadiusOffset>
83 <PathRevolutions>0</PathRevolutions> 85 <PathRevolutions>0</PathRevolutions>
84 <PathScaleX>100</PathScaleX> 86 <PathScaleX>100</PathScaleX>
85 <PathScaleY>100</PathScaleY> 87 <PathScaleY>100</PathScaleY>
86 <PathShearX>0</PathShearX> 88 <PathShearX>0</PathShearX>
87 <PathShearY>0</PathShearY> 89 <PathShearY>0</PathShearY>
88 <PathSkew>0</PathSkew> 90 <PathSkew>0</PathSkew>
89 <PathTaperX>0</PathTaperX> 91 <PathTaperX>0</PathTaperX>
90 <PathTaperY>0</PathTaperY> 92 <PathTaperY>0</PathTaperY>
91 <PathTwist>0</PathTwist> 93 <PathTwist>0</PathTwist>
92 <PathTwistBegin>0</PathTwistBegin> 94 <PathTwistBegin>0</PathTwistBegin>
93 <PCode>9</PCode> 95 <PCode>9</PCode>
94 <ProfileBegin>0</ProfileBegin> 96 <ProfileBegin>0</ProfileBegin>
95 <ProfileEnd>0</ProfileEnd> 97 <ProfileEnd>0</ProfileEnd>
96 <ProfileHollow>0</ProfileHollow> 98 <ProfileHollow>0</ProfileHollow>
97 <Scale><X>10</X><Y>10</Y><Z>0.5</Z></Scale> 99 <Scale><X>10</X><Y>10</Y><Z>0.5</Z></Scale>
98 <State>0</State> 100 <State>0</State>
99 <ProfileShape>Square</ProfileShape> 101 <ProfileShape>Square</ProfileShape>
100 <HollowShape>Same</HollowShape> 102 <HollowShape>Same</HollowShape>
101 <SculptTexture><Guid>00000000-0000-0000-0000-000000000000</Guid></SculptTexture> 103 <SculptTexture><Guid>00000000-0000-0000-0000-000000000000</Guid></SculptTexture>
102 <SculptType>0</SculptType><SculptData /> 104 <SculptType>0</SculptType><SculptData />
103 <FlexiSoftness>0</FlexiSoftness> 105 <FlexiSoftness>0</FlexiSoftness>
104 <FlexiTension>0</FlexiTension> 106 <FlexiTension>0</FlexiTension>
105 <FlexiDrag>0</FlexiDrag> 107 <FlexiDrag>0</FlexiDrag>
106 <FlexiGravity>0</FlexiGravity> 108 <FlexiGravity>0</FlexiGravity>
107 <FlexiWind>0</FlexiWind> 109 <FlexiWind>0</FlexiWind>
108 <FlexiForceX>0</FlexiForceX> 110 <FlexiForceX>0</FlexiForceX>
109 <FlexiForceY>0</FlexiForceY> 111 <FlexiForceY>0</FlexiForceY>
110 <FlexiForceZ>0</FlexiForceZ> 112 <FlexiForceZ>0</FlexiForceZ>
111 <LightColorR>0</LightColorR> 113 <LightColorR>0</LightColorR>
112 <LightColorG>0</LightColorG> 114 <LightColorG>0</LightColorG>
113 <LightColorB>0</LightColorB> 115 <LightColorB>0</LightColorB>
114 <LightColorA>1</LightColorA> 116 <LightColorA>1</LightColorA>
115 <LightRadius>0</LightRadius> 117 <LightRadius>0</LightRadius>
116 <LightCutoff>0</LightCutoff> 118 <LightCutoff>0</LightCutoff>
117 <LightFalloff>0</LightFalloff> 119 <LightFalloff>0</LightFalloff>
118 <LightIntensity>1</LightIntensity> 120 <LightIntensity>1</LightIntensity>
119 <FlexiEntry>false</FlexiEntry> 121 <FlexiEntry>false</FlexiEntry>
120 <LightEntry>false</LightEntry> 122 <LightEntry>false</LightEntry>
121 <SculptEntry>false</SculptEntry> 123 <SculptEntry>false</SculptEntry>
122 </Shape> 124 </Shape>
123 <Scale><X>10</X><Y>10</Y><Z>0.5</Z></Scale> 125 <Scale><X>10</X><Y>10</Y><Z>0.5</Z></Scale>
124 <UpdateFlag>0</UpdateFlag> 126 <UpdateFlag>0</UpdateFlag>
125 <SitTargetOrientation><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientation> 127 <SitTargetOrientation><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientation>
126 <SitTargetPosition><X>0</X><Y>0</Y><Z>0</Z></SitTargetPosition> 128 <SitTargetPosition><X>0</X><Y>0</Y><Z>0</Z></SitTargetPosition>
127 <SitTargetPositionLL><X>0</X><Y>0</Y><Z>0</Z></SitTargetPositionLL> 129 <SitTargetPositionLL><X>0</X><Y>0</Y><Z>0</Z></SitTargetPositionLL>
128 <SitTargetOrientationLL><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientationLL> 130 <SitTargetOrientationLL><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientationLL>
129 <ParentID>0</ParentID> 131 <ParentID>0</ParentID>
130 <CreationDate>1211330445</CreationDate> 132 <CreationDate>1211330445</CreationDate>
131 <Category>0</Category> 133 <Category>0</Category>
132 <SalePrice>0</SalePrice> 134 <SalePrice>0</SalePrice>
133 <ObjectSaleType>0</ObjectSaleType> 135 <ObjectSaleType>0</ObjectSaleType>
134 <OwnershipCost>0</OwnershipCost> 136 <OwnershipCost>0</OwnershipCost>
135 <GroupID><Guid>00000000-0000-0000-0000-000000000000</Guid></GroupID> 137 <GroupID><Guid>00000000-0000-0000-0000-000000000000</Guid></GroupID>
136 <OwnerID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></OwnerID> 138 <OwnerID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></OwnerID>
137 <LastOwnerID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></LastOwnerID> 139 <LastOwnerID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></LastOwnerID>
138 <BaseMask>2147483647</BaseMask> 140 <BaseMask>2147483647</BaseMask>
139 <OwnerMask>2147483647</OwnerMask> 141 <OwnerMask>2147483647</OwnerMask>
140 <GroupMask>0</GroupMask> 142 <GroupMask>0</GroupMask>
141 <EveryoneMask>0</EveryoneMask> 143 <EveryoneMask>0</EveryoneMask>
142 <NextOwnerMask>2147483647</NextOwnerMask> 144 <NextOwnerMask>2147483647</NextOwnerMask>
143 <Flags>None</Flags> 145 <Flags>None</Flags>
144 <CollisionSound><Guid>00000000-0000-0000-0000-000000000000</Guid></CollisionSound> 146 <CollisionSound><Guid>00000000-0000-0000-0000-000000000000</Guid></CollisionSound>
145 <CollisionSoundVolume>0</CollisionSoundVolume> 147 <CollisionSoundVolume>0</CollisionSoundVolume>
146 </SceneObjectPart> 148 <DynAttrs>
147 </RootPart> 149 <llsd>
148 <OtherParts /> 150 <map>
149 </SceneObjectGroup>"; 151 <key>MyNamespace</key>
150 152 <map>
151 private string badFloatsXml = @" 153 <key>MyStore</key>
154 <map>
155 <key>the answer</key>
156 <integer>42</integer>
157 </map>
158 </map>
159 </map>
160 </llsd>
161 </DynAttrs>
162 </SceneObjectPart>
163 </RootPart>";
164
165 private const string ObjectWithNoOtherPartsXml = ObjectRootPartStubXml +
166@"
167 <OtherParts />
168</SceneObjectGroup>";
169
170 private const string ObjectWithOtherPartsXml = ObjectRootPartStubXml +
171@"
172 <OtherParts>
173 <Part>
174 <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
175 <AllowedDrop>false</AllowedDrop>
176 <CreatorID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></CreatorID>
177 <FolderID><Guid>9958feb1-02a6-49e4-a4ce-eba6f578ee13</Guid></FolderID>
178 <InventorySerial>3</InventorySerial>
179 <UUID><Guid>9958feb1-02a6-49e4-a4ce-eba6f578ee13</Guid></UUID>
180 <LocalId>1154704500</LocalId>
181 <Name>Alien Head 1</Name>
182 <Material>3</Material>
183 <PassTouches>false</PassTouches>
184 <PassCollisions>false</PassCollisions>
185 <RegionHandle>21990232560640000</RegionHandle>
186 <ScriptAccessPin>0</ScriptAccessPin>
187 <GroupPosition><X>125.5655</X><Y>127.346</Y><Z>22.48036</Z></GroupPosition>
188 <OffsetPosition><X>-0.2171936</X><Y>0.1083984</Y><Z>0.0009994507</Z></OffsetPosition>
189 <RotationOffset><X>-0.5122106</X><Y>0.4851225</Y><Z>-0.4957454</Z><W>0.5064908</W></RotationOffset>
190 <Velocity><X>0</X><Y>0</Y><Z>0</Z></Velocity>
191 <AngularVelocity><X>0</X><Y>0</Y><Z>0</Z></AngularVelocity>
192 <Acceleration><X>0</X><Y>0</Y><Z>0</Z></Acceleration>
193 <Description>(No Description)</Description>
194 <Color><R>0</R><G>0</G><B>0</B><A>255</A></Color>
195 <Text/>
196 <SitName/>
197 <TouchName/>
198 <LinkNum>253</LinkNum>
199 <ClickAction>0</ClickAction>
200 <Shape>
201 <ProfileCurve>5</ProfileCurve>
202 <TextureEntry>Vw3dpvgTRUOiIUOGsnpWlAB/f38AAAAAgL8AAACAPwAAAAAAAAAF4ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</TextureEntry>
203 <ExtraParams>AA==</ExtraParams>
204 <PathBegin>0</PathBegin>
205 <PathCurve>32</PathCurve>
206 <PathEnd>0</PathEnd>
207 <PathRadiusOffset>0</PathRadiusOffset>
208 <PathRevolutions>0</PathRevolutions>
209 <PathScaleX>100</PathScaleX>
210 <PathScaleY>100</PathScaleY>
211 <PathShearX>0</PathShearX>
212 <PathShearY>0</PathShearY>
213 <PathSkew>0</PathSkew>
214 <PathTaperX>0</PathTaperX>
215 <PathTaperY>0</PathTaperY>
216 <PathTwist>0</PathTwist>
217 <PathTwistBegin>0</PathTwistBegin>
218 <PCode>9</PCode>
219 <ProfileBegin>0</ProfileBegin>
220 <ProfileEnd>0</ProfileEnd>
221 <ProfileHollow>0</ProfileHollow>
222 <State>9</State>
223 <LastAttachPoint>0</LastAttachPoint>
224 <ProfileShape>HalfCircle</ProfileShape>
225 <HollowShape>Same</HollowShape>
226 <SculptTexture><Guid>00000000-0000-0000-0000-000000000000</Guid></SculptTexture>
227 <SculptType>0</SculptType>
228 <FlexiSoftness>0</FlexiSoftness>
229 <FlexiTension>0</FlexiTension>
230 <FlexiDrag>0</FlexiDrag>
231 <FlexiGravity>0</FlexiGravity>
232 <FlexiWind>0</FlexiWind>
233 <FlexiForceX>0</FlexiForceX>
234 <FlexiForceY>0</FlexiForceY>
235 <FlexiForceZ>0</FlexiForceZ>
236 <LightColorR>0</LightColorR>
237 <LightColorG>0</LightColorG>
238 <LightColorB>0</LightColorB>
239 <LightColorA>1</LightColorA>
240 <LightRadius>0</LightRadius>
241 <LightCutoff>0</LightCutoff>
242 <LightFalloff>0</LightFalloff>
243 <LightIntensity>1</LightIntensity>
244 <FlexiEntry>false</FlexiEntry>
245 <LightEntry>false</LightEntry>
246 <SculptEntry>false</SculptEntry>
247 </Shape>
248 <Scale><X>0.1148195</X><Y>0.0143891</Y><Z>0.02768878</Z></Scale>
249 <SitTargetOrientation><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientation>
250 <SitTargetPosition><X>0</X><Y>0</Y><Z>0</Z></SitTargetPosition>
251 <SitTargetPositionLL><X>0</X><Y>0</Y><Z>0</Z></SitTargetPositionLL>
252 <SitTargetOrientationLL><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientationLL>
253 <ParentID>1154704499</ParentID>
254 <CreationDate>1256611042</CreationDate>
255 <Category>0</Category>
256 <SalePrice>10</SalePrice>
257 <ObjectSaleType>0</ObjectSaleType>
258 <OwnershipCost>0</OwnershipCost>
259 <GroupID><Guid>00000000-0000-0000-0000-000000000000</Guid></GroupID>
260 <OwnerID><Guid>7b2022f0-5f19-488c-b7e5-829d8f96b448</Guid></OwnerID>
261 <LastOwnerID><Guid>7b2022f0-5f19-488c-b7e5-829d8f96b448</Guid></LastOwnerID>
262 <BaseMask>647168</BaseMask>
263 <OwnerMask>647168</OwnerMask>
264 <GroupMask>0</GroupMask>
265 <EveryoneMask>0</EveryoneMask>
266 <NextOwnerMask>581632</NextOwnerMask>
267 <Flags>None</Flags>
268 <CollisionSound><Guid>00000000-0000-0000-0000-000000000000</Guid></CollisionSound>
269 <CollisionSoundVolume>0</CollisionSoundVolume>
270 <AttachedPos><X>0</X><Y>0</Y><Z>0</Z></AttachedPos>
271 <TextureAnimation/>
272 <ParticleSystem/>
273 <PayPrice0>-2</PayPrice0>
274 <PayPrice1>-2</PayPrice1>
275 <PayPrice2>-2</PayPrice2>
276 <PayPrice3>-2</PayPrice3>
277 <PayPrice4>-2</PayPrice4>
278 </SceneObjectPart>
279 </Part>
280 <Part>
281 <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
282 <AllowedDrop>false</AllowedDrop>
283 <CreatorID><Guid>a6dacf01-4636-4bb9-8a97-30609438af9d</Guid></CreatorID>
284 <FolderID><Guid>674b6b86-f5aa-439a-8e00-0d75bc08c80a</Guid></FolderID>
285 <InventorySerial>3</InventorySerial>
286 <UUID><Guid>674b6b86-f5aa-439a-8e00-0d75bc08c80a</Guid></UUID>
287 <LocalId>1154704501</LocalId>
288 <Name>Alien Head 2</Name>
289 <Material>3</Material>
290 <PassTouches>false</PassTouches>
291 <PassCollisions>false</PassCollisions>
292 <RegionHandle>21990232560640000</RegionHandle>
293 <ScriptAccessPin>0</ScriptAccessPin>
294 <GroupPosition><X>125.5655</X><Y>127.346</Y><Z>22.48036</Z></GroupPosition>
295 <OffsetPosition><X>-0.2490997</X><Y>0.08520126</Y><Z>0.0009002686</Z></OffsetPosition>
296 <RotationOffset><X>-0.4765368</X><Y>0.5194498</Y><Z>-0.5301372</Z><W>0.4712104</W></RotationOffset>
297 <Velocity><X>0</X><Y>0</Y><Z>0</Z></Velocity>
298 <AngularVelocity><X>0</X><Y>0</Y><Z>0</Z></AngularVelocity>
299 <Acceleration><X>0</X><Y>0</Y><Z>0</Z></Acceleration>
300 <Description>(No Description)</Description>
301 <Color><R>0</R><G>0</G><B>0</B><A>255</A></Color>
302 <Text/>
303 <SitName/>
304 <TouchName/>
305 <LinkNum>252</LinkNum>
306 <ClickAction>0</ClickAction>
307 <Shape>
308 <ProfileCurve>0</ProfileCurve>
309 <TextureEntry>Vw3dpvgTRUOiIUOGsnpWlAB/f38AAAAAgL8AAACAPwAAAAAAAAAF4ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</TextureEntry>
310 <ExtraParams>AA==</ExtraParams>
311 <PathBegin>0</PathBegin>
312 <PathCurve>32</PathCurve>
313 <PathEnd>0</PathEnd>
314 <PathRadiusOffset>0</PathRadiusOffset>
315 <PathRevolutions>0</PathRevolutions>
316 <PathScaleX>100</PathScaleX>
317 <PathScaleY>150</PathScaleY>
318 <PathShearX>0</PathShearX>
319 <PathShearY>0</PathShearY>
320 <PathSkew>0</PathSkew>
321 <PathTaperX>0</PathTaperX>
322 <PathTaperY>0</PathTaperY>
323 <PathTwist>0</PathTwist>
324 <PathTwistBegin>0</PathTwistBegin>
325 <PCode>9</PCode>
326 <ProfileBegin>0</ProfileBegin>
327 <ProfileEnd>0</ProfileEnd>
328 <ProfileHollow>0</ProfileHollow>
329 <State>9</State>
330 <LastAttachPoint>0</LastAttachPoint>
331 <ProfileShape>Circle</ProfileShape>
332 <HollowShape>Same</HollowShape>
333 <SculptTexture><Guid>00000000-0000-0000-0000-000000000000</Guid></SculptTexture>
334 <SculptType>0</SculptType>
335 <FlexiSoftness>0</FlexiSoftness>
336 <FlexiTension>0</FlexiTension>
337 <FlexiDrag>0</FlexiDrag>
338 <FlexiGravity>0</FlexiGravity>
339 <FlexiWind>0</FlexiWind>
340 <FlexiForceX>0</FlexiForceX>
341 <FlexiForceY>0</FlexiForceY>
342 <FlexiForceZ>0</FlexiForceZ>
343 <LightColorR>0</LightColorR>
344 <LightColorG>0</LightColorG>
345 <LightColorB>0</LightColorB>
346 <LightColorA>1</LightColorA>
347 <LightRadius>0</LightRadius>
348 <LightCutoff>0</LightCutoff>
349 <LightFalloff>0</LightFalloff>
350 <LightIntensity>1</LightIntensity>
351 <FlexiEntry>false</FlexiEntry>
352 <LightEntry>false</LightEntry>
353 <SculptEntry>false</SculptEntry>
354 </Shape>
355 <Scale><X>0.03574385</X><Y>0.05958032</Y><Z>0.04764182</Z></Scale>
356 <SitTargetOrientation><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientation>
357 <SitTargetPosition><X>0</X><Y>0</Y><Z>0</Z></SitTargetPosition>
358 <SitTargetPositionLL><X>0</X><Y>0</Y><Z>0</Z></SitTargetPositionLL>
359 <SitTargetOrientationLL><X>0</X><Y>0</Y><Z>0</Z><W>1</W></SitTargetOrientationLL>
360 <ParentID>1154704499</ParentID>
361 <CreationDate>1256611042</CreationDate>
362 <Category>0</Category>
363 <SalePrice>10</SalePrice>
364 <ObjectSaleType>0</ObjectSaleType>
365 <OwnershipCost>0</OwnershipCost>
366 <GroupID><Guid>00000000-0000-0000-0000-000000000000</Guid></GroupID>
367 <OwnerID><Guid>7b2022f0-5f19-488c-b7e5-829d8f96b448</Guid></OwnerID>
368 <LastOwnerID><Guid>7b2022f0-5f19-488c-b7e5-829d8f96b448</Guid></LastOwnerID>
369 <BaseMask>647168</BaseMask>
370 <OwnerMask>647168</OwnerMask>
371 <GroupMask>0</GroupMask>
372 <EveryoneMask>0</EveryoneMask>
373 <NextOwnerMask>581632</NextOwnerMask>
374 <Flags>None</Flags>
375 <CollisionSound><Guid>00000000-0000-0000-0000-000000000000</Guid></CollisionSound>
376 <CollisionSoundVolume>0</CollisionSoundVolume>
377 <AttachedPos><X>0</X><Y>0</Y><Z>0</Z></AttachedPos>
378 <TextureAnimation/>
379 <ParticleSystem/>
380 <PayPrice0>-2</PayPrice0>
381 <PayPrice1>-2</PayPrice1>
382 <PayPrice2>-2</PayPrice2>
383 <PayPrice3>-2</PayPrice3>
384 <PayPrice4>-2</PayPrice4>
385 </SceneObjectPart>
386 </Part>
387 </OtherParts>
388</SceneObjectGroup>";
389
390 private const string ObjectWithBadFloatsXml = @"
152 <SceneObjectGroup> 391 <SceneObjectGroup>
153 <RootPart> 392 <RootPart>
154 <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> 393 <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
@@ -255,7 +494,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
255 <OtherParts /> 494 <OtherParts />
256 </SceneObjectGroup>"; 495 </SceneObjectGroup>";
257 496
258 private string xml2 = @" 497 private const string ObjectWithNoPartsXml2 = @"
259 <SceneObjectGroup> 498 <SceneObjectGroup>
260 <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> 499 <SceneObjectPart xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
261 <CreatorID><UUID>b46ef588-411e-4a8b-a284-d7dcfe8e74ef</UUID></CreatorID> 500 <CreatorID><UUID>b46ef588-411e-4a8b-a284-d7dcfe8e74ef</UUID></CreatorID>
@@ -331,6 +570,20 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
331 <EveryoneMask>0</EveryoneMask> 570 <EveryoneMask>0</EveryoneMask>
332 <NextOwnerMask>2147483647</NextOwnerMask> 571 <NextOwnerMask>2147483647</NextOwnerMask>
333 <Flags>None</Flags> 572 <Flags>None</Flags>
573 <DynAttrs>
574 <llsd>
575 <map>
576 <key>MyNamespace</key>
577 <map>
578 <key>MyStore</key>
579 <map>
580 <key>last words</key>
581 <string>Rosebud</string>
582 </map>
583 </map>
584 </map>
585 </llsd>
586 </DynAttrs>
334 <SitTargetAvatar><UUID>00000000-0000-0000-0000-000000000000</UUID></SitTargetAvatar> 587 <SitTargetAvatar><UUID>00000000-0000-0000-0000-000000000000</UUID></SitTargetAvatar>
335 </SceneObjectPart> 588 </SceneObjectPart>
336 <OtherParts /> 589 <OtherParts />
@@ -348,17 +601,58 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
348 } 601 }
349 602
350 [Test] 603 [Test]
351 public void TestDeserializeXml() 604 public void TestDeserializeXmlObjectWithNoOtherParts()
352 { 605 {
353 TestHelpers.InMethod(); 606 TestHelpers.InMethod();
354 //log4net.Config.XmlConfigurator.Configure(); 607 TestHelpers.EnableLogging();
355 608
356 SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(xml); 609 SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(ObjectWithNoOtherPartsXml);
357 SceneObjectPart rootPart = so.RootPart; 610 SceneObjectPart rootPart = so.RootPart;
358 611
359 Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790"))); 612 Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790")));
360 Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d"))); 613 Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d")));
361 Assert.That(rootPart.Name, Is.EqualTo("PrimMyRide")); 614 Assert.That(rootPart.Name, Is.EqualTo("PrimMyRide"));
615 OSDMap store = rootPart.DynAttrs.GetStore("MyNamespace", "MyStore");
616 Assert.AreEqual(42, store["the answer"].AsInteger());
617
618 // TODO: Check other properties
619 }
620
621 [Test]
622 public void TestDeserializeXmlObjectWithOtherParts()
623 {
624 TestHelpers.InMethod();
625 TestHelpers.EnableLogging();
626
627 SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(ObjectWithOtherPartsXml);
628 SceneObjectPart[] parts = so.Parts;
629 Assert.AreEqual(3, so.Parts.Length);
630
631 {
632 SceneObjectPart part = parts[0];
633
634 Assert.That(part.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790")));
635 Assert.That(part.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d")));
636 Assert.That(part.Name, Is.EqualTo("PrimMyRide"));
637 OSDMap store = part.DynAttrs.GetStore("MyNamespace", "MyStore");
638 Assert.AreEqual(42, store["the answer"].AsInteger());
639 }
640
641 {
642 SceneObjectPart part = parts[1];
643
644 Assert.That(part.UUID, Is.EqualTo(new UUID("9958feb1-02a6-49e4-a4ce-eba6f578ee13")));
645 Assert.That(part.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d")));
646 Assert.That(part.Name, Is.EqualTo("Alien Head 1"));
647 }
648
649 {
650 SceneObjectPart part = parts[2];
651
652 Assert.That(part.UUID, Is.EqualTo(new UUID("674b6b86-f5aa-439a-8e00-0d75bc08c80a")));
653 Assert.That(part.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d")));
654 Assert.That(part.Name, Is.EqualTo("Alien Head 2"));
655 }
362 656
363 // TODO: Check other properties 657 // TODO: Check other properties
364 } 658 }
@@ -369,7 +663,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
369 TestHelpers.InMethod(); 663 TestHelpers.InMethod();
370// log4net.Config.XmlConfigurator.Configure(); 664// log4net.Config.XmlConfigurator.Configure();
371 665
372 SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(badFloatsXml); 666 SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(ObjectWithBadFloatsXml);
373 SceneObjectPart rootPart = so.RootPart; 667 SceneObjectPart rootPart = so.RootPart;
374 668
375 Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790"))); 669 Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790")));
@@ -409,6 +703,15 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
409 rp.CreatorID = rpCreatorId; 703 rp.CreatorID = rpCreatorId;
410 rp.Shape = shape; 704 rp.Shape = shape;
411 705
706 string daNamespace = "MyNamespace";
707 string daStoreName = "MyStore";
708 string daKey = "foo";
709 string daValue = "bar";
710 OSDMap myStore = new OSDMap();
711 myStore.Add(daKey, daValue);
712 rp.DynAttrs = new DAMap();
713 rp.DynAttrs.SetStore(daNamespace, daStoreName, myStore);
714
412 SceneObjectGroup so = new SceneObjectGroup(rp); 715 SceneObjectGroup so = new SceneObjectGroup(rp);
413 716
414 // Need to add the object to the scene so that the request to get script state succeeds 717 // Need to add the object to the scene so that the request to get script state succeeds
@@ -424,6 +727,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
424 UUID uuid = UUID.Zero; 727 UUID uuid = UUID.Zero;
425 string name = null; 728 string name = null;
426 UUID creatorId = UUID.Zero; 729 UUID creatorId = UUID.Zero;
730 DAMap daMap = null;
427 731
428 while (xtr.Read() && xtr.Name != "SceneObjectPart") 732 while (xtr.Read() && xtr.Name != "SceneObjectPart")
429 { 733 {
@@ -449,6 +753,10 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
449 creatorId = UUID.Parse(xtr.ReadElementString("UUID")); 753 creatorId = UUID.Parse(xtr.ReadElementString("UUID"));
450 xtr.ReadEndElement(); 754 xtr.ReadEndElement();
451 break; 755 break;
756 case "DynAttrs":
757 daMap = new DAMap();
758 daMap.ReadXml(xtr);
759 break;
452 } 760 }
453 } 761 }
454 762
@@ -462,6 +770,8 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
462 Assert.That(uuid, Is.EqualTo(rpUuid)); 770 Assert.That(uuid, Is.EqualTo(rpUuid));
463 Assert.That(name, Is.EqualTo(rpName)); 771 Assert.That(name, Is.EqualTo(rpName));
464 Assert.That(creatorId, Is.EqualTo(rpCreatorId)); 772 Assert.That(creatorId, Is.EqualTo(rpCreatorId));
773 Assert.NotNull(daMap);
774 Assert.AreEqual(daValue, daMap.GetStore(daNamespace, daStoreName)[daKey].AsString());
465 } 775 }
466 776
467 [Test] 777 [Test]
@@ -470,12 +780,14 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
470 TestHelpers.InMethod(); 780 TestHelpers.InMethod();
471 //log4net.Config.XmlConfigurator.Configure(); 781 //log4net.Config.XmlConfigurator.Configure();
472 782
473 SceneObjectGroup so = m_serialiserModule.DeserializeGroupFromXml2(xml2); 783 SceneObjectGroup so = m_serialiserModule.DeserializeGroupFromXml2(ObjectWithNoPartsXml2);
474 SceneObjectPart rootPart = so.RootPart; 784 SceneObjectPart rootPart = so.RootPart;
475 785
476 Assert.That(rootPart.UUID, Is.EqualTo(new UUID("9be68fdd-f740-4a0f-9675-dfbbb536b946"))); 786 Assert.That(rootPart.UUID, Is.EqualTo(new UUID("9be68fdd-f740-4a0f-9675-dfbbb536b946")));
477 Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("b46ef588-411e-4a8b-a284-d7dcfe8e74ef"))); 787 Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("b46ef588-411e-4a8b-a284-d7dcfe8e74ef")));
478 Assert.That(rootPart.Name, Is.EqualTo("PrimFun")); 788 Assert.That(rootPart.Name, Is.EqualTo("PrimFun"));
789 OSDMap store = rootPart.DynAttrs.GetStore("MyNamespace", "MyStore");
790 Assert.AreEqual("Rosebud", store["last words"].AsString());
479 791
480 // TODO: Check other properties 792 // TODO: Check other properties
481 } 793 }
@@ -500,6 +812,15 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
500 rp.CreatorID = rpCreatorId; 812 rp.CreatorID = rpCreatorId;
501 rp.Shape = shape; 813 rp.Shape = shape;
502 814
815 string daNamespace = "MyNamespace";
816 string daStoreName = "MyStore";
817 string daKey = "foo";
818 string daValue = "bar";
819 OSDMap myStore = new OSDMap();
820 myStore.Add(daKey, daValue);
821 rp.DynAttrs = new DAMap();
822 rp.DynAttrs.SetStore(daNamespace, daStoreName, myStore);
823
503 SceneObjectGroup so = new SceneObjectGroup(rp); 824 SceneObjectGroup so = new SceneObjectGroup(rp);
504 825
505 // Need to add the object to the scene so that the request to get script state succeeds 826 // Need to add the object to the scene so that the request to get script state succeeds
@@ -516,6 +837,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
516 UUID uuid = UUID.Zero; 837 UUID uuid = UUID.Zero;
517 string name = null; 838 string name = null;
518 UUID creatorId = UUID.Zero; 839 UUID creatorId = UUID.Zero;
840 DAMap daMap = null;
519 841
520 while (xtr.Read() && xtr.Name != "SceneObjectPart") 842 while (xtr.Read() && xtr.Name != "SceneObjectPart")
521 { 843 {
@@ -537,6 +859,10 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
537 creatorId = UUID.Parse(xtr.ReadElementString("Guid")); 859 creatorId = UUID.Parse(xtr.ReadElementString("Guid"));
538 xtr.ReadEndElement(); 860 xtr.ReadEndElement();
539 break; 861 break;
862 case "DynAttrs":
863 daMap = new DAMap();
864 daMap.ReadXml(xtr);
865 break;
540 } 866 }
541 } 867 }
542 868
@@ -549,6 +875,8 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
549 Assert.That(uuid, Is.EqualTo(rpUuid)); 875 Assert.That(uuid, Is.EqualTo(rpUuid));
550 Assert.That(name, Is.EqualTo(rpName)); 876 Assert.That(name, Is.EqualTo(rpName));
551 Assert.That(creatorId, Is.EqualTo(rpCreatorId)); 877 Assert.That(creatorId, Is.EqualTo(rpCreatorId));
878 Assert.NotNull(daMap);
879 Assert.AreEqual(daValue, daMap.GetStore(daNamespace, daStoreName)[daKey].AsString());
552 } 880 }
553 } 881 }
554} \ No newline at end of file 882} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
index 883045a..d093224 100644
--- a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
+++ b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
@@ -369,6 +369,15 @@ namespace OpenSim.Region.CoreModules.World.Sound
369 }); 369 });
370 } 370 }
371 371
372 public void SetSoundQueueing(UUID objectID, bool shouldQueue)
373 {
374 SceneObjectPart part;
375 if (!m_scene.TryGetSceneObjectPart(objectID, out part))
376 return;
377
378 part.SoundQueueing = shouldQueue;
379 }
380
372 #endregion 381 #endregion
373 } 382 }
374} 383}
diff --git a/OpenSim/Region/CoreModules/World/Sun/SunModule.cs b/OpenSim/Region/CoreModules/World/Sun/SunModule.cs
index a321c09..d0318eb 100644
--- a/OpenSim/Region/CoreModules/World/Sun/SunModule.cs
+++ b/OpenSim/Region/CoreModules/World/Sun/SunModule.cs
@@ -68,9 +68,6 @@ namespace OpenSim.Region.CoreModules
68 // updating those region settings in GenSunPos() 68 // updating those region settings in GenSunPos()
69 private bool receivedEstateToolsSunUpdate = false; 69 private bool receivedEstateToolsSunUpdate = false;
70 70
71 // Configurable values
72 private string m_RegionMode = "SL";
73
74 // Sun's position information is updated and sent to clients every m_UpdateInterval frames 71 // Sun's position information is updated and sent to clients every m_UpdateInterval frames
75 private int m_UpdateInterval = 0; 72 private int m_UpdateInterval = 0;
76 73
@@ -90,7 +87,6 @@ namespace OpenSim.Region.CoreModules
90 // private double m_longitude = 0; 87 // private double m_longitude = 0;
91 // private double m_latitude = 0; 88 // private double m_latitude = 0;
92 // Configurable defaults Defaults close to SL 89 // Configurable defaults Defaults close to SL
93 private string d_mode = "SL";
94 private int d_frame_mod = 100; // Every 10 seconds (actually less) 90 private int d_frame_mod = 100; // Every 10 seconds (actually less)
95 private double d_day_length = 4; // A VW day is 4 RW hours long 91 private double d_day_length = 4; // A VW day is 4 RW hours long
96 private int d_year_length = 60; // There are 60 VW days in a VW year 92 private int d_year_length = 60; // There are 60 VW days in a VW year
@@ -134,12 +130,15 @@ namespace OpenSim.Region.CoreModules
134 130
135 private const int TICKS_PER_SECOND = 10000000; 131 private const int TICKS_PER_SECOND = 10000000;
136 132
133 private ulong m_CurrentTimeOffset = 0;
134
137 // Current time in elapsed seconds since Jan 1st 1970 135 // Current time in elapsed seconds since Jan 1st 1970
138 private ulong CurrentTime 136 private ulong CurrentTime
139 { 137 {
140 get 138 get
141 { 139 {
142 return (ulong)(((DateTime.Now.Ticks) - TicksToEpoch + TicksUTCOffset) / TICKS_PER_SECOND); 140 ulong ctime = (ulong)(((DateTime.Now.Ticks) - TicksToEpoch + TicksUTCOffset) / TICKS_PER_SECOND);
141 return ctime + m_CurrentTimeOffset;
143 } 142 }
144 } 143 }
145 144
@@ -252,21 +251,18 @@ namespace OpenSim.Region.CoreModules
252 } 251 }
253 252
254 // TODO: Decouple this, so we can get rid of Linden Hour info 253 // TODO: Decouple this, so we can get rid of Linden Hour info
255 // Update Region infor with new Sun Position and Hour 254 // Update Region with new Sun Vector
256 // set estate settings for region access to sun position 255 // set estate settings for region access to sun position
257 if (receivedEstateToolsSunUpdate) 256 if (receivedEstateToolsSunUpdate)
258 { 257 {
259 m_scene.RegionInfo.RegionSettings.SunVector = Position; 258 m_scene.RegionInfo.RegionSettings.SunVector = Position;
260 m_scene.RegionInfo.RegionSettings.SunPosition = GetCurrentTimeAsLindenSunHour();
261 } 259 }
262 } 260 }
263 261
264 private float GetCurrentTimeAsLindenSunHour() 262 private float GetCurrentTimeAsLindenSunHour()
265 { 263 {
266 if (m_SunFixed) 264 float curtime = m_SunFixed ? m_SunFixedHour : GetCurrentSunHour();
267 return m_SunFixedHour + 6; 265 return (curtime + 6.0f) % 24.0f;
268
269 return GetCurrentSunHour() + 6.0f;
270 } 266 }
271 267
272 #region INonSharedRegion Methods 268 #region INonSharedRegion Methods
@@ -292,8 +288,6 @@ namespace OpenSim.Region.CoreModules
292 try 288 try
293 { 289 {
294 // Mode: determines how the sun is handled 290 // Mode: determines how the sun is handled
295 m_RegionMode = config.Configs["Sun"].GetString("mode", d_mode);
296 // Mode: determines how the sun is handled
297 // m_latitude = config.Configs["Sun"].GetDouble("latitude", d_latitude); 291 // m_latitude = config.Configs["Sun"].GetDouble("latitude", d_latitude);
298 // Mode: determines how the sun is handled 292 // Mode: determines how the sun is handled
299 // m_longitude = config.Configs["Sun"].GetDouble("longitude", d_longitude); 293 // m_longitude = config.Configs["Sun"].GetDouble("longitude", d_longitude);
@@ -315,7 +309,6 @@ namespace OpenSim.Region.CoreModules
315 catch (Exception e) 309 catch (Exception e)
316 { 310 {
317 m_log.Debug("[SUN]: Configuration access failed, using defaults. Reason: " + e.Message); 311 m_log.Debug("[SUN]: Configuration access failed, using defaults. Reason: " + e.Message);
318 m_RegionMode = d_mode;
319 m_YearLengthDays = d_year_length; 312 m_YearLengthDays = d_year_length;
320 m_DayLengthHours = d_day_length; 313 m_DayLengthHours = d_day_length;
321 m_HorizonShift = d_day_night; 314 m_HorizonShift = d_day_night;
@@ -326,40 +319,28 @@ namespace OpenSim.Region.CoreModules
326 // m_longitude = d_longitude; 319 // m_longitude = d_longitude;
327 } 320 }
328 321
329 switch (m_RegionMode) 322 SecondsPerSunCycle = (uint) (m_DayLengthHours * 60 * 60);
330 { 323 SecondsPerYear = (uint) (SecondsPerSunCycle*m_YearLengthDays);
331 case "T1":
332 default:
333 case "SL":
334 // Time taken to complete a cycle (day and season)
335
336 SecondsPerSunCycle = (uint) (m_DayLengthHours * 60 * 60);
337 SecondsPerYear = (uint) (SecondsPerSunCycle*m_YearLengthDays);
338
339 // Ration of real-to-virtual time
340 324
341 // VWTimeRatio = 24/m_day_length; 325 // Ration of real-to-virtual time
342 326
343 // Speed of rotation needed to complete a cycle in the 327 // VWTimeRatio = 24/m_day_length;
344 // designated period (day and season)
345 328
346 SunSpeed = m_SunCycle/SecondsPerSunCycle; 329 // Speed of rotation needed to complete a cycle in the
347 SeasonSpeed = m_SeasonalCycle/SecondsPerYear; 330 // designated period (day and season)
348 331
349 // Horizon translation 332 SunSpeed = m_SunCycle/SecondsPerSunCycle;
333 SeasonSpeed = m_SeasonalCycle/SecondsPerYear;
350 334
351 HorizonShift = m_HorizonShift; // Z axis translation 335 // Horizon translation
352 // HoursToRadians = (SunCycle/24)*VWTimeRatio;
353 336
354 m_log.Debug("[SUN]: Mode is " + m_RegionMode); 337 HorizonShift = m_HorizonShift; // Z axis translation
355 m_log.Debug("[SUN]: Initialization completed. Day is " + SecondsPerSunCycle + " seconds, and year is " + m_YearLengthDays + " days"); 338 // HoursToRadians = (SunCycle/24)*VWTimeRatio;
356 m_log.Debug("[SUN]: Axis offset is " + m_HorizonShift);
357 m_log.Debug("[SUN]: Percentage of time for daylight " + m_DayTimeSunHourScale);
358 m_log.Debug("[SUN]: Positional data updated every " + m_UpdateInterval + " frames");
359
360 break;
361 }
362 339
340 m_log.Debug("[SUN]: Initialization completed. Day is " + SecondsPerSunCycle + " seconds, and year is " + m_YearLengthDays + " days");
341 m_log.Debug("[SUN]: Axis offset is " + m_HorizonShift);
342 m_log.Debug("[SUN]: Percentage of time for daylight " + m_DayTimeSunHourScale);
343 m_log.Debug("[SUN]: Positional data updated every " + m_UpdateInterval + " frames");
363 } 344 }
364 345
365 public Type ReplaceableInterface 346 public Type ReplaceableInterface
@@ -386,7 +367,8 @@ namespace OpenSim.Region.CoreModules
386 string sunCommand = string.Format("sun {0}", kvp.Key); 367 string sunCommand = string.Format("sun {0}", kvp.Key);
387 m_scene.AddCommand("Regions", this, sunCommand, string.Format("{0} [<value>]", sunCommand), kvp.Value, "", HandleSunConsoleCommand); 368 m_scene.AddCommand("Regions", this, sunCommand, string.Format("{0} [<value>]", sunCommand), kvp.Value, "", HandleSunConsoleCommand);
388 } 369 }
389 370 m_scene.AddCommand("Regions", this, "sun help", "sun help", "list parameters that can be changed", "", HandleSunConsoleCommand);
371 m_scene.AddCommand("Regions", this, "sun list", "sun list", "list parameters that can be changed", "", HandleSunConsoleCommand);
390 ready = true; 372 ready = true;
391 } 373 }
392 374
@@ -395,7 +377,7 @@ namespace OpenSim.Region.CoreModules
395 ready = false; 377 ready = false;
396 378
397 // Remove our hooks 379 // Remove our hooks
398 m_scene.EventManager.OnFrame -= SunUpdate; 380 m_scene.EventManager.OnFrame -= SunUpdate;
399 m_scene.EventManager.OnAvatarEnteringNewParcel -= AvatarEnteringParcel; 381 m_scene.EventManager.OnAvatarEnteringNewParcel -= AvatarEnteringParcel;
400 m_scene.EventManager.OnEstateToolsSunUpdate -= EstateToolsSunUpdate; 382 m_scene.EventManager.OnEstateToolsSunUpdate -= EstateToolsSunUpdate;
401 m_scene.EventManager.OnGetCurrentTimeAsLindenSunHour -= GetCurrentTimeAsLindenSunHour; 383 m_scene.EventManager.OnGetCurrentTimeAsLindenSunHour -= GetCurrentTimeAsLindenSunHour;
@@ -420,23 +402,22 @@ namespace OpenSim.Region.CoreModules
420 402
421 public void SunToClient(IClientAPI client) 403 public void SunToClient(IClientAPI client)
422 { 404 {
423 if (m_RegionMode != "T1") 405 if (ready)
424 { 406 {
425 if (ready) 407 if (m_SunFixed)
426 { 408 {
427 if (m_SunFixed) 409 // m_log.DebugFormat("[SUN]: Fixed SunHour {0}, Position {1}, PosTime {2}, OrbitalPosition : {3} ",
428 { 410 // m_SunFixedHour, Position.ToString(), PosTime.ToString(), OrbitalPosition.ToString());
429 // m_log.DebugFormat("[SUN]: SunHour {0}, Position {1}, PosTime {2}, OrbitalPosition : {3} ", m_SunFixedHour, Position.ToString(), PosTime.ToString(), OrbitalPosition.ToString()); 411 client.SendSunPos(Position, Velocity, PosTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition);
430 client.SendSunPos(Position, Velocity, PosTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition); 412 }
431 } 413 else
432 else 414 {
433 { 415 // m_log.DebugFormat("[SUN]: SunHour {0}, Position {1}, PosTime {2}, OrbitalPosition : {3} ",
434 // m_log.DebugFormat("[SUN]: SunHour {0}, Position {1}, PosTime {2}, OrbitalPosition : {3} ", m_SunFixedHour, Position.ToString(), PosTime.ToString(), OrbitalPosition.ToString()); 416 // m_SunFixedHour, Position.ToString(), PosTime.ToString(), OrbitalPosition.ToString());
435 client.SendSunPos(Position, Velocity, CurrentTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition); 417 client.SendSunPos(Position, Velocity, CurrentTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition);
436 }
437 } 418 }
438 } 419 }
439 } 420 }
440 421
441 public void SunUpdate() 422 public void SunUpdate()
442 { 423 {
@@ -459,26 +440,33 @@ namespace OpenSim.Region.CoreModules
459 SunToClient(avatar.ControllingClient); 440 SunToClient(avatar.ControllingClient);
460 } 441 }
461 442
462 /// <summary> 443 public void EstateToolsSunUpdate(ulong regionHandle)
463 ///
464 /// </summary>
465 /// <param name="regionHandle"></param>
466 /// <param name="FixedTime">Is the sun's position fixed?</param>
467 /// <param name="useEstateTime">Use the Region or Estate Sun hour?</param>
468 /// <param name="FixedSunHour">What hour of the day is the Sun Fixed at?</param>
469 public void EstateToolsSunUpdate(ulong regionHandle, bool FixedSun, bool useEstateTime, float FixedSunHour)
470 { 444 {
471 if (m_scene.RegionInfo.RegionHandle == regionHandle) 445 if (m_scene.RegionInfo.RegionHandle == regionHandle)
472 { 446 {
473 // Must limit the Sun Hour to 0 ... 24 447 float sunFixedHour;
474 while (FixedSunHour > 24.0f) 448 bool fixedSun;
475 FixedSunHour -= 24;
476 449
477 while (FixedSunHour < 0) 450 if (m_scene.RegionInfo.RegionSettings.UseEstateSun)
478 FixedSunHour += 24; 451 {
452 sunFixedHour = (float)m_scene.RegionInfo.EstateSettings.SunPosition;
453 fixedSun = m_scene.RegionInfo.EstateSettings.FixedSun;
454 }
455 else
456 {
457 sunFixedHour = (float)m_scene.RegionInfo.RegionSettings.SunPosition - 6.0f;
458 fixedSun = m_scene.RegionInfo.RegionSettings.FixedSun;
459 }
460
461 // Must limit the Sun Hour to 0 ... 24
462 while (sunFixedHour > 24.0f)
463 sunFixedHour -= 24;
479 464
480 m_SunFixedHour = FixedSunHour; 465 while (sunFixedHour < 0)
481 m_SunFixed = FixedSun; 466 sunFixedHour += 24;
467
468 m_SunFixedHour = sunFixedHour;
469 m_SunFixed = fixedSun;
482 470
483 // m_log.DebugFormat("[SUN]: Sun Settings Update: Fixed Sun? : {0}", m_SunFixed.ToString()); 471 // m_log.DebugFormat("[SUN]: Sun Settings Update: Fixed Sun? : {0}", m_SunFixed.ToString());
484 // m_log.DebugFormat("[SUN]: Sun Settings Update: Sun Hour : {0}", m_SunFixedHour.ToString()); 472 // m_log.DebugFormat("[SUN]: Sun Settings Update: Sun Hour : {0}", m_SunFixedHour.ToString());
@@ -501,7 +489,7 @@ namespace OpenSim.Region.CoreModules
501 { 489 {
502 m_scene.ForEachRootClient(delegate(IClientAPI client) 490 m_scene.ForEachRootClient(delegate(IClientAPI client)
503 { 491 {
504 SunToClient(client); 492 SunToClient(client);
505 }); 493 });
506 } 494 }
507 495
@@ -526,6 +514,9 @@ namespace OpenSim.Region.CoreModules
526 case "update_interval": 514 case "update_interval":
527 return m_UpdateInterval; 515 return m_UpdateInterval;
528 516
517 case "current_time":
518 return GetCurrentTimeAsLindenSunHour();
519
529 default: 520 default:
530 throw new Exception("Unknown sun parameter."); 521 throw new Exception("Unknown sun parameter.");
531 } 522 }
@@ -533,7 +524,51 @@ namespace OpenSim.Region.CoreModules
533 524
534 public void SetSunParameter(string param, double value) 525 public void SetSunParameter(string param, double value)
535 { 526 {
536 HandleSunConsoleCommand("sun", new string[] {param, value.ToString() }); 527 switch (param)
528 {
529 case "year_length":
530 m_YearLengthDays = (int)value;
531 SecondsPerYear = (uint) (SecondsPerSunCycle*m_YearLengthDays);
532 SeasonSpeed = m_SeasonalCycle/SecondsPerYear;
533 break;
534
535 case "day_length":
536 m_DayLengthHours = value;
537 SecondsPerSunCycle = (uint) (m_DayLengthHours * 60 * 60);
538 SecondsPerYear = (uint) (SecondsPerSunCycle*m_YearLengthDays);
539 SunSpeed = m_SunCycle/SecondsPerSunCycle;
540 SeasonSpeed = m_SeasonalCycle/SecondsPerYear;
541 break;
542
543 case "day_night_offset":
544 m_HorizonShift = value;
545 HorizonShift = m_HorizonShift;
546 break;
547
548 case "day_time_sun_hour_scale":
549 m_DayTimeSunHourScale = value;
550 break;
551
552 case "update_interval":
553 m_UpdateInterval = (int)value;
554 break;
555
556 case "current_time":
557 value = (value + 18.0) % 24.0;
558 // set the current offset so that the effective sun time is the parameter
559 m_CurrentTimeOffset = 0; // clear this first so we use raw time
560 m_CurrentTimeOffset = (ulong)(SecondsPerSunCycle * value/ 24.0) - (CurrentTime % SecondsPerSunCycle);
561 break;
562
563 default:
564 throw new Exception("Unknown sun parameter.");
565 }
566
567 // Generate shared values
568 GenSunPos();
569
570 // When sun settings are updated, we should update all clients with new settings.
571 SunUpdateToAllClients();
537 } 572 }
538 573
539 public float GetCurrentSunHour() 574 public float GetCurrentSunHour()
@@ -566,7 +601,7 @@ namespace OpenSim.Region.CoreModules
566 601
567 foreach (string output in ParseCmdParams(cmdparams)) 602 foreach (string output in ParseCmdParams(cmdparams))
568 { 603 {
569 m_log.Info("[SUN] " + output); 604 MainConsole.Instance.Output(output);
570 } 605 }
571 } 606 }
572 607
@@ -575,10 +610,11 @@ namespace OpenSim.Region.CoreModules
575 Dictionary<string, string> Params = new Dictionary<string, string>(); 610 Dictionary<string, string> Params = new Dictionary<string, string>();
576 611
577 Params.Add("year_length", "number of days to a year"); 612 Params.Add("year_length", "number of days to a year");
578 Params.Add("day_length", "number of seconds to a day"); 613 Params.Add("day_length", "number of hours to a day");
579 Params.Add("day_night_offset", "induces a horizon shift"); 614 Params.Add("day_night_offset", "induces a horizon shift");
580 Params.Add("update_interval", "how often to update the sun's position in frames"); 615 Params.Add("update_interval", "how often to update the sun's position in frames");
581 Params.Add("day_time_sun_hour_scale", "scales day light vs nite hours to change day/night ratio"); 616 Params.Add("day_time_sun_hour_scale", "scales day light vs nite hours to change day/night ratio");
617 Params.Add("current_time", "time in seconds of the simulator");
582 618
583 return Params; 619 return Params;
584 } 620 }
@@ -612,46 +648,15 @@ namespace OpenSim.Region.CoreModules
612 } 648 }
613 else if (args.Length == 3) 649 else if (args.Length == 3)
614 { 650 {
615 float value = 0.0f; 651 double value = 0.0;
616 if (!float.TryParse(args[2], out value)) 652 if (! double.TryParse(args[2], out value))
617 { 653 {
618 Output.Add(String.Format("The parameter value {0} is not a valid number.", args[2])); 654 Output.Add(String.Format("The parameter value {0} is not a valid number.", args[2]));
655 return Output;
619 } 656 }
620 657
621 switch (args[1].ToLower()) 658 SetSunParameter(args[1].ToLower(), value);
622 {
623 case "year_length":
624 m_YearLengthDays = (int)value;
625 break;
626
627 case "day_length":
628 m_DayLengthHours = value;
629 break;
630
631 case "day_night_offset":
632 m_HorizonShift = value;
633 break;
634
635 case "day_time_sun_hour_scale":
636 m_DayTimeSunHourScale = value;
637 break;
638
639 case "update_interval":
640 m_UpdateInterval = (int)value;
641 break;
642
643 default:
644 Output.Add(String.Format("Unknown parameter {0}.", args[1]));
645 return Output;
646 }
647
648 Output.Add(String.Format("Parameter {0} set to {1}.", args[1], value.ToString())); 659 Output.Add(String.Format("Parameter {0} set to {1}.", args[1], value.ToString()));
649
650 // Generate shared values
651 GenSunPos();
652
653 // When sun settings are updated, we should update all clients with new settings.
654 SunUpdateToAllClients();
655 } 660 }
656 661
657 return Output; 662 return Output;
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs b/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs
index 7186dd7..89087b1 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs
@@ -42,7 +42,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Effects
42 for (y = 0; y < map.Height; y++) 42 for (y = 0; y < map.Height; y++)
43 { 43 {
44 map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 3, 0.25) * 10; 44 map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 3, 0.25) * 10;
45 double spherFac = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2, Constants.RegionSize / 2, 50) * 0.01; 45 double spherFac = TerrainUtil.SphericalFactor(x, y, map.Width / 2, map.Height / 2, 50) * 0.01;
46 if (map[x, y] < spherFac) 46 if (map[x, y] < spherFac)
47 { 47 {
48 map[x, y] = spherFac; 48 map[x, y] = spherFac;
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs
index d78ade5..d5c77ec 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs
@@ -67,7 +67,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
67 { 67 {
68 using (Bitmap bitmap = new Bitmap(filename)) 68 using (Bitmap bitmap = new Bitmap(filename))
69 { 69 {
70 ITerrainChannel retval = new TerrainChannel(true); 70 ITerrainChannel retval = new TerrainChannel(w, h);
71 71
72 for (int x = 0; x < retval.Width; x++) 72 for (int x = 0; x < retval.Width; x++)
73 { 73 {
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs
index 62d232e..be1fb24 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.IO; 29using System.IO;
30using OpenSim.Framework;
30using OpenSim.Region.Framework.Interfaces; 31using OpenSim.Region.Framework.Interfaces;
31using OpenSim.Region.Framework.Scenes; 32using OpenSim.Region.Framework.Scenes;
32 33
@@ -73,12 +74,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
73 public ITerrainChannel LoadFile(string filename) 74 public ITerrainChannel LoadFile(string filename)
74 { 75 {
75 FileInfo file = new FileInfo(filename); 76 FileInfo file = new FileInfo(filename);
76 FileStream s = file.Open(FileMode.Open, FileAccess.Read);
77 ITerrainChannel retval = LoadStream(s);
78 77
79 s.Close(); 78 ITerrainChannel channel;
80 79
81 return retval; 80 using (FileStream s = file.Open(FileMode.Open, FileAccess.Read))
81 channel = LoadStream(s);
82
83 return channel;
82 } 84 }
83 85
84 public ITerrainChannel LoadFile(string filename, int offsetX, int offsetY, int fileWidth, int fileHeight, int sectionWidth, int sectionHeight) 86 public ITerrainChannel LoadFile(string filename, int offsetX, int offsetY, int fileWidth, int fileHeight, int sectionWidth, int sectionHeight)
@@ -86,153 +88,159 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
86 TerrainChannel retval = new TerrainChannel(sectionWidth, sectionHeight); 88 TerrainChannel retval = new TerrainChannel(sectionWidth, sectionHeight);
87 89
88 FileInfo file = new FileInfo(filename); 90 FileInfo file = new FileInfo(filename);
89 FileStream s = file.Open(FileMode.Open, FileAccess.Read);
90 BinaryReader bs = new BinaryReader(s);
91 91
92 int currFileYOffset = fileHeight - 1; 92 using (FileStream s = file.Open(FileMode.Open, FileAccess.Read))
93 93 using (BinaryReader bs = new BinaryReader(s))
94 // if our region isn't on the first Y section of the areas to be landscaped, then
95 // advance to our section of the file
96 while (currFileYOffset > offsetY)
97 { 94 {
98 // read a whole strip of regions 95 int currFileYOffset = fileHeight - 1;
99 int heightsToRead = sectionHeight * (fileWidth * sectionWidth);
100 bs.ReadBytes(heightsToRead * 13); // because there are 13 fun channels
101 currFileYOffset--;
102 }
103 96
104 // got to the Y start offset within the file of our region 97 // if our region isn't on the first Y section of the areas to be landscaped, then
105 // so read the file bits associated with our region 98 // advance to our section of the file
106 int y; 99 while (currFileYOffset > offsetY)
107 // for each Y within our Y offset
108 for (y = sectionHeight - 1; y >= 0; y--)
109 {
110 int currFileXOffset = 0;
111
112 // if our region isn't the first X section of the areas to be landscaped, then
113 // advance the stream to the X start pos of our section in the file
114 // i.e. eat X upto where we start
115 while (currFileXOffset < offsetX)
116 { 100 {
117 bs.ReadBytes(sectionWidth * 13); 101 // read a whole strip of regions
118 currFileXOffset++; 102 int heightsToRead = sectionHeight * (fileWidth * sectionWidth);
103 bs.ReadBytes(heightsToRead * 13); // because there are 13 fun channels
104 currFileYOffset--;
119 } 105 }
120 106
121 // got to our X offset, so write our regions X line 107 // got to the Y start offset within the file of our region
122 int x; 108 // so read the file bits associated with our region
123 for (x = 0; x < sectionWidth; x++) 109 int y;
124 {
125 // Read a strip and continue
126 retval[x, y] = bs.ReadByte() * (bs.ReadByte() / 128.0);
127 bs.ReadBytes(11);
128 }
129 // record that we wrote it
130 currFileXOffset++;
131 110
132 // if our region isn't the last X section of the areas to be landscaped, then 111 // for each Y within our Y offset
133 // advance the stream to the end of this Y column 112 for (y = sectionHeight - 1; y >= 0; y--)
134 while (currFileXOffset < fileWidth)
135 { 113 {
136 // eat the next regions x line 114 int currFileXOffset = 0;
137 bs.ReadBytes(sectionWidth * 13); //The 13 channels again 115
116 // if our region isn't the first X section of the areas to be landscaped, then
117 // advance the stream to the X start pos of our section in the file
118 // i.e. eat X upto where we start
119 while (currFileXOffset < offsetX)
120 {
121 bs.ReadBytes(sectionWidth * 13);
122 currFileXOffset++;
123 }
124
125 // got to our X offset, so write our regions X line
126 int x;
127 for (x = 0; x < sectionWidth; x++)
128 {
129 // Read a strip and continue
130 retval[x, y] = bs.ReadByte() * (bs.ReadByte() / 128.0);
131 bs.ReadBytes(11);
132 }
133 // record that we wrote it
138 currFileXOffset++; 134 currFileXOffset++;
135
136 // if our region isn't the last X section of the areas to be landscaped, then
137 // advance the stream to the end of this Y column
138 while (currFileXOffset < fileWidth)
139 {
140 // eat the next regions x line
141 bs.ReadBytes(sectionWidth * 13); //The 13 channels again
142 currFileXOffset++;
143 }
139 } 144 }
140 } 145 }
141 146
142 bs.Close();
143 s.Close();
144
145 return retval; 147 return retval;
146 } 148 }
147 149
148 public ITerrainChannel LoadStream(Stream s) 150 public ITerrainChannel LoadStream(Stream s)
149 { 151 {
150 TerrainChannel retval = new TerrainChannel(); 152 // The raw format doesn't contain any dimension information.
153 // Guess the square dimensions by using the length of the raw file.
154 double dimension = Math.Sqrt((double)(s.Length / 13));
155 // Regions are always multiples of 256.
156 int trimmedDimension = (int)dimension - ((int)dimension % (int)Constants.RegionSize);
157 if (trimmedDimension < Constants.RegionSize)
158 trimmedDimension = (int)Constants.RegionSize;
159
160 TerrainChannel retval = new TerrainChannel(trimmedDimension, trimmedDimension);
151 161
152 BinaryReader bs = new BinaryReader(s); 162 using (BinaryReader bs = new BinaryReader(s))
153 int y;
154 for (y = 0; y < retval.Height; y++)
155 { 163 {
156 int x; 164 int y;
157 for (x = 0; x < retval.Width; x++) 165 for (y = 0; y < retval.Height; y++)
158 { 166 {
159 retval[x, (retval.Height - 1) - y] = bs.ReadByte() * (bs.ReadByte() / 128.0); 167 int x;
160 bs.ReadBytes(11); // Advance the stream to next bytes. 168 for (x = 0; x < retval.Width; x++)
169 {
170 retval[x, (retval.Height - 1) - y] = bs.ReadByte() * (bs.ReadByte() / 128.0);
171 bs.ReadBytes(11); // Advance the stream to next bytes.
172 }
161 } 173 }
162 } 174 }
163 175
164 bs.Close();
165
166 return retval; 176 return retval;
167 } 177 }
168 178
169 public void SaveFile(string filename, ITerrainChannel map) 179 public void SaveFile(string filename, ITerrainChannel map)
170 { 180 {
171 FileInfo file = new FileInfo(filename); 181 FileInfo file = new FileInfo(filename);
172 FileStream s = file.Open(FileMode.CreateNew, FileAccess.Write);
173 SaveStream(s, map);
174 182
175 s.Close(); 183 using (FileStream s = file.Open(FileMode.CreateNew, FileAccess.Write))
184 SaveStream(s, map);
176 } 185 }
177 186
178 public void SaveStream(Stream s, ITerrainChannel map) 187 public void SaveStream(Stream s, ITerrainChannel map)
179 { 188 {
180 BinaryWriter binStream = new BinaryWriter(s); 189 using (BinaryWriter binStream = new BinaryWriter(s))
181
182 // Output the calculated raw
183 for (int y = 0; y < map.Height; y++)
184 { 190 {
185 for (int x = 0; x < map.Width; x++) 191 // Output the calculated raw
192 for (int y = 0; y < map.Height; y++)
186 { 193 {
187 double t = map[x, (map.Height - 1) - y]; 194 for (int x = 0; x < map.Width; x++)
188 //if height is less than 0, set it to 0 as
189 //can't save -ve values in a LLRAW file
190 if (t < 0d)
191 { 195 {
192 t = 0d; 196 double t = map[x, (map.Height - 1) - y];
197 //if height is less than 0, set it to 0 as
198 //can't save -ve values in a LLRAW file
199 if (t < 0d)
200 {
201 t = 0d;
202 }
203
204 int index = 0;
205
206 // The lookup table is pre-sorted, so we either find an exact match or
207 // the next closest (smaller) match with a binary search
208 index = Array.BinarySearch<HeightmapLookupValue>(LookupHeightTable, new HeightmapLookupValue(0, (float)t));
209 if (index < 0)
210 index = ~index - 1;
211
212 index = LookupHeightTable[index].Index;
213
214 byte red = (byte) (index & 0xFF);
215 byte green = (byte) ((index >> 8) & 0xFF);
216 const byte blue = 20;
217 const byte alpha1 = 0;
218 const byte alpha2 = 0;
219 const byte alpha3 = 0;
220 const byte alpha4 = 0;
221 const byte alpha5 = 255;
222 const byte alpha6 = 255;
223 const byte alpha7 = 255;
224 const byte alpha8 = 255;
225 byte alpha9 = red;
226 byte alpha10 = green;
227
228 binStream.Write(red);
229 binStream.Write(green);
230 binStream.Write(blue);
231 binStream.Write(alpha1);
232 binStream.Write(alpha2);
233 binStream.Write(alpha3);
234 binStream.Write(alpha4);
235 binStream.Write(alpha5);
236 binStream.Write(alpha6);
237 binStream.Write(alpha7);
238 binStream.Write(alpha8);
239 binStream.Write(alpha9);
240 binStream.Write(alpha10);
193 } 241 }
194
195 int index = 0;
196
197 // The lookup table is pre-sorted, so we either find an exact match or
198 // the next closest (smaller) match with a binary search
199 index = Array.BinarySearch<HeightmapLookupValue>(LookupHeightTable, new HeightmapLookupValue(0, (float)t));
200 if (index < 0)
201 index = ~index - 1;
202
203 index = LookupHeightTable[index].Index;
204
205 byte red = (byte) (index & 0xFF);
206 byte green = (byte) ((index >> 8) & 0xFF);
207 const byte blue = 20;
208 const byte alpha1 = 0;
209 const byte alpha2 = 0;
210 const byte alpha3 = 0;
211 const byte alpha4 = 0;
212 const byte alpha5 = 255;
213 const byte alpha6 = 255;
214 const byte alpha7 = 255;
215 const byte alpha8 = 255;
216 byte alpha9 = red;
217 byte alpha10 = green;
218
219 binStream.Write(red);
220 binStream.Write(green);
221 binStream.Write(blue);
222 binStream.Write(alpha1);
223 binStream.Write(alpha2);
224 binStream.Write(alpha3);
225 binStream.Write(alpha4);
226 binStream.Write(alpha5);
227 binStream.Write(alpha6);
228 binStream.Write(alpha7);
229 binStream.Write(alpha8);
230 binStream.Write(alpha9);
231 binStream.Write(alpha10);
232 } 242 }
233 } 243 }
234
235 binStream.Close();
236 } 244 }
237 245
238 public string FileExtension 246 public string FileExtension
@@ -259,7 +267,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
259 public bool SupportsTileSave() 267 public bool SupportsTileSave()
260 { 268 {
261 return false; 269 return false;
262 } 270 }
263
264 } 271 }
265} 272} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs
index 9fb7ef7..d467abb 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs
@@ -25,7 +25,10 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System;
28using System.IO; 29using System.IO;
30
31using OpenSim.Framework;
29using OpenSim.Region.Framework.Interfaces; 32using OpenSim.Region.Framework.Interfaces;
30using OpenSim.Region.Framework.Scenes; 33using OpenSim.Region.Framework.Scenes;
31 34
@@ -116,7 +119,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
116 119
117 public ITerrainChannel LoadStream(Stream s) 120 public ITerrainChannel LoadStream(Stream s)
118 { 121 {
119 TerrainChannel retval = new TerrainChannel(); 122 // The raw format doesn't contain any dimension information.
123 // Guess the square dimensions by using the length of the raw file.
124 double dimension = Math.Sqrt((double)(s.Length / 4));
125 // Regions are always multiples of 256.
126 int trimmedDimension = (int)dimension - ((int)dimension % (int)Constants.RegionSize);
127 if (trimmedDimension < Constants.RegionSize)
128 trimmedDimension = (int)Constants.RegionSize;
129
130 TerrainChannel retval = new TerrainChannel(trimmedDimension, trimmedDimension);
120 131
121 BinaryReader bs = new BinaryReader(s); 132 BinaryReader bs = new BinaryReader(s);
122 int y; 133 int y;
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs
index b5c7d33..219011e 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs
@@ -65,7 +65,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
65 bool eof = false; 65 bool eof = false;
66 66
67 int fileXPoints = 0; 67 int fileXPoints = 0;
68// int fileYPoints = 0; 68 int fileYPoints = 0;
69 69
70 // Terragen file 70 // Terragen file
71 while (eof == false) 71 while (eof == false)
@@ -75,7 +75,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
75 { 75 {
76 case "SIZE": 76 case "SIZE":
77 fileXPoints = bs.ReadInt16() + 1; 77 fileXPoints = bs.ReadInt16() + 1;
78// fileYPoints = fileXPoints; 78 fileYPoints = fileXPoints;
79 bs.ReadInt16(); 79 bs.ReadInt16();
80 break; 80 break;
81 case "XPTS": 81 case "XPTS":
@@ -83,8 +83,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
83 bs.ReadInt16(); 83 bs.ReadInt16();
84 break; 84 break;
85 case "YPTS": 85 case "YPTS":
86// fileYPoints = bs.ReadInt16(); 86 fileYPoints = bs.ReadInt16();
87 bs.ReadInt16();
88 bs.ReadInt16(); 87 bs.ReadInt16();
89 break; 88 break;
90 case "ALTW": 89 case "ALTW":
@@ -138,7 +137,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
138 bs.ReadInt16(); 137 bs.ReadInt16();
139 } 138 }
140 139
141
142 break; 140 break;
143 default: 141 default:
144 bs.ReadInt32(); 142 bs.ReadInt32();
@@ -154,10 +152,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
154 152
155 public ITerrainChannel LoadStream(Stream s) 153 public ITerrainChannel LoadStream(Stream s)
156 { 154 {
157 155 // Set to default size
158 int w = (int)Constants.RegionSize; 156 int w = (int)Constants.RegionSize;
159 int h = (int)Constants.RegionSize; 157 int h = (int)Constants.RegionSize;
160 158
159 // create a dummy channel (in case data is bad)
161 TerrainChannel retval = new TerrainChannel(w, h); 160 TerrainChannel retval = new TerrainChannel(w, h);
162 161
163 BinaryReader bs = new BinaryReader(s); 162 BinaryReader bs = new BinaryReader(s);
@@ -165,8 +164,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
165 bool eof = false; 164 bool eof = false;
166 if (Encoding.ASCII.GetString(bs.ReadBytes(16)) == "TERRAGENTERRAIN ") 165 if (Encoding.ASCII.GetString(bs.ReadBytes(16)) == "TERRAGENTERRAIN ")
167 { 166 {
168// int fileWidth = w;
169// int fileHeight = h;
170 167
171 // Terragen file 168 // Terragen file
172 while (eof == false) 169 while (eof == false)
@@ -175,31 +172,29 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
175 switch (tmp) 172 switch (tmp)
176 { 173 {
177 case "SIZE": 174 case "SIZE":
178// int sztmp = bs.ReadInt16() + 1; 175 w = bs.ReadInt16() + 1;
179// fileWidth = sztmp; 176 h = w;
180// fileHeight = sztmp;
181 bs.ReadInt16();
182 bs.ReadInt16(); 177 bs.ReadInt16();
183 break; 178 break;
184 case "XPTS": 179 case "XPTS":
185// fileWidth = bs.ReadInt16(); 180 w = bs.ReadInt16();
186 bs.ReadInt16();
187 bs.ReadInt16(); 181 bs.ReadInt16();
188 break; 182 break;
189 case "YPTS": 183 case "YPTS":
190// fileHeight = bs.ReadInt16(); 184 h = bs.ReadInt16();
191 bs.ReadInt16();
192 bs.ReadInt16(); 185 bs.ReadInt16();
193 break; 186 break;
194 case "ALTW": 187 case "ALTW":
195 eof = true; 188 eof = true;
196 Int16 heightScale = bs.ReadInt16(); 189 // create new channel of proper size (now that we know it)
197 Int16 baseHeight = bs.ReadInt16(); 190 retval = new TerrainChannel(w, h);
191 double heightScale = (double)bs.ReadInt16() / 65536.0;
192 double baseHeight = (double)bs.ReadInt16();
198 for (int y = 0; y < h; y++) 193 for (int y = 0; y < h; y++)
199 { 194 {
200 for (int x = 0; x < w; x++) 195 for (int x = 0; x < w; x++)
201 { 196 {
202 retval[x, y] = baseHeight + bs.ReadInt16() * (double)heightScale / 65536.0; 197 retval[x, y] = baseHeight + (double)bs.ReadInt16() * heightScale;
203 } 198 }
204 } 199 }
205 break; 200 break;
@@ -209,9 +204,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
209 } 204 }
210 } 205 }
211 } 206 }
212
213 bs.Close(); 207 bs.Close();
214
215 return retval; 208 return retval;
216 } 209 }
217 210
@@ -257,17 +250,17 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
257 bs.Write(enc.GetBytes("TERRAGENTERRAIN ")); 250 bs.Write(enc.GetBytes("TERRAGENTERRAIN "));
258 251
259 bs.Write(enc.GetBytes("SIZE")); 252 bs.Write(enc.GetBytes("SIZE"));
260 bs.Write(Convert.ToInt16(Constants.RegionSize)); 253 bs.Write(Convert.ToInt16(map.Width));
261 bs.Write(Convert.ToInt16(0)); // necessary padding 254 bs.Write(Convert.ToInt16(0)); // necessary padding
262 255
263 //The XPTS and YPTS chunks are not needed for square regions 256 //The XPTS and YPTS chunks are not needed for square regions
264 //but L3DT won't load the terrain file properly without them. 257 //but L3DT won't load the terrain file properly without them.
265 bs.Write(enc.GetBytes("XPTS")); 258 bs.Write(enc.GetBytes("XPTS"));
266 bs.Write(Convert.ToInt16(Constants.RegionSize)); 259 bs.Write(Convert.ToInt16(map.Width));
267 bs.Write(Convert.ToInt16(0)); // necessary padding 260 bs.Write(Convert.ToInt16(0)); // necessary padding
268 261
269 bs.Write(enc.GetBytes("YPTS")); 262 bs.Write(enc.GetBytes("YPTS"));
270 bs.Write(Convert.ToInt16(Constants.RegionSize)); 263 bs.Write(Convert.ToInt16(map.Height));
271 bs.Write(Convert.ToInt16(0)); // necessary padding 264 bs.Write(Convert.ToInt16(0)); // necessary padding
272 265
273 bs.Write(enc.GetBytes("SCAL")); 266 bs.Write(enc.GetBytes("SCAL"));
@@ -283,11 +276,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
283 bs.Write(Convert.ToInt16(horizontalScale)); // range between max and min 276 bs.Write(Convert.ToInt16(horizontalScale)); // range between max and min
284 bs.Write(Convert.ToInt16(baseHeight)); // base height or mid point 277 bs.Write(Convert.ToInt16(baseHeight)); // base height or mid point
285 278
279 double factor = 65536.0 / horizontalScale; // avoid computing this on each iteration
280
286 for (int y = 0; y < map.Height; y++) 281 for (int y = 0; y < map.Height; y++)
287 { 282 {
288 for (int x = 0; x < map.Width; x++) 283 for (int x = 0; x < map.Width; x++)
289 { 284 {
290 float elevation = (float)((map[x,y] - baseHeight) * 65536 ) / (float)horizontalScale; // see LoadStream for inverse 285 float elevation = (float)((map[x,y] - baseHeight) * factor); // see LoadStream for inverse
291 286
292 // clamp rounding issues 287 // clamp rounding issues
293 if (elevation > Int16.MaxValue) 288 if (elevation > Int16.MaxValue)
@@ -299,7 +294,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
299 } 294 }
300 } 295 }
301 296
302 //This is only necessary for older versions of Terragen. 297 //This is necessary for older versions of Terragen.
303 bs.Write(enc.GetBytes("EOF ")); 298 bs.Write(enc.GetBytes("EOF "));
304 299
305 bs.Close(); 300 bs.Close();
@@ -343,7 +338,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
343 if (BitConverter.IsLittleEndian == false) 338 if (BitConverter.IsLittleEndian == false)
344 { 339 {
345 byte[] tmp = new byte[4]; 340 byte[] tmp = new byte[4];
346 for (int i = 0; i < 4; i++) 341 for (int i = 3; i >= 0; i--)
347 { 342 {
348 tmp[i] = retVal[3 - i]; 343 tmp[i] = retVal[3 - i];
349 } 344 }
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs
index 630473e..b6c635c 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs
@@ -45,7 +45,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes
45 { 45 {
46 if (fillArea[x, y]) 46 if (fillArea[x, y])
47 { 47 {
48 double noise = TerrainUtil.PerlinNoise2D((double) x / Constants.RegionSize, (double) y / Constants.RegionSize, 8, 1.0); 48 double noise = TerrainUtil.PerlinNoise2D((double) x / map.Width, (double) y / map.Height, 8, 1.0);
49 49
50 map[x, y] += noise * strength; 50 map[x, y] += noise * strength;
51 } 51 }
diff --git a/OpenSim/Framework/Communications/XMPP/XmppStanza.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainFeature.cs
index 5312a31..78a43db 100644
--- a/OpenSim/Framework/Communications/XMPP/XmppStanza.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainFeature.cs
@@ -26,45 +26,35 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Xml.Serialization; 29using OpenSim.Region.Framework.Interfaces;
30 30
31namespace OpenSim.Framework.Communications.XMPP 31namespace OpenSim.Region.CoreModules.World.Terrain
32{ 32{
33 public abstract class XmppStanza 33 public interface ITerrainFeature
34 { 34 {
35 /// <summary> 35 /// <summary>
36 /// counter used for generating ID 36 /// Creates the feature.
37 /// </summary> 37 /// </summary>
38 [XmlIgnore] 38 /// <returns>
39 private static ulong _ctr = 0; 39 /// Empty string if successful, otherwise error message.
40 /// </returns>
41 /// <param name='map'>
42 /// ITerrainChannel holding terrain data.
43 /// </param>
44 /// <param name='args'>
45 /// command-line arguments from console.
46 /// </param>
47 string CreateFeature(ITerrainChannel map, string[] args);
40 48
41 /// <summary> 49 /// <summary>
42 /// recipient JID 50 /// Gets a string describing the usage.
43 /// </summary> 51 /// </summary>
44 [XmlAttribute("to")] 52 /// <returns>
45 public string ToJid; 53 /// A string describing parameters for creating the feature.
46 54 /// Format is "feature-name <arg1> <arg2> ..."
47 /// <summary> 55 /// </returns>
48 /// sender JID 56 string GetUsage();
49 /// </summary>
50 [XmlAttribute("from")]
51 public string FromJid;
52
53 /// <summary>
54 /// unique ID.
55 /// </summary>
56 [XmlAttribute("id")]
57 public string MessageId;
58
59 public XmppStanza()
60 {
61 }
62
63 public XmppStanza(string fromJid, string toJid)
64 {
65 ToJid = toJid;
66 FromJid = fromJid;
67 MessageId = String.Format("OpenSim_{0}{1}", DateTime.UtcNow.Ticks, _ctr++);
68 }
69 } 57 }
58
70} 59}
60
diff --git a/OpenSim/Framework/ForeignUserProfileData.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs
index 2beaf80..0e0a0e4 100644
--- a/OpenSim/Framework/ForeignUserProfileData.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs
@@ -26,52 +26,52 @@
26 */ 26 */
27 27
28using System; 28using System;
29using OpenSim.Region.Framework.Interfaces;
29 30
30namespace OpenSim.Framework 31namespace OpenSim.Region.CoreModules.World.Terrain
31{ 32{
32 public class ForeignUserProfileData : UserProfileData 33 public interface ITerrainModifier
33 { 34 {
34 /// <summary> 35 /// <summary>
35 /// The address of the users home sim, used for foreigners. 36 /// Creates the feature.
36 /// </summary> 37 /// </summary>
37 private string _userUserServerURI = String.Empty; 38 /// <returns>
39 /// Empty string if successful, otherwise error message.
40 /// </returns>
41 /// <param name='map'>
42 /// ITerrainChannel holding terrain data.
43 /// </param>
44 /// <param name='args'>
45 /// command-line arguments from console.
46 /// </param>
47 string ModifyTerrain(ITerrainChannel map, string[] args);
38 48
39 /// <summary> 49 /// <summary>
40 /// The address of the users home sim, used for foreigners. 50 /// Gets a string describing the usage.
41 /// </summary> 51 /// </summary>
42 private string _userHomeAddress = String.Empty; 52 /// <returns>
53 /// A string describing parameters for creating the feature.
54 /// Format is "feature-name <arg1> <arg2> ..."
55 /// </returns>
56 string GetUsage();
43 57
44 /// <summary> 58 /// <summary>
45 /// The port of the users home sim, used for foreigners. 59 /// Apply the appropriate operation on the specified map, at (x, y).
46 /// </summary> 60 /// </summary>
47 private string _userHomePort = String.Empty; 61 /// <param name='map'>
48 /// <summary> 62 /// Map.
49 /// The remoting port of the users home sim, used for foreigners. 63 /// </param>
50 /// </summary> 64 /// <param name='data'>
51 private string _userHomeRemotingPort = String.Empty; 65 /// Data.
52 66 /// </param>
53 public string UserServerURI 67 /// <param name='x'>
54 { 68 /// X.
55 get { return _userUserServerURI; } 69 /// </param>
56 set { _userUserServerURI = value; } 70 /// <param name='y'>
57 } 71 /// Y.
58 72 /// </param>
59 public string UserHomeAddress 73 double operate(double[,] map, TerrainModifierData data, int x, int y);
60 {
61 get { return _userHomeAddress; }
62 set { _userHomeAddress = value; }
63 }
64
65 public string UserHomePort
66 {
67 get { return _userHomePort; }
68 set { _userHomePort = value; }
69 }
70
71 public string UserHomeRemotingPort
72 {
73 get { return _userHomeRemotingPort; }
74 set { _userHomeRemotingPort = value; }
75 }
76 } 74 }
75
77} 76}
77
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs
new file mode 100644
index 0000000..32f1de9
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs
@@ -0,0 +1,93 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28
29using OpenSim.Region.CoreModules.World.Terrain;
30using OpenSim.Region.Framework.Interfaces;
31
32namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
33{
34 public class FillModifier : TerrainModifier
35 {
36
37 public FillModifier(ITerrainModule module) : base(module)
38 {
39 }
40
41 public override string ModifyTerrain(ITerrainChannel map, string[] args)
42 {
43 string result;
44 if (args.Length < 3)
45 {
46 result = "Usage: " + GetUsage();
47 }
48 else
49 {
50 TerrainModifierData data;
51 result = this.parseParameters(args, out data);
52
53 // Context-specific validation
54 if (result == String.Empty)
55 {
56 if (data.shape == String.Empty)
57 {
58 data.shape = "rectangle";
59 data.x0 = 0;
60 data.y0 = 0;
61 data.dx = map.Width;
62 data.dy = map.Height;
63 }
64 }
65
66 // if it's all good, then do the work
67 if (result == String.Empty)
68 {
69 this.applyModification(map, data);
70 }
71 }
72
73 return result;
74 }
75
76 public override string GetUsage()
77 {
78 string val = "fill <height> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<height2>]"
79 + "\nSets all points within the specified range to the specified value.";
80 return val;
81 }
82
83 public override double operate(double[,] map, TerrainModifierData data, int x, int y)
84 {
85 double factor = this.computeBevel(data, x, y);
86 double result = data.elevation - (data.elevation - data.bevelevation) * factor;
87 return result;
88 }
89
90 }
91
92}
93
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs
new file mode 100644
index 0000000..2ab4bcc
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs
@@ -0,0 +1,92 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using OpenSim.Region.CoreModules.World.Terrain;
29using OpenSim.Region.Framework.Interfaces;
30
31namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
32{
33 public class LowerModifier : TerrainModifier
34 {
35 public LowerModifier(ITerrainModule module) : base(module)
36 {
37 }
38
39 public override string ModifyTerrain(ITerrainChannel map, string[] args)
40 {
41 string result;
42 if (args.Length < 3)
43 {
44 result = "Usage: " + GetUsage();
45 }
46 else
47 {
48 TerrainModifierData data;
49 result = this.parseParameters(args, out data);
50
51 // Context-specific validation
52 if (result == String.Empty)
53 {
54 if (data.shape == String.Empty)
55 {
56 data.shape = "rectangle";
57 data.x0 = 0;
58 data.y0 = 0;
59 data.dx = map.Width;
60 data.dy = map.Height;
61 }
62 }
63
64 // if it's all good, then do the work
65 if (result == String.Empty)
66 {
67 this.applyModification(map, data);
68 }
69 }
70
71 return result;
72 }
73
74 public override string GetUsage()
75 {
76 string val = "lower <delta> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<delta2>]"
77 + "\nLowers all points within the specified range by the specified amount.";
78 return val;
79
80 }
81
82 public override double operate(double[,] map, TerrainModifierData data, int x, int y)
83 {
84 double factor = this.computeBevel(data, x, y);
85 double result = map[x, y] - (data.elevation - (data.elevation - data.bevelevation) * factor);
86 return result;
87 }
88
89 }
90
91}
92
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs
new file mode 100644
index 0000000..0939c0a
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs
@@ -0,0 +1,92 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using OpenSim.Region.CoreModules.World.Terrain;
29using OpenSim.Region.Framework.Interfaces;
30
31namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
32{
33 public class MaxModifier : TerrainModifier
34 {
35 public MaxModifier(ITerrainModule module) : base(module)
36 {
37 }
38
39 public override string ModifyTerrain(ITerrainChannel map, string[] args)
40 {
41 string result;
42 if (args.Length < 3)
43 {
44 result = "Usage: " + GetUsage();
45 }
46 else
47 {
48 TerrainModifierData data;
49 result = this.parseParameters(args, out data);
50
51 // Context-specific validation
52 if (result == String.Empty)
53 {
54 if (data.shape == String.Empty)
55 {
56 data.shape = "rectangle";
57 data.x0 = 0;
58 data.y0 = 0;
59 data.dx = map.Width;
60 data.dy = map.Height;
61 }
62 }
63
64 // if it's all good, then do the work
65 if (result == String.Empty)
66 {
67 this.applyModification(map, data);
68 }
69 }
70
71 return result;
72 }
73
74 public override string GetUsage()
75 {
76 string val = "max <height> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<height2>]"
77 + "\nEnsures that all points within the specified range are no higher than the specified value.";
78 return val;
79
80 }
81
82 public override double operate(double[,] map, TerrainModifierData data, int x, int y)
83 {
84 double factor = this.computeBevel(data, x, y);
85 double result = Math.Min(data.elevation - (data.elevation - data.bevelevation) * factor, map[x, y]);
86 return result;
87 }
88
89 }
90
91}
92
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs
new file mode 100644
index 0000000..cbbccc0
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs
@@ -0,0 +1,92 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using OpenSim.Region.CoreModules.World.Terrain;
29using OpenSim.Region.Framework.Interfaces;
30
31namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
32{
33 public class MinModifier : TerrainModifier
34 {
35 public MinModifier(ITerrainModule module) : base(module)
36 {
37 }
38
39 public override string ModifyTerrain(ITerrainChannel map, string[] args)
40 {
41 string result;
42 if (args.Length < 3)
43 {
44 result = "Usage: " + GetUsage();
45 }
46 else
47 {
48 TerrainModifierData data;
49 result = this.parseParameters(args, out data);
50
51 // Context-specific validation
52 if (result == String.Empty)
53 {
54 if (data.shape == String.Empty)
55 {
56 data.shape = "rectangle";
57 data.x0 = 0;
58 data.y0 = 0;
59 data.dx = map.Width;
60 data.dy = map.Height;
61 }
62 }
63
64 // if it's all good, then do the work
65 if (result == String.Empty)
66 {
67 this.applyModification(map, data);
68 }
69 }
70
71 return result;
72 }
73
74 public override string GetUsage()
75 {
76 string val = "min <height> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<height2>]"
77 + "\nEnsures that all points within the specified range are no lower than the specified value.";
78 return val;
79
80 }
81
82 public override double operate(double[,] map, TerrainModifierData data, int x, int y)
83 {
84 double factor = this.computeBevel(data, x, y);
85 double result = Math.Max(data.elevation - (data.elevation - data.bevelevation) * factor, map[x, y]);
86 return result;
87 }
88
89 }
90
91}
92
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs
new file mode 100644
index 0000000..d6b95d0
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs
@@ -0,0 +1,108 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using OpenSim.Region.CoreModules.World.Terrain;
29using OpenSim.Region.Framework.Interfaces;
30using OpenSim.Region.Framework.Scenes;
31
32namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
33{
34 public class NoiseModifier : TerrainModifier
35 {
36 public NoiseModifier(ITerrainModule module) : base(module)
37 {
38 }
39
40 public override string ModifyTerrain(ITerrainChannel map, string[] args)
41 {
42 string result;
43 if (args.Length < 3)
44 {
45 result = "Usage: " + GetUsage();
46 }
47 else
48 {
49 TerrainModifierData data;
50 result = this.parseParameters(args, out data);
51
52 // Context-specific validation
53 if (result == String.Empty)
54 {
55 if (data.bevel == "taper")
56 {
57 if (data.bevelevation < 0.0 || data.bevelevation > 1.0)
58 {
59 result = String.Format("Taper must be 0.0 to 1.0: {0}", data.bevelevation);
60 }
61 }
62 else
63 {
64 data.bevelevation = 1.0f;
65 }
66
67 if (data.elevation < 0.0 || data.elevation > 1.0)
68 {
69 result = String.Format("Noise strength must be 0.0 to 1.0: {0}", data.elevation);
70 }
71
72 if (data.shape == String.Empty)
73 {
74 data.shape = "rectangle";
75 data.x0 = 0;
76 data.y0 = 0;
77 data.dx = map.Width;
78 data.dy = map.Height;
79 }
80 }
81
82 // if it's all good, then do the work
83 if (result == String.Empty)
84 {
85 this.applyModification(map, data);
86 }
87 }
88
89 return result;
90 }
91
92 public override string GetUsage()
93 {
94 string val = "noise <delta> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<delta2>]"
95 + "\nAdds noise to all points within the specified range.";
96 return val;
97 }
98
99 public override double operate(double[,] map, TerrainModifierData data, int x, int y)
100 {
101 double factor = this.computeBevel(data, x, y);
102 double noise = TerrainUtil.PerlinNoise2D((double)x / map.GetLength(0), (double)y / map.GetLength(1), 8, 1.0);
103 return map[x, y] + (data.elevation - (data.elevation - data.bevelevation) * factor) * (noise - .5);
104 }
105
106 }
107
108}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs
new file mode 100644
index 0000000..35fb9d6
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs
@@ -0,0 +1,92 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using OpenSim.Region.CoreModules.World.Terrain;
29using OpenSim.Region.Framework.Interfaces;
30
31namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
32{
33 public class RaiseModifier : TerrainModifier
34 {
35 public RaiseModifier(ITerrainModule module) : base(module)
36 {
37 }
38
39 public override string ModifyTerrain(ITerrainChannel map, string[] args)
40 {
41 string result;
42 if (args.Length < 3)
43 {
44 result = "Usage: " + GetUsage();
45 }
46 else
47 {
48 TerrainModifierData data;
49 result = this.parseParameters(args, out data);
50
51 // Context-specific validation
52 if (result == String.Empty)
53 {
54 if (data.shape == String.Empty)
55 {
56 data.shape = "rectangle";
57 data.x0 = 0;
58 data.y0 = 0;
59 data.dx = map.Width;
60 data.dy = map.Height;
61 }
62 }
63
64 // if it's all good, then do the work
65 if (result == String.Empty)
66 {
67 this.applyModification(map, data);
68 }
69 }
70
71 return result;
72 }
73
74 public override string GetUsage()
75 {
76 string val = "raise <delta> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<delta2>]"
77 + "\nRaises all points within the specified range by the specified amount.";
78 return val;
79
80 }
81
82 public override double operate(double[,] map, TerrainModifierData data, int x, int y)
83 {
84 double factor = this.computeBevel(data, x, y);
85 double result = map[x, y] + (data.elevation - (data.elevation - data.bevelevation) * factor);
86 return result;
87 }
88
89 }
90
91}
92
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs
new file mode 100644
index 0000000..9f8d5b2
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs
@@ -0,0 +1,131 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using OpenSim.Region.CoreModules.World.Terrain;
29using OpenSim.Region.Framework.Interfaces;
30
31namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
32{
33 public class SmoothModifier : TerrainModifier
34 {
35 public SmoothModifier(ITerrainModule module) : base(module)
36 {
37 }
38
39 public override string ModifyTerrain(ITerrainChannel map, string[] args)
40 {
41 string result;
42 if (args.Length < 3)
43 {
44 result = "Usage: " + GetUsage();
45 }
46 else
47 {
48 TerrainModifierData data;
49 result = this.parseParameters(args, out data);
50
51 // Context-specific validation
52 if (result == String.Empty)
53 {
54 if (data.bevel == "taper")
55 {
56 if (data.bevelevation < 0.01 || data.bevelevation > 0.99)
57 {
58 result = String.Format("Taper must be 0.01 to 0.99: {0}", data.bevelevation);
59 }
60 }
61 else
62 {
63 data.bevelevation = 2.0f / 3.0f;
64 }
65
66 if (data.elevation < 0.0 || data.elevation > 1.0)
67 {
68 result = String.Format("Smoothing strength must be 0.0 to 1.0: {0}", data.elevation);
69 }
70
71 if (data.shape == String.Empty)
72 {
73 data.shape = "rectangle";
74 data.x0 = 0;
75 data.y0 = 0;
76 data.dx = map.Width;
77 data.dy = map.Height;
78 }
79 }
80
81 // if it's all good, then do the work
82 if (result == String.Empty)
83 {
84 this.applyModification(map, data);
85 }
86 }
87
88 return result;
89 }
90
91 public override string GetUsage()
92 {
93 string val = "smooth <strength> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<fraction>]"
94 + "\nSmooths all points within the specified range using a simple averaging algorithm.";
95 return val;
96 }
97
98 public override double operate(double[,] map, TerrainModifierData data, int x, int y)
99 {
100 double[] scale = new double[3];
101 scale[0] = data.elevation;
102 scale[1] = ((1.0 - scale[0]) * data.bevelevation) / 8.0;
103 scale[2] = ((1.0 - scale[0]) * (1.0 - data.bevelevation)) / 16.0;
104 int xMax = map.GetLength(0);
105 int yMax = map.GetLength(1);
106 double result;
107 if ((x == 0) || (y == 0) || (x == (xMax - 1)) || (y == (yMax - 1)))
108 {
109 result = map[x, y];
110 }
111 else
112 {
113 result = 0.0;
114 for(int yPos = (y - 2); yPos < (y + 3); yPos++)
115 {
116 int yVal = (yPos <= 0) ? 0 : ((yPos < yMax) ? yPos : yMax - 1);
117 for(int xPos = (x - 2); xPos < (x + 3); xPos++)
118 {
119 int xVal = (xPos <= 0) ? 0 : ((xPos < xMax) ? xPos : xMax - 1);
120 int dist = Math.Max(Math.Abs(x - xVal), Math.Abs(y - yVal));
121 result += map[xVal, yVal] * scale[dist];
122 }
123 }
124 }
125 return result;
126 }
127
128 }
129
130}
131
diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs
index 989b7d8..e7df3f8 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs
@@ -53,7 +53,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes
53 z *= z; 53 z *= z;
54 z -= ((x - rx) * (x - rx)) + ((y - ry) * (y - ry)); 54 z -= ((x - rx) * (x - rx)) + ((y - ry) * (y - ry));
55 55
56 double noise = TerrainUtil.PerlinNoise2D(x / (double) Constants.RegionSize, y / (double) Constants.RegionSize, 8, 1.0); 56 double noise = TerrainUtil.PerlinNoise2D(x / (double) map.Width, y / (double) map.Height, 8, 1.0);
57 57
58 if (z > 0.0) 58 if (z > 0.0)
59 map[x, y] += noise * z * duration; 59 map[x, y] += noise * z * duration;
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs
new file mode 100644
index 0000000..7ebd08e
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs
@@ -0,0 +1,378 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Reflection;
29using log4net;
30
31using OpenSim.Region.Framework.Interfaces;
32
33namespace OpenSim.Region.CoreModules.World.Terrain
34{
35 public abstract class TerrainModifier : ITerrainModifier
36 {
37 protected ITerrainModule m_module;
38 protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
39
40 protected TerrainModifier(ITerrainModule module)
41 {
42 m_module = module;
43 }
44
45 public abstract string ModifyTerrain(ITerrainChannel map, string[] args);
46
47 public abstract string GetUsage();
48
49 public abstract double operate(double[,] map, TerrainModifierData data, int x, int y);
50
51 protected String parseParameters(string[] args, out TerrainModifierData data)
52 {
53 string val;
54 string arg;
55 string result;
56 data = new TerrainModifierData();
57 data.shape = String.Empty;
58 data.bevel = String.Empty;
59 data.dx = 0;
60 data.dy = 0;
61 if (args.Length < 4)
62 {
63 result = "Usage: " + GetUsage();
64 }
65 else
66 {
67 result = this.parseFloat(args[3], out data.elevation);
68 }
69 if (result == String.Empty)
70 {
71 int index = 3;
72 while(++index < args.Length && result == String.Empty)
73 {
74 arg = args[index];
75 // check for shape
76 if (arg.StartsWith("-rec=") || arg.StartsWith("-ell="))
77 {
78 if (data.shape != String.Empty)
79 {
80 result = "Only 1 '-rec' or '-ell' parameter is permitted.";
81 }
82 else
83 {
84 data.shape = arg.StartsWith("-ell=") ? "ellipse" : "rectangle";
85 val = arg.Substring(arg.IndexOf("=") + 1);
86 string[] coords = val.Split(new char[] {','});
87 if ((coords.Length < 3) || (coords.Length > 4))
88 {
89 result = String.Format("Bad format for shape parameter {0}", arg);
90 }
91 else
92 {
93 result = this.parseInt(coords[0], out data.x0);
94 if (result == String.Empty)
95 {
96 result = this.parseInt(coords[1], out data.y0);
97 }
98 if (result == String.Empty)
99 {
100 result = this.parseInt(coords[2], out data.dx);
101 }
102 if (result == String.Empty)
103 {
104 if (coords.Length == 4)
105 {
106 result = this.parseInt(coords[3], out data.dy);
107 }
108 else
109 {
110 data.dy = data.dx;
111 }
112 }
113 if (result == String.Empty)
114 {
115 if ((data.dx <= 0) || (data.dy <= 0))
116 {
117 result = "Shape sizes must be positive integers";
118 }
119 }
120 else
121 {
122 result = String.Format("Bad value in shape parameters {0}", arg);
123 }
124 }
125 }
126 }
127 else if (arg.StartsWith("-taper="))
128 {
129 if (data.bevel != String.Empty)
130 {
131 result = "Only 1 '-taper' parameter is permitted.";
132 }
133 else
134 {
135 data.bevel = "taper";
136 val = arg.Substring(arg.IndexOf("=") + 1);
137 result = this.parseFloat(val, out data.bevelevation);
138 if (result != String.Empty)
139 {
140 result = String.Format("Bad format for taper parameter {0}", arg);
141 }
142 }
143 }
144 else
145 {
146 result = String.Format("Unrecognized parameter {0}", arg);
147 }
148 }
149 }
150 return result;
151 }
152
153 protected string parseFloat(String s, out float f)
154 {
155 string result;
156 double d;
157 if (Double.TryParse(s, out d))
158 {
159 try
160 {
161 f = (float)d;
162 result = String.Empty;
163 }
164 catch(InvalidCastException)
165 {
166 result = String.Format("{0} is invalid", s);
167 f = -1.0f;
168 }
169 }
170 else
171 {
172 f = -1.0f;
173 result = String.Format("{0} is invalid", s);
174 }
175 return result;
176 }
177
178 protected string parseInt(String s, out int i)
179 {
180 string result;
181 if (Int32.TryParse(s, out i))
182 {
183 result = String.Empty;
184 }
185 else
186 {
187 result = String.Format("{0} is invalid", s);
188 }
189 return result;
190 }
191
192 protected void applyModification(ITerrainChannel map, TerrainModifierData data)
193 {
194 bool[,] mask;
195 int xMax;
196 int yMax;
197 int xMid;
198 int yMid;
199 if (data.shape == "ellipse")
200 {
201 mask = this.ellipticalMask(data.dx, data.dy);
202 xMax = mask.GetLength(0);
203 yMax = mask.GetLength(1);
204 xMid = xMax / 2 + xMax % 2;
205 yMid = yMax / 2 + yMax % 2;
206 }
207 else
208 {
209 mask = this.rectangularMask(data.dx, data.dy);
210 xMax = mask.GetLength(0);
211 yMax = mask.GetLength(1);
212 xMid = 0;
213 yMid = 0;
214 }
215// m_log.DebugFormat("Apply {0} mask {1}x{2} @ {3},{4}", data.shape, xMax, yMax, xMid, yMid);
216 double[,] buffer = map.GetDoubles();
217 int yDim = yMax;
218 while(--yDim >= 0)
219 {
220 int yPos = data.y0 + yDim - yMid;
221 if ((yPos >= 0) && (yPos < map.Height))
222 {
223 int xDim = xMax;
224 while(--xDim >= 0)
225 {
226 int xPos = data.x0 + xDim - xMid;
227 if ((xPos >= 0) && (xPos < map.Width) && (mask[xDim, yDim]))
228 {
229 double endElevation = this.operate(buffer, data, xPos, yPos);
230 map[xPos, yPos] = endElevation;
231 }
232 }
233 }
234 }
235 }
236
237 protected double computeBevel(TerrainModifierData data, int x, int y)
238 {
239 int deltaX;
240 int deltaY;
241 int xMax;
242 int yMax;
243 double factor;
244 if (data.bevel == "taper")
245 {
246 if (data.shape == "ellipse")
247 {
248 deltaX = x - data.x0;
249 deltaY = y - data.y0;
250 xMax = data.dx;
251 yMax = data.dy;
252 factor = (double)((deltaX * deltaX) + (deltaY * deltaY));
253 factor /= ((xMax * xMax) + (yMax * yMax));
254 }
255 else
256 {
257 // pyramid
258 xMax = data.dx / 2 + data.dx % 2;
259 yMax = data.dy / 2 + data.dy % 2;
260 deltaX = Math.Abs(data.x0 + xMax - x);
261 deltaY = Math.Abs(data.y0 + yMax - y);
262 factor = Math.Max(((double)(deltaY) / yMax), ((double)(deltaX) / xMax));
263 }
264 }
265 else
266 {
267 factor = 0.0;
268 }
269 return factor;
270 }
271
272 private bool[,] rectangularMask(int xSize, int ySize)
273 {
274 bool[,] mask = new bool[xSize, ySize];
275 int yPos = ySize;
276 while(--yPos >= 0)
277 {
278 int xPos = xSize;
279 while(--xPos >= 0)
280 {
281 mask[xPos, yPos] = true;
282 }
283 }
284 return mask;
285 }
286
287 /*
288 * Fast ellipse-based derivative of Bresenham algorithm.
289 * https://web.archive.org/web/20120225095359/http://homepage.smc.edu/kennedy_john/belipse.pdf
290 */
291 private bool[,] ellipticalMask(int xRadius, int yRadius)
292 {
293 long twoASquared = 2L * xRadius * xRadius;
294 long twoBSquared = 2L * yRadius * yRadius;
295
296 bool[,] mask = new bool[2 * xRadius + 1, 2 * yRadius + 1];
297
298 long ellipseError = 0L;
299 long stoppingX = twoBSquared * xRadius;
300 long stoppingY = 0L;
301 long xChange = yRadius * yRadius * (1L - 2L * xRadius);
302 long yChange = xRadius * xRadius;
303
304 int xPos = xRadius;
305 int yPos = 0;
306
307 // first set of points
308 while(stoppingX >= stoppingY)
309 {
310 int yUpper = yRadius + yPos;
311 int yLower = yRadius - yPos;
312 // fill in the mask
313 int xNow = xPos;
314 while(xNow >= 0)
315 {
316 mask[xRadius + xNow, yUpper] = true;
317 mask[xRadius - xNow, yUpper] = true;
318 mask[xRadius + xNow, yLower] = true;
319 mask[xRadius - xNow, yLower] = true;
320 --xNow;
321 }
322 yPos++;
323 stoppingY += twoASquared;
324 ellipseError += yChange;
325 yChange += twoASquared;
326 if ((2L * ellipseError + xChange) > 0L)
327 {
328 xPos--;
329 stoppingX -= twoBSquared;
330 ellipseError += xChange;
331 xChange += twoBSquared;
332 }
333 }
334
335 // second set of points
336 xPos = 0;
337 yPos = yRadius;
338 xChange = yRadius * yRadius;
339 yChange = xRadius * xRadius * (1L - 2L * yRadius);
340
341 ellipseError = 0L;
342 stoppingX = 0L;
343 stoppingY = twoASquared * yRadius;
344
345 while(stoppingX <= stoppingY)
346 {
347 int xUpper = xRadius + xPos;
348 int xLower = xRadius - xPos;
349 // fill in the mask
350 int yNow = yPos;
351 while(yNow >= 0)
352 {
353 mask[xUpper, yRadius + yNow] = true;
354 mask[xUpper, yRadius - yNow] = true;
355 mask[xLower, yRadius + yNow] = true;
356 mask[xLower, yRadius - yNow] = true;
357 --yNow;
358 }
359 xPos++;
360 stoppingX += twoBSquared;
361 ellipseError += xChange;
362 xChange += twoBSquared;
363 if ((2L * ellipseError + yChange) > 0L)
364 {
365 yPos--;
366 stoppingY -= twoASquared;
367 ellipseError += yChange;
368 yChange += twoASquared;
369 }
370 }
371 return mask;
372 }
373
374
375 }
376
377}
378
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs
new file mode 100644
index 0000000..4e0f8d7
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs
@@ -0,0 +1,17 @@
1using System;
2
3namespace OpenSim.Region.CoreModules.World.Terrain
4{
5 public struct TerrainModifierData
6 {
7 public float elevation;
8 public string shape;
9 public int x0;
10 public int y0;
11 public int dx;
12 public int dy;
13 public string bevel;
14 public float bevelevation;
15 }
16}
17
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
index fd30c46..932652c 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
@@ -24,19 +24,24 @@
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27
28using System; 27using System;
29using System.Collections.Generic; 28using System.Collections.Generic;
30using System.IO; 29using System.IO;
31using System.Reflection; 30using System.Reflection;
32using System.Net; 31using System.Net;
32
33using log4net; 33using log4net;
34using Nini.Config; 34using Nini.Config;
35
35using OpenMetaverse; 36using OpenMetaverse;
36using Mono.Addins; 37using Mono.Addins;
38
39using OpenSim.Data;
37using OpenSim.Framework; 40using OpenSim.Framework;
41using OpenSim.Framework.Console;
38using OpenSim.Region.CoreModules.Framework.InterfaceCommander; 42using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
39using OpenSim.Region.CoreModules.World.Terrain.FileLoaders; 43using OpenSim.Region.CoreModules.World.Terrain.FileLoaders;
44using OpenSim.Region.CoreModules.World.Terrain.Modifiers;
40using OpenSim.Region.CoreModules.World.Terrain.FloodBrushes; 45using OpenSim.Region.CoreModules.World.Terrain.FloodBrushes;
41using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes; 46using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes;
42using OpenSim.Region.Framework.Interfaces; 47using OpenSim.Region.Framework.Interfaces;
@@ -70,26 +75,112 @@ namespace OpenSim.Region.CoreModules.World.Terrain
70 #endregion 75 #endregion
71 76
72 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 77 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
73
74 private readonly Commander m_commander = new Commander("terrain");
75 78
79#pragma warning disable 414
80 private static readonly string LogHeader = "[TERRAIN MODULE]";
81#pragma warning restore 414
82
83 private readonly Commander m_commander = new Commander("terrain");
76 private readonly Dictionary<StandardTerrainEffects, ITerrainFloodEffect> m_floodeffects = 84 private readonly Dictionary<StandardTerrainEffects, ITerrainFloodEffect> m_floodeffects =
77 new Dictionary<StandardTerrainEffects, ITerrainFloodEffect>(); 85 new Dictionary<StandardTerrainEffects, ITerrainFloodEffect>();
78
79 private readonly Dictionary<string, ITerrainLoader> m_loaders = new Dictionary<string, ITerrainLoader>(); 86 private readonly Dictionary<string, ITerrainLoader> m_loaders = new Dictionary<string, ITerrainLoader>();
80
81 private readonly Dictionary<StandardTerrainEffects, ITerrainPaintableEffect> m_painteffects = 87 private readonly Dictionary<StandardTerrainEffects, ITerrainPaintableEffect> m_painteffects =
82 new Dictionary<StandardTerrainEffects, ITerrainPaintableEffect>(); 88 new Dictionary<StandardTerrainEffects, ITerrainPaintableEffect>();
83
84 private ITerrainChannel m_channel;
85 private Dictionary<string, ITerrainEffect> m_plugineffects; 89 private Dictionary<string, ITerrainEffect> m_plugineffects;
90 private Dictionary<string, ITerrainModifier> m_modifyOperations =
91 new Dictionary<string, ITerrainModifier>();
92 private ITerrainChannel m_channel;
86 private ITerrainChannel m_revert; 93 private ITerrainChannel m_revert;
87 private Scene m_scene; 94 private Scene m_scene;
88 private volatile bool m_tainted; 95 private volatile bool m_tainted;
89 private readonly Stack<LandUndoState> m_undo = new Stack<LandUndoState>(5); 96 private readonly Stack<LandUndoState> m_undo = new Stack<LandUndoState>(5);
90
91 private String m_InitialTerrain = "pinhead-island"; 97 private String m_InitialTerrain = "pinhead-island";
92 98
99 // If true, send terrain patch updates to clients based on their view distance
100 private bool m_sendTerrainUpdatesByViewDistance = true;
101
102 // Class to keep the per client collection of terrain patches that must be sent.
103 // A patch is set to 'true' meaning it should be sent to the client. Once the
104 // patch packet is queued to the client, the bit for that patch is set to 'false'.
105 private class PatchUpdates
106 {
107 private bool[,] updated; // for each patch, whether it needs to be sent to this client
108 private int updateCount; // number of patches that need to be sent
109 public ScenePresence Presence; // a reference to the client to send to
110 public TerrainData Terrain; // reference to the underlying terrain
111 public PatchUpdates(TerrainData terrData, ScenePresence pPresence)
112 {
113 updated = new bool[terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize];
114 updateCount = 0;
115 Presence = pPresence;
116 Terrain = terrData;
117 // Initially, send all patches to the client
118 SetAll(true);
119 }
120 // Returns 'true' if there are any patches marked for sending
121 public bool HasUpdates()
122 {
123 return (updateCount > 0);
124 }
125
126 public void SetByXY(int x, int y, bool state)
127 {
128 this.SetByPatch(x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, state);
129 }
130
131 public bool GetByPatch(int patchX, int patchY)
132 {
133 return updated[patchX, patchY];
134 }
135
136 public void SetByPatch(int patchX, int patchY, bool state)
137 {
138 bool prevState = updated[patchX, patchY];
139 if (!prevState && state)
140 updateCount++;
141 if (prevState && !state)
142 updateCount--;
143 updated[patchX, patchY] = state;
144 }
145
146 public void SetAll(bool state)
147 {
148 updateCount = 0;
149 for(int xx = 0; xx < updated.GetLength(0); xx++)
150 for(int yy = 0; yy < updated.GetLength(1); yy++)
151 updated[xx, yy] = state;
152 if (state)
153 updateCount = updated.GetLength(0) * updated.GetLength(1);
154 }
155 // Logically OR's the terrain data's patch taint map into this client's update map.
156 public void SetAll(TerrainData terrData)
157 {
158 if (updated.GetLength(0) != (terrData.SizeX / Constants.TerrainPatchSize)
159 || updated.GetLength(1) != (terrData.SizeY / Constants.TerrainPatchSize))
160 {
161 throw new Exception(
162 String.Format("{0} PatchUpdates.SetAll: patch array not same size as terrain. arr=<{1},{2}>, terr=<{3},{4}>",
163 LogHeader, updated.GetLength(0), updated.GetLength(1),
164 terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize)
165 );
166 }
167 for(int xx = 0; xx < terrData.SizeX; xx += Constants.TerrainPatchSize)
168 {
169 for(int yy = 0; yy < terrData.SizeY; yy += Constants.TerrainPatchSize)
170 {
171 // Only set tainted. The patch bit may be set if the patch was to be sent later.
172 if (terrData.IsTaintedAt(xx, yy, false))
173 {
174 this.SetByXY(xx, yy, true);
175 }
176 }
177 }
178 }
179 }
180
181 // The flags of which terrain patches to send for each of the ScenePresence's
182 private Dictionary<UUID, PatchUpdates> m_perClientPatchUpdates = new Dictionary<UUID, PatchUpdates>();
183
93 /// <summary> 184 /// <summary>
94 /// Human readable list of terrain file extensions that are supported. 185 /// Human readable list of terrain file extensions that are supported.
95 /// </summary> 186 /// </summary>
@@ -100,8 +191,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
100 191
101 #region ICommandableModule Members 192 #region ICommandableModule Members
102 193
103 public ICommander CommandInterface 194 public ICommander CommandInterface {
104 {
105 get { return m_commander; } 195 get { return m_commander; }
106 } 196 }
107 197
@@ -118,7 +208,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
118 { 208 {
119 IConfig terrainConfig = config.Configs["Terrain"]; 209 IConfig terrainConfig = config.Configs["Terrain"];
120 if (terrainConfig != null) 210 if (terrainConfig != null)
211 {
121 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); 212 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain);
213 m_sendTerrainUpdatesByViewDistance = terrainConfig.GetBoolean("SendTerrainUpdatesByViewDistance", m_sendTerrainUpdatesByViewDistance);
214 }
122 } 215 }
123 216
124 public void AddRegion(Scene scene) 217 public void AddRegion(Scene scene)
@@ -126,26 +219,28 @@ namespace OpenSim.Region.CoreModules.World.Terrain
126 m_scene = scene; 219 m_scene = scene;
127 220
128 // Install terrain module in the simulator 221 // Install terrain module in the simulator
129 lock (m_scene) 222 lock(m_scene)
130 { 223 {
131 if (m_scene.Heightmap == null) 224 if (m_scene.Heightmap == null)
132 { 225 {
133 m_channel = new TerrainChannel(m_InitialTerrain); 226 m_channel = new TerrainChannel(m_InitialTerrain, (int)m_scene.RegionInfo.RegionSizeX,
227 (int)m_scene.RegionInfo.RegionSizeY,
228 (int)m_scene.RegionInfo.RegionSizeZ);
134 m_scene.Heightmap = m_channel; 229 m_scene.Heightmap = m_channel;
135 m_revert = new TerrainChannel();
136 UpdateRevertMap(); 230 UpdateRevertMap();
137 } 231 }
138 else 232 else
139 { 233 {
140 m_channel = m_scene.Heightmap; 234 m_channel = m_scene.Heightmap;
141 m_revert = new TerrainChannel();
142 UpdateRevertMap(); 235 UpdateRevertMap();
143 } 236 }
144 237
145 m_scene.RegisterModuleInterface<ITerrainModule>(this); 238 m_scene.RegisterModuleInterface<ITerrainModule>(this);
146 m_scene.EventManager.OnNewClient += EventManager_OnNewClient; 239 m_scene.EventManager.OnNewClient += EventManager_OnNewClient;
240 m_scene.EventManager.OnClientClosed += EventManager_OnClientClosed;
147 m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; 241 m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole;
148 m_scene.EventManager.OnTerrainTick += EventManager_OnTerrainTick; 242 m_scene.EventManager.OnTerrainTick += EventManager_OnTerrainTick;
243 m_scene.EventManager.OnFrame += EventManager_OnFrame;
149 } 244 }
150 245
151 InstallDefaultEffects(); 246 InstallDefaultEffects();
@@ -156,7 +251,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
156 string supportedFilesSeparatorForTileSave = ""; 251 string supportedFilesSeparatorForTileSave = "";
157 252
158 m_supportFileExtensionsForTileSave = ""; 253 m_supportFileExtensionsForTileSave = "";
159 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) 254 foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
160 { 255 {
161 m_supportedFileExtensions += supportedFilesSeparator + loader.Key + " (" + loader.Value + ")"; 256 m_supportedFileExtensions += supportedFilesSeparator + loader.Key + " (" + loader.Value + ")";
162 supportedFilesSeparator = ", "; 257 supportedFilesSeparator = ", ";
@@ -179,13 +274,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain
179 274
180 public void RemoveRegion(Scene scene) 275 public void RemoveRegion(Scene scene)
181 { 276 {
182 lock (m_scene) 277 lock(m_scene)
183 { 278 {
184 // remove the commands 279 // remove the commands
185 m_scene.UnregisterModuleCommander(m_commander.Name); 280 m_scene.UnregisterModuleCommander(m_commander.Name);
186 // remove the event-handlers 281 // remove the event-handlers
282 m_scene.EventManager.OnFrame -= EventManager_OnFrame;
187 m_scene.EventManager.OnTerrainTick -= EventManager_OnTerrainTick; 283 m_scene.EventManager.OnTerrainTick -= EventManager_OnTerrainTick;
188 m_scene.EventManager.OnPluginConsole -= EventManager_OnPluginConsole; 284 m_scene.EventManager.OnPluginConsole -= EventManager_OnPluginConsole;
285 m_scene.EventManager.OnClientClosed -= EventManager_OnClientClosed;
189 m_scene.EventManager.OnNewClient -= EventManager_OnNewClient; 286 m_scene.EventManager.OnNewClient -= EventManager_OnNewClient;
190 // remove the interface 287 // remove the interface
191 m_scene.UnregisterModuleInterface<ITerrainModule>(this); 288 m_scene.UnregisterModuleInterface<ITerrainModule>(this);
@@ -196,13 +293,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
196 { 293 {
197 } 294 }
198 295
199 public Type ReplaceableInterface 296 public Type ReplaceableInterface {
200 {
201 get { return null; } 297 get { return null; }
202 } 298 }
203 299
204 public string Name 300 public string Name {
205 {
206 get { return "TerrainModule"; } 301 get { return "TerrainModule"; }
207 } 302 }
208 303
@@ -221,47 +316,46 @@ namespace OpenSim.Region.CoreModules.World.Terrain
221 /// <param name="filename">Filename to terrain file. Type is determined by extension.</param> 316 /// <param name="filename">Filename to terrain file. Type is determined by extension.</param>
222 public void LoadFromFile(string filename) 317 public void LoadFromFile(string filename)
223 { 318 {
224 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) 319 foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
225 { 320 {
226 if (filename.EndsWith(loader.Key)) 321 if (filename.EndsWith(loader.Key))
227 { 322 {
228 lock (m_scene) 323 lock(m_scene)
229 { 324 {
230 try 325 try
231 { 326 {
232 ITerrainChannel channel = loader.Value.LoadFile(filename); 327 ITerrainChannel channel = loader.Value.LoadFile(filename);
233 if (channel.Width != Constants.RegionSize || channel.Height != Constants.RegionSize) 328 if (channel.Width != m_scene.RegionInfo.RegionSizeX || channel.Height != m_scene.RegionInfo.RegionSizeY)
234 { 329 {
235 // TerrainChannel expects a RegionSize x RegionSize map, currently 330 // TerrainChannel expects a RegionSize x RegionSize map, currently
236 throw new ArgumentException(String.Format("wrong size, use a file with size {0} x {1}", 331 throw new ArgumentException(String.Format("wrong size, use a file with size {0} x {1}",
237 Constants.RegionSize, Constants.RegionSize)); 332 m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY));
238 } 333 }
239 m_log.DebugFormat("[TERRAIN]: Loaded terrain, wd/ht: {0}/{1}", channel.Width, channel.Height); 334 m_log.DebugFormat("[TERRAIN]: Loaded terrain, wd/ht: {0}/{1}", channel.Width, channel.Height);
240 m_scene.Heightmap = channel; 335 m_scene.Heightmap = channel;
241 m_channel = channel; 336 m_channel = channel;
242 UpdateRevertMap(); 337 UpdateRevertMap();
243 } 338 }
244 catch (NotImplementedException) 339 catch(NotImplementedException)
245 { 340 {
246 m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value + 341 m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value +
247 " parser does not support file loading. (May be save only)"); 342 " parser does not support file loading. (May be save only)");
248 throw new TerrainException(String.Format("unable to load heightmap: parser {0} does not support loading", loader.Value)); 343 throw new TerrainException(String.Format("unable to load heightmap: parser {0} does not support loading", loader.Value));
249 } 344 }
250 catch (FileNotFoundException) 345 catch(FileNotFoundException)
251 { 346 {
252 m_log.Error( 347 m_log.Error(
253 "[TERRAIN]: Unable to load heightmap, file not found. (A directory permissions error may also cause this)"); 348 "[TERRAIN]: Unable to load heightmap, file not found. (A directory permissions error may also cause this)");
254 throw new TerrainException( 349 throw new TerrainException(
255 String.Format("unable to load heightmap: file {0} not found (or permissions do not allow access", filename)); 350 String.Format("unable to load heightmap: file {0} not found (or permissions do not allow access", filename));
256 } 351 }
257 catch (ArgumentException e) 352 catch(ArgumentException e)
258 { 353 {
259 m_log.ErrorFormat("[TERRAIN]: Unable to load heightmap: {0}", e.Message); 354 m_log.ErrorFormat("[TERRAIN]: Unable to load heightmap: {0}", e.Message);
260 throw new TerrainException( 355 throw new TerrainException(
261 String.Format("Unable to load heightmap: {0}", e.Message)); 356 String.Format("Unable to load heightmap: {0}", e.Message));
262 } 357 }
263 } 358 }
264 CheckForTerrainUpdates();
265 m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully"); 359 m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully");
266 return; 360 return;
267 } 361 }
@@ -279,7 +373,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
279 { 373 {
280 try 374 try
281 { 375 {
282 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) 376 foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
283 { 377 {
284 if (filename.EndsWith(loader.Key)) 378 if (filename.EndsWith(loader.Key))
285 { 379 {
@@ -289,7 +383,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
289 } 383 }
290 } 384 }
291 } 385 }
292 catch (IOException ioe) 386 catch(IOException ioe)
293 { 387 {
294 m_log.Error(String.Format("[TERRAIN]: Unable to save to {0}, {1}", filename, ioe.Message)); 388 m_log.Error(String.Format("[TERRAIN]: Unable to save to {0}, {1}", filename, ioe.Message));
295 } 389 }
@@ -309,27 +403,32 @@ namespace OpenSim.Region.CoreModules.World.Terrain
309 LoadFromStream(filename, URIFetch(pathToTerrainHeightmap)); 403 LoadFromStream(filename, URIFetch(pathToTerrainHeightmap));
310 } 404 }
311 405
406 public void LoadFromStream(string filename, Stream stream)
407 {
408 LoadFromStream(filename, Vector3.Zero, 0f, Vector2.Zero, stream);
409 }
410
312 /// <summary> 411 /// <summary>
313 /// Loads a terrain file from a stream and installs it in the scene. 412 /// Loads a terrain file from a stream and installs it in the scene.
314 /// </summary> 413 /// </summary>
315 /// <param name="filename">Filename to terrain file. Type is determined by extension.</param> 414 /// <param name="filename">Filename to terrain file. Type is determined by extension.</param>
316 /// <param name="stream"></param> 415 /// <param name="stream"></param>
317 public void LoadFromStream(string filename, Stream stream) 416 public void LoadFromStream(string filename, Vector3 displacement,
417 float radianRotation, Vector2 rotationDisplacement, Stream stream)
318 { 418 {
319 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) 419 foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
320 { 420 {
321 if (filename.EndsWith(loader.Key)) 421 if (filename.EndsWith(loader.Key))
322 { 422 {
323 lock (m_scene) 423 lock(m_scene)
324 { 424 {
325 try 425 try
326 { 426 {
327 ITerrainChannel channel = loader.Value.LoadStream(stream); 427 ITerrainChannel channel = loader.Value.LoadStream(stream);
328 m_scene.Heightmap = channel; 428 m_channel.Merge(channel, displacement, radianRotation, rotationDisplacement);
329 m_channel = channel;
330 UpdateRevertMap(); 429 UpdateRevertMap();
331 } 430 }
332 catch (NotImplementedException) 431 catch(NotImplementedException)
333 { 432 {
334 m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value + 433 m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value +
335 " parser does not support file loading. (May be save only)"); 434 " parser does not support file loading. (May be save only)");
@@ -337,7 +436,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
337 } 436 }
338 } 437 }
339 438
340 CheckForTerrainUpdates();
341 m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully"); 439 m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully");
342 return; 440 return;
343 } 441 }
@@ -390,7 +488,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
390 { 488 {
391 try 489 try
392 { 490 {
393 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) 491 foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
394 { 492 {
395 if (filename.EndsWith(loader.Key)) 493 if (filename.EndsWith(loader.Key))
396 { 494 {
@@ -399,18 +497,56 @@ namespace OpenSim.Region.CoreModules.World.Terrain
399 } 497 }
400 } 498 }
401 } 499 }
402 catch (NotImplementedException) 500 catch(NotImplementedException)
403 { 501 {
404 m_log.Error("Unable to save to " + filename + ", saving of this file format has not been implemented."); 502 m_log.Error("Unable to save to " + filename + ", saving of this file format has not been implemented.");
405 throw new TerrainException(String.Format("Unable to save heightmap: saving of this file format not implemented")); 503 throw new TerrainException(String.Format("Unable to save heightmap: saving of this file format not implemented"));
406 } 504 }
407 } 505 }
408 506
409 public void TaintTerrain () 507 // Someone diddled terrain outside the normal code paths. Set the taintedness for all clients.
508 // ITerrainModule.TaintTerrain()
509 public void TaintTerrain()
410 { 510 {
411 CheckForTerrainUpdates(); 511 lock(m_perClientPatchUpdates)
512 {
513 // Set the flags for all clients so the tainted patches will be sent out
514 foreach(PatchUpdates pups in m_perClientPatchUpdates.Values)
515 {
516 pups.SetAll(m_scene.Heightmap.GetTerrainData());
517 }
518 }
412 } 519 }
413 520
521 // ITerrainModule.PushTerrain()
522 public void PushTerrain(IClientAPI pClient)
523 {
524 // If view distance based, set the modified patch bits and the frame event will send the updates
525 if (m_sendTerrainUpdatesByViewDistance)
526 {
527 ScenePresence presence = m_scene.GetScenePresence(pClient.AgentId);
528 if (presence != null)
529 {
530 lock(m_perClientPatchUpdates)
531 {
532 PatchUpdates pups;
533 if (!m_perClientPatchUpdates.TryGetValue(pClient.AgentId, out pups))
534 {
535 // There is a ScenePresence without a send patch map. Create one.
536 pups = new PatchUpdates(m_scene.Heightmap.GetTerrainData(), presence);
537 m_perClientPatchUpdates.Add(presence.UUID, pups);
538 }
539 // By setting all to modified, the next update tick will send the patches
540 pups.SetAll(true);
541 }
542 }
543 }
544 else
545 {
546 // The traditional way is to call into the protocol stack to send them all.
547 pClient.SendLayerData(new float[10]);
548 }
549 }
414 #region Plugin Loading Methods 550 #region Plugin Loading Methods
415 551
416 private void LoadPlugins() 552 private void LoadPlugins()
@@ -418,13 +554,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain
418 m_plugineffects = new Dictionary<string, ITerrainEffect>(); 554 m_plugineffects = new Dictionary<string, ITerrainEffect>();
419 LoadPlugins(Assembly.GetCallingAssembly()); 555 LoadPlugins(Assembly.GetCallingAssembly());
420 string plugineffectsPath = "Terrain"; 556 string plugineffectsPath = "Terrain";
421 557
422 // Load the files in the Terrain/ dir 558 // Load the files in the Terrain/ dir
423 if (!Directory.Exists(plugineffectsPath)) 559 if (!Directory.Exists(plugineffectsPath))
424 return; 560 return;
425 561
426 string[] files = Directory.GetFiles(plugineffectsPath); 562 string[] files = Directory.GetFiles(plugineffectsPath);
427 foreach (string file in files) 563 foreach(string file in files)
428 { 564 {
429 m_log.Info("Loading effects in " + file); 565 m_log.Info("Loading effects in " + file);
430 try 566 try
@@ -432,7 +568,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
432 Assembly library = Assembly.LoadFrom(file); 568 Assembly library = Assembly.LoadFrom(file);
433 LoadPlugins(library); 569 LoadPlugins(library);
434 } 570 }
435 catch (BadImageFormatException) 571 catch(BadImageFormatException)
436 { 572 {
437 } 573 }
438 } 574 }
@@ -440,7 +576,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
440 576
441 private void LoadPlugins(Assembly library) 577 private void LoadPlugins(Assembly library)
442 { 578 {
443 foreach (Type pluginType in library.GetTypes()) 579 foreach(Type pluginType in library.GetTypes())
444 { 580 {
445 try 581 try
446 { 582 {
@@ -462,7 +598,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
462 m_log.Info("L ... " + typeName); 598 m_log.Info("L ... " + typeName);
463 } 599 }
464 } 600 }
465 catch (AmbiguousMatchException) 601 catch(AmbiguousMatchException)
466 { 602 {
467 } 603 }
468 } 604 }
@@ -470,7 +606,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
470 606
471 public void InstallPlugin(string pluginName, ITerrainEffect effect) 607 public void InstallPlugin(string pluginName, ITerrainEffect effect)
472 { 608 {
473 lock (m_plugineffects) 609 lock(m_plugineffects)
474 { 610 {
475 if (!m_plugineffects.ContainsKey(pluginName)) 611 if (!m_plugineffects.ContainsKey(pluginName))
476 { 612 {
@@ -513,6 +649,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain
513 m_floodeffects[StandardTerrainEffects.Flatten] = new FlattenArea(); 649 m_floodeffects[StandardTerrainEffects.Flatten] = new FlattenArea();
514 m_floodeffects[StandardTerrainEffects.Revert] = new RevertArea(m_revert); 650 m_floodeffects[StandardTerrainEffects.Revert] = new RevertArea(m_revert);
515 651
652 // Terrain Modifier operations
653 m_modifyOperations["min"] = new MinModifier(this);
654 m_modifyOperations["max"] = new MaxModifier(this);
655 m_modifyOperations["raise"] = new RaiseModifier(this);
656 m_modifyOperations["lower"] = new LowerModifier(this);
657 m_modifyOperations["fill"] = new FillModifier(this);
658 m_modifyOperations["smooth"] = new SmoothModifier(this);
659 m_modifyOperations["noise"] = new NoiseModifier(this);
660
516 // Filesystem load/save loaders 661 // Filesystem load/save loaders
517 m_loaders[".r32"] = new RAW32(); 662 m_loaders[".r32"] = new RAW32();
518 m_loaders[".f32"] = m_loaders[".r32"]; 663 m_loaders[".f32"] = m_loaders[".r32"];
@@ -532,6 +677,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
532 /// </summary> 677 /// </summary>
533 public void UpdateRevertMap() 678 public void UpdateRevertMap()
534 { 679 {
680 /*
535 int x; 681 int x;
536 for (x = 0; x < m_channel.Width; x++) 682 for (x = 0; x < m_channel.Width; x++)
537 { 683 {
@@ -541,6 +687,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
541 m_revert[x, y] = m_channel[x, y]; 687 m_revert[x, y] = m_channel[x, y];
542 } 688 }
543 } 689 }
690 */
691 m_revert = m_channel.MakeCopy();
544 } 692 }
545 693
546 /// <summary> 694 /// <summary>
@@ -553,22 +701,22 @@ namespace OpenSim.Region.CoreModules.World.Terrain
553 /// <param name="fileStartY">Where to begin our slice</param> 701 /// <param name="fileStartY">Where to begin our slice</param>
554 public void LoadFromFile(string filename, int fileWidth, int fileHeight, int fileStartX, int fileStartY) 702 public void LoadFromFile(string filename, int fileWidth, int fileHeight, int fileStartX, int fileStartY)
555 { 703 {
556 int offsetX = (int) m_scene.RegionInfo.RegionLocX - fileStartX; 704 int offsetX = (int)m_scene.RegionInfo.RegionLocX - fileStartX;
557 int offsetY = (int) m_scene.RegionInfo.RegionLocY - fileStartY; 705 int offsetY = (int)m_scene.RegionInfo.RegionLocY - fileStartY;
558 706
559 if (offsetX >= 0 && offsetX < fileWidth && offsetY >= 0 && offsetY < fileHeight) 707 if (offsetX >= 0 && offsetX < fileWidth && offsetY >= 0 && offsetY < fileHeight)
560 { 708 {
561 // this region is included in the tile request 709 // this region is included in the tile request
562 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) 710 foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
563 { 711 {
564 if (filename.EndsWith(loader.Key)) 712 if (filename.EndsWith(loader.Key))
565 { 713 {
566 lock (m_scene) 714 lock(m_scene)
567 { 715 {
568 ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY, 716 ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY,
569 fileWidth, fileHeight, 717 fileWidth, fileHeight,
570 (int) Constants.RegionSize, 718 (int)m_scene.RegionInfo.RegionSizeX,
571 (int) Constants.RegionSize); 719 (int)m_scene.RegionInfo.RegionSizeY);
572 m_scene.Heightmap = channel; 720 m_scene.Heightmap = channel;
573 m_channel = channel; 721 m_channel = channel;
574 UpdateRevertMap(); 722 UpdateRevertMap();
@@ -607,23 +755,23 @@ namespace OpenSim.Region.CoreModules.World.Terrain
607 } 755 }
608 756
609 // this region is included in the tile request 757 // this region is included in the tile request
610 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) 758 foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
611 { 759 {
612 if (filename.EndsWith(loader.Key) && loader.Value.SupportsTileSave()) 760 if (filename.EndsWith(loader.Key) && loader.Value.SupportsTileSave())
613 { 761 {
614 lock (m_scene) 762 lock(m_scene)
615 { 763 {
616 loader.Value.SaveFile(m_channel, filename, offsetX, offsetY, 764 loader.Value.SaveFile(m_channel, filename, offsetX, offsetY,
617 fileWidth, fileHeight, 765 fileWidth, fileHeight,
618 (int)Constants.RegionSize, 766 (int)m_scene.RegionInfo.RegionSizeX,
619 (int)Constants.RegionSize); 767 (int)m_scene.RegionInfo.RegionSizeY);
620 768
621 MainConsole.Instance.OutputFormat( 769 MainConsole.Instance.OutputFormat(
622 "Saved terrain from ({0},{1}) to ({2},{3}) from {4} to {5}", 770 "Saved terrain from ({0},{1}) to ({2},{3}) from {4} to {5}",
623 fileStartX, fileStartY, fileStartX + fileWidth - 1, fileStartY + fileHeight - 1, 771 fileStartX, fileStartY, fileStartX + fileWidth - 1, fileStartY + fileHeight - 1,
624 m_scene.RegionInfo.RegionName, filename); 772 m_scene.RegionInfo.RegionName, filename);
625 } 773 }
626 774
627 return; 775 return;
628 } 776 }
629 } 777 }
@@ -634,7 +782,44 @@ namespace OpenSim.Region.CoreModules.World.Terrain
634 } 782 }
635 783
636 /// <summary> 784 /// <summary>
785 /// Called before processing of every simulation frame.
786 /// This is used to check to see of any of the terrain is tainted and, if so, schedule
787 /// updates for all the presences.
788 /// This also checks to see if there are updates that need to be sent for each presence.
789 /// This is where the logic is to send terrain updates to clients.
790 /// </summary>
791 private void EventManager_OnFrame()
792 {
793 TerrainData terrData = m_channel.GetTerrainData();
794
795 bool shouldTaint = false;
796 for(int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize)
797 {
798 for(int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize)
799 {
800 if (terrData.IsTaintedAt(x, y))
801 {
802 // Found a patch that was modified. Push this flag into the clients.
803 SendToClients(terrData, x, y);
804 shouldTaint = true;
805 }
806 }
807 }
808
809 // This event also causes changes to be sent to the clients
810 CheckSendingPatchesToClients();
811
812 // If things changes, generate some events
813 if (shouldTaint)
814 {
815 m_scene.EventManager.TriggerTerrainTainted();
816 m_tainted = true;
817 }
818 }
819
820 /// <summary>
637 /// Performs updates to the region periodically, synchronising physics and other heightmap aware sections 821 /// Performs updates to the region periodically, synchronising physics and other heightmap aware sections
822 /// Called infrequently (like every 5 seconds or so). Best used for storing terrain.
638 /// </summary> 823 /// </summary>
639 private void EventManager_OnTerrainTick() 824 private void EventManager_OnTerrainTick()
640 { 825 {
@@ -665,7 +850,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
665 850
666 string[] tmpArgs = new string[args.Length - 2]; 851 string[] tmpArgs = new string[args.Length - 2];
667 int i; 852 int i;
668 for (i = 2; i < args.Length; i++) 853 for(i = 2; i < args.Length; i++)
669 tmpArgs[i - 2] = args[i]; 854 tmpArgs[i - 2] = args[i];
670 855
671 m_commander.ProcessConsoleCommand(args[1], tmpArgs); 856 m_commander.ProcessConsoleCommand(args[1], tmpArgs);
@@ -683,56 +868,50 @@ namespace OpenSim.Region.CoreModules.World.Terrain
683 client.OnLandUndo += client_OnLandUndo; 868 client.OnLandUndo += client_OnLandUndo;
684 client.OnUnackedTerrain += client_OnUnackedTerrain; 869 client.OnUnackedTerrain += client_OnUnackedTerrain;
685 } 870 }
686 871
687 /// <summary> 872 /// <summary>
688 /// Checks to see if the terrain has been modified since last check 873 /// Installs terrain brush hook to IClientAPI
689 /// but won't attempt to limit those changes to the limits specified in the estate settings
690 /// currently invoked by the command line operations in the region server only
691 /// </summary> 874 /// </summary>
692 private void CheckForTerrainUpdates() 875 /// <param name="client"></param>
876 private void EventManager_OnClientClosed(UUID client, Scene scene)
693 { 877 {
694 CheckForTerrainUpdates(false); 878 ScenePresence presence = scene.GetScenePresence(client);
879 if (presence != null)
880 {
881 presence.ControllingClient.OnModifyTerrain -= client_OnModifyTerrain;
882 presence.ControllingClient.OnBakeTerrain -= client_OnBakeTerrain;
883 presence.ControllingClient.OnLandUndo -= client_OnLandUndo;
884 presence.ControllingClient.OnUnackedTerrain -= client_OnUnackedTerrain;
885 }
886
887 lock(m_perClientPatchUpdates)
888 m_perClientPatchUpdates.Remove(client);
695 } 889 }
696 890
697 /// <summary> 891 /// <summary>
698 /// Checks to see if the terrain has been modified since last check. 892 /// Scan over changes in the terrain and limit height changes. This enforces the
699 /// If it has been modified, every all the terrain patches are sent to the client. 893 /// non-estate owner limits on rate of terrain editting.
700 /// If the call is asked to respect the estate settings for terrain_raise_limit and 894 /// Returns 'true' if any heights were limited.
701 /// terrain_lower_limit, it will clamp terrain updates between these values
702 /// currently invoked by client_OnModifyTerrain only and not the Commander interfaces
703 /// <param name="respectEstateSettings">should height map deltas be limited to the estate settings limits</param>
704 /// </summary> 895 /// </summary>
705 private void CheckForTerrainUpdates(bool respectEstateSettings) 896 private bool EnforceEstateLimits()
706 { 897 {
707 bool shouldTaint = false; 898 TerrainData terrData = m_channel.GetTerrainData();
708 float[] serialised = m_channel.GetFloatsSerialised(); 899
709 int x; 900 bool wasLimited = false;
710 for (x = 0; x < m_channel.Width; x += Constants.TerrainPatchSize) 901 for(int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize)
711 { 902 {
712 int y; 903 for(int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize)
713 for (y = 0; y < m_channel.Height; y += Constants.TerrainPatchSize)
714 { 904 {
715 if (m_channel.Tainted(x, y)) 905 if (terrData.IsTaintedAt(x, y, false /* clearOnTest */))
716 { 906 {
717 // if we should respect the estate settings then 907 // If we should respect the estate settings then
718 // fixup and height deltas that don't respect them 908 // fixup and height deltas that don't respect them.
719 if (respectEstateSettings && LimitChannelChanges(x, y)) 909 // Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values.
720 { 910 wasLimited |= LimitChannelChanges(terrData, x, y);
721 // this has been vetoed, so update
722 // what we are going to send to the client
723 serialised = m_channel.GetFloatsSerialised();
724 }
725
726 SendToClients(serialised, x, y);
727 shouldTaint = true;
728 } 911 }
729 } 912 }
730 } 913 }
731 if (shouldTaint) 914 return wasLimited;
732 {
733 m_scene.EventManager.TriggerTerrainTainted();
734 m_tainted = true;
735 }
736 } 915 }
737 916
738 /// <summary> 917 /// <summary>
@@ -740,31 +919,30 @@ namespace OpenSim.Region.CoreModules.World.Terrain
740 /// are all within the current estate limits 919 /// are all within the current estate limits
741 /// <returns>true if changes were limited, false otherwise</returns> 920 /// <returns>true if changes were limited, false otherwise</returns>
742 /// </summary> 921 /// </summary>
743 private bool LimitChannelChanges(int xStart, int yStart) 922 private bool LimitChannelChanges(TerrainData terrData, int xStart, int yStart)
744 { 923 {
745 bool changesLimited = false; 924 bool changesLimited = false;
746 double minDelta = m_scene.RegionInfo.RegionSettings.TerrainLowerLimit; 925 float minDelta = (float)m_scene.RegionInfo.RegionSettings.TerrainLowerLimit;
747 double maxDelta = m_scene.RegionInfo.RegionSettings.TerrainRaiseLimit; 926 float maxDelta = (float)m_scene.RegionInfo.RegionSettings.TerrainRaiseLimit;
748 927
749 // loop through the height map for this patch and compare it against 928 // loop through the height map for this patch and compare it against
750 // the revert map 929 // the revert map
751 for (int x = xStart; x < xStart + Constants.TerrainPatchSize; x++) 930 for(int x = xStart; x < xStart + Constants.TerrainPatchSize; x++)
752 { 931 {
753 for (int y = yStart; y < yStart + Constants.TerrainPatchSize; y++) 932 for(int y = yStart; y < yStart + Constants.TerrainPatchSize; y++)
754 { 933 {
755 934 float requestedHeight = terrData[x, y];
756 double requestedHeight = m_channel[x, y]; 935 float bakedHeight = (float)m_revert[x, y];
757 double bakedHeight = m_revert[x, y]; 936 float requestedDelta = requestedHeight - bakedHeight;
758 double requestedDelta = requestedHeight - bakedHeight;
759 937
760 if (requestedDelta > maxDelta) 938 if (requestedDelta > maxDelta)
761 { 939 {
762 m_channel[x, y] = bakedHeight + maxDelta; 940 terrData[x, y] = bakedHeight + maxDelta;
763 changesLimited = true; 941 changesLimited = true;
764 } 942 }
765 else if (requestedDelta < minDelta) 943 else if (requestedDelta < minDelta)
766 { 944 {
767 m_channel[x, y] = bakedHeight + minDelta; //as lower is a -ve delta 945 terrData[x, y] = bakedHeight + minDelta; //as lower is a -ve delta
768 changesLimited = true; 946 changesLimited = true;
769 } 947 }
770 } 948 }
@@ -775,7 +953,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
775 953
776 private void client_OnLandUndo(IClientAPI client) 954 private void client_OnLandUndo(IClientAPI client)
777 { 955 {
778 lock (m_undo) 956 lock(m_undo)
779 { 957 {
780 if (m_undo.Count > 0) 958 if (m_undo.Count > 0)
781 { 959 {
@@ -792,14 +970,177 @@ namespace OpenSim.Region.CoreModules.World.Terrain
792 /// <param name="serialised">A copy of the terrain as a 1D float array of size w*h</param> 970 /// <param name="serialised">A copy of the terrain as a 1D float array of size w*h</param>
793 /// <param name="x">The patch corner to send</param> 971 /// <param name="x">The patch corner to send</param>
794 /// <param name="y">The patch corner to send</param> 972 /// <param name="y">The patch corner to send</param>
795 private void SendToClients(float[] serialised, int x, int y) 973 private void SendToClients(TerrainData terrData, int x, int y)
796 { 974 {
797 m_scene.ForEachClient( 975 if (m_sendTerrainUpdatesByViewDistance)
798 delegate(IClientAPI controller) 976 {
799 { controller.SendLayerData( 977 // Add that this patch needs to be sent to the accounting for each client.
800 x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, serialised); 978 lock(m_perClientPatchUpdates)
979 {
980 m_scene.ForEachScenePresence(presence =>
981 {
982 PatchUpdates thisClientUpdates;
983 if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates))
984 {
985 // There is a ScenePresence without a send patch map. Create one.
986 thisClientUpdates = new PatchUpdates(terrData, presence);
987 m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates);
988 }
989 thisClientUpdates.SetByXY(x, y, true);
801 } 990 }
802 ); 991 );
992 }
993 }
994 else
995 {
996 // Legacy update sending where the update is sent out as soon as noticed
997 // We know the actual terrain data that is passed is ignored so this passes a dummy heightmap.
998 //float[] heightMap = terrData.GetFloatsSerialized();
999 float[] heightMap = new float[10];
1000 m_scene.ForEachClient(
1001 delegate(IClientAPI controller)
1002 {
1003 controller.SendLayerData(x / Constants.TerrainPatchSize,
1004 y / Constants.TerrainPatchSize,
1005 heightMap);
1006 }
1007 );
1008 }
1009 }
1010
1011 private class PatchesToSend : IComparable<PatchesToSend>
1012 {
1013 public int PatchX;
1014 public int PatchY;
1015 public float Dist;
1016
1017 public PatchesToSend(int pX, int pY, float pDist)
1018 {
1019 PatchX = pX;
1020 PatchY = pY;
1021 Dist = pDist;
1022 }
1023
1024 public int CompareTo(PatchesToSend other)
1025 {
1026 return Dist.CompareTo(other.Dist);
1027 }
1028 }
1029
1030 // Called each frame time to see if there are any patches to send to any of the
1031 // ScenePresences.
1032 // We know this is only called if we are doing view distance patch sending so some
1033 // tests are not made.
1034 // Loop through all the per-client info and send any patches necessary.
1035 private void CheckSendingPatchesToClients()
1036 {
1037 lock(m_perClientPatchUpdates)
1038 {
1039 foreach(PatchUpdates pups in m_perClientPatchUpdates.Values)
1040 {
1041 if (pups.HasUpdates())
1042 {
1043 // There is something that could be sent to this client.
1044 List<PatchesToSend> toSend = GetModifiedPatchesInViewDistance(pups);
1045 if (toSend.Count > 0)
1046 {
1047 // m_log.DebugFormat("{0} CheckSendingPatchesToClient: sending {1} patches to {2} in region {3}",
1048 // LogHeader, toSend.Count, pups.Presence.Name, m_scene.RegionInfo.RegionName);
1049 // Sort the patches to send by the distance from the presence
1050 toSend.Sort();
1051 /* old way that sent individual patches
1052 foreach (PatchesToSend pts in toSend)
1053 {
1054 pups.Presence.ControllingClient.SendLayerData(pts.PatchX, pts.PatchY, null);
1055 // presence.ControllingClient.SendLayerData(xs.ToArray(), ys.ToArray(), null, TerrainPatch.LayerType.Land);
1056 }
1057 */
1058
1059 // new way that sends all patches to the protocol so they can be sent in one block
1060 int[] xPieces = new int[toSend.Count];
1061 int[] yPieces = new int[toSend.Count];
1062 float[] patchPieces = new float[toSend.Count * 2];
1063 int pieceIndex = 0;
1064 foreach(PatchesToSend pts in toSend)
1065 {
1066 patchPieces[pieceIndex++] = pts.PatchX;
1067 patchPieces[pieceIndex++] = pts.PatchY;
1068 }
1069 pups.Presence.ControllingClient.SendLayerData(-toSend.Count, 0, patchPieces);
1070 }
1071 }
1072 }
1073 }
1074 }
1075
1076 // Compute a list of modified patches that are within our view distance.
1077 private List<PatchesToSend> GetModifiedPatchesInViewDistance(PatchUpdates pups)
1078 {
1079 List<PatchesToSend> ret = new List<PatchesToSend>();
1080
1081 ScenePresence presence = pups.Presence;
1082 if (presence == null)
1083 return ret;
1084
1085 Vector3 presencePos = presence.AbsolutePosition;
1086
1087 // Before this distance check, the whole region just showed up. Adding the distance
1088 // check causes different things to happen for the current and adjacent regions.
1089 // So, to keep legacy views, if the region is legacy sized, don't do distance check.
1090 bool isLegacySizedRegion = pups.Terrain.SizeX == Constants.RegionSize && pups.Terrain.SizeY == Constants.RegionSize;
1091 bool shouldCheckViewDistance = m_sendTerrainUpdatesByViewDistance && !isLegacySizedRegion;
1092
1093 int startX = 0;
1094 int endX = (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize;
1095 int startY = 0;
1096 int endY = (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize;
1097
1098 // The following only reduces the size of area scanned for updates. Only significant for very large varregions.
1099 if (shouldCheckViewDistance)
1100 {
1101 // Compute the area of patches within our draw distance
1102 startX = (((int)(presencePos.X - presence.DrawDistance)) / Constants.TerrainPatchSize) - 2;
1103 startX = Math.Max(startX, 0);
1104 startX = Math.Min(startX, (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize);
1105 startY = (((int)(presencePos.Y - presence.DrawDistance)) / Constants.TerrainPatchSize) - 2;
1106 startY = Math.Max(startY, 0);
1107 startY = Math.Min(startY, (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize);
1108 endX = (((int)(presencePos.X + presence.DrawDistance)) / Constants.TerrainPatchSize) + 2;
1109 endX = Math.Max(endX, 0);
1110 endX = Math.Min(endX, (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize);
1111 endY = (((int)(presencePos.Y + presence.DrawDistance)) / Constants.TerrainPatchSize) + 2;
1112 endY = Math.Max(endY, 0);
1113 endY = Math.Min(endY, (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize);
1114 }
1115
1116 // m_log.DebugFormat("{0} GetModifiedPatchesInViewDistance. rName={1}, ddist={2}, apos={3}, cpos={4}, isChild={5}, start=<{6},{7}>, end=<{8},{9}>",
1117 // LogHeader, m_scene.RegionInfo.RegionName,
1118 // presence.DrawDistance, presencePos, presence.CameraPosition,
1119 // isLegacySizeChildRegion,
1120 // startX, startY, endX, endY);
1121 for(int x = startX; x < endX; x++)
1122 {
1123 for(int y = startY; y < endY; y++)
1124 {
1125 //Need to make sure we don't send the same ones over and over
1126 Vector3 patchPos = new Vector3(x * Constants.TerrainPatchSize, y * Constants.TerrainPatchSize, presencePos.Z);
1127 if (pups.GetByPatch(x, y))
1128 {
1129 //Check which has less distance, camera or avatar position, both have to be done.
1130 //Its not a radius, its a diameter and we add 50 so that it doesn't look like it cuts off
1131 if (!shouldCheckViewDistance
1132 || Util.DistanceLessThan(presencePos, patchPos, presence.DrawDistance + 50)
1133 || Util.DistanceLessThan(presence.CameraPosition, patchPos, presence.DrawDistance + 50))
1134 {
1135 //They can see it, send it to them
1136 pups.SetByPatch(x, y, false);
1137 float dist = Vector3.DistanceSquared(presencePos, patchPos);
1138 ret.Add(new PatchesToSend(x, y, dist));
1139 }
1140 }
1141 }
1142 }
1143 return ret;
803 } 1144 }
804 1145
805 private void client_OnModifyTerrain(UUID user, float height, float seconds, byte size, byte action, 1146 private void client_OnModifyTerrain(UUID user, float height, float seconds, byte size, byte action,
@@ -809,28 +1150,28 @@ namespace OpenSim.Region.CoreModules.World.Terrain
809 bool allowed = false; 1150 bool allowed = false;
810 if (north == south && east == west) 1151 if (north == south && east == west)
811 { 1152 {
812 if (m_painteffects.ContainsKey((StandardTerrainEffects) action)) 1153 if (m_painteffects.ContainsKey((StandardTerrainEffects)action))
813 { 1154 {
814 bool[,] allowMask = new bool[m_channel.Width,m_channel.Height]; 1155 bool[,] allowMask = new bool[m_channel.Width, m_channel.Height];
815 allowMask.Initialize(); 1156 allowMask.Initialize();
816 int n = size + 1; 1157 int n = size + 1;
817 if (n > 2) 1158 if (n > 2)
818 n = 4; 1159 n = 4;
819 1160
820 int zx = (int) (west + 0.5); 1161 int zx = (int)(west + 0.5);
821 int zy = (int) (north + 0.5); 1162 int zy = (int)(north + 0.5);
822 1163
823 int dx; 1164 int dx;
824 for (dx=-n; dx<=n; dx++) 1165 for(dx=-n; dx<=n; dx++)
825 { 1166 {
826 int dy; 1167 int dy;
827 for (dy=-n; dy<=n; dy++) 1168 for(dy=-n; dy<=n; dy++)
828 { 1169 {
829 int x = zx + dx; 1170 int x = zx + dx;
830 int y = zy + dy; 1171 int y = zy + dy;
831 if (x>=0 && y>=0 && x<m_channel.Width && y<m_channel.Height) 1172 if (x >= 0 && y >= 0 && x < m_channel.Width && y < m_channel.Height)
832 { 1173 {
833 if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x,y,0))) 1174 if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0)))
834 { 1175 {
835 allowMask[x, y] = true; 1176 allowMask[x, y] = true;
836 allowed = true; 1177 allowed = true;
@@ -841,10 +1182,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain
841 if (allowed) 1182 if (allowed)
842 { 1183 {
843 StoreUndoState(); 1184 StoreUndoState();
844 m_painteffects[(StandardTerrainEffects) action].PaintEffect( 1185 m_painteffects[(StandardTerrainEffects)action].PaintEffect(
845 m_channel, allowMask, west, south, height, size, seconds); 1186 m_channel, allowMask, west, south, height, size, seconds);
846 1187
847 CheckForTerrainUpdates(!god); //revert changes outside estate limits 1188 //revert changes outside estate limits
1189 if (!god)
1190 EnforceEstateLimits();
848 } 1191 }
849 } 1192 }
850 else 1193 else
@@ -854,22 +1197,22 @@ namespace OpenSim.Region.CoreModules.World.Terrain
854 } 1197 }
855 else 1198 else
856 { 1199 {
857 if (m_floodeffects.ContainsKey((StandardTerrainEffects) action)) 1200 if (m_floodeffects.ContainsKey((StandardTerrainEffects)action))
858 { 1201 {
859 bool[,] fillArea = new bool[m_channel.Width,m_channel.Height]; 1202 bool[,] fillArea = new bool[m_channel.Width, m_channel.Height];
860 fillArea.Initialize(); 1203 fillArea.Initialize();
861 1204
862 int x; 1205 int x;
863 for (x = 0; x < m_channel.Width; x++) 1206 for(x = 0; x < m_channel.Width; x++)
864 { 1207 {
865 int y; 1208 int y;
866 for (y = 0; y < m_channel.Height; y++) 1209 for(y = 0; y < m_channel.Height; y++)
867 { 1210 {
868 if (x < east && x > west) 1211 if (x < east && x > west)
869 { 1212 {
870 if (y < north && y > south) 1213 if (y < north && y > south)
871 { 1214 {
872 if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x,y,0))) 1215 if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0)))
873 { 1216 {
874 fillArea[x, y] = true; 1217 fillArea[x, y] = true;
875 allowed = true; 1218 allowed = true;
@@ -882,10 +1225,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
882 if (allowed) 1225 if (allowed)
883 { 1226 {
884 StoreUndoState(); 1227 StoreUndoState();
885 m_floodeffects[(StandardTerrainEffects) action].FloodEffect( 1228 m_floodeffects[(StandardTerrainEffects)action].FloodEffect(m_channel, fillArea, size);
886 m_channel, fillArea, size);
887 1229
888 CheckForTerrainUpdates(!god); //revert changes outside estate limits 1230 //revert changes outside estate limits
1231 if (!god)
1232 EnforceEstateLimits();
889 } 1233 }
890 } 1234 }
891 else 1235 else
@@ -905,16 +1249,18 @@ namespace OpenSim.Region.CoreModules.World.Terrain
905 InterfaceBakeTerrain(null); //bake terrain does not use the passed in parameter 1249 InterfaceBakeTerrain(null); //bake terrain does not use the passed in parameter
906 } 1250 }
907 } 1251 }
908 1252
909 protected void client_OnUnackedTerrain(IClientAPI client, int patchX, int patchY) 1253 protected void client_OnUnackedTerrain(IClientAPI client, int patchX, int patchY)
910 { 1254 {
911 //m_log.Debug("Terrain packet unacked, resending patch: " + patchX + " , " + patchY); 1255 //m_log.Debug("Terrain packet unacked, resending patch: " + patchX + " , " + patchY);
912 client.SendLayerData(patchX, patchY, m_scene.Heightmap.GetFloatsSerialised()); 1256 // SendLayerData does not use the heightmap parameter. This kludge is so as to not change IClientAPI.
1257 float[] heightMap = new float[10];
1258 client.SendLayerData(patchX, patchY, heightMap);
913 } 1259 }
914 1260
915 private void StoreUndoState() 1261 private void StoreUndoState()
916 { 1262 {
917 lock (m_undo) 1263 lock(m_undo)
918 { 1264 {
919 if (m_undo.Count > 0) 1265 if (m_undo.Count > 0)
920 { 1266 {
@@ -935,23 +1281,21 @@ namespace OpenSim.Region.CoreModules.World.Terrain
935 1281
936 private void InterfaceLoadFile(Object[] args) 1282 private void InterfaceLoadFile(Object[] args)
937 { 1283 {
938 LoadFromFile((string) args[0]); 1284 LoadFromFile((string)args[0]);
939 CheckForTerrainUpdates();
940 } 1285 }
941 1286
942 private void InterfaceLoadTileFile(Object[] args) 1287 private void InterfaceLoadTileFile(Object[] args)
943 { 1288 {
944 LoadFromFile((string) args[0], 1289 LoadFromFile((string)args[0],
945 (int) args[1], 1290 (int)args[1],
946 (int) args[2], 1291 (int)args[2],
947 (int) args[3], 1292 (int)args[3],
948 (int) args[4]); 1293 (int)args[4]);
949 CheckForTerrainUpdates();
950 } 1294 }
951 1295
952 private void InterfaceSaveFile(Object[] args) 1296 private void InterfaceSaveFile(Object[] args)
953 { 1297 {
954 SaveToFile((string) args[0]); 1298 SaveToFile((string)args[0]);
955 } 1299 }
956 1300
957 private void InterfaceSaveTileFile(Object[] args) 1301 private void InterfaceSaveTileFile(Object[] args)
@@ -971,11 +1315,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
971 private void InterfaceRevertTerrain(Object[] args) 1315 private void InterfaceRevertTerrain(Object[] args)
972 { 1316 {
973 int x, y; 1317 int x, y;
974 for (x = 0; x < m_channel.Width; x++) 1318 for(x = 0; x < m_channel.Width; x++)
975 for (y = 0; y < m_channel.Height; y++) 1319 for(y = 0; y < m_channel.Height; y++)
976 m_channel[x, y] = m_revert[x, y]; 1320 m_channel[x, y] = m_revert[x, y];
977 1321
978 CheckForTerrainUpdates();
979 } 1322 }
980 1323
981 private void InterfaceFlipTerrain(Object[] args) 1324 private void InterfaceFlipTerrain(Object[] args)
@@ -984,39 +1327,36 @@ namespace OpenSim.Region.CoreModules.World.Terrain
984 1327
985 if (direction.ToLower().StartsWith("y")) 1328 if (direction.ToLower().StartsWith("y"))
986 { 1329 {
987 for (int x = 0; x < Constants.RegionSize; x++) 1330 for(int x = 0; x < m_channel.Width; x++)
988 { 1331 {
989 for (int y = 0; y < Constants.RegionSize / 2; y++) 1332 for(int y = 0; y < m_channel.Height / 2; y++)
990 { 1333 {
991 double height = m_channel[x, y]; 1334 double height = m_channel[x, y];
992 double flippedHeight = m_channel[x, (int)Constants.RegionSize - 1 - y]; 1335 double flippedHeight = m_channel[x, (int)m_channel.Height - 1 - y];
993 m_channel[x, y] = flippedHeight; 1336 m_channel[x, y] = flippedHeight;
994 m_channel[x, (int)Constants.RegionSize - 1 - y] = height; 1337 m_channel[x, (int)m_channel.Height - 1 - y] = height;
995 1338
996 } 1339 }
997 } 1340 }
998 } 1341 }
999 else if (direction.ToLower().StartsWith("x")) 1342 else if (direction.ToLower().StartsWith("x"))
1000 { 1343 {
1001 for (int y = 0; y < Constants.RegionSize; y++) 1344 for(int y = 0; y < m_channel.Height; y++)
1002 { 1345 {
1003 for (int x = 0; x < Constants.RegionSize / 2; x++) 1346 for(int x = 0; x < m_channel.Width / 2; x++)
1004 { 1347 {
1005 double height = m_channel[x, y]; 1348 double height = m_channel[x, y];
1006 double flippedHeight = m_channel[(int)Constants.RegionSize - 1 - x, y]; 1349 double flippedHeight = m_channel[(int)m_channel.Width - 1 - x, y];
1007 m_channel[x, y] = flippedHeight; 1350 m_channel[x, y] = flippedHeight;
1008 m_channel[(int)Constants.RegionSize - 1 - x, y] = height; 1351 m_channel[(int)m_channel.Width - 1 - x, y] = height;
1009 1352
1010 } 1353 }
1011 } 1354 }
1012 } 1355 }
1013 else 1356 else
1014 { 1357 {
1015 m_log.Error("Unrecognised direction - need x or y"); 1358 MainConsole.Instance.OutputFormat("ERROR: Unrecognised direction {0} - need x or y", direction);
1016 } 1359 }
1017
1018
1019 CheckForTerrainUpdates();
1020 } 1360 }
1021 1361
1022 private void InterfaceRescaleTerrain(Object[] args) 1362 private void InterfaceRescaleTerrain(Object[] args)
@@ -1042,9 +1382,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1042 int width = m_channel.Width; 1382 int width = m_channel.Width;
1043 int height = m_channel.Height; 1383 int height = m_channel.Height;
1044 1384
1045 for (int x = 0; x < width; x++) 1385 for(int x = 0; x < width; x++)
1046 { 1386 {
1047 for (int y = 0; y < height; y++) 1387 for(int y = 0; y < height; y++)
1048 { 1388 {
1049 double currHeight = m_channel[x, y]; 1389 double currHeight = m_channel[x, y];
1050 if (currHeight < currMin) 1390 if (currHeight < currMin)
@@ -1065,16 +1405,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1065 //m_log.InfoFormat("Scale = {0}", scale); 1405 //m_log.InfoFormat("Scale = {0}", scale);
1066 1406
1067 // scale the heightmap accordingly 1407 // scale the heightmap accordingly
1068 for (int x = 0; x < width; x++) 1408 for(int x = 0; x < width; x++)
1069 { 1409 {
1070 for (int y = 0; y < height; y++) 1410 for(int y = 0; y < height; y++)
1071 { 1411 {
1072 double currHeight = m_channel[x, y] - currMin; 1412 double currHeight = m_channel[x, y] - currMin;
1073 m_channel[x, y] = desiredMin + (currHeight * scale); 1413 m_channel[x, y] = desiredMin + (currHeight * scale);
1074 } 1414 }
1075 } 1415 }
1076 1416
1077 CheckForTerrainUpdates();
1078 } 1417 }
1079 1418
1080 } 1419 }
@@ -1082,64 +1421,73 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1082 private void InterfaceElevateTerrain(Object[] args) 1421 private void InterfaceElevateTerrain(Object[] args)
1083 { 1422 {
1084 int x, y; 1423 int x, y;
1085 for (x = 0; x < m_channel.Width; x++) 1424 for(x = 0; x < m_channel.Width; x++)
1086 for (y = 0; y < m_channel.Height; y++) 1425 for(y = 0; y < m_channel.Height; y++)
1087 m_channel[x, y] += (double) args[0]; 1426 m_channel[x, y] += (double)args[0];
1088 CheckForTerrainUpdates();
1089 } 1427 }
1090 1428
1091 private void InterfaceMultiplyTerrain(Object[] args) 1429 private void InterfaceMultiplyTerrain(Object[] args)
1092 { 1430 {
1093 int x, y; 1431 int x, y;
1094 for (x = 0; x < m_channel.Width; x++) 1432 for(x = 0; x < m_channel.Width; x++)
1095 for (y = 0; y < m_channel.Height; y++) 1433 for(y = 0; y < m_channel.Height; y++)
1096 m_channel[x, y] *= (double) args[0]; 1434 m_channel[x, y] *= (double)args[0];
1097 CheckForTerrainUpdates();
1098 } 1435 }
1099 1436
1100 private void InterfaceLowerTerrain(Object[] args) 1437 private void InterfaceLowerTerrain(Object[] args)
1101 { 1438 {
1102 int x, y; 1439 int x, y;
1103 for (x = 0; x < m_channel.Width; x++) 1440 for(x = 0; x < m_channel.Width; x++)
1104 for (y = 0; y < m_channel.Height; y++) 1441 for(y = 0; y < m_channel.Height; y++)
1105 m_channel[x, y] -= (double) args[0]; 1442 m_channel[x, y] -= (double)args[0];
1106 CheckForTerrainUpdates();
1107 } 1443 }
1108 1444
1109 private void InterfaceFillTerrain(Object[] args) 1445 public void InterfaceFillTerrain(Object[] args)
1110 { 1446 {
1111 int x, y; 1447 int x, y;
1112 1448
1113 for (x = 0; x < m_channel.Width; x++) 1449 for(x = 0; x < m_channel.Width; x++)
1114 for (y = 0; y < m_channel.Height; y++) 1450 for(y = 0; y < m_channel.Height; y++)
1115 m_channel[x, y] = (double) args[0]; 1451 m_channel[x, y] = (double)args[0];
1116 CheckForTerrainUpdates();
1117 } 1452 }
1118 1453
1119 private void InterfaceMinTerrain(Object[] args) 1454 private void InterfaceMinTerrain(Object[] args)
1120 { 1455 {
1121 int x, y; 1456 int x, y;
1122 for (x = 0; x < m_channel.Width; x++) 1457 for(x = 0; x < m_channel.Width; x++)
1123 { 1458 {
1124 for (y = 0; y < m_channel.Height; y++) 1459 for(y = 0; y < m_channel.Height; y++)
1125 { 1460 {
1126 m_channel[x, y] = Math.Max((double)args[0], m_channel[x, y]); 1461 m_channel[x, y] = Math.Max((double)args[0], m_channel[x, y]);
1127 } 1462 }
1128 } 1463 }
1129 CheckForTerrainUpdates();
1130 } 1464 }
1131 1465
1132 private void InterfaceMaxTerrain(Object[] args) 1466 private void InterfaceMaxTerrain(Object[] args)
1133 { 1467 {
1134 int x, y; 1468 int x, y;
1135 for (x = 0; x < m_channel.Width; x++) 1469 for(x = 0; x < m_channel.Width; x++)
1136 { 1470 {
1137 for (y = 0; y < m_channel.Height; y++) 1471 for(y = 0; y < m_channel.Height; y++)
1138 { 1472 {
1139 m_channel[x, y] = Math.Min((double)args[0], m_channel[x, y]); 1473 m_channel[x, y] = Math.Min((double)args[0], m_channel[x, y]);
1140 } 1474 }
1141 } 1475 }
1142 CheckForTerrainUpdates(); 1476 }
1477
1478 private void InterfaceShow(Object[] args)
1479 {
1480 Vector2 point;
1481
1482 if (!ConsoleUtil.TryParseConsole2DVector((string)args[0], null, out point))
1483 {
1484 Console.WriteLine("ERROR: {0} is not a valid vector", args[0]);
1485 return;
1486 }
1487
1488 double height = m_channel[(int)point.X, (int)point.Y];
1489
1490 Console.WriteLine("Terrain height at {0} is {1}", point, height);
1143 } 1491 }
1144 1492
1145 private void InterfaceShowDebugStats(Object[] args) 1493 private void InterfaceShowDebugStats(Object[] args)
@@ -1149,10 +1497,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1149 double sum = 0; 1497 double sum = 0;
1150 1498
1151 int x; 1499 int x;
1152 for (x = 0; x < m_channel.Width; x++) 1500 for(x = 0; x < m_channel.Width; x++)
1153 { 1501 {
1154 int y; 1502 int y;
1155 for (y = 0; y < m_channel.Height; y++) 1503 for(y = 0; y < m_channel.Height; y++)
1156 { 1504 {
1157 sum += m_channel[x, y]; 1505 sum += m_channel[x, y];
1158 if (max < m_channel[x, y]) 1506 if (max < m_channel[x, y])
@@ -1164,13 +1512,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1164 1512
1165 double avg = sum / (m_channel.Height * m_channel.Width); 1513 double avg = sum / (m_channel.Height * m_channel.Width);
1166 1514
1167 m_log.Info("Channel " + m_channel.Width + "x" + m_channel.Height); 1515 MainConsole.Instance.OutputFormat("Channel {0}x{1}", m_channel.Width, m_channel.Height);
1168 m_log.Info("max/min/avg/sum: " + max + "/" + min + "/" + avg + "/" + sum); 1516 MainConsole.Instance.OutputFormat("max/min/avg/sum: {0}/{1}/{2}/{3}", max, min, avg, sum);
1169 } 1517 }
1170 1518
1171 private void InterfaceEnableExperimentalBrushes(Object[] args) 1519 private void InterfaceEnableExperimentalBrushes(Object[] args)
1172 { 1520 {
1173 if ((bool) args[0]) 1521 if ((bool)args[0])
1174 { 1522 {
1175 m_painteffects[StandardTerrainEffects.Revert] = new WeatherSphere(); 1523 m_painteffects[StandardTerrainEffects.Revert] = new WeatherSphere();
1176 m_painteffects[StandardTerrainEffects.Flatten] = new OlsenSphere(); 1524 m_painteffects[StandardTerrainEffects.Flatten] = new OlsenSphere();
@@ -1185,28 +1533,30 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1185 private void InterfaceRunPluginEffect(Object[] args) 1533 private void InterfaceRunPluginEffect(Object[] args)
1186 { 1534 {
1187 string firstArg = (string)args[0]; 1535 string firstArg = (string)args[0];
1536
1188 if (firstArg == "list") 1537 if (firstArg == "list")
1189 { 1538 {
1190 m_log.Info("List of loaded plugins"); 1539 MainConsole.Instance.Output("List of loaded plugins");
1191 foreach (KeyValuePair<string, ITerrainEffect> kvp in m_plugineffects) 1540 foreach(KeyValuePair<string, ITerrainEffect> kvp in m_plugineffects)
1192 { 1541 {
1193 m_log.Info(kvp.Key); 1542 MainConsole.Instance.Output(kvp.Key);
1194 } 1543 }
1195 return; 1544 return;
1196 } 1545 }
1546
1197 if (firstArg == "reload") 1547 if (firstArg == "reload")
1198 { 1548 {
1199 LoadPlugins(); 1549 LoadPlugins();
1200 return; 1550 return;
1201 } 1551 }
1552
1202 if (m_plugineffects.ContainsKey(firstArg)) 1553 if (m_plugineffects.ContainsKey(firstArg))
1203 { 1554 {
1204 m_plugineffects[firstArg].RunEffect(m_channel); 1555 m_plugineffects[firstArg].RunEffect(m_channel);
1205 CheckForTerrainUpdates();
1206 } 1556 }
1207 else 1557 else
1208 { 1558 {
1209 m_log.Warn("No such plugin effect loaded."); 1559 MainConsole.Instance.Output("WARNING: No such plugin effect {0} loaded.", firstArg);
1210 } 1560 }
1211 } 1561 }
1212 1562
@@ -1295,12 +1645,17 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1295 new Command("stats", CommandIntentions.COMMAND_STATISTICAL, InterfaceShowDebugStats, 1645 new Command("stats", CommandIntentions.COMMAND_STATISTICAL, InterfaceShowDebugStats,
1296 "Shows some information about the regions heightmap for debugging purposes."); 1646 "Shows some information about the regions heightmap for debugging purposes.");
1297 1647
1648 Command showCommand =
1649 new Command("show", CommandIntentions.COMMAND_NON_HAZARDOUS, InterfaceShow,
1650 "Shows terrain height at a given co-ordinate.");
1651 showCommand.AddArgument("point", "point in <x>,<y> format with no spaces (e.g. 45,45)", "String");
1652
1298 Command experimentalBrushesCommand = 1653 Command experimentalBrushesCommand =
1299 new Command("newbrushes", CommandIntentions.COMMAND_HAZARDOUS, InterfaceEnableExperimentalBrushes, 1654 new Command("newbrushes", CommandIntentions.COMMAND_HAZARDOUS, InterfaceEnableExperimentalBrushes,
1300 "Enables experimental brushes which replace the standard terrain brushes. WARNING: This is a debug setting and may be removed at any time."); 1655 "Enables experimental brushes which replace the standard terrain brushes. WARNING: This is a debug setting and may be removed at any time.");
1301 experimentalBrushesCommand.AddArgument("Enabled?", "true / false - Enable new brushes", "Boolean"); 1656 experimentalBrushesCommand.AddArgument("Enabled?", "true / false - Enable new brushes", "Boolean");
1302 1657
1303 //Plugins 1658 // Plugins
1304 Command pluginRunCommand = 1659 Command pluginRunCommand =
1305 new Command("effect", CommandIntentions.COMMAND_HAZARDOUS, InterfaceRunPluginEffect, "Runs a specified plugin effect"); 1660 new Command("effect", CommandIntentions.COMMAND_HAZARDOUS, InterfaceRunPluginEffect, "Runs a specified plugin effect");
1306 pluginRunCommand.AddArgument("name", "The plugin effect you wish to run, or 'list' to see all plugins", "String"); 1661 pluginRunCommand.AddArgument("name", "The plugin effect you wish to run, or 'list' to see all plugins", "String");
@@ -1316,6 +1671,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1316 m_commander.RegisterCommand("bake", bakeRegionCommand); 1671 m_commander.RegisterCommand("bake", bakeRegionCommand);
1317 m_commander.RegisterCommand("revert", revertRegionCommand); 1672 m_commander.RegisterCommand("revert", revertRegionCommand);
1318 m_commander.RegisterCommand("newbrushes", experimentalBrushesCommand); 1673 m_commander.RegisterCommand("newbrushes", experimentalBrushesCommand);
1674 m_commander.RegisterCommand("show", showCommand);
1319 m_commander.RegisterCommand("stats", showDebugStatsCommand); 1675 m_commander.RegisterCommand("stats", showDebugStatsCommand);
1320 m_commander.RegisterCommand("effect", pluginRunCommand); 1676 m_commander.RegisterCommand("effect", pluginRunCommand);
1321 m_commander.RegisterCommand("flip", flipCommand); 1677 m_commander.RegisterCommand("flip", flipCommand);
@@ -1325,10 +1681,66 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1325 1681
1326 // Add this to our scene so scripts can call these functions 1682 // Add this to our scene so scripts can call these functions
1327 m_scene.RegisterModuleCommander(m_commander); 1683 m_scene.RegisterModuleCommander(m_commander);
1684
1685 // Add Modify command to Scene, since Command object requires fixed-length arglists
1686 m_scene.AddCommand("Terrain", this, "terrain modify",
1687 "terrain modify <operation> <value> [<area>] [<taper>]",
1688 "Modifies the terrain as instructed." +
1689 "\nEach operation can be limited to an area of effect:" +
1690 "\n * -ell=x,y,rx[,ry] constrains the operation to an ellipse centred at x,y" +
1691 "\n * -rec=x,y,dx[,dy] constrains the operation to a rectangle based at x,y" +
1692 "\nEach operation can have its effect tapered based on distance from centre:" +
1693 "\n * elliptical operations taper as cones" +
1694 "\n * rectangular operations taper as pyramids"
1695 ,
1696 ModifyCommand);
1697
1328 } 1698 }
1329 1699
1700 public void ModifyCommand(string module, string[] cmd)
1701 {
1702 string result;
1703 Scene scene = SceneManager.Instance.CurrentScene;
1704 if ((scene != null) && (scene != m_scene))
1705 {
1706 result = String.Empty;
1707 }
1708 else if (cmd.Length > 2)
1709 {
1710 string operationType = cmd[2];
1330 1711
1331 #endregion 1712
1713 ITerrainModifier operation;
1714 if (!m_modifyOperations.TryGetValue(operationType, out operation))
1715 {
1716 result = String.Format("Terrain Modify \"{0}\" not found.", operationType);
1717 }
1718 else if ((cmd.Length > 3) && (cmd[3] == "usage"))
1719 {
1720 result = "Usage: " + operation.GetUsage();
1721 }
1722 else
1723 {
1724 result = operation.ModifyTerrain(m_channel, cmd);
1725 }
1726
1727 if (result == String.Empty)
1728 {
1729 result = "Modified terrain";
1730 m_log.DebugFormat("Performed terrain operation {0}", operationType);
1731 }
1732 }
1733 else
1734 {
1735 result = "Usage: <operation-name> <arg1> <arg2>...";
1736 }
1737 if (result != String.Empty)
1738 {
1739 MainConsole.Instance.Output(result);
1740 }
1741 }
1742
1743#endregion
1332 1744
1333 } 1745 }
1334} 1746}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainModuleTests.cs b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainModuleTests.cs
new file mode 100644
index 0000000..0563ad0
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainModuleTests.cs
@@ -0,0 +1,75 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using NUnit.Framework;
30using OpenSim.Framework;
31using OpenSim.Region.CoreModules.World.Terrain;
32using OpenSim.Region.Framework.Scenes;
33using OpenSim.Tests.Common;
34
35namespace OpenSim.Region.CoreModules.Terrain.Tests
36{
37 public class TerrainModuleTests : OpenSimTestCase
38 {
39 [Test]
40 public void TestTerrainFill()
41 {
42 TestHelpers.InMethod();
43// TestHelpers.EnableLogging();
44
45 //UUID userId = TestHelpers.ParseTail(0x1);
46
47 TerrainModule tm = new TerrainModule();
48 Scene scene = new SceneHelpers().SetupScene();
49 SceneHelpers.SetupSceneModules(scene, tm);
50
51 // Fillheight of 30
52 {
53 double fillHeight = 30;
54
55 tm.InterfaceFillTerrain(new object[] { fillHeight });
56
57 double height = scene.Heightmap[128, 128];
58
59 Assert.AreEqual(fillHeight, height);
60 }
61
62 // Max fillheight of 30
63 // According to http://wiki.secondlife.com/wiki/Tips_for_Creating_Heightfields_and_Details_on_Terrain_RAW_Files#Notes_for_Creating_Height_Field_Maps_for_Second_Life
64 {
65 double fillHeight = 508;
66
67 tm.InterfaceFillTerrain(new object[] { fillHeight });
68
69 double height = scene.Heightmap[128, 128];
70
71 Assert.AreEqual(fillHeight, height);
72 }
73 }
74 }
75} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs
index be719ea..29e80ef 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs
@@ -40,10 +40,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests
40 [Test] 40 [Test]
41 public void BrushTest() 41 public void BrushTest()
42 { 42 {
43 int midRegion = (int)Constants.RegionSize / 2;
44
45 // Create a mask that covers only the left half of the region
43 bool[,] allowMask = new bool[(int)Constants.RegionSize, 256]; 46 bool[,] allowMask = new bool[(int)Constants.RegionSize, 256];
44 int x; 47 int x;
45 int y; 48 int y;
46 for (x = 0; x < (int)((int)Constants.RegionSize * 0.5f); x++) 49 for (x = 0; x < midRegion; x++)
47 { 50 {
48 for (y = 0; y < (int)Constants.RegionSize; y++) 51 for (y = 0; y < (int)Constants.RegionSize; y++)
49 { 52 {
@@ -57,13 +60,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests
57 TerrainChannel map = new TerrainChannel((int)Constants.RegionSize, (int)Constants.RegionSize); 60 TerrainChannel map = new TerrainChannel((int)Constants.RegionSize, (int)Constants.RegionSize);
58 ITerrainPaintableEffect effect = new RaiseSphere(); 61 ITerrainPaintableEffect effect = new RaiseSphere();
59 62
60 effect.PaintEffect(map, allowMask, (int)Constants.RegionSize * 0.5f, (int)Constants.RegionSize * 0.5f, -1.0, 2, 0.1); 63 effect.PaintEffect(map, allowMask, midRegion, midRegion, -1.0, 2, 6.0);
61 Assert.That(map[127, (int)((int)Constants.RegionSize * 0.5f)] > 0.0, "Raise brush should raising value at this point (127,128)."); 64 Assert.That(map[127, midRegion] > 0.0, "Raise brush should raising value at this point (127,128).");
62 Assert.That(map[124, (int)((int)Constants.RegionSize * 0.5f)] > 0.0, "Raise brush should raising value at this point (124,128)."); 65 Assert.That(map[125, midRegion] > 0.0, "Raise brush should raising value at this point (124,128).");
63 Assert.That(map[123, (int)((int)Constants.RegionSize * 0.5f)] == 0.0, "Raise brush should not change value at this point (123,128)."); 66 Assert.That(map[120, midRegion] == 0.0, "Raise brush should not change value at this point (120,128).");
64 Assert.That(map[128, (int)((int)Constants.RegionSize * 0.5f)] == 0.0, "Raise brush should not change value at this point (128,128)."); 67 Assert.That(map[128, midRegion] == 0.0, "Raise brush should not change value at this point (128,128).");
65 Assert.That(map[0, (int)((int)Constants.RegionSize * 0.5f)] == 0.0, "Raise brush should not change value at this point (0,128)."); 68 Assert.That(map[0, midRegion] == 0.0, "Raise brush should not change value at this point (0,128).");
66
67 // 69 //
68 // Test LowerSphere 70 // Test LowerSphere
69 // 71 //
@@ -77,13 +79,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests
77 } 79 }
78 effect = new LowerSphere(); 80 effect = new LowerSphere();
79 81
80 effect.PaintEffect(map, allowMask, ((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), -1.0, 2, 6.0); 82 effect.PaintEffect(map, allowMask, midRegion, midRegion, -1.0, 2, 6.0);
81 Assert.That(map[127, (int)((int)Constants.RegionSize * 0.5f)] >= 0.0, "Lower should not lowering value below 0.0 at this point (127,128)."); 83 Assert.That(map[127, midRegion] >= 0.0, "Lower should not lowering value below 0.0 at this point (127,128).");
82 Assert.That(map[127, (int)((int)Constants.RegionSize * 0.5f)] == 0.0, "Lower brush should lowering value to 0.0 at this point (127,128)."); 84 Assert.That(map[127, midRegion] == 0.0, "Lower brush should lowering value to 0.0 at this point (127,128).");
83 Assert.That(map[124, (int)((int)Constants.RegionSize * 0.5f)] < 1.0, "Lower brush should lowering value at this point (124,128)."); 85 Assert.That(map[125, midRegion] < 1.0, "Lower brush should lowering value at this point (124,128).");
84 Assert.That(map[123, (int)((int)Constants.RegionSize * 0.5f)] == 1.0, "Lower brush should not change value at this point (123,128)."); 86 Assert.That(map[120, midRegion] == 1.0, "Lower brush should not change value at this point (120,128).");
85 Assert.That(map[128, (int)((int)Constants.RegionSize * 0.5f)] == 1.0, "Lower brush should not change value at this point (128,128)."); 87 Assert.That(map[128, midRegion] == 1.0, "Lower brush should not change value at this point (128,128).");
86 Assert.That(map[0, (int)((int)Constants.RegionSize * 0.5f)] == 1.0, "Lower brush should not change value at this point (0,128)."); 88 Assert.That(map[0, midRegion] == 1.0, "Lower brush should not change value at this point (0,128).");
87 } 89 }
88 90
89 [Test] 91 [Test]
@@ -100,10 +102,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests
100 x[0, 0] -= 1.0; 102 x[0, 0] -= 1.0;
101 Assert.That(x[0, 0] == 4.0, "Terrain addition/subtraction error."); 103 Assert.That(x[0, 0] == 4.0, "Terrain addition/subtraction error.");
102 104
103 x[0, 0] = Math.PI;
104 double[,] doublesExport = x.GetDoubles();
105 Assert.That(doublesExport[0, 0] == Math.PI, "Export to double[,] array not working correctly.");
106
107 x[0, 0] = 1.0; 105 x[0, 0] = 1.0;
108 float[] floatsExport = x.GetFloatsSerialised(); 106 float[] floatsExport = x.GetFloatsSerialised();
109 Assert.That(floatsExport[0] == 1.0f, "Export to float[] not working correctly."); 107 Assert.That(floatsExport[0] == 1.0f, "Export to float[] not working correctly.");
diff --git a/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs b/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs
index df5ac92..9534ad3 100644
--- a/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs
+++ b/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -32,6 +32,7 @@ using System.Drawing.Imaging;
32using log4net; 32using log4net;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Services.Interfaces; 36using OpenSim.Services.Interfaces;
36 37
37namespace OpenSim.Region.CoreModules.World.Warp3DMap 38namespace OpenSim.Region.CoreModules.World.Warp3DMap
@@ -66,261 +67,271 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
66 #endregion Constants 67 #endregion Constants
67 68
68 private static readonly ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); 69 private static readonly ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
70 private static string LogHeader = "[WARP3D TERRAIN SPLAT]";
69 71
70 /// <summary> 72 /// <summary>
71 /// Builds a composited terrain texture given the region texture 73 /// Builds a composited terrain texture given the region texture
72 /// and heightmap settings 74 /// and heightmap settings
73 /// </summary> 75 /// </summary>
74 /// <param name="heightmap">Terrain heightmap</param> 76 /// <param name="terrain">Terrain heightmap</param>
75 /// <param name="regionInfo">Region information including terrain texture parameters</param> 77 /// <param name="regionInfo">Region information including terrain texture parameters</param>
76 /// <returns>A composited 256x256 RGB texture ready for rendering</returns> 78 /// <returns>A 256x256 square RGB texture ready for rendering</returns>
77 /// <remarks>Based on the algorithm described at http://opensimulator.org/wiki/Terrain_Splatting 79 /// <remarks>Based on the algorithm described at http://opensimulator.org/wiki/Terrain_Splatting
80 /// Note we create a 256x256 dimension texture even if the actual terrain is larger.
78 /// </remarks> 81 /// </remarks>
79 public static Bitmap Splat(float[] heightmap, UUID[] textureIDs, float[] startHeights, float[] heightRanges, Vector3d regionPosition, IAssetService assetService, bool textureTerrain) 82 public static Bitmap Splat(ITerrainChannel terrain,
83 UUID[] textureIDs, float[] startHeights, float[] heightRanges,
84 Vector3d regionPosition, IAssetService assetService, bool textureTerrain)
80 { 85 {
81 Debug.Assert(heightmap.Length == 256 * 256);
82 Debug.Assert(textureIDs.Length == 4); 86 Debug.Assert(textureIDs.Length == 4);
83 Debug.Assert(startHeights.Length == 4); 87 Debug.Assert(startHeights.Length == 4);
84 Debug.Assert(heightRanges.Length == 4); 88 Debug.Assert(heightRanges.Length == 4);
85 89
86 Bitmap[] detailTexture = new Bitmap[4]; 90 Bitmap[] detailTexture = new Bitmap[4];
87 Bitmap output = null;
88 BitmapData outputData = null;
89 91
90 try 92 if (textureTerrain)
91 { 93 {
92 if (textureTerrain) 94 // Swap empty terrain textureIDs with default IDs
95 for (int i = 0; i < textureIDs.Length; i++)
93 { 96 {
94 // Swap empty terrain textureIDs with default IDs 97 if (textureIDs[i] == UUID.Zero)
95 for (int i = 0; i < textureIDs.Length; i++) 98 textureIDs[i] = DEFAULT_TERRAIN_DETAIL[i];
96 { 99 }
97 if (textureIDs[i] == UUID.Zero) 100
98 textureIDs[i] = DEFAULT_TERRAIN_DETAIL[i]; 101 #region Texture Fetching
99 } 102
100 103 if (assetService != null)
101 #region Texture Fetching 104 {
102 105 for (int i = 0; i < 4; i++)
103 if (assetService != null)
104 { 106 {
105 for (int i = 0; i < 4; i++) 107 AssetBase asset;
108 UUID cacheID = UUID.Combine(TERRAIN_CACHE_MAGIC, textureIDs[i]);
109
110 // Try to fetch a cached copy of the decoded/resized version of this texture
111 asset = assetService.GetCached(cacheID.ToString());
112 if (asset != null)
113 {
114 try
115 {
116 using (System.IO.MemoryStream stream = new System.IO.MemoryStream(asset.Data))
117 detailTexture[i] = (Bitmap)Image.FromStream(stream);
118 }
119 catch (Exception ex)
120 {
121 m_log.Warn("Failed to decode cached terrain texture " + cacheID +
122 " (textureID: " + textureIDs[i] + "): " + ex.Message);
123 }
124 }
125
126 if (detailTexture[i] == null)
106 { 127 {
107 AssetBase asset; 128 // Try to fetch the original JPEG2000 texture, resize if needed, and cache as PNG
108 UUID cacheID = UUID.Combine(TERRAIN_CACHE_MAGIC, textureIDs[i]); 129 asset = assetService.Get(textureIDs[i].ToString());
109
110 // Try to fetch a cached copy of the decoded/resized version of this texture
111 asset = assetService.GetCached(cacheID.ToString());
112 if (asset != null) 130 if (asset != null)
113 { 131 {
114// m_log.DebugFormat( 132// m_log.DebugFormat(
115// "[TERRAIN SPLAT]: Got asset service cached terrain texture {0} {1}", i, asset.ID); 133// "[TERRAIN SPLAT]: Got cached original JPEG2000 terrain texture {0} {1}", i, asset.ID);
116 134
117 try 135 try { detailTexture[i] = (Bitmap)CSJ2K.J2kImage.FromBytes(asset.Data); }
118 {
119 using (System.IO.MemoryStream stream = new System.IO.MemoryStream(asset.Data))
120 detailTexture[i] = (Bitmap)Image.FromStream(stream);
121 }
122 catch (Exception ex) 136 catch (Exception ex)
123 { 137 {
124 m_log.Warn("Failed to decode cached terrain texture " + cacheID + 138 m_log.Warn("Failed to decode terrain texture " + asset.ID + ": " + ex.Message);
125 " (textureID: " + textureIDs[i] + "): " + ex.Message);
126 } 139 }
127 } 140 }
128
129 if (detailTexture[i] == null)
130 {
131 // Try to fetch the original JPEG2000 texture, resize if needed, and cache as PNG
132 asset = assetService.Get(textureIDs[i].ToString());
133 if (asset != null)
134 {
135// m_log.DebugFormat(
136// "[TERRAIN SPLAT]: Got cached original JPEG2000 terrain texture {0} {1}", i, asset.ID);
137 141
138 try { detailTexture[i] = (Bitmap)CSJ2K.J2kImage.FromBytes(asset.Data); } 142 if (detailTexture[i] != null)
139 catch (Exception ex) 143 {
144 // Make sure this texture is the correct size, otherwise resize
145 if (detailTexture[i].Width != 256 || detailTexture[i].Height != 256)
146 {
147 using (Bitmap origBitmap = detailTexture[i])
140 { 148 {
141 m_log.Warn("Failed to decode terrain texture " + asset.ID + ": " + ex.Message); 149 detailTexture[i] = ImageUtils.ResizeImage(origBitmap, 256, 256);
142 } 150 }
143 } 151 }
144 152
145 if (detailTexture[i] != null) 153 // Save the decoded and resized texture to the cache
146 { 154 byte[] data;
147 // Make sure this texture is the correct size, otherwise resize 155 using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
148 if (detailTexture[i].Width != 256 || detailTexture[i].Height != 256) 156 {
149 { 157 detailTexture[i].Save(stream, ImageFormat.Png);
150 using (Bitmap origBitmap = detailTexture[i]) 158 data = stream.ToArray();
151 {
152 detailTexture[i] = ImageUtils.ResizeImage(origBitmap, 256, 256);
153 }
154 }
155
156 // Save the decoded and resized texture to the cache
157 byte[] data;
158 using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
159 {
160 detailTexture[i].Save(stream, ImageFormat.Png);
161 data = stream.ToArray();
162 }
163
164 // Cache a PNG copy of this terrain texture
165 AssetBase newAsset = new AssetBase
166 {
167 Data = data,
168 Description = "PNG",
169 Flags = AssetFlags.Collectable,
170 FullID = cacheID,
171 ID = cacheID.ToString(),
172 Local = true,
173 Name = String.Empty,
174 Temporary = true,
175 Type = (sbyte)AssetType.Unknown
176 };
177 newAsset.Metadata.ContentType = "image/png";
178 assetService.Store(newAsset);
179 } 159 }
160
161 // Cache a PNG copy of this terrain texture
162 AssetBase newAsset = new AssetBase
163 {
164 Data = data,
165 Description = "PNG",
166 Flags = AssetFlags.Collectable,
167 FullID = cacheID,
168 ID = cacheID.ToString(),
169 Local = true,
170 Name = String.Empty,
171 Temporary = true,
172 Type = (sbyte)AssetType.Unknown
173 };
174 newAsset.Metadata.ContentType = "image/png";
175 assetService.Store(newAsset);
180 } 176 }
181 } 177 }
182 } 178 }
183
184 #endregion Texture Fetching
185 } 179 }
186 180
187 // Fill in any missing textures with a solid color 181 #endregion Texture Fetching
188 for (int i = 0; i < 4; i++) 182 }
183
184 // Fill in any missing textures with a solid color
185 for (int i = 0; i < 4; i++)
186 {
187 if (detailTexture[i] == null)
189 { 188 {
190 if (detailTexture[i] == null) 189 m_log.DebugFormat("{0} Missing terrain texture for layer {1}. Filling with solid default color",
190 LogHeader, i);
191 // Create a solid color texture for this layer
192 detailTexture[i] = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
193 using (Graphics gfx = Graphics.FromImage(detailTexture[i]))
191 { 194 {
192// m_log.DebugFormat( 195 using (SolidBrush brush = new SolidBrush(DEFAULT_TERRAIN_COLOR[i]))
193// "[TERRAIN SPLAT]: Generating solid colour for missing texture {0}", i); 196 gfx.FillRectangle(brush, 0, 0, 256, 256);
194
195 // Create a solid color texture for this layer
196 detailTexture[i] = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
197 using (Graphics gfx = Graphics.FromImage(detailTexture[i]))
198 {
199 using (SolidBrush brush = new SolidBrush(DEFAULT_TERRAIN_COLOR[i]))
200 gfx.FillRectangle(brush, 0, 0, 256, 256);
201 }
202 } 197 }
203 } 198 }
204 199 else
205 #region Layer Map
206
207 float[] layermap = new float[256 * 256];
208
209 for (int y = 0; y < 256; y++)
210 { 200 {
211 for (int x = 0; x < 256; x++) 201 if (detailTexture[i].Width != 256 || detailTexture[i].Height != 256)
212 { 202 {
213 float height = heightmap[y * 256 + x]; 203 detailTexture[i] = ResizeBitmap(detailTexture[i], 256, 256);
214
215 float pctX = (float)x / 255f;
216 float pctY = (float)y / 255f;
217
218 // Use bilinear interpolation between the four corners of start height and
219 // height range to select the current values at this position
220 float startHeight = ImageUtils.Bilinear(
221 startHeights[0],
222 startHeights[2],
223 startHeights[1],
224 startHeights[3],
225 pctX, pctY);
226 startHeight = Utils.Clamp(startHeight, 0f, 255f);
227
228 float heightRange = ImageUtils.Bilinear(
229 heightRanges[0],
230 heightRanges[2],
231 heightRanges[1],
232 heightRanges[3],
233 pctX, pctY);
234 heightRange = Utils.Clamp(heightRange, 0f, 255f);
235
236 // Generate two frequencies of perlin noise based on our global position
237 // The magic values were taken from http://opensimulator.org/wiki/Terrain_Splatting
238 Vector3 vec = new Vector3
239 (
240 ((float)regionPosition.X + x) * 0.20319f,
241 ((float)regionPosition.Y + y) * 0.20319f,
242 height * 0.25f
243 );
244
245 float lowFreq = Perlin.noise2(vec.X * 0.222222f, vec.Y * 0.222222f) * 6.5f;
246 float highFreq = Perlin.turbulence2(vec.X, vec.Y, 2f) * 2.25f;
247 float noise = (lowFreq + highFreq) * 2f;
248
249 // Combine the current height, generated noise, start height, and height range parameters, then scale all of it
250 float layer = ((height + noise - startHeight) / heightRange) * 4f;
251 if (Single.IsNaN(layer)) layer = 0f;
252 layermap[y * 256 + x] = Utils.Clamp(layer, 0f, 3f);
253 } 204 }
254 } 205 }
255 206 }
256 #endregion Layer Map 207
257 208 #region Layer Map
258 #region Texture Compositing 209
259 210 float[,] layermap = new float[256, 256];
260 output = new Bitmap(256, 256, PixelFormat.Format24bppRgb); 211
261 outputData = output.LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb); 212 // Scale difference between actual region size and the 256 texture being created
262 213 int xFactor = terrain.Width / 256;
263 unsafe 214 int yFactor = terrain.Height / 256;
215
216 // Create 'layermap' where each value is the fractional layer number to place
217 // at that point. For instance, a value of 1.345 gives the blending of
218 // layer 1 and layer 2 for that point.
219 for (int y = 0; y < 256; y++)
220 {
221 for (int x = 0; x < 256; x++)
264 { 222 {
265 // Get handles to all of the texture data arrays 223 float height = (float)terrain[x * xFactor, y * yFactor];
266 BitmapData[] datas = new BitmapData[] 224
267 { 225 float pctX = (float)x / 255f;
268 detailTexture[0].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[0].PixelFormat), 226 float pctY = (float)y / 255f;
269 detailTexture[1].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[1].PixelFormat), 227
270 detailTexture[2].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[2].PixelFormat), 228 // Use bilinear interpolation between the four corners of start height and
271 detailTexture[3].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[3].PixelFormat) 229 // height range to select the current values at this position
272 }; 230 float startHeight = ImageUtils.Bilinear(
273 231 startHeights[0],
274 int[] comps = new int[] 232 startHeights[2],
275 { 233 startHeights[1],
276 (datas[0].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, 234 startHeights[3],
277 (datas[1].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, 235 pctX, pctY);
278 (datas[2].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, 236 startHeight = Utils.Clamp(startHeight, 0f, 255f);
279 (datas[3].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3 237
280 }; 238 float heightRange = ImageUtils.Bilinear(
281 239 heightRanges[0],
282 for (int y = 0; y < 256; y++) 240 heightRanges[2],
283 { 241 heightRanges[1],
284 for (int x = 0; x < 256; x++) 242 heightRanges[3],
285 { 243 pctX, pctY);
286 float layer = layermap[y * 256 + x]; 244 heightRange = Utils.Clamp(heightRange, 0f, 255f);
287 245
288 // Select two textures 246 // Generate two frequencies of perlin noise based on our global position
289 int l0 = (int)Math.Floor(layer); 247 // The magic values were taken from http://opensimulator.org/wiki/Terrain_Splatting
290 int l1 = Math.Min(l0 + 1, 3); 248 Vector3 vec = new Vector3
291 249 (
292 byte* ptrA = (byte*)datas[l0].Scan0 + y * datas[l0].Stride + x * comps[l0]; 250 ((float)regionPosition.X + (x * xFactor)) * 0.20319f,
293 byte* ptrB = (byte*)datas[l1].Scan0 + y * datas[l1].Stride + x * comps[l1]; 251 ((float)regionPosition.Y + (y * yFactor)) * 0.20319f,
294 byte* ptrO = (byte*)outputData.Scan0 + y * outputData.Stride + x * 3; 252 height * 0.25f
295 253 );
296 float aB = *(ptrA + 0); 254
297 float aG = *(ptrA + 1); 255 float lowFreq = Perlin.noise2(vec.X * 0.222222f, vec.Y * 0.222222f) * 6.5f;
298 float aR = *(ptrA + 2); 256 float highFreq = Perlin.turbulence2(vec.X, vec.Y, 2f) * 2.25f;
299 257 float noise = (lowFreq + highFreq) * 2f;
300 float bB = *(ptrB + 0); 258
301 float bG = *(ptrB + 1); 259 // Combine the current height, generated noise, start height, and height range parameters, then scale all of it
302 float bR = *(ptrB + 2); 260 float layer = ((height + noise - startHeight) / heightRange) * 4f;
303 261 if (Single.IsNaN(layer))
304 float layerDiff = layer - l0; 262 layer = 0f;
305 263 layermap[x, y] = Utils.Clamp(layer, 0f, 3f);
306 // Interpolate between the two selected textures
307 *(ptrO + 0) = (byte)Math.Floor(aB + layerDiff * (bB - aB));
308 *(ptrO + 1) = (byte)Math.Floor(aG + layerDiff * (bG - aG));
309 *(ptrO + 2) = (byte)Math.Floor(aR + layerDiff * (bR - aR));
310 }
311 }
312
313 for (int i = 0; i < 4; i++)
314 detailTexture[i].UnlockBits(datas[i]);
315 } 264 }
316 } 265 }
317 finally 266
267 #endregion Layer Map
268
269 #region Texture Compositing
270
271 Bitmap output = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
272 BitmapData outputData = output.LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
273
274 // Unsafe work as we lock down the source textures for quicker access and access the
275 // pixel data directly
276 unsafe
318 { 277 {
319 for (int i = 0; i < 4; i++) 278 // Get handles to all of the texture data arrays
320 if (detailTexture[i] != null) 279 BitmapData[] datas = new BitmapData[]
321 detailTexture[i].Dispose(); 280 {
281 detailTexture[0].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[0].PixelFormat),
282 detailTexture[1].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[1].PixelFormat),
283 detailTexture[2].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[2].PixelFormat),
284 detailTexture[3].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[3].PixelFormat)
285 };
286
287 // Compute size of each pixel data (used to address into the pixel data array)
288 int[] comps = new int[]
289 {
290 (datas[0].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
291 (datas[1].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
292 (datas[2].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
293 (datas[3].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3
294 };
295
296 for (int y = 0; y < 256; y++)
297 {
298 for (int x = 0; x < 256; x++)
299 {
300 float layer = layermap[x, y];
301
302 // Select two textures
303 int l0 = (int)Math.Floor(layer);
304 int l1 = Math.Min(l0 + 1, 3);
305
306 byte* ptrA = (byte*)datas[l0].Scan0 + y * datas[l0].Stride + x * comps[l0];
307 byte* ptrB = (byte*)datas[l1].Scan0 + y * datas[l1].Stride + x * comps[l1];
308 byte* ptrO = (byte*)outputData.Scan0 + y * outputData.Stride + x * 3;
309
310 float aB = *(ptrA + 0);
311 float aG = *(ptrA + 1);
312 float aR = *(ptrA + 2);
313
314 float bB = *(ptrB + 0);
315 float bG = *(ptrB + 1);
316 float bR = *(ptrB + 2);
317
318 float layerDiff = layer - l0;
319
320 // Interpolate between the two selected textures
321 *(ptrO + 0) = (byte)Math.Floor(aB + layerDiff * (bB - aB));
322 *(ptrO + 1) = (byte)Math.Floor(aG + layerDiff * (bG - aG));
323 *(ptrO + 2) = (byte)Math.Floor(aR + layerDiff * (bR - aR));
324 }
325 }
326
327 for (int i = 0; i < detailTexture.Length; i++)
328 detailTexture[i].UnlockBits(datas[i]);
322 } 329 }
323 330
331 for (int i = 0; i < detailTexture.Length; i++)
332 if (detailTexture[i] != null)
333 detailTexture[i].Dispose();
334
324 output.UnlockBits(outputData); 335 output.UnlockBits(outputData);
325 336
326 // We generated the texture upside down, so flip it 337 // We generated the texture upside down, so flip it
@@ -331,6 +342,17 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
331 return output; 342 return output;
332 } 343 }
333 344
345 public static Bitmap ResizeBitmap(Bitmap b, int nWidth, int nHeight)
346 {
347 m_log.DebugFormat("{0} ResizeBitmap. From <{1},{2}> to <{3},{4}>",
348 LogHeader, b.Width, b.Height, nWidth, nHeight);
349 Bitmap result = new Bitmap(nWidth, nHeight);
350 using (Graphics g = Graphics.FromImage(result))
351 g.DrawImage(b, 0, 0, nWidth, nHeight);
352 b.Dispose();
353 return result;
354 }
355
334 public static Bitmap SplatSimple(float[] heightmap) 356 public static Bitmap SplatSimple(float[] heightmap)
335 { 357 {
336 const float BASE_HSV_H = 93f / 360f; 358 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 5e0dfa7..5f2534b 100644
--- a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs
+++ b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs
@@ -31,21 +31,25 @@ using System.Drawing;
31using System.Drawing.Imaging; 31using System.Drawing.Imaging;
32using System.IO; 32using System.IO;
33using System.Reflection; 33using System.Reflection;
34
34using CSJ2K; 35using CSJ2K;
35using Nini.Config; 36using Nini.Config;
36using log4net; 37using log4net;
37using Rednettle.Warp3D; 38using Rednettle.Warp3D;
38using Mono.Addins; 39using Mono.Addins;
39using OpenMetaverse; 40
40using OpenMetaverse.Imaging;
41using OpenMetaverse.Rendering;
42using OpenMetaverse.StructuredData;
43using OpenSim.Framework; 41using OpenSim.Framework;
44using OpenSim.Region.Framework.Interfaces; 42using OpenSim.Region.Framework.Interfaces;
45using OpenSim.Region.Framework.Scenes; 43using OpenSim.Region.Framework.Scenes;
46using OpenSim.Region.Physics.Manager; 44using OpenSim.Region.PhysicsModules.SharedBase;
47using OpenSim.Services.Interfaces; 45using OpenSim.Services.Interfaces;
48 46
47using OpenMetaverse;
48using OpenMetaverse.Assets;
49using OpenMetaverse.Imaging;
50using OpenMetaverse.Rendering;
51using OpenMetaverse.StructuredData;
52
49using WarpRenderer = global::Warp3D.Warp3D; 53using WarpRenderer = global::Warp3D.Warp3D;
50 54
51namespace OpenSim.Region.CoreModules.World.Warp3DMap 55namespace OpenSim.Region.CoreModules.World.Warp3DMap
@@ -58,11 +62,22 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
58 62
59 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 63 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
60 64
65#pragma warning disable 414
66 private static string LogHeader = "[WARP 3D IMAGE MODULE]";
67#pragma warning restore 414
68
61 private Scene m_scene; 69 private Scene m_scene;
62 private IRendering m_primMesher; 70 private IRendering m_primMesher;
63 private IConfigSource m_config;
64 private Dictionary<UUID, Color4> m_colors = new Dictionary<UUID, Color4>(); 71 private Dictionary<UUID, Color4> m_colors = new Dictionary<UUID, Color4>();
65 private bool m_useAntiAliasing = false; // TODO: Make this a config option 72
73 private IConfigSource m_config;
74 private bool m_drawPrimVolume = true; // true if should render the prims on the tile
75 private bool m_textureTerrain = true; // true if to create terrain splatting texture
76 private bool m_texturePrims = true; // true if should texture the rendered prims
77 private float m_texturePrimSize = 48f; // size of prim before we consider texturing it
78 private bool m_renderMeshes = false; // true if to render meshes rather than just bounding boxes
79 private bool m_useAntiAliasing = false; // true if to anti-alias the rendered image
80
66 private bool m_Enabled = false; 81 private bool m_Enabled = false;
67 82
68 #region Region Module interface 83 #region Region Module interface
@@ -71,11 +86,27 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
71 { 86 {
72 m_config = source; 87 m_config = source;
73 88
74 IConfig startupConfig = m_config.Configs["Startup"]; 89 string[] configSections = new string[] { "Map", "Startup" };
75 if (startupConfig.GetString("MapImageModule", "MapImageModule") != "Warp3DImageModule") 90
91 if (Util.GetConfigVarFromSections<string>(
92 m_config, "MapImageModule", configSections, "MapImageModule") != "Warp3DImageModule")
76 return; 93 return;
77 94
78 m_Enabled = true; 95 m_Enabled = true;
96
97 m_drawPrimVolume
98 = Util.GetConfigVarFromSections<bool>(m_config, "DrawPrimOnMapTile", configSections, m_drawPrimVolume);
99 m_textureTerrain
100 = Util.GetConfigVarFromSections<bool>(m_config, "TextureOnMapTile", configSections, m_textureTerrain);
101 m_texturePrims
102 = Util.GetConfigVarFromSections<bool>(m_config, "TexturePrims", configSections, m_texturePrims);
103 m_texturePrimSize
104 = Util.GetConfigVarFromSections<float>(m_config, "TexturePrimSize", configSections, m_texturePrimSize);
105 m_renderMeshes
106 = Util.GetConfigVarFromSections<bool>(m_config, "RenderMeshes", configSections, m_renderMeshes);
107 m_useAntiAliasing
108 = Util.GetConfigVarFromSections<bool>(m_config, "UseAntiAliasing", configSections, m_useAntiAliasing);
109
79 } 110 }
80 111
81 public void AddRegion(Scene scene) 112 public void AddRegion(Scene scene)
@@ -127,33 +158,28 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
127 158
128 public Bitmap CreateMapTile() 159 public Bitmap CreateMapTile()
129 { 160 {
130 Vector3 camPos = new Vector3(127.5f, 127.5f, 221.7025033688163f); 161 // Vector3 camPos = new Vector3(127.5f, 127.5f, 221.7025033688163f);
131 Viewport viewport = new Viewport(camPos, -Vector3.UnitZ, 1024f, 0.1f, (int)Constants.RegionSize, (int)Constants.RegionSize, (float)Constants.RegionSize, (float)Constants.RegionSize); 162 // Camera above the middle of the region
163 Vector3 camPos = new Vector3(
164 m_scene.RegionInfo.RegionSizeX/2 - 0.5f,
165 m_scene.RegionInfo.RegionSizeY/2 - 0.5f,
166 221.7025033688163f);
167 // Viewport viewing down onto the region
168 Viewport viewport = new Viewport(camPos, -Vector3.UnitZ, 1024f, 0.1f,
169 (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY,
170 (float)m_scene.RegionInfo.RegionSizeX, (float)m_scene.RegionInfo.RegionSizeY );
171 // Fill the viewport and return the image
132 return CreateMapTile(viewport, false); 172 return CreateMapTile(viewport, false);
133 } 173 }
134 174
135 public Bitmap CreateViewImage(Vector3 camPos, Vector3 camDir, float fov, int width, int height, bool useTextures) 175 public Bitmap CreateViewImage(Vector3 camPos, Vector3 camDir, float fov, int width, int height, bool useTextures)
136 { 176 {
137 Viewport viewport = new Viewport(camPos, camDir, fov, (float)Constants.RegionSize, 0.1f, width, height); 177 Viewport viewport = new Viewport(camPos, camDir, fov, Constants.RegionSize, 0.1f, width, height);
138 return CreateMapTile(viewport, useTextures); 178 return CreateMapTile(viewport, useTextures);
139 } 179 }
140 180
141 public Bitmap CreateMapTile(Viewport viewport, bool useTextures) 181 public Bitmap CreateMapTile(Viewport viewport, bool useTextures)
142 { 182 {
143 bool drawPrimVolume = true;
144 bool textureTerrain = true;
145
146 try
147 {
148 IConfig startupConfig = m_config.Configs["Startup"];
149 drawPrimVolume = startupConfig.GetBoolean("DrawPrimOnMapTile", drawPrimVolume);
150 textureTerrain = startupConfig.GetBoolean("TextureOnMapTile", textureTerrain);
151 }
152 catch
153 {
154 m_log.Warn("[WARP 3D IMAGE MODULE]: Failed to load StartupConfig");
155 }
156
157 m_colors.Clear(); 183 m_colors.Clear();
158 184
159 int width = viewport.Width; 185 int width = viewport.Width;
@@ -166,6 +192,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
166 } 192 }
167 193
168 WarpRenderer renderer = new WarpRenderer(); 194 WarpRenderer renderer = new WarpRenderer();
195
169 renderer.CreateScene(width, height); 196 renderer.CreateScene(width, height);
170 renderer.Scene.autoCalcNormals = false; 197 renderer.Scene.autoCalcNormals = false;
171 198
@@ -197,8 +224,8 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
197 renderer.Scene.addLight("Light2", new warp_Light(new warp_Vector(-1f, -1f, 1f), 0xffffff, 0, 100, 40)); 224 renderer.Scene.addLight("Light2", new warp_Light(new warp_Vector(-1f, -1f, 1f), 0xffffff, 0, 100, 40));
198 225
199 CreateWater(renderer); 226 CreateWater(renderer);
200 CreateTerrain(renderer, textureTerrain); 227 CreateTerrain(renderer, m_textureTerrain);
201 if (drawPrimVolume) 228 if (m_drawPrimVolume)
202 CreateAllPrims(renderer, useTextures); 229 CreateAllPrims(renderer, useTextures);
203 230
204 renderer.Render(); 231 renderer.Render();
@@ -214,6 +241,18 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
214 // afterwards. It's generally regarded as a bad idea to manually GC. If Warp3D is using lots of memory 241 // afterwards. It's generally regarded as a bad idea to manually GC. If Warp3D is using lots of memory
215 // then this may be some issue with the Warp3D code itself, though it's also quite possible that generating 242 // then this may be some issue with the Warp3D code itself, though it's also quite possible that generating
216 // this map tile simply takes a lot of memory. 243 // this map tile simply takes a lot of memory.
244 foreach (var o in renderer.Scene.objectData.Values)
245 {
246 warp_Object obj = (warp_Object)o;
247 obj.vertexData = null;
248 obj.triangleData = null;
249 }
250
251 renderer.Scene.removeAllObjects();
252 renderer = null;
253 viewport = null;
254
255 m_colors.Clear();
217 GC.Collect(); 256 GC.Collect();
218 m_log.Debug("[WARP 3D IMAGE MODULE]: GC.Collect()"); 257 m_log.Debug("[WARP 3D IMAGE MODULE]: GC.Collect()");
219 258
@@ -240,61 +279,74 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
240 279
241 #region Rendering Methods 280 #region Rendering Methods
242 281
282 // Add a water plane to the renderer.
243 private void CreateWater(WarpRenderer renderer) 283 private void CreateWater(WarpRenderer renderer)
244 { 284 {
245 float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight; 285 float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight;
246 286
247 renderer.AddPlane("Water", 256f * 0.5f); 287 renderer.AddPlane("Water", m_scene.RegionInfo.RegionSizeX * 0.5f);
248 renderer.Scene.sceneobject("Water").setPos(127.5f, waterHeight, 127.5f); 288 renderer.Scene.sceneobject("Water").setPos(m_scene.RegionInfo.RegionSizeX/2 - 0.5f,
289 waterHeight,
290 m_scene.RegionInfo.RegionSizeY/2 - 0.5f );
249 291
250 renderer.AddMaterial("WaterColor", ConvertColor(WATER_COLOR)); 292 warp_Material waterColorMaterial = new warp_Material(ConvertColor(WATER_COLOR));
251 renderer.Scene.material("WaterColor").setReflectivity(0); // match water color with standard map module thanks lkalif 293 waterColorMaterial.setReflectivity(0); // match water color with standard map module thanks lkalif
252 renderer.Scene.material("WaterColor").setTransparency((byte)((1f - WATER_COLOR.A) * 255f)); 294 waterColorMaterial.setTransparency((byte)((1f - WATER_COLOR.A) * 255f));
295 renderer.Scene.addMaterial("WaterColor", waterColorMaterial);
253 renderer.SetObjectMaterial("Water", "WaterColor"); 296 renderer.SetObjectMaterial("Water", "WaterColor");
254 } 297 }
255 298
299 // Add a terrain to the renderer.
300 // Note that we create a 'low resolution' 256x256 vertex terrain rather than trying for
301 // full resolution. This saves a lot of memory especially for very large regions.
256 private void CreateTerrain(WarpRenderer renderer, bool textureTerrain) 302 private void CreateTerrain(WarpRenderer renderer, bool textureTerrain)
257 { 303 {
258 ITerrainChannel terrain = m_scene.Heightmap; 304 ITerrainChannel terrain = m_scene.Heightmap;
259 float[] heightmap = terrain.GetFloatsSerialised(); 305
306 // 'diff' is the difference in scale between the real region size and the size of terrain we're buiding
307 float diff = (float)m_scene.RegionInfo.RegionSizeX / 256f;
260 308
261 warp_Object obj = new warp_Object(256 * 256, 255 * 255 * 2); 309 warp_Object obj = new warp_Object(256 * 256, 255 * 255 * 2);
262 310
263 for (int y = 0; y < 256; y++) 311 // Create all the vertices for the terrain
312 for (float y = 0; y < m_scene.RegionInfo.RegionSizeY; y += diff)
264 { 313 {
265 for (int x = 0; x < 256; x++) 314 for (float x = 0; x < m_scene.RegionInfo.RegionSizeX; x += diff)
266 { 315 {
267 int v = y * 256 + x; 316 warp_Vector pos = ConvertVector(x, y, (float)terrain[(int)x, (int)y]);
268 float height = heightmap[v]; 317 obj.addVertex(new warp_Vertex(pos,
269 318 x / (float)m_scene.RegionInfo.RegionSizeX,
270 warp_Vector pos = ConvertVector(new Vector3(x, y, height)); 319 (((float)m_scene.RegionInfo.RegionSizeY) - y) / m_scene.RegionInfo.RegionSizeY) );
271 obj.addVertex(new warp_Vertex(pos, (float)x / 255f, (float)(255 - y) / 255f));
272 } 320 }
273 } 321 }
274 322
275 for (int y = 0; y < 256; y++) 323 // Now that we have all the vertices, make another pass and create
324 // the normals for each of the surface triangles and
325 // create the list of triangle indices.
326 for (float y = 0; y < m_scene.RegionInfo.RegionSizeY; y += diff)
276 { 327 {
277 for (int x = 0; x < 256; x++) 328 for (float x = 0; x < m_scene.RegionInfo.RegionSizeX; x += diff)
278 { 329 {
279 if (x < 255 && y < 255) 330 float newX = x / diff;
331 float newY = y / diff;
332 if (newX < 255 && newY < 255)
280 { 333 {
281 int v = y * 256 + x; 334 int v = (int)newY * 256 + (int)newX;
282 335
283 // Normal 336 // Normal for a triangle made up of three adjacent vertices
284 Vector3 v1 = new Vector3(x, y, heightmap[y * 256 + x]); 337 Vector3 v1 = new Vector3(newX, newY, (float)terrain[(int)x, (int)y]);
285 Vector3 v2 = new Vector3(x + 1, y, heightmap[y * 256 + x + 1]); 338 Vector3 v2 = new Vector3(newX + 1, newY, (float)terrain[(int)(x + 1), (int)y]);
286 Vector3 v3 = new Vector3(x, y + 1, heightmap[(y + 1) * 256 + x]); 339 Vector3 v3 = new Vector3(newX, newY + 1, (float)terrain[(int)x, ((int)(y + 1))]);
287 warp_Vector norm = ConvertVector(SurfaceNormal(v1, v2, v3)); 340 warp_Vector norm = ConvertVector(SurfaceNormal(v1, v2, v3));
288 norm = norm.reverse(); 341 norm = norm.reverse();
289 obj.vertex(v).n = norm; 342 obj.vertex(v).n = norm;
290 343
291 // Triangle 1 344 // Make two triangles for each of the squares in the grid of vertices
292 obj.addTriangle( 345 obj.addTriangle(
293 v, 346 v,
294 v + 1, 347 v + 1,
295 v + 256); 348 v + 256);
296 349
297 // Triangle 2
298 obj.addTriangle( 350 obj.addTriangle(
299 v + 256 + 1, 351 v + 256 + 1,
300 v + 256, 352 v + 256,
@@ -309,7 +361,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
309 float[] startHeights = new float[4]; 361 float[] startHeights = new float[4];
310 float[] heightRanges = new float[4]; 362 float[] heightRanges = new float[4];
311 363
312 RegionSettings regionInfo = m_scene.RegionInfo.RegionSettings; 364 OpenSim.Framework.RegionSettings regionInfo = m_scene.RegionInfo.RegionSettings;
313 365
314 textureIDs[0] = regionInfo.TerrainTexture1; 366 textureIDs[0] = regionInfo.TerrainTexture1;
315 textureIDs[1] = regionInfo.TerrainTexture2; 367 textureIDs[1] = regionInfo.TerrainTexture2;
@@ -327,14 +379,12 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
327 heightRanges[3] = (float)regionInfo.Elevation2NE; 379 heightRanges[3] = (float)regionInfo.Elevation2NE;
328 380
329 uint globalX, globalY; 381 uint globalX, globalY;
330 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out globalX, out globalY); 382 Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle, out globalX, out globalY);
331 383
332 warp_Texture texture; 384 warp_Texture texture;
333
334 using ( 385 using (
335 Bitmap image 386 Bitmap image
336 = TerrainSplat.Splat( 387 = TerrainSplat.Splat(terrain, textureIDs, startHeights, heightRanges,
337 heightmap, textureIDs, startHeights, heightRanges,
338 new Vector3d(globalX, globalY, 0.0), m_scene.AssetService, textureTerrain)) 388 new Vector3d(globalX, globalY, 0.0), m_scene.AssetService, textureTerrain))
339 { 389 {
340 texture = new warp_Texture(image); 390 texture = new warp_Texture(image);
@@ -355,7 +405,6 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
355 m_scene.ForEachSOG( 405 m_scene.ForEachSOG(
356 delegate(SceneObjectGroup group) 406 delegate(SceneObjectGroup group)
357 { 407 {
358 CreatePrim(renderer, group.RootPart, useTextures);
359 foreach (SceneObjectPart child in group.Parts) 408 foreach (SceneObjectPart child in group.Parts)
360 CreatePrim(renderer, child, useTextures); 409 CreatePrim(renderer, child, useTextures);
361 } 410 }
@@ -372,8 +421,48 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
372 if (prim.Scale.LengthSquared() < MIN_SIZE * MIN_SIZE) 421 if (prim.Scale.LengthSquared() < MIN_SIZE * MIN_SIZE)
373 return; 422 return;
374 423
424 FacetedMesh renderMesh = null;
375 Primitive omvPrim = prim.Shape.ToOmvPrimitive(prim.OffsetPosition, prim.RotationOffset); 425 Primitive omvPrim = prim.Shape.ToOmvPrimitive(prim.OffsetPosition, prim.RotationOffset);
376 FacetedMesh renderMesh = m_primMesher.GenerateFacetedMesh(omvPrim, DetailLevel.Medium); 426
427 if (m_renderMeshes)
428 {
429 if (omvPrim.Sculpt != null && omvPrim.Sculpt.SculptTexture != UUID.Zero)
430 {
431 // Try fetchinng the asset
432 byte[] sculptAsset = m_scene.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString());
433 if (sculptAsset != null)
434 {
435 // Is it a mesh?
436 if (omvPrim.Sculpt.Type == SculptType.Mesh)
437 {
438 AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset);
439 FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out renderMesh);
440 meshAsset = null;
441 }
442 else // It's sculptie
443 {
444 IJ2KDecoder imgDecoder = m_scene.RequestModuleInterface<IJ2KDecoder>();
445 if (imgDecoder != null)
446 {
447 Image sculpt = imgDecoder.DecodeToImage(sculptAsset);
448 if (sculpt != null)
449 {
450 renderMesh = m_primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt,
451 DetailLevel.Medium);
452 sculpt.Dispose();
453 }
454 }
455 }
456 }
457 }
458 }
459
460 // If not a mesh or sculptie, try the regular mesher
461 if (renderMesh == null)
462 {
463 renderMesh = m_primMesher.GenerateFacetedMesh(omvPrim, DetailLevel.Medium);
464 }
465
377 if (renderMesh == null) 466 if (renderMesh == null)
378 return; 467 return;
379 468
@@ -432,7 +521,11 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
432 521
433 Primitive.TextureEntryFace teFace = prim.Shape.Textures.GetFace((uint)i); 522 Primitive.TextureEntryFace teFace = prim.Shape.Textures.GetFace((uint)i);
434 Color4 faceColor = GetFaceColor(teFace); 523 Color4 faceColor = GetFaceColor(teFace);
435 string materialName = GetOrCreateMaterial(renderer, faceColor); 524 string materialName = String.Empty;
525 if (m_texturePrims && prim.Scale.LengthSquared() > m_texturePrimSize*m_texturePrimSize)
526 materialName = GetOrCreateMaterial(renderer, faceColor, teFace.TextureID);
527 else
528 materialName = GetOrCreateMaterial(renderer, faceColor);
436 529
437 faceObj.transform(m); 530 faceObj.transform(m);
438 faceObj.setPos(primPos); 531 faceObj.setPos(primPos);
@@ -521,10 +614,59 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
521 return name; 614 return name;
522 } 615 }
523 616
617 public string GetOrCreateMaterial(WarpRenderer renderer, Color4 faceColor, UUID textureID)
618 {
619 string materialName = "Color-" + faceColor.ToString() + "-Texture-" + textureID.ToString();
620
621 if (renderer.Scene.material(materialName) == null)
622 {
623 renderer.AddMaterial(materialName, ConvertColor(faceColor));
624 if (faceColor.A < 1f)
625 {
626 renderer.Scene.material(materialName).setTransparency((byte) ((1f - faceColor.A)*255f));
627 }
628 warp_Texture texture = GetTexture(textureID);
629 if (texture != null)
630 renderer.Scene.material(materialName).setTexture(texture);
631 }
632
633 return materialName;
634 }
635
636 private warp_Texture GetTexture(UUID id)
637 {
638 warp_Texture ret = null;
639
640 byte[] asset = m_scene.AssetService.GetData(id.ToString());
641
642 if (asset != null)
643 {
644 IJ2KDecoder imgDecoder = m_scene.RequestModuleInterface<IJ2KDecoder>();
645
646 try
647 {
648 using (Bitmap img = (Bitmap)imgDecoder.DecodeToImage(asset))
649 ret = new warp_Texture(img);
650 }
651 catch (Exception e)
652 {
653 m_log.Warn(string.Format("[WARP 3D IMAGE MODULE]: Failed to decode asset {0}, exception ", id), e);
654 }
655 }
656
657 return ret;
658 }
659
524 #endregion Rendering Methods 660 #endregion Rendering Methods
525 661
526 #region Static Helpers 662 #region Static Helpers
527 663
664 // Note: axis change.
665 private static warp_Vector ConvertVector(float x, float y, float z)
666 {
667 return new warp_Vector(x, z, y);
668 }
669
528 private static warp_Vector ConvertVector(Vector3 vector) 670 private static warp_Vector ConvertVector(Vector3 vector)
529 { 671 {
530 return new warp_Vector(vector.X, vector.Z, vector.Y); 672 return new warp_Vector(vector.X, vector.Z, vector.Y);
diff --git a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs
index 9de588c..35014f5 100644
--- a/OpenSim/Region/CoreModules/World/Wind/WindModule.cs
+++ b/OpenSim/Region/CoreModules/World/Wind/WindModule.cs
@@ -216,13 +216,13 @@ namespace OpenSim.Region.CoreModules
216 // FIXME: If console region is root then this will be printed by every module. Currently, there is no 216 // FIXME: If console region is root then this will be printed by every module. Currently, there is no
217 // way to prevent this, short of making the entire module shared (which is complete overkill). 217 // way to prevent this, short of making the entire module shared (which is complete overkill).
218 // One possibility is to return a bool to signal whether the module has completely handled the command 218 // One possibility is to return a bool to signal whether the module has completely handled the command
219 m_log.InfoFormat("[WIND]: Please change to a specific region in order to set Sun parameters."); 219 MainConsole.Instance.Output("Please change to a specific region in order to set Sun parameters.");
220 return; 220 return;
221 } 221 }
222 222
223 if (m_scene.ConsoleScene() != m_scene) 223 if (m_scene.ConsoleScene() != m_scene)
224 { 224 {
225 m_log.InfoFormat("[WIND]: Console Scene is not my scene."); 225 MainConsole.Instance.Output("Console Scene is not my scene.");
226 return; 226 return;
227 } 227 }
228 } 228 }
@@ -233,7 +233,9 @@ namespace OpenSim.Region.CoreModules
233 private void HandleConsoleCommand(string module, string[] cmdparams) 233 private void HandleConsoleCommand(string module, string[] cmdparams)
234 { 234 {
235 ValidateConsole(); 235 ValidateConsole();
236 m_log.Info("[WIND] The wind command can be used to change the currently active wind model plugin and update the parameters for wind plugins."); 236
237 MainConsole.Instance.Output(
238 "The wind command can be used to change the currently active wind model plugin and update the parameters for wind plugins.");
237 } 239 }
238 240
239 /// <summary> 241 /// <summary>
@@ -246,7 +248,9 @@ namespace OpenSim.Region.CoreModules
246 if ((cmdparams.Length != 4) 248 if ((cmdparams.Length != 4)
247 || !cmdparams[1].Equals("base")) 249 || !cmdparams[1].Equals("base"))
248 { 250 {
249 m_log.Info("[WIND] Invalid parameters to change parameters for Wind module base, usage: wind base <parameter> <value>"); 251 MainConsole.Instance.Output(
252 "Invalid parameters to change parameters for Wind module base, usage: wind base <parameter> <value>");
253
250 return; 254 return;
251 } 255 }
252 256
@@ -261,7 +265,9 @@ namespace OpenSim.Region.CoreModules
261 } 265 }
262 else 266 else
263 { 267 {
264 m_log.InfoFormat("[WIND] Invalid value {0} specified for {1}", cmdparams[3], cmdparams[2]); 268 MainConsole.Instance.OutputFormat(
269 "Invalid value {0} specified for {1}", cmdparams[3], cmdparams[2]);
270
265 return; 271 return;
266 } 272 }
267 273
@@ -271,22 +277,23 @@ namespace OpenSim.Region.CoreModules
271 277
272 if (desiredPlugin.Equals(m_activeWindPlugin.Name)) 278 if (desiredPlugin.Equals(m_activeWindPlugin.Name))
273 { 279 {
274 m_log.InfoFormat("[WIND] Wind model plugin {0} is already active", cmdparams[3]); 280 MainConsole.Instance.OutputFormat("Wind model plugin {0} is already active", cmdparams[3]);
281
275 return; 282 return;
276 } 283 }
277 284
278 if (m_availableWindPlugins.ContainsKey(desiredPlugin)) 285 if (m_availableWindPlugins.ContainsKey(desiredPlugin))
279 { 286 {
280 m_activeWindPlugin = m_availableWindPlugins[cmdparams[3]]; 287 m_activeWindPlugin = m_availableWindPlugins[cmdparams[3]];
281 m_log.InfoFormat("[WIND] {0} wind model plugin now active", m_activeWindPlugin.Name); 288
289 MainConsole.Instance.OutputFormat("{0} wind model plugin now active", m_activeWindPlugin.Name);
282 } 290 }
283 else 291 else
284 { 292 {
285 m_log.InfoFormat("[WIND] Could not find wind model plugin {0}", desiredPlugin); 293 MainConsole.Instance.OutputFormat("Could not find wind model plugin {0}", desiredPlugin);
286 } 294 }
287 break; 295 break;
288 } 296 }
289
290 } 297 }
291 298
292 /// <summary> 299 /// <summary>
@@ -300,7 +307,7 @@ namespace OpenSim.Region.CoreModules
300 if ((cmdparams.Length != 4) 307 if ((cmdparams.Length != 4)
301 && (cmdparams.Length != 3)) 308 && (cmdparams.Length != 3))
302 { 309 {
303 m_log.Info("[WIND] Usage: wind <plugin> <param> [value]"); 310 MainConsole.Instance.Output("Usage: wind <plugin> <param> [value]");
304 return; 311 return;
305 } 312 }
306 313
@@ -311,16 +318,17 @@ namespace OpenSim.Region.CoreModules
311 { 318 {
312 if (!float.TryParse(cmdparams[3], out value)) 319 if (!float.TryParse(cmdparams[3], out value))
313 { 320 {
314 m_log.InfoFormat("[WIND] Invalid value {0}", cmdparams[3]); 321 MainConsole.Instance.OutputFormat("Invalid value {0}", cmdparams[3]);
315 } 322 }
316 323
317 try 324 try
318 { 325 {
319 WindParamSet(plugin, param, value); 326 WindParamSet(plugin, param, value);
327 MainConsole.Instance.OutputFormat("{0} set to {1}", param, value);
320 } 328 }
321 catch (Exception e) 329 catch (Exception e)
322 { 330 {
323 m_log.InfoFormat("[WIND] {0}", e.Message); 331 MainConsole.Instance.OutputFormat("{0}", e.Message);
324 } 332 }
325 } 333 }
326 else 334 else
@@ -328,11 +336,11 @@ namespace OpenSim.Region.CoreModules
328 try 336 try
329 { 337 {
330 value = WindParamGet(plugin, param); 338 value = WindParamGet(plugin, param);
331 m_log.InfoFormat("[WIND] {0} : {1}", param, value); 339 MainConsole.Instance.OutputFormat("{0} : {1}", param, value);
332 } 340 }
333 catch (Exception e) 341 catch (Exception e)
334 { 342 {
335 m_log.InfoFormat("[WIND] {0}", e.Message); 343 MainConsole.Instance.OutputFormat("{0}", e.Message);
336 } 344 }
337 } 345 }
338 346
@@ -366,13 +374,11 @@ namespace OpenSim.Region.CoreModules
366 { 374 {
367 IWindModelPlugin windPlugin = m_availableWindPlugins[plugin]; 375 IWindModelPlugin windPlugin = m_availableWindPlugins[plugin];
368 windPlugin.WindParamSet(param, value); 376 windPlugin.WindParamSet(param, value);
369 m_log.InfoFormat("[WIND] {0} set to {1}", param, value);
370 } 377 }
371 else 378 else
372 { 379 {
373 throw new Exception(String.Format("Could not find plugin {0}", plugin)); 380 throw new Exception(String.Format("Could not find plugin {0}", plugin));
374 } 381 }
375
376 } 382 }
377 383
378 public float WindParamGet(string plugin, string param) 384 public float WindParamGet(string plugin, string param)
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
index 708a9a2..d862f18 100644
--- a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
+++ b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
@@ -49,6 +49,18 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
49 List<Scene> m_scenes = new List<Scene>(); 49 List<Scene> m_scenes = new List<Scene>();
50 List<UUID> m_Clients; 50 List<UUID> m_Clients;
51 51
52 IWorldMapModule m_WorldMap;
53 IWorldMapModule WorldMap
54 {
55 get
56 {
57 if (m_WorldMap == null)
58 m_WorldMap = m_scene.RequestModuleInterface<IWorldMapModule>();
59 return m_WorldMap;
60 }
61
62 }
63
52 #region ISharedRegionModule Members 64 #region ISharedRegionModule Members
53 public void Initialise(IConfigSource source) 65 public void Initialise(IConfigSource source)
54 { 66 {
@@ -64,6 +76,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
64 m_scenes.Add(scene); 76 m_scenes.Add(scene);
65 scene.EventManager.OnNewClient += OnNewClient; 77 scene.EventManager.OnNewClient += OnNewClient;
66 m_Clients = new List<UUID>(); 78 m_Clients = new List<UUID>();
79
67 } 80 }
68 81
69 public void RemoveRegion(Scene scene) 82 public void RemoveRegion(Scene scene)
@@ -129,7 +142,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
129 private void OnMapNameRequest(IClientAPI remoteClient, string mapName, uint flags) 142 private void OnMapNameRequest(IClientAPI remoteClient, string mapName, uint flags)
130 { 143 {
131 List<MapBlockData> blocks = new List<MapBlockData>(); 144 List<MapBlockData> blocks = new List<MapBlockData>();
132 MapBlockData data;
133 if (mapName.Length < 3 || (mapName.EndsWith("#") && mapName.Length < 4)) 145 if (mapName.Length < 3 || (mapName.EndsWith("#") && mapName.Length < 4))
134 { 146 {
135 // final block, closing the search result 147 // final block, closing the search result
@@ -143,50 +155,51 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
143 } 155 }
144 156
145 157
146 //m_log.DebugFormat("MAP NAME=({0})", mapName); 158 List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20);
147 159
148 // Hack to get around the fact that ll V3 now drops the port from the
149 // map name. See https://jira.secondlife.com/browse/VWR-28570
150 //
151 // Caller, use this magic form instead:
152 // secondlife://http|!!mygrid.com|8002|Region+Name/128/128
153 // or url encode if possible.
154 // the hacks we do with this viewer...
155 //
156 string mapNameOrig = mapName; 160 string mapNameOrig = mapName;
157 if (mapName.Contains("|")) 161 if (regionInfos.Count == 0)
158 mapName = mapName.Replace('|', ':'); 162 {
159 if (mapName.Contains("+")) 163 // Hack to get around the fact that ll V3 now drops the port from the
160 mapName = mapName.Replace('+', ' '); 164 // map name. See https://jira.secondlife.com/browse/VWR-28570
161 if (mapName.Contains("!")) 165 //
162 mapName = mapName.Replace('!', '/'); 166 // Caller, use this magic form instead:
167 // secondlife://http|!!mygrid.com|8002|Region+Name/128/128
168 // or url encode if possible.
169 // the hacks we do with this viewer...
170 //
171 if (mapName.Contains("|"))
172 mapName = mapName.Replace('|', ':');
173 if (mapName.Contains("+"))
174 mapName = mapName.Replace('+', ' ');
175 if (mapName.Contains("!"))
176 mapName = mapName.Replace('!', '/');
177
178 if (mapName != mapNameOrig)
179 regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20);
180 }
163 181
164 // try to fetch from GridServer
165 List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20);
166
167 m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions. Flags={2}", mapName, regionInfos.Count, flags); 182 m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions. Flags={2}", mapName, regionInfos.Count, flags);
183
168 if (regionInfos.Count > 0) 184 if (regionInfos.Count > 0)
169 { 185 {
170 foreach (GridRegion info in regionInfos) 186 foreach (GridRegion info in regionInfos)
171 { 187 {
172 data = new MapBlockData(); 188 if ((flags & 2) == 2) // V2 sends this
173 data.Agents = 0; 189 {
174 data.Access = info.Access; 190 List<MapBlockData> datas = WorldMap.Map2BlockFromGridRegion(info, flags);
175 if (flags == 2) // V2 sends this 191 // ugh! V2-3 is very sensitive about the result being
176 data.MapImageId = UUID.Zero; 192 // exactly the same as the requested name
177 else 193 if (regionInfos.Count == 1 && (mapName != mapNameOrig))
178 data.MapImageId = info.TerrainImage; 194 datas.ForEach(d => d.Name = mapNameOrig);
179 // ugh! V2-3 is very sensitive about the result being 195
180 // exactly the same as the requested name 196 blocks.AddRange(datas);
181 if (regionInfos.Count == 1 && mapNameOrig.Contains("|") || mapNameOrig.Contains("+")) 197 }
182 data.Name = mapNameOrig;
183 else 198 else
184 data.Name = info.RegionName; 199 {
185 data.RegionFlags = 0; // TODO not used? 200 MapBlockData data = WorldMap.MapBlockFromGridRegion(info, flags);
186 data.WaterHeight = 0; // not used 201 blocks.Add(data);
187 data.X = (ushort)(info.RegionLocX / Constants.RegionSize); 202 }
188 data.Y = (ushort)(info.RegionLocY / Constants.RegionSize);
189 blocks.Add(data);
190 } 203 }
191 } 204 }
192 205
@@ -204,8 +217,9 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
204 { 217 {
205 if (regionInfos.Count == 0) 218 if (regionInfos.Count == 0)
206 remoteClient.SendAlertMessage("No regions found with that name."); 219 remoteClient.SendAlertMessage("No regions found with that name.");
207 else if (regionInfos.Count == 1) 220 // this seems unnecessary because found regions will show up in the search results
208 remoteClient.SendAlertMessage("Region found!"); 221 //else if (regionInfos.Count == 1)
222 // remoteClient.SendAlertMessage("Region found!");
209 } 223 }
210 } 224 }
211 225
@@ -214,7 +228,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
214 // final block, closing the search result 228 // final block, closing the search result
215 MapBlockData data = new MapBlockData(); 229 MapBlockData data = new MapBlockData();
216 data.Agents = 0; 230 data.Agents = 0;
217 data.Access = 255; 231 data.Access = (byte)SimAccess.NonExistent;
218 data.MapImageId = UUID.Zero; 232 data.MapImageId = UUID.Zero;
219 data.Name = ""; 233 data.Name = "";
220 data.RegionFlags = 0; 234 data.RegionFlags = 0;
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
index e2f525c..db1187e 100644
--- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
+++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
@@ -59,13 +59,18 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
59 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WorldMapModule")] 59 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WorldMapModule")]
60 public class WorldMapModule : INonSharedRegionModule, IWorldMapModule 60 public class WorldMapModule : INonSharedRegionModule, IWorldMapModule
61 { 61 {
62 private static readonly ILog m_log = 62 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
63 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 63#pragma warning disable 414
64 private static string LogHeader = "[WORLD MAP]";
65#pragma warning restore 414
64 66
65 private static readonly string DEFAULT_WORLD_MAP_EXPORT_PATH = "exportmap.jpg"; 67 private static readonly string DEFAULT_WORLD_MAP_EXPORT_PATH = "exportmap.jpg";
66 private static readonly UUID STOP_UUID = UUID.Random(); 68 private static readonly UUID STOP_UUID = UUID.Random();
67 private static readonly string m_mapLayerPath = "0001/"; 69 private static readonly string m_mapLayerPath = "0001/";
68 70
71 private IMapImageGenerator m_mapImageGenerator;
72 private IMapImageUploadModule m_mapImageServiceModule;
73
69 private OpenSim.Framework.BlockingQueue<MapRequestState> requests = new OpenSim.Framework.BlockingQueue<MapRequestState>(); 74 private OpenSim.Framework.BlockingQueue<MapRequestState> requests = new OpenSim.Framework.BlockingQueue<MapRequestState>();
70 75
71 protected Scene m_scene; 76 protected Scene m_scene;
@@ -81,19 +86,24 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
81 private List<UUID> m_rootAgents = new List<UUID>(); 86 private List<UUID> m_rootAgents = new List<UUID>();
82 private volatile bool threadrunning = false; 87 private volatile bool threadrunning = false;
83 88
89 private IServiceThrottleModule m_ServiceThrottle;
90
84 //private int CacheRegionsDistance = 256; 91 //private int CacheRegionsDistance = 256;
85 92
86 #region INonSharedRegionModule Members 93 #region INonSharedRegionModule Members
87 public virtual void Initialise (IConfigSource config) 94 public virtual void Initialise (IConfigSource config)
88 { 95 {
89 IConfig startupConfig = config.Configs["Startup"]; 96 string[] configSections = new string[] { "Map", "Startup" };
90 if (startupConfig.GetString("WorldMapModule", "WorldMap") == "WorldMap") 97
98 if (Util.GetConfigVarFromSections<string>(
99 config, "WorldMapModule", configSections, "WorldMap") == "WorldMap")
91 m_Enabled = true; 100 m_Enabled = true;
92 101
93 blacklistTimeout = startupConfig.GetInt("BlacklistTimeout", 10*60) * 1000; 102 blacklistTimeout
103 = Util.GetConfigVarFromSections<int>(config, "BlacklistTimeout", configSections, 10 * 60) * 1000;
94 } 104 }
95 105
96 public virtual void AddRegion (Scene scene) 106 public virtual void AddRegion(Scene scene)
97 { 107 {
98 if (!m_Enabled) 108 if (!m_Enabled)
99 return; 109 return;
@@ -109,6 +119,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
109 "export-map [<path>]", 119 "export-map [<path>]",
110 "Save an image of the world map", HandleExportWorldMapConsoleCommand); 120 "Save an image of the world map", HandleExportWorldMapConsoleCommand);
111 121
122 m_scene.AddCommand(
123 "Regions", this, "generate map",
124 "generate map",
125 "Generates and stores a new maptile.", HandleGenerateMapConsoleCommand);
126
112 AddHandlers(); 127 AddHandlers();
113 } 128 }
114 } 129 }
@@ -128,8 +143,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
128 143
129 public virtual void RegionLoaded (Scene scene) 144 public virtual void RegionLoaded (Scene scene)
130 { 145 {
131 } 146 if (!m_Enabled)
147 return;
132 148
149 m_ServiceThrottle = scene.RequestModuleInterface<IServiceThrottleModule>();
150
151 m_mapImageGenerator = m_scene.RequestModuleInterface<IMapImageGenerator>();
152 m_mapImageServiceModule = m_scene.RequestModuleInterface<IMapImageUploadModule>();
153 }
133 154
134 public virtual void Close() 155 public virtual void Close()
135 { 156 {
@@ -156,7 +177,16 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
156 regionimage = regionimage.Replace("-", ""); 177 regionimage = regionimage.Replace("-", "");
157 m_log.Info("[WORLD MAP]: JPEG Map location: " + m_scene.RegionInfo.ServerURI + "index.php?method=" + regionimage); 178 m_log.Info("[WORLD MAP]: JPEG Map location: " + m_scene.RegionInfo.ServerURI + "index.php?method=" + regionimage);
158 179
159 MainServer.Instance.AddHTTPHandler(regionimage, OnHTTPGetMapImage); 180 MainServer.Instance.AddHTTPHandler(regionimage,
181 new GenericHTTPDOSProtector(OnHTTPGetMapImage, OnHTTPThrottled, new BasicDosProtectorOptions()
182 {
183 AllowXForwardedFor = false,
184 ForgetTimeSpan = TimeSpan.FromMinutes(2),
185 MaxRequestsInTimeframe = 4,
186 ReportingName = "MAPDOSPROTECTOR",
187 RequestTimeSpan = TimeSpan.FromSeconds(10),
188 ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod
189 }).Process);
160 MainServer.Instance.AddLLSDHandler( 190 MainServer.Instance.AddLLSDHandler(
161 "/MAP/MapItems/" + m_scene.RegionInfo.RegionHandle.ToString(), HandleRemoteMapItemRequest); 191 "/MAP/MapItems/" + m_scene.RegionInfo.RegionHandle.ToString(), HandleRemoteMapItemRequest);
162 192
@@ -167,13 +197,13 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
167 m_scene.EventManager.OnMakeRootAgent += MakeRootAgent; 197 m_scene.EventManager.OnMakeRootAgent += MakeRootAgent;
168 m_scene.EventManager.OnRegionUp += OnRegionUp; 198 m_scene.EventManager.OnRegionUp += OnRegionUp;
169 199
170 StartThread(new object()); 200// StartThread(new object());
171 } 201 }
172 202
173 // this has to be called with a lock on m_scene 203 // this has to be called with a lock on m_scene
174 protected virtual void RemoveHandlers() 204 protected virtual void RemoveHandlers()
175 { 205 {
176 StopThread(); 206// StopThread();
177 207
178 m_scene.EventManager.OnRegionUp -= OnRegionUp; 208 m_scene.EventManager.OnRegionUp -= OnRegionUp;
179 m_scene.EventManager.OnMakeRootAgent -= MakeRootAgent; 209 m_scene.EventManager.OnMakeRootAgent -= MakeRootAgent;
@@ -259,15 +289,15 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
259 { 289 {
260 List<MapBlockData> mapBlocks = new List<MapBlockData>(); ; 290 List<MapBlockData> mapBlocks = new List<MapBlockData>(); ;
261 291
292 // Get regions that are within 8 regions of here
262 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, 293 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
263 (int)(m_scene.RegionInfo.RegionLocX - 8) * (int)Constants.RegionSize, 294 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX - 8),
264 (int)(m_scene.RegionInfo.RegionLocX + 8) * (int)Constants.RegionSize, 295 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX + 8),
265 (int)(m_scene.RegionInfo.RegionLocY - 8) * (int)Constants.RegionSize, 296 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY - 8),
266 (int)(m_scene.RegionInfo.RegionLocY + 8) * (int)Constants.RegionSize); 297 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY + 8) );
267 foreach (GridRegion r in regions) 298 foreach (GridRegion r in regions)
268 { 299 {
269 MapBlockData block = new MapBlockData(); 300 MapBlockData block = MapBlockFromGridRegion(r, 0);
270 MapBlockFromGridRegion(block, r, 0);
271 mapBlocks.Add(block); 301 mapBlocks.Add(block);
272 } 302 }
273 avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0); 303 avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0);
@@ -351,7 +381,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
351 381
352// m_log.Debug("[WORLD MAP]: Starting remote MapItem request thread"); 382// m_log.Debug("[WORLD MAP]: Starting remote MapItem request thread");
353 383
354 Watchdog.StartThread( 384 WorkManager.StartThread(
355 process, 385 process,
356 string.Format("MapItemRequestThread ({0})", m_scene.RegionInfo.RegionName), 386 string.Format("MapItemRequestThread ({0})", m_scene.RegionInfo.RegionName),
357 ThreadPriority.BelowNormal, 387 ThreadPriority.BelowNormal,
@@ -387,24 +417,23 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
387 } 417 }
388 uint xstart = 0; 418 uint xstart = 0;
389 uint ystart = 0; 419 uint ystart = 0;
390 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out xstart, out ystart); 420 Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle, out xstart, out ystart);
391 if (itemtype == 6) // Service 6 right now (MAP_ITEM_AGENTS_LOCATION; green dots) 421 if (itemtype == (int)GridItemType.AgentLocations)
392 { 422 {
393 if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) 423 if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle)
394 { 424 {
395 // Local Map Item Request 425 // Just requesting map info about the current, local region
396 int tc = Environment.TickCount; 426 int tc = Environment.TickCount;
397 List<mapItemReply> mapitems = new List<mapItemReply>(); 427 List<mapItemReply> mapitems = new List<mapItemReply>();
398 mapItemReply mapitem = new mapItemReply(); 428 mapItemReply mapitem = new mapItemReply();
399 if (m_scene.GetRootAgentCount() <= 1) 429 if (m_scene.GetRootAgentCount() <= 1)
400 { 430 {
401 mapitem = new mapItemReply(); 431 mapitem = new mapItemReply(
402 mapitem.x = (uint)(xstart + 1); 432 xstart + 1,
403 mapitem.y = (uint)(ystart + 1); 433 ystart + 1,
404 mapitem.id = UUID.Zero; 434 UUID.Zero,
405 mapitem.name = Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()); 435 Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()),
406 mapitem.Extra = 0; 436 0, 0);
407 mapitem.Extra2 = 0;
408 mapitems.Add(mapitem); 437 mapitems.Add(mapitem);
409 } 438 }
410 else 439 else
@@ -414,13 +443,12 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
414 // Don't send a green dot for yourself 443 // Don't send a green dot for yourself
415 if (sp.UUID != remoteClient.AgentId) 444 if (sp.UUID != remoteClient.AgentId)
416 { 445 {
417 mapitem = new mapItemReply(); 446 mapitem = new mapItemReply(
418 mapitem.x = (uint)(xstart + sp.AbsolutePosition.X); 447 xstart + (uint)sp.AbsolutePosition.X,
419 mapitem.y = (uint)(ystart + sp.AbsolutePosition.Y); 448 ystart + (uint)sp.AbsolutePosition.Y,
420 mapitem.id = UUID.Zero; 449 UUID.Zero,
421 mapitem.name = Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()); 450 Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()),
422 mapitem.Extra = 1; 451 1, 0);
423 mapitem.Extra2 = 0;
424 mapitems.Add(mapitem); 452 mapitems.Add(mapitem);
425 } 453 }
426 }); 454 });
@@ -435,7 +463,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
435 RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle); 463 RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle);
436 } 464 }
437 } 465 }
438 else if (itemtype == 7) // Service 7 (MAP_ITEM_LAND_FOR_SALE) 466 else if (itemtype == (int)GridItemType.LandForSale) // Service 7 (MAP_ITEM_LAND_FOR_SALE)
439 { 467 {
440 if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) 468 if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle)
441 { 469 {
@@ -465,14 +493,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
465 float x = (min.X+max.X)/2; 493 float x = (min.X+max.X)/2;
466 float y = (min.Y+max.Y)/2; 494 float y = (min.Y+max.Y)/2;
467 495
468 mapitem = new mapItemReply(); 496 mapitem = new mapItemReply(
469 mapitem.x = (uint)(xstart + x); 497 xstart + (uint)x,
470 mapitem.y = (uint)(ystart + y); 498 ystart + (uint)y,
471 // mapitem.z = (uint)m_scene.GetGroundHeight(x,y); 499 parcel.GlobalID,
472 mapitem.id = parcel.GlobalID; 500 parcel.Name,
473 mapitem.name = parcel.Name; 501 parcel.Area,
474 mapitem.Extra = parcel.Area; 502 parcel.SalePrice
475 mapitem.Extra2 = parcel.SalePrice; 503 );
476 mapitems.Add(mapitem); 504 mapitems.Add(mapitem);
477 } 505 }
478 } 506 }
@@ -487,7 +515,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
487 RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle); 515 RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle);
488 } 516 }
489 } 517 }
490 else if (itemtype == 1) // Service 1 (MAP_ITEM_TELEHUB) 518 else if (itemtype == (int)GridItemType.Telehub) // Service 1 (MAP_ITEM_TELEHUB)
491 { 519 {
492 if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) 520 if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle)
493 { 521 {
@@ -497,13 +525,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
497 SceneObjectGroup sog = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject); 525 SceneObjectGroup sog = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject);
498 if (sog != null) 526 if (sog != null)
499 { 527 {
500 mapitem = new mapItemReply(); 528 mapitem = new mapItemReply(
501 mapitem.x = (uint)(xstart + sog.AbsolutePosition.X); 529 xstart + (uint)sog.AbsolutePosition.X,
502 mapitem.y = (uint)(ystart + sog.AbsolutePosition.Y); 530 ystart + (uint)sog.AbsolutePosition.Y,
503 mapitem.id = UUID.Zero; 531 UUID.Zero,
504 mapitem.name = sog.Name; 532 sog.Name,
505 mapitem.Extra = 0; // color (not used) 533 0, // color (not used)
506 mapitem.Extra2 = 0; // 0 = telehub / 1 = infohub 534 0 // 0 = telehub / 1 = infohub
535 );
507 mapitems.Add(mapitem); 536 mapitems.Add(mapitem);
508 537
509 remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags); 538 remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags);
@@ -523,7 +552,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
523 /// </summary> 552 /// </summary>
524 public void process() 553 public void process()
525 { 554 {
526 const int MAX_ASYNC_REQUESTS = 20; 555 //const int MAX_ASYNC_REQUESTS = 20;
527 try 556 try
528 { 557 {
529 while (true) 558 while (true)
@@ -568,13 +597,44 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
568 Watchdog.RemoveThread(); 597 Watchdog.RemoveThread();
569 } 598 }
570 599
600 const int MAX_ASYNC_REQUESTS = 20;
601
571 /// <summary> 602 /// <summary>
572 /// Enqueues the map item request into the processing thread 603 /// Enqueues the map item request into the services throttle processing thread
573 /// </summary> 604 /// </summary>
574 /// <param name="state"></param> 605 /// <param name="state"></param>
575 public void EnqueueMapItemRequest(MapRequestState state) 606 public void EnqueueMapItemRequest(MapRequestState st)
576 { 607 {
577 requests.Enqueue(state); 608
609 m_ServiceThrottle.Enqueue("map-item", st.regionhandle.ToString() + st.agentID.ToString(), delegate
610 {
611 if (st.agentID != UUID.Zero)
612 {
613 bool dorequest = true;
614 lock (m_rootAgents)
615 {
616 if (!m_rootAgents.Contains(st.agentID))
617 dorequest = false;
618 }
619
620 if (dorequest && !m_blacklistedregions.ContainsKey(st.regionhandle))
621 {
622 if (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break
623 {
624 // AH!!! Recursive !
625 // Put this request back in the queue and return
626 EnqueueMapItemRequest(st);
627 return;
628 }
629
630 RequestMapItemsDelegate d = RequestMapItemsAsync;
631 d.BeginInvoke(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle, RequestMapItemsCompleted, null);
632 //OSDMap response = RequestMapItemsAsync(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle);
633 //RequestMapItemsCompleted(response);
634 Interlocked.Increment(ref nAsyncRequests);
635 }
636 }
637 });
578 } 638 }
579 639
580 /// <summary> 640 /// <summary>
@@ -622,19 +682,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
622 { 682 {
623 OSDMap mapitem = (OSDMap)itemarray[i]; 683 OSDMap mapitem = (OSDMap)itemarray[i];
624 mapItemReply mi = new mapItemReply(); 684 mapItemReply mi = new mapItemReply();
625 mi.x = (uint)mapitem["X"].AsInteger(); 685 mi.FromOSD(mapitem);
626 mi.y = (uint)mapitem["Y"].AsInteger();
627 mi.id = mapitem["ID"].AsUUID();
628 mi.Extra = mapitem["Extra"].AsInteger();
629 mi.Extra2 = mapitem["Extra2"].AsInteger();
630 mi.name = mapitem["Name"].AsString();
631 returnitems.Add(mi); 686 returnitems.Add(mi);
632 } 687 }
633 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), mrs.itemtype, mrs.flags); 688 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), mrs.itemtype, mrs.flags);
634 } 689 }
635 690
636 // Service 7 (MAP_ITEM_LAND_FOR_SALE) 691 // Service 7 (MAP_ITEM_LAND_FOR_SALE)
637 uint itemtype = 7; 692 uint itemtype = (uint)GridItemType.LandForSale;
638 693
639 if (response.ContainsKey(itemtype.ToString())) 694 if (response.ContainsKey(itemtype.ToString()))
640 { 695 {
@@ -644,19 +699,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
644 { 699 {
645 OSDMap mapitem = (OSDMap)itemarray[i]; 700 OSDMap mapitem = (OSDMap)itemarray[i];
646 mapItemReply mi = new mapItemReply(); 701 mapItemReply mi = new mapItemReply();
647 mi.x = (uint)mapitem["X"].AsInteger(); 702 mi.FromOSD(mapitem);
648 mi.y = (uint)mapitem["Y"].AsInteger();
649 mi.id = mapitem["ID"].AsUUID();
650 mi.Extra = mapitem["Extra"].AsInteger();
651 mi.Extra2 = mapitem["Extra2"].AsInteger();
652 mi.name = mapitem["Name"].AsString();
653 returnitems.Add(mi); 703 returnitems.Add(mi);
654 } 704 }
655 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags); 705 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags);
656 } 706 }
657 707
658 // Service 1 (MAP_ITEM_TELEHUB) 708 // Service 1 (MAP_ITEM_TELEHUB)
659 itemtype = 1; 709 itemtype = (uint)GridItemType.Telehub;
660 710
661 if (response.ContainsKey(itemtype.ToString())) 711 if (response.ContainsKey(itemtype.ToString()))
662 { 712 {
@@ -666,12 +716,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
666 { 716 {
667 OSDMap mapitem = (OSDMap)itemarray[i]; 717 OSDMap mapitem = (OSDMap)itemarray[i];
668 mapItemReply mi = new mapItemReply(); 718 mapItemReply mi = new mapItemReply();
669 mi.x = (uint)mapitem["X"].AsInteger(); 719 mi.FromOSD(mapitem);
670 mi.y = (uint)mapitem["Y"].AsInteger();
671 mi.id = mapitem["ID"].AsUUID();
672 mi.Extra = mapitem["Extra"].AsInteger();
673 mi.Extra2 = mapitem["Extra2"].AsInteger();
674 mi.name = mapitem["Name"].AsString();
675 returnitems.Add(mi); 720 returnitems.Add(mi);
676 } 721 }
677 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags); 722 av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags);
@@ -754,7 +799,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
754 if (httpserver.Length == 0) 799 if (httpserver.Length == 0)
755 { 800 {
756 uint x = 0, y = 0; 801 uint x = 0, y = 0;
757 Utils.LongToUInts(regionhandle, out x, out y); 802 Util.RegionHandleToWorldLoc(regionhandle, out x, out y);
758 GridRegion mreg = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); 803 GridRegion mreg = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y);
759 804
760 if (mreg != null) 805 if (mreg != null)
@@ -861,24 +906,26 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
861 finally 906 finally
862 { 907 {
863 if (os != null) 908 if (os != null)
864 os.Close(); 909 os.Dispose();
865 } 910 }
866 911
867 string response_mapItems_reply = null; 912 string response_mapItems_reply = null;
868 { // get the response 913 {
869 StreamReader sr = null;
870 try 914 try
871 { 915 {
872 WebResponse webResponse = mapitemsrequest.GetResponse(); 916 using (WebResponse webResponse = mapitemsrequest.GetResponse())
873 if (webResponse != null)
874 {
875 sr = new StreamReader(webResponse.GetResponseStream());
876 response_mapItems_reply = sr.ReadToEnd().Trim();
877 }
878 else
879 { 917 {
880 return new OSDMap(); 918 if (webResponse != null)
881 } 919 {
920 using (Stream s = webResponse.GetResponseStream())
921 using (StreamReader sr = new StreamReader(s))
922 response_mapItems_reply = sr.ReadToEnd().Trim();
923 }
924 else
925 {
926 return new OSDMap();
927 }
928 }
882 } 929 }
883 catch (WebException) 930 catch (WebException)
884 { 931 {
@@ -905,11 +952,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
905 952
906 return responseMap; 953 return responseMap;
907 } 954 }
908 finally
909 {
910 if (sr != null)
911 sr.Close();
912 }
913 955
914 OSD rezResponse = null; 956 OSD rezResponse = null;
915 try 957 try
@@ -923,6 +965,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
923 { 965 {
924 m_log.InfoFormat("[WORLD MAP]: exception on parse of RequestMapItems reply from {0}: {1}", httpserver, ex.Message); 966 m_log.InfoFormat("[WORLD MAP]: exception on parse of RequestMapItems reply from {0}: {1}", httpserver, ex.Message);
925 responseMap["connect"] = OSD.FromBoolean(false); 967 responseMap["connect"] = OSD.FromBoolean(false);
968
926 lock (m_blacklistedregions) 969 lock (m_blacklistedregions)
927 { 970 {
928 if (!m_blacklistedregions.ContainsKey(regionhandle)) 971 if (!m_blacklistedregions.ContainsKey(regionhandle))
@@ -955,7 +998,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
955 /// <param name="maxY"></param> 998 /// <param name="maxY"></param>
956 public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) 999 public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
957 { 1000 {
958 //m_log.ErrorFormat("[YYY] RequestMapBlocks {0}={1}={2}={3} {4}", minX, minY, maxX, maxY, flag);
959 if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible 1001 if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible
960 { 1002 {
961 List<MapBlockData> response = new List<MapBlockData>(); 1003 List<MapBlockData> response = new List<MapBlockData>();
@@ -964,22 +1006,24 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
964 // on an unloaded square. 1006 // on an unloaded square.
965 // But make sure: Look whether the one we requested is in there 1007 // But make sure: Look whether the one we requested is in there
966 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, 1008 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
967 minX * (int)Constants.RegionSize, 1009 (int)Util.RegionToWorldLoc((uint)minX), (int)Util.RegionToWorldLoc((uint)maxX),
968 maxX * (int)Constants.RegionSize, 1010 (int)Util.RegionToWorldLoc((uint)minY), (int)Util.RegionToWorldLoc((uint)maxY) );
969 minY * (int)Constants.RegionSize,
970 maxY * (int)Constants.RegionSize);
971 1011
1012 m_log.DebugFormat("[WORLD MAP MODULE] RequestMapBlocks min=<{0},{1}>, max=<{2},{3}>, flag={4}, cntFound={5}",
1013 minX, minY, maxX, maxY, flag.ToString("X"), regions.Count);
972 if (regions != null) 1014 if (regions != null)
973 { 1015 {
974 foreach (GridRegion r in regions) 1016 foreach (GridRegion r in regions)
975 { 1017 {
976 if ((r.RegionLocX == minX * (int)Constants.RegionSize) && 1018 if (r.RegionLocX == Util.RegionToWorldLoc((uint)minX)
977 (r.RegionLocY == minY * (int)Constants.RegionSize)) 1019 && r.RegionLocY == Util.RegionToWorldLoc((uint)minY) )
978 { 1020 {
979 // found it => add it to response 1021 // found it => add it to response
980 MapBlockData block = new MapBlockData(); 1022 // Version 2 viewers can handle the larger regions
981 MapBlockFromGridRegion(block, r, flag); 1023 if ((flag & 2) == 2)
982 response.Add(block); 1024 response.AddRange(Map2BlockFromGridRegion(r, flag));
1025 else
1026 response.Add(MapBlockFromGridRegion(r, flag));
983 break; 1027 break;
984 } 1028 }
985 } 1029 }
@@ -991,7 +1035,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
991 MapBlockData block = new MapBlockData(); 1035 MapBlockData block = new MapBlockData();
992 block.X = (ushort)minX; 1036 block.X = (ushort)minX;
993 block.Y = (ushort)minY; 1037 block.Y = (ushort)minY;
994 block.Access = 254; // means 'simulator is offline' 1038 block.Access = (byte)SimAccess.Down; // means 'simulator is offline'
1039 // block.Access = (byte)SimAccess.NonExistent;
995 response.Add(block); 1040 response.Add(block);
996 } 1041 }
997 // The lower 16 bits are an unsigned int16 1042 // The lower 16 bits are an unsigned int16
@@ -1008,39 +1053,94 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1008 { 1053 {
1009 List<MapBlockData> mapBlocks = new List<MapBlockData>(); 1054 List<MapBlockData> mapBlocks = new List<MapBlockData>();
1010 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, 1055 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
1011 (minX - 4) * (int)Constants.RegionSize, 1056 (int)Util.RegionToWorldLoc((uint)(minX - 4)), (int)Util.RegionToWorldLoc((uint)(maxX + 4)),
1012 (maxX + 4) * (int)Constants.RegionSize, 1057 (int)Util.RegionToWorldLoc((uint)(minY - 4)), (int)Util.RegionToWorldLoc((uint)(maxY + 4)) );
1013 (minY - 4) * (int)Constants.RegionSize, 1058 //m_log.DebugFormat("{0} GetAndSendBlocks. min=<{1},{2}>, max=<{3},{4}>, cntFound={5}",
1014 (maxY + 4) * (int)Constants.RegionSize); 1059 // LogHeader, minX, minY, maxX, maxY, regions.Count);
1015 foreach (GridRegion r in regions) 1060 foreach (GridRegion r in regions)
1016 { 1061 {
1017 MapBlockData block = new MapBlockData(); 1062 // Version 2 viewers can handle the larger regions
1018 MapBlockFromGridRegion(block, r, flag); 1063 if ((flag & 2) == 2)
1019 mapBlocks.Add(block); 1064 mapBlocks.AddRange(Map2BlockFromGridRegion(r, flag));
1065 else
1066 mapBlocks.Add(MapBlockFromGridRegion(r, flag));
1020 } 1067 }
1021 remoteClient.SendMapBlock(mapBlocks, flag & 0xffff); 1068 remoteClient.SendMapBlock(mapBlocks, flag & 0xffff);
1022 1069
1023 return mapBlocks; 1070 return mapBlocks;
1024 } 1071 }
1025 1072
1026 protected void MapBlockFromGridRegion(MapBlockData block, GridRegion r, uint flag) 1073 // Fill a passed MapBlockData from a GridRegion
1074 public MapBlockData MapBlockFromGridRegion(GridRegion r, uint flag)
1027 { 1075 {
1076 MapBlockData block = new MapBlockData();
1077
1028 block.Access = r.Access; 1078 block.Access = r.Access;
1029 switch (flag & 0xffff) 1079 switch (flag & 0xffff)
1030 { 1080 {
1031 case 0: 1081 case 0:
1032 block.MapImageId = r.TerrainImage; 1082 block.MapImageId = r.TerrainImage;
1033 break; 1083 break;
1034 case 2: 1084 case 2:
1035 block.MapImageId = r.ParcelImage; 1085 block.MapImageId = r.ParcelImage;
1036 break; 1086 break;
1037 default: 1087 default:
1038 block.MapImageId = UUID.Zero; 1088 block.MapImageId = UUID.Zero;
1039 break; 1089 break;
1040 } 1090 }
1041 block.Name = r.RegionName; 1091 block.Name = r.RegionName;
1042 block.X = (ushort)(r.RegionLocX / Constants.RegionSize); 1092 block.X = (ushort)Util.WorldToRegionLoc((uint)r.RegionLocX);
1043 block.Y = (ushort)(r.RegionLocY / Constants.RegionSize); 1093 block.Y = (ushort)Util.WorldToRegionLoc((uint)r.RegionLocY);
1094 block.SizeX = (ushort) r.RegionSizeX;
1095 block.SizeY = (ushort) r.RegionSizeY;
1096
1097 return block;
1098 }
1099
1100 public List<MapBlockData> Map2BlockFromGridRegion(GridRegion r, uint flag)
1101 {
1102 List<MapBlockData> blocks = new List<MapBlockData>();
1103 MapBlockData block = new MapBlockData();
1104 if (r == null)
1105 {
1106 block.Access = (byte)SimAccess.Down;
1107 block.MapImageId = UUID.Zero;
1108 blocks.Add(block);
1109 }
1110 else
1111 {
1112 block.Access = r.Access;
1113 switch (flag & 0xffff)
1114 {
1115 case 0:
1116 block.MapImageId = r.TerrainImage;
1117 break;
1118 case 2:
1119 block.MapImageId = r.ParcelImage;
1120 break;
1121 default:
1122 block.MapImageId = UUID.Zero;
1123 break;
1124 }
1125 block.Name = r.RegionName;
1126 block.X = (ushort)(r.RegionLocX / Constants.RegionSize);
1127 block.Y = (ushort)(r.RegionLocY / Constants.RegionSize);
1128 block.SizeX = (ushort)r.RegionSizeX;
1129 block.SizeY = (ushort)r.RegionSizeY;
1130 blocks.Add(block);
1131 }
1132 return blocks;
1133 }
1134
1135
1136 public Hashtable OnHTTPThrottled(Hashtable keysvals)
1137 {
1138 Hashtable reply = new Hashtable();
1139 int statuscode = 500;
1140 reply["str_response_string"] = "";
1141 reply["int_response_code"] = statuscode;
1142 reply["content_type"] = "text/plain";
1143 return reply;
1044 } 1144 }
1045 1145
1046 public Hashtable OnHTTPGetMapImage(Hashtable keysvals) 1146 public Hashtable OnHTTPGetMapImage(Hashtable keysvals)
@@ -1052,7 +1152,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1052 1152
1053 if (myMapImageJPEG.Length == 0) 1153 if (myMapImageJPEG.Length == 0)
1054 { 1154 {
1055 MemoryStream imgstream = new MemoryStream(); 1155 MemoryStream imgstream = null;
1056 Bitmap mapTexture = new Bitmap(1,1); 1156 Bitmap mapTexture = new Bitmap(1,1);
1057 ManagedImage managedImage; 1157 ManagedImage managedImage;
1058 Image image = (Image)mapTexture; 1158 Image image = (Image)mapTexture;
@@ -1099,10 +1199,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1099 image.Dispose(); 1199 image.Dispose();
1100 1200
1101 if (imgstream != null) 1201 if (imgstream != null)
1102 {
1103 imgstream.Close();
1104 imgstream.Dispose(); 1202 imgstream.Dispose();
1105 }
1106 } 1203 }
1107 } 1204 }
1108 else 1205 else
@@ -1161,17 +1258,16 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1161 1258
1162 List<MapBlockData> mapBlocks = new List<MapBlockData>(); 1259 List<MapBlockData> mapBlocks = new List<MapBlockData>();
1163 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, 1260 List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
1164 (int)(m_scene.RegionInfo.RegionLocX - 9) * (int)Constants.RegionSize, 1261 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX - 9),
1165 (int)(m_scene.RegionInfo.RegionLocX + 9) * (int)Constants.RegionSize, 1262 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX + 9),
1166 (int)(m_scene.RegionInfo.RegionLocY - 9) * (int)Constants.RegionSize, 1263 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY - 9),
1167 (int)(m_scene.RegionInfo.RegionLocY + 9) * (int)Constants.RegionSize); 1264 (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY + 9));
1168 List<AssetBase> textures = new List<AssetBase>(); 1265 List<AssetBase> textures = new List<AssetBase>();
1169 List<Image> bitImages = new List<Image>(); 1266 List<Image> bitImages = new List<Image>();
1170 1267
1171 foreach (GridRegion r in regions) 1268 foreach (GridRegion r in regions)
1172 { 1269 {
1173 MapBlockData mapBlock = new MapBlockData(); 1270 MapBlockData mapBlock = MapBlockFromGridRegion(r, 0);
1174 MapBlockFromGridRegion(mapBlock, r, 0);
1175 AssetBase texAsset = m_scene.AssetService.Get(mapBlock.MapImageId.ToString()); 1271 AssetBase texAsset = m_scene.AssetService.Get(mapBlock.MapImageId.ToString());
1176 1272
1177 if (texAsset != null) 1273 if (texAsset != null)
@@ -1217,12 +1313,34 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1217 m_scene.RegionInfo.RegionName, exportPath); 1313 m_scene.RegionInfo.RegionName, exportPath);
1218 } 1314 }
1219 1315
1316 public void HandleGenerateMapConsoleCommand(string module, string[] cmdparams)
1317 {
1318 Scene consoleScene = m_scene.ConsoleScene();
1319
1320 if (consoleScene != null && consoleScene != m_scene)
1321 return;
1322
1323 if (m_mapImageGenerator == null)
1324 {
1325 Console.WriteLine("No map image generator available for {0}", m_scene.Name);
1326 return;
1327 }
1328
1329 using (Bitmap mapbmp = m_mapImageGenerator.CreateMapTile())
1330 {
1331 GenerateMaptile(mapbmp);
1332 m_mapImageServiceModule.UploadMapTile(m_scene, mapbmp);
1333 }
1334 }
1335
1220 public OSD HandleRemoteMapItemRequest(string path, OSD request, string endpoint) 1336 public OSD HandleRemoteMapItemRequest(string path, OSD request, string endpoint)
1221 { 1337 {
1222 uint xstart = 0; 1338 uint xstart = 0;
1223 uint ystart = 0; 1339 uint ystart = 0;
1224 1340
1225 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle,out xstart,out ystart); 1341 Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle,out xstart,out ystart);
1342 // m_log.DebugFormat("{0} HandleRemoteMapItemRequest. loc=<{1},{2}>",
1343 // LogHeader, Util.WorldToRegionLoc(xstart), Util.WorldToRegionLoc(ystart));
1226 1344
1227 // Service 6 (MAP_ITEM_AGENTS_LOCATION; green dots) 1345 // Service 6 (MAP_ITEM_AGENTS_LOCATION; green dots)
1228 1346
@@ -1337,20 +1455,35 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1337 1455
1338 public void GenerateMaptile() 1456 public void GenerateMaptile()
1339 { 1457 {
1340 // Cannot create a map for a nonexistant heightmap 1458 // Cannot create a map for a nonexistent heightmap
1341 if (m_scene.Heightmap == null) 1459 if (m_scene.Heightmap == null)
1342 return; 1460 return;
1343 1461
1344 //create a texture asset of the terrain 1462 m_log.DebugFormat("[WORLD MAP]: Generating map image for {0}", m_scene.Name);
1345 IMapImageGenerator terrain = m_scene.RequestModuleInterface<IMapImageGenerator>(); 1463
1346 if (terrain == null) 1464 using (Bitmap mapbmp = m_mapImageGenerator.CreateMapTile())
1347 return; 1465 {
1466 // V1 (This Module)
1467 GenerateMaptile(mapbmp);
1468
1469 // v2/3 (MapImageServiceModule)
1470 m_mapImageServiceModule.UploadMapTile(m_scene, mapbmp);
1471 }
1472 }
1348 1473
1349 m_log.DebugFormat("[WORLD MAP]: Generating map image for {0}", m_scene.RegionInfo.RegionName); 1474 private void GenerateMaptile(Bitmap mapbmp)
1475 {
1476 byte[] data;
1350 1477
1351 byte[] data = terrain.WriteJpeg2000Image(); 1478 try
1352 if (data == null) 1479 {
1480 data = OpenJPEG.EncodeFromImage(mapbmp, true);
1481 }
1482 catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke
1483 {
1484 m_log.Error("[WORLD MAP]: Failed generating terrain map: " + e);
1353 return; 1485 return;
1486 }
1354 1487
1355 byte[] overlay = GenerateOverlay(); 1488 byte[] overlay = GenerateOverlay();
1356 1489
@@ -1448,62 +1581,80 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1448 1581
1449 private Byte[] GenerateOverlay() 1582 private Byte[] GenerateOverlay()
1450 { 1583 {
1451 Bitmap overlay = new Bitmap(256, 256); 1584 // These need to be ints for bitmap generation
1585 int regionSizeX = (int)m_scene.RegionInfo.RegionSizeX;
1586 int regionSizeY = (int)m_scene.RegionInfo.RegionSizeY;
1452 1587
1453 bool[,] saleBitmap = new bool[64, 64]; 1588 int landTileSize = LandManagementModule.LandUnit;
1454 for (int x = 0 ; x < 64 ; x++) 1589 int regionLandTilesX = regionSizeX / landTileSize;
1455 { 1590 int regionLandTilesY = regionSizeY / landTileSize;
1456 for (int y = 0 ; y < 64 ; y++)
1457 saleBitmap[x, y] = false;
1458 }
1459 1591
1460 bool landForSale = false; 1592 using (Bitmap overlay = new Bitmap(regionSizeX, regionSizeY))
1593 {
1594 bool[,] saleBitmap = new bool[regionLandTilesX, regionLandTilesY];
1595 for (int x = 0; x < regionLandTilesX; x++)
1596 {
1597 for (int y = 0; y < regionLandTilesY; y++)
1598 saleBitmap[x, y] = false;
1599 }
1461 1600
1462 List<ILandObject> parcels = m_scene.LandChannel.AllParcels(); 1601 bool landForSale = false;
1463 1602
1464 Color background = Color.FromArgb(0, 0, 0, 0); 1603 List<ILandObject> parcels = m_scene.LandChannel.AllParcels();
1465 SolidBrush transparent = new SolidBrush(background);
1466 Graphics g = Graphics.FromImage(overlay);
1467 g.FillRectangle(transparent, 0, 0, 256, 256);
1468 1604
1469 SolidBrush yellow = new SolidBrush(Color.FromArgb(255, 249, 223, 9)); 1605 Color background = Color.FromArgb(0, 0, 0, 0);
1470 1606
1471 foreach (ILandObject land in parcels) 1607 using (Graphics g = Graphics.FromImage(overlay))
1472 {
1473 // m_log.DebugFormat("[WORLD MAP]: Parcel {0} flags {1}", land.LandData.Name, land.LandData.Flags);
1474 if ((land.LandData.Flags & (uint)ParcelFlags.ForSale) != 0)
1475 { 1608 {
1476 landForSale = true; 1609 using (SolidBrush transparent = new SolidBrush(background))
1610 g.FillRectangle(transparent, 0, 0, regionSizeX, regionSizeY);
1477 1611
1478 saleBitmap = land.MergeLandBitmaps(saleBitmap, land.GetLandBitmap()); 1612 foreach (ILandObject land in parcels)
1479 } 1613 {
1480 } 1614 // m_log.DebugFormat("[WORLD MAP]: Parcel {0} flags {1}", land.LandData.Name, land.LandData.Flags);
1615 if ((land.LandData.Flags & (uint)ParcelFlags.ForSale) != 0)
1616 {
1617 landForSale = true;
1481 1618
1482 if (!landForSale) 1619 saleBitmap = land.MergeLandBitmaps(saleBitmap, land.GetLandBitmap());
1483 { 1620 }
1484 m_log.DebugFormat("[WORLD MAP]: Region {0} has no parcels for sale, not generating overlay", m_scene.RegionInfo.RegionName); 1621 }
1485 return null; 1622
1486 } 1623 if (!landForSale)
1624 {
1625 m_log.DebugFormat("[WORLD MAP]: Region {0} has no parcels for sale, not generating overlay", m_scene.RegionInfo.RegionName);
1626 return null;
1627 }
1487 1628
1488 m_log.DebugFormat("[WORLD MAP]: Region {0} has parcels for sale, generating overlay", m_scene.RegionInfo.RegionName); 1629 m_log.DebugFormat("[WORLD MAP]: Region {0} has parcels for sale, generating overlay", m_scene.RegionInfo.RegionName);
1489 1630
1490 for (int x = 0 ; x < 64 ; x++) 1631 using (SolidBrush yellow = new SolidBrush(Color.FromArgb(255, 249, 223, 9)))
1491 { 1632 {
1492 for (int y = 0 ; y < 64 ; y++) 1633 for (int x = 0 ; x < regionLandTilesX ; x++)
1634 {
1635 for (int y = 0 ; y < regionLandTilesY ; y++)
1636 {
1637 if (saleBitmap[x, y])
1638 g.FillRectangle(
1639 yellow, x * landTileSize,
1640 regionSizeX - landTileSize - (y * landTileSize),
1641 landTileSize,
1642 landTileSize);
1643 }
1644 }
1645 }
1646 }
1647
1648 try
1493 { 1649 {
1494 if (saleBitmap[x, y]) 1650 return OpenJPEG.EncodeFromImage(overlay, true);
1495 g.FillRectangle(yellow, x * 4, 252 - (y * 4), 4, 4); 1651 }
1652 catch (Exception e)
1653 {
1654 m_log.DebugFormat("[WORLD MAP]: Error creating parcel overlay: " + e.ToString());
1496 } 1655 }
1497 } 1656 }
1498 1657
1499 try
1500 {
1501 return OpenJPEG.EncodeFromImage(overlay, true);
1502 }
1503 catch (Exception e)
1504 {
1505 m_log.DebugFormat("[WORLD MAP]: Error creating parcel overlay: " + e.ToString());
1506 }
1507 return null; 1658 return null;
1508 } 1659 }
1509 } 1660 }