aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/World
diff options
context:
space:
mode:
authorDiva Canto2014-06-01 10:06:59 -0700
committerDiva Canto2014-06-01 10:06:59 -0700
commit0eaca7aafb0365fb21b6d1ce8e1590845a6b5125 (patch)
tree1120139228e2c934de544f3288b306699018bb50 /OpenSim/Region/CoreModules/World
parentFixed a few things pertaining to interfacing with the estate service. Specifi... (diff)
parentMove the generation of the multi-resolution map tiles off the main (diff)
downloadopensim-SC_OLD-0eaca7aafb0365fb21b6d1ce8e1590845a6b5125.zip
opensim-SC_OLD-0eaca7aafb0365fb21b6d1ce8e1590845a6b5125.tar.gz
opensim-SC_OLD-0eaca7aafb0365fb21b6d1ce8e1590845a6b5125.tar.bz2
opensim-SC_OLD-0eaca7aafb0365fb21b6d1ce8e1590845a6b5125.tar.xz
Merge branch 'master' of ssh://opensimulator.org/var/git/opensim
Diffstat (limited to 'OpenSim/Region/CoreModules/World')
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs295
1 files changed, 262 insertions, 33 deletions
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
index 6e1e8d6..c22c5b6 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
@@ -96,9 +96,88 @@ namespace OpenSim.Region.CoreModules.World.Terrain
96 private Scene m_scene; 96 private Scene m_scene;
97 private volatile bool m_tainted; 97 private volatile bool m_tainted;
98 private readonly Stack<LandUndoState> m_undo = new Stack<LandUndoState>(5); 98 private readonly Stack<LandUndoState> m_undo = new Stack<LandUndoState>(5);
99 99
100 private String m_InitialTerrain = "pinhead-island"; 100 private String m_InitialTerrain = "pinhead-island";
101 101
102 // If true, send terrain patch updates to clients based on their view distance
103 private bool m_sendTerrainUpdatesByViewDistance = false;
104
105 // Class to keep the per client collection of terrain patches that must be sent.
106 // A patch is set to 'true' meaning it should be sent to the client. Once the
107 // patch packet is queued to the client, the bit for that patch is set to 'false'.
108 private class PatchUpdates
109 {
110 private bool[,] updated; // for each patch, whether it needs to be sent to this client
111 private int updateCount; // number of patches that need to be sent
112 public ScenePresence Presence; // a reference to the client to send to
113 public PatchUpdates(TerrainData terrData, ScenePresence pPresence)
114 {
115 updated = new bool[terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize];
116 updateCount = 0;
117 Presence = pPresence;
118 // Initially, send all patches to the client
119 SetAll(true);
120 }
121 // Returns 'true' if there are any patches marked for sending
122 public bool HasUpdates()
123 {
124 return (updateCount > 0);
125 }
126 public void SetByXY(int x, int y, bool state)
127 {
128 this.SetByPatch(x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, state);
129 }
130 public bool GetByPatch(int patchX, int patchY)
131 {
132 return updated[patchX, patchY];
133 }
134 public void SetByPatch(int patchX, int patchY, bool state)
135 {
136 bool prevState = updated[patchX, patchY];
137 if (!prevState && state)
138 updateCount++;
139 if (prevState && !state)
140 updateCount--;
141 updated[patchX, patchY] = state;
142 }
143 public void SetAll(bool state)
144 {
145 updateCount = 0;
146 for (int xx = 0; xx < updated.GetLength(0); xx++)
147 for (int yy = 0; yy < updated.GetLength(1); yy++)
148 updated[xx, yy] = state;
149 if (state)
150 updateCount = updated.GetLength(0) * updated.GetLength(1);
151 }
152 // Logically OR's the terrain data's patch taint map into this client's update map.
153 public void SetAll(TerrainData terrData)
154 {
155 if (updated.GetLength(0) != (terrData.SizeX / Constants.TerrainPatchSize)
156 || updated.GetLength(1) != (terrData.SizeY / Constants.TerrainPatchSize))
157 {
158 throw new Exception(
159 String.Format("{0} PatchUpdates.SetAll: patch array not same size as terrain. arr=<{1},{2}>, terr=<{3},{4}>",
160 LogHeader, updated.GetLength(0), updated.GetLength(1),
161 terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize)
162 );
163 }
164 for (int xx = 0; xx < terrData.SizeX; xx += Constants.TerrainPatchSize)
165 {
166 for (int yy = 0; yy < terrData.SizeY; yy += Constants.TerrainPatchSize)
167 {
168 // Only set tainted. The patch bit may be set if the patch was to be sent later.
169 if (terrData.IsTaintedAt(xx, yy, false))
170 {
171 this.SetByXY(xx, yy, true);
172 }
173 }
174 }
175 }
176 }
177
178 // The flags of which terrain patches to send for each of the ScenePresence's
179 private Dictionary<UUID, PatchUpdates> m_perClientPatchUpdates = new Dictionary<UUID, PatchUpdates>();
180
102 /// <summary> 181 /// <summary>
103 /// Human readable list of terrain file extensions that are supported. 182 /// Human readable list of terrain file extensions that are supported.
104 /// </summary> 183 /// </summary>
@@ -127,7 +206,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
127 { 206 {
128 IConfig terrainConfig = config.Configs["Terrain"]; 207 IConfig terrainConfig = config.Configs["Terrain"];
129 if (terrainConfig != null) 208 if (terrainConfig != null)
209 {
130 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); 210 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain);
211 m_sendTerrainUpdatesByViewDistance = terrainConfig.GetBoolean("SendTerrainUpdatesByViewDistance", m_sendTerrainUpdatesByViewDistance);
212 }
131 } 213 }
132 214
133 public void AddRegion(Scene scene) 215 public void AddRegion(Scene scene)
@@ -422,9 +504,46 @@ namespace OpenSim.Region.CoreModules.World.Terrain
422 } 504 }
423 } 505 }
424 506
507 // Someone diddled terrain outside the normal code paths. Set the taintedness for all clients.
508 // ITerrainModule.TaintTerrain()
425 public void TaintTerrain () 509 public void TaintTerrain ()
426 { 510 {
427 m_channel.GetTerrainData().TaintAllTerrain(); 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 }
519 }
520
521 // ITerrainModule.PushTerrain()
522 public void PushTerrain(IClientAPI pClient)
523 {
524 if (m_sendTerrainUpdatesByViewDistance)
525 {
526 ScenePresence presence = m_scene.GetScenePresence(pClient.AgentId);
527 if (presence != null)
528 {
529 lock (m_perClientPatchUpdates)
530 {
531 PatchUpdates pups;
532 if (!m_perClientPatchUpdates.TryGetValue(pClient.AgentId, out pups))
533 {
534 // There is a ScenePresence without a send patch map. Create one.
535 pups = new PatchUpdates(m_scene.Heightmap.GetTerrainData(), presence);
536 m_perClientPatchUpdates.Add(presence.UUID, pups);
537 }
538 pups.SetAll(true);
539 }
540 }
541 }
542 else
543 {
544 // The traditional way is to call into the protocol stack to send them all.
545 pClient.SendLayerData(new float[10]);
546 }
428 } 547 }
429 548
430 #region Plugin Loading Methods 549 #region Plugin Loading Methods
@@ -676,6 +795,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
676 } 795 }
677 } 796 }
678 } 797 }
798
799 // This event also causes changes to be sent to the clients
800 CheckSendingPatchesToClients();
801
802 // If things changes, generate some events
679 if (shouldTaint) 803 if (shouldTaint)
680 { 804 {
681 m_scene.EventManager.TriggerTerrainTainted(); 805 m_scene.EventManager.TriggerTerrainTainted();
@@ -749,31 +873,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain
749 presence.ControllingClient.OnLandUndo -= client_OnLandUndo; 873 presence.ControllingClient.OnLandUndo -= client_OnLandUndo;
750 presence.ControllingClient.OnUnackedTerrain -= client_OnUnackedTerrain; 874 presence.ControllingClient.OnUnackedTerrain -= client_OnUnackedTerrain;
751 } 875 }
876 if (m_perClientPatchUpdates.ContainsKey(client))
877 {
878 m_perClientPatchUpdates.Remove(client);
879 }
752 } 880 }
753 881
754 /// <summary> 882 /// <summary>
755 /// Checks to see if the terrain has been modified since last check
756 /// but won't attempt to limit those changes to the limits specified in the estate settings
757 /// currently invoked by the command line operations in the region server only
758 /// </summary>
759 private void CheckForTerrainUpdates()
760 {
761 CheckForTerrainUpdates(false);
762 }
763
764 /// <summary>
765 /// Checks to see if the terrain has been modified since last check.
766 /// If it has been modified, every all the terrain patches are sent to the client.
767 /// If the call is asked to respect the estate settings for terrain_raise_limit and
768 /// terrain_lower_limit, it will clamp terrain updates between these values
769 /// currently invoked by client_OnModifyTerrain only and not the Commander interfaces
770 /// <param name="respectEstateSettings">should height map deltas be limited to the estate settings limits</param>
771 /// </summary>
772 private void CheckForTerrainUpdates(bool respectEstateSettings)
773 {
774 }
775
776 /// <summary>
777 /// Scan over changes in the terrain and limit height changes. This enforces the 883 /// Scan over changes in the terrain and limit height changes. This enforces the
778 /// non-estate owner limits on rate of terrain editting. 884 /// non-estate owner limits on rate of terrain editting.
779 /// Returns 'true' if any heights were limited. 885 /// Returns 'true' if any heights were limited.
@@ -857,17 +963,140 @@ namespace OpenSim.Region.CoreModules.World.Terrain
857 /// <param name="y">The patch corner to send</param> 963 /// <param name="y">The patch corner to send</param>
858 private void SendToClients(TerrainData terrData, int x, int y) 964 private void SendToClients(TerrainData terrData, int x, int y)
859 { 965 {
860 // We know the actual terrain data passed is ignored. This kludge saves changing IClientAPI. 966 if (m_sendTerrainUpdatesByViewDistance)
861 //float[] heightMap = terrData.GetFloatsSerialized(); 967 {
862 float[] heightMap = new float[10]; 968 // Add that this patch needs to be sent to the accounting for each client.
863 m_scene.ForEachClient( 969 lock (m_perClientPatchUpdates)
864 delegate(IClientAPI controller) 970 {
971 m_scene.ForEachScenePresence(presence =>
972 {
973 PatchUpdates thisClientUpdates;
974 if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates))
975 {
976 // There is a ScenePresence without a send patch map. Create one.
977 thisClientUpdates = new PatchUpdates(terrData, presence);
978 m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates);
979 }
980 thisClientUpdates.SetByXY(x, y, true);
981 }
982 );
983 }
984 }
985 else
986 {
987 // Legacy update sending where the update is sent out as soon as noticed
988 // We know the actual terrain data passed is ignored. This kludge saves changing IClientAPI.
989 //float[] heightMap = terrData.GetFloatsSerialized();
990 float[] heightMap = new float[10];
991 m_scene.ForEachClient(
992 delegate(IClientAPI controller)
865 { 993 {
866 controller.SendLayerData( x / Constants.TerrainPatchSize, 994 controller.SendLayerData(x / Constants.TerrainPatchSize,
867 y / Constants.TerrainPatchSize, 995 y / Constants.TerrainPatchSize,
868 heightMap); 996 heightMap);
869 } 997 }
870 ); 998 );
999 }
1000 }
1001
1002 private class PatchesToSend : IComparable<PatchesToSend>
1003 {
1004 public int PatchX;
1005 public int PatchY;
1006 public float Dist;
1007 public PatchesToSend(int pX, int pY, float pDist)
1008 {
1009 PatchX = pX;
1010 PatchY = pY;
1011 Dist = pDist;
1012 }
1013 public int CompareTo(PatchesToSend other)
1014 {
1015 return Dist.CompareTo(other.Dist);
1016 }
1017 }
1018
1019 // Called each frame time to see if there are any patches to send to any of the
1020 // ScenePresences.
1021 // Loop through all the per-client info and send any patches necessary.
1022 private void CheckSendingPatchesToClients()
1023 {
1024 lock (m_perClientPatchUpdates)
1025 {
1026 foreach (PatchUpdates pups in m_perClientPatchUpdates.Values)
1027 {
1028 if (pups.HasUpdates())
1029 {
1030 // There is something that could be sent to this client.
1031 List<PatchesToSend> toSend = GetModifiedPatchesInViewDistance(pups);
1032 if (toSend.Count > 0)
1033 {
1034 // m_log.DebugFormat("{0} CheckSendingPatchesToClient: sending {1} patches to {2} in region {3}",
1035 // LogHeader, toSend.Count, pups.Presence.Name, m_scene.RegionInfo.RegionName);
1036 // Sort the patches to send by the distance from the presence
1037 toSend.Sort();
1038 foreach (PatchesToSend pts in toSend)
1039 {
1040 // TODO: one can send multiple patches in a packet. Do that.
1041 pups.Presence.ControllingClient.SendLayerData(pts.PatchX, pts.PatchY, null);
1042 // presence.ControllingClient.SendLayerData(xs.ToArray(), ys.ToArray(), null, TerrainPatch.LayerType.Land);
1043 }
1044 }
1045 }
1046 }
1047 }
1048 }
1049
1050 private List<PatchesToSend> GetModifiedPatchesInViewDistance(PatchUpdates pups)
1051 {
1052 List<PatchesToSend> ret = new List<PatchesToSend>();
1053
1054 ScenePresence presence = pups.Presence;
1055 if (presence == null)
1056 return ret;
1057
1058 // Compute the area of patches within our draw distance
1059 int startX = (((int) (presence.AbsolutePosition.X - presence.DrawDistance))/Constants.TerrainPatchSize) - 2;
1060 startX = Math.Max(startX, 0);
1061 startX = Math.Min(startX, (int)m_scene.RegionInfo.RegionSizeX/Constants.TerrainPatchSize);
1062 int startY = (((int) (presence.AbsolutePosition.Y - presence.DrawDistance))/Constants.TerrainPatchSize) - 2;
1063 startY = Math.Max(startY, 0);
1064 startY = Math.Min(startY, (int)m_scene.RegionInfo.RegionSizeY/Constants.TerrainPatchSize);
1065 int endX = (((int) (presence.AbsolutePosition.X + presence.DrawDistance))/Constants.TerrainPatchSize) + 2;
1066 endX = Math.Max(endX, 0);
1067 endX = Math.Min(endX, (int)m_scene.RegionInfo.RegionSizeX/Constants.TerrainPatchSize);
1068 int endY = (((int) (presence.AbsolutePosition.Y + presence.DrawDistance))/Constants.TerrainPatchSize) + 2;
1069 endY = Math.Max(endY, 0);
1070 endY = Math.Min(endY, (int)m_scene.RegionInfo.RegionSizeY/Constants.TerrainPatchSize);
1071 // m_log.DebugFormat("{0} GetModifiedPatchesInViewDistance. rName={1}, ddist={2}, apos={3}, start=<{4},{5}>, end=<{6},{7}>",
1072 // LogHeader, m_scene.RegionInfo.RegionName,
1073 // presence.DrawDistance, presence.AbsolutePosition,
1074 // startX, startY, endX, endY);
1075 for (int x = startX; x < endX; x++)
1076 {
1077 for (int y = startY; y < endY; y++)
1078 {
1079 //Need to make sure we don't send the same ones over and over
1080 Vector3 presencePos = presence.AbsolutePosition;
1081 Vector3 patchPos = new Vector3(x * Constants.TerrainPatchSize, y * Constants.TerrainPatchSize, presencePos.Z);
1082 if (pups.GetByPatch(x, y))
1083 {
1084 //Check which has less distance, camera or avatar position, both have to be done.
1085 //Its not a radius, its a diameter and we add 50 so that it doesn't look like it cuts off
1086 if (Util.DistanceLessThan(presencePos, patchPos, presence.DrawDistance + 50)
1087 || Util.DistanceLessThan(presence.CameraPosition, patchPos, presence.DrawDistance + 50))
1088 {
1089 //They can see it, send it to them
1090 pups.SetByPatch(x, y, false);
1091 float dist = Vector3.DistanceSquared(presencePos, patchPos);
1092 ret.Add(new PatchesToSend(x, y, dist));
1093 //Wait and send them all at once
1094 // pups.client.SendLayerData(x, y, null);
1095 }
1096 }
1097 }
1098 }
1099 return ret;
871 } 1100 }
872 1101
873 private void client_OnModifyTerrain(UUID user, float height, float seconds, byte size, byte action, 1102 private void client_OnModifyTerrain(UUID user, float height, float seconds, byte size, byte action,