aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/LandManagement/LandChannel.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Environment/Modules/LandManagement/LandChannel.cs (renamed from OpenSim/Region/Environment/LandManagement/LandManager.cs)1858
1 files changed, 916 insertions, 942 deletions
diff --git a/OpenSim/Region/Environment/LandManagement/LandManager.cs b/OpenSim/Region/Environment/Modules/LandManagement/LandChannel.cs
index 0b3c5de..ba0c550 100644
--- a/OpenSim/Region/Environment/LandManagement/LandManager.cs
+++ b/OpenSim/Region/Environment/Modules/LandManagement/LandChannel.cs
@@ -1,942 +1,916 @@
1/* 1using System;
2 * Copyright (c) Contributors, http://opensimulator.org/ 2using System.Collections.Generic;
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3using System.Text;
4 * 4
5 * Redistribution and use in source and binary forms, with or without 5using Axiom.Math;
6 * modification, are permitted provided that the following conditions are met: 6using libsecondlife;
7 * * Redistributions of source code must retain the above copyright 7using libsecondlife.Packets;
8 * notice, this list of conditions and the following disclaimer. 8using OpenSim.Framework;
9 * * Redistributions in binary form must reproduce the above copyright 9using OpenSim.Framework.Console;
10 * notice, this list of conditions and the following disclaimer in the 10using OpenSim.Region.Environment.Scenes;
11 * documentation and/or other materials provided with the distribution. 11using OpenSim.Region.Environment.Interfaces;
12 * * Neither the name of the OpenSim Project nor the 12using OpenSim.Region.Physics.Manager;
13 * names of its contributors may be used to endorse or promote products 13
14 * derived from this software without specific prior written permission. 14namespace OpenSim.Region.Environment.Modules.LandManagement
15 * 15{
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 16 public class LandChannel : ILandChannel
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 {
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 #region Constants
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 //Land types set with flags in ParcelOverlay.
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 //Only one of these can be used.
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 public const byte LAND_TYPE_PUBLIC = (byte)0; //Equals 00000000
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 public const byte LAND_TYPE_OWNED_BY_OTHER = (byte)1; //Equals 00000001
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 public const byte LAND_TYPE_OWNED_BY_GROUP = (byte)2; //Equals 00000010
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 public const byte LAND_TYPE_OWNED_BY_REQUESTER = (byte)3; //Equals 00000011
26 */ 26 public const byte LAND_TYPE_IS_FOR_SALE = (byte)4; //Equals 00000100
27 27 public const byte LAND_TYPE_IS_BEING_AUCTIONED = (byte)5; //Equals 00000101
28using System; 28
29using System.Collections.Generic; 29 //Flags that when set, a border on the given side will be placed
30using Axiom.Math; 30 //NOTE: North and East is assumable by the west and south sides (if land to east has a west border, then I have an east border; etc)
31using libsecondlife; 31 //This took forever to figure out -- jeesh. /blame LL for even having to send these
32using libsecondlife.Packets; 32 public const byte LAND_FLAG_PROPERTY_BORDER_WEST = (byte)64; //Equals 01000000
33using OpenSim.Framework; 33 public const byte LAND_FLAG_PROPERTY_BORDER_SOUTH = (byte)128; //Equals 10000000
34using OpenSim.Framework.Console; 34
35using OpenSim.Region.Environment.Scenes; 35 //RequestResults (I think these are right, they seem to work):
36using OpenSim.Region.Environment.Interfaces; 36 public const int LAND_RESULT_SINGLE = 0; // The request they made contained only a single piece of land
37using OpenSim.Region.Physics.Manager; 37 public const int LAND_RESULT_MULTIPLE = 1; // The request they made contained more than a single peice of land
38 38
39namespace OpenSim.Region.Environment.LandManagement 39 //ParcelSelectObjects
40{ 40 public const int LAND_SELECT_OBJECTS_OWNER = 2;
41 #region LandManager Class 41 public const int LAND_SELECT_OBJECTS_GROUP = 4;
42 42 public const int LAND_SELECT_OBJECTS_OTHER = 8;
43 /// <summary> 43
44 /// Handles Land objects and operations requiring information from other Land objects (divide, join, etc) 44 //These are other constants. Yay!
45 /// </summary> 45 public const int START_LAND_LOCAL_ID = 1;
46 public class LandManager 46
47 { 47 public const float BAN_LINE_SAFETY_HIEGHT = 100;
48 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 48
49 49 #endregion
50 #region Constants 50
51 51 private Scene m_scene;
52 //Land types set with flags in ParcelOverlay. 52
53 //Only one of these can be used. 53 private Dictionary<int, ILandObject> landList = new Dictionary<int, ILandObject>();
54 public const byte LAND_TYPE_PUBLIC = (byte) 0; //Equals 00000000 54 private int lastLandLocalID = START_LAND_LOCAL_ID - 1;
55 public const byte LAND_TYPE_OWNED_BY_OTHER = (byte) 1; //Equals 00000001 55 private int[,] landIDList = new int[64, 64];
56 public const byte LAND_TYPE_OWNED_BY_GROUP = (byte) 2; //Equals 00000010 56
57 public const byte LAND_TYPE_OWNED_BY_REQUESTER = (byte) 3; //Equals 00000011 57 private bool landPrimCountTainted = false;
58 public const byte LAND_TYPE_IS_FOR_SALE = (byte) 4; //Equals 00000100 58
59 public const byte LAND_TYPE_IS_BEING_AUCTIONED = (byte) 5; //Equals 00000101 59 private bool m_allowedForcefulBans = true;
60 60 public bool allowedForcefulBans
61 //Flags that when set, a border on the given side will be placed 61 {
62 //NOTE: North and East is assumable by the west and south sides (if land to east has a west border, then I have an east border; etc) 62 get
63 //This took forever to figure out -- jeesh. /blame LL for even having to send these 63 {
64 public const byte LAND_FLAG_PROPERTY_BORDER_WEST = (byte) 64; //Equals 01000000 64 return m_allowedForcefulBans;
65 public const byte LAND_FLAG_PROPERTY_BORDER_SOUTH = (byte) 128; //Equals 10000000 65 }
66 66 set
67 //RequestResults (I think these are right, they seem to work): 67 {
68 public const int LAND_RESULT_SINGLE = 0; // The request they made contained only a single piece of land 68 m_allowedForcefulBans = value;
69 public const int LAND_RESULT_MULTIPLE = 1; // The request they made contained more than a single peice of land 69 }
70 70 }
71 //ParcelSelectObjects 71
72 public const int LAND_SELECT_OBJECTS_OWNER = 2; 72 public LandChannel(Scene scene)
73 public const int LAND_SELECT_OBJECTS_GROUP = 4; 73 {
74 public const int LAND_SELECT_OBJECTS_OTHER = 8; 74 m_scene = scene;
75 75 landIDList.Initialize();
76 //These are other constants. Yay! 76 }
77 public const int START_LAND_LOCAL_ID = 1; 77 #region Land Object From Storage Functions
78 78
79 public const float BAN_LINE_SAFETY_HIEGHT = 100; 79 public void IncomingLandObjectsFromStorage(List<LandData> data)
80 80 {
81 #endregion 81 for (int i = 0; i < data.Count; i++)
82 82 {
83 #region Member Variables 83 //try
84 84 //{
85 public Dictionary<int, Land> landList = new Dictionary<int, Land>(); 85 IncomingLandObjectFromStorage(data[i]);
86 private int lastLandLocalID = START_LAND_LOCAL_ID - 1; 86 //}
87 private int[,] landIDList = new int[64,64]; 87 //catch (Exception ex)
88 88 //{
89 /// <summary> 89 //m_log.Error("[LandManager]: IncomingLandObjectsFromStorage: Exception: " + ex.ToString());
90 /// Set to true when a prim is moved, created, added. Performs a prim count update 90 //throw ex;
91 /// </summary> 91 //}
92 public bool landPrimCountTainted = false; 92 }
93 93 //foreach (LandData parcel in data)
94 private readonly Scene m_scene; 94 //{
95 private readonly RegionInfo m_regInfo; 95 // IncomingLandObjectFromStorage(parcel);
96 96 //}
97 public bool allowedForcefulBans = true; 97 }
98 98
99 #endregion 99 public void IncomingLandObjectFromStorage(LandData data)
100 100 {
101 #region Constructors 101 ILandObject new_land = new LandObject(data.ownerID, data.isGroupOwned, m_scene);
102 102 new_land.landData = data.Copy();
103 public LandManager(Scene scene, RegionInfo reginfo) 103 new_land.setLandBitmapFromByteArray();
104 { 104 addLandObject(new_land);
105 m_scene = scene; 105 }
106 m_regInfo = reginfo; 106
107 landIDList.Initialize(); 107 public void NoLandDataFromStorage()
108 scene.EventManager.OnAvatarEnteringNewParcel += 108 {
109 new EventManager.AvatarEnteringNewParcel(handleAvatarChangingParcel); 109 resetSimLandObjects();
110 scene.EventManager.OnClientMovement += new EventManager.ClientMovement(handleAnyClientMovement); 110 }
111 } 111
112 112 #endregion
113 #endregion 113
114 114 #region Parcel Add/Remove/Get/Create
115 #region Member Functions 115
116 116 /// <summary>
117 #region Land Object From Storage Functions 117 /// Creates a basic Parcel object without an owner (a zeroed key)
118 118 /// </summary>
119 public void IncomingLandObjectsFromStorage(List<LandData> data) 119 /// <returns></returns>
120 { 120 public ILandObject createBaseLand()
121 for (int i = 0; i < data.Count; i++) 121 {
122 { 122 return new LandObject(LLUUID.Zero, false, m_scene);
123 //try 123 }
124 //{ 124
125 IncomingLandObjectFromStorage(data[i]); 125 /// <summary>
126 //} 126 /// Adds a land object to the stored list and adds them to the landIDList to what they own
127 //catch (Exception ex) 127 /// </summary>
128 //{ 128 /// <param name="new_land">The land object being added</param>
129 //m_log.Error("[LandManager]: IncomingLandObjectsFromStorage: Exception: " + ex.ToString()); 129 public ILandObject addLandObject(ILandObject new_land)
130 //throw ex; 130 {
131 //} 131 lastLandLocalID++;
132 } 132 new_land.landData.localID = lastLandLocalID;
133 //foreach (LandData parcel in data) 133 landList.Add(lastLandLocalID, (LandObject)new_land.Copy());
134 //{ 134
135 // IncomingLandObjectFromStorage(parcel); 135
136 //} 136 bool[,] landBitmap = new_land.getLandBitmap();
137 } 137 int x, y;
138 138 for (x = 0; x < 64; x++)
139 public void IncomingLandObjectFromStorage(LandData data) 139 {
140 { 140 for (y = 0; y < 64; y++)
141 Land new_land = new Land(data.ownerID, data.isGroupOwned, m_scene); 141 {
142 new_land.landData = data.Copy(); 142 if (landBitmap[x, y])
143 new_land.setLandBitmapFromByteArray(); 143 {
144 addLandObject(new_land); 144 landIDList[x, y] = lastLandLocalID;
145 } 145 }
146 146 }
147 public void NoLandDataFromStorage() 147 }
148 { 148 landList[lastLandLocalID].forceUpdateLandInfo();
149 Console.WriteLine("No LandData in storage! Loading a single, flat parcel instead"); 149 m_scene.EventManager.TriggerLandObjectAdded(new_land);
150 resetSimLandObjects(); 150 return new_land;
151 } 151 }
152 152
153 #endregion 153 /// <summary>
154 154 /// Removes a land object from the list. Will not remove if local_id is still owning an area in landIDList
155 #region Parcel Add/Remove/Get/Create 155 /// </summary>
156 156 /// <param name="local_id">Land.localID of the peice of land to remove.</param>
157 /// <summary> 157 public void removeLandObject(int local_id)
158 /// Creates a basic Parcel object without an owner (a zeroed key) 158 {
159 /// </summary> 159 int x, y;
160 /// <returns></returns> 160 for (x = 0; x < 64; x++)
161 public Land createBaseLand() 161 {
162 { 162 for (y = 0; y < 64; y++)
163 return new Land(LLUUID.Zero, false, m_scene); 163 {
164 } 164 if (landIDList[x, y] == local_id)
165 165 {
166 /// <summary> 166 return;
167 /// Adds a land object to the stored list and adds them to the landIDList to what they own 167 //throw new Exception("Could not remove land object. Still being used at " + x + ", " + y);
168 /// </summary> 168 }
169 /// <param name="new_land">The land object being added</param> 169 }
170 public Land addLandObject(Land new_land) 170 }
171 { 171
172 lastLandLocalID++; 172 m_scene.EventManager.TriggerLandObjectRemoved(landList[local_id].landData.globalID);
173 new_land.landData.localID = lastLandLocalID; 173 landList.Remove(local_id);
174 landList.Add(lastLandLocalID, new_land.Copy()); 174 }
175 175
176 176 public void updateLandObject(int local_id, LandData newData)
177 bool[,] landBitmap = new_land.getLandBitmap(); 177 {
178 int x, y; 178 if (landList.ContainsKey(local_id))
179 for (x = 0; x < 64; x++) 179 {
180 { 180 landList[local_id].landData = newData.Copy();
181 for (y = 0; y < 64; y++) 181 m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, landList[local_id]);
182 { 182 }
183 if (landBitmap[x, y]) 183 }
184 { 184
185 landIDList[x, y] = lastLandLocalID; 185 private void performFinalLandJoin(ILandObject master, ILandObject slave)
186 } 186 {
187 } 187 int x, y;
188 } 188 bool[,] landBitmapSlave = slave.getLandBitmap();
189 landList[lastLandLocalID].forceUpdateLandInfo(); 189 for (x = 0; x < 64; x++)
190 m_scene.EventManager.TriggerLandObjectAdded(new_land, m_scene.RegionInfo.RegionID); 190 {
191 return new_land; 191 for (y = 0; y < 64; y++)
192 } 192 {
193 193 if (landBitmapSlave[x, y])
194 /// <summary> 194 {
195 /// Removes a land object from the list. Will not remove if local_id is still owning an area in landIDList 195 landIDList[x, y] = master.landData.localID;
196 /// </summary> 196 }
197 /// <param name="local_id">Land.localID of the peice of land to remove.</param> 197 }
198 public void removeLandObject(int local_id) 198 }
199 { 199
200 int x, y; 200 removeLandObject(slave.landData.localID);
201 for (x = 0; x < 64; x++) 201 updateLandObject(master.landData.localID, master.landData);
202 { 202 }
203 for (y = 0; y < 64; y++) 203
204 { 204 /// <summary>
205 if (landIDList[x, y] == local_id) 205 /// Get the land object at the specified point
206 { 206 /// </summary>
207 return; 207 /// <param name="x">Value between 0 - 256 on the x axis of the point</param>
208 //throw new Exception("Could not remove land object. Still being used at " + x + ", " + y); 208 /// <param name="y">Value between 0 - 256 on the y axis of the point</param>
209 } 209 /// <returns>Land object at the point supplied</returns>
210 } 210 public ILandObject getLandObject(float x_float, float y_float)
211 } 211 {
212 212 int x;
213 m_scene.EventManager.TriggerLandObjectRemoved(landList[local_id].landData.globalID); 213 int y;
214 landList.Remove(local_id); 214
215 } 215 try
216 216 {
217 public void updateLandObject(int local_id, LandData newData) 217 x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / Convert.ToDouble(4.0)));
218 { 218 y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / Convert.ToDouble(4.0)));
219 if (landList.ContainsKey(local_id)) 219 }
220 { 220 catch (System.OverflowException)
221 landList[local_id].landData = newData.Copy(); 221 {
222 m_scene.EventManager.TriggerLandObjectUpdated((uint) local_id, landList[local_id]); 222 return null;
223 } 223 }
224 else 224
225 { 225 if (x >= 64 || y >= 64 || x < 0 || y < 0)
226 //throw new Exception("Could not update land object. Local ID '" + local_id + "' does not exist"); 226 {
227 } 227 return null;
228 } 228 }
229 229 else
230 private void performFinalLandJoin(Land master, Land slave) 230 {
231 { 231 return landList[landIDList[x, y]];
232 int x, y; 232 }
233 bool[,] landBitmapSlave = slave.getLandBitmap(); 233 }
234 for (x = 0; x < 64; x++) 234
235 { 235 public ILandObject getLandObject(int x, int y)
236 for (y = 0; y < 64; y++) 236 {
237 { 237 if (x >= Convert.ToInt32(Constants.RegionSize) || y >= Convert.ToInt32(Constants.RegionSize) || x < 0 || y < 0)
238 if (landBitmapSlave[x, y]) 238 {
239 { 239 // These exceptions here will cause a lot of complaints from the users specifically because
240 landIDList[x, y] = master.landData.localID; 240 // they happen every time at border crossings
241 } 241 throw new Exception("Error: Parcel not found at point " + x + ", " + y);
242 } 242 }
243 } 243 else
244 244 {
245 removeLandObject(slave.landData.localID); 245 return landList[landIDList[x / 4, y / 4]];
246 updateLandObject(master.landData.localID, master.landData); 246 }
247 } 247 }
248 248
249 /// <summary> 249 #endregion
250 /// Get the land object at the specified point 250
251 /// </summary> 251 #region Parcel Modification
252 /// <param name="x">Value between 0 - 256 on the x axis of the point</param> 252
253 /// <param name="y">Value between 0 - 256 on the y axis of the point</param> 253 /// <summary>
254 /// <returns>Land object at the point supplied</returns> 254 /// Subdivides a piece of land
255 public Land getLandObject(float x_float, float y_float) 255 /// </summary>
256 { 256 /// <param name="start_x">West Point</param>
257 int x; 257 /// <param name="start_y">South Point</param>
258 int y; 258 /// <param name="end_x">East Point</param>
259 259 /// <param name="end_y">North Point</param>
260 try 260 /// <param name="attempting_user_id">LLUUID of user who is trying to subdivide</param>
261 { 261 /// <returns>Returns true if successful</returns>
262 x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / Convert.ToDouble(4.0))); 262 private bool subdivide(int start_x, int start_y, int end_x, int end_y, LLUUID attempting_user_id)
263 y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / Convert.ToDouble(4.0))); 263 {
264 } 264 //First, lets loop through the points and make sure they are all in the same peice of land
265 catch (System.OverflowException) 265 //Get the land object at start
266 { 266 ILandObject startLandObject = null;
267 return null; 267 try
268 } 268 {
269 269 startLandObject = getLandObject(start_x, start_y);
270 if (x >= 64 || y >= 64 || x < 0 || y < 0) 270 }
271 { 271 catch (Exception)
272 return null; 272 {
273 } 273 //m_log.Error("[LAND]: " + "Unable to get land object for subdivision at x: " + start_x + " y:" + start_y);
274 else 274 }
275 { 275 if (startLandObject == null) return false; //No such land object at the beginning
276 // Console.WriteLine("Point (" + x + ", " + y + ") determined from point (" + x_float + ", " + y_float + ")"); 276
277 return landList[landIDList[x, y]]; 277 //Loop through the points
278 } 278 try
279 } 279 {
280 280 int totalX = end_x - start_x;
281 public Land getLandObject(int x, int y) 281 int totalY = end_y - start_y;
282 { 282 int x, y;
283 if (x >= Convert.ToInt32(Constants.RegionSize) || y >= Convert.ToInt32(Constants.RegionSize) || x < 0 || y < 0) 283 for (y = 0; y < totalY; y++)
284 { 284 {
285 // These exceptions here will cause a lot of complaints from the users specifically because 285 for (x = 0; x < totalX; x++)
286 // they happen every time at border crossings 286 {
287 throw new Exception("Error: Parcel not found at point " + x + ", " + y); 287 ILandObject tempLandObject = getLandObject(start_x + x, start_y + y);
288 } 288 if (tempLandObject == null) return false; //No such land object at that point
289 else 289 if (tempLandObject != startLandObject) return false; //Subdividing over 2 land objects; no-no
290 { 290 }
291 return landList[landIDList[x/4, y/4]]; 291 }
292 } 292 }
293 } 293 catch (Exception)
294 294 {
295 #endregion 295 return false; //Exception. For now, lets skip subdivision
296 296 }
297 #region Parcel Modification 297
298 298 //If we are still here, then they are subdividing within one piece of land
299 /// <summary> 299 //Check owner
300 /// Subdivides a piece of land 300 if (startLandObject.landData.ownerID != attempting_user_id)
301 /// </summary> 301 {
302 /// <param name="start_x">West Point</param> 302 return false; //They cant do this!
303 /// <param name="start_y">South Point</param> 303 }
304 /// <param name="end_x">East Point</param> 304
305 /// <param name="end_y">North Point</param> 305 //Lets create a new land object with bitmap activated at that point (keeping the old land objects info)
306 /// <param name="attempting_user_id">LLUUID of user who is trying to subdivide</param> 306 ILandObject newLand = startLandObject.Copy();
307 /// <returns>Returns true if successful</returns> 307 newLand.landData.landName = "Subdivision of " + newLand.landData.landName;
308 private bool subdivide(int start_x, int start_y, int end_x, int end_y, LLUUID attempting_user_id) 308 newLand.landData.globalID = LLUUID.Random();
309 { 309
310 //First, lets loop through the points and make sure they are all in the same peice of land 310 newLand.setLandBitmap(newLand.getSquareLandBitmap(start_x, start_y, end_x, end_y));
311 //Get the land object at start 311
312 Land startLandObject = null; 312 //Now, lets set the subdivision area of the original to false
313 try 313 int startLandObjectIndex = startLandObject.landData.localID;
314 { 314 landList[startLandObjectIndex].setLandBitmap(
315 startLandObject = getLandObject(start_x, start_y); 315 newLand.modifyLandBitmapSquare(startLandObject.getLandBitmap(), start_x, start_y, end_x, end_y, false));
316 } 316 landList[startLandObjectIndex].forceUpdateLandInfo();
317 catch (Exception) 317
318 { 318 setPrimsTainted();
319 m_log.Error("[LAND]: " + "Unable to get land object for subdivision at x: " + start_x + " y:" + start_y); 319
320 } 320 //Now add the new land object
321 if (startLandObject == null) return false; //No such land object at the beginning 321 ILandObject result = addLandObject(newLand);
322 322 updateLandObject(startLandObject.landData.localID, startLandObject.landData);
323 //Loop through the points 323 result.sendLandUpdateToAvatarsOverMe();
324 try 324
325 { 325
326 int totalX = end_x - start_x; 326 return true;
327 int totalY = end_y - start_y; 327 }
328 int x, y; 328
329 for (y = 0; y < totalY; y++) 329 /// <summary>
330 { 330 /// Join 2 land objects together
331 for (x = 0; x < totalX; x++) 331 /// </summary>
332 { 332 /// <param name="start_x">x value in first piece of land</param>
333 Land tempLandObject = getLandObject(start_x + x, start_y + y); 333 /// <param name="start_y">y value in first piece of land</param>
334 if (tempLandObject == null) return false; //No such land object at that point 334 /// <param name="end_x">x value in second peice of land</param>
335 if (tempLandObject != startLandObject) return false; //Subdividing over 2 land objects; no-no 335 /// <param name="end_y">y value in second peice of land</param>
336 } 336 /// <param name="attempting_user_id">LLUUID of the avatar trying to join the land objects</param>
337 } 337 /// <returns>Returns true if successful</returns>
338 } 338 private bool join(int start_x, int start_y, int end_x, int end_y, LLUUID attempting_user_id)
339 catch (Exception) 339 {
340 { 340 end_x -= 4;
341 return false; //Exception. For now, lets skip subdivision 341 end_y -= 4;
342 } 342
343 343 List<ILandObject> selectedLandObjects = new List<ILandObject>();
344 //If we are still here, then they are subdividing within one piece of land 344 int stepXSelected = 0;
345 //Check owner 345 int stepYSelected = 0;
346 if (startLandObject.landData.ownerID != attempting_user_id) 346 for (stepYSelected = start_y; stepYSelected <= end_y; stepYSelected += 4)
347 { 347 {
348 return false; //They cant do this! 348 for (stepXSelected = start_x; stepXSelected <= end_x; stepXSelected += 4)
349 } 349 {
350 350 ILandObject p = null;
351 //Lets create a new land object with bitmap activated at that point (keeping the old land objects info) 351 try
352 Land newLand = startLandObject.Copy(); 352 {
353 newLand.landData.landName = "Subdivision of " + newLand.landData.landName; 353 p = getLandObject(stepXSelected, stepYSelected);
354 newLand.landData.globalID = LLUUID.Random(); 354 }
355 355 catch (Exception)
356 newLand.setLandBitmap(Land.getSquareLandBitmap(start_x, start_y, end_x, end_y)); 356 {
357 357 //m_log.Error("[LAND]: " + "Unable to get land object for subdivision at x: " + stepXSelected + " y:" + stepYSelected);
358 //Now, lets set the subdivision area of the original to false 358 }
359 int startLandObjectIndex = startLandObject.landData.localID; 359 if (p != null)
360 landList[startLandObjectIndex].setLandBitmap( 360 {
361 Land.modifyLandBitmapSquare(startLandObject.getLandBitmap(), start_x, start_y, end_x, end_y, false)); 361 if (!selectedLandObjects.Contains(p))
362 landList[startLandObjectIndex].forceUpdateLandInfo(); 362 {
363 363 selectedLandObjects.Add(p);
364 setPrimsTainted(); 364 }
365 365 }
366 //Now add the new land object 366 }
367 Land result = addLandObject(newLand); 367 }
368 updateLandObject(startLandObject.landData.localID, startLandObject.landData); 368 ILandObject masterLandObject = selectedLandObjects[0];
369 result.sendLandUpdateToAvatarsOverMe(); 369 selectedLandObjects.RemoveAt(0);
370 370
371 371
372 return true; 372 if (selectedLandObjects.Count < 1)
373 } 373 {
374 374 return false; //Only one piece of land selected
375 /// <summary> 375 }
376 /// Join 2 land objects together 376 if (masterLandObject.landData.ownerID != attempting_user_id)
377 /// </summary> 377 {
378 /// <param name="start_x">x value in first piece of land</param> 378 return false; //Not the same owner
379 /// <param name="start_y">y value in first piece of land</param> 379 }
380 /// <param name="end_x">x value in second peice of land</param> 380 foreach (ILandObject p in selectedLandObjects)
381 /// <param name="end_y">y value in second peice of land</param> 381 {
382 /// <param name="attempting_user_id">LLUUID of the avatar trying to join the land objects</param> 382 if (p.landData.ownerID != masterLandObject.landData.ownerID)
383 /// <returns>Returns true if successful</returns> 383 {
384 private bool join(int start_x, int start_y, int end_x, int end_y, LLUUID attempting_user_id) 384 return false; //Over multiple users. TODO: make this just ignore this piece of land?
385 { 385 }
386 end_x -= 4; 386 }
387 end_y -= 4; 387 foreach (ILandObject slaveLandObject in selectedLandObjects)
388 388 {
389 List<Land> selectedLandObjects = new List<Land>(); 389 landList[masterLandObject.landData.localID].setLandBitmap(
390 int stepXSelected = 0; 390 slaveLandObject.mergeLandBitmaps(masterLandObject.getLandBitmap(), slaveLandObject.getLandBitmap()));
391 int stepYSelected = 0; 391 performFinalLandJoin(masterLandObject, slaveLandObject);
392 for (stepYSelected = start_y; stepYSelected <= end_y; stepYSelected += 4) 392 }
393 { 393
394 for (stepXSelected = start_x; stepXSelected <= end_x; stepXSelected += 4) 394
395 { 395 setPrimsTainted();
396 Land p = null; 396
397 try 397 masterLandObject.sendLandUpdateToAvatarsOverMe();
398 { 398
399 p = getLandObject(stepXSelected, stepYSelected); 399 return true;
400 } 400 }
401 catch (Exception) 401
402 { 402 public void resetAllLandPrimCounts()
403 m_log.Error("[LAND]: " + "Unable to get land object for subdivision at x: " + stepXSelected + " y:" + stepYSelected); 403 {
404 } 404 foreach (LandObject p in landList.Values)
405 if (p != null) 405 {
406 { 406 p.resetLandPrimCounts();
407 if (!selectedLandObjects.Contains(p)) 407 }
408 { 408 }
409 selectedLandObjects.Add(p); 409
410 } 410 public void setPrimsTainted()
411 } 411 {
412 } 412 landPrimCountTainted = true;
413 } 413 }
414 Land masterLandObject = selectedLandObjects[0]; 414
415 selectedLandObjects.RemoveAt(0); 415 public bool isLandPrimCountTainted()
416 416 {
417 417 return landPrimCountTainted;
418 if (selectedLandObjects.Count < 1) 418 }
419 { 419
420 return false; //Only one piece of land selected 420 public void addPrimToLandPrimCounts(SceneObjectGroup obj)
421 } 421 {
422 if (masterLandObject.landData.ownerID != attempting_user_id) 422 LLVector3 position = obj.AbsolutePosition;
423 { 423 ILandObject landUnderPrim = getLandObject(position.X, position.Y);
424 return false; //Not the same owner 424 if (landUnderPrim != null)
425 } 425 {
426 foreach (Land p in selectedLandObjects) 426 landUnderPrim.addPrimToCount(obj);
427 { 427 }
428 if (p.landData.ownerID != masterLandObject.landData.ownerID) 428 }
429 { 429
430 return false; //Over multiple users. TODO: make this just ignore this piece of land? 430 public void removePrimFromLandPrimCounts(SceneObjectGroup obj)
431 } 431 {
432 } 432 foreach (LandObject p in landList.Values)
433 foreach (Land slaveLandObject in selectedLandObjects) 433 {
434 { 434 p.removePrimFromCount(obj);
435 landList[masterLandObject.landData.localID].setLandBitmap( 435 }
436 Land.mergeLandBitmaps(masterLandObject.getLandBitmap(), slaveLandObject.getLandBitmap())); 436 }
437 performFinalLandJoin(masterLandObject, slaveLandObject); 437
438 } 438 public void finalizeLandPrimCountUpdate()
439 439 {
440 440 //Get Simwide prim count for owner
441 setPrimsTainted(); 441 Dictionary<LLUUID, List<LandObject>> landOwnersAndParcels = new Dictionary<LLUUID, List<LandObject>>();
442 442 foreach (LandObject p in landList.Values)
443 masterLandObject.sendLandUpdateToAvatarsOverMe(); 443 {
444 444 if (!landOwnersAndParcels.ContainsKey(p.landData.ownerID))
445 return true; 445 {
446 } 446 List<LandObject> tempList = new List<LandObject>();
447 447 tempList.Add(p);
448 #endregion 448 landOwnersAndParcels.Add(p.landData.ownerID, tempList);
449 449 }
450 #region Parcel Updating 450 else
451 451 {
452 /// <summary> 452 landOwnersAndParcels[p.landData.ownerID].Add(p);
453 /// Where we send the ParcelOverlay packet to the client 453 }
454 /// </summary> 454 }
455 /// <param name="remote_client">The object representing the client</param> 455
456 public void sendParcelOverlay(IClientAPI remote_client) 456 foreach (LLUUID owner in landOwnersAndParcels.Keys)
457 { 457 {
458 const int LAND_BLOCKS_PER_PACKET = 1024; 458 int simArea = 0;
459 int x, y = 0; 459 int simPrims = 0;
460 byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET]; 460 foreach (LandObject p in landOwnersAndParcels[owner])
461 int byteArrayCount = 0; 461 {
462 int sequenceID = 0; 462 simArea += p.landData.area;
463 ParcelOverlayPacket packet; 463 simPrims += p.landData.ownerPrims + p.landData.otherPrims + p.landData.groupPrims +
464 464 p.landData.selectedPrims;
465 for (y = 0; y < 64; y++) 465 }
466 { 466
467 for (x = 0; x < 64; x++) 467 foreach (LandObject p in landOwnersAndParcels[owner])
468 { 468 {
469 byte tempByte = (byte) 0; //This represents the byte for the current 4x4 469 p.landData.simwideArea = simArea;
470 Land currentParcelBlock = null; 470 p.landData.simwidePrims = simPrims;
471 471 }
472 try 472 }
473 { 473 }
474 currentParcelBlock = getLandObject(x * 4, y * 4); 474
475 } 475 public void updateLandPrimCounts()
476 catch (Exception) 476 {
477 { 477 foreach (EntityBase obj in m_scene.Entities.Values)
478 m_log.Warn("[LAND]: " + "unable to get land at x: " + (x * 4) + " y: " + (y * 4)); 478 {
479 } 479 if (obj is SceneObjectGroup)
480 480 {
481 481 m_scene.EventManager.TriggerParcelPrimCountAdd((SceneObjectGroup)obj);
482 if (currentParcelBlock != null) 482 }
483 { 483 }
484 if (currentParcelBlock.landData.ownerID == remote_client.AgentId) 484 }
485 { 485
486 //Owner Flag 486 public void performParcelPrimCountUpdate()
487 tempByte = Convert.ToByte(tempByte | LAND_TYPE_OWNED_BY_REQUESTER); 487 {
488 } 488 resetAllLandPrimCounts();
489 else if (currentParcelBlock.landData.salePrice > 0 && 489 m_scene.EventManager.TriggerParcelPrimCountUpdate();
490 (currentParcelBlock.landData.authBuyerID == LLUUID.Zero || 490 finalizeLandPrimCountUpdate();
491 currentParcelBlock.landData.authBuyerID == remote_client.AgentId)) 491 landPrimCountTainted = false;
492 { 492 }
493 //Sale Flag 493 #endregion
494 tempByte = Convert.ToByte(tempByte | LAND_TYPE_IS_FOR_SALE); 494
495 } 495 #region Parcel Updating
496 else if (currentParcelBlock.landData.ownerID == LLUUID.Zero) 496
497 { 497 /// <summary>
498 //Public Flag 498 /// Where we send the ParcelOverlay packet to the client
499 tempByte = Convert.ToByte(tempByte | LAND_TYPE_PUBLIC); 499 /// </summary>
500 } 500 /// <param name="remote_client">The object representing the client</param>
501 else 501 public void sendParcelOverlay(IClientAPI remote_client)
502 { 502 {
503 //Other Flag 503 const int LAND_BLOCKS_PER_PACKET = 1024;
504 tempByte = Convert.ToByte(tempByte | LAND_TYPE_OWNED_BY_OTHER); 504 int x, y = 0;
505 } 505 byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET];
506 506 int byteArrayCount = 0;
507 507 int sequenceID = 0;
508 //Now for border control 508 ParcelOverlayPacket packet;
509 try 509
510 { 510 for (y = 0; y < 64; y++)
511 Land westParcel = null; 511 {
512 Land southParcel = null; 512 for (x = 0; x < 64; x++)
513 if (x > 0) 513 {
514 { 514 byte tempByte = (byte)0; //This represents the byte for the current 4x4
515 westParcel = getLandObject((x - 1)*4, y*4); 515 ILandObject currentParcelBlock = null;
516 } 516
517 if (y > 0) 517 try
518 { 518 {
519 southParcel = getLandObject(x*4, (y - 1)*4); 519 currentParcelBlock = getLandObject(x * 4, y * 4);
520 } 520 }
521 521 catch (Exception)
522 if (x == 0) 522 {
523 { 523 //m_log.Warn("[LAND]: " + "unable to get land at x: " + (x * 4) + " y: " + (y * 4));
524 tempByte = Convert.ToByte(tempByte | LAND_FLAG_PROPERTY_BORDER_WEST); 524 }
525 } 525
526 else if (westParcel != null && westParcel != currentParcelBlock) 526
527 { 527 if (currentParcelBlock != null)
528 tempByte = Convert.ToByte(tempByte | LAND_FLAG_PROPERTY_BORDER_WEST); 528 {
529 } 529 if (currentParcelBlock.landData.ownerID == remote_client.AgentId)
530 530 {
531 if (y == 0) 531 //Owner Flag
532 { 532 tempByte = Convert.ToByte(tempByte | LAND_TYPE_OWNED_BY_REQUESTER);
533 tempByte = Convert.ToByte(tempByte | LAND_FLAG_PROPERTY_BORDER_SOUTH); 533 }
534 } 534 else if (currentParcelBlock.landData.salePrice > 0 &&
535 else if (southParcel != null && southParcel != currentParcelBlock) 535 (currentParcelBlock.landData.authBuyerID == LLUUID.Zero ||
536 { 536 currentParcelBlock.landData.authBuyerID == remote_client.AgentId))
537 tempByte = Convert.ToByte(tempByte | LAND_FLAG_PROPERTY_BORDER_SOUTH); 537 {
538 } 538 //Sale Flag
539 539 tempByte = Convert.ToByte(tempByte | LAND_TYPE_IS_FOR_SALE);
540 byteArray[byteArrayCount] = tempByte; 540 }
541 byteArrayCount++; 541 else if (currentParcelBlock.landData.ownerID == LLUUID.Zero)
542 if (byteArrayCount >= LAND_BLOCKS_PER_PACKET) 542 {
543 { 543 //Public Flag
544 byteArrayCount = 0; 544 tempByte = Convert.ToByte(tempByte | LAND_TYPE_PUBLIC);
545 packet = (ParcelOverlayPacket) PacketPool.Instance.GetPacket(PacketType.ParcelOverlay); 545 }
546 packet.ParcelData.Data = byteArray; 546 else
547 packet.ParcelData.SequenceID = sequenceID; 547 {
548 remote_client.OutPacket((Packet) packet, ThrottleOutPacketType.Task); 548 //Other Flag
549 sequenceID++; 549 tempByte = Convert.ToByte(tempByte | LAND_TYPE_OWNED_BY_OTHER);
550 byteArray = new byte[LAND_BLOCKS_PER_PACKET]; 550 }
551 } 551
552 } 552
553 catch (Exception e) 553 //Now for border control
554 { 554 try
555 m_log.Debug("[LAND]: Skipped Land checks because avatar is out of bounds: " + e.Message); 555 {
556 } 556 ILandObject westParcel = null;
557 } 557 ILandObject southParcel = null;
558 } 558 if (x > 0)
559 } 559 {
560 } 560 westParcel = getLandObject((x - 1) * 4, y * 4);
561 561 }
562 public void handleParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id, 562 if (y > 0)
563 bool snap_selection, IClientAPI remote_client) 563 {
564 { 564 southParcel = getLandObject(x * 4, (y - 1) * 4);
565 //Get the land objects within the bounds 565 }
566 List<Land> temp = new List<Land>(); 566
567 int x, y, i; 567 if (x == 0)
568 int inc_x = end_x - start_x; 568 {
569 int inc_y = end_y - start_y; 569 tempByte = Convert.ToByte(tempByte | LAND_FLAG_PROPERTY_BORDER_WEST);
570 for (x = 0; x < inc_x; x++) 570 }
571 { 571 else if (westParcel != null && westParcel != currentParcelBlock)
572 for (y = 0; y < inc_y; y++) 572 {
573 { 573 tempByte = Convert.ToByte(tempByte | LAND_FLAG_PROPERTY_BORDER_WEST);
574 574 }
575 Land currentParcel = null; 575
576 try 576 if (y == 0)
577 { 577 {
578 currentParcel = getLandObject(start_x + x, start_y + y); 578 tempByte = Convert.ToByte(tempByte | LAND_FLAG_PROPERTY_BORDER_SOUTH);
579 } 579 }
580 catch (Exception) 580 else if (southParcel != null && southParcel != currentParcelBlock)
581 { 581 {
582 m_log.Warn("[LAND]: " + "unable to get land at x: " + (start_x + x) + " y: " + (start_y + y)); 582 tempByte = Convert.ToByte(tempByte | LAND_FLAG_PROPERTY_BORDER_SOUTH);
583 } 583 }
584 if (currentParcel != null) 584
585 { 585 byteArray[byteArrayCount] = tempByte;
586 if (!temp.Contains(currentParcel)) 586 byteArrayCount++;
587 { 587 if (byteArrayCount >= LAND_BLOCKS_PER_PACKET)
588 currentParcel.forceUpdateLandInfo(); 588 {
589 temp.Add(currentParcel); 589 byteArrayCount = 0;
590 } 590 packet = (ParcelOverlayPacket)PacketPool.Instance.GetPacket(PacketType.ParcelOverlay);
591 } 591 packet.ParcelData.Data = byteArray;
592 } 592 packet.ParcelData.SequenceID = sequenceID;
593 } 593 remote_client.OutPacket((Packet)packet, ThrottleOutPacketType.Task);
594 594 sequenceID++;
595 int requestResult = LAND_RESULT_SINGLE; 595 byteArray = new byte[LAND_BLOCKS_PER_PACKET];
596 if (temp.Count > 1) 596 }
597 { 597 }
598 requestResult = LAND_RESULT_MULTIPLE; 598 catch (Exception e)
599 } 599 {
600 600 //m_log.Debug("[LAND]: Skipped Land checks because avatar is out of bounds: " + e.Message);
601 for (i = 0; i < temp.Count; i++) 601 }
602 { 602 }
603 temp[i].sendLandProperties(sequence_id, snap_selection, requestResult, remote_client); 603 }
604 } 604 }
605 605 }
606 606
607 sendParcelOverlay(remote_client); 607 public void handleParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id,
608 } 608 bool snap_selection, IClientAPI remote_client)
609 609 {
610 public void handleParcelPropertiesUpdateRequest(ParcelPropertiesUpdatePacket packet, IClientAPI remote_client) 610 //Get the land objects within the bounds
611 { 611 List<ILandObject> temp = new List<ILandObject>();
612 if (landList.ContainsKey(packet.ParcelData.LocalID)) 612 int x, y, i;
613 { 613 int inc_x = end_x - start_x;
614 landList[packet.ParcelData.LocalID].updateLandProperties(packet, remote_client); 614 int inc_y = end_y - start_y;
615 } 615 for (x = 0; x < inc_x; x++)
616 } 616 {
617 617 for (y = 0; y < inc_y; y++)
618 public void handleParcelDivideRequest(int west, int south, int east, int north, IClientAPI remote_client) 618 {
619 { 619
620 subdivide(west, south, east, north, remote_client.AgentId); 620 ILandObject currentParcel = null;
621 } 621 try
622 622 {
623 public void handleParcelJoinRequest(int west, int south, int east, int north, IClientAPI remote_client) 623 currentParcel = getLandObject(start_x + x, start_y + y);
624 { 624 }
625 join(west, south, east, north, remote_client.AgentId); 625 catch (Exception)
626 } 626 {
627 627 //m_log.Warn("[LAND]: " + "unable to get land at x: " + (start_x + x) + " y: " + (start_y + y));
628 public void handleParcelSelectObjectsRequest(int local_id, int request_type, IClientAPI remote_client) 628 }
629 { 629 if (currentParcel != null)
630 landList[local_id].sendForceObjectSelect(local_id, request_type, remote_client); 630 {
631 } 631 if (!temp.Contains(currentParcel))
632 632 {
633 public void handleParcelObjectOwnersRequest(int local_id, IClientAPI remote_client) 633 currentParcel.forceUpdateLandInfo();
634 { 634 temp.Add(currentParcel);
635 landList[local_id].sendLandObjectOwners(remote_client); 635 }
636 } 636 }
637 637 }
638 #endregion 638 }
639 639
640 /// <summary> 640 int requestResult = LAND_RESULT_SINGLE;
641 /// Resets the sim to the default land object (full sim piece of land owned by the default user) 641 if (temp.Count > 1)
642 /// </summary> 642 {
643 public void resetSimLandObjects() 643 requestResult = LAND_RESULT_MULTIPLE;
644 { 644 }
645 //Remove all the land objects in the sim and add a blank, full sim land object set to public 645
646 landList.Clear(); 646 for (i = 0; i < temp.Count; i++)
647 lastLandLocalID = START_LAND_LOCAL_ID - 1; 647 {
648 landIDList.Initialize(); 648 temp[i].sendLandProperties(sequence_id, snap_selection, requestResult, remote_client);
649 649 }
650 Land fullSimParcel = new Land(LLUUID.Zero, false, m_scene); 650
651 651
652 fullSimParcel.setLandBitmap(Land.getSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize)); 652 sendParcelOverlay(remote_client);
653 fullSimParcel.landData.ownerID = m_regInfo.MasterAvatarAssignedUUID; 653 }
654 654
655 addLandObject(fullSimParcel); 655 public void handleParcelPropertiesUpdateRequest(ParcelPropertiesUpdatePacket packet, IClientAPI remote_client)
656 } 656 {
657 657 if (landList.ContainsKey(packet.ParcelData.LocalID))
658 public List<Land> parcelsNearPoint(LLVector3 position) 658 {
659 { 659 landList[packet.ParcelData.LocalID].updateLandProperties(packet, remote_client);
660 List<Land> parcelsNear = new List<Land>(); 660 }
661 int x, y; 661 }
662 for (x = -4; x <= 4; x += 4) 662
663 { 663 public void handleParcelDivideRequest(int west, int south, int east, int north, IClientAPI remote_client)
664 for (y = -4; y <= 4; y += 4) 664 {
665 { 665 subdivide(west, south, east, north, remote_client.AgentId);
666 Land check = getLandObject(position.X + x, position.Y + y); 666 }
667 if (check != null) 667
668 { 668 public void handleParcelJoinRequest(int west, int south, int east, int north, IClientAPI remote_client)
669 if (!parcelsNear.Contains(check)) 669 {
670 { 670 join(west, south, east, north, remote_client.AgentId);
671 parcelsNear.Add(check); 671 }
672 } 672
673 } 673 public void handleParcelSelectObjectsRequest(int local_id, int request_type, IClientAPI remote_client)
674 } 674 {
675 } 675 landList[local_id].sendForceObjectSelect(local_id, request_type, remote_client);
676 676 }
677 return parcelsNear; 677
678 } 678 public void handleParcelObjectOwnersRequest(int local_id, IClientAPI remote_client)
679 679 {
680 public void sendYouAreBannedNotice(ScenePresence avatar) 680 landList[local_id].sendLandObjectOwners(remote_client);
681 { 681 }
682 if (allowedForcefulBans) 682
683 { 683 #endregion
684 avatar.ControllingClient.SendAlertMessage( 684
685 "You are not allowed on this parcel because you are banned. Please go away. <3 OpenSim Developers"); 685 /// <summary>
686 686 /// Resets the sim to the default land object (full sim piece of land owned by the default user)
687 avatar.PhysicsActor.Position = 687 /// </summary>
688 new PhysicsVector(avatar.lastKnownAllowedPosition.x, avatar.lastKnownAllowedPosition.y, 688 public void resetSimLandObjects()
689 avatar.lastKnownAllowedPosition.z); 689 {
690 avatar.PhysicsActor.Velocity = new PhysicsVector(0, 0, 0); 690 //Remove all the land objects in the sim and add a blank, full sim land object set to public
691 } 691 landList.Clear();
692 else 692 lastLandLocalID = START_LAND_LOCAL_ID - 1;
693 { 693 landIDList.Initialize();
694 avatar.ControllingClient.SendAlertMessage( 694
695 "You are not allowed on this parcel because you are banned; however, the grid administrator has disabled ban lines globally. Please obey the land owner's requests or you can be banned from the entire sim! <3 OpenSim Developers"); 695 ILandObject fullSimParcel = new LandObject(LLUUID.Zero, false, m_scene);
696 } 696
697 } 697 fullSimParcel.setLandBitmap(fullSimParcel.getSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize));
698 698 fullSimParcel.landData.ownerID = m_scene.RegionInfo.MasterAvatarAssignedUUID;
699 public void handleAvatarChangingParcel(ScenePresence avatar, int localLandID, LLUUID regionID) 699
700 { 700 addLandObject(fullSimParcel);
701 if (m_scene.RegionInfo.RegionID == regionID) 701 }
702 { 702
703 if (landList[localLandID] != null) 703 public List<ILandObject> parcelsNearPoint(LLVector3 position)
704 { 704 {
705 Land parcelAvatarIsEntering = landList[localLandID]; 705 List<ILandObject> parcelsNear = new List<ILandObject>();
706 if (avatar.AbsolutePosition.Z < BAN_LINE_SAFETY_HIEGHT) 706 int x, y;
707 { 707 for (x = -4; x <= 4; x += 4)
708 if (parcelAvatarIsEntering.isBannedFromLand(avatar.UUID)) 708 {
709 { 709 for (y = -4; y <= 4; y += 4)
710 sendYouAreBannedNotice(avatar); 710 {
711 } 711 ILandObject check = getLandObject(position.X + x, position.Y + y);
712 else if (parcelAvatarIsEntering.isRestrictedFromLand(avatar.UUID)) 712 if (check != null)
713 { 713 {
714 avatar.ControllingClient.SendAlertMessage( 714 if (!parcelsNear.Contains(check))
715 "You are not allowed on this parcel because the land owner has restricted access. For now, you can enter, but please respect the land owner's decisions (or he can ban you!). <3 OpenSim Developers"); 715 {
716 } 716 parcelsNear.Add(check);
717 else 717 }
718 { 718 }
719 avatar.sentMessageAboutRestrictedParcelFlyingDown = true; 719 }
720 } 720 }
721 } 721
722 else 722 return parcelsNear;
723 { 723 }
724 avatar.sentMessageAboutRestrictedParcelFlyingDown = true; 724
725 } 725 public void sendYouAreBannedNotice(ScenePresence avatar)
726 } 726 {
727 } 727 if (allowedForcefulBans)
728 } 728 {
729 729 avatar.ControllingClient.SendAlertMessage(
730 public void sendOutNearestBanLine(IClientAPI avatar) 730 "You are not allowed on this parcel because you are banned. Please go away. <3 OpenSim Developers");
731 { 731
732 List<ScenePresence> avatars = m_scene.GetAvatars(); 732 avatar.PhysicsActor.Position =
733 foreach (ScenePresence presence in avatars) 733 new PhysicsVector(avatar.lastKnownAllowedPosition.x, avatar.lastKnownAllowedPosition.y,
734 { 734 avatar.lastKnownAllowedPosition.z);
735 if (presence.UUID == avatar.AgentId) 735 avatar.PhysicsActor.Velocity = new PhysicsVector(0, 0, 0);
736 { 736 }
737 737 else
738 List<Land> checkLandParcels = parcelsNearPoint(presence.AbsolutePosition); 738 {
739 foreach (Land checkBan in checkLandParcels) 739 avatar.ControllingClient.SendAlertMessage(
740 { 740 "You are not allowed on this parcel because you are banned; however, the grid administrator has disabled ban lines globally. Please obey the land owner's requests or you can be banned from the entire sim! <3 OpenSim Developers");
741 if (checkBan.isBannedFromLand(avatar.AgentId)) 741 }
742 { 742 }
743 checkBan.sendLandProperties(-30000, false, (int) ParcelManager.ParcelResult.Single, avatar); 743
744 return; //Only send one 744 public void handleAvatarChangingParcel(ScenePresence avatar, int localLandID, LLUUID regionID)
745 } 745 {
746 else if (checkBan.isRestrictedFromLand(avatar.AgentId)) 746 if (m_scene.RegionInfo.RegionID == regionID)
747 { 747 {
748 checkBan.sendLandProperties(-40000, false, (int) ParcelManager.ParcelResult.Single, avatar); 748 if (landList[localLandID] != null)
749 return; //Only send one 749 {
750 } 750 ILandObject parcelAvatarIsEntering = landList[localLandID];
751 } 751 if (avatar.AbsolutePosition.Z < BAN_LINE_SAFETY_HIEGHT)
752 return; 752 {
753 } 753 if (parcelAvatarIsEntering.isBannedFromLand(avatar.UUID))
754 } 754 {
755 } 755 sendYouAreBannedNotice(avatar);
756 756 }
757 public void sendLandUpdate(ScenePresence avatar, bool force) 757 else if (parcelAvatarIsEntering.isRestrictedFromLand(avatar.UUID))
758 { 758 {
759 Land over = null; 759 avatar.ControllingClient.SendAlertMessage(
760 try 760 "You are not allowed on this parcel because the land owner has restricted access. For now, you can enter, but please respect the land owner's decisions (or he can ban you!). <3 OpenSim Developers");
761 { 761 }
762 over = getLandObject((int)Math.Min(255, Math.Max(0, Math.Round(avatar.AbsolutePosition.X))), 762 else
763 (int)Math.Min(255, Math.Max(0, Math.Round(avatar.AbsolutePosition.Y)))); 763 {
764 } 764 avatar.sentMessageAboutRestrictedParcelFlyingDown = true;
765 catch (Exception) 765 }
766 { 766 }
767 m_log.Warn("[LAND]: " + "unable to get land at x: " + Math.Round(avatar.AbsolutePosition.X) + " y: " + Math.Round(avatar.AbsolutePosition.Y)); 767 else
768 } 768 {
769 769 avatar.sentMessageAboutRestrictedParcelFlyingDown = true;
770 if (over != null) 770 }
771 { 771 }
772 if (force) 772 }
773 { 773 }
774 if (!avatar.IsChildAgent) 774
775 { 775 public void sendOutNearestBanLine(IClientAPI avatar)
776 over.sendLandUpdateToClient(avatar.ControllingClient); 776 {
777 m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar, over.landData.localID, 777 List<ScenePresence> avatars = m_scene.GetAvatars();
778 m_scene.RegionInfo.RegionID); 778 foreach (ScenePresence presence in avatars)
779 } 779 {
780 } 780 if (presence.UUID == avatar.AgentId)
781 781 {
782 if (avatar.currentParcelUUID != over.landData.globalID) 782
783 { 783 List<ILandObject> checkLandParcels = parcelsNearPoint(presence.AbsolutePosition);
784 if (!avatar.IsChildAgent) 784 foreach (ILandObject checkBan in checkLandParcels)
785 { 785 {
786 over.sendLandUpdateToClient(avatar.ControllingClient); 786 if (checkBan.isBannedFromLand(avatar.AgentId))
787 avatar.currentParcelUUID = over.landData.globalID; 787 {
788 m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar, over.landData.localID, 788 checkBan.sendLandProperties(-30000, false, (int)ParcelManager.ParcelResult.Single, avatar);
789 m_scene.RegionInfo.RegionID); 789 return; //Only send one
790 } 790 }
791 } 791 else if (checkBan.isRestrictedFromLand(avatar.AgentId))
792 } 792 {
793 } 793 checkBan.sendLandProperties(-40000, false, (int)ParcelManager.ParcelResult.Single, avatar);
794 public void sendLandUpdate(ScenePresence avatar) 794 return; //Only send one
795 { 795 }
796 sendLandUpdate(avatar, false); 796 }
797 797 return;
798 } 798 }
799 public void handleSignificantClientMovement(IClientAPI remote_client) 799 }
800 { 800 }
801 ScenePresence clientAvatar = m_scene.GetScenePresence(remote_client.AgentId); 801
802 802 public void sendLandUpdate(ScenePresence avatar, bool force)
803 if (clientAvatar != null) 803 {
804 { 804 ILandObject over = null;
805 sendLandUpdate(clientAvatar); 805 try
806 sendOutNearestBanLine(remote_client); 806 {
807 Land parcel = getLandObject(clientAvatar.AbsolutePosition.X, clientAvatar.AbsolutePosition.Y); 807 over = getLandObject((int)Math.Min(255, Math.Max(0, Math.Round(avatar.AbsolutePosition.X))),
808 if (parcel != null) 808 (int)Math.Min(255, Math.Max(0, Math.Round(avatar.AbsolutePosition.Y))));
809 { 809 }
810 if (clientAvatar.AbsolutePosition.Z < BAN_LINE_SAFETY_HIEGHT && 810 catch (Exception)
811 clientAvatar.sentMessageAboutRestrictedParcelFlyingDown) 811 {
812 { 812 //m_log.Warn("[LAND]: " + "unable to get land at x: " + Math.Round(avatar.AbsolutePosition.X) + " y: " + Math.Round(avatar.AbsolutePosition.Y));
813 handleAvatarChangingParcel(clientAvatar, parcel.landData.localID, m_scene.RegionInfo.RegionID); 813 }
814 //They are going below the safety line! 814
815 if (!parcel.isBannedFromLand(clientAvatar.UUID)) 815 if (over != null)
816 { 816 {
817 clientAvatar.sentMessageAboutRestrictedParcelFlyingDown = false; 817 if (force)
818 } 818 {
819 } 819 if (!avatar.IsChildAgent)
820 else if (clientAvatar.AbsolutePosition.Z < BAN_LINE_SAFETY_HIEGHT && 820 {
821 parcel.isBannedFromLand(clientAvatar.UUID)) 821 over.sendLandUpdateToClient(avatar.ControllingClient);
822 { 822 m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar, over.landData.localID,
823 sendYouAreBannedNotice(clientAvatar); 823 m_scene.RegionInfo.RegionID);
824 } 824 }
825 } 825 }
826 } 826
827 } 827 if (avatar.currentParcelUUID != over.landData.globalID)
828 828 {
829 public void handleAnyClientMovement(ScenePresence avatar) 829 if (!avatar.IsChildAgent)
830 //Like handleSignificantClientMovement, but called with an AgentUpdate regardless of distance. 830 {
831 { 831 over.sendLandUpdateToClient(avatar.ControllingClient);
832 Land over = getLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); 832 avatar.currentParcelUUID = over.landData.globalID;
833 if (over != null) 833 m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar, over.landData.localID,
834 { 834 m_scene.RegionInfo.RegionID);
835 if (!over.isBannedFromLand(avatar.UUID) || avatar.AbsolutePosition.Z >= BAN_LINE_SAFETY_HIEGHT) 835 }
836 { 836 }
837 avatar.lastKnownAllowedPosition = 837 }
838 new Vector3(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, avatar.AbsolutePosition.Z); 838 }
839 } 839 public void sendLandUpdate(ScenePresence avatar)
840 } 840 {
841 } 841 sendLandUpdate(avatar, false);
842 842
843 843 }
844 public void handleParcelAccessRequest(LLUUID agentID, LLUUID sessionID, uint flags, int sequenceID, 844 public void handleSignificantClientMovement(IClientAPI remote_client)
845 int landLocalID, IClientAPI remote_client) 845 {
846 { 846 ScenePresence clientAvatar = m_scene.GetScenePresence(remote_client.AgentId);
847 if (landList.ContainsKey(landLocalID)) 847
848 { 848 if (clientAvatar != null)
849 landList[landLocalID].sendAccessList(agentID, sessionID, flags, sequenceID, remote_client); 849 {
850 } 850 sendLandUpdate(clientAvatar);
851 } 851 sendOutNearestBanLine(remote_client);
852 852 ILandObject parcel = getLandObject(clientAvatar.AbsolutePosition.X, clientAvatar.AbsolutePosition.Y);
853 public void handleParcelAccessUpdateRequest(LLUUID agentID, LLUUID sessionID, uint flags, int landLocalID, 853 if (parcel != null)
854 List<ParcelManager.ParcelAccessEntry> entries, 854 {
855 IClientAPI remote_client) 855 if (clientAvatar.AbsolutePosition.Z < BAN_LINE_SAFETY_HIEGHT &&
856 { 856 clientAvatar.sentMessageAboutRestrictedParcelFlyingDown)
857 if (landList.ContainsKey(landLocalID)) 857 {
858 { 858 handleAvatarChangingParcel(clientAvatar, parcel.landData.localID, m_scene.RegionInfo.RegionID);
859 if (agentID == landList[landLocalID].landData.ownerID) 859 //They are going below the safety line!
860 { 860 if (!parcel.isBannedFromLand(clientAvatar.UUID))
861 landList[landLocalID].updateAccessList(flags, entries, remote_client); 861 {
862 } 862 clientAvatar.sentMessageAboutRestrictedParcelFlyingDown = false;
863 } 863 }
864 else 864 }
865 { 865 else if (clientAvatar.AbsolutePosition.Z < BAN_LINE_SAFETY_HIEGHT &&
866 Console.WriteLine("INVALID LOCAL LAND ID"); 866 parcel.isBannedFromLand(clientAvatar.UUID))
867 } 867 {
868 } 868 sendYouAreBannedNotice(clientAvatar);
869 869 }
870 public void resetAllLandPrimCounts() 870 }
871 { 871 }
872 foreach (Land p in landList.Values) 872 }
873 { 873
874 p.resetLandPrimCounts(); 874 public void handleAnyClientMovement(ScenePresence avatar)
875 } 875 //Like handleSignificantClientMovement, but called with an AgentUpdate regardless of distance.
876 } 876 {
877 877 ILandObject over = getLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
878 public void setPrimsTainted() 878 if (over != null)
879 { 879 {
880 landPrimCountTainted = true; 880 if (!over.isBannedFromLand(avatar.UUID) || avatar.AbsolutePosition.Z >= BAN_LINE_SAFETY_HIEGHT)
881 } 881 {
882 882 avatar.lastKnownAllowedPosition =
883 public void addPrimToLandPrimCounts(SceneObjectGroup obj) 883 new Vector3(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, avatar.AbsolutePosition.Z);
884 { 884 }
885 LLVector3 position = obj.AbsolutePosition; 885 }
886 Land landUnderPrim = getLandObject(position.X, position.Y); 886 }
887 if (landUnderPrim != null) 887
888 { 888
889 landUnderPrim.addPrimToCount(obj); 889 public void handleParcelAccessRequest(LLUUID agentID, LLUUID sessionID, uint flags, int sequenceID,
890 } 890 int landLocalID, IClientAPI remote_client)
891 } 891 {
892 892 if (landList.ContainsKey(landLocalID))
893 public void removePrimFromLandPrimCounts(SceneObjectGroup obj) 893 {
894 { 894 landList[landLocalID].sendAccessList(agentID, sessionID, flags, sequenceID, remote_client);
895 foreach (Land p in landList.Values) 895 }
896 { 896 }
897 p.removePrimFromCount(obj); 897
898 } 898 public void handleParcelAccessUpdateRequest(LLUUID agentID, LLUUID sessionID, uint flags, int landLocalID,
899 } 899 List<ParcelManager.ParcelAccessEntry> entries,
900 900 IClientAPI remote_client)
901 public void finalizeLandPrimCountUpdate() 901 {
902 { 902 if (landList.ContainsKey(landLocalID))
903 //Get Simwide prim count for owner 903 {
904 Dictionary<LLUUID, List<Land>> landOwnersAndParcels = new Dictionary<LLUUID, List<Land>>(); 904 if (agentID == landList[landLocalID].landData.ownerID)
905 foreach (Land p in landList.Values) 905 {
906 { 906 landList[landLocalID].updateAccessList(flags, entries, remote_client);
907 if (!landOwnersAndParcels.ContainsKey(p.landData.ownerID)) 907 }
908 { 908 }
909 List<Land> tempList = new List<Land>(); 909 else
910 tempList.Add(p); 910 {
911 landOwnersAndParcels.Add(p.landData.ownerID, tempList); 911 Console.WriteLine("INVALID LOCAL LAND ID");
912 } 912 }
913 else 913 }
914 { 914
915 landOwnersAndParcels[p.landData.ownerID].Add(p); 915 }
916 } 916}
917 }
918
919 foreach (LLUUID owner in landOwnersAndParcels.Keys)
920 {
921 int simArea = 0;
922 int simPrims = 0;
923 foreach (Land p in landOwnersAndParcels[owner])
924 {
925 simArea += p.landData.area;
926 simPrims += p.landData.ownerPrims + p.landData.otherPrims + p.landData.groupPrims +
927 p.landData.selectedPrims;
928 }
929
930 foreach (Land p in landOwnersAndParcels[owner])
931 {
932 p.landData.simwideArea = simArea;
933 p.landData.simwidePrims = simPrims;
934 }
935 }
936 }
937
938 #endregion
939 }
940
941 #endregion
942}