diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index d516fa89bd..b17ab8b9ea 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -114,6 +114,7 @@ what it is today. * Kitto Flora * KittyLiu * Kurt Taylor (IBM) +* Lani Global * lkalif * lulurun * M.Igarashi diff --git a/OpenSim/Framework/TerrainData.cs b/OpenSim/Framework/TerrainData.cs index 9325df23d5..25f9ca699f 100644 --- a/OpenSim/Framework/TerrainData.cs +++ b/OpenSim/Framework/TerrainData.cs @@ -50,8 +50,9 @@ namespace OpenSim.Framework // Someday terrain will have caves public abstract float this[int x, int y, int z] { get; set; } - public bool IsTainted { get; protected set; } public abstract bool IsTaintedAt(int xx, int yy); + public abstract bool IsTaintedAt(int xx, int yy, bool clearOnTest); + public abstract void TaintAllTerrain(); public abstract void ClearTaint(); public abstract void ClearLand(); @@ -75,6 +76,7 @@ namespace OpenSim.Framework public abstract short[] GetCompressedMap(); public abstract float CompressionFactor { get; } + public abstract float[] GetFloatsSerialized(); public abstract double[,] GetDoubles(); public abstract TerrainData Clone(); } @@ -138,10 +140,20 @@ namespace OpenSim.Framework // TerrainData.ClearTaint public override void ClearTaint() { - IsTainted = false; + SetAllTaint(false); + } + + // TerrainData.TaintAllTerrain + public override void TaintAllTerrain() + { + SetAllTaint(true); + } + + private void SetAllTaint(bool setting) + { for (int ii = 0; ii < m_taint.GetLength(0); ii++) for (int jj = 0; jj < m_taint.GetLength(1); jj++) - m_taint[ii, jj] = false; + m_taint[ii, jj] = setting; } // TerrainData.ClearLand @@ -158,15 +170,25 @@ namespace OpenSim.Framework m_heightmap[xx, yy] = flatHeight; } - public override bool IsTaintedAt(int xx, int yy) + // Return 'true' of the patch that contains these region coordinates has been modified. + // Note that checking the taint clears it. + // There is existing code that relies on this feature. + public override bool IsTaintedAt(int xx, int yy, bool clearOnTest) { int tx = xx / Constants.TerrainPatchSize; int ty = yy / Constants.TerrainPatchSize; bool ret = m_taint[tx, ty]; - m_taint[tx, ty] = false; + if (ret && clearOnTest) + m_taint[tx, ty] = false; return ret; } + // Old form that clears the taint flag when we check it. + public override bool IsTaintedAt(int xx, int yy) + { + return IsTaintedAt(xx, yy, true /* clearOnTest */); + } + // TerrainData.GetDatabaseBlob // The user wants something to store in the database. public override bool GetDatabaseBlob(out int DBRevisionCode, out Array blob) @@ -212,6 +234,25 @@ namespace OpenSim.Framework return ret; } + // TerrainData.GetFloatsSerialized + // This one dimensional version is ordered so height = map[y*sizeX+x]; + // DEPRECATED: don't use this function as it does not retain the dimensions of the terrain + // and the caller will probably do the wrong thing if the terrain is not the legacy 256x256. + public override float[] GetFloatsSerialized() + { + int points = SizeX * SizeY; + float[] heights = new float[points]; + + int idx = 0; + for (int jj = 0; jj < SizeY; jj++) + for (int ii = 0; ii < SizeX; ii++) + { + heights[idx++] = FromCompressedHeight(m_heightmap[ii, jj]); + } + + return heights; + } + // TerrainData.GetDoubles public override double[,] GetDoubles() { diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index 08891d98a8..3fda67f551 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs @@ -149,8 +149,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_scene.RegisterModuleInterface(this); m_scene.EventManager.OnNewClient += EventManager_OnNewClient; + m_scene.EventManager.OnClientClosed += EventManager_OnClientClosed; m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; m_scene.EventManager.OnTerrainTick += EventManager_OnTerrainTick; + m_scene.EventManager.OnFrame += EventManager_OnFrame; } InstallDefaultEffects(); @@ -189,8 +191,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain // remove the commands m_scene.UnregisterModuleCommander(m_commander.Name); // remove the event-handlers + m_scene.EventManager.OnFrame -= EventManager_OnFrame; m_scene.EventManager.OnTerrainTick -= EventManager_OnTerrainTick; m_scene.EventManager.OnPluginConsole -= EventManager_OnPluginConsole; + m_scene.EventManager.OnClientClosed -= EventManager_OnClientClosed; m_scene.EventManager.OnNewClient -= EventManager_OnNewClient; // remove the interface m_scene.UnregisterModuleInterface(this); @@ -266,7 +270,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain String.Format("Unable to load heightmap: {0}", e.Message)); } } - CheckForTerrainUpdates(); m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully"); return; } @@ -347,7 +350,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain } } - CheckForTerrainUpdates(); m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully"); return; } @@ -418,7 +420,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain public void TaintTerrain () { - CheckForTerrainUpdates(); + m_channel.GetTerrainData().TaintAllTerrain(); } #region Plugin Loading Methods @@ -646,8 +648,40 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_scene.RegionInfo.RegionName, filename, m_supportFileExtensionsForTileSave); } + /// + /// Called before processing of every simulation frame. + /// This is used to check to see of any of the terrain is tainted and, if so, schedule + /// updates for all the presences. + /// This also checks to see if there are updates that need to be sent for each presence. + /// This is where the logic is to send terrain updates to clients. + /// + private void EventManager_OnFrame() + { + TerrainData terrData = m_channel.GetTerrainData(); + + bool shouldTaint = false; + for (int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) + { + for (int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) + { + if (terrData.IsTaintedAt(x, y)) + { + // Found a patch that was modified. Push this flag into the clients. + SendToClients(terrData, x, y); + shouldTaint = true; + } + } + } + if (shouldTaint) + { + m_scene.EventManager.TriggerTerrainTainted(); + m_tainted = true; + } + } + /// /// Performs updates to the region periodically, synchronising physics and other heightmap aware sections + /// Called infrequently (like every 5 seconds or so). Best used for storing terrain. /// private void EventManager_OnTerrainTick() { @@ -697,6 +731,22 @@ namespace OpenSim.Region.CoreModules.World.Terrain client.OnUnackedTerrain += client_OnUnackedTerrain; } + /// + /// Installs terrain brush hook to IClientAPI + /// + /// + private void EventManager_OnClientClosed(UUID client, Scene scene) + { + ScenePresence presence = scene.GetScenePresence(client); + if (presence != null) + { + presence.ControllingClient.OnModifyTerrain -= client_OnModifyTerrain; + presence.ControllingClient.OnBakeTerrain -= client_OnBakeTerrain; + presence.ControllingClient.OnLandUndo -= client_OnLandUndo; + presence.ControllingClient.OnUnackedTerrain -= client_OnUnackedTerrain; + } + } + /// /// Checks to see if the terrain has been modified since last check /// but won't attempt to limit those changes to the limits specified in the estate settings @@ -717,36 +767,32 @@ namespace OpenSim.Region.CoreModules.World.Terrain /// private void CheckForTerrainUpdates(bool respectEstateSettings) { - bool shouldTaint = false; - float[] terrHeights = m_channel.GetFloatsSerialised(); - int x; - for (x = 0; x < m_channel.Width; x += Constants.TerrainPatchSize) + } + + /// + /// Scan over changes in the terrain and limit height changes. This enforces the + /// non-estate owner limits on rate of terrain editting. + /// Returns 'true' if any heights were limited. + /// + private bool EnforceEstateLimits() + { + TerrainData terrData = m_channel.GetTerrainData(); + + bool wasLimited = false; + for (int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) { - int y; - for (y = 0; y < m_channel.Height; y += Constants.TerrainPatchSize) + for (int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) { - if (m_channel.Tainted(x, y)) - { + if (terrData.IsTaintedAt(x, y, false /* clearOnTest */)) + { // If we should respect the estate settings then // fixup and height deltas that don't respect them. // Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values. - if (respectEstateSettings && LimitChannelChanges(x, y)) - { - // Terrain heights were modified. Refetch the terrain info. - terrHeights = m_channel.GetFloatsSerialised(); - } - - // m_log.DebugFormat("{0} Patch modified. Sending (x,y) = ({1},{2})", LogHeader, x, y); - SendToClients(terrHeights, x, y); - shouldTaint = true; + wasLimited |= LimitChannelChanges(terrData, x, y); } } } - if (shouldTaint) - { - m_scene.EventManager.TriggerTerrainTainted(); - m_tainted = true; - } + return wasLimited; } /// @@ -754,11 +800,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain /// are all within the current estate limits /// true if changes were limited, false otherwise /// - private bool LimitChannelChanges(int xStart, int yStart) + private bool LimitChannelChanges(TerrainData terrData, int xStart, int yStart) { bool changesLimited = false; - double minDelta = m_scene.RegionInfo.RegionSettings.TerrainLowerLimit; - double maxDelta = m_scene.RegionInfo.RegionSettings.TerrainRaiseLimit; + float minDelta = (float)m_scene.RegionInfo.RegionSettings.TerrainLowerLimit; + float maxDelta = (float)m_scene.RegionInfo.RegionSettings.TerrainRaiseLimit; // loop through the height map for this patch and compare it against // the revert map @@ -766,19 +812,18 @@ namespace OpenSim.Region.CoreModules.World.Terrain { for (int y = yStart; y < yStart + Constants.TerrainPatchSize; y++) { - - double requestedHeight = m_channel[x, y]; - double bakedHeight = m_revert[x, y]; - double requestedDelta = requestedHeight - bakedHeight; + float requestedHeight = terrData[x, y]; + float bakedHeight = (float)m_revert[x, y]; + float requestedDelta = requestedHeight - bakedHeight; if (requestedDelta > maxDelta) { - m_channel[x, y] = bakedHeight + maxDelta; + terrData[x, y] = bakedHeight + maxDelta; changesLimited = true; } else if (requestedDelta < minDelta) { - m_channel[x, y] = bakedHeight + minDelta; //as lower is a -ve delta + terrData[x, y] = bakedHeight + minDelta; //as lower is a -ve delta changesLimited = true; } } @@ -806,11 +851,18 @@ namespace OpenSim.Region.CoreModules.World.Terrain /// A copy of the terrain as a 1D float array of size w*h /// The patch corner to send /// The patch corner to send - private void SendToClients(float[] heightMap, int x, int y) + private void SendToClients(TerrainData terrData, int x, int y) { + // We know the actual terrain data passed is ignored. This kludge saves changing IClientAPI. + //float[] heightMap = terrData.GetFloatsSerialized(); + float[] heightMap = new float[10]; m_scene.ForEachClient( delegate(IClientAPI controller) - { controller.SendLayerData( x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, heightMap); } + { + controller.SendLayerData( x / Constants.TerrainPatchSize, + y / Constants.TerrainPatchSize, + heightMap); + } ); } @@ -856,7 +908,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_painteffects[(StandardTerrainEffects) action].PaintEffect( m_channel, allowMask, west, south, height, size, seconds); - CheckForTerrainUpdates(!god); //revert changes outside estate limits + //revert changes outside estate limits + if (!god) + EnforceEstateLimits(); } } else @@ -897,7 +951,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_floodeffects[(StandardTerrainEffects) action].FloodEffect( m_channel, fillArea, size); - CheckForTerrainUpdates(!god); //revert changes outside estate limits + //revert changes outside estate limits + if (!god) + EnforceEstateLimits(); } } else @@ -921,7 +977,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain protected void client_OnUnackedTerrain(IClientAPI client, int patchX, int patchY) { //m_log.Debug("Terrain packet unacked, resending patch: " + patchX + " , " + patchY); - client.SendLayerData(patchX, patchY, m_scene.Heightmap.GetFloatsSerialised()); + // SendLayerData does not use the heightmap parameter. This kludge is so as to not change IClientAPI. + float[] heightMap = new float[10]; + client.SendLayerData(patchX, patchY, heightMap); } private void StoreUndoState() @@ -948,7 +1006,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void InterfaceLoadFile(Object[] args) { LoadFromFile((string) args[0]); - CheckForTerrainUpdates(); } private void InterfaceLoadTileFile(Object[] args) @@ -958,7 +1015,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain (int) args[2], (int) args[3], (int) args[4]); - CheckForTerrainUpdates(); } private void InterfaceSaveFile(Object[] args) @@ -987,7 +1043,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain for (y = 0; y < m_channel.Height; y++) m_channel[x, y] = m_revert[x, y]; - CheckForTerrainUpdates(); } private void InterfaceFlipTerrain(Object[] args) @@ -1028,7 +1083,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain } - CheckForTerrainUpdates(); } private void InterfaceRescaleTerrain(Object[] args) @@ -1086,7 +1140,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain } } - CheckForTerrainUpdates(); } } @@ -1097,7 +1150,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain for (x = 0; x < m_channel.Width; x++) for (y = 0; y < m_channel.Height; y++) m_channel[x, y] += (double) args[0]; - CheckForTerrainUpdates(); } private void InterfaceMultiplyTerrain(Object[] args) @@ -1106,7 +1158,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain for (x = 0; x < m_channel.Width; x++) for (y = 0; y < m_channel.Height; y++) m_channel[x, y] *= (double) args[0]; - CheckForTerrainUpdates(); } private void InterfaceLowerTerrain(Object[] args) @@ -1115,7 +1166,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain for (x = 0; x < m_channel.Width; x++) for (y = 0; y < m_channel.Height; y++) m_channel[x, y] -= (double) args[0]; - CheckForTerrainUpdates(); } private void InterfaceFillTerrain(Object[] args) @@ -1125,7 +1175,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain for (x = 0; x < m_channel.Width; x++) for (y = 0; y < m_channel.Height; y++) m_channel[x, y] = (double) args[0]; - CheckForTerrainUpdates(); } private void InterfaceMinTerrain(Object[] args) @@ -1138,7 +1187,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_channel[x, y] = Math.Max((double)args[0], m_channel[x, y]); } } - CheckForTerrainUpdates(); } private void InterfaceMaxTerrain(Object[] args) @@ -1151,7 +1199,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_channel[x, y] = Math.Min((double)args[0], m_channel[x, y]); } } - CheckForTerrainUpdates(); } private void InterfaceShowDebugStats(Object[] args) @@ -1214,7 +1261,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain if (m_plugineffects.ContainsKey(firstArg)) { m_plugineffects[firstArg].RunEffect(m_channel); - CheckForTerrainUpdates(); } else { diff --git a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs index 60dc6c9676..cc040a66d7 100644 --- a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs +++ b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs @@ -124,17 +124,7 @@ namespace OpenSim.Region.Framework.Scenes // and the caller will probably do the wrong thing if the terrain is not the legacy 256x256. public float[] GetFloatsSerialised() { - int points = Width * Height; - float[] heights = new float[points]; - - int idx = 0; - for (int jj = 0; jj < Height; jj++) - for (int ii = 0; ii < Width; ii++) - { - heights[idx++] = m_terrainData[ii, jj]; - } - - return heights; + return m_terrainData.GetFloatsSerialized(); } // ITerrainChannel.GetDoubles() diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index e3b91ae7e1..c4697a178c 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -113,15 +113,15 @@ ;; NonPhysicalPrimMax!). ; NonPhysicalPrimMax = 256 - ;# {PhysicalPrimMin} {} {Minimum size of physical prims?} {} 10 + ;# {PhysicalPrimMin} {} {Minimum size of physical prims?} {} 0.01 ;; Maximum size where a prim can be physical. Affects resizing of ;; existing prims. This can be overriden in the region config file. ; PhysicalPrimMin = 0.01 - ;# {PhysicalPrimMax} {} {Maximum size of physical prims?} {} 10 + ;# {PhysicalPrimMax} {} {Maximum size of physical prims?} {} 64 ;; Maximum size where a prim can be physical. Affects resizing of ;; existing prims. This can be overriden in the region config file. - ; PhysicalPrimMax = 10 + ; PhysicalPrimMax = 64 ;# {ClampPrimSize} {} {Clamp viewer rezzed prims to max sizes?} {true false} false ;; If a viewer attempts to rez a prim larger than the non-physical or diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 026f285707..f59dbf2d6e 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -97,7 +97,7 @@ NonPhysicalPrimMax = 256 ; Maximum size of physical prims. Affects resizing of existing prims. This can be overriden in the region config file. - PhysicalPrimMax = 10 + PhysicalPrimMax = 64 ; If a viewer attempts to rez a prim larger than the non-physical or physical prim max, clamp the dimensions to the appropriate maximum ; This can be overriden in the region config file. diff --git a/bin/Regions/Regions.ini.example b/bin/Regions/Regions.ini.example index ab3a62aea9..aabc4f8b2b 100644 --- a/bin/Regions/Regions.ini.example +++ b/bin/Regions/Regions.ini.example @@ -29,7 +29,7 @@ ExternalHostName = "SYSTEMIP" ; * ; NonphysicalPrimMax = 256 -; PhysicalPrimMax = 10 +; PhysicalPrimMax = 64 ; ClampPrimSize = False ; MaxPrims = 15000 ; MaxAgents = 100