aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
diff options
context:
space:
mode:
authoronefang2019-05-19 21:24:15 +1000
committeronefang2019-05-19 21:24:15 +1000
commit5e4d6cab00cb29cd088ab7b62ab13aff103b64cb (patch)
treea9fbc62df9eb2d1d9ba2698d8552eae71eca20d8 /OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
parentAdd a build script. (diff)
downloadopensim-SC_OLD-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.zip
opensim-SC_OLD-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.gz
opensim-SC_OLD-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.bz2
opensim-SC_OLD-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.xz
Dump OpenSim 0.9.0.1 into it's own branch.
Diffstat (limited to 'OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs')
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs698
1 files changed, 447 insertions, 251 deletions
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
index 932652c..65d4c4a 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
@@ -29,6 +29,7 @@ using System.Collections.Generic;
29using System.IO; 29using System.IO;
30using System.Reflection; 30using System.Reflection;
31using System.Net; 31using System.Net;
32using System.Threading;
32 33
33using log4net; 34using log4net;
34using Nini.Config; 35using Nini.Config;
@@ -36,7 +37,6 @@ using Nini.Config;
36using OpenMetaverse; 37using OpenMetaverse;
37using Mono.Addins; 38using Mono.Addins;
38 39
39using OpenSim.Data;
40using OpenSim.Framework; 40using OpenSim.Framework;
41using OpenSim.Framework.Console; 41using OpenSim.Framework.Console;
42using OpenSim.Region.CoreModules.Framework.InterfaceCommander; 42using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
@@ -86,14 +86,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain
86 private readonly Dictionary<string, ITerrainLoader> m_loaders = new Dictionary<string, ITerrainLoader>(); 86 private readonly Dictionary<string, ITerrainLoader> m_loaders = new Dictionary<string, ITerrainLoader>();
87 private readonly Dictionary<StandardTerrainEffects, ITerrainPaintableEffect> m_painteffects = 87 private readonly Dictionary<StandardTerrainEffects, ITerrainPaintableEffect> m_painteffects =
88 new Dictionary<StandardTerrainEffects, ITerrainPaintableEffect>(); 88 new Dictionary<StandardTerrainEffects, ITerrainPaintableEffect>();
89 private Dictionary<string, ITerrainEffect> m_plugineffects;
90 private Dictionary<string, ITerrainModifier> m_modifyOperations = 89 private Dictionary<string, ITerrainModifier> m_modifyOperations =
91 new Dictionary<string, ITerrainModifier>(); 90 new Dictionary<string, ITerrainModifier>();
91 private Dictionary<string, ITerrainEffect> m_plugineffects;
92 private ITerrainChannel m_channel; 92 private ITerrainChannel m_channel;
93 private ITerrainChannel m_revert; 93 private ITerrainChannel m_baked;
94 private Scene m_scene; 94 private Scene m_scene;
95 private volatile bool m_tainted; 95 private volatile bool m_tainted;
96 private readonly Stack<LandUndoState> m_undo = new Stack<LandUndoState>(5); 96
97 private String m_InitialTerrain = "pinhead-island"; 97 private String m_InitialTerrain = "pinhead-island";
98 98
99 // If true, send terrain patch updates to clients based on their view distance 99 // If true, send terrain patch updates to clients based on their view distance
@@ -107,13 +107,16 @@ namespace OpenSim.Region.CoreModules.World.Terrain
107 private bool[,] updated; // for each patch, whether it needs to be sent to this client 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 108 private int updateCount; // number of patches that need to be sent
109 public ScenePresence Presence; // a reference to the client to send to 109 public ScenePresence Presence; // a reference to the client to send to
110 public TerrainData Terrain; // reference to the underlying terrain 110 public bool sendAll;
111 public int sendAllcurrentX;
112 public int sendAllcurrentY;
113
114
111 public PatchUpdates(TerrainData terrData, ScenePresence pPresence) 115 public PatchUpdates(TerrainData terrData, ScenePresence pPresence)
112 { 116 {
113 updated = new bool[terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize]; 117 updated = new bool[terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize];
114 updateCount = 0; 118 updateCount = 0;
115 Presence = pPresence; 119 Presence = pPresence;
116 Terrain = terrData;
117 // Initially, send all patches to the client 120 // Initially, send all patches to the client
118 SetAll(true); 121 SetAll(true);
119 } 122 }
@@ -146,12 +149,16 @@ namespace OpenSim.Region.CoreModules.World.Terrain
146 public void SetAll(bool state) 149 public void SetAll(bool state)
147 { 150 {
148 updateCount = 0; 151 updateCount = 0;
149 for(int xx = 0; xx < updated.GetLength(0); xx++) 152 for (int xx = 0; xx < updated.GetLength(0); xx++)
150 for(int yy = 0; yy < updated.GetLength(1); yy++) 153 for (int yy = 0; yy < updated.GetLength(1); yy++)
151 updated[xx, yy] = state; 154 updated[xx, yy] = state;
152 if (state) 155 if (state)
153 updateCount = updated.GetLength(0) * updated.GetLength(1); 156 updateCount = updated.GetLength(0) * updated.GetLength(1);
157 sendAllcurrentX = 0;
158 sendAllcurrentY = 0;
159 sendAll = true;
154 } 160 }
161
155 // Logically OR's the terrain data's patch taint map into this client's update map. 162 // Logically OR's the terrain data's patch taint map into this client's update map.
156 public void SetAll(TerrainData terrData) 163 public void SetAll(TerrainData terrData)
157 { 164 {
@@ -164,9 +171,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
164 terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize) 171 terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize)
165 ); 172 );
166 } 173 }
167 for(int xx = 0; xx < terrData.SizeX; xx += Constants.TerrainPatchSize) 174
175 for (int xx = 0; xx < terrData.SizeX; xx += Constants.TerrainPatchSize)
168 { 176 {
169 for(int yy = 0; yy < terrData.SizeY; yy += Constants.TerrainPatchSize) 177 for (int yy = 0; yy < terrData.SizeY; yy += Constants.TerrainPatchSize)
170 { 178 {
171 // Only set tainted. The patch bit may be set if the patch was to be sent later. 179 // Only set tainted. The patch bit may be set if the patch was to be sent later.
172 if (terrData.IsTaintedAt(xx, yy, false)) 180 if (terrData.IsTaintedAt(xx, yy, false))
@@ -210,7 +218,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
210 if (terrainConfig != null) 218 if (terrainConfig != null)
211 { 219 {
212 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); 220 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain);
213 m_sendTerrainUpdatesByViewDistance = terrainConfig.GetBoolean("SendTerrainUpdatesByViewDistance", m_sendTerrainUpdatesByViewDistance); 221 m_sendTerrainUpdatesByViewDistance =
222 terrainConfig.GetBoolean(
223 "SendTerrainUpdatesByViewDistance",m_sendTerrainUpdatesByViewDistance);
214 } 224 }
215 } 225 }
216 226
@@ -221,26 +231,34 @@ namespace OpenSim.Region.CoreModules.World.Terrain
221 // Install terrain module in the simulator 231 // Install terrain module in the simulator
222 lock(m_scene) 232 lock(m_scene)
223 { 233 {
234 if(m_scene.Bakedmap != null)
235 {
236 m_baked = m_scene.Bakedmap;
237 }
224 if (m_scene.Heightmap == null) 238 if (m_scene.Heightmap == null)
225 { 239 {
226 m_channel = new TerrainChannel(m_InitialTerrain, (int)m_scene.RegionInfo.RegionSizeX, 240 if(m_baked != null)
227 (int)m_scene.RegionInfo.RegionSizeY, 241 m_channel = m_baked.MakeCopy();
228 (int)m_scene.RegionInfo.RegionSizeZ); 242 else
243 m_channel = new TerrainChannel(m_InitialTerrain,
244 (int)m_scene.RegionInfo.RegionSizeX,
245 (int)m_scene.RegionInfo.RegionSizeY,
246 (int)m_scene.RegionInfo.RegionSizeZ);
229 m_scene.Heightmap = m_channel; 247 m_scene.Heightmap = m_channel;
230 UpdateRevertMap();
231 } 248 }
232 else 249 else
233 { 250 {
234 m_channel = m_scene.Heightmap; 251 m_channel = m_scene.Heightmap;
235 UpdateRevertMap();
236 } 252 }
253 if(m_baked == null)
254 UpdateBakedMap();
237 255
238 m_scene.RegisterModuleInterface<ITerrainModule>(this); 256 m_scene.RegisterModuleInterface<ITerrainModule>(this);
239 m_scene.EventManager.OnNewClient += EventManager_OnNewClient; 257 m_scene.EventManager.OnNewClient += EventManager_OnNewClient;
240 m_scene.EventManager.OnClientClosed += EventManager_OnClientClosed; 258 m_scene.EventManager.OnClientClosed += EventManager_OnClientClosed;
241 m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; 259 m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole;
242 m_scene.EventManager.OnTerrainTick += EventManager_OnTerrainTick; 260 m_scene.EventManager.OnTerrainTick += EventManager_OnTerrainTick;
243 m_scene.EventManager.OnFrame += EventManager_OnFrame; 261 m_scene.EventManager.OnTerrainCheckUpdates += EventManager_TerrainCheckUpdates;
244 } 262 }
245 263
246 InstallDefaultEffects(); 264 InstallDefaultEffects();
@@ -279,7 +297,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
279 // remove the commands 297 // remove the commands
280 m_scene.UnregisterModuleCommander(m_commander.Name); 298 m_scene.UnregisterModuleCommander(m_commander.Name);
281 // remove the event-handlers 299 // remove the event-handlers
282 m_scene.EventManager.OnFrame -= EventManager_OnFrame; 300
301 m_scene.EventManager.OnTerrainCheckUpdates -= EventManager_TerrainCheckUpdates;
283 m_scene.EventManager.OnTerrainTick -= EventManager_OnTerrainTick; 302 m_scene.EventManager.OnTerrainTick -= EventManager_OnTerrainTick;
284 m_scene.EventManager.OnPluginConsole -= EventManager_OnPluginConsole; 303 m_scene.EventManager.OnPluginConsole -= EventManager_OnPluginConsole;
285 m_scene.EventManager.OnClientClosed -= EventManager_OnClientClosed; 304 m_scene.EventManager.OnClientClosed -= EventManager_OnClientClosed;
@@ -334,7 +353,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
334 m_log.DebugFormat("[TERRAIN]: Loaded terrain, wd/ht: {0}/{1}", channel.Width, channel.Height); 353 m_log.DebugFormat("[TERRAIN]: Loaded terrain, wd/ht: {0}/{1}", channel.Width, channel.Height);
335 m_scene.Heightmap = channel; 354 m_scene.Heightmap = channel;
336 m_channel = channel; 355 m_channel = channel;
337 UpdateRevertMap(); 356 UpdateBakedMap();
338 } 357 }
339 catch(NotImplementedException) 358 catch(NotImplementedException)
340 { 359 {
@@ -426,7 +445,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
426 { 445 {
427 ITerrainChannel channel = loader.Value.LoadStream(stream); 446 ITerrainChannel channel = loader.Value.LoadStream(stream);
428 m_channel.Merge(channel, displacement, radianRotation, rotationDisplacement); 447 m_channel.Merge(channel, displacement, radianRotation, rotationDisplacement);
429 UpdateRevertMap(); 448 UpdateBakedMap();
430 } 449 }
431 catch(NotImplementedException) 450 catch(NotImplementedException)
432 { 451 {
@@ -444,6 +463,37 @@ namespace OpenSim.Region.CoreModules.World.Terrain
444 throw new TerrainException(String.Format("unable to load heightmap from file {0}: no loader available for that format", filename)); 463 throw new TerrainException(String.Format("unable to load heightmap from file {0}: no loader available for that format", filename));
445 } 464 }
446 465
466 public void LoadFromStream(string filename, Vector3 displacement,
467 float rotationDegrees, Vector2 boundingOrigin, Vector2 boundingSize, Stream stream)
468 {
469 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders)
470 {
471 if (filename.EndsWith(loader.Key))
472 {
473 lock (m_scene)
474 {
475 try
476 {
477 ITerrainChannel channel = loader.Value.LoadStream(stream);
478 m_channel.MergeWithBounding(channel, displacement, rotationDegrees, boundingOrigin, boundingSize);
479 UpdateBakedMap();
480 }
481 catch (NotImplementedException)
482 {
483 m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value +
484 " parser does not support file loading. (May be save only)");
485 throw new TerrainException(String.Format("unable to load heightmap: parser {0} does not support loading", loader.Value));
486 }
487 }
488
489 m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully");
490 return;
491 }
492 }
493 m_log.Error("[TERRAIN]: Unable to load heightmap, no file loader available for that format.");
494 throw new TerrainException(String.Format("unable to load heightmap from file {0}: no loader available for that format", filename));
495 }
496
447 private static Stream URIFetch(Uri uri) 497 private static Stream URIFetch(Uri uri)
448 { 498 {
449 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); 499 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
@@ -506,12 +556,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain
506 556
507 // Someone diddled terrain outside the normal code paths. Set the taintedness for all clients. 557 // Someone diddled terrain outside the normal code paths. Set the taintedness for all clients.
508 // ITerrainModule.TaintTerrain() 558 // ITerrainModule.TaintTerrain()
509 public void TaintTerrain() 559 public void TaintTerrain ()
510 { 560 {
511 lock(m_perClientPatchUpdates) 561 lock (m_perClientPatchUpdates)
512 { 562 {
513 // Set the flags for all clients so the tainted patches will be sent out 563 // Set the flags for all clients so the tainted patches will be sent out
514 foreach(PatchUpdates pups in m_perClientPatchUpdates.Values) 564 foreach (PatchUpdates pups in m_perClientPatchUpdates.Values)
515 { 565 {
516 pups.SetAll(m_scene.Heightmap.GetTerrainData()); 566 pups.SetAll(m_scene.Heightmap.GetTerrainData());
517 } 567 }
@@ -521,13 +571,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain
521 // ITerrainModule.PushTerrain() 571 // ITerrainModule.PushTerrain()
522 public void PushTerrain(IClientAPI pClient) 572 public void PushTerrain(IClientAPI pClient)
523 { 573 {
524 // If view distance based, set the modified patch bits and the frame event will send the updates
525 if (m_sendTerrainUpdatesByViewDistance) 574 if (m_sendTerrainUpdatesByViewDistance)
526 { 575 {
527 ScenePresence presence = m_scene.GetScenePresence(pClient.AgentId); 576 ScenePresence presence = m_scene.GetScenePresence(pClient.AgentId);
528 if (presence != null) 577 if (presence != null)
529 { 578 {
530 lock(m_perClientPatchUpdates) 579 lock (m_perClientPatchUpdates)
531 { 580 {
532 PatchUpdates pups; 581 PatchUpdates pups;
533 if (!m_perClientPatchUpdates.TryGetValue(pClient.AgentId, out pups)) 582 if (!m_perClientPatchUpdates.TryGetValue(pClient.AgentId, out pups))
@@ -536,7 +585,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
536 pups = new PatchUpdates(m_scene.Heightmap.GetTerrainData(), presence); 585 pups = new PatchUpdates(m_scene.Heightmap.GetTerrainData(), presence);
537 m_perClientPatchUpdates.Add(presence.UUID, pups); 586 m_perClientPatchUpdates.Add(presence.UUID, pups);
538 } 587 }
539 // By setting all to modified, the next update tick will send the patches
540 pups.SetAll(true); 588 pups.SetAll(true);
541 } 589 }
542 } 590 }
@@ -547,6 +595,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
547 pClient.SendLayerData(new float[10]); 595 pClient.SendLayerData(new float[10]);
548 } 596 }
549 } 597 }
598
550 #region Plugin Loading Methods 599 #region Plugin Loading Methods
551 600
552 private void LoadPlugins() 601 private void LoadPlugins()
@@ -636,7 +685,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
636 m_painteffects[StandardTerrainEffects.Smooth] = new SmoothSphere(); 685 m_painteffects[StandardTerrainEffects.Smooth] = new SmoothSphere();
637 m_painteffects[StandardTerrainEffects.Noise] = new NoiseSphere(); 686 m_painteffects[StandardTerrainEffects.Noise] = new NoiseSphere();
638 m_painteffects[StandardTerrainEffects.Flatten] = new FlattenSphere(); 687 m_painteffects[StandardTerrainEffects.Flatten] = new FlattenSphere();
639 m_painteffects[StandardTerrainEffects.Revert] = new RevertSphere(m_revert); 688 m_painteffects[StandardTerrainEffects.Revert] = new RevertSphere(m_baked);
640 m_painteffects[StandardTerrainEffects.Erode] = new ErodeSphere(); 689 m_painteffects[StandardTerrainEffects.Erode] = new ErodeSphere();
641 m_painteffects[StandardTerrainEffects.Weather] = new WeatherSphere(); 690 m_painteffects[StandardTerrainEffects.Weather] = new WeatherSphere();
642 m_painteffects[StandardTerrainEffects.Olsen] = new OlsenSphere(); 691 m_painteffects[StandardTerrainEffects.Olsen] = new OlsenSphere();
@@ -647,9 +696,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
647 m_floodeffects[StandardTerrainEffects.Smooth] = new SmoothArea(); 696 m_floodeffects[StandardTerrainEffects.Smooth] = new SmoothArea();
648 m_floodeffects[StandardTerrainEffects.Noise] = new NoiseArea(); 697 m_floodeffects[StandardTerrainEffects.Noise] = new NoiseArea();
649 m_floodeffects[StandardTerrainEffects.Flatten] = new FlattenArea(); 698 m_floodeffects[StandardTerrainEffects.Flatten] = new FlattenArea();
650 m_floodeffects[StandardTerrainEffects.Revert] = new RevertArea(m_revert); 699 m_floodeffects[StandardTerrainEffects.Revert] = new RevertArea(m_baked);
651 700
652 // Terrain Modifier operations 701 // Terrain Modifier operations
702
653 m_modifyOperations["min"] = new MinModifier(this); 703 m_modifyOperations["min"] = new MinModifier(this);
654 m_modifyOperations["max"] = new MaxModifier(this); 704 m_modifyOperations["max"] = new MaxModifier(this);
655 m_modifyOperations["raise"] = new RaiseModifier(this); 705 m_modifyOperations["raise"] = new RaiseModifier(this);
@@ -673,22 +723,16 @@ namespace OpenSim.Region.CoreModules.World.Terrain
673 } 723 }
674 724
675 /// <summary> 725 /// <summary>
676 /// Saves the current state of the region into the revert map buffer. 726 /// Saves the current state of the region into the baked map buffer.
727
677 /// </summary> 728 /// </summary>
678 public void UpdateRevertMap() 729 public void UpdateBakedMap()
679 { 730 {
680 /* 731 m_baked = m_channel.MakeCopy();
681 int x; 732 m_painteffects[StandardTerrainEffects.Revert] = new RevertSphere(m_baked);
682 for (x = 0; x < m_channel.Width; x++) 733 m_floodeffects[StandardTerrainEffects.Revert] = new RevertArea(m_baked);
683 { 734 m_scene.Bakedmap = m_baked;
684 int y; 735 m_scene.SaveBakedTerrain();
685 for (y = 0; y < m_channel.Height; y++)
686 {
687 m_revert[x, y] = m_channel[x, y];
688 }
689 }
690 */
691 m_revert = m_channel.MakeCopy();
692 } 736 }
693 737
694 /// <summary> 738 /// <summary>
@@ -715,11 +759,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
715 { 759 {
716 ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY, 760 ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY,
717 fileWidth, fileHeight, 761 fileWidth, fileHeight,
718 (int)m_scene.RegionInfo.RegionSizeX, 762 (int) m_scene.RegionInfo.RegionSizeX,
719 (int)m_scene.RegionInfo.RegionSizeY); 763 (int) m_scene.RegionInfo.RegionSizeY);
720 m_scene.Heightmap = channel; 764 m_scene.Heightmap = channel;
721 m_channel = channel; 765 m_channel = channel;
722 UpdateRevertMap(); 766 UpdateBakedMap();
723 } 767 }
724 768
725 return; 769 return;
@@ -781,39 +825,54 @@ namespace OpenSim.Region.CoreModules.World.Terrain
781 m_scene.RegionInfo.RegionName, filename, m_supportFileExtensionsForTileSave); 825 m_scene.RegionInfo.RegionName, filename, m_supportFileExtensionsForTileSave);
782 } 826 }
783 827
828
784 /// <summary> 829 /// <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 830 /// This is used to check to see of any of the terrain is tainted and, if so, schedule
787 /// updates for all the presences. 831 /// updates for all the presences.
788 /// This also checks to see if there are updates that need to be sent for each presence. 832 /// 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. 833 /// This is where the logic is to send terrain updates to clients.
790 /// </summary> 834 /// </summary>
791 private void EventManager_OnFrame() 835 /// doing it async, since currently this is 2 heavy for heartbeat
836 private void EventManager_TerrainCheckUpdates()
792 { 837 {
793 TerrainData terrData = m_channel.GetTerrainData(); 838 Util.FireAndForget(
839 EventManager_TerrainCheckUpdatesAsync);
840 }
841
842 object TerrainCheckUpdatesLock = new object();
794 843
795 bool shouldTaint = false; 844 private void EventManager_TerrainCheckUpdatesAsync(object o)
796 for(int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) 845 {
846 // dont overlap execution
847 if(Monitor.TryEnter(TerrainCheckUpdatesLock))
797 { 848 {
798 for(int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) 849 // this needs fixing
850 TerrainData terrData = m_channel.GetTerrainData();
851
852 bool shouldTaint = false;
853 for (int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize)
799 { 854 {
800 if (terrData.IsTaintedAt(x, y)) 855 for (int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize)
801 { 856 {
802 // Found a patch that was modified. Push this flag into the clients. 857 if (terrData.IsTaintedAt(x, y,true))
803 SendToClients(terrData, x, y); 858 {
804 shouldTaint = true; 859 // Found a patch that was modified. Push this flag into the clients.
860 SendToClients(terrData, x, y);
861 shouldTaint = true;
862 }
805 } 863 }
806 } 864 }
807 }
808 865
809 // This event also causes changes to be sent to the clients 866 // This event also causes changes to be sent to the clients
810 CheckSendingPatchesToClients(); 867 CheckSendingPatchesToClients();
811 868
812 // If things changes, generate some events 869 // If things changes, generate some events
813 if (shouldTaint) 870 if (shouldTaint)
814 { 871 {
815 m_scene.EventManager.TriggerTerrainTainted(); 872 m_scene.EventManager.TriggerTerrainTainted();
816 m_tainted = true; 873 m_tainted = true;
874 }
875 Monitor.Exit(TerrainCheckUpdatesLock);
817 } 876 }
818 } 877 }
819 878
@@ -883,8 +942,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
883 presence.ControllingClient.OnLandUndo -= client_OnLandUndo; 942 presence.ControllingClient.OnLandUndo -= client_OnLandUndo;
884 presence.ControllingClient.OnUnackedTerrain -= client_OnUnackedTerrain; 943 presence.ControllingClient.OnUnackedTerrain -= client_OnUnackedTerrain;
885 } 944 }
886 945 lock (m_perClientPatchUpdates)
887 lock(m_perClientPatchUpdates)
888 m_perClientPatchUpdates.Remove(client); 946 m_perClientPatchUpdates.Remove(client);
889 } 947 }
890 948
@@ -898,12 +956,33 @@ namespace OpenSim.Region.CoreModules.World.Terrain
898 TerrainData terrData = m_channel.GetTerrainData(); 956 TerrainData terrData = m_channel.GetTerrainData();
899 957
900 bool wasLimited = false; 958 bool wasLimited = false;
901 for(int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) 959 for (int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize)
902 { 960 {
903 for(int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) 961 for (int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize)
904 { 962 {
905 if (terrData.IsTaintedAt(x, y, false /* clearOnTest */)) 963 if (terrData.IsTaintedAt(x, y, false /* clearOnTest */))
906 { 964 {
965 // If we should respect the estate settings then
966 // fixup and height deltas that don't respect them.
967 // Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values.
968 wasLimited |= LimitChannelChanges(terrData, x, y);
969 }
970 }
971 }
972 return wasLimited;
973 }
974
975 private bool EnforceEstateLimits(int startX, int startY, int endX, int endY)
976 {
977 TerrainData terrData = m_channel.GetTerrainData();
978
979 bool wasLimited = false;
980 for (int x = startX; x <= endX; x += Constants.TerrainPatchSize)
981 {
982 for (int y = startX; y <= endY; y += Constants.TerrainPatchSize)
983 {
984 if (terrData.IsTaintedAt(x, y, false /* clearOnTest */))
985 {
907 // If we should respect the estate settings then 986 // If we should respect the estate settings then
908 // fixup and height deltas that don't respect them. 987 // fixup and height deltas that don't respect them.
909 // Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values. 988 // Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values.
@@ -926,13 +1005,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain
926 float maxDelta = (float)m_scene.RegionInfo.RegionSettings.TerrainRaiseLimit; 1005 float maxDelta = (float)m_scene.RegionInfo.RegionSettings.TerrainRaiseLimit;
927 1006
928 // loop through the height map for this patch and compare it against 1007 // loop through the height map for this patch and compare it against
929 // the revert map 1008 // the baked map
930 for(int x = xStart; x < xStart + Constants.TerrainPatchSize; x++) 1009 for (int x = xStart; x < xStart + Constants.TerrainPatchSize; x++)
931 { 1010 {
932 for(int y = yStart; y < yStart + Constants.TerrainPatchSize; y++) 1011 for(int y = yStart; y < yStart + Constants.TerrainPatchSize; y++)
933 { 1012 {
934 float requestedHeight = terrData[x, y]; 1013 float requestedHeight = terrData[x, y];
935 float bakedHeight = (float)m_revert[x, y]; 1014 float bakedHeight = (float)m_baked[x, y];
936 float requestedDelta = requestedHeight - bakedHeight; 1015 float requestedDelta = requestedHeight - bakedHeight;
937 1016
938 if (requestedDelta > maxDelta) 1017 if (requestedDelta > maxDelta)
@@ -953,15 +1032,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
953 1032
954 private void client_OnLandUndo(IClientAPI client) 1033 private void client_OnLandUndo(IClientAPI client)
955 { 1034 {
956 lock(m_undo)
957 {
958 if (m_undo.Count > 0)
959 {
960 LandUndoState goback = m_undo.Pop();
961 if (goback != null)
962 goback.PlaybackState();
963 }
964 }
965 } 1035 }
966 1036
967 /// <summary> 1037 /// <summary>
@@ -975,19 +1045,19 @@ namespace OpenSim.Region.CoreModules.World.Terrain
975 if (m_sendTerrainUpdatesByViewDistance) 1045 if (m_sendTerrainUpdatesByViewDistance)
976 { 1046 {
977 // Add that this patch needs to be sent to the accounting for each client. 1047 // Add that this patch needs to be sent to the accounting for each client.
978 lock(m_perClientPatchUpdates) 1048 lock (m_perClientPatchUpdates)
979 { 1049 {
980 m_scene.ForEachScenePresence(presence => 1050 m_scene.ForEachScenePresence(presence =>
981 {
982 PatchUpdates thisClientUpdates;
983 if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates))
984 { 1051 {
985 // There is a ScenePresence without a send patch map. Create one. 1052 PatchUpdates thisClientUpdates;
986 thisClientUpdates = new PatchUpdates(terrData, presence); 1053 if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates))
987 m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates); 1054 {
1055 // There is a ScenePresence without a send patch map. Create one.
1056 thisClientUpdates = new PatchUpdates(terrData, presence);
1057 m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates);
1058 }
1059 thisClientUpdates.SetByXY(x, y, true);
988 } 1060 }
989 thisClientUpdates.SetByXY(x, y, true);
990 }
991 ); 1061 );
992 } 1062 }
993 } 1063 }
@@ -998,7 +1068,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
998 //float[] heightMap = terrData.GetFloatsSerialized(); 1068 //float[] heightMap = terrData.GetFloatsSerialized();
999 float[] heightMap = new float[10]; 1069 float[] heightMap = new float[10];
1000 m_scene.ForEachClient( 1070 m_scene.ForEachClient(
1001 delegate(IClientAPI controller) 1071 delegate (IClientAPI controller)
1002 { 1072 {
1003 controller.SendLayerData(x / Constants.TerrainPatchSize, 1073 controller.SendLayerData(x / Constants.TerrainPatchSize,
1004 y / Constants.TerrainPatchSize, 1074 y / Constants.TerrainPatchSize,
@@ -1013,14 +1083,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1013 public int PatchX; 1083 public int PatchX;
1014 public int PatchY; 1084 public int PatchY;
1015 public float Dist; 1085 public float Dist;
1016
1017 public PatchesToSend(int pX, int pY, float pDist) 1086 public PatchesToSend(int pX, int pY, float pDist)
1018 { 1087 {
1019 PatchX = pX; 1088 PatchX = pX;
1020 PatchY = pY; 1089 PatchY = pY;
1021 Dist = pDist; 1090 Dist = pDist;
1022 } 1091 }
1023
1024 public int CompareTo(PatchesToSend other) 1092 public int CompareTo(PatchesToSend other)
1025 { 1093 {
1026 return Dist.CompareTo(other.Dist); 1094 return Dist.CompareTo(other.Dist);
@@ -1029,113 +1097,216 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1029 1097
1030 // Called each frame time to see if there are any patches to send to any of the 1098 // Called each frame time to see if there are any patches to send to any of the
1031 // ScenePresences. 1099 // 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. 1100 // Loop through all the per-client info and send any patches necessary.
1035 private void CheckSendingPatchesToClients() 1101 private void CheckSendingPatchesToClients()
1036 { 1102 {
1037 lock(m_perClientPatchUpdates) 1103 lock (m_perClientPatchUpdates)
1038 { 1104 {
1039 foreach(PatchUpdates pups in m_perClientPatchUpdates.Values) 1105 foreach (PatchUpdates pups in m_perClientPatchUpdates.Values)
1040 { 1106 {
1107 if(pups.Presence.IsDeleted)
1108 continue;
1109
1110 // limit rate acording to udp land queue state
1111 if (!pups.Presence.ControllingClient.CanSendLayerData())
1112 continue;
1113
1041 if (pups.HasUpdates()) 1114 if (pups.HasUpdates())
1042 { 1115 {
1043 // There is something that could be sent to this client. 1116 if (m_sendTerrainUpdatesByViewDistance)
1044 List<PatchesToSend> toSend = GetModifiedPatchesInViewDistance(pups);
1045 if (toSend.Count > 0)
1046 { 1117 {
1047 // m_log.DebugFormat("{0} CheckSendingPatchesToClient: sending {1} patches to {2} in region {3}", 1118 // There is something that could be sent to this client.
1048 // LogHeader, toSend.Count, pups.Presence.Name, m_scene.RegionInfo.RegionName); 1119 List<PatchesToSend> toSend = GetModifiedPatchesInViewDistance(pups);
1049 // Sort the patches to send by the distance from the presence 1120 if (toSend.Count > 0)
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 { 1121 {
1066 patchPieces[pieceIndex++] = pts.PatchX; 1122 // m_log.DebugFormat("{0} CheckSendingPatchesToClient: sending {1} patches to {2} in region {3}",
1067 patchPieces[pieceIndex++] = pts.PatchY; 1123 // LogHeader, toSend.Count, pups.Presence.Name, m_scene.RegionInfo.RegionName);
1124 // Sort the patches to send by the distance from the presence
1125 toSend.Sort();
1126 /*
1127 foreach (PatchesToSend pts in toSend)
1128 {
1129 pups.Presence.ControllingClient.SendLayerData(pts.PatchX, pts.PatchY, null);
1130 // presence.ControllingClient.SendLayerData(xs.ToArray(), ys.ToArray(), null, TerrainPatch.LayerType.Land);
1131 }
1132 */
1133
1134 float[] patchPieces = new float[toSend.Count * 2];
1135 int pieceIndex = 0;
1136 foreach (PatchesToSend pts in toSend)
1137 {
1138 patchPieces[pieceIndex++] = pts.PatchX;
1139 patchPieces[pieceIndex++] = pts.PatchY;
1140 }
1141 pups.Presence.ControllingClient.SendLayerData(-toSend.Count, 0, patchPieces);
1068 } 1142 }
1069 pups.Presence.ControllingClient.SendLayerData(-toSend.Count, 0, patchPieces); 1143 if (pups.sendAll && toSend.Count < 1024)
1144 SendAllModifiedPatchs(pups);
1145 }
1146 else
1147 SendAllModifiedPatchs(pups);
1148 }
1149 }
1150 }
1151 }
1152 private void SendAllModifiedPatchs(PatchUpdates pups)
1153 {
1154 if (!pups.sendAll) // sanity
1155 return;
1156
1157 int limitX = (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize;
1158 int limitY = (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize;
1159
1160 if (pups.sendAllcurrentX >= limitX && pups.sendAllcurrentY >= limitY)
1161 {
1162 pups.sendAll = false;
1163 pups.sendAllcurrentX = 0;
1164 pups.sendAllcurrentY = 0;
1165 return;
1166 }
1167
1168 int npatchs = 0;
1169 List<PatchesToSend> patchs = new List<PatchesToSend>();
1170 int x = pups.sendAllcurrentX;
1171 int y = pups.sendAllcurrentY;
1172 // send it in the order viewer draws it
1173 // even if not best for memory scan
1174 for (; y < limitY; y++)
1175 {
1176 for (; x < limitX; x++)
1177 {
1178 if (pups.GetByPatch(x, y))
1179 {
1180 pups.SetByPatch(x, y, false);
1181 patchs.Add(new PatchesToSend(x, y, 0));
1182 if (++npatchs >= 128)
1183 {
1184 x++;
1185 break;
1070 } 1186 }
1071 } 1187 }
1072 } 1188 }
1189 if (npatchs >= 128)
1190 break;
1191 x = 0;
1192 }
1193
1194 if (x >= limitX && y >= limitY)
1195 {
1196 pups.sendAll = false;
1197 pups.sendAllcurrentX = 0;
1198 pups.sendAllcurrentY = 0;
1199 }
1200 else
1201 {
1202 pups.sendAllcurrentX = x;
1203 pups.sendAllcurrentY = y;
1204 }
1205
1206 npatchs = patchs.Count;
1207 if (npatchs > 0)
1208 {
1209 int[] xPieces = new int[npatchs];
1210 int[] yPieces = new int[npatchs];
1211 float[] patchPieces = new float[npatchs * 2];
1212 int pieceIndex = 0;
1213 foreach (PatchesToSend pts in patchs)
1214 {
1215 patchPieces[pieceIndex++] = pts.PatchX;
1216 patchPieces[pieceIndex++] = pts.PatchY;
1217 }
1218 pups.Presence.ControllingClient.SendLayerData(-npatchs, 0, patchPieces);
1073 } 1219 }
1074 } 1220 }
1075 1221
1076 // Compute a list of modified patches that are within our view distance.
1077 private List<PatchesToSend> GetModifiedPatchesInViewDistance(PatchUpdates pups) 1222 private List<PatchesToSend> GetModifiedPatchesInViewDistance(PatchUpdates pups)
1078 { 1223 {
1079 List<PatchesToSend> ret = new List<PatchesToSend>(); 1224 List<PatchesToSend> ret = new List<PatchesToSend>();
1080 1225
1226 int npatchs = 0;
1227
1081 ScenePresence presence = pups.Presence; 1228 ScenePresence presence = pups.Presence;
1082 if (presence == null) 1229 if (presence == null)
1083 return ret; 1230 return ret;
1084 1231
1085 Vector3 presencePos = presence.AbsolutePosition; 1232 float minz = presence.AbsolutePosition.Z;
1086 1233 if (presence.CameraPosition.Z < minz)
1087 // Before this distance check, the whole region just showed up. Adding the distance 1234 minz = presence.CameraPosition.Z;
1088 // check causes different things to happen for the current and adjacent regions. 1235
1089 // So, to keep legacy views, if the region is legacy sized, don't do distance check. 1236 // this limit should be max terrainheight + max draw
1090 bool isLegacySizedRegion = pups.Terrain.SizeX == Constants.RegionSize && pups.Terrain.SizeY == Constants.RegionSize; 1237 if (minz > 1500f)
1091 bool shouldCheckViewDistance = m_sendTerrainUpdatesByViewDistance && !isLegacySizedRegion; 1238 return ret;
1092 1239
1093 int startX = 0; 1240 int DrawDistance = (int)presence.DrawDistance;
1094 int endX = (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize; 1241
1095 int startY = 0; 1242 DrawDistance = DrawDistance / Constants.TerrainPatchSize;
1096 int endY = (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize; 1243
1097 1244 int testposX;
1098 // The following only reduces the size of area scanned for updates. Only significant for very large varregions. 1245 int testposY;
1099 if (shouldCheckViewDistance) 1246
1100 { 1247 if (Math.Abs(presence.AbsolutePosition.X - presence.CameraPosition.X) > 30
1101 // Compute the area of patches within our draw distance 1248 || Math.Abs(presence.AbsolutePosition.Y - presence.CameraPosition.Y) > 30)
1102 startX = (((int)(presencePos.X - presence.DrawDistance)) / Constants.TerrainPatchSize) - 2; 1249 {
1103 startX = Math.Max(startX, 0); 1250 testposX = (int)presence.CameraPosition.X / Constants.TerrainPatchSize;
1104 startX = Math.Min(startX, (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize); 1251 testposY = (int)presence.CameraPosition.Y / Constants.TerrainPatchSize;
1105 startY = (((int)(presencePos.Y - presence.DrawDistance)) / Constants.TerrainPatchSize) - 2; 1252 }
1106 startY = Math.Max(startY, 0); 1253 else
1107 startY = Math.Min(startY, (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize); 1254 {
1108 endX = (((int)(presencePos.X + presence.DrawDistance)) / Constants.TerrainPatchSize) + 2; 1255 testposX = (int)presence.AbsolutePosition.X / Constants.TerrainPatchSize;
1109 endX = Math.Max(endX, 0); 1256 testposY = (int)presence.AbsolutePosition.Y / Constants.TerrainPatchSize;
1110 endX = Math.Min(endX, (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize); 1257 }
1111 endY = (((int)(presencePos.Y + presence.DrawDistance)) / Constants.TerrainPatchSize) + 2; 1258 int limitX = (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize;
1112 endY = Math.Max(endY, 0); 1259 int limitY = (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize;
1113 endY = Math.Min(endY, (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize); 1260
1114 } 1261 // Compute the area of patches within our draw distance
1115 1262 int startX = testposX - DrawDistance;
1116 // m_log.DebugFormat("{0} GetModifiedPatchesInViewDistance. rName={1}, ddist={2}, apos={3}, cpos={4}, isChild={5}, start=<{6},{7}>, end=<{8},{9}>", 1263 if (startX < 0)
1117 // LogHeader, m_scene.RegionInfo.RegionName, 1264 startX = 0;
1118 // presence.DrawDistance, presencePos, presence.CameraPosition, 1265 else if (startX >= limitX)
1119 // isLegacySizeChildRegion, 1266 startX = limitX - 1;
1120 // startX, startY, endX, endY); 1267
1121 for(int x = startX; x < endX; x++) 1268 int startY = testposY - DrawDistance;
1122 { 1269 if (startY < 0)
1123 for(int y = startY; y < endY; y++) 1270 startY = 0;
1271 else if (startY >= limitY)
1272 startY = limitY - 1;
1273
1274 int endX = testposX + DrawDistance;
1275 if (endX < 0)
1276 endX = 0;
1277 else if (endX > limitX)
1278 endX = limitX;
1279
1280 int endY = testposY + DrawDistance;
1281 if (endY < 0)
1282 endY = 0;
1283 else if (endY > limitY)
1284 endY = limitY;
1285
1286 int distx;
1287 int disty;
1288 int distsq;
1289
1290 DrawDistance *= DrawDistance;
1291
1292 for (int x = startX; x < endX; x++)
1293 {
1294 for (int y = startY; y < endY; y++)
1124 { 1295 {
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)) 1296 if (pups.GetByPatch(x, y))
1128 { 1297 {
1129 //Check which has less distance, camera or avatar position, both have to be done. 1298 distx = x - testposX;
1130 //Its not a radius, its a diameter and we add 50 so that it doesn't look like it cuts off 1299 disty = y - testposY;
1131 if (!shouldCheckViewDistance 1300 distsq = distx * distx + disty * disty;
1132 || Util.DistanceLessThan(presencePos, patchPos, presence.DrawDistance + 50) 1301 if (distsq < DrawDistance)
1133 || Util.DistanceLessThan(presence.CameraPosition, patchPos, presence.DrawDistance + 50))
1134 { 1302 {
1135 //They can see it, send it to them
1136 pups.SetByPatch(x, y, false); 1303 pups.SetByPatch(x, y, false);
1137 float dist = Vector3.DistanceSquared(presencePos, patchPos); 1304 ret.Add(new PatchesToSend(x, y, (float)distsq));
1138 ret.Add(new PatchesToSend(x, y, dist)); 1305 if (npatchs++ > 1024)
1306 {
1307 y = endY;
1308 x = endX;
1309 }
1139 } 1310 }
1140 } 1311 }
1141 } 1312 }
@@ -1161,33 +1332,44 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1161 int zx = (int)(west + 0.5); 1332 int zx = (int)(west + 0.5);
1162 int zy = (int)(north + 0.5); 1333 int zy = (int)(north + 0.5);
1163 1334
1164 int dx; 1335 int startX = zx - n;
1165 for(dx=-n; dx<=n; dx++) 1336 if (startX < 0)
1337 startX = 0;
1338
1339 int startY = zy - n;
1340 if (startY < 0)
1341 startY = 0;
1342
1343 int endX = zx + n;
1344 if (endX >= m_channel.Width)
1345 endX = m_channel.Width - 1;
1346 int endY = zy + n;
1347 if (endY >= m_channel.Height)
1348 endY = m_channel.Height - 1;
1349
1350 int x, y;
1351
1352 for (x = startX; x <= endX; x++)
1166 { 1353 {
1167 int dy; 1354 for (y = startY; y <= endY; y++)
1168 for(dy=-n; dy<=n; dy++)
1169 { 1355 {
1170 int x = zx + dx; 1356 if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0)))
1171 int y = zy + dy;
1172 if (x >= 0 && y >= 0 && x < m_channel.Width && y < m_channel.Height)
1173 { 1357 {
1174 if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0))) 1358 allowMask[x, y] = true;
1175 { 1359 allowed = true;
1176 allowMask[x, y] = true;
1177 allowed = true;
1178 }
1179 } 1360 }
1180 } 1361 }
1181 } 1362 }
1182 if (allowed) 1363 if (allowed)
1183 { 1364 {
1184 StoreUndoState(); 1365 StoreUndoState();
1185 m_painteffects[(StandardTerrainEffects)action].PaintEffect( 1366 m_painteffects[(StandardTerrainEffects) action].PaintEffect(
1186 m_channel, allowMask, west, south, height, size, seconds); 1367 m_channel, allowMask, west, south, height, size, seconds,
1368 startX, endX, startY, endY);
1187 1369
1188 //revert changes outside estate limits 1370 //block changes outside estate limits
1189 if (!god) 1371 if (!god)
1190 EnforceEstateLimits(); 1372 EnforceEstateLimits(startX, endX, startY, endY);
1191 } 1373 }
1192 } 1374 }
1193 else 1375 else
@@ -1202,22 +1384,42 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1202 bool[,] fillArea = new bool[m_channel.Width, m_channel.Height]; 1384 bool[,] fillArea = new bool[m_channel.Width, m_channel.Height];
1203 fillArea.Initialize(); 1385 fillArea.Initialize();
1204 1386
1205 int x; 1387 int startX = (int)west;
1206 for(x = 0; x < m_channel.Width; x++) 1388 int startY = (int)south;
1389 int endX = (int)east;
1390 int endY = (int)north;
1391
1392 if (startX < 0)
1393 startX = 0;
1394 else if (startX >= m_channel.Width)
1395 startX = m_channel.Width - 1;
1396
1397 if (endX < 0)
1398 endX = 0;
1399 else if (endX >= m_channel.Width)
1400 endX = m_channel.Width - 1;
1401
1402 if (startY < 0)
1403 startY = 0;
1404 else if (startY >= m_channel.Height)
1405 startY = m_channel.Height - 1;
1406
1407 if (endY < 0)
1408 endY = 0;
1409 else if (endY >= m_channel.Height)
1410 endY = m_channel.Height - 1;
1411
1412
1413 int x, y;
1414
1415 for (x = startX; x <= endX; x++)
1207 { 1416 {
1208 int y; 1417 for (y = startY; y <= endY; y++)
1209 for(y = 0; y < m_channel.Height; y++)
1210 { 1418 {
1211 if (x < east && x > west) 1419 if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0)))
1212 { 1420 {
1213 if (y < north && y > south) 1421 fillArea[x, y] = true;
1214 { 1422 allowed = true;
1215 if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0)))
1216 {
1217 fillArea[x, y] = true;
1218 allowed = true;
1219 }
1220 }
1221 } 1423 }
1222 } 1424 }
1223 } 1425 }
@@ -1225,11 +1427,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1225 if (allowed) 1427 if (allowed)
1226 { 1428 {
1227 StoreUndoState(); 1429 StoreUndoState();
1228 m_floodeffects[(StandardTerrainEffects)action].FloodEffect(m_channel, fillArea, size); 1430 m_floodeffects[(StandardTerrainEffects)action].FloodEffect(m_channel, fillArea, size,
1431 startX, endX, startY, endY);
1229 1432
1230 //revert changes outside estate limits 1433 //block changes outside estate limits
1231 if (!god) 1434 if (!god)
1232 EnforceEstateLimits(); 1435 EnforceEstateLimits(startX, endX, startY, endY);
1233 } 1436 }
1234 } 1437 }
1235 else 1438 else
@@ -1260,37 +1463,22 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1260 1463
1261 private void StoreUndoState() 1464 private void StoreUndoState()
1262 { 1465 {
1263 lock(m_undo)
1264 {
1265 if (m_undo.Count > 0)
1266 {
1267 LandUndoState last = m_undo.Peek();
1268 if (last != null)
1269 {
1270 if (last.Compare(m_channel))
1271 return;
1272 }
1273 }
1274
1275 LandUndoState nUndo = new LandUndoState(this, m_channel);
1276 m_undo.Push(nUndo);
1277 }
1278 } 1466 }
1279 1467
1280 #region Console Commands 1468 #region Console Commands
1281 1469
1282 private void InterfaceLoadFile(Object[] args) 1470 private void InterfaceLoadFile(Object[] args)
1283 { 1471 {
1284 LoadFromFile((string)args[0]); 1472 LoadFromFile((string) args[0]);
1285 } 1473 }
1286 1474
1287 private void InterfaceLoadTileFile(Object[] args) 1475 private void InterfaceLoadTileFile(Object[] args)
1288 { 1476 {
1289 LoadFromFile((string)args[0], 1477 LoadFromFile((string) args[0],
1290 (int)args[1], 1478 (int) args[1],
1291 (int)args[2], 1479 (int) args[2],
1292 (int)args[3], 1480 (int) args[3],
1293 (int)args[4]); 1481 (int) args[4]);
1294 } 1482 }
1295 1483
1296 private void InterfaceSaveFile(Object[] args) 1484 private void InterfaceSaveFile(Object[] args)
@@ -1309,15 +1497,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1309 1497
1310 private void InterfaceBakeTerrain(Object[] args) 1498 private void InterfaceBakeTerrain(Object[] args)
1311 { 1499 {
1312 UpdateRevertMap(); 1500 UpdateBakedMap();
1313 } 1501 }
1314 1502
1315 private void InterfaceRevertTerrain(Object[] args) 1503 private void InterfaceRevertTerrain(Object[] args)
1316 { 1504 {
1317 int x, y; 1505 int x, y;
1318 for(x = 0; x < m_channel.Width; x++) 1506 for (x = 0; x < m_channel.Width; x++)
1319 for(y = 0; y < m_channel.Height; y++) 1507 for (y = 0; y < m_channel.Height; y++)
1320 m_channel[x, y] = m_revert[x, y]; 1508 m_channel[x, y] = m_baked[x, y];
1321 1509
1322 } 1510 }
1323 1511
@@ -1327,9 +1515,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1327 1515
1328 if (direction.ToLower().StartsWith("y")) 1516 if (direction.ToLower().StartsWith("y"))
1329 { 1517 {
1330 for(int x = 0; x < m_channel.Width; x++) 1518 for (int x = 0; x < m_channel.Width; x++)
1331 { 1519 {
1332 for(int y = 0; y < m_channel.Height / 2; y++) 1520 for (int y = 0; y < m_channel.Height / 2; y++)
1333 { 1521 {
1334 double height = m_channel[x, y]; 1522 double height = m_channel[x, y];
1335 double flippedHeight = m_channel[x, (int)m_channel.Height - 1 - y]; 1523 double flippedHeight = m_channel[x, (int)m_channel.Height - 1 - y];
@@ -1341,9 +1529,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1341 } 1529 }
1342 else if (direction.ToLower().StartsWith("x")) 1530 else if (direction.ToLower().StartsWith("x"))
1343 { 1531 {
1344 for(int y = 0; y < m_channel.Height; y++) 1532 for (int y = 0; y < m_channel.Height; y++)
1345 { 1533 {
1346 for(int x = 0; x < m_channel.Width / 2; x++) 1534 for (int x = 0; x < m_channel.Width / 2; x++)
1347 { 1535 {
1348 double height = m_channel[x, y]; 1536 double height = m_channel[x, y];
1349 double flippedHeight = m_channel[(int)m_channel.Width - 1 - x, y]; 1537 double flippedHeight = m_channel[(int)m_channel.Width - 1 - x, y];
@@ -1415,50 +1603,57 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1415 } 1603 }
1416 1604
1417 } 1605 }
1418
1419 } 1606 }
1420 1607
1421 private void InterfaceElevateTerrain(Object[] args) 1608 private void InterfaceElevateTerrain(Object[] args)
1422 { 1609 {
1610 double val = (double)args[0];
1611
1423 int x, y; 1612 int x, y;
1424 for(x = 0; x < m_channel.Width; x++) 1613 for (x = 0; x < m_channel.Width; x++)
1425 for(y = 0; y < m_channel.Height; y++) 1614 for (y = 0; y < m_channel.Height; y++)
1426 m_channel[x, y] += (double)args[0]; 1615 m_channel[x, y] += val;
1427 } 1616 }
1428 1617
1429 private void InterfaceMultiplyTerrain(Object[] args) 1618 private void InterfaceMultiplyTerrain(Object[] args)
1430 { 1619 {
1431 int x, y; 1620 int x, y;
1432 for(x = 0; x < m_channel.Width; x++) 1621 double val = (double)args[0];
1433 for(y = 0; y < m_channel.Height; y++) 1622
1434 m_channel[x, y] *= (double)args[0]; 1623 for (x = 0; x < m_channel.Width; x++)
1624 for (y = 0; y < m_channel.Height; y++)
1625 m_channel[x, y] *= val;
1435 } 1626 }
1436 1627
1437 private void InterfaceLowerTerrain(Object[] args) 1628 private void InterfaceLowerTerrain(Object[] args)
1438 { 1629 {
1439 int x, y; 1630 int x, y;
1440 for(x = 0; x < m_channel.Width; x++) 1631 double val = (double)args[0];
1441 for(y = 0; y < m_channel.Height; y++) 1632
1442 m_channel[x, y] -= (double)args[0]; 1633 for (x = 0; x < m_channel.Width; x++)
1634 for (y = 0; y < m_channel.Height; y++)
1635 m_channel[x, y] -= val;
1443 } 1636 }
1444 1637
1445 public void InterfaceFillTerrain(Object[] args) 1638 public void InterfaceFillTerrain(Object[] args)
1446 { 1639 {
1447 int x, y; 1640 int x, y;
1641 double val = (double)args[0];
1448 1642
1449 for(x = 0; x < m_channel.Width; x++) 1643 for (x = 0; x < m_channel.Width; x++)
1450 for(y = 0; y < m_channel.Height; y++) 1644 for (y = 0; y < m_channel.Height; y++)
1451 m_channel[x, y] = (double)args[0]; 1645 m_channel[x, y] = val;
1452 } 1646 }
1453 1647
1454 private void InterfaceMinTerrain(Object[] args) 1648 private void InterfaceMinTerrain(Object[] args)
1455 { 1649 {
1456 int x, y; 1650 int x, y;
1457 for(x = 0; x < m_channel.Width; x++) 1651 double val = (double)args[0];
1652 for (x = 0; x < m_channel.Width; x++)
1458 { 1653 {
1459 for(y = 0; y < m_channel.Height; y++) 1654 for(y = 0; y < m_channel.Height; y++)
1460 { 1655 {
1461 m_channel[x, y] = Math.Max((double)args[0], m_channel[x, y]); 1656 m_channel[x, y] = Math.Max(val, m_channel[x, y]);
1462 } 1657 }
1463 } 1658 }
1464 } 1659 }
@@ -1466,11 +1661,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1466 private void InterfaceMaxTerrain(Object[] args) 1661 private void InterfaceMaxTerrain(Object[] args)
1467 { 1662 {
1468 int x, y; 1663 int x, y;
1469 for(x = 0; x < m_channel.Width; x++) 1664 double val = (double)args[0];
1665 for (x = 0; x < m_channel.Width; x++)
1470 { 1666 {
1471 for(y = 0; y < m_channel.Height; y++) 1667 for(y = 0; y < m_channel.Height; y++)
1472 { 1668 {
1473 m_channel[x, y] = Math.Min((double)args[0], m_channel[x, y]); 1669 m_channel[x, y] = Math.Min(val, m_channel[x, y]);
1474 } 1670 }
1475 } 1671 }
1476 } 1672 }
@@ -1620,9 +1816,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1620 multiplyCommand.AddArgument("value", "The value to multiply the heightmap by.", "Double"); 1816 multiplyCommand.AddArgument("value", "The value to multiply the heightmap by.", "Double");
1621 1817
1622 Command bakeRegionCommand = 1818 Command bakeRegionCommand =
1623 new Command("bake", CommandIntentions.COMMAND_HAZARDOUS, InterfaceBakeTerrain, "Saves the current terrain into the regions revert map."); 1819 new Command("bake", CommandIntentions.COMMAND_HAZARDOUS, InterfaceBakeTerrain, "Saves the current terrain into the regions baked map.");
1624 Command revertRegionCommand = 1820 Command revertRegionCommand =
1625 new Command("revert", CommandIntentions.COMMAND_HAZARDOUS, InterfaceRevertTerrain, "Loads the revert map terrain into the regions heightmap."); 1821 new Command("revert", CommandIntentions.COMMAND_HAZARDOUS, InterfaceRevertTerrain, "Loads the baked map terrain into the regions heightmap.");
1626 1822
1627 Command flipCommand = 1823 Command flipCommand =
1628 new Command("flip", CommandIntentions.COMMAND_HAZARDOUS, InterfaceFlipTerrain, "Flips the current terrain about the X or Y axis"); 1824 new Command("flip", CommandIntentions.COMMAND_HAZARDOUS, InterfaceFlipTerrain, "Flips the current terrain about the X or Y axis");