diff options
Diffstat (limited to 'OpenSim/Region/CoreModules/World/Land/LandObject.cs')
-rw-r--r-- | OpenSim/Region/CoreModules/World/Land/LandObject.cs | 883 |
1 files changed, 753 insertions, 130 deletions
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index a0c1b9d..ce67fcc 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs | |||
@@ -50,15 +50,22 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
50 | private readonly int landUnit = 4; | 50 | private readonly int landUnit = 4; |
51 | 51 | ||
52 | private int m_lastSeqId = 0; | 52 | private int m_lastSeqId = 0; |
53 | 53 | private int m_expiryCounter = 0; | |
54 | |||
54 | protected Scene m_scene; | 55 | protected Scene m_scene; |
55 | protected List<SceneObjectGroup> primsOverMe = new List<SceneObjectGroup>(); | 56 | protected List<SceneObjectGroup> primsOverMe = new List<SceneObjectGroup>(); |
56 | protected Dictionary<uint, UUID> m_listTransactions = new Dictionary<uint, UUID>(); | 57 | protected Dictionary<uint, UUID> m_listTransactions = new Dictionary<uint, UUID>(); |
57 | 58 | ||
58 | protected ExpiringCache<UUID, bool> m_groupMemberCache = new ExpiringCache<UUID, bool>(); | 59 | protected ExpiringCache<UUID, bool> m_groupMemberCache = new ExpiringCache<UUID, bool>(); |
59 | protected TimeSpan m_groupMemberCacheTimeout = TimeSpan.FromSeconds(30); // cache invalidation after 30 seconds | 60 | protected TimeSpan m_groupMemberCacheTimeout = TimeSpan.FromSeconds(30); // cache invalidation after 30 seconds |
61 | IDwellModule m_dwellModule; | ||
60 | 62 | ||
61 | public bool[,] LandBitmap { get; set; } | 63 | private bool[,] m_landBitmap; |
64 | public bool[,] LandBitmap | ||
65 | { | ||
66 | get { return m_landBitmap; } | ||
67 | set { m_landBitmap = value; } | ||
68 | } | ||
62 | 69 | ||
63 | #endregion | 70 | #endregion |
64 | 71 | ||
@@ -69,7 +76,13 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
69 | return free; | 76 | return free; |
70 | } | 77 | } |
71 | 78 | ||
72 | public LandData LandData { get; set; } | 79 | protected LandData m_landData; |
80 | public LandData LandData | ||
81 | { | ||
82 | get { return m_landData; } | ||
83 | |||
84 | set { m_landData = value; } | ||
85 | } | ||
73 | 86 | ||
74 | public IPrimCounts PrimCounts { get; set; } | 87 | public IPrimCounts PrimCounts { get; set; } |
75 | 88 | ||
@@ -78,77 +91,230 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
78 | get { return m_scene.RegionInfo.RegionID; } | 91 | get { return m_scene.RegionInfo.RegionID; } |
79 | } | 92 | } |
80 | 93 | ||
81 | public Vector3 StartPoint | 94 | private Vector2 m_startPoint = Vector2.Zero; |
95 | private Vector2 m_endPoint = Vector2.Zero; | ||
96 | private Vector2 m_centerPoint = Vector2.Zero; | ||
97 | private Vector2 m_AABBmin = Vector2.Zero; | ||
98 | private Vector2 m_AABBmax = Vector2.Zero; | ||
99 | |||
100 | public Vector2 StartPoint | ||
82 | { | 101 | { |
83 | get | 102 | get |
84 | { | 103 | { |
85 | for (int y = 0; y < LandBitmap.GetLength(1); y++) | 104 | return m_startPoint; |
86 | { | 105 | } |
87 | for (int x = 0; x < LandBitmap.GetLength(0); x++) | 106 | } |
88 | { | ||
89 | if (LandBitmap[x, y]) | ||
90 | return new Vector3(x * landUnit, y * landUnit, 0); | ||
91 | } | ||
92 | } | ||
93 | 107 | ||
94 | m_log.ErrorFormat("{0} StartPoint. No start point found. bitmapSize=<{1},{2}>", | 108 | public Vector2 EndPoint |
95 | LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1)); | 109 | { |
96 | return new Vector3(-1, -1, -1); | 110 | get |
111 | { | ||
112 | return m_endPoint; | ||
97 | } | 113 | } |
98 | } | 114 | } |
99 | 115 | ||
100 | public Vector3 EndPoint | 116 | //estimate a center point of a parcel |
117 | public Vector2 CenterPoint | ||
101 | { | 118 | { |
102 | get | 119 | get |
103 | { | 120 | { |
104 | for (int y = LandBitmap.GetLength(1) - 1; y >= 0; y--) | 121 | return m_centerPoint; |
122 | } | ||
123 | } | ||
124 | |||
125 | public Vector2? GetNearestPoint(Vector3 pos) | ||
126 | { | ||
127 | Vector3 direction = new Vector3(m_centerPoint.X - pos.X, m_centerPoint.Y - pos.Y, 0f ); | ||
128 | return GetNearestPointAlongDirection(pos, direction); | ||
129 | } | ||
130 | |||
131 | public Vector2? GetNearestPointAlongDirection(Vector3 pos, Vector3 pdirection) | ||
132 | { | ||
133 | Vector2 testpos; | ||
134 | Vector2 direction; | ||
135 | |||
136 | testpos.X = pos.X / landUnit; | ||
137 | testpos.Y = pos.Y / landUnit; | ||
138 | |||
139 | if(LandBitmap[(int)testpos.X, (int)testpos.Y]) | ||
140 | return new Vector2(pos.X, pos.Y); // we are already here | ||
141 | |||
142 | direction.X = pdirection.X; | ||
143 | direction.Y = pdirection.Y; | ||
144 | |||
145 | if(direction.X == 0f && direction.Y == 0f) | ||
146 | return null; // we can't look anywhere | ||
147 | |||
148 | direction.Normalize(); | ||
149 | |||
150 | int minx = (int)(m_AABBmin.X / landUnit); | ||
151 | int maxx = (int)(m_AABBmax.X / landUnit); | ||
152 | |||
153 | // check against AABB | ||
154 | if(direction.X > 0f) | ||
155 | { | ||
156 | if(testpos.X >= maxx) | ||
157 | return null; // will never get there | ||
158 | if(testpos.X < minx) | ||
159 | testpos.X = minx; | ||
160 | } | ||
161 | else if(direction.X < 0f) | ||
162 | { | ||
163 | if(testpos.X < minx) | ||
164 | return null; // will never get there | ||
165 | if(testpos.X >= maxx) | ||
166 | testpos.X = maxx - 1; | ||
167 | } | ||
168 | else | ||
169 | { | ||
170 | if(testpos.X < minx) | ||
171 | return null; // will never get there | ||
172 | else if(testpos.X >= maxx) | ||
173 | return null; // will never get there | ||
174 | } | ||
175 | |||
176 | int miny = (int)(m_AABBmin.Y / landUnit); | ||
177 | int maxy = (int)(m_AABBmax.Y / landUnit); | ||
178 | |||
179 | if(direction.Y > 0f) | ||
180 | { | ||
181 | if(testpos.Y >= maxy) | ||
182 | return null; // will never get there | ||
183 | if(testpos.Y < miny) | ||
184 | testpos.Y = miny; | ||
185 | } | ||
186 | else if(direction.Y < 0f) | ||
187 | { | ||
188 | if(testpos.Y < miny) | ||
189 | return null; // will never get there | ||
190 | if(testpos.Y >= maxy) | ||
191 | testpos.Y = maxy - 1; | ||
192 | } | ||
193 | else | ||
194 | { | ||
195 | if(testpos.Y < miny) | ||
196 | return null; // will never get there | ||
197 | else if(testpos.Y >= maxy) | ||
198 | return null; // will never get there | ||
199 | } | ||
200 | |||
201 | while(!LandBitmap[(int)testpos.X, (int)testpos.Y]) | ||
202 | { | ||
203 | testpos += direction; | ||
204 | |||
205 | if(testpos.X < minx) | ||
206 | return null; | ||
207 | if (testpos.X >= maxx) | ||
208 | return null; | ||
209 | if(testpos.Y < miny) | ||
210 | return null; | ||
211 | if (testpos.Y >= maxy) | ||
212 | return null; | ||
213 | } | ||
214 | |||
215 | testpos *= landUnit; | ||
216 | float ftmp; | ||
217 | |||
218 | if(Math.Abs(direction.X) > Math.Abs(direction.Y)) | ||
219 | { | ||
220 | if(direction.X < 0) | ||
221 | testpos.X += landUnit - 0.5f; | ||
222 | else | ||
223 | testpos.X += 0.5f; | ||
224 | ftmp = testpos.X - pos.X; | ||
225 | ftmp /= direction.X; | ||
226 | ftmp = Math.Abs(ftmp); | ||
227 | ftmp *= direction.Y; | ||
228 | ftmp += pos.Y; | ||
229 | |||
230 | if(ftmp < testpos.Y + .5f) | ||
231 | ftmp = testpos.Y + .5f; | ||
232 | else | ||
105 | { | 233 | { |
106 | for (int x = LandBitmap.GetLength(0) - 1; x >= 0; x--) | 234 | testpos.Y += landUnit - 0.5f; |
107 | { | 235 | if(ftmp > testpos.Y) |
108 | if (LandBitmap[x, y]) | 236 | ftmp = testpos.Y; |
109 | { | ||
110 | return new Vector3(x * landUnit + landUnit, y * landUnit + landUnit, 0); | ||
111 | } | ||
112 | } | ||
113 | } | 237 | } |
114 | 238 | testpos.Y = ftmp; | |
115 | m_log.ErrorFormat("{0} EndPoint. No end point found. bitmapSize=<{1},{2}>", | 239 | } |
116 | LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1)); | 240 | else |
117 | return new Vector3(-1, -1, -1); | 241 | { |
242 | if(direction.Y < 0) | ||
243 | testpos.Y += landUnit - 0.5f; | ||
244 | else | ||
245 | testpos.Y += 0.5f; | ||
246 | ftmp = testpos.Y - pos.Y; | ||
247 | ftmp /= direction.Y; | ||
248 | ftmp = Math.Abs(ftmp); | ||
249 | ftmp *= direction.X; | ||
250 | ftmp += pos.X; | ||
251 | |||
252 | if(ftmp < testpos.X + .5f) | ||
253 | ftmp = testpos.X + .5f; | ||
254 | else | ||
255 | { | ||
256 | testpos.X += landUnit - 0.5f; | ||
257 | if(ftmp > testpos.X) | ||
258 | ftmp = testpos.X; | ||
259 | } | ||
260 | testpos.X = ftmp; | ||
118 | } | 261 | } |
262 | return testpos; | ||
119 | } | 263 | } |
120 | 264 | ||
265 | |||
121 | #region Constructors | 266 | #region Constructors |
122 | 267 | ||
123 | public LandObject(LandData landData, Scene scene) | 268 | public LandObject(LandData landData, Scene scene) |
124 | { | 269 | { |
125 | LandData = landData.Copy(); | 270 | LandData = landData.Copy(); |
126 | m_scene = scene; | 271 | m_scene = scene; |
272 | m_scene.EventManager.OnFrame += OnFrame; | ||
273 | m_dwellModule = m_scene.RequestModuleInterface<IDwellModule>(); | ||
127 | } | 274 | } |
128 | 275 | ||
129 | public LandObject(UUID owner_id, bool is_group_owned, Scene scene) | 276 | public LandObject(UUID owner_id, bool is_group_owned, Scene scene, LandData data = null) |
130 | { | 277 | { |
131 | m_scene = scene; | 278 | m_scene = scene; |
132 | if (m_scene == null) | 279 | if (m_scene == null) |
133 | LandBitmap = new bool[Constants.RegionSize / landUnit, Constants.RegionSize / landUnit]; | 280 | LandBitmap = new bool[Constants.RegionSize / landUnit, Constants.RegionSize / landUnit]; |
134 | else | 281 | else |
282 | { | ||
135 | LandBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; | 283 | LandBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; |
284 | m_dwellModule = m_scene.RequestModuleInterface<IDwellModule>(); | ||
285 | } | ||
286 | |||
287 | if(data == null) | ||
288 | LandData = new LandData(); | ||
289 | else | ||
290 | LandData = data; | ||
136 | 291 | ||
137 | LandData = new LandData(); | ||
138 | LandData.OwnerID = owner_id; | 292 | LandData.OwnerID = owner_id; |
139 | if (is_group_owned) | 293 | if (is_group_owned) |
140 | LandData.GroupID = owner_id; | 294 | LandData.GroupID = owner_id; |
141 | else | 295 | |
142 | LandData.GroupID = UUID.Zero; | ||
143 | LandData.IsGroupOwned = is_group_owned; | 296 | LandData.IsGroupOwned = is_group_owned; |
297 | |||
298 | if(m_dwellModule == null) | ||
299 | LandData.Dwell = 0; | ||
300 | |||
301 | m_scene.EventManager.OnFrame += OnFrame; | ||
302 | } | ||
303 | |||
304 | public void Clear() | ||
305 | { | ||
306 | if(m_scene != null) | ||
307 | m_scene.EventManager.OnFrame -= OnFrame; | ||
308 | LandData = null; | ||
144 | } | 309 | } |
145 | 310 | ||
311 | |||
146 | #endregion | 312 | #endregion |
147 | 313 | ||
148 | #region Member Functions | 314 | #region Member Functions |
149 | 315 | ||
150 | #region General Functions | 316 | #region General Functions |
151 | 317 | ||
152 | /// <summary> | 318 | /// <summary> |
153 | /// Checks to see if this land object contains a point | 319 | /// Checks to see if this land object contains a point |
154 | /// </summary> | 320 | /// </summary> |
@@ -195,14 +361,22 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
195 | else | 361 | else |
196 | { | 362 | { |
197 | // Normal Calculations | 363 | // Normal Calculations |
198 | int parcelMax = (int)(((float)LandData.Area / (m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY)) | 364 | int parcelMax = (int)( |
199 | * (float)m_scene.RegionInfo.ObjectCapacity | 365 | (double)LandData.Area |
200 | * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); | 366 | * (double)m_scene.RegionInfo.ObjectCapacity |
201 | // TODO: The calculation of ObjectBonus should be refactored. It does still not work in the same manner as SL! | 367 | * (double)m_scene.RegionInfo.RegionSettings.ObjectBonus |
368 | / (double)(m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY) | ||
369 | + 0.5 ); | ||
370 | |||
371 | if(parcelMax > m_scene.RegionInfo.ObjectCapacity) | ||
372 | parcelMax = m_scene.RegionInfo.ObjectCapacity; | ||
373 | |||
374 | //m_log.DebugFormat("Area: {0}, Capacity {1}, Bonus {2}, Parcel {3}", LandData.Area, m_scene.RegionInfo.ObjectCapacity, m_scene.RegionInfo.RegionSettings.ObjectBonus, parcelMax); | ||
202 | return parcelMax; | 375 | return parcelMax; |
203 | } | 376 | } |
204 | } | 377 | } |
205 | 378 | ||
379 | // the total prims a parcel owner can have on a region | ||
206 | public int GetSimulatorMaxPrimCount() | 380 | public int GetSimulatorMaxPrimCount() |
207 | { | 381 | { |
208 | if (overrideSimulatorMaxPrimCount != null) | 382 | if (overrideSimulatorMaxPrimCount != null) |
@@ -212,18 +386,34 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
212 | else | 386 | else |
213 | { | 387 | { |
214 | //Normal Calculations | 388 | //Normal Calculations |
215 | int simMax = (int)(((float)LandData.SimwideArea / (m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY)) | 389 | int simMax = (int)( (double)LandData.SimwideArea |
216 | * (float)m_scene.RegionInfo.ObjectCapacity); | 390 | * (double)m_scene.RegionInfo.ObjectCapacity |
391 | * (double)m_scene.RegionInfo.RegionSettings.ObjectBonus | ||
392 | / (long)(m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY) | ||
393 | +0.5 ); | ||
394 | // sanity check | ||
395 | if(simMax > m_scene.RegionInfo.ObjectCapacity) | ||
396 | simMax = m_scene.RegionInfo.ObjectCapacity; | ||
397 | //m_log.DebugFormat("Simwide Area: {0}, Capacity {1}, SimMax {2}, SimWidePrims {3}", | ||
398 | // LandData.SimwideArea, m_scene.RegionInfo.ObjectCapacity, simMax, LandData.SimwidePrims); | ||
217 | return simMax; | 399 | return simMax; |
218 | } | 400 | } |
219 | } | 401 | } |
220 | 402 | ||
221 | #endregion | 403 | #endregion |
222 | 404 | ||
223 | #region Packet Request Handling | 405 | #region Packet Request Handling |
224 | 406 | ||
225 | public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client) | 407 | public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client) |
226 | { | 408 | { |
409 | if(m_scene.RegionInfo.RegionSettings.AllowDamage) | ||
410 | remote_client.SceneAgent.Invulnerable = false; | ||
411 | else | ||
412 | remote_client.SceneAgent.Invulnerable = (m_landData.Flags & (uint)ParcelFlags.AllowDamage) == 0; | ||
413 | |||
414 | if (remote_client.SceneAgent.PresenceType == PresenceType.Npc) | ||
415 | return; | ||
416 | |||
227 | IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>(); | 417 | IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>(); |
228 | // uint regionFlags = 336723974 & ~((uint)(RegionFlags.AllowLandmark | RegionFlags.AllowSetHome)); | 418 | // uint regionFlags = 336723974 & ~((uint)(RegionFlags.AllowLandmark | RegionFlags.AllowSetHome)); |
229 | uint regionFlags = (uint)(RegionFlags.PublicAllowed | 419 | uint regionFlags = (uint)(RegionFlags.PublicAllowed |
@@ -252,10 +442,11 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
252 | GetSimulatorMaxPrimCount(), regionFlags); | 442 | GetSimulatorMaxPrimCount(), regionFlags); |
253 | } | 443 | } |
254 | 444 | ||
255 | public void UpdateLandProperties(LandUpdateArgs args, IClientAPI remote_client) | 445 | public bool UpdateLandProperties(LandUpdateArgs args, IClientAPI remote_client, out bool snap_selection, out bool needOverlay) |
256 | { | 446 | { |
257 | //Needs later group support | 447 | //Needs later group support |
258 | bool snap_selection = false; | 448 | snap_selection = false; |
449 | needOverlay = false; | ||
259 | LandData newData = LandData.Copy(); | 450 | LandData newData = LandData.Copy(); |
260 | 451 | ||
261 | uint allowedDelta = 0; | 452 | uint allowedDelta = 0; |
@@ -264,7 +455,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
264 | // ParcelFlags.ForSaleObjects | 455 | // ParcelFlags.ForSaleObjects |
265 | // ParcelFlags.LindenHome | 456 | // ParcelFlags.LindenHome |
266 | 457 | ||
267 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions)) | 458 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions, false)) |
268 | { | 459 | { |
269 | allowedDelta |= (uint)(ParcelFlags.AllowLandmark | | 460 | allowedDelta |= (uint)(ParcelFlags.AllowLandmark | |
270 | ParcelFlags.AllowTerraform | | 461 | ParcelFlags.AllowTerraform | |
@@ -277,9 +468,12 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
277 | ParcelFlags.AllowAPrimitiveEntry | | 468 | ParcelFlags.AllowAPrimitiveEntry | |
278 | ParcelFlags.AllowGroupObjectEntry | | 469 | ParcelFlags.AllowGroupObjectEntry | |
279 | ParcelFlags.AllowFly); | 470 | ParcelFlags.AllowFly); |
471 | newData.SeeAVs = args.SeeAVs; | ||
472 | newData.AnyAVSounds = args.AnyAVSounds; | ||
473 | newData.GroupAVSounds = args.GroupAVSounds; | ||
280 | } | 474 | } |
281 | 475 | ||
282 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandSetSale)) | 476 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandSetSale, true)) |
283 | { | 477 | { |
284 | if (args.AuthBuyerID != newData.AuthBuyerID || | 478 | if (args.AuthBuyerID != newData.AuthBuyerID || |
285 | args.SalePrice != newData.SalePrice) | 479 | args.SalePrice != newData.SalePrice) |
@@ -302,30 +496,30 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
302 | allowedDelta |= (uint)ParcelFlags.ForSale; | 496 | allowedDelta |= (uint)ParcelFlags.ForSale; |
303 | } | 497 | } |
304 | 498 | ||
305 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.FindPlaces)) | 499 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.FindPlaces, false)) |
306 | { | 500 | { |
307 | newData.Category = args.Category; | 501 | newData.Category = args.Category; |
308 | 502 | ||
309 | allowedDelta |= (uint)(ParcelFlags.ShowDirectory | | 503 | allowedDelta |= (uint)(ParcelFlags.ShowDirectory | |
310 | ParcelFlags.AllowPublish | | 504 | ParcelFlags.AllowPublish | |
311 | ParcelFlags.MaturePublish); | 505 | ParcelFlags.MaturePublish) | (uint)(1 << 23); |
312 | } | 506 | } |
313 | 507 | ||
314 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.LandChangeIdentity)) | 508 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.LandChangeIdentity, false)) |
315 | { | 509 | { |
316 | newData.Description = args.Desc; | 510 | newData.Description = args.Desc; |
317 | newData.Name = args.Name; | 511 | newData.Name = args.Name; |
318 | newData.SnapshotID = args.SnapshotID; | 512 | newData.SnapshotID = args.SnapshotID; |
319 | } | 513 | } |
320 | 514 | ||
321 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.SetLandingPoint)) | 515 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.SetLandingPoint, false)) |
322 | { | 516 | { |
323 | newData.LandingType = args.LandingType; | 517 | newData.LandingType = args.LandingType; |
324 | newData.UserLocation = args.UserLocation; | 518 | newData.UserLocation = args.UserLocation; |
325 | newData.UserLookAt = args.UserLookAt; | 519 | newData.UserLookAt = args.UserLookAt; |
326 | } | 520 | } |
327 | 521 | ||
328 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.ChangeMedia)) | 522 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.ChangeMedia, false)) |
329 | { | 523 | { |
330 | newData.MediaAutoScale = args.MediaAutoScale; | 524 | newData.MediaAutoScale = args.MediaAutoScale; |
331 | newData.MediaID = args.MediaID; | 525 | newData.MediaID = args.MediaID; |
@@ -346,7 +540,8 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
346 | ParcelFlags.UseEstateVoiceChan); | 540 | ParcelFlags.UseEstateVoiceChan); |
347 | } | 541 | } |
348 | 542 | ||
349 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.LandManagePasses)) | 543 | // don't allow passes on group owned until we can give money to groups |
544 | if (!newData.IsGroupOwned && m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.LandManagePasses, false)) | ||
350 | { | 545 | { |
351 | newData.PassHours = args.PassHours; | 546 | newData.PassHours = args.PassHours; |
352 | newData.PassPrice = args.PassPrice; | 547 | newData.PassPrice = args.PassPrice; |
@@ -354,13 +549,13 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
354 | allowedDelta |= (uint)ParcelFlags.UsePassList; | 549 | allowedDelta |= (uint)ParcelFlags.UsePassList; |
355 | } | 550 | } |
356 | 551 | ||
357 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandManageAllowed)) | 552 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandManageAllowed, false)) |
358 | { | 553 | { |
359 | allowedDelta |= (uint)(ParcelFlags.UseAccessGroup | | 554 | allowedDelta |= (uint)(ParcelFlags.UseAccessGroup | |
360 | ParcelFlags.UseAccessList); | 555 | ParcelFlags.UseAccessList); |
361 | } | 556 | } |
362 | 557 | ||
363 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandManageBanned)) | 558 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandManageBanned, false)) |
364 | { | 559 | { |
365 | allowedDelta |= (uint)(ParcelFlags.UseBanList | | 560 | allowedDelta |= (uint)(ParcelFlags.UseBanList | |
366 | ParcelFlags.DenyAnonymous | | 561 | ParcelFlags.DenyAnonymous | |
@@ -372,9 +567,16 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
372 | uint preserve = LandData.Flags & ~allowedDelta; | 567 | uint preserve = LandData.Flags & ~allowedDelta; |
373 | newData.Flags = preserve | (args.ParcelFlags & allowedDelta); | 568 | newData.Flags = preserve | (args.ParcelFlags & allowedDelta); |
374 | 569 | ||
570 | uint curdelta = LandData.Flags ^ newData.Flags; | ||
571 | curdelta &= (uint)(ParcelFlags.SoundLocal); | ||
572 | |||
573 | if(curdelta != 0 || newData.SeeAVs != LandData.SeeAVs) | ||
574 | needOverlay = true; | ||
575 | |||
375 | m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData); | 576 | m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData); |
376 | SendLandUpdateToAvatarsOverMe(snap_selection); | 577 | return true; |
377 | } | 578 | } |
579 | return false; | ||
378 | } | 580 | } |
379 | 581 | ||
380 | public void UpdateLandSold(UUID avatarID, UUID groupID, bool groupOwned, uint AuctionID, int claimprice, int area) | 582 | public void UpdateLandSold(UUID avatarID, UUID groupID, bool groupOwned, uint AuctionID, int claimprice, int area) |
@@ -395,7 +597,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
395 | UUID previousOwner = LandData.OwnerID; | 597 | UUID previousOwner = LandData.OwnerID; |
396 | 598 | ||
397 | m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData); | 599 | m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData); |
398 | m_scene.EventManager.TriggerParcelPrimCountUpdate(); | 600 | // m_scene.EventManager.TriggerParcelPrimCountUpdate(); |
399 | SendLandUpdateToAvatarsOverMe(true); | 601 | SendLandUpdateToAvatarsOverMe(true); |
400 | 602 | ||
401 | if (sellObjects) SellLandObjects(previousOwner); | 603 | if (sellObjects) SellLandObjects(previousOwner); |
@@ -431,7 +633,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
431 | 633 | ||
432 | public bool CanBeOnThisLand(UUID avatar, float posHeight) | 634 | public bool CanBeOnThisLand(UUID avatar, float posHeight) |
433 | { | 635 | { |
434 | if (posHeight < LandChannel.BAN_LINE_SAFETY_HIEGHT && IsBannedFromLand(avatar)) | 636 | if (posHeight < LandChannel.BAN_LINE_SAFETY_HEIGHT && IsBannedFromLand(avatar)) |
435 | { | 637 | { |
436 | return false; | 638 | return false; |
437 | } | 639 | } |
@@ -530,7 +732,30 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
530 | if (HasGroupAccess(avatar)) | 732 | if (HasGroupAccess(avatar)) |
531 | return false; | 733 | return false; |
532 | 734 | ||
533 | return !IsInLandAccessList(avatar); | 735 | if(IsInLandAccessList(avatar)) |
736 | return false; | ||
737 | |||
738 | // check for a NPC | ||
739 | ScenePresence sp; | ||
740 | if (!m_scene.TryGetScenePresence(avatar, out sp)) | ||
741 | return true; | ||
742 | |||
743 | if(sp==null || !sp.IsNPC) | ||
744 | return true; | ||
745 | |||
746 | INPC npccli = (INPC)sp.ControllingClient; | ||
747 | if(npccli== null) | ||
748 | return true; | ||
749 | |||
750 | UUID owner = npccli.Owner; | ||
751 | |||
752 | if(owner == UUID.Zero) | ||
753 | return true; | ||
754 | |||
755 | if (owner == LandData.OwnerID) | ||
756 | return false; | ||
757 | |||
758 | return !IsInLandAccessList(owner); | ||
534 | } | 759 | } |
535 | 760 | ||
536 | public bool IsInLandAccessList(UUID avatar) | 761 | public bool IsInLandAccessList(UUID avatar) |
@@ -568,6 +793,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
568 | 793 | ||
569 | public void SendLandUpdateToAvatarsOverMe(bool snap_selection) | 794 | public void SendLandUpdateToAvatarsOverMe(bool snap_selection) |
570 | { | 795 | { |
796 | m_scene.EventManager.TriggerParcelPrimCountUpdate(); | ||
571 | m_scene.ForEachRootScenePresence(delegate(ScenePresence avatar) | 797 | m_scene.ForEachRootScenePresence(delegate(ScenePresence avatar) |
572 | { | 798 | { |
573 | ILandObject over = null; | 799 | ILandObject over = null; |
@@ -587,13 +813,13 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
587 | { | 813 | { |
588 | if (over.LandData.LocalID == LandData.LocalID) | 814 | if (over.LandData.LocalID == LandData.LocalID) |
589 | { | 815 | { |
590 | if (((over.LandData.Flags & (uint)ParcelFlags.AllowDamage) != 0) && | 816 | if(m_scene.RegionInfo.RegionSettings.AllowDamage) |
591 | m_scene.RegionInfo.RegionSettings.AllowDamage) | ||
592 | avatar.Invulnerable = false; | 817 | avatar.Invulnerable = false; |
593 | else | 818 | else |
594 | avatar.Invulnerable = true; | 819 | avatar.Invulnerable = (over.LandData.Flags & (uint)ParcelFlags.AllowDamage) == 0; |
595 | 820 | ||
596 | SendLandUpdateToClient(snap_selection, avatar.ControllingClient); | 821 | SendLandUpdateToClient(snap_selection, avatar.ControllingClient); |
822 | avatar.currentParcelUUID = LandData.GlobalID; | ||
597 | } | 823 | } |
598 | } | 824 | } |
599 | }); | 825 | }); |
@@ -630,13 +856,13 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
630 | IClientAPI remote_client) | 856 | IClientAPI remote_client) |
631 | { | 857 | { |
632 | 858 | ||
633 | if (flags == (uint) AccessList.Access || flags == (uint) AccessList.Both) | 859 | if ((flags & (uint) AccessList.Access) != 0) |
634 | { | 860 | { |
635 | List<LandAccessEntry> accessEntries = CreateAccessListArrayByFlag(AccessList.Access); | 861 | List<LandAccessEntry> accessEntries = CreateAccessListArrayByFlag(AccessList.Access); |
636 | remote_client.SendLandAccessListData(accessEntries,(uint) AccessList.Access,LandData.LocalID); | 862 | remote_client.SendLandAccessListData(accessEntries,(uint) AccessList.Access,LandData.LocalID); |
637 | } | 863 | } |
638 | 864 | ||
639 | if (flags == (uint) AccessList.Ban || flags == (uint) AccessList.Both) | 865 | if ((flags & (uint) AccessList.Ban) != 0) |
640 | { | 866 | { |
641 | List<LandAccessEntry> accessEntries = CreateAccessListArrayByFlag(AccessList.Ban); | 867 | List<LandAccessEntry> accessEntries = CreateAccessListArrayByFlag(AccessList.Ban); |
642 | remote_client.SendLandAccessListData(accessEntries, (uint)AccessList.Ban, LandData.LocalID); | 868 | remote_client.SendLandAccessListData(accessEntries, (uint)AccessList.Ban, LandData.LocalID); |
@@ -691,6 +917,17 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
691 | newData.ParcelAccessList.Add(temp); | 917 | newData.ParcelAccessList.Add(temp); |
692 | } | 918 | } |
693 | 919 | ||
920 | // update use lists flags | ||
921 | // rights already checked or we wont be here | ||
922 | uint parcelflags = newData.Flags; | ||
923 | |||
924 | if((flags & (uint)AccessList.Access) != 0) | ||
925 | parcelflags |= (uint)ParcelFlags.UseAccessList; | ||
926 | if((flags & (uint)AccessList.Ban) != 0) | ||
927 | parcelflags |= (uint)ParcelFlags.UseBanList; | ||
928 | |||
929 | newData.Flags = parcelflags; | ||
930 | |||
694 | m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData); | 931 | m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData); |
695 | } | 932 | } |
696 | 933 | ||
@@ -708,7 +945,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
708 | /// </summary> | 945 | /// </summary> |
709 | public void ForceUpdateLandInfo() | 946 | public void ForceUpdateLandInfo() |
710 | { | 947 | { |
711 | UpdateAABBAndAreaValues(); | 948 | UpdateGeometryValues(); |
712 | UpdateLandBitmapByteArray(); | 949 | UpdateLandBitmapByteArray(); |
713 | } | 950 | } |
714 | 951 | ||
@@ -718,52 +955,117 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
718 | } | 955 | } |
719 | 956 | ||
720 | /// <summary> | 957 | /// <summary> |
721 | /// Updates the AABBMin and AABBMax values after area/shape modification of the land object | 958 | /// Updates geomtric values after area/shape modification of the land object |
722 | /// </summary> | 959 | /// </summary> |
723 | private void UpdateAABBAndAreaValues() | 960 | private void UpdateGeometryValues() |
724 | { | 961 | { |
725 | int min_x = 10000; | 962 | int min_x = Int32.MaxValue; |
726 | int min_y = 10000; | 963 | int min_y = Int32.MaxValue; |
727 | int max_x = 0; | 964 | int max_x = Int32.MinValue; |
728 | int max_y = 0; | 965 | int max_y = Int32.MinValue; |
729 | int tempArea = 0; | 966 | int tempArea = 0; |
730 | int x, y; | 967 | int x, y; |
968 | |||
969 | int lastX = 0; | ||
970 | int lastY = 0; | ||
971 | float avgx = 0f; | ||
972 | float avgy = 0f; | ||
973 | |||
974 | bool needFirst = true; | ||
975 | |||
731 | for (x = 0; x < LandBitmap.GetLength(0); x++) | 976 | for (x = 0; x < LandBitmap.GetLength(0); x++) |
732 | { | 977 | { |
733 | for (y = 0; y < LandBitmap.GetLength(1); y++) | 978 | for (y = 0; y < LandBitmap.GetLength(1); y++) |
734 | { | 979 | { |
735 | if (LandBitmap[x, y] == true) | 980 | if (LandBitmap[x, y]) |
736 | { | 981 | { |
737 | if (min_x > x) min_x = x; | 982 | if (min_x > x) |
738 | if (min_y > y) min_y = y; | 983 | min_x = x; |
739 | if (max_x < x) max_x = x; | 984 | if (min_y > y) |
740 | if (max_y < y) max_y = y; | 985 | min_y = y; |
741 | tempArea += landUnit * landUnit; //16sqm peice of land | 986 | if (max_x < x) |
987 | max_x = x; | ||
988 | if (max_y < y) | ||
989 | max_y = y; | ||
990 | |||
991 | if(needFirst) | ||
992 | { | ||
993 | avgx = x; | ||
994 | avgy = y; | ||
995 | m_startPoint.X = x * landUnit; | ||
996 | m_startPoint.Y = y * landUnit; | ||
997 | needFirst = false; | ||
998 | } | ||
999 | else | ||
1000 | { | ||
1001 | // keeping previus odd average | ||
1002 | avgx = (avgx * tempArea + x) / (tempArea + 1); | ||
1003 | avgy = (avgy * tempArea + y) / (tempArea + 1); | ||
1004 | } | ||
1005 | |||
1006 | tempArea++; | ||
1007 | |||
1008 | lastX = x; | ||
1009 | lastY = y; | ||
742 | } | 1010 | } |
743 | } | 1011 | } |
744 | } | 1012 | } |
1013 | |||
1014 | int halfunit = landUnit/2; | ||
1015 | |||
1016 | m_centerPoint.X = avgx * landUnit + halfunit; | ||
1017 | m_centerPoint.Y = avgy * landUnit + halfunit; | ||
1018 | |||
1019 | m_endPoint.X = lastX * landUnit + landUnit; | ||
1020 | m_endPoint.Y = lastY * landUnit + landUnit; | ||
1021 | |||
1022 | // next tests should not be needed | ||
1023 | // if they fail, something is wrong | ||
1024 | |||
1025 | int regionSizeX = (int)Constants.RegionSize; | ||
1026 | int regionSizeY = (int)Constants.RegionSize; | ||
1027 | |||
1028 | if(m_scene != null) | ||
1029 | { | ||
1030 | regionSizeX = (int)m_scene.RegionInfo.RegionSizeX; | ||
1031 | regionSizeY = (int)m_scene.RegionInfo.RegionSizeX; | ||
1032 | } | ||
1033 | |||
745 | int tx = min_x * landUnit; | 1034 | int tx = min_x * landUnit; |
746 | if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1)) | 1035 | if (tx >= regionSizeX) |
747 | tx = ((int)m_scene.RegionInfo.RegionSizeX - 1); | 1036 | tx = regionSizeX - 1; |
1037 | |||
748 | int ty = min_y * landUnit; | 1038 | int ty = min_y * landUnit; |
749 | if (ty > ((int)m_scene.RegionInfo.RegionSizeY - 1)) | 1039 | if (ty >= regionSizeY) |
750 | ty = ((int)m_scene.RegionInfo.RegionSizeY - 1); | 1040 | ty = regionSizeY - 1; |
751 | 1041 | ||
752 | LandData.AABBMin = | 1042 | m_AABBmin.X = tx; |
753 | new Vector3( | 1043 | m_AABBmin.Y = ty; |
754 | (float)(min_x * landUnit), (float)(min_y * landUnit), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0); | 1044 | |
1045 | if(m_scene == null || m_scene.Heightmap == null) | ||
1046 | LandData.AABBMin = new Vector3(tx, ty, 0f); | ||
1047 | else | ||
1048 | LandData.AABBMin = new Vector3(tx, ty, (float)m_scene.Heightmap[tx, ty]); | ||
755 | 1049 | ||
1050 | max_x++; | ||
756 | tx = max_x * landUnit; | 1051 | tx = max_x * landUnit; |
757 | if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1)) | 1052 | if (tx > regionSizeX) |
758 | tx = ((int)m_scene.RegionInfo.RegionSizeX - 1); | 1053 | tx = regionSizeX; |
1054 | |||
1055 | max_y++; | ||
759 | ty = max_y * landUnit; | 1056 | ty = max_y * landUnit; |
760 | if (ty > ((int)m_scene.RegionInfo.RegionSizeY - 1)) | 1057 | if (ty > regionSizeY) |
761 | ty = ((int)m_scene.RegionInfo.RegionSizeY - 1); | 1058 | ty = regionSizeY; |
1059 | |||
1060 | m_AABBmax.X = tx; | ||
1061 | m_AABBmax.Y = ty; | ||
762 | 1062 | ||
763 | LandData.AABBMax | 1063 | if(m_scene == null || m_scene.Heightmap == null) |
764 | = new Vector3( | 1064 | LandData.AABBMax = new Vector3(tx, ty, 0f); |
765 | (float)(max_x * landUnit), (float)(max_y * landUnit), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0); | 1065 | else |
1066 | LandData.AABBMax = new Vector3(tx, ty, (float)m_scene.Heightmap[tx - 1, ty - 1]); | ||
766 | 1067 | ||
1068 | tempArea *= landUnit * landUnit; | ||
767 | LandData.Area = tempArea; | 1069 | LandData.Area = tempArea; |
768 | } | 1070 | } |
769 | 1071 | ||
@@ -778,7 +1080,6 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
778 | public void SetLandBitmap(bool[,] bitmap) | 1080 | public void SetLandBitmap(bool[,] bitmap) |
779 | { | 1081 | { |
780 | LandBitmap = bitmap; | 1082 | LandBitmap = bitmap; |
781 | // m_log.DebugFormat("{0} SetLandBitmap. BitmapSize=<{1},{2}>", LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1)); | ||
782 | ForceUpdateLandInfo(); | 1083 | ForceUpdateLandInfo(); |
783 | } | 1084 | } |
784 | 1085 | ||
@@ -793,17 +1094,17 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
793 | 1094 | ||
794 | public bool[,] BasicFullRegionLandBitmap() | 1095 | public bool[,] BasicFullRegionLandBitmap() |
795 | { | 1096 | { |
796 | return GetSquareLandBitmap(0, 0, (int)m_scene.RegionInfo.RegionSizeX, (int) m_scene.RegionInfo.RegionSizeY); | 1097 | return GetSquareLandBitmap(0, 0, (int)m_scene.RegionInfo.RegionSizeX, (int) m_scene.RegionInfo.RegionSizeY, true); |
797 | } | 1098 | } |
798 | 1099 | ||
799 | public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y) | 1100 | public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y, bool set_value = true) |
800 | { | 1101 | { |
801 | // Empty bitmap for the whole region | 1102 | // Empty bitmap for the whole region |
802 | bool[,] tempBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; | 1103 | bool[,] tempBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; |
803 | tempBitmap.Initialize(); | 1104 | tempBitmap.Initialize(); |
804 | 1105 | ||
805 | // Fill the bitmap square area specified by state and end | 1106 | // Fill the bitmap square area specified by state and end |
806 | tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true); | 1107 | tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, set_value); |
807 | // m_log.DebugFormat("{0} GetSquareLandBitmap. tempBitmapSize=<{1},{2}>", | 1108 | // m_log.DebugFormat("{0} GetSquareLandBitmap. tempBitmapSize=<{1},{2}>", |
808 | // LogHeader, tempBitmap.GetLength(0), tempBitmap.GetLength(1)); | 1109 | // LogHeader, tempBitmap.GetLength(0), tempBitmap.GetLength(1)); |
809 | return tempBitmap; | 1110 | return tempBitmap; |
@@ -873,51 +1174,287 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
873 | } | 1174 | } |
874 | 1175 | ||
875 | /// <summary> | 1176 | /// <summary> |
1177 | /// Remap a land bitmap. Takes the supplied land bitmap and rotates it, crops it and finally offsets it into | ||
1178 | /// a final land bitmap of the target region size. | ||
1179 | /// </summary> | ||
1180 | /// <param name="bitmap_base">The original parcel bitmap</param> | ||
1181 | /// <param name="rotationDegrees"></param> | ||
1182 | /// <param name="displacement"><x,y,?></param> | ||
1183 | /// <param name="boundingOrigin"><x,y,?></param> | ||
1184 | /// <param name="boundingSize"><x,y,?></param> | ||
1185 | /// <param name="regionSize"><x,y,?></param> | ||
1186 | /// <param name="isEmptyNow">out: This is set if the resultant bitmap is now empty</param> | ||
1187 | /// <param name="AABBMin">out: parcel.AABBMin <x,y,0></param> | ||
1188 | /// <param name="AABBMax">out: parcel.AABBMax <x,y,0></param> | ||
1189 | /// <returns>New parcel bitmap</returns> | ||
1190 | public bool[,] RemapLandBitmap(bool[,] bitmap_base, Vector2 displacement, float rotationDegrees, Vector2 boundingOrigin, Vector2 boundingSize, Vector2 regionSize, out bool isEmptyNow, out Vector3 AABBMin, out Vector3 AABBMax) | ||
1191 | { | ||
1192 | // get the size of the incoming bitmap | ||
1193 | int baseX = bitmap_base.GetLength(0); | ||
1194 | int baseY = bitmap_base.GetLength(1); | ||
1195 | |||
1196 | // create an intermediate bitmap that is 25% bigger on each side that we can work with to handle rotations | ||
1197 | int offsetX = baseX / 4; // the original origin will now be at these coordinates so now we can have imaginary negative coordinates ;) | ||
1198 | int offsetY = baseY / 4; | ||
1199 | int tmpX = baseX + baseX / 2; | ||
1200 | int tmpY = baseY + baseY / 2; | ||
1201 | int centreX = tmpX / 2; | ||
1202 | int centreY = tmpY / 2; | ||
1203 | bool[,] bitmap_tmp = new bool[tmpX, tmpY]; | ||
1204 | |||
1205 | double radianRotation = Math.PI * rotationDegrees / 180f; | ||
1206 | double cosR = Math.Cos(radianRotation); | ||
1207 | double sinR = Math.Sin(radianRotation); | ||
1208 | if (rotationDegrees < 0f) rotationDegrees += 360f; //-90=270 -180=180 -270=90 | ||
1209 | |||
1210 | // So first we apply the rotation to the incoming bitmap, storing the result in bitmap_tmp | ||
1211 | // We special case orthogonal rotations for accuracy because even using double precision math, Math.Cos(90 degrees) is never fully 0 | ||
1212 | // and we can never rotate around a centre pixel because the bitmap size is always even | ||
1213 | int x, y, sx, sy; | ||
1214 | for (y = 0; y <= tmpY; y++) | ||
1215 | { | ||
1216 | for (x = 0; x <= tmpX; x++) | ||
1217 | { | ||
1218 | if (rotationDegrees == 0f) | ||
1219 | { | ||
1220 | sx = x - offsetX; | ||
1221 | sy = y - offsetY; | ||
1222 | } | ||
1223 | else if (rotationDegrees == 90f) | ||
1224 | { | ||
1225 | sx = y - offsetX; | ||
1226 | sy = tmpY - 1 - x - offsetY; | ||
1227 | } | ||
1228 | else if (rotationDegrees == 180f) | ||
1229 | { | ||
1230 | sx = tmpX - 1 - x - offsetX; | ||
1231 | sy = tmpY - 1 - y - offsetY; | ||
1232 | } | ||
1233 | else if (rotationDegrees == 270f) | ||
1234 | { | ||
1235 | sx = tmpX - 1 - y - offsetX; | ||
1236 | sy = x - offsetY; | ||
1237 | } | ||
1238 | else | ||
1239 | { | ||
1240 | // arbitary rotation: hmmm should I be using (centreX - 0.5) and (centreY - 0.5) and round cosR and sinR to say only 5 decimal places? | ||
1241 | sx = centreX + (int)Math.Round((((double)x - centreX) * cosR) + (((double)y - centreY) * sinR)) - offsetX; | ||
1242 | sy = centreY + (int)Math.Round((((double)y - centreY) * cosR) - (((double)x - centreX) * sinR)) - offsetY; | ||
1243 | } | ||
1244 | if (sx >= 0 && sx < baseX && sy >= 0 && sy < baseY) | ||
1245 | { | ||
1246 | try | ||
1247 | { | ||
1248 | if (bitmap_base[sx, sy]) bitmap_tmp[x, y] = true; | ||
1249 | } | ||
1250 | catch (Exception) //just in case we've still not taken care of every way the arrays might go out of bounds! ;) | ||
1251 | { | ||
1252 | m_log.DebugFormat("{0} RemapLandBitmap Rotate: Out of Bounds sx={1} sy={2} dx={3} dy={4}", LogHeader, sx, sy, x, y); | ||
1253 | } | ||
1254 | } | ||
1255 | } | ||
1256 | } | ||
1257 | |||
1258 | // We could also incorporate the next steps, bounding-rectangle and displacement in the loop above, but it's simpler to visualise if done separately | ||
1259 | // and will also make it much easier when later I want the option for maybe a circular or oval bounding shape too ;). | ||
1260 | // So... our output land bitmap must be the size of the current region but rememeber, parcel landbitmaps are landUnit metres (4x4 metres) per point, | ||
1261 | // and region sizes, boundaries and displacements are in metres so we need to scale down | ||
1262 | |||
1263 | int newX = (int)(regionSize.X / landUnit); | ||
1264 | int newY = (int)(regionSize.Y / landUnit); | ||
1265 | bool[,] bitmap_new = new bool[newX, newY]; | ||
1266 | // displacement is relative to <0,0> in the destination region and defines where the origin of the data selected by the bounding-rectangle is placed | ||
1267 | int dispX = (int)Math.Floor(displacement.X / landUnit); | ||
1268 | int dispY = (int)Math.Floor(displacement.Y / landUnit); | ||
1269 | |||
1270 | // startX/Y and endX/Y are coordinates in bitmap_tmp | ||
1271 | int startX = (int)Math.Floor(boundingOrigin.X / landUnit) + offsetX; | ||
1272 | if (startX > tmpX) startX = tmpX; | ||
1273 | if (startX < 0) startX = 0; | ||
1274 | int startY = (int)Math.Floor(boundingOrigin.Y / landUnit) + offsetY; | ||
1275 | if (startY > tmpY) startY = tmpY; | ||
1276 | if (startY < 0) startY = 0; | ||
1277 | |||
1278 | int endX = (int)Math.Floor((boundingOrigin.X + boundingSize.X) / landUnit) + offsetX; | ||
1279 | if (endX > tmpX) endX = tmpX; | ||
1280 | if (endX < 0) endX = 0; | ||
1281 | int endY = (int)Math.Floor((boundingOrigin.Y + boundingSize.Y) / landUnit) + offsetY; | ||
1282 | if (endY > tmpY) endY = tmpY; | ||
1283 | if (endY < 0) endY = 0; | ||
1284 | |||
1285 | //m_log.DebugFormat("{0} RemapLandBitmap: inSize=<{1},{2}>, disp=<{3},{4}> rot={5}, offset=<{6},{7}>, boundingStart=<{8},{9}>, boundingEnd=<{10},{11}>, cosR={12}, sinR={13}, outSize=<{14},{15}>", LogHeader, | ||
1286 | // baseX, baseY, dispX, dispY, radianRotation, offsetX, offsetY, startX, startY, endX, endY, cosR, sinR, newX, newY); | ||
1287 | |||
1288 | isEmptyNow = true; | ||
1289 | int minX = newX; | ||
1290 | int minY = newY; | ||
1291 | int maxX = 0; | ||
1292 | int maxY = 0; | ||
1293 | |||
1294 | int dx, dy; | ||
1295 | for (y = startY; y < endY; y++) | ||
1296 | { | ||
1297 | for (x = startX; x < endX; x++) | ||
1298 | { | ||
1299 | dx = x - startX + dispX; | ||
1300 | dy = y - startY + dispY; | ||
1301 | if (dx >= 0 && dx < newX && dy >= 0 && dy < newY) | ||
1302 | { | ||
1303 | try | ||
1304 | { | ||
1305 | if (bitmap_tmp[x, y]) | ||
1306 | { | ||
1307 | bitmap_new[dx, dy] = true; | ||
1308 | isEmptyNow = false; | ||
1309 | if (dx < minX) minX = dx; | ||
1310 | if (dy < minY) minY = dy; | ||
1311 | if (dx > maxX) maxX = dx; | ||
1312 | if (dy > maxY) maxY = dy; | ||
1313 | } | ||
1314 | } | ||
1315 | catch (Exception) //just in case we've still not taken care of every way the arrays might go out of bounds! ;) | ||
1316 | { | ||
1317 | m_log.DebugFormat("{0} RemapLandBitmap - Bound & Displace: Out of Bounds sx={1} sy={2} dx={3} dy={4}", LogHeader, x, y, dx, dy); | ||
1318 | } | ||
1319 | } | ||
1320 | } | ||
1321 | } | ||
1322 | if (isEmptyNow) | ||
1323 | { | ||
1324 | //m_log.DebugFormat("{0} RemapLandBitmap: Land bitmap is marked as Empty", LogHeader); | ||
1325 | minX = 0; | ||
1326 | minY = 0; | ||
1327 | } | ||
1328 | |||
1329 | AABBMin = new Vector3(minX * landUnit, minY * landUnit, 0); | ||
1330 | AABBMax = new Vector3(maxX * landUnit, maxY * landUnit, 0); | ||
1331 | return bitmap_new; | ||
1332 | } | ||
1333 | |||
1334 | /// <summary> | ||
1335 | /// Clears any parcel data in bitmap_base where there exists parcel data in bitmap_new. In other words the parcel data | ||
1336 | /// in bitmap_new takes over the space of the parcel data in bitmap_base. | ||
1337 | /// </summary> | ||
1338 | /// <param name="bitmap_base"></param> | ||
1339 | /// <param name="bitmap_new"></param> | ||
1340 | /// <param name="isEmptyNow">out: This is set if the resultant bitmap is now empty</param> | ||
1341 | /// <param name="AABBMin">out: parcel.AABBMin <x,y,0></param> | ||
1342 | /// <param name="AABBMax">out: parcel.AABBMax <x,y,0></param> | ||
1343 | /// <returns>New parcel bitmap</returns> | ||
1344 | public bool[,] RemoveFromLandBitmap(bool[,] bitmap_base, bool[,] bitmap_new, out bool isEmptyNow, out Vector3 AABBMin, out Vector3 AABBMax) | ||
1345 | { | ||
1346 | // get the size of the incoming bitmaps | ||
1347 | int baseX = bitmap_base.GetLength(0); | ||
1348 | int baseY = bitmap_base.GetLength(1); | ||
1349 | int newX = bitmap_new.GetLength(0); | ||
1350 | int newY = bitmap_new.GetLength(1); | ||
1351 | |||
1352 | if (baseX != newX || baseY != newY) | ||
1353 | { | ||
1354 | throw new Exception( | ||
1355 | String.Format("{0} RemoveFromLandBitmap: Land bitmaps are not the same size! baseX={1} baseY={2} newX={3} newY={4}", LogHeader, baseX, baseY, newX, newY)); | ||
1356 | } | ||
1357 | |||
1358 | isEmptyNow = true; | ||
1359 | int minX = baseX; | ||
1360 | int minY = baseY; | ||
1361 | int maxX = 0; | ||
1362 | int maxY = 0; | ||
1363 | |||
1364 | for (int y = 0; y < baseY; y++) | ||
1365 | { | ||
1366 | for (int x = 0; x < baseX; x++) | ||
1367 | { | ||
1368 | if (bitmap_new[x, y]) bitmap_base[x, y] = false; | ||
1369 | if (bitmap_base[x, y]) | ||
1370 | { | ||
1371 | isEmptyNow = false; | ||
1372 | if (x < minX) minX = x; | ||
1373 | if (y < minY) minY = y; | ||
1374 | if (x > maxX) maxX = x; | ||
1375 | if (y > maxY) maxY = y; | ||
1376 | } | ||
1377 | } | ||
1378 | } | ||
1379 | if (isEmptyNow) | ||
1380 | { | ||
1381 | //m_log.DebugFormat("{0} RemoveFromLandBitmap: Land bitmap is marked as Empty", LogHeader); | ||
1382 | minX = 0; | ||
1383 | minY = 0; | ||
1384 | } | ||
1385 | AABBMin = new Vector3(minX * landUnit, minY * landUnit, 0); | ||
1386 | AABBMax = new Vector3(maxX * landUnit, maxY * landUnit, 0); | ||
1387 | return bitmap_base; | ||
1388 | } | ||
1389 | |||
1390 | /// <summary> | ||
876 | /// Converts the land bitmap to a packet friendly byte array | 1391 | /// Converts the land bitmap to a packet friendly byte array |
877 | /// </summary> | 1392 | /// </summary> |
878 | /// <returns></returns> | 1393 | /// <returns></returns> |
879 | private byte[] ConvertLandBitmapToBytes() | 1394 | public byte[] ConvertLandBitmapToBytes() |
880 | { | 1395 | { |
881 | byte[] tempConvertArr = new byte[LandBitmap.GetLength(0) * LandBitmap.GetLength(1) / 8]; | 1396 | byte[] tempConvertArr = new byte[LandBitmap.GetLength(0) * LandBitmap.GetLength(1) / 8]; |
882 | byte tempByte = 0; | 1397 | |
1398 | int tempByte = 0; | ||
883 | int byteNum = 0; | 1399 | int byteNum = 0; |
884 | int i = 0; | 1400 | int mask = 1; |
885 | for (int y = 0; y < LandBitmap.GetLength(1); y++) | 1401 | for (int y = 0; y < LandBitmap.GetLength(1); y++) |
886 | { | 1402 | { |
887 | for (int x = 0; x < LandBitmap.GetLength(0); x++) | 1403 | for (int x = 0; x < LandBitmap.GetLength(0); x++) |
888 | { | 1404 | { |
889 | tempByte = Convert.ToByte(tempByte | Convert.ToByte(LandBitmap[x, y]) << (i++ % 8)); | 1405 | if (LandBitmap[x, y]) |
890 | if (i % 8 == 0) | 1406 | tempByte |= mask; |
1407 | mask = mask << 1; | ||
1408 | if (mask == 0x100) | ||
891 | { | 1409 | { |
892 | tempConvertArr[byteNum] = tempByte; | 1410 | mask = 1; |
893 | tempByte = (byte) 0; | 1411 | tempConvertArr[byteNum++] = (byte)tempByte; |
894 | i = 0; | 1412 | tempByte = 0; |
895 | byteNum++; | ||
896 | } | 1413 | } |
897 | } | 1414 | } |
898 | } | 1415 | } |
899 | // m_log.DebugFormat("{0} ConvertLandBitmapToBytes. BitmapSize=<{1},{2}>", | 1416 | |
900 | // LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1)); | 1417 | if(tempByte != 0 && byteNum < 512) |
1418 | tempConvertArr[byteNum] = (byte)tempByte; | ||
1419 | |||
901 | return tempConvertArr; | 1420 | return tempConvertArr; |
902 | } | 1421 | } |
903 | 1422 | ||
904 | private bool[,] ConvertBytesToLandBitmap() | 1423 | public bool[,] ConvertBytesToLandBitmap(bool overrideRegionSize = false) |
905 | { | 1424 | { |
906 | bool[,] tempConvertMap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; | 1425 | int bitmapLen; |
907 | tempConvertMap.Initialize(); | 1426 | int xLen; |
908 | byte tempByte = 0; | 1427 | bool[,] tempConvertMap; |
909 | // Math.Min overcomes an old bug that might have made it into the database. Only use the bytes that fit into convertMap. | ||
910 | int bitmapLen = Math.Min(LandData.Bitmap.Length, tempConvertMap.GetLength(0) * tempConvertMap.GetLength(1) / 8); | ||
911 | int xLen = (int)(m_scene.RegionInfo.RegionSizeX / landUnit); | ||
912 | 1428 | ||
913 | if (bitmapLen == 512) | 1429 | if (overrideRegionSize) |
1430 | { | ||
1431 | // Importing land parcel data from an OAR where the source region is a different size to the dest region requires us | ||
1432 | // to make a LandBitmap that's not derived from the current region's size. We use the LandData.Bitmap size in bytes | ||
1433 | // to figure out what the OAR's region dimensions are. (Is there a better way to get the src region x and y from the OAR?) | ||
1434 | // This method assumes we always will have square regions | ||
1435 | |||
1436 | bitmapLen = LandData.Bitmap.Length; | ||
1437 | xLen = (int)Math.Abs(Math.Sqrt(bitmapLen * 8)); | ||
1438 | tempConvertMap = new bool[xLen, xLen]; | ||
1439 | tempConvertMap.Initialize(); | ||
1440 | } | ||
1441 | else | ||
914 | { | 1442 | { |
915 | // Legacy bitmap being passed in. Use the legacy region size | 1443 | tempConvertMap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; |
916 | // and only set the lower area of the larger region. | 1444 | tempConvertMap.Initialize(); |
917 | xLen = (int)(Constants.RegionSize / landUnit); | 1445 | // Math.Min overcomes an old bug that might have made it into the database. Only use the bytes that fit into convertMap. |
1446 | bitmapLen = Math.Min(LandData.Bitmap.Length, tempConvertMap.GetLength(0) * tempConvertMap.GetLength(1) / 8); | ||
1447 | xLen = (int)(m_scene.RegionInfo.RegionSizeX / landUnit); | ||
1448 | if (bitmapLen == 512) | ||
1449 | { | ||
1450 | // Legacy bitmap being passed in. Use the legacy region size | ||
1451 | // and only set the lower area of the larger region. | ||
1452 | xLen = (int)(Constants.RegionSize / landUnit); | ||
1453 | } | ||
918 | } | 1454 | } |
919 | // m_log.DebugFormat("{0} ConvertBytesToLandBitmap: bitmapLen={1}, xLen={2}", LogHeader, bitmapLen, xLen); | 1455 | // m_log.DebugFormat("{0} ConvertBytesToLandBitmap: bitmapLen={1}, xLen={2}", LogHeader, bitmapLen, xLen); |
920 | 1456 | ||
1457 | byte tempByte; | ||
921 | int x = 0, y = 0; | 1458 | int x = 0, y = 0; |
922 | for (int i = 0; i < bitmapLen; i++) | 1459 | for (int i = 0; i < bitmapLen; i++) |
923 | { | 1460 | { |
@@ -945,13 +1482,39 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
945 | return tempConvertMap; | 1482 | return tempConvertMap; |
946 | } | 1483 | } |
947 | 1484 | ||
1485 | public bool IsLandBitmapEmpty(bool[,] landBitmap) | ||
1486 | { | ||
1487 | for (int y = 0; y < landBitmap.GetLength(1); y++) | ||
1488 | { | ||
1489 | for (int x = 0; x < landBitmap.GetLength(0); x++) | ||
1490 | { | ||
1491 | if (landBitmap[x, y]) return false; | ||
1492 | } | ||
1493 | } | ||
1494 | return true; | ||
1495 | } | ||
1496 | |||
1497 | public void DebugLandBitmap(bool[,] landBitmap) | ||
1498 | { | ||
1499 | m_log.InfoFormat("{0}: Map Key: #=claimed land .=unclaimed land.", LogHeader); | ||
1500 | for (int y = landBitmap.GetLength(1) - 1; y >= 0; y--) | ||
1501 | { | ||
1502 | string row = ""; | ||
1503 | for (int x = 0; x < landBitmap.GetLength(0); x++) | ||
1504 | { | ||
1505 | row += landBitmap[x, y] ? "#" : "."; | ||
1506 | } | ||
1507 | m_log.InfoFormat("{0}: {1}", LogHeader, row); | ||
1508 | } | ||
1509 | } | ||
1510 | |||
948 | #endregion | 1511 | #endregion |
949 | 1512 | ||
950 | #region Object Select and Object Owner Listing | 1513 | #region Object Select and Object Owner Listing |
951 | 1514 | ||
952 | public void SendForceObjectSelect(int local_id, int request_type, List<UUID> returnIDs, IClientAPI remote_client) | 1515 | public void SendForceObjectSelect(int local_id, int request_type, List<UUID> returnIDs, IClientAPI remote_client) |
953 | { | 1516 | { |
954 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions)) | 1517 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions, true)) |
955 | { | 1518 | { |
956 | List<uint> resultLocalIDs = new List<uint>(); | 1519 | List<uint> resultLocalIDs = new List<uint>(); |
957 | try | 1520 | try |
@@ -1001,7 +1564,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1001 | /// </param> | 1564 | /// </param> |
1002 | public void SendLandObjectOwners(IClientAPI remote_client) | 1565 | public void SendLandObjectOwners(IClientAPI remote_client) |
1003 | { | 1566 | { |
1004 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions)) | 1567 | if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions, true)) |
1005 | { | 1568 | { |
1006 | Dictionary<UUID, int> primCount = new Dictionary<UUID, int>(); | 1569 | Dictionary<UUID, int> primCount = new Dictionary<UUID, int>(); |
1007 | List<UUID> groups = new List<UUID>(); | 1570 | List<UUID> groups = new List<UUID>(); |
@@ -1009,9 +1572,9 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1009 | lock (primsOverMe) | 1572 | lock (primsOverMe) |
1010 | { | 1573 | { |
1011 | // m_log.DebugFormat( | 1574 | // m_log.DebugFormat( |
1012 | // "[LAND OBJECT]: Request for SendLandObjectOwners() from {0} with {1} known prims on region", | 1575 | // "[LAND OBJECT]: Request for SendLandObjectOwners() from {0} with {1} known prims on region", |
1013 | // remote_client.Name, primsOverMe.Count); | 1576 | // remote_client.Name, primsOverMe.Count); |
1014 | 1577 | ||
1015 | try | 1578 | try |
1016 | { | 1579 | { |
1017 | foreach (SceneObjectGroup obj in primsOverMe) | 1580 | foreach (SceneObjectGroup obj in primsOverMe) |
@@ -1052,7 +1615,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1052 | public Dictionary<UUID, int> GetLandObjectOwners() | 1615 | public Dictionary<UUID, int> GetLandObjectOwners() |
1053 | { | 1616 | { |
1054 | Dictionary<UUID, int> ownersAndCount = new Dictionary<UUID, int>(); | 1617 | Dictionary<UUID, int> ownersAndCount = new Dictionary<UUID, int>(); |
1055 | 1618 | ||
1056 | lock (primsOverMe) | 1619 | lock (primsOverMe) |
1057 | { | 1620 | { |
1058 | try | 1621 | try |
@@ -1106,8 +1669,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1106 | { | 1669 | { |
1107 | foreach (SceneObjectGroup obj in primsOverMe) | 1670 | foreach (SceneObjectGroup obj in primsOverMe) |
1108 | { | 1671 | { |
1109 | if (obj.OwnerID == previousOwner && obj.GroupID == UUID.Zero && | 1672 | if(m_scene.Permissions.CanSellObject(previousOwner,obj, (byte)SaleType.Original)) |
1110 | (obj.GetEffectivePermissions() & (uint)(OpenSim.Framework.PermissionMask.Transfer)) != 0) | ||
1111 | m_BuySellModule.BuyObject(sp.ControllingClient, UUID.Zero, obj.LocalId, 1, 0); | 1673 | m_BuySellModule.BuyObject(sp.ControllingClient, UUID.Zero, obj.LocalId, 1, 0); |
1112 | } | 1674 | } |
1113 | } | 1675 | } |
@@ -1121,14 +1683,14 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1121 | { | 1683 | { |
1122 | SceneObjectGroup[] objs = new SceneObjectGroup[1]; | 1684 | SceneObjectGroup[] objs = new SceneObjectGroup[1]; |
1123 | objs[0] = obj; | 1685 | objs[0] = obj; |
1124 | m_scene.returnObjects(objs, obj.OwnerID); | 1686 | m_scene.returnObjects(objs, null); |
1125 | } | 1687 | } |
1126 | 1688 | ||
1127 | public void ReturnLandObjects(uint type, UUID[] owners, UUID[] tasks, IClientAPI remote_client) | 1689 | public void ReturnLandObjects(uint type, UUID[] owners, UUID[] tasks, IClientAPI remote_client) |
1128 | { | 1690 | { |
1129 | // m_log.DebugFormat( | 1691 | // m_log.DebugFormat( |
1130 | // "[LAND OBJECT]: Request to return objects in {0} from {1}", LandData.Name, remote_client.Name); | 1692 | // "[LAND OBJECT]: Request to return objects in {0} from {1}", LandData.Name, remote_client.Name); |
1131 | 1693 | ||
1132 | Dictionary<UUID,List<SceneObjectGroup>> returns = new Dictionary<UUID,List<SceneObjectGroup>>(); | 1694 | Dictionary<UUID,List<SceneObjectGroup>> returns = new Dictionary<UUID,List<SceneObjectGroup>>(); |
1133 | 1695 | ||
1134 | lock (primsOverMe) | 1696 | lock (primsOverMe) |
@@ -1152,6 +1714,8 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1152 | { | 1714 | { |
1153 | if (obj.GroupID == LandData.GroupID) | 1715 | if (obj.GroupID == LandData.GroupID) |
1154 | { | 1716 | { |
1717 | if (obj.OwnerID == LandData.OwnerID) | ||
1718 | continue; | ||
1155 | if (!returns.ContainsKey(obj.OwnerID)) | 1719 | if (!returns.ContainsKey(obj.OwnerID)) |
1156 | returns[obj.OwnerID] = | 1720 | returns[obj.OwnerID] = |
1157 | new List<SceneObjectGroup>(); | 1721 | new List<SceneObjectGroup>(); |
@@ -1193,8 +1757,8 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1193 | 1757 | ||
1194 | foreach (List<SceneObjectGroup> ol in returns.Values) | 1758 | foreach (List<SceneObjectGroup> ol in returns.Values) |
1195 | { | 1759 | { |
1196 | if (m_scene.Permissions.CanReturnObjects(this, remote_client.AgentId, ol)) | 1760 | if (m_scene.Permissions.CanReturnObjects(this, remote_client, ol)) |
1197 | m_scene.returnObjects(ol.ToArray(), remote_client.AgentId); | 1761 | m_scene.returnObjects(ol.ToArray(), remote_client); |
1198 | } | 1762 | } |
1199 | } | 1763 | } |
1200 | 1764 | ||
@@ -1211,7 +1775,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1211 | public void AddPrimOverMe(SceneObjectGroup obj) | 1775 | public void AddPrimOverMe(SceneObjectGroup obj) |
1212 | { | 1776 | { |
1213 | // m_log.DebugFormat("[LAND OBJECT]: Adding scene object {0} {1} over {2}", obj.Name, obj.LocalId, LandData.Name); | 1777 | // m_log.DebugFormat("[LAND OBJECT]: Adding scene object {0} {1} over {2}", obj.Name, obj.LocalId, LandData.Name); |
1214 | 1778 | ||
1215 | lock (primsOverMe) | 1779 | lock (primsOverMe) |
1216 | primsOverMe.Add(obj); | 1780 | primsOverMe.Add(obj); |
1217 | } | 1781 | } |
@@ -1219,13 +1783,13 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1219 | public void RemovePrimFromOverMe(SceneObjectGroup obj) | 1783 | public void RemovePrimFromOverMe(SceneObjectGroup obj) |
1220 | { | 1784 | { |
1221 | // m_log.DebugFormat("[LAND OBJECT]: Removing scene object {0} {1} from over {2}", obj.Name, obj.LocalId, LandData.Name); | 1785 | // m_log.DebugFormat("[LAND OBJECT]: Removing scene object {0} {1} from over {2}", obj.Name, obj.LocalId, LandData.Name); |
1222 | 1786 | ||
1223 | lock (primsOverMe) | 1787 | lock (primsOverMe) |
1224 | primsOverMe.Remove(obj); | 1788 | primsOverMe.Remove(obj); |
1225 | } | 1789 | } |
1226 | 1790 | ||
1227 | #endregion | 1791 | #endregion |
1228 | 1792 | ||
1229 | /// <summary> | 1793 | /// <summary> |
1230 | /// Set the media url for this land parcel | 1794 | /// Set the media url for this land parcel |
1231 | /// </summary> | 1795 | /// </summary> |
@@ -1233,9 +1797,10 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1233 | public void SetMediaUrl(string url) | 1797 | public void SetMediaUrl(string url) |
1234 | { | 1798 | { |
1235 | LandData.MediaURL = url; | 1799 | LandData.MediaURL = url; |
1800 | m_scene.LandChannel.UpdateLandObject(LandData.LocalID, LandData); | ||
1236 | SendLandUpdateToAvatarsOverMe(); | 1801 | SendLandUpdateToAvatarsOverMe(); |
1237 | } | 1802 | } |
1238 | 1803 | ||
1239 | /// <summary> | 1804 | /// <summary> |
1240 | /// Set the music url for this land parcel | 1805 | /// Set the music url for this land parcel |
1241 | /// </summary> | 1806 | /// </summary> |
@@ -1243,6 +1808,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1243 | public void SetMusicUrl(string url) | 1808 | public void SetMusicUrl(string url) |
1244 | { | 1809 | { |
1245 | LandData.MusicURL = url; | 1810 | LandData.MusicURL = url; |
1811 | m_scene.LandChannel.UpdateLandObject(LandData.LocalID, LandData); | ||
1246 | SendLandUpdateToAvatarsOverMe(); | 1812 | SendLandUpdateToAvatarsOverMe(); |
1247 | } | 1813 | } |
1248 | 1814 | ||
@@ -1257,6 +1823,48 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1257 | 1823 | ||
1258 | #endregion | 1824 | #endregion |
1259 | 1825 | ||
1826 | private void OnFrame() | ||
1827 | { | ||
1828 | m_expiryCounter++; | ||
1829 | |||
1830 | if (m_expiryCounter >= 50) | ||
1831 | { | ||
1832 | ExpireAccessList(); | ||
1833 | m_expiryCounter = 0; | ||
1834 | } | ||
1835 | |||
1836 | // need to update dwell here bc landdata has no parent info | ||
1837 | if(LandData != null && m_dwellModule != null) | ||
1838 | { | ||
1839 | double now = Util.GetTimeStampMS(); | ||
1840 | double elapsed = now - LandData.LastDwellTimeMS; | ||
1841 | if(elapsed > 150000) //2.5 minutes resolution / throttle | ||
1842 | { | ||
1843 | float dwell = LandData.Dwell; | ||
1844 | double cur = dwell * 60000.0; | ||
1845 | double decay = 1.5e-8 * cur * elapsed; | ||
1846 | cur -= decay; | ||
1847 | if(cur < 0) | ||
1848 | cur = 0; | ||
1849 | |||
1850 | UUID lgid = LandData.GlobalID; | ||
1851 | m_scene.ForEachRootScenePresence(delegate(ScenePresence sp) | ||
1852 | { | ||
1853 | if(sp.IsNPC || sp.IsLoggingIn || sp.IsDeleted || sp.currentParcelUUID != lgid) | ||
1854 | return; | ||
1855 | cur += (now - sp.ParcelDwellTickMS); | ||
1856 | sp.ParcelDwellTickMS = now; | ||
1857 | }); | ||
1858 | |||
1859 | float newdwell = (float)(cur * 1.666666666667e-5); | ||
1860 | LandData.Dwell = newdwell; | ||
1861 | |||
1862 | if(Math.Abs(newdwell - dwell) >= 0.9) | ||
1863 | m_scene.EventManager.TriggerLandObjectAdded(this); | ||
1864 | } | ||
1865 | } | ||
1866 | } | ||
1867 | |||
1260 | private void ExpireAccessList() | 1868 | private void ExpireAccessList() |
1261 | { | 1869 | { |
1262 | List<LandAccessEntry> delete = new List<LandAccessEntry>(); | 1870 | List<LandAccessEntry> delete = new List<LandAccessEntry>(); |
@@ -1267,7 +1875,22 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1267 | delete.Add(entry); | 1875 | delete.Add(entry); |
1268 | } | 1876 | } |
1269 | foreach (LandAccessEntry entry in delete) | 1877 | foreach (LandAccessEntry entry in delete) |
1878 | { | ||
1270 | LandData.ParcelAccessList.Remove(entry); | 1879 | LandData.ParcelAccessList.Remove(entry); |
1880 | ScenePresence presence; | ||
1881 | |||
1882 | if (m_scene.TryGetScenePresence(entry.AgentID, out presence) && (!presence.IsChildAgent)) | ||
1883 | { | ||
1884 | ILandObject land = m_scene.LandChannel.GetLandObject(presence.AbsolutePosition.X, presence.AbsolutePosition.Y); | ||
1885 | if (land.LandData.LocalID == LandData.LocalID) | ||
1886 | { | ||
1887 | Vector3 pos = m_scene.GetNearestAllowedPosition(presence, land); | ||
1888 | presence.TeleportOnEject(pos); | ||
1889 | presence.ControllingClient.SendAlertMessage("You have been ejected from this land"); | ||
1890 | } | ||
1891 | } | ||
1892 | m_log.DebugFormat("[LAND]: Removing entry {0} because it has expired", entry.AgentID); | ||
1893 | } | ||
1271 | 1894 | ||
1272 | if (delete.Count > 0) | 1895 | if (delete.Count > 0) |
1273 | m_scene.EventManager.TriggerLandObjectUpdated((uint)LandData.LocalID, this); | 1896 | m_scene.EventManager.TriggerLandObjectUpdated((uint)LandData.LocalID, this); |