diff options
Diffstat (limited to 'OpenSim/Region/CoreModules')
33 files changed, 1511 insertions, 970 deletions
diff --git a/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs b/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs index d9b0eff..732781a 100644 --- a/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs +++ b/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Drawing; | ||
30 | using System.IO; | 31 | using System.IO; |
31 | using System.Reflection; | 32 | using System.Reflection; |
32 | using System.Text; | 33 | using System.Text; |
@@ -182,6 +183,25 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender | |||
182 | return DoJ2KDecode(assetID, j2kData, out layers, out components); | 183 | return DoJ2KDecode(assetID, j2kData, out layers, out components); |
183 | } | 184 | } |
184 | 185 | ||
186 | public Image DecodeToImage(byte[] j2kData) | ||
187 | { | ||
188 | if (m_useCSJ2K) | ||
189 | return J2kImage.FromBytes(j2kData); | ||
190 | else | ||
191 | { | ||
192 | ManagedImage mimage; | ||
193 | Image image; | ||
194 | if (OpenJPEG.DecodeToImage(j2kData, out mimage, out image)) | ||
195 | { | ||
196 | mimage = null; | ||
197 | return image; | ||
198 | } | ||
199 | else | ||
200 | return null; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | |||
185 | #endregion IJ2KDecoder | 205 | #endregion IJ2KDecoder |
186 | 206 | ||
187 | /// <summary> | 207 | /// <summary> |
diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs index 27ace68..10122e6 100644 --- a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs | |||
@@ -189,8 +189,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat | |||
189 | string message = c.Message; | 189 | string message = c.Message; |
190 | Scene scene = (Scene)c.Scene; | 190 | Scene scene = (Scene)c.Scene; |
191 | Vector3 fromPos = c.Position; | 191 | Vector3 fromPos = c.Position; |
192 | Vector3 regionPos = new Vector3(scene.RegionInfo.RegionLocX * Constants.RegionSize, | 192 | Vector3 regionPos = new Vector3(scene.RegionInfo.WorldLocX, scene.RegionInfo.WorldLocY, 0); |
193 | scene.RegionInfo.RegionLocY * Constants.RegionSize, 0); | ||
194 | 193 | ||
195 | if (c.Channel == DEBUG_CHANNEL) c.Type = ChatTypeEnum.DebugChannel; | 194 | if (c.Channel == DEBUG_CHANNEL) c.Type = ChatTypeEnum.DebugChannel; |
196 | 195 | ||
@@ -342,8 +341,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat | |||
342 | { | 341 | { |
343 | Vector3 fromRegionPos = fromPos + regionPos; | 342 | Vector3 fromRegionPos = fromPos + regionPos; |
344 | Vector3 toRegionPos = presence.AbsolutePosition + | 343 | Vector3 toRegionPos = presence.AbsolutePosition + |
345 | new Vector3(presence.Scene.RegionInfo.RegionLocX * Constants.RegionSize, | 344 | new Vector3(presence.Scene.RegionInfo.WorldLocX, presence.Scene.RegionInfo.WorldLocY, 0); |
346 | presence.Scene.RegionInfo.RegionLocY * Constants.RegionSize, 0); | ||
347 | 345 | ||
348 | int dis = (int)Util.GetDistanceTo(toRegionPos, fromRegionPos); | 346 | int dis = (int)Util.GetDistanceTo(toRegionPos, fromRegionPos); |
349 | 347 | ||
diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index bfa30e6..7e50cc6 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs | |||
@@ -667,8 +667,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles | |||
667 | 667 | ||
668 | Vector3 avaPos = p.AbsolutePosition; | 668 | Vector3 avaPos = p.AbsolutePosition; |
669 | // Getting the global position for the Avatar | 669 | // Getting the global position for the Avatar |
670 | Vector3 posGlobal = new Vector3(remoteClient.Scene.RegionInfo.RegionLocX*Constants.RegionSize + avaPos.X, | 670 | Vector3 posGlobal = new Vector3(remoteClient.Scene.RegionInfo.WorldLocX + avaPos.X, |
671 | remoteClient.Scene.RegionInfo.RegionLocY*Constants.RegionSize + avaPos.Y, | 671 | remoteClient.Scene.RegionInfo.WorldLocY + avaPos.Y, |
672 | avaPos.Z); | 672 | avaPos.Z); |
673 | 673 | ||
674 | string landOwnerName = string.Empty; | 674 | string landOwnerName = string.Empty; |
diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs index 6545a99..13cc99a 100644 --- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs | |||
@@ -269,9 +269,7 @@ namespace OpenSim.Region.CoreModules.Framework | |||
269 | foreach (KeyValuePair<ulong, string> kvp in m_childrenSeeds[agentID]) | 269 | foreach (KeyValuePair<ulong, string> kvp in m_childrenSeeds[agentID]) |
270 | { | 270 | { |
271 | uint x, y; | 271 | uint x, y; |
272 | Utils.LongToUInts(kvp.Key, out x, out y); | 272 | Util.RegionHandleToRegionLoc(kvp.Key, out x, out y); |
273 | x = x / Constants.RegionSize; | ||
274 | y = y / Constants.RegionSize; | ||
275 | m_log.Info(" >> "+x+", "+y+": "+kvp.Value); | 273 | m_log.Info(" >> "+x+", "+y+": "+kvp.Value); |
276 | } | 274 | } |
277 | } | 275 | } |
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 5fea0cf..85e8159 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | |||
@@ -51,7 +51,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
51 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "EntityTransferModule")] | 51 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "EntityTransferModule")] |
52 | public class EntityTransferModule : INonSharedRegionModule, IEntityTransferModule | 52 | public class EntityTransferModule : INonSharedRegionModule, IEntityTransferModule |
53 | { | 53 | { |
54 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 54 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
55 | private static readonly string LogHeader = "[ENTITY TRANSFER MODULE]"; | 55 | private static readonly string LogHeader = "[ENTITY TRANSFER MODULE]"; |
56 | 56 | ||
57 | public const int DefaultMaxTransferDistance = 4095; | 57 | public const int DefaultMaxTransferDistance = 4095; |
@@ -121,8 +121,53 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
121 | /// </summary> | 121 | /// </summary> |
122 | private EntityTransferStateMachine m_entityTransferStateMachine; | 122 | private EntityTransferStateMachine m_entityTransferStateMachine; |
123 | 123 | ||
124 | private ExpiringCache<UUID, ExpiringCache<ulong, DateTime>> m_bannedRegions = | 124 | // For performance, we keed a cached of banned regions so we don't keep going |
125 | new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>(); | 125 | // to the grid service. |
126 | private class BannedRegionCache | ||
127 | { | ||
128 | private ExpiringCache<UUID, ExpiringCache<ulong, DateTime>> m_bannedRegions = | ||
129 | new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>(); | ||
130 | ExpiringCache<ulong, DateTime> m_idCache; | ||
131 | DateTime m_banUntil; | ||
132 | public BannedRegionCache() | ||
133 | { | ||
134 | } | ||
135 | // Return 'true' if there is a valid ban entry for this agent in this region | ||
136 | public bool IfBanned(ulong pRegionHandle, UUID pAgentID) | ||
137 | { | ||
138 | bool ret = false; | ||
139 | if (m_bannedRegions.TryGetValue(pAgentID, out m_idCache)) | ||
140 | { | ||
141 | if (m_idCache.TryGetValue(pRegionHandle, out m_banUntil)) | ||
142 | { | ||
143 | if (DateTime.Now < m_banUntil) | ||
144 | { | ||
145 | ret = true; | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | return ret; | ||
150 | } | ||
151 | // Add this agent in this region as a banned person | ||
152 | public void Add(ulong pRegionHandle, UUID pAgentID) | ||
153 | { | ||
154 | if (!m_bannedRegions.TryGetValue(pAgentID, out m_idCache)) | ||
155 | { | ||
156 | m_idCache = new ExpiringCache<ulong, DateTime>(); | ||
157 | m_bannedRegions.Add(pAgentID, m_idCache, TimeSpan.FromSeconds(45)); | ||
158 | } | ||
159 | m_idCache.Add(pRegionHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15)); | ||
160 | } | ||
161 | // Remove the agent from the region's banned list | ||
162 | public void Remove(ulong pRegionHandle, UUID pAgentID) | ||
163 | { | ||
164 | if (m_bannedRegions.TryGetValue(pAgentID, out m_idCache)) | ||
165 | { | ||
166 | m_idCache.Remove(pRegionHandle); | ||
167 | } | ||
168 | } | ||
169 | } | ||
170 | private BannedRegionCache m_bannedRegionCache = new BannedRegionCache(); | ||
126 | 171 | ||
127 | private IEventQueue m_eqModule; | 172 | private IEventQueue m_eqModule; |
128 | private IRegionCombinerModule m_regionCombinerModule; | 173 | private IRegionCombinerModule m_regionCombinerModule; |
@@ -337,6 +382,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
337 | "[ENTITY TRANSFER MODULE]: Received teleport cancel request from {0} in {1}", client.Name, Scene.Name); | 382 | "[ENTITY TRANSFER MODULE]: Received teleport cancel request from {0} in {1}", client.Name, Scene.Name); |
338 | } | 383 | } |
339 | 384 | ||
385 | // Attempt to teleport the ScenePresence to the specified position in the specified region (spec'ed by its handle). | ||
340 | public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) | 386 | public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) |
341 | { | 387 | { |
342 | if (sp.Scene.Permissions.IsGridGod(sp.UUID)) | 388 | if (sp.Scene.Permissions.IsGridGod(sp.UUID)) |
@@ -434,10 +480,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
434 | float posZLimit = 22; | 480 | float posZLimit = 22; |
435 | 481 | ||
436 | // TODO: Check other Scene HeightField | 482 | // TODO: Check other Scene HeightField |
437 | if (position.X > 0 && position.X <= (int)Constants.RegionSize && position.Y > 0 && position.Y <= (int)Constants.RegionSize) | 483 | posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y]; |
438 | { | ||
439 | posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y]; | ||
440 | } | ||
441 | 484 | ||
442 | float newPosZ = posZLimit + localAVHeight; | 485 | float newPosZ = posZLimit + localAVHeight; |
443 | if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) | 486 | if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) |
@@ -481,7 +524,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
481 | Vector3 lookAt, uint teleportFlags, out GridRegion finalDestination) | 524 | Vector3 lookAt, uint teleportFlags, out GridRegion finalDestination) |
482 | { | 525 | { |
483 | uint x = 0, y = 0; | 526 | uint x = 0, y = 0; |
484 | Utils.LongToUInts(regionHandle, out x, out y); | 527 | Util.RegionHandleToWorldLoc(regionHandle, out x, out y); |
485 | GridRegion reg = Scene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); | 528 | GridRegion reg = Scene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); |
486 | 529 | ||
487 | if (reg != null) | 530 | if (reg != null) |
@@ -490,9 +533,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
490 | 533 | ||
491 | if (finalDestination == null) | 534 | if (finalDestination == null) |
492 | { | 535 | { |
493 | m_log.WarnFormat( | 536 | m_log.WarnFormat( "{0} Final destination is having problems. Unable to teleport {1} {2}", |
494 | "[ENTITY TRANSFER MODULE]: Final destination is having problems. Unable to teleport {0} {1}", | 537 | LogHeader, sp.Name, sp.UUID); |
495 | sp.Name, sp.UUID); | ||
496 | 538 | ||
497 | sp.ControllingClient.SendTeleportFailed("Problem at destination"); | 539 | sp.ControllingClient.SendTeleportFailed("Problem at destination"); |
498 | return; | 540 | return; |
@@ -533,11 +575,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
533 | 575 | ||
534 | // and set the map-tile to '(Offline)' | 576 | // and set the map-tile to '(Offline)' |
535 | uint regX, regY; | 577 | uint regX, regY; |
536 | Utils.LongToUInts(regionHandle, out regX, out regY); | 578 | Util.RegionHandleToRegionLoc(regionHandle, out regX, out regY); |
537 | 579 | ||
538 | MapBlockData block = new MapBlockData(); | 580 | MapBlockData block = new MapBlockData(); |
539 | block.X = (ushort)(regX / Constants.RegionSize); | 581 | block.X = (ushort)regX; |
540 | block.Y = (ushort)(regY / Constants.RegionSize); | 582 | block.Y = (ushort)regY; |
541 | block.Access = 254; // == not there | 583 | block.Access = 254; // == not there |
542 | 584 | ||
543 | List<MapBlockData> blocks = new List<MapBlockData>(); | 585 | List<MapBlockData> blocks = new List<MapBlockData>(); |
@@ -1349,6 +1391,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1349 | if (uinfo.HomeRegionID == UUID.Zero) | 1391 | if (uinfo.HomeRegionID == UUID.Zero) |
1350 | { | 1392 | { |
1351 | // can't find the Home region: Tell viewer and abort | 1393 | // can't find the Home region: Tell viewer and abort |
1394 | m_log.ErrorFormat("{0} No grid user info found for {1} {2}. Cannot send home.", | ||
1395 | LogHeader, client.Name, client.AgentId); | ||
1352 | client.SendTeleportFailed("You don't have a home position set."); | 1396 | client.SendTeleportFailed("You don't have a home position set."); |
1353 | return false; | 1397 | return false; |
1354 | } | 1398 | } |
@@ -1382,7 +1426,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1382 | 1426 | ||
1383 | #region Agent Crossings | 1427 | #region Agent Crossings |
1384 | 1428 | ||
1385 | public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, out uint xDest, out uint yDest, out string version, out Vector3 newpos) | 1429 | // Given a position relative to the current region (which has previously been tested to |
1430 | // see that it is actually outside the current region), find the new region that the | ||
1431 | // point is actually in. | ||
1432 | // Returns the coordinates and information of the new region or 'null' of it doesn't exist. | ||
1433 | public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, out string version, out Vector3 newpos) | ||
1386 | { | 1434 | { |
1387 | version = String.Empty; | 1435 | version = String.Empty; |
1388 | newpos = pos; | 1436 | newpos = pos; |
@@ -1390,131 +1438,54 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1390 | // m_log.DebugFormat( | 1438 | // m_log.DebugFormat( |
1391 | // "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name); | 1439 | // "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name); |
1392 | 1440 | ||
1393 | uint neighbourx = scene.RegionInfo.RegionLocX; | 1441 | // Compute world location of the object's position |
1394 | uint neighboury = scene.RegionInfo.RegionLocY; | 1442 | double presenceWorldX = (double)scene.RegionInfo.WorldLocX + pos.X; |
1395 | const float boundaryDistance = 1.7f; | 1443 | double presenceWorldY = (double)scene.RegionInfo.WorldLocY + pos.Y; |
1396 | Vector3 northCross = new Vector3(0, boundaryDistance, 0); | ||
1397 | Vector3 southCross = new Vector3(0, -1 * boundaryDistance, 0); | ||
1398 | Vector3 eastCross = new Vector3(boundaryDistance, 0, 0); | ||
1399 | Vector3 westCross = new Vector3(-1 * boundaryDistance, 0, 0); | ||
1400 | 1444 | ||
1401 | // distance into new region to place avatar | 1445 | // Call the grid service to lookup the region containing the new position. |
1402 | const float enterDistance = 0.5f; | 1446 | GridRegion neighbourRegion = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID, |
1447 | presenceWorldX, presenceWorldY, | ||
1448 | Math.Max(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY)); | ||
1403 | 1449 | ||
1404 | if (scene.TestBorderCross(pos + westCross, Cardinals.W)) | 1450 | if (neighbourRegion != null) |
1405 | { | 1451 | { |
1406 | if (scene.TestBorderCross(pos + northCross, Cardinals.N)) | 1452 | // Compute the entity's position relative to the new region |
1407 | { | 1453 | newpos = new Vector3( (float)(presenceWorldX - (double)neighbourRegion.RegionLocX), |
1408 | Border b = scene.GetCrossedBorder(pos + northCross, Cardinals.N); | 1454 | (float)(presenceWorldY - (double)neighbourRegion.RegionLocY), |
1409 | neighboury += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize); | 1455 | pos.Z); |
1410 | } | ||
1411 | else if (scene.TestBorderCross(pos + southCross, Cardinals.S)) | ||
1412 | { | ||
1413 | neighboury--; | ||
1414 | newpos.Y = Constants.RegionSize - enterDistance; | ||
1415 | } | ||
1416 | |||
1417 | neighbourx--; | ||
1418 | newpos.X = Constants.RegionSize - enterDistance; | ||
1419 | } | ||
1420 | else if (scene.TestBorderCross(pos + eastCross, Cardinals.E)) | ||
1421 | { | ||
1422 | Border b = scene.GetCrossedBorder(pos + eastCross, Cardinals.E); | ||
1423 | neighbourx += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize); | ||
1424 | newpos.X = enterDistance; | ||
1425 | 1456 | ||
1426 | if (scene.TestBorderCross(pos + southCross, Cardinals.S)) | 1457 | if (m_bannedRegionCache.IfBanned(neighbourRegion.RegionHandle, agentID)) |
1427 | { | 1458 | { |
1428 | neighboury--; | 1459 | neighbourRegion = null; |
1429 | newpos.Y = Constants.RegionSize - enterDistance; | ||
1430 | } | 1460 | } |
1431 | else if (scene.TestBorderCross(pos + northCross, Cardinals.N)) | 1461 | else |
1432 | { | 1462 | { |
1433 | Border c = scene.GetCrossedBorder(pos + northCross, Cardinals.N); | 1463 | // If not banned, make sure this agent is not in the list. |
1434 | neighboury += (uint)(int)(c.BorderLine.Z / (int)Constants.RegionSize); | 1464 | m_bannedRegionCache.Remove(neighbourRegion.RegionHandle, agentID); |
1435 | newpos.Y = enterDistance; | ||
1436 | } | 1465 | } |
1437 | } | ||
1438 | else if (scene.TestBorderCross(pos + southCross, Cardinals.S)) | ||
1439 | { | ||
1440 | Border b = scene.GetCrossedBorder(pos + southCross, Cardinals.S); | ||
1441 | neighboury--; | ||
1442 | newpos.Y = Constants.RegionSize - enterDistance; | ||
1443 | } | ||
1444 | else if (scene.TestBorderCross(pos + northCross, Cardinals.N)) | ||
1445 | { | ||
1446 | Border b = scene.GetCrossedBorder(pos + northCross, Cardinals.N); | ||
1447 | neighboury += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize); | ||
1448 | newpos.Y = enterDistance; | ||
1449 | } | ||
1450 | |||
1451 | /* | ||
1452 | |||
1453 | if (pos.X < boundaryDistance) //West | ||
1454 | { | ||
1455 | neighbourx--; | ||
1456 | newpos.X = Constants.RegionSize - enterDistance; | ||
1457 | } | ||
1458 | else if (pos.X > Constants.RegionSize - boundaryDistance) // East | ||
1459 | { | ||
1460 | neighbourx++; | ||
1461 | newpos.X = enterDistance; | ||
1462 | } | ||
1463 | |||
1464 | if (pos.Y < boundaryDistance) // South | ||
1465 | { | ||
1466 | neighboury--; | ||
1467 | newpos.Y = Constants.RegionSize - enterDistance; | ||
1468 | } | ||
1469 | else if (pos.Y > Constants.RegionSize - boundaryDistance) // North | ||
1470 | { | ||
1471 | neighboury++; | ||
1472 | newpos.Y = enterDistance; | ||
1473 | } | ||
1474 | */ | ||
1475 | |||
1476 | xDest = neighbourx; | ||
1477 | yDest = neighboury; | ||
1478 | |||
1479 | int x = (int)(neighbourx * Constants.RegionSize), y = (int)(neighboury * Constants.RegionSize); | ||
1480 | 1466 | ||
1481 | ulong neighbourHandle = Utils.UIntsToLong((uint)x, (uint)y); | 1467 | // Check to see if we have access to the target region. |
1482 | 1468 | string reason; | |
1483 | ExpiringCache<ulong, DateTime> r; | 1469 | if (neighbourRegion != null |
1484 | DateTime banUntil; | 1470 | && !scene.SimulationService.QueryAccess(neighbourRegion, agentID, newpos, out version, out reason)) |
1485 | |||
1486 | if (m_bannedRegions.TryGetValue(agentID, out r)) | ||
1487 | { | ||
1488 | if (r.TryGetValue(neighbourHandle, out banUntil)) | ||
1489 | { | 1471 | { |
1490 | if (DateTime.Now < banUntil) | 1472 | // remember banned |
1491 | return null; | 1473 | m_bannedRegionCache.Add(neighbourRegion.RegionHandle, agentID); |
1492 | r.Remove(neighbourHandle); | 1474 | neighbourRegion = null; |
1493 | } | 1475 | } |
1494 | } | 1476 | } |
1495 | else | ||
1496 | { | ||
1497 | r = null; | ||
1498 | } | ||
1499 | |||
1500 | GridRegion neighbourRegion = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID, (int)x, (int)y); | ||
1501 | 1477 | ||
1502 | string reason; | 1478 | if (neighbourRegion == null) |
1503 | if (!scene.SimulationService.QueryAccess(neighbourRegion, agentID, newpos, out version, out reason)) | 1479 | m_log.DebugFormat("{0} GetDestination: region not found. Old region name={1} at <{2},{3}> of size <{4},{5}>. Old pos={6}", |
1504 | { | 1480 | LogHeader, scene.RegionInfo.RegionName, |
1505 | if (r == null) | 1481 | scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY, |
1506 | { | 1482 | scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY, |
1507 | r = new ExpiringCache<ulong, DateTime>(); | 1483 | pos); |
1508 | r.Add(neighbourHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15)); | 1484 | else |
1509 | 1485 | m_log.DebugFormat("{0} GetDestination: new region={1} at <{2},{3}> of size <{4},{5}>, newpos=<{6},{7}>", | |
1510 | m_bannedRegions.Add(agentID, r, TimeSpan.FromSeconds(45)); | 1486 | LogHeader, neighbourRegion.RegionName, |
1511 | } | 1487 | neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY, |
1512 | else | 1488 | newpos.X, newpos.Y); |
1513 | { | ||
1514 | r.Add(neighbourHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15)); | ||
1515 | } | ||
1516 | return null; | ||
1517 | } | ||
1518 | 1489 | ||
1519 | return neighbourRegion; | 1490 | return neighbourRegion; |
1520 | } | 1491 | } |
@@ -1526,7 +1497,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1526 | Vector3 newpos; | 1497 | Vector3 newpos; |
1527 | string version; | 1498 | string version; |
1528 | 1499 | ||
1529 | GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, agent.AbsolutePosition, out x, out y, out version, out newpos); | 1500 | GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, agent.AbsolutePosition, out version, out newpos); |
1530 | if (neighbourRegion == null) | 1501 | if (neighbourRegion == null) |
1531 | { | 1502 | { |
1532 | agent.ControllingClient.SendAlertMessage("Cannot region cross into banned parcel"); | 1503 | agent.ControllingClient.SendAlertMessage("Cannot region cross into banned parcel"); |
@@ -1568,7 +1539,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1568 | 1539 | ||
1569 | agent.Scene.RequestTeleportLocation( | 1540 | agent.Scene.RequestTeleportLocation( |
1570 | agent.ControllingClient, | 1541 | agent.ControllingClient, |
1571 | Utils.UIntsToLong(regionX * (uint)Constants.RegionSize, regionY * (uint)Constants.RegionSize), | 1542 | Util.RegionLocToHandle(regionX, regionY), |
1572 | position, | 1543 | position, |
1573 | agent.Lookat, | 1544 | agent.Lookat, |
1574 | (uint)Constants.TeleportFlags.ViaLocation); | 1545 | (uint)Constants.TeleportFlags.ViaLocation); |
@@ -1578,11 +1549,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1578 | if (im != null) | 1549 | if (im != null) |
1579 | { | 1550 | { |
1580 | UUID gotoLocation = Util.BuildFakeParcelID( | 1551 | UUID gotoLocation = Util.BuildFakeParcelID( |
1581 | Util.UIntsToLong( | 1552 | Util.RegionLocToHandle(regionX, regionY), |
1582 | (regionX * | ||
1583 | (uint)Constants.RegionSize), | ||
1584 | (regionY * | ||
1585 | (uint)Constants.RegionSize)), | ||
1586 | (uint)(int)position.X, | 1553 | (uint)(int)position.X, |
1587 | (uint)(int)position.Y, | 1554 | (uint)(int)position.Y, |
1588 | (uint)(int)position.Z); | 1555 | (uint)(int)position.Z); |
@@ -1635,17 +1602,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1635 | /// Calls an asynchronous method to do so.. so it doesn't lag the sim. | 1602 | /// Calls an asynchronous method to do so.. so it doesn't lag the sim. |
1636 | /// </summary> | 1603 | /// </summary> |
1637 | public ScenePresence CrossAgentToNewRegionAsync( | 1604 | public ScenePresence CrossAgentToNewRegionAsync( |
1638 | ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, | 1605 | ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, |
1639 | bool isFlying, string version) | 1606 | bool isFlying, string version) |
1640 | { | 1607 | { |
1608 | m_log.DebugFormat("{0} CrossAgentToNewRegionAsync: new region={1} at <{2},{3}>. newpos={4}", | ||
1609 | LogHeader, neighbourRegion.RegionName, neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, pos); | ||
1610 | |||
1641 | if (!CrossAgentToNewRegionPrep(agent, neighbourRegion)) | 1611 | if (!CrossAgentToNewRegionPrep(agent, neighbourRegion)) |
1642 | { | 1612 | { |
1613 | m_log.DebugFormat("{0} CrossAgentToNewRegionAsync: prep failed. Resetting transfer state", LogHeader); | ||
1643 | m_entityTransferStateMachine.ResetFromTransit(agent.UUID); | 1614 | m_entityTransferStateMachine.ResetFromTransit(agent.UUID); |
1644 | return agent; | 1615 | return agent; |
1645 | } | 1616 | } |
1646 | 1617 | ||
1647 | if (!CrossAgentIntoNewRegionMain(agent, pos, neighbourRegion, isFlying)) | 1618 | if (!CrossAgentIntoNewRegionMain(agent, pos, neighbourRegion, isFlying)) |
1648 | { | 1619 | { |
1620 | m_log.DebugFormat("{0} CrossAgentToNewRegionAsync: cross main failed. Resetting transfer state", LogHeader); | ||
1649 | m_entityTransferStateMachine.ResetFromTransit(agent.UUID); | 1621 | m_entityTransferStateMachine.ResetFromTransit(agent.UUID); |
1650 | return agent; | 1622 | return agent; |
1651 | } | 1623 | } |
@@ -2038,15 +2010,195 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2038 | } | 2010 | } |
2039 | } | 2011 | } |
2040 | 2012 | ||
2013 | // Computes the difference between two region bases. | ||
2014 | // Returns a vector of world coordinates (meters) from base of first region to the second. | ||
2015 | // The first region is the home region of the passed scene presence. | ||
2041 | Vector3 CalculateOffset(ScenePresence sp, GridRegion neighbour) | 2016 | Vector3 CalculateOffset(ScenePresence sp, GridRegion neighbour) |
2042 | { | 2017 | { |
2043 | int rRegionX = (int)sp.Scene.RegionInfo.RegionLocX; | 2018 | /* |
2044 | int rRegionY = (int)sp.Scene.RegionInfo.RegionLocY; | 2019 | int rRegionX = (int)sp.Scene.RegionInfo.LegacyRegionLocX; |
2020 | int rRegionY = (int)sp.Scene.RegionInfo.LegacyRegionLocY; | ||
2045 | int tRegionX = neighbour.RegionLocX / (int)Constants.RegionSize; | 2021 | int tRegionX = neighbour.RegionLocX / (int)Constants.RegionSize; |
2046 | int tRegionY = neighbour.RegionLocY / (int)Constants.RegionSize; | 2022 | int tRegionY = neighbour.RegionLocY / (int)Constants.RegionSize; |
2047 | int shiftx = (rRegionX - tRegionX) * (int)Constants.RegionSize; | 2023 | int shiftx = (rRegionX - tRegionX) * (int)Constants.RegionSize; |
2048 | int shifty = (rRegionY - tRegionY) * (int)Constants.RegionSize; | 2024 | int shifty = (rRegionY - tRegionY) * (int)Constants.RegionSize; |
2049 | return new Vector3(shiftx, shifty, 0f); | 2025 | return new Vector3(shiftx, shifty, 0f); |
2026 | */ | ||
2027 | return new Vector3( sp.Scene.RegionInfo.WorldLocX - neighbour.RegionLocX, | ||
2028 | sp.Scene.RegionInfo.WorldLocY - neighbour.RegionLocY, | ||
2029 | 0f); | ||
2030 | } | ||
2031 | |||
2032 | public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py) | ||
2033 | { | ||
2034 | // Since we don't know how big the regions could be, we have to search a very large area | ||
2035 | // to find possible regions. | ||
2036 | return GetRegionContainingWorldLocation(pGridService, pScopeID, px, py, Constants.MaximumRegionSize); | ||
2037 | } | ||
2038 | |||
2039 | #region NotFoundLocationCache class | ||
2040 | // A collection of not found locations to make future lookups 'not found' lookups quick. | ||
2041 | // A simple expiring cache that keeps not found locations for some number of seconds. | ||
2042 | // A 'not found' location is presumed to be anywhere in the minimum sized region that | ||
2043 | // contains that point. A conservitive estimate. | ||
2044 | private class NotFoundLocationCache | ||
2045 | { | ||
2046 | private struct NotFoundLocation | ||
2047 | { | ||
2048 | public double minX, maxX, minY, maxY; | ||
2049 | public DateTime expireTime; | ||
2050 | } | ||
2051 | private List<NotFoundLocation> m_notFoundLocations = new List<NotFoundLocation>(); | ||
2052 | public NotFoundLocationCache() | ||
2053 | { | ||
2054 | } | ||
2055 | // Add an area to the lost of 'not found' places. The area is the snapped region | ||
2056 | // area around the added point. | ||
2057 | public void Add(double pX, double pY) | ||
2058 | { | ||
2059 | lock (m_notFoundLocations) | ||
2060 | { | ||
2061 | if (!LockedContains(pX, pY)) | ||
2062 | { | ||
2063 | NotFoundLocation nfl = new NotFoundLocation(); | ||
2064 | // A not found location is not found for at least a whole region sized area | ||
2065 | nfl.minX = pX - (pX % (double)Constants.RegionSize); | ||
2066 | nfl.minY = pY - (pY % (double)Constants.RegionSize); | ||
2067 | nfl.maxX = nfl.minX + (double)Constants.RegionSize; | ||
2068 | nfl.maxY = nfl.minY + (double)Constants.RegionSize; | ||
2069 | nfl.expireTime = DateTime.Now + TimeSpan.FromSeconds(30); | ||
2070 | m_notFoundLocations.Add(nfl); | ||
2071 | } | ||
2072 | } | ||
2073 | |||
2074 | } | ||
2075 | // Test to see of this point is in any of the 'not found' areas. | ||
2076 | // Return 'true' if the point is found inside the 'not found' areas. | ||
2077 | public bool Contains(double pX, double pY) | ||
2078 | { | ||
2079 | bool ret = false; | ||
2080 | lock (m_notFoundLocations) | ||
2081 | ret = LockedContains(pX, pY); | ||
2082 | return ret; | ||
2083 | } | ||
2084 | private bool LockedContains(double pX, double pY) | ||
2085 | { | ||
2086 | bool ret = false; | ||
2087 | this.DoExpiration(); | ||
2088 | foreach (NotFoundLocation nfl in m_notFoundLocations) | ||
2089 | { | ||
2090 | if (pX >= nfl.minX && pX < nfl.maxX && pY >= nfl.minY && pY < nfl.maxY) | ||
2091 | { | ||
2092 | ret = true; | ||
2093 | break; | ||
2094 | } | ||
2095 | } | ||
2096 | return ret; | ||
2097 | } | ||
2098 | private void DoExpiration() | ||
2099 | { | ||
2100 | List<NotFoundLocation> m_toRemove = null; | ||
2101 | DateTime now = DateTime.Now; | ||
2102 | foreach (NotFoundLocation nfl in m_notFoundLocations) | ||
2103 | { | ||
2104 | if (nfl.expireTime < now) | ||
2105 | { | ||
2106 | if (m_toRemove == null) | ||
2107 | m_toRemove = new List<NotFoundLocation>(); | ||
2108 | m_toRemove.Add(nfl); | ||
2109 | } | ||
2110 | } | ||
2111 | if (m_toRemove != null) | ||
2112 | { | ||
2113 | foreach (NotFoundLocation nfl in m_toRemove) | ||
2114 | m_notFoundLocations.Remove(nfl); | ||
2115 | m_toRemove.Clear(); | ||
2116 | } | ||
2117 | } | ||
2118 | } | ||
2119 | #endregion // NotFoundLocationCache class | ||
2120 | private NotFoundLocationCache m_notFoundLocationCache = new NotFoundLocationCache(); | ||
2121 | |||
2122 | // Given a world position (fractional meter coordinate), get the GridRegion info for | ||
2123 | // the region containing that point. | ||
2124 | // Someday this should be a method on GridService. | ||
2125 | // 'pSizeHint' is the size of the source region but since the destination point can be anywhere | ||
2126 | // the size of the target region is unknown thus the search area might have to be very large. | ||
2127 | // Return 'null' if no such region exists. | ||
2128 | public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, | ||
2129 | double px, double py, uint pSizeHint) | ||
2130 | { | ||
2131 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: call, XY=<{1},{2}>", LogHeader, px, py); | ||
2132 | GridRegion ret = null; | ||
2133 | const double fudge = 2.0; | ||
2134 | |||
2135 | // One problem with this routine is negative results. That is, this can be called lots of times | ||
2136 | // for regions that don't exist. m_notFoundLocationCache remembers 'not found' results so they | ||
2137 | // will be quick 'not found's next time. | ||
2138 | // NotFoundLocationCache is an expiring cache so it will eventually forget about 'not found' and | ||
2139 | // thus re-ask the GridService about the location. | ||
2140 | if (m_notFoundLocationCache.Contains(px, py)) | ||
2141 | { | ||
2142 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found via cache. loc=<{1},{2}>", LogHeader, px, py); | ||
2143 | return null; | ||
2144 | } | ||
2145 | |||
2146 | // As an optimization, since most regions will be legacy sized regions (256x256), first try to get | ||
2147 | // the region at the appropriate legacy region location. | ||
2148 | uint possibleX = (uint)Math.Floor(px); | ||
2149 | possibleX -= possibleX % Constants.RegionSize; | ||
2150 | uint possibleY = (uint)Math.Floor(py); | ||
2151 | possibleY -= possibleY % Constants.RegionSize; | ||
2152 | ret = pGridService.GetRegionByPosition(pScopeID, (int)possibleX, (int)possibleY); | ||
2153 | if (ret != null) | ||
2154 | { | ||
2155 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Found region using legacy size. rloc=<{1},{2}>. Rname={3}", | ||
2156 | LogHeader, possibleX, possibleY, ret.RegionName); | ||
2157 | } | ||
2158 | |||
2159 | if (ret == null) | ||
2160 | { | ||
2161 | // If the simple lookup failed, search the larger area for a region that contains this point | ||
2162 | double range = (double)pSizeHint + fudge; | ||
2163 | while (ret == null && range <= (Constants.MaximumRegionSize + Constants.RegionSize)) | ||
2164 | { | ||
2165 | // Get from the grid service a list of regions that might contain this point. | ||
2166 | // The region origin will be in the zero direction so only subtract the range. | ||
2167 | List<GridRegion> possibleRegions = pGridService.GetRegionRange(pScopeID, | ||
2168 | (int)(px - range), (int)(px), | ||
2169 | (int)(py - range), (int)(py)); | ||
2170 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegions cnt={1}, range={2}", | ||
2171 | LogHeader, possibleRegions.Count, range); | ||
2172 | if (possibleRegions != null && possibleRegions.Count > 0) | ||
2173 | { | ||
2174 | // If we found some regions, check to see if the point is within | ||
2175 | foreach (GridRegion gr in possibleRegions) | ||
2176 | { | ||
2177 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegion nm={1}, regionLoc=<{2},{3}>, regionSize=<{4},{5}>", | ||
2178 | LogHeader, gr.RegionName, gr.RegionLocX, gr.RegionLocY, gr.RegionSizeX, gr.RegionSizeY); | ||
2179 | if (px >= (double)gr.RegionLocX && px < (double)(gr.RegionLocX + gr.RegionSizeX) | ||
2180 | && py >= (double)gr.RegionLocY && py < (double)(gr.RegionLocY + gr.RegionSizeY)) | ||
2181 | { | ||
2182 | // Found a region that contains the point | ||
2183 | ret = gr; | ||
2184 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: found. RegionName={1}", LogHeader, ret.RegionName); | ||
2185 | break; | ||
2186 | } | ||
2187 | } | ||
2188 | } | ||
2189 | // Larger search area for next time around if not found | ||
2190 | range *= 2; | ||
2191 | } | ||
2192 | } | ||
2193 | |||
2194 | if (ret == null) | ||
2195 | { | ||
2196 | // remember this location was not found so we can quickly not find it next time | ||
2197 | m_notFoundLocationCache.Add(px, py); | ||
2198 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found. Remembering loc=<{1},{2}>", LogHeader, px, py); | ||
2199 | } | ||
2200 | |||
2201 | return ret; | ||
2050 | } | 2202 | } |
2051 | 2203 | ||
2052 | private void InformClientOfNeighbourCompleted(IAsyncResult iar) | 2204 | private void InformClientOfNeighbourCompleted(IAsyncResult iar) |
@@ -2168,16 +2320,19 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2168 | // view to include everything in the megaregion | 2320 | // view to include everything in the megaregion |
2169 | if (m_regionCombinerModule == null || !m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID)) | 2321 | if (m_regionCombinerModule == null || !m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID)) |
2170 | { | 2322 | { |
2171 | int dd = avatar.DrawDistance < Constants.RegionSize ? (int)Constants.RegionSize : (int)avatar.DrawDistance; | 2323 | // The area to check is as big as the current region. |
2324 | // We presume all adjacent regions are the same size as this region. | ||
2325 | uint dd = Math.Max((uint)avatar.DrawDistance, | ||
2326 | Math.Max(Scene.RegionInfo.RegionSizeX, Scene.RegionInfo.RegionSizeY)); | ||
2172 | 2327 | ||
2173 | int startX = (int)pRegionLocX * (int)Constants.RegionSize - dd + (int)(Constants.RegionSize/2); | 2328 | uint startX = Util.RegionToWorldLoc(pRegionLocX) - dd + Constants.RegionSize/2; |
2174 | int startY = (int)pRegionLocY * (int)Constants.RegionSize - dd + (int)(Constants.RegionSize/2); | 2329 | uint startY = Util.RegionToWorldLoc(pRegionLocY) - dd + Constants.RegionSize/2; |
2175 | 2330 | ||
2176 | int endX = (int)pRegionLocX * (int)Constants.RegionSize + dd + (int)(Constants.RegionSize/2); | 2331 | uint endX = Util.RegionToWorldLoc(pRegionLocX) + dd + Constants.RegionSize/2; |
2177 | int endY = (int)pRegionLocY * (int)Constants.RegionSize + dd + (int)(Constants.RegionSize/2); | 2332 | uint endY = Util.RegionToWorldLoc(pRegionLocY) + dd + Constants.RegionSize/2; |
2178 | 2333 | ||
2179 | List<GridRegion> neighbours = | 2334 | List<GridRegion> neighbours = |
2180 | avatar.Scene.GridService.GetRegionRange(m_regionInfo.ScopeID, startX, endX, startY, endY); | 2335 | avatar.Scene.GridService.GetRegionRange(m_regionInfo.ScopeID, (int)startX, (int)endX, (int)startY, (int)endY); |
2181 | 2336 | ||
2182 | neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; }); | 2337 | neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; }); |
2183 | return neighbours; | 2338 | return neighbours; |
@@ -2190,10 +2345,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2190 | List<GridRegion> neighbours | 2345 | List<GridRegion> neighbours |
2191 | = pScene.GridService.GetRegionRange( | 2346 | = pScene.GridService.GetRegionRange( |
2192 | m_regionInfo.ScopeID, | 2347 | m_regionInfo.ScopeID, |
2193 | (int)swCorner.X * (int)Constants.RegionSize, | 2348 | (int)Util.RegionToWorldLoc((uint)swCorner.X), (int)Util.RegionToWorldLoc((uint)neCorner.X), |
2194 | (int)neCorner.X * (int)Constants.RegionSize, | 2349 | (int)Util.RegionToWorldLoc((uint)swCorner.Y), (int)Util.RegionToWorldLoc((uint)neCorner.Y) ); |
2195 | (int)swCorner.Y * (int)Constants.RegionSize, | ||
2196 | (int)neCorner.Y * (int)Constants.RegionSize); | ||
2197 | 2350 | ||
2198 | neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; }); | 2351 | neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; }); |
2199 | 2352 | ||
@@ -2256,10 +2409,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2256 | /// Move the given scene object into a new region depending on which region its absolute position has moved | 2409 | /// Move the given scene object into a new region depending on which region its absolute position has moved |
2257 | /// into. | 2410 | /// into. |
2258 | /// | 2411 | /// |
2259 | /// This method locates the new region handle and offsets the prim position for the new region | 2412 | /// Using the objects new world location, ask the grid service for a the new region and adjust the prim |
2413 | /// position to be relative to the new region. | ||
2260 | /// </summary> | 2414 | /// </summary> |
2261 | /// <param name="attemptedPosition">the attempted out of region position of the scene object</param> | ||
2262 | /// <param name="grp">the scene object that we're crossing</param> | 2415 | /// <param name="grp">the scene object that we're crossing</param> |
2416 | /// <param name="attemptedPosition">the attempted out of region position of the scene object. This position is | ||
2417 | /// relative to the region the object currently is in.</param> | ||
2418 | /// <param name="silent">if 'true', the deletion of the client from the region is not broadcast to the clients</param> | ||
2263 | public void Cross(SceneObjectGroup grp, Vector3 attemptedPosition, bool silent) | 2419 | public void Cross(SceneObjectGroup grp, Vector3 attemptedPosition, bool silent) |
2264 | { | 2420 | { |
2265 | if (grp == null) | 2421 | if (grp == null) |
@@ -2285,208 +2441,49 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2285 | return; | 2441 | return; |
2286 | } | 2442 | } |
2287 | 2443 | ||
2288 | int thisx = (int)scene.RegionInfo.RegionLocX; | 2444 | // Remember the old group position in case the region lookup fails so position can be restored. |
2289 | int thisy = (int)scene.RegionInfo.RegionLocY; | 2445 | Vector3 oldGroupPosition = grp.RootPart.GroupPosition; |
2290 | Vector3 EastCross = new Vector3(0.1f, 0, 0); | ||
2291 | Vector3 WestCross = new Vector3(-0.1f, 0, 0); | ||
2292 | Vector3 NorthCross = new Vector3(0, 0.1f, 0); | ||
2293 | Vector3 SouthCross = new Vector3(0, -0.1f, 0); | ||
2294 | |||
2295 | |||
2296 | // use this if no borders were crossed! | ||
2297 | ulong newRegionHandle | ||
2298 | = Util.UIntsToLong((uint)((thisx) * Constants.RegionSize), | ||
2299 | (uint)((thisy) * Constants.RegionSize)); | ||
2300 | |||
2301 | Vector3 pos = attemptedPosition; | ||
2302 | |||
2303 | int changeX = 1; | ||
2304 | int changeY = 1; | ||
2305 | |||
2306 | if (scene.TestBorderCross(attemptedPosition + WestCross, Cardinals.W)) | ||
2307 | { | ||
2308 | if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S)) | ||
2309 | { | ||
2310 | |||
2311 | Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W); | ||
2312 | |||
2313 | if (crossedBorderx.BorderLine.Z > 0) | ||
2314 | { | ||
2315 | pos.X = ((pos.X + crossedBorderx.BorderLine.Z)); | ||
2316 | changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize); | ||
2317 | } | ||
2318 | else | ||
2319 | pos.X = ((pos.X + Constants.RegionSize)); | ||
2320 | |||
2321 | Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S); | ||
2322 | //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize) | ||
2323 | |||
2324 | if (crossedBordery.BorderLine.Z > 0) | ||
2325 | { | ||
2326 | pos.Y = ((pos.Y + crossedBordery.BorderLine.Z)); | ||
2327 | changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize); | ||
2328 | } | ||
2329 | else | ||
2330 | pos.Y = ((pos.Y + Constants.RegionSize)); | ||
2331 | |||
2332 | |||
2333 | |||
2334 | newRegionHandle | ||
2335 | = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize), | ||
2336 | (uint)((thisy - changeY) * Constants.RegionSize)); | ||
2337 | // x - 1 | ||
2338 | // y - 1 | ||
2339 | } | ||
2340 | else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N)) | ||
2341 | { | ||
2342 | Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W); | ||
2343 | |||
2344 | if (crossedBorderx.BorderLine.Z > 0) | ||
2345 | { | ||
2346 | pos.X = ((pos.X + crossedBorderx.BorderLine.Z)); | ||
2347 | changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize); | ||
2348 | } | ||
2349 | else | ||
2350 | pos.X = ((pos.X + Constants.RegionSize)); | ||
2351 | |||
2352 | 2446 | ||
2353 | Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S); | 2447 | // Compute the absolute position of the object. |
2354 | //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize) | 2448 | double objectWorldLocX = (double)scene.RegionInfo.WorldLocX + attemptedPosition.X; |
2449 | double objectWorldLocY = (double)scene.RegionInfo.WorldLocY + attemptedPosition.Y; | ||
2355 | 2450 | ||
2356 | if (crossedBordery.BorderLine.Z > 0) | 2451 | // Ask the grid service for the region that contains the passed address |
2357 | { | 2452 | GridRegion destination = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID, |
2358 | pos.Y = ((pos.Y + crossedBordery.BorderLine.Z)); | 2453 | objectWorldLocX, objectWorldLocY); |
2359 | changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize); | ||
2360 | } | ||
2361 | else | ||
2362 | pos.Y = ((pos.Y + Constants.RegionSize)); | ||
2363 | 2454 | ||
2364 | newRegionHandle | 2455 | Vector3 pos = Vector3.Zero; |
2365 | = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize), | 2456 | if (destination != null) |
2366 | (uint)((thisy + changeY) * Constants.RegionSize)); | ||
2367 | // x - 1 | ||
2368 | // y + 1 | ||
2369 | } | ||
2370 | else | ||
2371 | { | ||
2372 | Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W); | ||
2373 | |||
2374 | if (crossedBorderx.BorderLine.Z > 0) | ||
2375 | { | ||
2376 | pos.X = ((pos.X + crossedBorderx.BorderLine.Z)); | ||
2377 | changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize); | ||
2378 | } | ||
2379 | else | ||
2380 | pos.X = ((pos.X + Constants.RegionSize)); | ||
2381 | |||
2382 | newRegionHandle | ||
2383 | = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize), | ||
2384 | (uint)(thisy * Constants.RegionSize)); | ||
2385 | // x - 1 | ||
2386 | } | ||
2387 | } | ||
2388 | else if (scene.TestBorderCross(attemptedPosition + EastCross, Cardinals.E)) | ||
2389 | { | 2457 | { |
2390 | if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S)) | 2458 | // Adjust the object's relative position from the old region (attemptedPosition) |
2391 | { | 2459 | // to be relative to the new region (pos). |
2392 | 2460 | pos = new Vector3( (float)(objectWorldLocX - (double)destination.RegionLocX), | |
2393 | pos.X = ((pos.X - Constants.RegionSize)); | 2461 | (float)(objectWorldLocY - (double)destination.RegionLocY), |
2394 | Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S); | 2462 | attemptedPosition.Z); |
2395 | //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize) | ||
2396 | |||
2397 | if (crossedBordery.BorderLine.Z > 0) | ||
2398 | { | ||
2399 | pos.Y = ((pos.Y + crossedBordery.BorderLine.Z)); | ||
2400 | changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize); | ||
2401 | } | ||
2402 | else | ||
2403 | pos.Y = ((pos.Y + Constants.RegionSize)); | ||
2404 | |||
2405 | |||
2406 | newRegionHandle | ||
2407 | = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize), | ||
2408 | (uint)((thisy - changeY) * Constants.RegionSize)); | ||
2409 | // x + 1 | ||
2410 | // y - 1 | ||
2411 | } | ||
2412 | else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N)) | ||
2413 | { | ||
2414 | pos.X = ((pos.X - Constants.RegionSize)); | ||
2415 | pos.Y = ((pos.Y - Constants.RegionSize)); | ||
2416 | newRegionHandle | ||
2417 | = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize), | ||
2418 | (uint)((thisy + changeY) * Constants.RegionSize)); | ||
2419 | // x + 1 | ||
2420 | // y + 1 | ||
2421 | } | ||
2422 | else | ||
2423 | { | ||
2424 | pos.X = ((pos.X - Constants.RegionSize)); | ||
2425 | newRegionHandle | ||
2426 | = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize), | ||
2427 | (uint)(thisy * Constants.RegionSize)); | ||
2428 | // x + 1 | ||
2429 | } | ||
2430 | } | 2463 | } |
2431 | else if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S)) | ||
2432 | { | ||
2433 | Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S); | ||
2434 | //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize) | ||
2435 | |||
2436 | if (crossedBordery.BorderLine.Z > 0) | ||
2437 | { | ||
2438 | pos.Y = ((pos.Y + crossedBordery.BorderLine.Z)); | ||
2439 | changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize); | ||
2440 | } | ||
2441 | else | ||
2442 | pos.Y = ((pos.Y + Constants.RegionSize)); | ||
2443 | 2464 | ||
2444 | newRegionHandle | 2465 | if (destination == null || !CrossPrimGroupIntoNewRegion(destination, pos, grp, silent)) |
2445 | = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy - changeY) * Constants.RegionSize)); | ||
2446 | // y - 1 | ||
2447 | } | ||
2448 | else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N)) | ||
2449 | { | 2466 | { |
2467 | m_log.InfoFormat("[ENTITY TRANSFER MODULE] cross region transfer failed for object {0}", grp.UUID); | ||
2450 | 2468 | ||
2451 | pos.Y = ((pos.Y - Constants.RegionSize)); | 2469 | // We are going to move the object back to the old position so long as the old position |
2452 | newRegionHandle | 2470 | // is in the region |
2453 | = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy + changeY) * Constants.RegionSize)); | 2471 | oldGroupPosition.X = Util.Clamp<float>(oldGroupPosition.X, 1.0f, (float)(scene.RegionInfo.RegionSizeX - 1)); |
2454 | // y + 1 | 2472 | oldGroupPosition.Y = Util.Clamp<float>(oldGroupPosition.Y, 1.0f, (float)(scene.RegionInfo.RegionSizeY - 1)); |
2455 | } | 2473 | oldGroupPosition.Z = Util.Clamp<float>(oldGroupPosition.Z, 1.0f, Constants.RegionHeight); |
2456 | 2474 | ||
2457 | // Offset the positions for the new region across the border | 2475 | grp.AbsolutePosition = oldGroupPosition; |
2458 | Vector3 oldGroupPosition = grp.RootPart.GroupPosition; | 2476 | grp.Velocity = Vector3.Zero; |
2477 | if (grp.RootPart.PhysActor != null) | ||
2478 | grp.RootPart.PhysActor.CrossingFailure(); | ||
2459 | 2479 | ||
2460 | // If we fail to cross the border, then reset the position of the scene object on that border. | 2480 | if (grp.RootPart.KeyframeMotion != null) |
2461 | uint x = 0, y = 0; | 2481 | grp.RootPart.KeyframeMotion.CrossingFailure(); |
2462 | Utils.LongToUInts(newRegionHandle, out x, out y); | ||
2463 | GridRegion destination = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID, (int)x, (int)y); | ||
2464 | 2482 | ||
2465 | if (destination != null) | 2483 | grp.ScheduleGroupForFullUpdate(); |
2466 | { | ||
2467 | if (CrossPrimGroupIntoNewRegion(destination, pos, grp, silent)) | ||
2468 | return; // we did it | ||
2469 | } | 2484 | } |
2470 | |||
2471 | // no one or failed lets go back and tell physics to go on | ||
2472 | oldGroupPosition.X = Util.Clamp<float>(oldGroupPosition.X, 0.5f, (float)Constants.RegionSize - 0.5f); | ||
2473 | oldGroupPosition.Y = Util.Clamp<float>(oldGroupPosition.Y, 0.5f, (float)Constants.RegionSize - 0.5f); | ||
2474 | oldGroupPosition.Z = Util.Clamp<float>(oldGroupPosition.Z, 0.5f, 4096.0f); | ||
2475 | |||
2476 | grp.AbsolutePosition = oldGroupPosition; | ||
2477 | grp.Velocity = Vector3.Zero; | ||
2478 | |||
2479 | if (grp.RootPart.PhysActor != null) | ||
2480 | grp.RootPart.PhysActor.CrossingFailure(); | ||
2481 | |||
2482 | if (grp.RootPart.KeyframeMotion != null) | ||
2483 | grp.RootPart.KeyframeMotion.CrossingFailure(); | ||
2484 | |||
2485 | grp.ScheduleGroupForFullUpdate(); | ||
2486 | } | 2485 | } |
2487 | 2486 | ||
2488 | |||
2489 | |||
2490 | /// <summary> | 2487 | /// <summary> |
2491 | /// Move the given scene object into a new region | 2488 | /// Move the given scene object into a new region |
2492 | /// </summary> | 2489 | /// </summary> |
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs index fc02916..6a04acf 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs | |||
@@ -77,6 +77,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
77 | public class EntityTransferStateMachine | 77 | public class EntityTransferStateMachine |
78 | { | 78 | { |
79 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 79 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
80 | private static readonly string LogHeader = "[ENTITY TRANSFER STATE MACHINE]"; | ||
80 | 81 | ||
81 | /// <summary> | 82 | /// <summary> |
82 | /// If true then on a teleport, the source region waits for a callback from the destination region. If | 83 | /// If true then on a teleport, the source region waits for a callback from the destination region. If |
@@ -100,6 +101,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
100 | /// <returns>true if the agent was not already in transit, false if it was</returns> | 101 | /// <returns>true if the agent was not already in transit, false if it was</returns> |
101 | internal bool SetInTransit(UUID id) | 102 | internal bool SetInTransit(UUID id) |
102 | { | 103 | { |
104 | m_log.DebugFormat("{0} SetInTransit. agent={1}, newState=Preparing", LogHeader, id); | ||
103 | lock (m_agentsInTransit) | 105 | lock (m_agentsInTransit) |
104 | { | 106 | { |
105 | if (!m_agentsInTransit.ContainsKey(id)) | 107 | if (!m_agentsInTransit.ContainsKey(id)) |
@@ -121,6 +123,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
121 | /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception> | 123 | /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception> |
122 | internal bool UpdateInTransit(UUID id, AgentTransferState newState) | 124 | internal bool UpdateInTransit(UUID id, AgentTransferState newState) |
123 | { | 125 | { |
126 | m_log.DebugFormat("{0} UpdateInTransit. agent={1}, newState={2}", LogHeader, id, newState); | ||
127 | |||
124 | bool transitionOkay = false; | 128 | bool transitionOkay = false; |
125 | 129 | ||
126 | // We don't want to throw an exception on cancel since this can come it at any time. | 130 | // We don't want to throw an exception on cancel since this can come it at any time. |
@@ -193,6 +197,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
193 | } | 197 | } |
194 | else if (failIfNotOkay) | 198 | else if (failIfNotOkay) |
195 | { | 199 | { |
200 | m_log.DebugFormat("{0} UpdateInTransit. Throwing transition failure = {1}", LogHeader, failureMessage); | ||
196 | throw new Exception(failureMessage); | 201 | throw new Exception(failureMessage); |
197 | } | 202 | } |
198 | // else | 203 | // else |
diff --git a/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs b/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs index d943b20..4e7ad75 100644 --- a/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs | |||
@@ -213,8 +213,8 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules | |||
213 | if (part != null) | 213 | if (part != null) |
214 | { | 214 | { |
215 | ObjectRegionName = s.RegionInfo.RegionName; | 215 | ObjectRegionName = s.RegionInfo.RegionName; |
216 | uint localX = (s.RegionInfo.RegionLocX * (int)Constants.RegionSize); | 216 | uint localX = s.RegionInfo.WorldLocX; |
217 | uint localY = (s.RegionInfo.RegionLocY * (int)Constants.RegionSize); | 217 | uint localY = s.RegionInfo.WorldLocY; |
218 | ObjectRegionName = ObjectRegionName + " (" + localX + ", " + localY + ")"; | 218 | ObjectRegionName = ObjectRegionName + " (" + localX + ", " + localY + ")"; |
219 | return part; | 219 | return part; |
220 | } | 220 | } |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs index 31ef79b..3b38c71 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs | |||
@@ -48,6 +48,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid | |||
48 | private static readonly ILog m_log = | 48 | private static readonly ILog m_log = |
49 | LogManager.GetLogger( | 49 | LogManager.GetLogger( |
50 | MethodBase.GetCurrentMethod().DeclaringType); | 50 | MethodBase.GetCurrentMethod().DeclaringType); |
51 | private static string LogHeader = "[LOCAL GRID SERVICE CONNECTOR]"; | ||
51 | 52 | ||
52 | private IGridService m_GridService; | 53 | private IGridService m_GridService; |
53 | private Dictionary<UUID, RegionCache> m_LocalCache = new Dictionary<UUID, RegionCache>(); | 54 | private Dictionary<UUID, RegionCache> m_LocalCache = new Dictionary<UUID, RegionCache>(); |
@@ -56,12 +57,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid | |||
56 | 57 | ||
57 | public LocalGridServicesConnector() | 58 | public LocalGridServicesConnector() |
58 | { | 59 | { |
59 | m_log.Debug("[LOCAL GRID SERVICE CONNECTOR]: LocalGridServicesConnector no parms."); | 60 | m_log.DebugFormat("{0} LocalGridServicesConnector no parms.", LogHeader); |
60 | } | 61 | } |
61 | 62 | ||
62 | public LocalGridServicesConnector(IConfigSource source) | 63 | public LocalGridServicesConnector(IConfigSource source) |
63 | { | 64 | { |
64 | m_log.Debug("[LOCAL GRID SERVICE CONNECTOR]: LocalGridServicesConnector instantiated directly."); | 65 | m_log.DebugFormat("{0} LocalGridServicesConnector instantiated directly.", LogHeader); |
65 | InitialiseService(source); | 66 | InitialiseService(source); |
66 | } | 67 | } |
67 | 68 | ||
@@ -192,6 +193,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid | |||
192 | return m_GridService.GetRegionByUUID(scopeID, regionID); | 193 | return m_GridService.GetRegionByUUID(scopeID, regionID); |
193 | } | 194 | } |
194 | 195 | ||
196 | // Get a region given its base coordinates. | ||
197 | // NOTE: this is NOT 'get a region by some point in the region'. The coordinate MUST | ||
198 | // be the base coordinate of the region. | ||
195 | public GridRegion GetRegionByPosition(UUID scopeID, int x, int y) | 199 | public GridRegion GetRegionByPosition(UUID scopeID, int x, int y) |
196 | { | 200 | { |
197 | GridRegion region = null; | 201 | GridRegion region = null; |
@@ -206,13 +210,25 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid | |||
206 | region = rcache.GetRegionByPosition(x, y); | 210 | region = rcache.GetRegionByPosition(x, y); |
207 | if (region != null) | 211 | if (region != null) |
208 | { | 212 | { |
209 | return region; | 213 | // m_log.DebugFormat("{0} GetRegionByPosition. Found region {1} in cache. Pos=<{2},{3}>", |
214 | // LogHeader, region.RegionName, x, y); | ||
215 | break; | ||
210 | } | 216 | } |
211 | } | 217 | } |
212 | } | 218 | } |
213 | 219 | ||
214 | // Then try on this sim (may be a lookup in DB if this is using MySql). | 220 | // Then try on this sim (may be a lookup in DB if this is using MySql). |
215 | return m_GridService.GetRegionByPosition(scopeID, x, y); | 221 | if (region == null) |
222 | { | ||
223 | region = m_GridService.GetRegionByPosition(scopeID, x, y); | ||
224 | if (region == null) | ||
225 | m_log.DebugFormat("{0} GetRegionByPosition. Region not found by grid service. Pos=<{1},{2}>", | ||
226 | LogHeader, x, y); | ||
227 | else | ||
228 | m_log.DebugFormat("{0} GetRegionByPosition. Requested region {1} from grid service. Pos=<{2},{3}>", | ||
229 | LogHeader, region.RegionName, x, y); | ||
230 | } | ||
231 | return region; | ||
216 | } | 232 | } |
217 | 233 | ||
218 | public GridRegion GetRegionByName(UUID scopeID, string regionName) | 234 | public GridRegion GetRegionByName(UUID scopeID, string regionName) |
@@ -268,7 +284,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid | |||
268 | caps.AppendFormat("*** Neighbours of {0} ({1}) ***\n", kvp.Value.RegionName, kvp.Key); | 284 | caps.AppendFormat("*** Neighbours of {0} ({1}) ***\n", kvp.Value.RegionName, kvp.Key); |
269 | List<GridRegion> regions = kvp.Value.GetNeighbours(); | 285 | List<GridRegion> regions = kvp.Value.GetNeighbours(); |
270 | foreach (GridRegion r in regions) | 286 | foreach (GridRegion r in regions) |
271 | caps.AppendFormat(" {0} @ {1}-{2}\n", r.RegionName, r.RegionLocX / Constants.RegionSize, r.RegionLocY / Constants.RegionSize); | 287 | caps.AppendFormat(" {0} @ {1}-{2}\n", r.RegionName, Util.WorldToRegionLoc((uint)r.RegionLocX), Util.WorldToRegionLoc((uint)r.RegionLocY)); |
272 | } | 288 | } |
273 | } | 289 | } |
274 | 290 | ||
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs index 9172536..ae76288 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs | |||
@@ -66,7 +66,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid | |||
66 | return; | 66 | return; |
67 | 67 | ||
68 | m_log.DebugFormat("[REGION CACHE]: (on region {0}) Region {1} is up @ {2}-{3}", | 68 | m_log.DebugFormat("[REGION CACHE]: (on region {0}) Region {1} is up @ {2}-{3}", |
69 | m_scene.RegionInfo.RegionName, otherRegion.RegionName, otherRegion.RegionLocX / Constants.RegionSize, otherRegion.RegionLocY / Constants.RegionSize); | 69 | m_scene.RegionInfo.RegionName, otherRegion.RegionName, Util.WorldToRegionLoc((uint)otherRegion.RegionLocX), Util.WorldToRegionLoc((uint)otherRegion.RegionLocY)); |
70 | 70 | ||
71 | m_neighbours[otherRegion.RegionHandle] = otherRegion; | 71 | m_neighbours[otherRegion.RegionHandle] = otherRegion; |
72 | } | 72 | } |
@@ -82,11 +82,16 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid | |||
82 | return new List<GridRegion>(m_neighbours.Values); | 82 | return new List<GridRegion>(m_neighbours.Values); |
83 | } | 83 | } |
84 | 84 | ||
85 | // Get a region given its base coordinates (in meters). | ||
86 | // NOTE: this is NOT 'get a region by some point in the region'. The coordinate MUST | ||
87 | // be the base coordinate of the region. | ||
88 | // The snapping is technically unnecessary but is harmless because regions are always | ||
89 | // multiples of the legacy region size (256). | ||
85 | public GridRegion GetRegionByPosition(int x, int y) | 90 | public GridRegion GetRegionByPosition(int x, int y) |
86 | { | 91 | { |
87 | uint xsnap = (uint)(x / Constants.RegionSize) * Constants.RegionSize; | 92 | uint xsnap = (uint)(x / Constants.RegionSize) * Constants.RegionSize; |
88 | uint ysnap = (uint)(y / Constants.RegionSize) * Constants.RegionSize; | 93 | uint ysnap = (uint)(y / Constants.RegionSize) * Constants.RegionSize; |
89 | ulong handle = Utils.UIntsToLong(xsnap, ysnap); | 94 | ulong handle = Util.RegionWorldLocToHandle(xsnap, ysnap); |
90 | 95 | ||
91 | if (m_neighbours.ContainsKey(handle)) | 96 | if (m_neighbours.ContainsKey(handle)) |
92 | return m_neighbours[handle]; | 97 | return m_neighbours[handle]; |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs index 6a57d1f..ae5081c 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs | |||
@@ -186,10 +186,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid | |||
186 | return rinfo; | 186 | return rinfo; |
187 | } | 187 | } |
188 | 188 | ||
189 | // Get a region given its base world coordinates (in meters). | ||
190 | // NOTE: this is NOT 'get a region by some point in the region'. The coordinate MUST | ||
191 | // be the base coordinate of the region. | ||
192 | // The coordinates are world coords (meters), NOT region units. | ||
189 | public GridRegion GetRegionByPosition(UUID scopeID, int x, int y) | 193 | public GridRegion GetRegionByPosition(UUID scopeID, int x, int y) |
190 | { | 194 | { |
191 | bool inCache = false; | 195 | bool inCache = false; |
192 | GridRegion rinfo = m_RegionInfoCache.Get(scopeID, Util.UIntsToLong((uint)x, (uint)y), out inCache); | 196 | GridRegion rinfo = m_RegionInfoCache.Get(scopeID, Util.RegionWorldLocToHandle((uint)x, (uint)y), out inCache); |
193 | if (inCache) | 197 | if (inCache) |
194 | return rinfo; | 198 | return rinfo; |
195 | 199 | ||
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs index 4338133..25ae689 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs | |||
@@ -34,6 +34,7 @@ using log4net.Config; | |||
34 | using Nini.Config; | 34 | using Nini.Config; |
35 | using NUnit.Framework; | 35 | using NUnit.Framework; |
36 | using OpenMetaverse; | 36 | using OpenMetaverse; |
37 | |||
37 | using OpenSim.Framework; | 38 | using OpenSim.Framework; |
38 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid; | 39 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid; |
39 | using OpenSim.Region.Framework.Scenes; | 40 | using OpenSim.Region.Framework.Scenes; |
@@ -141,7 +142,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests | |||
141 | Assert.IsNotNull(result, "Retrieved GetRegionByUUID is null"); | 142 | Assert.IsNotNull(result, "Retrieved GetRegionByUUID is null"); |
142 | Assert.That(result.RegionID, Is.EqualTo(new UUID(1)), "Retrieved region's UUID does not match"); | 143 | Assert.That(result.RegionID, Is.EqualTo(new UUID(1)), "Retrieved region's UUID does not match"); |
143 | 144 | ||
144 | result = m_LocalConnector.GetRegionByPosition(UUID.Zero, 1000 * (int)Constants.RegionSize, 1000 * (int)Constants.RegionSize); | 145 | result = m_LocalConnector.GetRegionByPosition(UUID.Zero, (int)Util.RegionToWorldLoc(1000), (int)Util.RegionToWorldLoc(1000)); |
145 | Assert.IsNotNull(result, "Retrieved GetRegionByPosition is null"); | 146 | Assert.IsNotNull(result, "Retrieved GetRegionByPosition is null"); |
146 | Assert.That(result.RegionLocX, Is.EqualTo(1000 * (int)Constants.RegionSize), "Retrieved region's position does not match"); | 147 | Assert.That(result.RegionLocX, Is.EqualTo(1000 * (int)Constants.RegionSize), "Retrieved region's position does not match"); |
147 | 148 | ||
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs index 26d22b8..4d7538c 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs | |||
@@ -57,6 +57,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage | |||
57 | { | 57 | { |
58 | private static readonly ILog m_log = | 58 | private static readonly ILog m_log = |
59 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 59 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
60 | private static string LogHeader = "[MAP IMAGE SERVICE MODULE]"; | ||
60 | 61 | ||
61 | private bool m_enabled = false; | 62 | private bool m_enabled = false; |
62 | private IMapImageService m_MapService; | 63 | private IMapImageService m_MapService; |
@@ -192,42 +193,85 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage | |||
192 | ///</summary> | 193 | ///</summary> |
193 | private void UploadMapTile(IScene scene) | 194 | private void UploadMapTile(IScene scene) |
194 | { | 195 | { |
195 | m_log.DebugFormat("[MAP IMAGE SERVICE MODULE]: upload maptile for {0}", scene.RegionInfo.RegionName); | 196 | m_log.DebugFormat("{0} Upload maptile for {1}", LogHeader, scene.RegionInfo.RegionName); |
197 | string regionName = scene.RegionInfo.RegionName; | ||
196 | 198 | ||
197 | // Create a JPG map tile and upload it to the AddMapTile API | 199 | // Create a JPG map tile and upload it to the AddMapTile API |
198 | byte[] jpgData = Utils.EmptyBytes; | ||
199 | IMapImageGenerator tileGenerator = scene.RequestModuleInterface<IMapImageGenerator>(); | 200 | IMapImageGenerator tileGenerator = scene.RequestModuleInterface<IMapImageGenerator>(); |
200 | if (tileGenerator == null) | 201 | if (tileGenerator == null) |
201 | { | 202 | { |
202 | m_log.Warn("[MAP IMAGE SERVICE MODULE]: Cannot upload PNG map tile without an ImageGenerator"); | 203 | m_log.WarnFormat("{0} Cannot upload map tile without an ImageGenerator", LogHeader); |
203 | return; | 204 | return; |
204 | } | 205 | } |
205 | 206 | using (Bitmap mapTile = tileGenerator.CreateMapTile()) | |
206 | using (Image mapTile = tileGenerator.CreateMapTile()) | ||
207 | { | 207 | { |
208 | // XXX: The MapImageModule will return a null if the user has chosen not to create map tiles and there | 208 | if (mapTile != null) |
209 | // is no static map tile. | 209 | { |
210 | if (mapTile == null) | 210 | // mapTile.Save( // DEBUG DEBUG |
211 | return; | 211 | // String.Format("maptiles/raw-{0}-{1}-{2}.jpg", regionName, scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY), |
212 | 212 | // ImageFormat.Jpeg); | |
213 | using (MemoryStream stream = new MemoryStream()) | 213 | // If the region/maptile is legacy sized, just upload the one tile like it has always been done |
214 | if (mapTile.Width == Constants.RegionSize && mapTile.Height == Constants.RegionSize) | ||
215 | { | ||
216 | ConvertAndUploadMaptile(mapTile, | ||
217 | scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY, | ||
218 | scene.RegionInfo.RegionName); | ||
219 | } | ||
220 | else | ||
221 | { | ||
222 | // For larger regions (varregion) we must cut the region image into legacy sized | ||
223 | // pieces since that is how the maptile system works. | ||
224 | // Note the assumption that varregions are always a multiple of legacy size. | ||
225 | for (uint xx = 0; xx < mapTile.Width; xx += Constants.RegionSize) | ||
226 | { | ||
227 | for (uint yy = 0; yy < mapTile.Height; yy += Constants.RegionSize) | ||
228 | { | ||
229 | // Images are addressed from the upper left corner so have to do funny | ||
230 | // math to pick out the sub-tile since regions are numbered from | ||
231 | // the lower left. | ||
232 | Rectangle rect = new Rectangle( | ||
233 | (int)xx, | ||
234 | mapTile.Height - (int)yy - (int)Constants.RegionSize, | ||
235 | (int)Constants.RegionSize, (int)Constants.RegionSize); | ||
236 | using (Bitmap subMapTile = mapTile.Clone(rect, mapTile.PixelFormat)) | ||
237 | { | ||
238 | ConvertAndUploadMaptile(subMapTile, | ||
239 | scene.RegionInfo.RegionLocX + (xx / Constants.RegionSize), | ||
240 | scene.RegionInfo.RegionLocY + (yy / Constants.RegionSize), | ||
241 | regionName); | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | } | ||
246 | } | ||
247 | else | ||
214 | { | 248 | { |
215 | mapTile.Save(stream, ImageFormat.Jpeg); | 249 | m_log.WarnFormat("{0} Tile image generation failed", LogHeader); |
216 | jpgData = stream.ToArray(); | ||
217 | } | 250 | } |
218 | } | 251 | } |
252 | } | ||
219 | 253 | ||
220 | if (jpgData == Utils.EmptyBytes) | 254 | private void ConvertAndUploadMaptile(Image tileImage, uint locX, uint locY, string regionName) |
255 | { | ||
256 | byte[] jpgData = Utils.EmptyBytes; | ||
257 | |||
258 | using (MemoryStream stream = new MemoryStream()) | ||
221 | { | 259 | { |
222 | m_log.WarnFormat("[MAP IMAGE SERVICE MODULE]: Tile image generation failed"); | 260 | tileImage.Save(stream, ImageFormat.Jpeg); |
223 | return; | 261 | jpgData = stream.ToArray(); |
224 | } | 262 | } |
225 | 263 | if (jpgData != Utils.EmptyBytes) | |
226 | string reason = string.Empty; | 264 | { |
227 | if (!m_MapService.AddMapTile((int)scene.RegionInfo.RegionLocX, (int)scene.RegionInfo.RegionLocY, jpgData, out reason)) | 265 | string reason = string.Empty; |
266 | if (!m_MapService.AddMapTile((int)locX, (int)locY, jpgData, out reason)) | ||
267 | { | ||
268 | m_log.DebugFormat("{0} Unable to upload tile image for {1} at {2}-{3}: {4}", LogHeader, | ||
269 | regionName, locX, locY, reason); | ||
270 | } | ||
271 | } | ||
272 | else | ||
228 | { | 273 | { |
229 | m_log.DebugFormat("[MAP IMAGE SERVICE MODULE]: Unable to upload tile image for {0} at {1}-{2}: {3}", | 274 | m_log.WarnFormat("{0} Tile image generation failed for region {1}", LogHeader, regionName); |
230 | scene.RegionInfo.RegionName, scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY, reason); | ||
231 | } | 275 | } |
232 | } | 276 | } |
233 | } | 277 | } |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs index fd89428..56d9937 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs | |||
@@ -132,7 +132,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Neighbour | |||
132 | if (s.RegionInfo.RegionHandle == regionHandle) | 132 | if (s.RegionInfo.RegionHandle == regionHandle) |
133 | { | 133 | { |
134 | m_log.DebugFormat("[LOCAL NEIGHBOUR SERVICE CONNECTOR]: HelloNeighbour from region {0} to neighbour {1} at {2}-{3}", | 134 | m_log.DebugFormat("[LOCAL NEIGHBOUR SERVICE CONNECTOR]: HelloNeighbour from region {0} to neighbour {1} at {2}-{3}", |
135 | thisRegion.RegionName, s.Name, x / Constants.RegionSize, y / Constants.RegionSize); | 135 | thisRegion.RegionName, s.Name, Util.WorldToRegionLoc(x), Util.WorldToRegionLoc(y) ); |
136 | 136 | ||
137 | //m_log.Debug("[NEIGHBOUR CONNECTOR]: Found region to SendHelloNeighbour"); | 137 | //m_log.Debug("[NEIGHBOUR CONNECTOR]: Found region to SendHelloNeighbour"); |
138 | return s.IncomingHelloNeighbour(thisRegion); | 138 | return s.IncomingHelloNeighbour(thisRegion); |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs index d451b9e..f4807ad 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs | |||
@@ -96,14 +96,40 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
96 | 96 | ||
97 | /// <value> | 97 | /// <value> |
98 | /// Should the archive being loaded be merged with what is already on the region? | 98 | /// Should the archive being loaded be merged with what is already on the region? |
99 | /// Merging usually suppresses terrain and parcel loading | ||
99 | /// </value> | 100 | /// </value> |
100 | protected bool m_merge; | 101 | protected bool m_merge; |
101 | 102 | ||
102 | /// <value> | 103 | /// <value> |
104 | /// If true, force the loading of terrain from the oar file | ||
105 | /// </value> | ||
106 | protected bool m_forceTerrain; | ||
107 | |||
108 | /// <value> | ||
109 | /// If true, force the loading of parcels from the oar file | ||
110 | /// </value> | ||
111 | protected bool m_forceParcels; | ||
112 | |||
113 | /// <value> | ||
103 | /// Should we ignore any assets when reloading the archive? | 114 | /// Should we ignore any assets when reloading the archive? |
104 | /// </value> | 115 | /// </value> |
105 | protected bool m_skipAssets; | 116 | protected bool m_skipAssets; |
106 | 117 | ||
118 | /// <value> | ||
119 | /// Displacement added to each object as it is added to the world | ||
120 | /// </value> | ||
121 | protected Vector3 m_displacement = Vector3.Zero; | ||
122 | |||
123 | /// <value> | ||
124 | /// Rotation to apply to the objects as they are loaded. | ||
125 | /// </value> | ||
126 | protected float m_rotation = 0f; | ||
127 | |||
128 | /// <value> | ||
129 | /// Center around which to apply the rotation relative to the origional oar position | ||
130 | /// </value> | ||
131 | protected Vector3 m_rotationCenter = new Vector3(Constants.RegionSize / 2f, Constants.RegionSize / 2f, 0f); | ||
132 | |||
107 | /// <summary> | 133 | /// <summary> |
108 | /// Used to cache lookups for valid uuids. | 134 | /// Used to cache lookups for valid uuids. |
109 | /// </summary> | 135 | /// </summary> |
@@ -132,7 +158,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
132 | private IAssetService m_assetService = null; | 158 | private IAssetService m_assetService = null; |
133 | 159 | ||
134 | 160 | ||
135 | public ArchiveReadRequest(Scene scene, string loadPath, bool merge, bool skipAssets, Guid requestId) | 161 | public ArchiveReadRequest(Scene scene, string loadPath, Guid requestId, Dictionary<string,object>options) |
136 | { | 162 | { |
137 | m_rootScene = scene; | 163 | m_rootScene = scene; |
138 | 164 | ||
@@ -150,9 +176,15 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
150 | } | 176 | } |
151 | 177 | ||
152 | m_errorMessage = String.Empty; | 178 | m_errorMessage = String.Empty; |
153 | m_merge = merge; | 179 | m_merge = options.ContainsKey("merge"); |
154 | m_skipAssets = skipAssets; | 180 | m_forceTerrain = options.ContainsKey("forceTerrain"); |
181 | m_forceParcels = options.ContainsKey("forceParcels"); | ||
182 | m_skipAssets = options.ContainsKey("skipAssets"); | ||
155 | m_requestId = requestId; | 183 | m_requestId = requestId; |
184 | m_displacement = options.ContainsKey("displacement") ? (Vector3)options["displacement"] : Vector3.Zero; | ||
185 | m_rotation = options.ContainsKey("rotation") ? (float)options["rotation"] : 0f; | ||
186 | m_rotationCenter = options.ContainsKey("rotationCenter") ? (Vector3)options["rotationCenter"] | ||
187 | : new Vector3(Constants.RegionSize / 2f, Constants.RegionSize / 2f, 0f); | ||
156 | 188 | ||
157 | // Zero can never be a valid user id | 189 | // Zero can never be a valid user id |
158 | m_validUserUuids[UUID.Zero] = false; | 190 | m_validUserUuids[UUID.Zero] = false; |
@@ -161,13 +193,13 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
161 | m_assetService = m_rootScene.AssetService; | 193 | m_assetService = m_rootScene.AssetService; |
162 | } | 194 | } |
163 | 195 | ||
164 | public ArchiveReadRequest(Scene scene, Stream loadStream, bool merge, bool skipAssets, Guid requestId) | 196 | public ArchiveReadRequest(Scene scene, Stream loadStream, Guid requestId, Dictionary<string, object>options) |
165 | { | 197 | { |
166 | m_rootScene = scene; | 198 | m_rootScene = scene; |
167 | m_loadPath = null; | 199 | m_loadPath = null; |
168 | m_loadStream = loadStream; | 200 | m_loadStream = loadStream; |
169 | m_merge = merge; | 201 | m_skipAssets = options.ContainsKey("skipAssets"); |
170 | m_skipAssets = skipAssets; | 202 | m_merge = options.ContainsKey("merge"); |
171 | m_requestId = requestId; | 203 | m_requestId = requestId; |
172 | 204 | ||
173 | // Zero can never be a valid user id | 205 | // Zero can never be a valid user id |
@@ -243,7 +275,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
243 | if ((successfulAssetRestores + failedAssetRestores) % 250 == 0) | 275 | if ((successfulAssetRestores + failedAssetRestores) % 250 == 0) |
244 | m_log.Debug("[ARCHIVER]: Loaded " + successfulAssetRestores + " assets and failed to load " + failedAssetRestores + " assets..."); | 276 | m_log.Debug("[ARCHIVER]: Loaded " + successfulAssetRestores + " assets and failed to load " + failedAssetRestores + " assets..."); |
245 | } | 277 | } |
246 | else if (!m_merge && filePath.StartsWith(ArchiveConstants.TERRAINS_PATH)) | 278 | else if (filePath.StartsWith(ArchiveConstants.TERRAINS_PATH) && (!m_merge || m_forceTerrain)) |
247 | { | 279 | { |
248 | LoadTerrain(scene, filePath, data); | 280 | LoadTerrain(scene, filePath, data); |
249 | } | 281 | } |
@@ -251,7 +283,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
251 | { | 283 | { |
252 | LoadRegionSettings(scene, filePath, data, dearchivedScenes); | 284 | LoadRegionSettings(scene, filePath, data, dearchivedScenes); |
253 | } | 285 | } |
254 | else if (!m_merge && filePath.StartsWith(ArchiveConstants.LANDDATA_PATH)) | 286 | else if (filePath.StartsWith(ArchiveConstants.LANDDATA_PATH) && (!m_merge || m_forceParcels)) |
255 | { | 287 | { |
256 | sceneContext.SerialisedParcels.Add(Encoding.UTF8.GetString(data)); | 288 | sceneContext.SerialisedParcels.Add(Encoding.UTF8.GetString(data)); |
257 | } | 289 | } |
@@ -422,6 +454,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
422 | // Reload serialized prims | 454 | // Reload serialized prims |
423 | m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count); | 455 | m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count); |
424 | 456 | ||
457 | float angle = (float)(m_rotation / 180.0 * Math.PI); | ||
458 | OpenMetaverse.Quaternion rot = OpenMetaverse.Quaternion.CreateFromAxisAngle(0, 0, 1, angle); | ||
459 | |||
425 | UUID oldTelehubUUID = scene.RegionInfo.RegionSettings.TelehubObject; | 460 | UUID oldTelehubUUID = scene.RegionInfo.RegionSettings.TelehubObject; |
426 | 461 | ||
427 | IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>(); | 462 | IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>(); |
@@ -445,6 +480,23 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
445 | 480 | ||
446 | SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject); | 481 | SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject); |
447 | 482 | ||
483 | // Happily this does not do much to the object since it hasn't been added to the scene yet | ||
484 | if (sceneObject.AttachmentPoint == 0) | ||
485 | { | ||
486 | if (angle != 0f) | ||
487 | { | ||
488 | sceneObject.RootPart.RotationOffset = rot * sceneObject.GroupRotation; | ||
489 | Vector3 offset = sceneObject.AbsolutePosition - m_rotationCenter; | ||
490 | offset *= rot; | ||
491 | sceneObject.AbsolutePosition = m_rotationCenter + offset; | ||
492 | } | ||
493 | if (m_displacement != Vector3.Zero) | ||
494 | { | ||
495 | sceneObject.AbsolutePosition += m_displacement; | ||
496 | } | ||
497 | } | ||
498 | |||
499 | |||
448 | bool isTelehub = (sceneObject.UUID == oldTelehubUUID) && (oldTelehubUUID != UUID.Zero); | 500 | bool isTelehub = (sceneObject.UUID == oldTelehubUUID) && (oldTelehubUUID != UUID.Zero); |
449 | 501 | ||
450 | // For now, give all incoming scene objects new uuids. This will allow scenes to be cloned | 502 | // For now, give all incoming scene objects new uuids. This will allow scenes to be cloned |
@@ -549,6 +601,13 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
549 | foreach (string serialisedParcel in serialisedParcels) | 601 | foreach (string serialisedParcel in serialisedParcels) |
550 | { | 602 | { |
551 | LandData parcel = LandDataSerializer.Deserialize(serialisedParcel); | 603 | LandData parcel = LandDataSerializer.Deserialize(serialisedParcel); |
604 | |||
605 | if (m_displacement != Vector3.Zero) | ||
606 | { | ||
607 | Vector3 parcelDisp = new Vector3(m_displacement.X, m_displacement.Y, 0f); | ||
608 | parcel.AABBMin += parcelDisp; | ||
609 | parcel.AABBMax += parcelDisp; | ||
610 | } | ||
552 | 611 | ||
553 | // Validate User and Group UUID's | 612 | // Validate User and Group UUID's |
554 | 613 | ||
@@ -809,7 +868,15 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
809 | ITerrainModule terrainModule = scene.RequestModuleInterface<ITerrainModule>(); | 868 | ITerrainModule terrainModule = scene.RequestModuleInterface<ITerrainModule>(); |
810 | 869 | ||
811 | MemoryStream ms = new MemoryStream(data); | 870 | MemoryStream ms = new MemoryStream(data); |
812 | terrainModule.LoadFromStream(terrainPath, ms); | 871 | if (m_displacement != Vector3.Zero) |
872 | { | ||
873 | Vector2 terrainDisplacement = new Vector2(m_displacement.X, m_displacement.Y); | ||
874 | terrainModule.LoadFromStream(terrainPath, terrainDisplacement, ms); | ||
875 | } | ||
876 | else | ||
877 | { | ||
878 | terrainModule.LoadFromStream(terrainPath, ms); | ||
879 | } | ||
813 | ms.Close(); | 880 | ms.Close(); |
814 | 881 | ||
815 | m_log.DebugFormat("[ARCHIVER]: Restored terrain {0}", terrainPath); | 882 | m_log.DebugFormat("[ARCHIVER]: Restored terrain {0}", terrainPath); |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs index 7a844f4..cd95ee9 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs | |||
@@ -533,7 +533,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
533 | if (isMegaregion) | 533 | if (isMegaregion) |
534 | size = rcMod.GetSizeOfMegaregion(scene.RegionInfo.RegionID); | 534 | size = rcMod.GetSizeOfMegaregion(scene.RegionInfo.RegionID); |
535 | else | 535 | else |
536 | size = new Vector2((float)Constants.RegionSize, (float)Constants.RegionSize); | 536 | size = new Vector2((float)scene.RegionInfo.RegionSizeX, (float)scene.RegionInfo.RegionSizeY); |
537 | 537 | ||
538 | xtw.WriteElementString("is_megaregion", isMegaregion.ToString()); | 538 | xtw.WriteElementString("is_megaregion", isMegaregion.ToString()); |
539 | xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y)); | 539 | xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y)); |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs index 1be6386..2a6f1eb 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs | |||
@@ -33,11 +33,14 @@ using log4net; | |||
33 | using NDesk.Options; | 33 | using NDesk.Options; |
34 | using Nini.Config; | 34 | using Nini.Config; |
35 | using Mono.Addins; | 35 | using Mono.Addins; |
36 | |||
36 | using OpenSim.Framework; | 37 | using OpenSim.Framework; |
37 | using OpenSim.Framework.Console; | 38 | using OpenSim.Framework.Console; |
38 | using OpenSim.Region.Framework.Interfaces; | 39 | using OpenSim.Region.Framework.Interfaces; |
39 | using OpenSim.Region.Framework.Scenes; | 40 | using OpenSim.Region.Framework.Scenes; |
40 | 41 | ||
42 | using OpenMetaverse; | ||
43 | |||
41 | namespace OpenSim.Region.CoreModules.World.Archiver | 44 | namespace OpenSim.Region.CoreModules.World.Archiver |
42 | { | 45 | { |
43 | /// <summary> | 46 | /// <summary> |
@@ -101,9 +104,36 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
101 | { | 104 | { |
102 | bool mergeOar = false; | 105 | bool mergeOar = false; |
103 | bool skipAssets = false; | 106 | bool skipAssets = false; |
107 | bool forceTerrain = false; | ||
108 | bool forceParcels = false; | ||
109 | Vector3 displacement = new Vector3(0f, 0f, 0f); | ||
110 | float rotation = 0f; | ||
111 | Vector3 rotationCenter = new Vector3(Constants.RegionSize / 2f, Constants.RegionSize / 2f, 0); | ||
104 | 112 | ||
105 | OptionSet options = new OptionSet().Add("m|merge", delegate (string v) { mergeOar = v != null; }); | 113 | OptionSet options = new OptionSet(); |
106 | options.Add("s|skip-assets", delegate (string v) { skipAssets = v != null; }); | 114 | options.Add("m|merge", delegate (string v) { mergeOar = (v != null); }); |
115 | options.Add("s|skip-assets", delegate (string v) { skipAssets = (v != null); }); | ||
116 | options.Add("forceterrain", delegate (string v) { forceTerrain = (v != null); }); | ||
117 | options.Add("forceparcels", delegate (string v) { forceParcels = (v != null); }); | ||
118 | options.Add("displacement=", delegate (string v) { | ||
119 | try | ||
120 | { | ||
121 | displacement = v == null ? Vector3.Zero : Vector3.Parse(v); | ||
122 | } | ||
123 | catch (Exception e) | ||
124 | { | ||
125 | m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing displacement"); | ||
126 | displacement = new Vector3(0f, 0f, 0f); | ||
127 | } | ||
128 | }); | ||
129 | options.Add("rotation=", delegate (string v) { | ||
130 | rotation = float.Parse(v); | ||
131 | rotation = Util.Clamp<float>(rotation, -359f, 359f); | ||
132 | }); | ||
133 | options.Add("rotationcenter=", delegate (string v) { | ||
134 | // RA 20130119: libomv's Vector2.Parse doesn't work. Need to use vector3 for the moment | ||
135 | rotationCenter = Vector3.Parse(v); | ||
136 | }); | ||
107 | 137 | ||
108 | // Send a message to the region ready module | 138 | // Send a message to the region ready module |
109 | /* bluewall* Disable this for the time being | 139 | /* bluewall* Disable this for the time being |
@@ -122,13 +152,22 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
122 | // foreach (string param in mainParams) | 152 | // foreach (string param in mainParams) |
123 | // m_log.DebugFormat("GOT PARAM [{0}]", param); | 153 | // m_log.DebugFormat("GOT PARAM [{0}]", param); |
124 | 154 | ||
155 | Dictionary<string, object> archiveOptions = new Dictionary<string, object>(); | ||
156 | if (mergeOar) archiveOptions.Add("merge", null); | ||
157 | if (skipAssets) archiveOptions.Add("skipAssets", null); | ||
158 | if (forceTerrain) archiveOptions.Add("forceTerrain", null); | ||
159 | if (forceParcels) archiveOptions.Add("forceParcels", null); | ||
160 | archiveOptions.Add("displacement", displacement); | ||
161 | archiveOptions.Add("rotation", rotation); | ||
162 | archiveOptions.Add("rotationCenter", rotationCenter); | ||
163 | |||
125 | if (mainParams.Count > 2) | 164 | if (mainParams.Count > 2) |
126 | { | 165 | { |
127 | DearchiveRegion(mainParams[2], mergeOar, skipAssets, Guid.Empty); | 166 | DearchiveRegion(mainParams[2], Guid.Empty, archiveOptions); |
128 | } | 167 | } |
129 | else | 168 | else |
130 | { | 169 | { |
131 | DearchiveRegion(DEFAULT_OAR_BACKUP_FILENAME, mergeOar, skipAssets, Guid.Empty); | 170 | DearchiveRegion(DEFAULT_OAR_BACKUP_FILENAME, Guid.Empty, archiveOptions); |
132 | } | 171 | } |
133 | } | 172 | } |
134 | 173 | ||
@@ -198,25 +237,27 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
198 | 237 | ||
199 | public void DearchiveRegion(string loadPath) | 238 | public void DearchiveRegion(string loadPath) |
200 | { | 239 | { |
201 | DearchiveRegion(loadPath, false, false, Guid.Empty); | 240 | Dictionary<string, object> archiveOptions = new Dictionary<string, object>(); |
241 | DearchiveRegion(loadPath, Guid.Empty, archiveOptions); | ||
202 | } | 242 | } |
203 | 243 | ||
204 | public void DearchiveRegion(string loadPath, bool merge, bool skipAssets, Guid requestId) | 244 | public void DearchiveRegion(string loadPath, Guid requestId, Dictionary<string,object> options) |
205 | { | 245 | { |
206 | m_log.InfoFormat( | 246 | m_log.InfoFormat( |
207 | "[ARCHIVER]: Loading archive to region {0} from {1}", Scene.RegionInfo.RegionName, loadPath); | 247 | "[ARCHIVER]: Loading archive to region {0} from {1}", Scene.RegionInfo.RegionName, loadPath); |
208 | 248 | ||
209 | new ArchiveReadRequest(Scene, loadPath, merge, skipAssets, requestId).DearchiveRegion(); | 249 | new ArchiveReadRequest(Scene, loadPath, requestId, options).DearchiveRegion(); |
210 | } | 250 | } |
211 | 251 | ||
212 | public void DearchiveRegion(Stream loadStream) | 252 | public void DearchiveRegion(Stream loadStream) |
213 | { | 253 | { |
214 | DearchiveRegion(loadStream, false, false, Guid.Empty); | 254 | Dictionary<string, object> archiveOptions = new Dictionary<string, object>(); |
255 | DearchiveRegion(loadStream, Guid.Empty, archiveOptions); | ||
215 | } | 256 | } |
216 | 257 | ||
217 | public void DearchiveRegion(Stream loadStream, bool merge, bool skipAssets, Guid requestId) | 258 | public void DearchiveRegion(Stream loadStream, Guid requestId, Dictionary<string, object> options) |
218 | { | 259 | { |
219 | new ArchiveReadRequest(Scene, loadStream, merge, skipAssets, requestId).DearchiveRegion(); | 260 | new ArchiveReadRequest(Scene, loadStream, requestId, options).DearchiveRegion(); |
220 | } | 261 | } |
221 | } | 262 | } |
222 | } | 263 | } |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs index eec1cec..53f41f9 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs | |||
@@ -224,8 +224,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
224 | 224 | ||
225 | byte[] data = tar.ReadEntry(out filePath, out tarEntryType); | 225 | byte[] data = tar.ReadEntry(out filePath, out tarEntryType); |
226 | Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); | 226 | Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); |
227 | 227 | ||
228 | ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); | 228 | Dictionary<string, object> archiveOptions = new Dictionary<string, object>(); |
229 | ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions); | ||
229 | arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); | 230 | arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); |
230 | 231 | ||
231 | Assert.That(arr.ControlFileLoaded, Is.True); | 232 | Assert.That(arr.ControlFileLoaded, Is.True); |
@@ -308,8 +309,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
308 | 309 | ||
309 | byte[] data = tar.ReadEntry(out filePath, out tarEntryType); | 310 | byte[] data = tar.ReadEntry(out filePath, out tarEntryType); |
310 | Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); | 311 | Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); |
311 | 312 | ||
312 | ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); | 313 | Dictionary<string, object> archiveOptions = new Dictionary<string, object>(); |
314 | ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions); | ||
313 | arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); | 315 | arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); |
314 | 316 | ||
315 | Assert.That(arr.ControlFileLoaded, Is.True); | 317 | Assert.That(arr.ControlFileLoaded, Is.True); |
@@ -752,7 +754,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
752 | byte[] archive = archiveWriteStream.ToArray(); | 754 | byte[] archive = archiveWriteStream.ToArray(); |
753 | MemoryStream archiveReadStream = new MemoryStream(archive); | 755 | MemoryStream archiveReadStream = new MemoryStream(archive); |
754 | 756 | ||
755 | m_archiverModule.DearchiveRegion(archiveReadStream, true, false, Guid.Empty); | 757 | Dictionary<string, object> archiveOptions = new Dictionary<string, object>(); |
758 | archiveOptions.Add("merge", null); | ||
759 | m_archiverModule.DearchiveRegion(archiveReadStream, Guid.Empty, archiveOptions); | ||
756 | 760 | ||
757 | SceneObjectPart object1Existing = m_scene.GetSceneObjectPart(part1.Name); | 761 | SceneObjectPart object1Existing = m_scene.GetSceneObjectPart(part1.Name); |
758 | Assert.That(object1Existing, Is.Not.Null, "object1 was not present after merge"); | 762 | Assert.That(object1Existing, Is.Not.Null, "object1 was not present after merge"); |
@@ -860,7 +864,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
860 | byte[] data = tar.ReadEntry(out filePath, out tarEntryType); | 864 | byte[] data = tar.ReadEntry(out filePath, out tarEntryType); |
861 | Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); | 865 | Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); |
862 | 866 | ||
863 | ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); | 867 | Dictionary<string, object> archiveOptions = new Dictionary<string, object>(); |
868 | ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions); | ||
864 | arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); | 869 | arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); |
865 | 870 | ||
866 | Assert.That(arr.ControlFileLoaded, Is.True); | 871 | Assert.That(arr.ControlFileLoaded, Is.True); |
diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index 73c4d6c..99db7ff 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs | |||
@@ -64,6 +64,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
64 | public class LandManagementModule : INonSharedRegionModule | 64 | public class LandManagementModule : INonSharedRegionModule |
65 | { | 65 | { |
66 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 66 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
67 | private static readonly string LogHeader = "[LAND MANAGEMENT MODULE]"; | ||
67 | 68 | ||
68 | private static readonly string remoteParcelRequestPath = "0009/"; | 69 | private static readonly string remoteParcelRequestPath = "0009/"; |
69 | 70 | ||
@@ -74,15 +75,11 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
74 | protected IPrimCountModule m_primCountModule; | 75 | protected IPrimCountModule m_primCountModule; |
75 | protected IDialogModule m_Dialog; | 76 | protected IDialogModule m_Dialog; |
76 | 77 | ||
77 | // Minimum for parcels to work is 64m even if we don't actually use them. | ||
78 | #pragma warning disable 0429 | ||
79 | private const int landArrayMax = ((int)((int)Constants.RegionSize / 4) >= 64) ? (int)((int)Constants.RegionSize / 4) : 64; | ||
80 | #pragma warning restore 0429 | ||
81 | |||
82 | /// <value> | 78 | /// <value> |
83 | /// Local land ids at specified region co-ordinates (region size / 4) | 79 | /// Local land ids at specified region co-ordinates (region size / 4) |
84 | /// </value> | 80 | /// </value> |
85 | private readonly int[,] m_landIDList = new int[landArrayMax, landArrayMax]; | 81 | private int[,] m_landIDList; |
82 | private const int landUnit = 4; | ||
86 | 83 | ||
87 | /// <value> | 84 | /// <value> |
88 | /// Land objects keyed by local id | 85 | /// Land objects keyed by local id |
@@ -115,6 +112,8 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
115 | public void AddRegion(Scene scene) | 112 | public void AddRegion(Scene scene) |
116 | { | 113 | { |
117 | m_scene = scene; | 114 | m_scene = scene; |
115 | m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; | ||
116 | |||
118 | m_landIDList.Initialize(); | 117 | m_landIDList.Initialize(); |
119 | landChannel = new LandChannel(scene, this); | 118 | landChannel = new LandChannel(scene, this); |
120 | 119 | ||
@@ -297,6 +296,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
297 | { | 296 | { |
298 | m_landList.Clear(); | 297 | m_landList.Clear(); |
299 | m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1; | 298 | m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1; |
299 | m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; | ||
300 | m_landIDList.Initialize(); | 300 | m_landIDList.Initialize(); |
301 | } | 301 | } |
302 | } | 302 | } |
@@ -311,7 +311,8 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
311 | "[LAND MANAGEMENT MODULE]: Creating default parcel for region {0}", m_scene.RegionInfo.RegionName); | 311 | "[LAND MANAGEMENT MODULE]: Creating default parcel for region {0}", m_scene.RegionInfo.RegionName); |
312 | 312 | ||
313 | ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene); | 313 | ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene); |
314 | fullSimParcel.SetLandBitmap(fullSimParcel.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize)); | 314 | fullSimParcel.SetLandBitmap(fullSimParcel.GetSquareLandBitmap(0, 0, |
315 | (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY)); | ||
315 | fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; | 316 | fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; |
316 | fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch(); | 317 | fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch(); |
317 | 318 | ||
@@ -438,8 +439,8 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
438 | 439 | ||
439 | public void SendLandUpdate(ScenePresence avatar, bool force) | 440 | public void SendLandUpdate(ScenePresence avatar, bool force) |
440 | { | 441 | { |
441 | ILandObject over = GetLandObject((int)Math.Min(((int)Constants.RegionSize - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.X))), | 442 | ILandObject over = GetLandObject((int)Math.Min(((int)m_scene.RegionInfo.RegionSizeX - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.X))), |
442 | (int)Math.Min(((int)Constants.RegionSize - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.Y)))); | 443 | (int)Math.Min(((int)m_scene.RegionInfo.RegionSizeY - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.Y)))); |
443 | 444 | ||
444 | if (over != null) | 445 | if (over != null) |
445 | { | 446 | { |
@@ -605,17 +606,29 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
605 | new_land.LandData.LocalID = newLandLocalID; | 606 | new_land.LandData.LocalID = newLandLocalID; |
606 | 607 | ||
607 | bool[,] landBitmap = new_land.GetLandBitmap(); | 608 | bool[,] landBitmap = new_land.GetLandBitmap(); |
608 | for (int x = 0; x < landArrayMax; x++) | 609 | // m_log.DebugFormat("{0} AddLandObject. new_land.bitmapSize=({1},{2}). newLocalID={3}", |
610 | // LogHeader, landBitmap.GetLength(0), landBitmap.GetLength(1), newLandLocalID); | ||
611 | |||
612 | if (landBitmap.GetLength(0) != m_landIDList.GetLength(0) || landBitmap.GetLength(1) != m_landIDList.GetLength(1)) | ||
609 | { | 613 | { |
610 | for (int y = 0; y < landArrayMax; y++) | 614 | // Going to variable sized regions can cause mismatches |
615 | m_log.ErrorFormat("{0} AddLandObject. Added land bitmap different size than region ID map. bitmapSize=({1},{2}), landIDSize=({3},{4})", | ||
616 | LogHeader, landBitmap.GetLength(0), landBitmap.GetLength(1), m_landIDList.GetLength(0), m_landIDList.GetLength(1) ); | ||
617 | } | ||
618 | else | ||
619 | { | ||
620 | for (int x = 0; x < landBitmap.GetLength(0); x++) | ||
611 | { | 621 | { |
612 | if (landBitmap[x, y]) | 622 | for (int y = 0; y < landBitmap.GetLength(1); y++) |
613 | { | 623 | { |
614 | // m_log.DebugFormat( | 624 | if (landBitmap[x, y]) |
615 | // "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}", | 625 | { |
616 | // new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName); | 626 | // m_log.DebugFormat( |
617 | 627 | // "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}", | |
618 | m_landIDList[x, y] = newLandLocalID; | 628 | // new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName); |
629 | |||
630 | m_landIDList[x, y] = newLandLocalID; | ||
631 | } | ||
619 | } | 632 | } |
620 | } | 633 | } |
621 | } | 634 | } |
@@ -637,9 +650,9 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
637 | ILandObject land; | 650 | ILandObject land; |
638 | lock (m_landList) | 651 | lock (m_landList) |
639 | { | 652 | { |
640 | for (int x = 0; x < 64; x++) | 653 | for (int x = 0; x < m_landIDList.GetLength(0); x++) |
641 | { | 654 | { |
642 | for (int y = 0; y < 64; y++) | 655 | for (int y = 0; y < m_landIDList.GetLength(1); y++) |
643 | { | 656 | { |
644 | if (m_landIDList[x, y] == local_id) | 657 | if (m_landIDList[x, y] == local_id) |
645 | { | 658 | { |
@@ -691,9 +704,9 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
691 | bool[,] landBitmapSlave = slave.GetLandBitmap(); | 704 | bool[,] landBitmapSlave = slave.GetLandBitmap(); |
692 | lock (m_landList) | 705 | lock (m_landList) |
693 | { | 706 | { |
694 | for (int x = 0; x < 64; x++) | 707 | for (int x = 0; x < landBitmapSlave.GetLength(0); x++) |
695 | { | 708 | { |
696 | for (int y = 0; y < 64; y++) | 709 | for (int y = 0; y < landBitmapSlave.GetLength(1); y++) |
697 | { | 710 | { |
698 | if (landBitmapSlave[x, y]) | 711 | if (landBitmapSlave[x, y]) |
699 | { | 712 | { |
@@ -727,23 +740,28 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
727 | /// <returns>Land object at the point supplied</returns> | 740 | /// <returns>Land object at the point supplied</returns> |
728 | public ILandObject GetLandObject(float x_float, float y_float) | 741 | public ILandObject GetLandObject(float x_float, float y_float) |
729 | { | 742 | { |
743 | return GetLandObject((int)x_float, (int)y_float, true /* returnNullIfLandObjectNotFound */); | ||
744 | /* | ||
730 | int x; | 745 | int x; |
731 | int y; | 746 | int y; |
732 | 747 | ||
733 | if (x_float >= Constants.RegionSize || x_float < 0 || y_float >= Constants.RegionSize || y_float < 0) | 748 | if (x_float >= m_scene.RegionInfo.RegionSizeX || x_float < 0 || y_float >= m_scene.RegionInfo.RegionSizeX || y_float < 0) |
734 | return null; | 749 | return null; |
735 | 750 | ||
736 | try | 751 | try |
737 | { | 752 | { |
738 | x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / 4.0)); | 753 | x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / (float)landUnit)); |
739 | y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / 4.0)); | 754 | y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / (float)landUnit)); |
740 | } | 755 | } |
741 | catch (OverflowException) | 756 | catch (OverflowException) |
742 | { | 757 | { |
743 | return null; | 758 | return null; |
744 | } | 759 | } |
745 | 760 | ||
746 | if (x >= 64 || y >= 64 || x < 0 || y < 0) | 761 | if (x >= (m_scene.RegionInfo.RegionSizeX / landUnit) |
762 | || y >= (m_scene.RegionInfo.RegionSizeY / landUnit) | ||
763 | || x < 0 | ||
764 | || y < 0) | ||
747 | { | 765 | { |
748 | return null; | 766 | return null; |
749 | } | 767 | } |
@@ -759,38 +777,122 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
759 | // m_log.DebugFormat( | 777 | // m_log.DebugFormat( |
760 | // "[LAND MANAGEMENT MODULE]: No land object found at ({0}, {1}) on {2}", | 778 | // "[LAND MANAGEMENT MODULE]: No land object found at ({0}, {1}) on {2}", |
761 | // x, y, m_scene.RegionInfo.RegionName); | 779 | // x, y, m_scene.RegionInfo.RegionName); |
762 | 780 | ||
763 | if (m_landList.ContainsKey(m_landIDList[x, y])) | 781 | try |
764 | return m_landList[m_landIDList[x, y]]; | 782 | { |
783 | if (m_landList.ContainsKey(m_landIDList[x, y])) | ||
784 | return m_landList[m_landIDList[x, y]]; | ||
785 | } | ||
786 | catch (Exception e) | ||
787 | { | ||
788 | m_log.DebugFormat("{0} GetLandObject exception. x={1}, y={2}, m_landIDList.len=({3},{4})", | ||
789 | LogHeader, x, y, m_landIDList.GetLength(0), m_landIDList.GetLength(1)); | ||
790 | } | ||
765 | 791 | ||
766 | return null; | 792 | return null; |
767 | } | 793 | } |
794 | */ | ||
768 | } | 795 | } |
769 | 796 | ||
797 | // Public entry. | ||
798 | // Throws exception if land object is not found | ||
770 | public ILandObject GetLandObject(int x, int y) | 799 | public ILandObject GetLandObject(int x, int y) |
771 | { | 800 | { |
772 | if (x >= Convert.ToInt32(Constants.RegionSize) || y >= Convert.ToInt32(Constants.RegionSize) || x < 0 || y < 0) | 801 | return GetLandObject(x, y, false /* returnNullIfLandObjectNotFound */); |
802 | } | ||
803 | |||
804 | // Given a region position, return the parcel land object for that location | ||
805 | private ILandObject GetLandObject(int x, int y, bool returnNullIfLandObjectNotFound) | ||
806 | { | ||
807 | ILandObject ret = null; | ||
808 | |||
809 | if (x >= m_scene.RegionInfo.RegionSizeX || y >= m_scene.RegionInfo.RegionSizeY || x < 0 || y < 0) | ||
773 | { | 810 | { |
774 | // These exceptions here will cause a lot of complaints from the users specifically because | 811 | // These exceptions here will cause a lot of complaints from the users specifically because |
775 | // they happen every time at border crossings | 812 | // they happen every time at border crossings |
776 | throw new Exception("Error: Parcel not found at point " + x + ", " + y); | 813 | if (returnNullIfLandObjectNotFound) |
814 | return null; | ||
815 | else | ||
816 | throw new Exception( | ||
817 | String.Format("{0} GetLandObject for non-existant position. Region={1}, pos=<{2},{3}", | ||
818 | LogHeader, m_scene.RegionInfo.RegionName, x, y) | ||
819 | ); | ||
777 | } | 820 | } |
778 | 821 | ||
779 | lock (m_landIDList) | 822 | lock (m_landIDList) |
780 | { | 823 | { |
781 | try | 824 | try |
782 | { | 825 | { |
783 | return m_landList[m_landIDList[x / 4, y / 4]]; | 826 | int landID = m_landIDList[x / landUnit, y / landUnit]; |
827 | if (landID == 0) | ||
828 | { | ||
829 | // Zero is the uninitialized value saying there is no parcel for this location. | ||
830 | // This sometimes happens when terrain is resized. | ||
831 | if (m_landList.Count == 1) | ||
832 | { | ||
833 | int onlyParcelID = 0; | ||
834 | ILandObject onlyLandObject = null; | ||
835 | foreach (KeyValuePair<int, ILandObject> kvp in m_landList) | ||
836 | { | ||
837 | onlyParcelID = kvp.Key; | ||
838 | onlyLandObject = kvp.Value; | ||
839 | break; | ||
840 | } | ||
841 | |||
842 | // There is only one parcel. Grow it to fill all the unallocated spaces. | ||
843 | for (int xx = 0; xx < m_landIDList.GetLength(0); xx++) | ||
844 | for (int yy = 0; yy < m_landIDList.GetLength(1); yy++) | ||
845 | if (m_landIDList[xx, yy] == 0) | ||
846 | m_landIDList[xx, yy] = onlyParcelID; | ||
847 | |||
848 | onlyLandObject.LandBitmap = CreateBitmapForID(onlyParcelID); | ||
849 | landID = onlyParcelID; | ||
850 | } | ||
851 | else | ||
852 | { | ||
853 | // There are several other parcels so we must create a new one for the unassigned space | ||
854 | ILandObject newLand = new LandObject(UUID.Zero, false, m_scene); | ||
855 | // Claim all the unclaimed "0" ids | ||
856 | newLand.SetLandBitmap(CreateBitmapForID(0)); | ||
857 | newLand.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; | ||
858 | newLand.LandData.ClaimDate = Util.UnixTimeSinceEpoch(); | ||
859 | AddLandObject(newLand); | ||
860 | landID = m_lastLandLocalID; | ||
861 | } | ||
862 | } | ||
863 | |||
864 | ret = m_landList[landID]; | ||
784 | } | 865 | } |
785 | catch (IndexOutOfRangeException) | 866 | catch (IndexOutOfRangeException) |
786 | { | 867 | { |
787 | // m_log.WarnFormat( | 868 | m_log.ErrorFormat( |
788 | // "[LAND MANAGEMENT MODULE]: Tried to retrieve land object from out of bounds co-ordinate ({0},{1}) in {2}", | 869 | "{0} GetLandObject: Tried to retrieve land object from out of bounds co-ordinate ({1},{2}) in {3}. landListSize=({4},{5})", |
789 | // x, y, m_scene.RegionInfo.RegionName); | 870 | LogHeader, x, y, m_scene.RegionInfo.RegionName, m_landIDList.GetLength(0), m_landIDList.GetLength(1)); |
790 | 871 | return null; | |
872 | } | ||
873 | catch | ||
874 | { | ||
875 | m_log.ErrorFormat( | ||
876 | "{0} GetLandObject: LandID not in landlist. XY=<{1},{2}> in {3}. landID[x,y]={4}", | ||
877 | LogHeader, x, y, m_scene.RegionInfo.RegionName, m_landIDList[x/landUnit, y/landUnit]); | ||
791 | return null; | 878 | return null; |
792 | } | 879 | } |
793 | } | 880 | } |
881 | return ret; | ||
882 | } | ||
883 | |||
884 | // Create a 'parcel is here' bitmap for the parcel identified by the passed landID | ||
885 | private bool[,] CreateBitmapForID(int landID) | ||
886 | { | ||
887 | bool[,] ret = new bool[m_landIDList.GetLength(0), m_landIDList.GetLength(1)]; | ||
888 | ret.Initialize(); | ||
889 | |||
890 | for (int xx = 0; xx < m_landIDList.GetLength(0); xx++) | ||
891 | for (int yy = 0; yy < m_landIDList.GetLength(0); yy++) | ||
892 | if (m_landIDList[xx, yy] == landID) | ||
893 | ret[xx, yy] = true; | ||
894 | |||
895 | return ret; | ||
794 | } | 896 | } |
795 | 897 | ||
796 | #endregion | 898 | #endregion |
@@ -1053,85 +1155,93 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1053 | byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET]; | 1155 | byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET]; |
1054 | int byteArrayCount = 0; | 1156 | int byteArrayCount = 0; |
1055 | int sequenceID = 0; | 1157 | int sequenceID = 0; |
1056 | int blockmeters = 4 * (int) Constants.RegionSize/(int)Constants.TerrainPatchSize; | ||
1057 | |||
1058 | 1158 | ||
1059 | for (int y = 0; y < blockmeters; y++) | 1159 | // Layer data is in landUnit (4m) chunks |
1160 | for (int y = 0; y < m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / landUnit); y++) | ||
1060 | { | 1161 | { |
1061 | for (int x = 0; x < blockmeters; x++) | 1162 | for (int x = 0; x < m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / landUnit); x++) |
1062 | { | 1163 | { |
1063 | byte tempByte = 0; //This represents the byte for the current 4x4 | 1164 | byteArray[byteArrayCount] = BuildLayerByte(GetLandObject(x * landUnit, y * landUnit), x, y, remote_client); |
1165 | byteArrayCount++; | ||
1166 | if (byteArrayCount >= LAND_BLOCKS_PER_PACKET) | ||
1167 | { | ||
1168 | remote_client.SendLandParcelOverlay(byteArray, sequenceID); | ||
1169 | byteArrayCount = 0; | ||
1170 | sequenceID++; | ||
1171 | byteArray = new byte[LAND_BLOCKS_PER_PACKET]; | ||
1172 | } | ||
1064 | 1173 | ||
1065 | ILandObject currentParcelBlock = GetLandObject(x * 4, y * 4); | 1174 | } |
1175 | } | ||
1176 | if (byteArrayCount != 0) | ||
1177 | { | ||
1178 | remote_client.SendLandParcelOverlay(byteArray, sequenceID); | ||
1179 | } | ||
1180 | } | ||
1066 | 1181 | ||
1067 | if (currentParcelBlock != null) | 1182 | private byte BuildLayerByte(ILandObject currentParcelBlock, int x, int y, IClientAPI remote_client) |
1068 | { | 1183 | { |
1069 | if (currentParcelBlock.LandData.OwnerID == remote_client.AgentId) | 1184 | byte tempByte = 0; //This represents the byte for the current 4x4 |
1070 | { | ||
1071 | //Owner Flag | ||
1072 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER); | ||
1073 | } | ||
1074 | else if (currentParcelBlock.LandData.SalePrice > 0 && | ||
1075 | (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero || | ||
1076 | currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId)) | ||
1077 | { | ||
1078 | //Sale Flag | ||
1079 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_IS_FOR_SALE); | ||
1080 | } | ||
1081 | else if (currentParcelBlock.LandData.OwnerID == UUID.Zero) | ||
1082 | { | ||
1083 | //Public Flag | ||
1084 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_PUBLIC); | ||
1085 | } | ||
1086 | else | ||
1087 | { | ||
1088 | //Other Flag | ||
1089 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_OTHER); | ||
1090 | } | ||
1091 | 1185 | ||
1092 | //Now for border control | 1186 | if (currentParcelBlock != null) |
1187 | { | ||
1188 | if (currentParcelBlock.LandData.OwnerID == remote_client.AgentId) | ||
1189 | { | ||
1190 | //Owner Flag | ||
1191 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER); | ||
1192 | } | ||
1193 | else if (currentParcelBlock.LandData.SalePrice > 0 && | ||
1194 | (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero || | ||
1195 | currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId)) | ||
1196 | { | ||
1197 | //Sale Flag | ||
1198 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_IS_FOR_SALE); | ||
1199 | } | ||
1200 | else if (currentParcelBlock.LandData.OwnerID == UUID.Zero) | ||
1201 | { | ||
1202 | //Public Flag | ||
1203 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_PUBLIC); | ||
1204 | } | ||
1205 | else | ||
1206 | { | ||
1207 | //Other Flag | ||
1208 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_OTHER); | ||
1209 | } | ||
1093 | 1210 | ||
1094 | ILandObject westParcel = null; | 1211 | //Now for border control |
1095 | ILandObject southParcel = null; | ||
1096 | if (x > 0) | ||
1097 | { | ||
1098 | westParcel = GetLandObject((x - 1) * 4, y * 4); | ||
1099 | } | ||
1100 | if (y > 0) | ||
1101 | { | ||
1102 | southParcel = GetLandObject(x * 4, (y - 1) * 4); | ||
1103 | } | ||
1104 | 1212 | ||
1105 | if (x == 0) | 1213 | ILandObject westParcel = null; |
1106 | { | 1214 | ILandObject southParcel = null; |
1107 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST); | 1215 | if (x > 0) |
1108 | } | 1216 | { |
1109 | else if (westParcel != null && westParcel != currentParcelBlock) | 1217 | westParcel = GetLandObject((x - 1) * landUnit, y * landUnit); |
1110 | { | 1218 | } |
1111 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST); | 1219 | if (y > 0) |
1112 | } | 1220 | { |
1221 | southParcel = GetLandObject(x * landUnit, (y - 1) * landUnit); | ||
1222 | } | ||
1113 | 1223 | ||
1114 | if (y == 0) | 1224 | if (x == 0) |
1115 | { | 1225 | { |
1116 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH); | 1226 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST); |
1117 | } | 1227 | } |
1118 | else if (southParcel != null && southParcel != currentParcelBlock) | 1228 | else if (westParcel != null && westParcel != currentParcelBlock) |
1119 | { | 1229 | { |
1120 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH); | 1230 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST); |
1121 | } | 1231 | } |
1122 | 1232 | ||
1123 | byteArray[byteArrayCount] = tempByte; | 1233 | if (y == 0) |
1124 | byteArrayCount++; | 1234 | { |
1125 | if (byteArrayCount >= LAND_BLOCKS_PER_PACKET) | 1235 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH); |
1126 | { | 1236 | } |
1127 | remote_client.SendLandParcelOverlay(byteArray, sequenceID); | 1237 | else if (southParcel != null && southParcel != currentParcelBlock) |
1128 | byteArrayCount = 0; | 1238 | { |
1129 | sequenceID++; | 1239 | tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH); |
1130 | byteArray = new byte[LAND_BLOCKS_PER_PACKET]; | ||
1131 | } | ||
1132 | } | ||
1133 | } | 1240 | } |
1241 | |||
1134 | } | 1242 | } |
1243 | |||
1244 | return tempByte; | ||
1135 | } | 1245 | } |
1136 | 1246 | ||
1137 | public void ClientOnParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id, | 1247 | public void ClientOnParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id, |
@@ -1679,7 +1789,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1679 | { | 1789 | { |
1680 | // most likely still cached from building the extLandData entry | 1790 | // most likely still cached from building the extLandData entry |
1681 | uint x = 0, y = 0; | 1791 | uint x = 0, y = 0; |
1682 | Utils.LongToUInts(data.RegionHandle, out x, out y); | 1792 | Util.RegionHandleToWorldLoc(data.RegionHandle, out x, out y); |
1683 | info = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); | 1793 | info = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); |
1684 | } | 1794 | } |
1685 | // we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark. | 1795 | // we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark. |
@@ -2007,4 +2117,4 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
2007 | cdl.AddToStringBuilder(report); | 2117 | cdl.AddToStringBuilder(report); |
2008 | } | 2118 | } |
2009 | } | 2119 | } |
2010 | } \ No newline at end of file | 2120 | } |
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index e54c849..f8f4986 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs | |||
@@ -45,10 +45,10 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
45 | #region Member Variables | 45 | #region Member Variables |
46 | 46 | ||
47 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 47 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
48 | #pragma warning disable 0429 | 48 | private static readonly string LogHeader = "[LAND OBJECT]"; |
49 | private const int landArrayMax = ((int)((int)Constants.RegionSize / 4) >= 64) ? (int)((int)Constants.RegionSize / 4) : 64; | 49 | |
50 | #pragma warning restore 0429 | 50 | private bool[,] m_landBitmap; |
51 | private bool[,] m_landBitmap = new bool[landArrayMax,landArrayMax]; | 51 | private readonly int landUnit = 4; |
52 | 52 | ||
53 | private int m_lastSeqId = 0; | 53 | private int m_lastSeqId = 0; |
54 | 54 | ||
@@ -93,15 +93,17 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
93 | { | 93 | { |
94 | get | 94 | get |
95 | { | 95 | { |
96 | for (int y = 0; y < landArrayMax; y++) | 96 | for (int y = 0; y < LandBitmap.GetLength(1); y++) |
97 | { | 97 | { |
98 | for (int x = 0; x < landArrayMax; x++) | 98 | for (int x = 0; x < LandBitmap.GetLength(0); x++) |
99 | { | 99 | { |
100 | if (LandBitmap[x, y]) | 100 | if (LandBitmap[x, y]) |
101 | return new Vector3(x * 4, y * 4, 0); | 101 | return new Vector3(x * landUnit, y * landUnit, 0); |
102 | } | 102 | } |
103 | } | 103 | } |
104 | 104 | ||
105 | m_log.ErrorFormat("{0} StartPoint. No start point found. bitmapSize=<{1},{2}>", | ||
106 | LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1)); | ||
105 | return new Vector3(-1, -1, -1); | 107 | return new Vector3(-1, -1, -1); |
106 | } | 108 | } |
107 | } | 109 | } |
@@ -110,17 +112,19 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
110 | { | 112 | { |
111 | get | 113 | get |
112 | { | 114 | { |
113 | for (int y = landArrayMax - 1; y >= 0; y--) | 115 | for (int y = LandBitmap.GetLength(1) - 1; y >= 0; y--) |
114 | { | 116 | { |
115 | for (int x = landArrayMax - 1; x >= 0; x--) | 117 | for (int x = LandBitmap.GetLength(0) - 1; x >= 0; x--) |
116 | { | 118 | { |
117 | if (LandBitmap[x, y]) | 119 | if (LandBitmap[x, y]) |
118 | { | 120 | { |
119 | return new Vector3(x * 4 + 4, y * 4 + 4, 0); | 121 | return new Vector3(x * landUnit + landUnit, y * landUnit + landUnit, 0); |
120 | } | 122 | } |
121 | } | 123 | } |
122 | } | 124 | } |
123 | 125 | ||
126 | m_log.ErrorFormat("{0} EndPoint. No end point found. bitmapSize=<{1},{2}>", | ||
127 | LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1)); | ||
124 | return new Vector3(-1, -1, -1); | 128 | return new Vector3(-1, -1, -1); |
125 | } | 129 | } |
126 | } | 130 | } |
@@ -130,6 +134,8 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
130 | public LandObject(UUID owner_id, bool is_group_owned, Scene scene) | 134 | public LandObject(UUID owner_id, bool is_group_owned, Scene scene) |
131 | { | 135 | { |
132 | m_scene = scene; | 136 | m_scene = scene; |
137 | m_landBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; | ||
138 | |||
133 | LandData.OwnerID = owner_id; | 139 | LandData.OwnerID = owner_id; |
134 | if (is_group_owned) | 140 | if (is_group_owned) |
135 | LandData.GroupID = owner_id; | 141 | LandData.GroupID = owner_id; |
@@ -152,9 +158,9 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
152 | /// <returns>Returns true if the piece of land contains the specified point</returns> | 158 | /// <returns>Returns true if the piece of land contains the specified point</returns> |
153 | public bool ContainsPoint(int x, int y) | 159 | public bool ContainsPoint(int x, int y) |
154 | { | 160 | { |
155 | if (x >= 0 && y >= 0 && x < Constants.RegionSize && y < Constants.RegionSize) | 161 | if (x >= 0 && y >= 0 && x < m_scene.RegionInfo.RegionSizeX && y < m_scene.RegionInfo.RegionSizeY) |
156 | { | 162 | { |
157 | return (LandBitmap[x / 4, y / 4] == true); | 163 | return (LandBitmap[x / landUnit, y / landUnit] == true); |
158 | } | 164 | } |
159 | else | 165 | else |
160 | { | 166 | { |
@@ -194,7 +200,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
194 | else | 200 | else |
195 | { | 201 | { |
196 | // Normal Calculations | 202 | // Normal Calculations |
197 | int parcelMax = (int)(((float)LandData.Area / 65536.0f) | 203 | int parcelMax = (int)(((float)LandData.Area / (m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY)) |
198 | * (float)m_scene.RegionInfo.ObjectCapacity | 204 | * (float)m_scene.RegionInfo.ObjectCapacity |
199 | * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); | 205 | * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); |
200 | // TODO: The calculation of ObjectBonus should be refactored. It does still not work in the same manner as SL! | 206 | // TODO: The calculation of ObjectBonus should be refactored. It does still not work in the same manner as SL! |
@@ -211,7 +217,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
211 | else | 217 | else |
212 | { | 218 | { |
213 | //Normal Calculations | 219 | //Normal Calculations |
214 | int simMax = (int)(((float)LandData.SimwideArea / 65536.0f) | 220 | int simMax = (int)(((float)LandData.SimwideArea / (m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY)) |
215 | * (float)m_scene.RegionInfo.ObjectCapacity); | 221 | * (float)m_scene.RegionInfo.ObjectCapacity); |
216 | return simMax; | 222 | return simMax; |
217 | } | 223 | } |
@@ -224,7 +230,12 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
224 | public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client) | 230 | public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client) |
225 | { | 231 | { |
226 | IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>(); | 232 | IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>(); |
227 | uint regionFlags = 336723974 & ~((uint)(RegionFlags.AllowLandmark | RegionFlags.AllowSetHome)); | 233 | // uint regionFlags = 336723974 & ~((uint)(RegionFlags.AllowLandmark | RegionFlags.AllowSetHome)); |
234 | uint regionFlags = (uint)(RegionFlags.PublicAllowed | ||
235 | | RegionFlags.AllowDirectTeleport | ||
236 | | RegionFlags.AllowParcelChanges | ||
237 | | RegionFlags.AllowVoice ); | ||
238 | |||
228 | if (estateModule != null) | 239 | if (estateModule != null) |
229 | regionFlags = estateModule.GetRegionFlags(); | 240 | regionFlags = estateModule.GetRegionFlags(); |
230 | 241 | ||
@@ -559,8 +570,8 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
559 | try | 570 | try |
560 | { | 571 | { |
561 | over = | 572 | over = |
562 | m_scene.LandChannel.GetLandObject(Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.X), 0, ((int)Constants.RegionSize - 1)), | 573 | m_scene.LandChannel.GetLandObject(Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.X), 0, ((int)m_scene.RegionInfo.RegionSizeX - 1)), |
563 | Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.Y), 0, ((int)Constants.RegionSize - 1))); | 574 | Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.Y), 0, ((int)m_scene.RegionInfo.RegionSizeY - 1))); |
564 | } | 575 | } |
565 | catch (Exception) | 576 | catch (Exception) |
566 | { | 577 | { |
@@ -707,15 +718,15 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
707 | /// </summary> | 718 | /// </summary> |
708 | private void UpdateAABBAndAreaValues() | 719 | private void UpdateAABBAndAreaValues() |
709 | { | 720 | { |
710 | int min_x = 64; | 721 | int min_x = 10000; |
711 | int min_y = 64; | 722 | int min_y = 10000; |
712 | int max_x = 0; | 723 | int max_x = 0; |
713 | int max_y = 0; | 724 | int max_y = 0; |
714 | int tempArea = 0; | 725 | int tempArea = 0; |
715 | int x, y; | 726 | int x, y; |
716 | for (x = 0; x < 64; x++) | 727 | for (x = 0; x < LandBitmap.GetLength(0); x++) |
717 | { | 728 | { |
718 | for (y = 0; y < 64; y++) | 729 | for (y = 0; y < LandBitmap.GetLength(1); y++) |
719 | { | 730 | { |
720 | if (LandBitmap[x, y] == true) | 731 | if (LandBitmap[x, y] == true) |
721 | { | 732 | { |
@@ -723,31 +734,31 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
723 | if (min_y > y) min_y = y; | 734 | if (min_y > y) min_y = y; |
724 | if (max_x < x) max_x = x; | 735 | if (max_x < x) max_x = x; |
725 | if (max_y < y) max_y = y; | 736 | if (max_y < y) max_y = y; |
726 | tempArea += 16; //16sqm peice of land | 737 | tempArea += landUnit * landUnit; //16sqm peice of land |
727 | } | 738 | } |
728 | } | 739 | } |
729 | } | 740 | } |
730 | int tx = min_x * 4; | 741 | int tx = min_x * landUnit; |
731 | if (tx > ((int)Constants.RegionSize - 1)) | 742 | if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1)) |
732 | tx = ((int)Constants.RegionSize - 1); | 743 | tx = ((int)m_scene.RegionInfo.RegionSizeX - 1); |
733 | int ty = min_y * 4; | 744 | int ty = min_y * landUnit; |
734 | if (ty > ((int)Constants.RegionSize - 1)) | 745 | if (ty > ((int)m_scene.RegionInfo.RegionSizeY - 1)) |
735 | ty = ((int)Constants.RegionSize - 1); | 746 | ty = ((int)m_scene.RegionInfo.RegionSizeY - 1); |
736 | 747 | ||
737 | LandData.AABBMin = | 748 | LandData.AABBMin = |
738 | new Vector3( | 749 | new Vector3( |
739 | (float)(min_x * 4), (float)(min_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0); | 750 | (float)(min_x * landUnit), (float)(min_y * landUnit), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0); |
740 | 751 | ||
741 | tx = max_x * 4; | 752 | tx = max_x * landUnit; |
742 | if (tx > ((int)Constants.RegionSize - 1)) | 753 | if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1)) |
743 | tx = ((int)Constants.RegionSize - 1); | 754 | tx = ((int)m_scene.RegionInfo.RegionSizeX - 1); |
744 | ty = max_y * 4; | 755 | ty = max_y * landUnit; |
745 | if (ty > ((int)Constants.RegionSize - 1)) | 756 | if (ty > ((int)m_scene.RegionInfo.RegionSizeY - 1)) |
746 | ty = ((int)Constants.RegionSize - 1); | 757 | ty = ((int)m_scene.RegionInfo.RegionSizeY - 1); |
747 | 758 | ||
748 | LandData.AABBMax | 759 | LandData.AABBMax |
749 | = new Vector3( | 760 | = new Vector3( |
750 | (float)(max_x * 4), (float)(max_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0); | 761 | (float)(max_x * landUnit), (float)(max_y * landUnit), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0); |
751 | 762 | ||
752 | LandData.Area = tempArea; | 763 | LandData.Area = tempArea; |
753 | } | 764 | } |
@@ -759,20 +770,12 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
759 | /// <summary> | 770 | /// <summary> |
760 | /// Sets the land's bitmap manually | 771 | /// Sets the land's bitmap manually |
761 | /// </summary> | 772 | /// </summary> |
762 | /// <param name="bitmap">64x64 block representing where this land is on a map</param> | 773 | /// <param name="bitmap">block representing where this land is on a map mapped in a 4x4 meter grid</param> |
763 | public void SetLandBitmap(bool[,] bitmap) | 774 | public void SetLandBitmap(bool[,] bitmap) |
764 | { | 775 | { |
765 | if (bitmap.GetLength(0) != 64 || bitmap.GetLength(1) != 64 || bitmap.Rank != 2) | 776 | LandBitmap = bitmap; |
766 | { | 777 | // m_log.DebugFormat("{0} SetLandBitmap. BitmapSize=<{1},{2}>", LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1)); |
767 | //Throw an exception - The bitmap is not 64x64 | 778 | ForceUpdateLandInfo(); |
768 | //throw new Exception("Error: Invalid Parcel Bitmap"); | ||
769 | } | ||
770 | else | ||
771 | { | ||
772 | //Valid: Lets set it | ||
773 | LandBitmap = bitmap; | ||
774 | ForceUpdateLandInfo(); | ||
775 | } | ||
776 | } | 779 | } |
777 | 780 | ||
778 | /// <summary> | 781 | /// <summary> |
@@ -786,15 +789,19 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
786 | 789 | ||
787 | public bool[,] BasicFullRegionLandBitmap() | 790 | public bool[,] BasicFullRegionLandBitmap() |
788 | { | 791 | { |
789 | return GetSquareLandBitmap(0, 0, (int) Constants.RegionSize, (int) Constants.RegionSize); | 792 | return GetSquareLandBitmap(0, 0, (int)m_scene.RegionInfo.RegionSizeX, (int) m_scene.RegionInfo.RegionSizeY); |
790 | } | 793 | } |
791 | 794 | ||
792 | public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y) | 795 | public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y) |
793 | { | 796 | { |
794 | bool[,] tempBitmap = new bool[64,64]; | 797 | // Empty bitmap for the whole region |
798 | bool[,] tempBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; | ||
795 | tempBitmap.Initialize(); | 799 | tempBitmap.Initialize(); |
796 | 800 | ||
801 | // Fill the bitmap square area specified by state and end | ||
797 | tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true); | 802 | tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true); |
803 | // m_log.DebugFormat("{0} GetSquareLandBitmap. tempBitmapSize=<{1},{2}>", | ||
804 | // LogHeader, tempBitmap.GetLength(0), tempBitmap.GetLength(1)); | ||
798 | return tempBitmap; | 805 | return tempBitmap; |
799 | } | 806 | } |
800 | 807 | ||
@@ -811,24 +818,20 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
811 | public bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y, | 818 | public bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y, |
812 | bool set_value) | 819 | bool set_value) |
813 | { | 820 | { |
814 | if (land_bitmap.GetLength(0) != 64 || land_bitmap.GetLength(1) != 64 || land_bitmap.Rank != 2) | ||
815 | { | ||
816 | //Throw an exception - The bitmap is not 64x64 | ||
817 | //throw new Exception("Error: Invalid Parcel Bitmap in modifyLandBitmapSquare()"); | ||
818 | } | ||
819 | |||
820 | int x, y; | 821 | int x, y; |
821 | for (y = 0; y < 64; y++) | 822 | for (y = 0; y < land_bitmap.GetLength(1); y++) |
822 | { | 823 | { |
823 | for (x = 0; x < 64; x++) | 824 | for (x = 0; x < land_bitmap.GetLength(0); x++) |
824 | { | 825 | { |
825 | if (x >= start_x / 4 && x < end_x / 4 | 826 | if (x >= start_x / landUnit && x < end_x / landUnit |
826 | && y >= start_y / 4 && y < end_y / 4) | 827 | && y >= start_y / landUnit && y < end_y / landUnit) |
827 | { | 828 | { |
828 | land_bitmap[x, y] = set_value; | 829 | land_bitmap[x, y] = set_value; |
829 | } | 830 | } |
830 | } | 831 | } |
831 | } | 832 | } |
833 | // m_log.DebugFormat("{0} ModifyLandBitmapSquare. startXY=<{1},{2}>, endXY=<{3},{4}>, val={5}, landBitmapSize=<{6},{7}>", | ||
834 | // LogHeader, start_x, start_y, end_x, end_y, set_value, land_bitmap.GetLength(0), land_bitmap.GetLength(1)); | ||
832 | return land_bitmap; | 835 | return land_bitmap; |
833 | } | 836 | } |
834 | 837 | ||
@@ -840,21 +843,21 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
840 | /// <returns></returns> | 843 | /// <returns></returns> |
841 | public bool[,] MergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add) | 844 | public bool[,] MergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add) |
842 | { | 845 | { |
843 | if (bitmap_base.GetLength(0) != 64 || bitmap_base.GetLength(1) != 64 || bitmap_base.Rank != 2) | 846 | if (bitmap_base.GetLength(0) != bitmap_add.GetLength(0) |
847 | || bitmap_base.GetLength(1) != bitmap_add.GetLength(1) | ||
848 | || bitmap_add.Rank != 2 | ||
849 | || bitmap_base.Rank != 2) | ||
844 | { | 850 | { |
845 | //Throw an exception - The bitmap is not 64x64 | 851 | throw new Exception( |
846 | throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_base in mergeLandBitmaps"); | 852 | String.Format("{0} MergeLandBitmaps. merging maps not same size. baseSizeXY=<{1},{2}>, addSizeXY=<{3},{4}>", |
847 | } | 853 | LogHeader, bitmap_base.GetLength(0), bitmap_base.GetLength(1), bitmap_add.GetLength(0), bitmap_add.GetLength(1)) |
848 | if (bitmap_add.GetLength(0) != 64 || bitmap_add.GetLength(1) != 64 || bitmap_add.Rank != 2) | 854 | ); |
849 | { | ||
850 | //Throw an exception - The bitmap is not 64x64 | ||
851 | throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_add in mergeLandBitmaps"); | ||
852 | } | 855 | } |
853 | 856 | ||
854 | int x, y; | 857 | int x, y; |
855 | for (y = 0; y < 64; y++) | 858 | for (y = 0; y < bitmap_base.GetLength(1); y++) |
856 | { | 859 | { |
857 | for (x = 0; x < 64; x++) | 860 | for (x = 0; x < bitmap_add.GetLength(0); x++) |
858 | { | 861 | { |
859 | if (bitmap_add[x, y]) | 862 | if (bitmap_add[x, y]) |
860 | { | 863 | { |
@@ -871,13 +874,13 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
871 | /// <returns></returns> | 874 | /// <returns></returns> |
872 | private byte[] ConvertLandBitmapToBytes() | 875 | private byte[] ConvertLandBitmapToBytes() |
873 | { | 876 | { |
874 | byte[] tempConvertArr = new byte[512]; | 877 | byte[] tempConvertArr = new byte[LandBitmap.GetLength(0) * LandBitmap.GetLength(1) / 8]; |
875 | byte tempByte = 0; | 878 | byte tempByte = 0; |
876 | int x, y, i, byteNum = 0; | 879 | int byteNum = 0; |
877 | i = 0; | 880 | int i = 0; |
878 | for (y = 0; y < 64; y++) | 881 | for (int y = 0; y < LandBitmap.GetLength(1); y++) |
879 | { | 882 | { |
880 | for (x = 0; x < 64; x++) | 883 | for (int x = 0; x < LandBitmap.GetLength(0); x++) |
881 | { | 884 | { |
882 | tempByte = Convert.ToByte(tempByte | Convert.ToByte(LandBitmap[x, y]) << (i++ % 8)); | 885 | tempByte = Convert.ToByte(tempByte | Convert.ToByte(LandBitmap[x, y]) << (i++ % 8)); |
883 | if (i % 8 == 0) | 886 | if (i % 8 == 0) |
@@ -889,30 +892,52 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
889 | } | 892 | } |
890 | } | 893 | } |
891 | } | 894 | } |
895 | // m_log.DebugFormat("{0} ConvertLandBitmapToBytes. BitmapSize=<{1},{2}>", | ||
896 | // LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1)); | ||
892 | return tempConvertArr; | 897 | return tempConvertArr; |
893 | } | 898 | } |
894 | 899 | ||
895 | private bool[,] ConvertBytesToLandBitmap() | 900 | private bool[,] ConvertBytesToLandBitmap() |
896 | { | 901 | { |
897 | bool[,] tempConvertMap = new bool[landArrayMax, landArrayMax]; | 902 | bool[,] tempConvertMap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; |
898 | tempConvertMap.Initialize(); | 903 | tempConvertMap.Initialize(); |
899 | byte tempByte = 0; | 904 | byte tempByte = 0; |
900 | int x = 0, y = 0, i = 0, bitNum = 0; | 905 | // Math.Min overcomes an old bug that might have made it into the database. Only use the bytes that fit into convertMap. |
901 | for (i = 0; i < 512; i++) | 906 | int bitmapLen = Math.Min(LandData.Bitmap.Length, tempConvertMap.GetLength(0) * tempConvertMap.GetLength(1) / 8); |
907 | int xLen = (int)(m_scene.RegionInfo.RegionSizeX / landUnit); | ||
908 | |||
909 | if (bitmapLen == 512) | ||
910 | { | ||
911 | // Legacy bitmap being passed in. Use the legacy region size | ||
912 | // and only set the lower area of the larger region. | ||
913 | xLen = (int)(Constants.RegionSize / landUnit); | ||
914 | } | ||
915 | // m_log.DebugFormat("{0} ConvertBytesToLandBitmap: bitmapLen={1}, xLen={2}", LogHeader, bitmapLen, xLen); | ||
916 | |||
917 | int x = 0, y = 0; | ||
918 | for (int i = 0; i < bitmapLen; i++) | ||
902 | { | 919 | { |
903 | tempByte = LandData.Bitmap[i]; | 920 | tempByte = LandData.Bitmap[i]; |
904 | for (bitNum = 0; bitNum < 8; bitNum++) | 921 | for (int bitNum = 0; bitNum < 8; bitNum++) |
905 | { | 922 | { |
906 | bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1); | 923 | bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1); |
907 | tempConvertMap[x, y] = bit; | 924 | try |
925 | { | ||
926 | tempConvertMap[x, y] = bit; | ||
927 | } | ||
928 | catch (Exception e) | ||
929 | { | ||
930 | m_log.DebugFormat("{0} ConvertBytestoLandBitmap: i={1}, x={2}, y={3}", LogHeader, i, x, y); | ||
931 | } | ||
908 | x++; | 932 | x++; |
909 | if (x > 63) | 933 | if (x >= xLen) |
910 | { | 934 | { |
911 | x = 0; | 935 | x = 0; |
912 | y++; | 936 | y++; |
913 | } | 937 | } |
914 | } | 938 | } |
915 | } | 939 | } |
940 | |||
916 | return tempConvertMap; | 941 | return tempConvertMap; |
917 | } | 942 | } |
918 | 943 | ||
diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs index 40638f8..1007e0b 100644 --- a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs +++ b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs | |||
@@ -102,7 +102,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
102 | 102 | ||
103 | terrainRenderer.Initialise(m_scene, m_config); | 103 | terrainRenderer.Initialise(m_scene, m_config); |
104 | 104 | ||
105 | mapbmp = new Bitmap((int)Constants.RegionSize, (int)Constants.RegionSize, System.Drawing.Imaging.PixelFormat.Format24bppRgb); | 105 | mapbmp = new Bitmap((int)m_scene.Heightmap.Width, (int)m_scene.Heightmap.Height, |
106 | System.Drawing.Imaging.PixelFormat.Format24bppRgb); | ||
106 | //long t = System.Environment.TickCount; | 107 | //long t = System.Environment.TickCount; |
107 | //for (int i = 0; i < 10; ++i) { | 108 | //for (int i = 0; i < 10; ++i) { |
108 | terrainRenderer.TerrainToBitmap(mapbmp); | 109 | terrainRenderer.TerrainToBitmap(mapbmp); |
@@ -273,7 +274,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
273 | private Bitmap DrawObjectVolume(Scene whichScene, Bitmap mapbmp) | 274 | private Bitmap DrawObjectVolume(Scene whichScene, Bitmap mapbmp) |
274 | { | 275 | { |
275 | int tc = 0; | 276 | int tc = 0; |
276 | double[,] hm = whichScene.Heightmap.GetDoubles(); | 277 | ITerrainChannel hm = whichScene.Heightmap; |
277 | tc = Environment.TickCount; | 278 | tc = Environment.TickCount; |
278 | m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile"); | 279 | m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile"); |
279 | EntityBase[] objs = whichScene.GetEntities(); | 280 | EntityBase[] objs = whichScene.GetEntities(); |
@@ -356,7 +357,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
356 | Vector3 pos = part.GetWorldPosition(); | 357 | Vector3 pos = part.GetWorldPosition(); |
357 | 358 | ||
358 | // skip prim outside of retion | 359 | // skip prim outside of retion |
359 | if (pos.X < 0f || pos.X > 256f || pos.Y < 0f || pos.Y > 256f) | 360 | if (!m_scene.PositionIsInCurrentRegion(pos)) |
360 | continue; | 361 | continue; |
361 | 362 | ||
362 | // skip prim in non-finite position | 363 | // skip prim in non-finite position |
@@ -399,9 +400,14 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
399 | int mapdrawendY = (int)(pos.Y + scale.Y); | 400 | int mapdrawendY = (int)(pos.Y + scale.Y); |
400 | 401 | ||
401 | // If object is beyond the edge of the map, don't draw it to avoid errors | 402 | // If object is beyond the edge of the map, don't draw it to avoid errors |
402 | if (mapdrawstartX < 0 || mapdrawstartX > ((int)Constants.RegionSize - 1) || mapdrawendX < 0 || mapdrawendX > ((int)Constants.RegionSize - 1) | 403 | if (mapdrawstartX < 0 |
403 | || mapdrawstartY < 0 || mapdrawstartY > ((int)Constants.RegionSize - 1) || mapdrawendY < 0 | 404 | || mapdrawstartX > (hm.Width - 1) |
404 | || mapdrawendY > ((int)Constants.RegionSize - 1)) | 405 | || mapdrawendX < 0 |
406 | || mapdrawendX > (hm.Width - 1) | ||
407 | || mapdrawstartY < 0 | ||
408 | || mapdrawstartY > (hm.Height - 1) | ||
409 | || mapdrawendY < 0 | ||
410 | || mapdrawendY > (hm.Height - 1)) | ||
405 | continue; | 411 | continue; |
406 | 412 | ||
407 | #region obb face reconstruction part duex | 413 | #region obb face reconstruction part duex |
@@ -523,11 +529,11 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
523 | for (int i = 0; i < FaceA.Length; i++) | 529 | for (int i = 0; i < FaceA.Length; i++) |
524 | { | 530 | { |
525 | Point[] working = new Point[5]; | 531 | Point[] working = new Point[5]; |
526 | working[0] = project(FaceA[i], axPos); | 532 | working[0] = project(hm, FaceA[i], axPos); |
527 | working[1] = project(FaceB[i], axPos); | 533 | working[1] = project(hm, FaceB[i], axPos); |
528 | working[2] = project(FaceD[i], axPos); | 534 | working[2] = project(hm, FaceD[i], axPos); |
529 | working[3] = project(FaceC[i], axPos); | 535 | working[3] = project(hm, FaceC[i], axPos); |
530 | working[4] = project(FaceA[i], axPos); | 536 | working[4] = project(hm, FaceA[i], axPos); |
531 | 537 | ||
532 | face workingface = new face(); | 538 | face workingface = new face(); |
533 | workingface.pts = working; | 539 | workingface.pts = working; |
@@ -595,17 +601,17 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
595 | return mapbmp; | 601 | return mapbmp; |
596 | } | 602 | } |
597 | 603 | ||
598 | private Point project(Vector3 point3d, Vector3 originpos) | 604 | private Point project(ITerrainChannel hm, Vector3 point3d, Vector3 originpos) |
599 | { | 605 | { |
600 | Point returnpt = new Point(); | 606 | Point returnpt = new Point(); |
601 | //originpos = point3d; | 607 | //originpos = point3d; |
602 | //int d = (int)(256f / 1.5f); | 608 | //int d = (int)(256f / 1.5f); |
603 | 609 | ||
604 | //Vector3 topos = new Vector3(0, 0, 0); | 610 | //Vector3 topos = new Vector3(0, 0, 0); |
605 | // float z = -point3d.z - topos.z; | 611 | // float z = -point3d.z - topos.z; |
606 | 612 | ||
607 | returnpt.X = (int)point3d.X;//(int)((topos.x - point3d.x) / z * d); | 613 | returnpt.X = (int)point3d.X;//(int)((topos.x - point3d.x) / z * d); |
608 | returnpt.Y = (int)(((int)Constants.RegionSize - 1) - point3d.Y);//(int)(255 - (((topos.y - point3d.y) / z * d))); | 614 | returnpt.Y = (int)((hm.Width - 1) - point3d.Y);//(int)(255 - (((topos.y - point3d.y) / z * d))); |
609 | 615 | ||
610 | return returnpt; | 616 | return returnpt; |
611 | } | 617 | } |
diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs b/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs index 992bff3..9b939c9 100644 --- a/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs +++ b/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs | |||
@@ -31,6 +31,7 @@ using System.Reflection; | |||
31 | using log4net; | 31 | using log4net; |
32 | using Nini.Config; | 32 | using Nini.Config; |
33 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
34 | using OpenSim.Region.Framework.Interfaces; | ||
34 | using OpenSim.Region.Framework.Scenes; | 35 | using OpenSim.Region.Framework.Scenes; |
35 | 36 | ||
36 | namespace OpenSim.Region.CoreModules.World.LegacyMap | 37 | namespace OpenSim.Region.CoreModules.World.LegacyMap |
@@ -39,8 +40,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
39 | { | 40 | { |
40 | private static readonly Color WATER_COLOR = Color.FromArgb(29, 71, 95); | 41 | private static readonly Color WATER_COLOR = Color.FromArgb(29, 71, 95); |
41 | 42 | ||
42 | private static readonly ILog m_log = | 43 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
43 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 44 | private static readonly string LogHeader = "[SHADED MAPTILE RENDERER]"; |
44 | 45 | ||
45 | private Scene m_scene; | 46 | private Scene m_scene; |
46 | //private IConfigSource m_config; // not used currently | 47 | //private IConfigSource m_config; // not used currently |
@@ -53,19 +54,26 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
53 | 54 | ||
54 | public void TerrainToBitmap(Bitmap mapbmp) | 55 | public void TerrainToBitmap(Bitmap mapbmp) |
55 | { | 56 | { |
57 | m_log.DebugFormat("{0} Generating Maptile Step 1: Terrain", LogHeader); | ||
56 | int tc = Environment.TickCount; | 58 | int tc = Environment.TickCount; |
57 | m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Terrain"); | ||
58 | 59 | ||
59 | double[,] hm = m_scene.Heightmap.GetDoubles(); | 60 | ITerrainChannel hm = m_scene.Heightmap; |
61 | |||
62 | if (mapbmp.Width != hm.Width || mapbmp.Height != hm.Height) | ||
63 | { | ||
64 | m_log.ErrorFormat("{0} TerrainToBitmap. Passed bitmap wrong dimensions. passed=<{1},{2}>, size=<{3},{4}>", | ||
65 | LogHeader, mapbmp.Width, mapbmp.Height, hm.Width, hm.Height); | ||
66 | } | ||
67 | |||
60 | bool ShadowDebugContinue = true; | 68 | bool ShadowDebugContinue = true; |
61 | 69 | ||
62 | bool terraincorruptedwarningsaid = false; | 70 | bool terraincorruptedwarningsaid = false; |
63 | 71 | ||
64 | float low = 255; | 72 | float low = 255; |
65 | float high = 0; | 73 | float high = 0; |
66 | for (int x = 0; x < (int)Constants.RegionSize; x++) | 74 | for (int x = 0; x < hm.Width; x++) |
67 | { | 75 | { |
68 | for (int y = 0; y < (int)Constants.RegionSize; y++) | 76 | for (int y = 0; y < hm.Height; y++) |
69 | { | 77 | { |
70 | float hmval = (float)hm[x, y]; | 78 | float hmval = (float)hm[x, y]; |
71 | if (hmval < low) | 79 | if (hmval < low) |
@@ -77,12 +85,12 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
77 | 85 | ||
78 | float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight; | 86 | float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight; |
79 | 87 | ||
80 | for (int x = 0; x < (int)Constants.RegionSize; x++) | 88 | for (int x = 0; x < hm.Width; x++) |
81 | { | 89 | { |
82 | for (int y = 0; y < (int)Constants.RegionSize; y++) | 90 | for (int y = 0; y < hm.Height; y++) |
83 | { | 91 | { |
84 | // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left | 92 | // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left |
85 | int yr = ((int)Constants.RegionSize - 1) - y; | 93 | int yr = ((int)hm.Height - 1) - y; |
86 | 94 | ||
87 | float heightvalue = (float)hm[x, y]; | 95 | float heightvalue = (float)hm[x, y]; |
88 | 96 | ||
@@ -109,12 +117,12 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
109 | // . | 117 | // . |
110 | // | 118 | // |
111 | // Shade the terrain for shadows | 119 | // Shade the terrain for shadows |
112 | if (x < ((int)Constants.RegionSize - 1) && yr < ((int)Constants.RegionSize - 1)) | 120 | if (x < (hm.Width - 1) && yr < (hm.Height - 1)) |
113 | { | 121 | { |
114 | float hfvalue = (float)hm[x, y]; | 122 | float hfvalue = (float)hm[x, y]; |
115 | float hfvaluecompare = 0f; | 123 | float hfvaluecompare = 0f; |
116 | 124 | ||
117 | if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize)) | 125 | if ((x + 1 < hm.Width) && (y + 1 < hm.Height)) |
118 | { | 126 | { |
119 | hfvaluecompare = (float)hm[x + 1, y + 1]; // light from north-east => look at land height there | 127 | hfvaluecompare = (float)hm[x + 1, y + 1]; // light from north-east => look at land height there |
120 | } | 128 | } |
@@ -179,7 +187,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
179 | 187 | ||
180 | if (ShadowDebugContinue) | 188 | if (ShadowDebugContinue) |
181 | { | 189 | { |
182 | if ((x - 1 > 0) && (yr + 1 < (int)Constants.RegionSize)) | 190 | if ((x - 1 > 0) && (yr + 1 < hm.Height)) |
183 | { | 191 | { |
184 | color = mapbmp.GetPixel(x - 1, yr + 1); | 192 | color = mapbmp.GetPixel(x - 1, yr + 1); |
185 | int r = color.R; | 193 | int r = color.R; |
@@ -233,7 +241,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
233 | terraincorruptedwarningsaid = true; | 241 | terraincorruptedwarningsaid = true; |
234 | } | 242 | } |
235 | Color black = Color.Black; | 243 | Color black = Color.Black; |
236 | mapbmp.SetPixel(x, ((int)Constants.RegionSize - y) - 1, black); | 244 | mapbmp.SetPixel(x, (hm.Width - y) - 1, black); |
237 | } | 245 | } |
238 | } | 246 | } |
239 | } | 247 | } |
diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs b/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs index d13c2ef..413ac64 100644 --- a/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs +++ b/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs | |||
@@ -34,6 +34,8 @@ using Nini.Config; | |||
34 | using OpenMetaverse; | 34 | using OpenMetaverse; |
35 | using OpenMetaverse.Imaging; | 35 | using OpenMetaverse.Imaging; |
36 | using OpenSim.Framework; | 36 | using OpenSim.Framework; |
37 | using OpenSim.Region.Framework; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
37 | using OpenSim.Region.Framework.Scenes; | 39 | using OpenSim.Region.Framework.Scenes; |
38 | 40 | ||
39 | namespace OpenSim.Region.CoreModules.World.LegacyMap | 41 | namespace OpenSim.Region.CoreModules.World.LegacyMap |
@@ -122,8 +124,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
122 | { | 124 | { |
123 | #region Constants | 125 | #region Constants |
124 | 126 | ||
125 | private static readonly ILog m_log = | 127 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
126 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 128 | private static readonly string LogHeader = "[TEXTURED MAPTILE RENDERER]"; |
127 | 129 | ||
128 | // some hardcoded terrain UUIDs that work with SL 1.20 (the four default textures and "Blank"). | 130 | // some hardcoded terrain UUIDs that work with SL 1.20 (the four default textures and "Blank"). |
129 | // The color-values were choosen because they "look right" (at least to me) ;-) | 131 | // The color-values were choosen because they "look right" (at least to me) ;-) |
@@ -173,7 +175,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
173 | private Bitmap fetchTexture(UUID id) | 175 | private Bitmap fetchTexture(UUID id) |
174 | { | 176 | { |
175 | AssetBase asset = m_scene.AssetService.Get(id.ToString()); | 177 | AssetBase asset = m_scene.AssetService.Get(id.ToString()); |
176 | m_log.DebugFormat("[TexturedMapTileRenderer]: Fetched texture {0}, found: {1}", id, asset != null); | 178 | m_log.DebugFormat("{0} Fetched texture {1}, found: {2}", LogHeader, id, asset != null); |
177 | if (asset == null) return null; | 179 | if (asset == null) return null; |
178 | 180 | ||
179 | ManagedImage managedImage; | 181 | ManagedImage managedImage; |
@@ -188,18 +190,15 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
188 | } | 190 | } |
189 | catch (DllNotFoundException) | 191 | catch (DllNotFoundException) |
190 | { | 192 | { |
191 | m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg is not installed correctly on this system. Asset Data is empty for {0}", id); | 193 | m_log.ErrorFormat("{0} OpenJpeg is not installed correctly on this system. Asset Data is empty for {1}", LogHeader, id); |
192 | |||
193 | } | 194 | } |
194 | catch (IndexOutOfRangeException) | 195 | catch (IndexOutOfRangeException) |
195 | { | 196 | { |
196 | m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg was unable to encode this. Asset Data is empty for {0}", id); | 197 | m_log.ErrorFormat("{0} OpenJpeg was unable to encode this. Asset Data is empty for {1}", LogHeader, id); |
197 | |||
198 | } | 198 | } |
199 | catch (Exception) | 199 | catch (Exception) |
200 | { | 200 | { |
201 | m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg was unable to encode this. Asset Data is empty for {0}", id); | 201 | m_log.ErrorFormat("{0} OpenJpeg was unable to encode this. Asset Data is empty for {1}", LogHeader, id); |
202 | |||
203 | } | 202 | } |
204 | return null; | 203 | return null; |
205 | 204 | ||
@@ -267,8 +266,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
267 | 266 | ||
268 | // the heigthfield might have some jumps in values. Rendered land is smooth, though, | 267 | // the heigthfield might have some jumps in values. Rendered land is smooth, though, |
269 | // as a slope is rendered at that place. So average 4 neighbour values to emulate that. | 268 | // as a slope is rendered at that place. So average 4 neighbour values to emulate that. |
270 | private float getHeight(double[,] hm, int x, int y) { | 269 | private float getHeight(ITerrainChannel hm, int x, int y) { |
271 | if (x < ((int)Constants.RegionSize - 1) && y < ((int)Constants.RegionSize - 1)) | 270 | if (x < (hm.Width - 1) && y < (hm.Height - 1)) |
272 | return (float)(hm[x, y] * .444 + (hm[x + 1, y] + hm[x, y + 1]) * .222 + hm[x + 1, y +1] * .112); | 271 | return (float)(hm[x, y] * .444 + (hm[x + 1, y] + hm[x, y + 1]) * .222 + hm[x + 1, y +1] * .112); |
273 | else | 272 | else |
274 | return (float)hm[x, y]; | 273 | return (float)hm[x, y]; |
@@ -278,7 +277,15 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
278 | public void TerrainToBitmap(Bitmap mapbmp) | 277 | public void TerrainToBitmap(Bitmap mapbmp) |
279 | { | 278 | { |
280 | int tc = Environment.TickCount; | 279 | int tc = Environment.TickCount; |
281 | m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Terrain"); | 280 | m_log.DebugFormat("{0} Generating Maptile Step 1: Terrain", LogHeader); |
281 | |||
282 | ITerrainChannel hm = m_scene.Heightmap; | ||
283 | |||
284 | if (mapbmp.Width != hm.Width || mapbmp.Height != hm.Height) | ||
285 | { | ||
286 | m_log.ErrorFormat("{0} TerrainToBitmap. Passed bitmap wrong dimensions. passed=<{1},{2}>, size=<{3},{4}>", | ||
287 | LogHeader, mapbmp.Width, mapbmp.Height, hm.Width, hm.Height); | ||
288 | } | ||
282 | 289 | ||
283 | // These textures should be in the AssetCache anyway, as every client conneting to this | 290 | // These textures should be in the AssetCache anyway, as every client conneting to this |
284 | // region needs them. Except on start, when the map is recreated (before anyone connected), | 291 | // region needs them. Except on start, when the map is recreated (before anyone connected), |
@@ -306,19 +313,17 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
306 | 313 | ||
307 | float waterHeight = (float)settings.WaterHeight; | 314 | float waterHeight = (float)settings.WaterHeight; |
308 | 315 | ||
309 | double[,] hm = m_scene.Heightmap.GetDoubles(); | 316 | for (int x = 0; x < hm.Width; x++) |
310 | |||
311 | for (int x = 0; x < (int)Constants.RegionSize; x++) | ||
312 | { | 317 | { |
313 | float columnRatio = x / ((float)Constants.RegionSize - 1); // 0 - 1, for interpolation | 318 | float columnRatio = x / (hm.Width - 1); // 0 - 1, for interpolation |
314 | for (int y = 0; y < (int)Constants.RegionSize; y++) | 319 | for (int y = 0; y < hm.Height; y++) |
315 | { | 320 | { |
316 | float rowRatio = y / ((float)Constants.RegionSize - 1); // 0 - 1, for interpolation | 321 | float rowRatio = y / (hm.Height - 1); // 0 - 1, for interpolation |
317 | 322 | ||
318 | // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left | 323 | // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left |
319 | int yr = ((int)Constants.RegionSize - 1) - y; | 324 | int yr = (hm.Height - 1) - y; |
320 | 325 | ||
321 | float heightvalue = getHeight(hm, x, y); | 326 | float heightvalue = getHeight(m_scene.Heightmap, x, y); |
322 | if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue)) | 327 | if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue)) |
323 | heightvalue = 0; | 328 | heightvalue = 0; |
324 | 329 | ||
@@ -368,9 +373,9 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap | |||
368 | } | 373 | } |
369 | 374 | ||
370 | // Shade the terrain for shadows | 375 | // Shade the terrain for shadows |
371 | if (x < ((int)Constants.RegionSize - 1) && y < ((int)Constants.RegionSize - 1)) | 376 | if (x < (hm.Width - 1) && y < (hm.Height - 1)) |
372 | { | 377 | { |
373 | float hfvaluecompare = getHeight(hm, x + 1, y + 1); // light from north-east => look at land height there | 378 | float hfvaluecompare = getHeight(m_scene.Heightmap, x + 1, y + 1); // light from north-east => look at land height there |
374 | if (Single.IsInfinity(hfvaluecompare) || Single.IsNaN(hfvaluecompare)) | 379 | if (Single.IsInfinity(hfvaluecompare) || Single.IsNaN(hfvaluecompare)) |
375 | hfvaluecompare = 0f; | 380 | hfvaluecompare = 0f; |
376 | 381 | ||
diff --git a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs index 0cb574a..b8d4855 100644 --- a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs +++ b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs | |||
@@ -151,14 +151,9 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell | |||
151 | break; | 151 | break; |
152 | 152 | ||
153 | case 2: // Sell a copy | 153 | case 2: // Sell a copy |
154 | Vector3 inventoryStoredPosition = new Vector3 | 154 | Vector3 inventoryStoredPosition = new Vector3( |
155 | (((group.AbsolutePosition.X > (int)Constants.RegionSize) | 155 | Math.Min(group.AbsolutePosition.X, m_scene.RegionInfo.RegionSizeX - 6), |
156 | ? 250 | 156 | Math.Min(group.AbsolutePosition.Y, m_scene.RegionInfo.RegionSizeY - 6), |
157 | : group.AbsolutePosition.X) | ||
158 | , | ||
159 | (group.AbsolutePosition.X > (int)Constants.RegionSize) | ||
160 | ? 250 | ||
161 | : group.AbsolutePosition.X, | ||
162 | group.AbsolutePosition.Z); | 157 | group.AbsolutePosition.Z); |
163 | 158 | ||
164 | Vector3 originalPosition = group.AbsolutePosition; | 159 | Vector3 originalPosition = group.AbsolutePosition; |
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs index f8e93e1..45617fc 100644 --- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs +++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs | |||
@@ -1571,10 +1571,10 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
1571 | float X = position.X; | 1571 | float X = position.X; |
1572 | float Y = position.Y; | 1572 | float Y = position.Y; |
1573 | 1573 | ||
1574 | if (X > ((int)Constants.RegionSize - 1)) | 1574 | if (X > ((int)m_scene.RegionInfo.RegionSizeX - 1)) |
1575 | X = ((int)Constants.RegionSize - 1); | 1575 | X = ((int)m_scene.RegionInfo.RegionSizeX - 1); |
1576 | if (Y > ((int)Constants.RegionSize - 1)) | 1576 | if (Y > ((int)m_scene.RegionInfo.RegionSizeY - 1)) |
1577 | Y = ((int)Constants.RegionSize - 1); | 1577 | Y = ((int)m_scene.RegionInfo.RegionSizeY - 1); |
1578 | if (X < 0) | 1578 | if (X < 0) |
1579 | X = 0; | 1579 | X = 0; |
1580 | if (Y < 0) | 1580 | if (Y < 0) |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs b/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs index 7186dd7..89087b1 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs | |||
@@ -42,7 +42,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Effects | |||
42 | for (y = 0; y < map.Height; y++) | 42 | for (y = 0; y < map.Height; y++) |
43 | { | 43 | { |
44 | map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 3, 0.25) * 10; | 44 | map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 3, 0.25) * 10; |
45 | double spherFac = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2, Constants.RegionSize / 2, 50) * 0.01; | 45 | double spherFac = TerrainUtil.SphericalFactor(x, y, map.Width / 2, map.Height / 2, 50) * 0.01; |
46 | if (map[x, y] < spherFac) | 46 | if (map[x, y] < spherFac) |
47 | { | 47 | { |
48 | map[x, y] = spherFac; | 48 | map[x, y] = spherFac; |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs index d78ade5..d5c77ec 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs | |||
@@ -67,7 +67,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders | |||
67 | { | 67 | { |
68 | using (Bitmap bitmap = new Bitmap(filename)) | 68 | using (Bitmap bitmap = new Bitmap(filename)) |
69 | { | 69 | { |
70 | ITerrainChannel retval = new TerrainChannel(true); | 70 | ITerrainChannel retval = new TerrainChannel(w, h); |
71 | 71 | ||
72 | for (int x = 0; x < retval.Width; x++) | 72 | for (int x = 0; x < retval.Width; x++) |
73 | { | 73 | { |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs index 630473e..b6c635c 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs | |||
@@ -45,7 +45,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes | |||
45 | { | 45 | { |
46 | if (fillArea[x, y]) | 46 | if (fillArea[x, y]) |
47 | { | 47 | { |
48 | double noise = TerrainUtil.PerlinNoise2D((double) x / Constants.RegionSize, (double) y / Constants.RegionSize, 8, 1.0); | 48 | double noise = TerrainUtil.PerlinNoise2D((double) x / map.Width, (double) y / map.Height, 8, 1.0); |
49 | 49 | ||
50 | map[x, y] += noise * strength; | 50 | map[x, y] += noise * strength; |
51 | } | 51 | } |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs index 989b7d8..e7df3f8 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs | |||
@@ -53,7 +53,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes | |||
53 | z *= z; | 53 | z *= z; |
54 | z -= ((x - rx) * (x - rx)) + ((y - ry) * (y - ry)); | 54 | z -= ((x - rx) * (x - rx)) + ((y - ry) * (y - ry)); |
55 | 55 | ||
56 | double noise = TerrainUtil.PerlinNoise2D(x / (double) Constants.RegionSize, y / (double) Constants.RegionSize, 8, 1.0); | 56 | double noise = TerrainUtil.PerlinNoise2D(x / (double) map.Width, y / (double) map.Height, 8, 1.0); |
57 | 57 | ||
58 | if (z > 0.0) | 58 | if (z > 0.0) |
59 | map[x, y] += noise * z * duration; | 59 | map[x, y] += noise * z * duration; |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index fd30c46..7bc5e88 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs | |||
@@ -30,10 +30,14 @@ using System.Collections.Generic; | |||
30 | using System.IO; | 30 | using System.IO; |
31 | using System.Reflection; | 31 | using System.Reflection; |
32 | using System.Net; | 32 | using System.Net; |
33 | |||
33 | using log4net; | 34 | using log4net; |
34 | using Nini.Config; | 35 | using Nini.Config; |
36 | |||
35 | using OpenMetaverse; | 37 | using OpenMetaverse; |
36 | using Mono.Addins; | 38 | using Mono.Addins; |
39 | |||
40 | using OpenSim.Data; | ||
37 | using OpenSim.Framework; | 41 | using OpenSim.Framework; |
38 | using OpenSim.Region.CoreModules.Framework.InterfaceCommander; | 42 | using OpenSim.Region.CoreModules.Framework.InterfaceCommander; |
39 | using OpenSim.Region.CoreModules.World.Terrain.FileLoaders; | 43 | using OpenSim.Region.CoreModules.World.Terrain.FileLoaders; |
@@ -70,6 +74,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
70 | #endregion | 74 | #endregion |
71 | 75 | ||
72 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 76 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
77 | private static readonly string LogHeader = "[TERRAIN MODULE]"; | ||
73 | 78 | ||
74 | private readonly Commander m_commander = new Commander("terrain"); | 79 | private readonly Commander m_commander = new Commander("terrain"); |
75 | 80 | ||
@@ -130,15 +135,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
130 | { | 135 | { |
131 | if (m_scene.Heightmap == null) | 136 | if (m_scene.Heightmap == null) |
132 | { | 137 | { |
133 | m_channel = new TerrainChannel(m_InitialTerrain); | 138 | m_channel = new TerrainChannel(m_InitialTerrain, (int)m_scene.RegionInfo.RegionSizeX, |
139 | (int)m_scene.RegionInfo.RegionSizeY, | ||
140 | (int)m_scene.RegionInfo.RegionSizeZ); | ||
134 | m_scene.Heightmap = m_channel; | 141 | m_scene.Heightmap = m_channel; |
135 | m_revert = new TerrainChannel(); | ||
136 | UpdateRevertMap(); | 142 | UpdateRevertMap(); |
137 | } | 143 | } |
138 | else | 144 | else |
139 | { | 145 | { |
140 | m_channel = m_scene.Heightmap; | 146 | m_channel = m_scene.Heightmap; |
141 | m_revert = new TerrainChannel(); | ||
142 | UpdateRevertMap(); | 147 | UpdateRevertMap(); |
143 | } | 148 | } |
144 | 149 | ||
@@ -230,11 +235,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
230 | try | 235 | try |
231 | { | 236 | { |
232 | ITerrainChannel channel = loader.Value.LoadFile(filename); | 237 | ITerrainChannel channel = loader.Value.LoadFile(filename); |
233 | if (channel.Width != Constants.RegionSize || channel.Height != Constants.RegionSize) | 238 | if (channel.Width != m_scene.RegionInfo.RegionSizeX || channel.Height != m_scene.RegionInfo.RegionSizeY) |
234 | { | 239 | { |
235 | // TerrainChannel expects a RegionSize x RegionSize map, currently | 240 | // TerrainChannel expects a RegionSize x RegionSize map, currently |
236 | throw new ArgumentException(String.Format("wrong size, use a file with size {0} x {1}", | 241 | throw new ArgumentException(String.Format("wrong size, use a file with size {0} x {1}", |
237 | Constants.RegionSize, Constants.RegionSize)); | 242 | m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY)); |
238 | } | 243 | } |
239 | m_log.DebugFormat("[TERRAIN]: Loaded terrain, wd/ht: {0}/{1}", channel.Width, channel.Height); | 244 | m_log.DebugFormat("[TERRAIN]: Loaded terrain, wd/ht: {0}/{1}", channel.Width, channel.Height); |
240 | m_scene.Heightmap = channel; | 245 | m_scene.Heightmap = channel; |
@@ -309,12 +314,18 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
309 | LoadFromStream(filename, URIFetch(pathToTerrainHeightmap)); | 314 | LoadFromStream(filename, URIFetch(pathToTerrainHeightmap)); |
310 | } | 315 | } |
311 | 316 | ||
317 | public void LoadFromStream(string filename, Stream stream) | ||
318 | { | ||
319 | Vector2 defaultDisplacement = new Vector2(0f, 0f); | ||
320 | LoadFromStream(filename, defaultDisplacement, stream); | ||
321 | } | ||
322 | |||
312 | /// <summary> | 323 | /// <summary> |
313 | /// Loads a terrain file from a stream and installs it in the scene. | 324 | /// Loads a terrain file from a stream and installs it in the scene. |
314 | /// </summary> | 325 | /// </summary> |
315 | /// <param name="filename">Filename to terrain file. Type is determined by extension.</param> | 326 | /// <param name="filename">Filename to terrain file. Type is determined by extension.</param> |
316 | /// <param name="stream"></param> | 327 | /// <param name="stream"></param> |
317 | public void LoadFromStream(string filename, Stream stream) | 328 | public void LoadFromStream(string filename, Vector2 displacement, Stream stream) |
318 | { | 329 | { |
319 | foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) | 330 | foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) |
320 | { | 331 | { |
@@ -325,8 +336,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
325 | try | 336 | try |
326 | { | 337 | { |
327 | ITerrainChannel channel = loader.Value.LoadStream(stream); | 338 | ITerrainChannel channel = loader.Value.LoadStream(stream); |
328 | m_scene.Heightmap = channel; | 339 | MergeTerrainIntoExisting(channel, displacement); |
329 | m_channel = channel; | ||
330 | UpdateRevertMap(); | 340 | UpdateRevertMap(); |
331 | } | 341 | } |
332 | catch (NotImplementedException) | 342 | catch (NotImplementedException) |
@@ -346,6 +356,33 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
346 | throw new TerrainException(String.Format("unable to load heightmap from file {0}: no loader available for that format", filename)); | 356 | throw new TerrainException(String.Format("unable to load heightmap from file {0}: no loader available for that format", filename)); |
347 | } | 357 | } |
348 | 358 | ||
359 | private void MergeTerrainIntoExisting(ITerrainChannel channel, Vector2 displacement) | ||
360 | { | ||
361 | if (displacement == Vector2.Zero) | ||
362 | { | ||
363 | // If there is no displacement, just use this channel as the new heightmap | ||
364 | m_scene.Heightmap = channel; | ||
365 | m_channel = channel; | ||
366 | } | ||
367 | else | ||
368 | { | ||
369 | // If there is a displacement, we copy the loaded heightmap into the overall region | ||
370 | for (int xx = 0; xx < channel.Width; xx++) | ||
371 | { | ||
372 | for (int yy = 0; yy < channel.Height; yy++) | ||
373 | { | ||
374 | int dispX = xx + (int)displacement.X; | ||
375 | int dispY = yy + (int)displacement.Y; | ||
376 | if (dispX >= 0 && dispX < m_channel.Width | ||
377 | && dispY >= 0 && dispY < m_channel.Height) | ||
378 | { | ||
379 | m_channel[dispX, dispY] = channel[xx, yy]; | ||
380 | } | ||
381 | } | ||
382 | } | ||
383 | } | ||
384 | } | ||
385 | |||
349 | private static Stream URIFetch(Uri uri) | 386 | private static Stream URIFetch(Uri uri) |
350 | { | 387 | { |
351 | HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); | 388 | HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); |
@@ -532,6 +569,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
532 | /// </summary> | 569 | /// </summary> |
533 | public void UpdateRevertMap() | 570 | public void UpdateRevertMap() |
534 | { | 571 | { |
572 | /* | ||
535 | int x; | 573 | int x; |
536 | for (x = 0; x < m_channel.Width; x++) | 574 | for (x = 0; x < m_channel.Width; x++) |
537 | { | 575 | { |
@@ -541,6 +579,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
541 | m_revert[x, y] = m_channel[x, y]; | 579 | m_revert[x, y] = m_channel[x, y]; |
542 | } | 580 | } |
543 | } | 581 | } |
582 | */ | ||
583 | m_revert = m_channel.MakeCopy(); | ||
544 | } | 584 | } |
545 | 585 | ||
546 | /// <summary> | 586 | /// <summary> |
@@ -567,8 +607,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
567 | { | 607 | { |
568 | ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY, | 608 | ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY, |
569 | fileWidth, fileHeight, | 609 | fileWidth, fileHeight, |
570 | (int) Constants.RegionSize, | 610 | (int) m_scene.RegionInfo.RegionSizeX, |
571 | (int) Constants.RegionSize); | 611 | (int) m_scene.RegionInfo.RegionSizeY); |
572 | m_scene.Heightmap = channel; | 612 | m_scene.Heightmap = channel; |
573 | m_channel = channel; | 613 | m_channel = channel; |
574 | UpdateRevertMap(); | 614 | UpdateRevertMap(); |
@@ -615,8 +655,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
615 | { | 655 | { |
616 | loader.Value.SaveFile(m_channel, filename, offsetX, offsetY, | 656 | loader.Value.SaveFile(m_channel, filename, offsetX, offsetY, |
617 | fileWidth, fileHeight, | 657 | fileWidth, fileHeight, |
618 | (int)Constants.RegionSize, | 658 | (int)m_scene.RegionInfo.RegionSizeX, |
619 | (int)Constants.RegionSize); | 659 | (int)m_scene.RegionInfo.RegionSizeY); |
620 | 660 | ||
621 | MainConsole.Instance.OutputFormat( | 661 | MainConsole.Instance.OutputFormat( |
622 | "Saved terrain from ({0},{1}) to ({2},{3}) from {4} to {5}", | 662 | "Saved terrain from ({0},{1}) to ({2},{3}) from {4} to {5}", |
@@ -705,7 +745,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
705 | private void CheckForTerrainUpdates(bool respectEstateSettings) | 745 | private void CheckForTerrainUpdates(bool respectEstateSettings) |
706 | { | 746 | { |
707 | bool shouldTaint = false; | 747 | bool shouldTaint = false; |
708 | float[] serialised = m_channel.GetFloatsSerialised(); | 748 | float[] terrHeights = m_channel.GetFloatsSerialised(); |
709 | int x; | 749 | int x; |
710 | for (x = 0; x < m_channel.Width; x += Constants.TerrainPatchSize) | 750 | for (x = 0; x < m_channel.Width; x += Constants.TerrainPatchSize) |
711 | { | 751 | { |
@@ -714,16 +754,17 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
714 | { | 754 | { |
715 | if (m_channel.Tainted(x, y)) | 755 | if (m_channel.Tainted(x, y)) |
716 | { | 756 | { |
717 | // if we should respect the estate settings then | 757 | // If we should respect the estate settings then |
718 | // fixup and height deltas that don't respect them | 758 | // fixup and height deltas that don't respect them. |
759 | // Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values. | ||
719 | if (respectEstateSettings && LimitChannelChanges(x, y)) | 760 | if (respectEstateSettings && LimitChannelChanges(x, y)) |
720 | { | 761 | { |
721 | // this has been vetoed, so update | 762 | // Terrain heights were modified. Refetch the terrain info. |
722 | // what we are going to send to the client | 763 | terrHeights = m_channel.GetFloatsSerialised(); |
723 | serialised = m_channel.GetFloatsSerialised(); | ||
724 | } | 764 | } |
725 | 765 | ||
726 | SendToClients(serialised, x, y); | 766 | // m_log.DebugFormat("{0} Patch modified. Sending (x,y) = ({1},{2})", LogHeader, x, y); |
767 | SendToClients(terrHeights, x, y); | ||
727 | shouldTaint = true; | 768 | shouldTaint = true; |
728 | } | 769 | } |
729 | } | 770 | } |
@@ -792,13 +833,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
792 | /// <param name="serialised">A copy of the terrain as a 1D float array of size w*h</param> | 833 | /// <param name="serialised">A copy of the terrain as a 1D float array of size w*h</param> |
793 | /// <param name="x">The patch corner to send</param> | 834 | /// <param name="x">The patch corner to send</param> |
794 | /// <param name="y">The patch corner to send</param> | 835 | /// <param name="y">The patch corner to send</param> |
795 | private void SendToClients(float[] serialised, int x, int y) | 836 | private void SendToClients(float[] heightMap, int x, int y) |
796 | { | 837 | { |
797 | m_scene.ForEachClient( | 838 | m_scene.ForEachClient( |
798 | delegate(IClientAPI controller) | 839 | delegate(IClientAPI controller) |
799 | { controller.SendLayerData( | 840 | { controller.SendLayerData( x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, heightMap); } |
800 | x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, serialised); | ||
801 | } | ||
802 | ); | 841 | ); |
803 | } | 842 | } |
804 | 843 | ||
@@ -984,28 +1023,28 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
984 | 1023 | ||
985 | if (direction.ToLower().StartsWith("y")) | 1024 | if (direction.ToLower().StartsWith("y")) |
986 | { | 1025 | { |
987 | for (int x = 0; x < Constants.RegionSize; x++) | 1026 | for (int x = 0; x < m_channel.Width; x++) |
988 | { | 1027 | { |
989 | for (int y = 0; y < Constants.RegionSize / 2; y++) | 1028 | for (int y = 0; y < m_channel.Height / 2; y++) |
990 | { | 1029 | { |
991 | double height = m_channel[x, y]; | 1030 | double height = m_channel[x, y]; |
992 | double flippedHeight = m_channel[x, (int)Constants.RegionSize - 1 - y]; | 1031 | double flippedHeight = m_channel[x, (int)m_channel.Height - 1 - y]; |
993 | m_channel[x, y] = flippedHeight; | 1032 | m_channel[x, y] = flippedHeight; |
994 | m_channel[x, (int)Constants.RegionSize - 1 - y] = height; | 1033 | m_channel[x, (int)m_channel.Height - 1 - y] = height; |
995 | 1034 | ||
996 | } | 1035 | } |
997 | } | 1036 | } |
998 | } | 1037 | } |
999 | else if (direction.ToLower().StartsWith("x")) | 1038 | else if (direction.ToLower().StartsWith("x")) |
1000 | { | 1039 | { |
1001 | for (int y = 0; y < Constants.RegionSize; y++) | 1040 | for (int y = 0; y < m_channel.Height; y++) |
1002 | { | 1041 | { |
1003 | for (int x = 0; x < Constants.RegionSize / 2; x++) | 1042 | for (int x = 0; x < m_channel.Width / 2; x++) |
1004 | { | 1043 | { |
1005 | double height = m_channel[x, y]; | 1044 | double height = m_channel[x, y]; |
1006 | double flippedHeight = m_channel[(int)Constants.RegionSize - 1 - x, y]; | 1045 | double flippedHeight = m_channel[(int)m_channel.Width - 1 - x, y]; |
1007 | m_channel[x, y] = flippedHeight; | 1046 | m_channel[x, y] = flippedHeight; |
1008 | m_channel[(int)Constants.RegionSize - 1 - x, y] = height; | 1047 | m_channel[(int)m_channel.Width - 1 - x, y] = height; |
1009 | 1048 | ||
1010 | } | 1049 | } |
1011 | } | 1050 | } |
diff --git a/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs b/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs index df5ac92..9534ad3 100644 --- a/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs +++ b/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
@@ -32,6 +32,7 @@ using System.Drawing.Imaging; | |||
32 | using log4net; | 32 | using log4net; |
33 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Region.Framework.Interfaces; | ||
35 | using OpenSim.Services.Interfaces; | 36 | using OpenSim.Services.Interfaces; |
36 | 37 | ||
37 | namespace OpenSim.Region.CoreModules.World.Warp3DMap | 38 | namespace OpenSim.Region.CoreModules.World.Warp3DMap |
@@ -66,261 +67,271 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
66 | #endregion Constants | 67 | #endregion Constants |
67 | 68 | ||
68 | private static readonly ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); | 69 | private static readonly ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); |
70 | private static string LogHeader = "[WARP3D TERRAIN SPLAT]"; | ||
69 | 71 | ||
70 | /// <summary> | 72 | /// <summary> |
71 | /// Builds a composited terrain texture given the region texture | 73 | /// Builds a composited terrain texture given the region texture |
72 | /// and heightmap settings | 74 | /// and heightmap settings |
73 | /// </summary> | 75 | /// </summary> |
74 | /// <param name="heightmap">Terrain heightmap</param> | 76 | /// <param name="terrain">Terrain heightmap</param> |
75 | /// <param name="regionInfo">Region information including terrain texture parameters</param> | 77 | /// <param name="regionInfo">Region information including terrain texture parameters</param> |
76 | /// <returns>A composited 256x256 RGB texture ready for rendering</returns> | 78 | /// <returns>A 256x256 square RGB texture ready for rendering</returns> |
77 | /// <remarks>Based on the algorithm described at http://opensimulator.org/wiki/Terrain_Splatting | 79 | /// <remarks>Based on the algorithm described at http://opensimulator.org/wiki/Terrain_Splatting |
80 | /// Note we create a 256x256 dimension texture even if the actual terrain is larger. | ||
78 | /// </remarks> | 81 | /// </remarks> |
79 | public static Bitmap Splat(float[] heightmap, UUID[] textureIDs, float[] startHeights, float[] heightRanges, Vector3d regionPosition, IAssetService assetService, bool textureTerrain) | 82 | public static Bitmap Splat(ITerrainChannel terrain, |
83 | UUID[] textureIDs, float[] startHeights, float[] heightRanges, | ||
84 | Vector3d regionPosition, IAssetService assetService, bool textureTerrain) | ||
80 | { | 85 | { |
81 | Debug.Assert(heightmap.Length == 256 * 256); | ||
82 | Debug.Assert(textureIDs.Length == 4); | 86 | Debug.Assert(textureIDs.Length == 4); |
83 | Debug.Assert(startHeights.Length == 4); | 87 | Debug.Assert(startHeights.Length == 4); |
84 | Debug.Assert(heightRanges.Length == 4); | 88 | Debug.Assert(heightRanges.Length == 4); |
85 | 89 | ||
86 | Bitmap[] detailTexture = new Bitmap[4]; | 90 | Bitmap[] detailTexture = new Bitmap[4]; |
87 | Bitmap output = null; | ||
88 | BitmapData outputData = null; | ||
89 | 91 | ||
90 | try | 92 | if (textureTerrain) |
91 | { | 93 | { |
92 | if (textureTerrain) | 94 | // Swap empty terrain textureIDs with default IDs |
95 | for (int i = 0; i < textureIDs.Length; i++) | ||
93 | { | 96 | { |
94 | // Swap empty terrain textureIDs with default IDs | 97 | if (textureIDs[i] == UUID.Zero) |
95 | for (int i = 0; i < textureIDs.Length; i++) | 98 | textureIDs[i] = DEFAULT_TERRAIN_DETAIL[i]; |
96 | { | 99 | } |
97 | if (textureIDs[i] == UUID.Zero) | 100 | |
98 | textureIDs[i] = DEFAULT_TERRAIN_DETAIL[i]; | 101 | #region Texture Fetching |
99 | } | 102 | |
100 | 103 | if (assetService != null) | |
101 | #region Texture Fetching | 104 | { |
102 | 105 | for (int i = 0; i < 4; i++) | |
103 | if (assetService != null) | ||
104 | { | 106 | { |
105 | for (int i = 0; i < 4; i++) | 107 | AssetBase asset; |
108 | UUID cacheID = UUID.Combine(TERRAIN_CACHE_MAGIC, textureIDs[i]); | ||
109 | |||
110 | // Try to fetch a cached copy of the decoded/resized version of this texture | ||
111 | asset = assetService.GetCached(cacheID.ToString()); | ||
112 | if (asset != null) | ||
113 | { | ||
114 | try | ||
115 | { | ||
116 | using (System.IO.MemoryStream stream = new System.IO.MemoryStream(asset.Data)) | ||
117 | detailTexture[i] = (Bitmap)Image.FromStream(stream); | ||
118 | } | ||
119 | catch (Exception ex) | ||
120 | { | ||
121 | m_log.Warn("Failed to decode cached terrain texture " + cacheID + | ||
122 | " (textureID: " + textureIDs[i] + "): " + ex.Message); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | if (detailTexture[i] == null) | ||
106 | { | 127 | { |
107 | AssetBase asset; | 128 | // Try to fetch the original JPEG2000 texture, resize if needed, and cache as PNG |
108 | UUID cacheID = UUID.Combine(TERRAIN_CACHE_MAGIC, textureIDs[i]); | 129 | asset = assetService.Get(textureIDs[i].ToString()); |
109 | |||
110 | // Try to fetch a cached copy of the decoded/resized version of this texture | ||
111 | asset = assetService.GetCached(cacheID.ToString()); | ||
112 | if (asset != null) | 130 | if (asset != null) |
113 | { | 131 | { |
114 | // m_log.DebugFormat( | 132 | // m_log.DebugFormat( |
115 | // "[TERRAIN SPLAT]: Got asset service cached terrain texture {0} {1}", i, asset.ID); | 133 | // "[TERRAIN SPLAT]: Got cached original JPEG2000 terrain texture {0} {1}", i, asset.ID); |
116 | 134 | ||
117 | try | 135 | try { detailTexture[i] = (Bitmap)CSJ2K.J2kImage.FromBytes(asset.Data); } |
118 | { | ||
119 | using (System.IO.MemoryStream stream = new System.IO.MemoryStream(asset.Data)) | ||
120 | detailTexture[i] = (Bitmap)Image.FromStream(stream); | ||
121 | } | ||
122 | catch (Exception ex) | 136 | catch (Exception ex) |
123 | { | 137 | { |
124 | m_log.Warn("Failed to decode cached terrain texture " + cacheID + | 138 | m_log.Warn("Failed to decode terrain texture " + asset.ID + ": " + ex.Message); |
125 | " (textureID: " + textureIDs[i] + "): " + ex.Message); | ||
126 | } | 139 | } |
127 | } | 140 | } |
128 | |||
129 | if (detailTexture[i] == null) | ||
130 | { | ||
131 | // Try to fetch the original JPEG2000 texture, resize if needed, and cache as PNG | ||
132 | asset = assetService.Get(textureIDs[i].ToString()); | ||
133 | if (asset != null) | ||
134 | { | ||
135 | // m_log.DebugFormat( | ||
136 | // "[TERRAIN SPLAT]: Got cached original JPEG2000 terrain texture {0} {1}", i, asset.ID); | ||
137 | 141 | ||
138 | try { detailTexture[i] = (Bitmap)CSJ2K.J2kImage.FromBytes(asset.Data); } | 142 | if (detailTexture[i] != null) |
139 | catch (Exception ex) | 143 | { |
144 | // Make sure this texture is the correct size, otherwise resize | ||
145 | if (detailTexture[i].Width != 256 || detailTexture[i].Height != 256) | ||
146 | { | ||
147 | using (Bitmap origBitmap = detailTexture[i]) | ||
140 | { | 148 | { |
141 | m_log.Warn("Failed to decode terrain texture " + asset.ID + ": " + ex.Message); | 149 | detailTexture[i] = ImageUtils.ResizeImage(origBitmap, 256, 256); |
142 | } | 150 | } |
143 | } | 151 | } |
144 | 152 | ||
145 | if (detailTexture[i] != null) | 153 | // Save the decoded and resized texture to the cache |
146 | { | 154 | byte[] data; |
147 | // Make sure this texture is the correct size, otherwise resize | 155 | using (System.IO.MemoryStream stream = new System.IO.MemoryStream()) |
148 | if (detailTexture[i].Width != 256 || detailTexture[i].Height != 256) | 156 | { |
149 | { | 157 | detailTexture[i].Save(stream, ImageFormat.Png); |
150 | using (Bitmap origBitmap = detailTexture[i]) | 158 | data = stream.ToArray(); |
151 | { | ||
152 | detailTexture[i] = ImageUtils.ResizeImage(origBitmap, 256, 256); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | // Save the decoded and resized texture to the cache | ||
157 | byte[] data; | ||
158 | using (System.IO.MemoryStream stream = new System.IO.MemoryStream()) | ||
159 | { | ||
160 | detailTexture[i].Save(stream, ImageFormat.Png); | ||
161 | data = stream.ToArray(); | ||
162 | } | ||
163 | |||
164 | // Cache a PNG copy of this terrain texture | ||
165 | AssetBase newAsset = new AssetBase | ||
166 | { | ||
167 | Data = data, | ||
168 | Description = "PNG", | ||
169 | Flags = AssetFlags.Collectable, | ||
170 | FullID = cacheID, | ||
171 | ID = cacheID.ToString(), | ||
172 | Local = true, | ||
173 | Name = String.Empty, | ||
174 | Temporary = true, | ||
175 | Type = (sbyte)AssetType.Unknown | ||
176 | }; | ||
177 | newAsset.Metadata.ContentType = "image/png"; | ||
178 | assetService.Store(newAsset); | ||
179 | } | 159 | } |
160 | |||
161 | // Cache a PNG copy of this terrain texture | ||
162 | AssetBase newAsset = new AssetBase | ||
163 | { | ||
164 | Data = data, | ||
165 | Description = "PNG", | ||
166 | Flags = AssetFlags.Collectable, | ||
167 | FullID = cacheID, | ||
168 | ID = cacheID.ToString(), | ||
169 | Local = true, | ||
170 | Name = String.Empty, | ||
171 | Temporary = true, | ||
172 | Type = (sbyte)AssetType.Unknown | ||
173 | }; | ||
174 | newAsset.Metadata.ContentType = "image/png"; | ||
175 | assetService.Store(newAsset); | ||
180 | } | 176 | } |
181 | } | 177 | } |
182 | } | 178 | } |
183 | |||
184 | #endregion Texture Fetching | ||
185 | } | 179 | } |
186 | 180 | ||
187 | // Fill in any missing textures with a solid color | 181 | #endregion Texture Fetching |
188 | for (int i = 0; i < 4; i++) | 182 | } |
183 | |||
184 | // Fill in any missing textures with a solid color | ||
185 | for (int i = 0; i < 4; i++) | ||
186 | { | ||
187 | if (detailTexture[i] == null) | ||
189 | { | 188 | { |
190 | if (detailTexture[i] == null) | 189 | m_log.DebugFormat("{0} Missing terrain texture for layer {1}. Filling with solid default color", |
190 | LogHeader, i); | ||
191 | // Create a solid color texture for this layer | ||
192 | detailTexture[i] = new Bitmap(256, 256, PixelFormat.Format24bppRgb); | ||
193 | using (Graphics gfx = Graphics.FromImage(detailTexture[i])) | ||
191 | { | 194 | { |
192 | // m_log.DebugFormat( | 195 | using (SolidBrush brush = new SolidBrush(DEFAULT_TERRAIN_COLOR[i])) |
193 | // "[TERRAIN SPLAT]: Generating solid colour for missing texture {0}", i); | 196 | gfx.FillRectangle(brush, 0, 0, 256, 256); |
194 | |||
195 | // Create a solid color texture for this layer | ||
196 | detailTexture[i] = new Bitmap(256, 256, PixelFormat.Format24bppRgb); | ||
197 | using (Graphics gfx = Graphics.FromImage(detailTexture[i])) | ||
198 | { | ||
199 | using (SolidBrush brush = new SolidBrush(DEFAULT_TERRAIN_COLOR[i])) | ||
200 | gfx.FillRectangle(brush, 0, 0, 256, 256); | ||
201 | } | ||
202 | } | 197 | } |
203 | } | 198 | } |
204 | 199 | else | |
205 | #region Layer Map | ||
206 | |||
207 | float[] layermap = new float[256 * 256]; | ||
208 | |||
209 | for (int y = 0; y < 256; y++) | ||
210 | { | 200 | { |
211 | for (int x = 0; x < 256; x++) | 201 | if (detailTexture[i].Width != 256 || detailTexture[i].Height != 256) |
212 | { | 202 | { |
213 | float height = heightmap[y * 256 + x]; | 203 | detailTexture[i] = ResizeBitmap(detailTexture[i], 256, 256); |
214 | |||
215 | float pctX = (float)x / 255f; | ||
216 | float pctY = (float)y / 255f; | ||
217 | |||
218 | // Use bilinear interpolation between the four corners of start height and | ||
219 | // height range to select the current values at this position | ||
220 | float startHeight = ImageUtils.Bilinear( | ||
221 | startHeights[0], | ||
222 | startHeights[2], | ||
223 | startHeights[1], | ||
224 | startHeights[3], | ||
225 | pctX, pctY); | ||
226 | startHeight = Utils.Clamp(startHeight, 0f, 255f); | ||
227 | |||
228 | float heightRange = ImageUtils.Bilinear( | ||
229 | heightRanges[0], | ||
230 | heightRanges[2], | ||
231 | heightRanges[1], | ||
232 | heightRanges[3], | ||
233 | pctX, pctY); | ||
234 | heightRange = Utils.Clamp(heightRange, 0f, 255f); | ||
235 | |||
236 | // Generate two frequencies of perlin noise based on our global position | ||
237 | // The magic values were taken from http://opensimulator.org/wiki/Terrain_Splatting | ||
238 | Vector3 vec = new Vector3 | ||
239 | ( | ||
240 | ((float)regionPosition.X + x) * 0.20319f, | ||
241 | ((float)regionPosition.Y + y) * 0.20319f, | ||
242 | height * 0.25f | ||
243 | ); | ||
244 | |||
245 | float lowFreq = Perlin.noise2(vec.X * 0.222222f, vec.Y * 0.222222f) * 6.5f; | ||
246 | float highFreq = Perlin.turbulence2(vec.X, vec.Y, 2f) * 2.25f; | ||
247 | float noise = (lowFreq + highFreq) * 2f; | ||
248 | |||
249 | // Combine the current height, generated noise, start height, and height range parameters, then scale all of it | ||
250 | float layer = ((height + noise - startHeight) / heightRange) * 4f; | ||
251 | if (Single.IsNaN(layer)) layer = 0f; | ||
252 | layermap[y * 256 + x] = Utils.Clamp(layer, 0f, 3f); | ||
253 | } | 204 | } |
254 | } | 205 | } |
255 | 206 | } | |
256 | #endregion Layer Map | 207 | |
257 | 208 | #region Layer Map | |
258 | #region Texture Compositing | 209 | |
259 | 210 | float[,] layermap = new float[256, 256]; | |
260 | output = new Bitmap(256, 256, PixelFormat.Format24bppRgb); | 211 | |
261 | outputData = output.LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb); | 212 | // Scale difference between actual region size and the 256 texture being created |
262 | 213 | int xFactor = terrain.Width / 256; | |
263 | unsafe | 214 | int yFactor = terrain.Height / 256; |
215 | |||
216 | // Create 'layermap' where each value is the fractional layer number to place | ||
217 | // at that point. For instance, a value of 1.345 gives the blending of | ||
218 | // layer 1 and layer 2 for that point. | ||
219 | for (int y = 0; y < 256; y++) | ||
220 | { | ||
221 | for (int x = 0; x < 256; x++) | ||
264 | { | 222 | { |
265 | // Get handles to all of the texture data arrays | 223 | float height = (float)terrain[x * xFactor, y * yFactor]; |
266 | BitmapData[] datas = new BitmapData[] | 224 | |
267 | { | 225 | float pctX = (float)x / 255f; |
268 | detailTexture[0].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[0].PixelFormat), | 226 | float pctY = (float)y / 255f; |
269 | detailTexture[1].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[1].PixelFormat), | 227 | |
270 | detailTexture[2].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[2].PixelFormat), | 228 | // Use bilinear interpolation between the four corners of start height and |
271 | detailTexture[3].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[3].PixelFormat) | 229 | // height range to select the current values at this position |
272 | }; | 230 | float startHeight = ImageUtils.Bilinear( |
273 | 231 | startHeights[0], | |
274 | int[] comps = new int[] | 232 | startHeights[2], |
275 | { | 233 | startHeights[1], |
276 | (datas[0].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, | 234 | startHeights[3], |
277 | (datas[1].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, | 235 | pctX, pctY); |
278 | (datas[2].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, | 236 | startHeight = Utils.Clamp(startHeight, 0f, 255f); |
279 | (datas[3].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3 | 237 | |
280 | }; | 238 | float heightRange = ImageUtils.Bilinear( |
281 | 239 | heightRanges[0], | |
282 | for (int y = 0; y < 256; y++) | 240 | heightRanges[2], |
283 | { | 241 | heightRanges[1], |
284 | for (int x = 0; x < 256; x++) | 242 | heightRanges[3], |
285 | { | 243 | pctX, pctY); |
286 | float layer = layermap[y * 256 + x]; | 244 | heightRange = Utils.Clamp(heightRange, 0f, 255f); |
287 | 245 | ||
288 | // Select two textures | 246 | // Generate two frequencies of perlin noise based on our global position |
289 | int l0 = (int)Math.Floor(layer); | 247 | // The magic values were taken from http://opensimulator.org/wiki/Terrain_Splatting |
290 | int l1 = Math.Min(l0 + 1, 3); | 248 | Vector3 vec = new Vector3 |
291 | 249 | ( | |
292 | byte* ptrA = (byte*)datas[l0].Scan0 + y * datas[l0].Stride + x * comps[l0]; | 250 | ((float)regionPosition.X + (x * xFactor)) * 0.20319f, |
293 | byte* ptrB = (byte*)datas[l1].Scan0 + y * datas[l1].Stride + x * comps[l1]; | 251 | ((float)regionPosition.Y + (y * yFactor)) * 0.20319f, |
294 | byte* ptrO = (byte*)outputData.Scan0 + y * outputData.Stride + x * 3; | 252 | height * 0.25f |
295 | 253 | ); | |
296 | float aB = *(ptrA + 0); | 254 | |
297 | float aG = *(ptrA + 1); | 255 | float lowFreq = Perlin.noise2(vec.X * 0.222222f, vec.Y * 0.222222f) * 6.5f; |
298 | float aR = *(ptrA + 2); | 256 | float highFreq = Perlin.turbulence2(vec.X, vec.Y, 2f) * 2.25f; |
299 | 257 | float noise = (lowFreq + highFreq) * 2f; | |
300 | float bB = *(ptrB + 0); | 258 | |
301 | float bG = *(ptrB + 1); | 259 | // Combine the current height, generated noise, start height, and height range parameters, then scale all of it |
302 | float bR = *(ptrB + 2); | 260 | float layer = ((height + noise - startHeight) / heightRange) * 4f; |
303 | 261 | if (Single.IsNaN(layer)) | |
304 | float layerDiff = layer - l0; | 262 | layer = 0f; |
305 | 263 | layermap[x, y] = Utils.Clamp(layer, 0f, 3f); | |
306 | // Interpolate between the two selected textures | ||
307 | *(ptrO + 0) = (byte)Math.Floor(aB + layerDiff * (bB - aB)); | ||
308 | *(ptrO + 1) = (byte)Math.Floor(aG + layerDiff * (bG - aG)); | ||
309 | *(ptrO + 2) = (byte)Math.Floor(aR + layerDiff * (bR - aR)); | ||
310 | } | ||
311 | } | ||
312 | |||
313 | for (int i = 0; i < 4; i++) | ||
314 | detailTexture[i].UnlockBits(datas[i]); | ||
315 | } | 264 | } |
316 | } | 265 | } |
317 | finally | 266 | |
267 | #endregion Layer Map | ||
268 | |||
269 | #region Texture Compositing | ||
270 | |||
271 | Bitmap output = new Bitmap(256, 256, PixelFormat.Format24bppRgb); | ||
272 | BitmapData outputData = output.LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb); | ||
273 | |||
274 | // Unsafe work as we lock down the source textures for quicker access and access the | ||
275 | // pixel data directly | ||
276 | unsafe | ||
318 | { | 277 | { |
319 | for (int i = 0; i < 4; i++) | 278 | // Get handles to all of the texture data arrays |
320 | if (detailTexture[i] != null) | 279 | BitmapData[] datas = new BitmapData[] |
321 | detailTexture[i].Dispose(); | 280 | { |
281 | detailTexture[0].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[0].PixelFormat), | ||
282 | detailTexture[1].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[1].PixelFormat), | ||
283 | detailTexture[2].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[2].PixelFormat), | ||
284 | detailTexture[3].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[3].PixelFormat) | ||
285 | }; | ||
286 | |||
287 | // Compute size of each pixel data (used to address into the pixel data array) | ||
288 | int[] comps = new int[] | ||
289 | { | ||
290 | (datas[0].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, | ||
291 | (datas[1].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, | ||
292 | (datas[2].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, | ||
293 | (datas[3].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3 | ||
294 | }; | ||
295 | |||
296 | for (int y = 0; y < 256; y++) | ||
297 | { | ||
298 | for (int x = 0; x < 256; x++) | ||
299 | { | ||
300 | float layer = layermap[x, y]; | ||
301 | |||
302 | // Select two textures | ||
303 | int l0 = (int)Math.Floor(layer); | ||
304 | int l1 = Math.Min(l0 + 1, 3); | ||
305 | |||
306 | byte* ptrA = (byte*)datas[l0].Scan0 + y * datas[l0].Stride + x * comps[l0]; | ||
307 | byte* ptrB = (byte*)datas[l1].Scan0 + y * datas[l1].Stride + x * comps[l1]; | ||
308 | byte* ptrO = (byte*)outputData.Scan0 + y * outputData.Stride + x * 3; | ||
309 | |||
310 | float aB = *(ptrA + 0); | ||
311 | float aG = *(ptrA + 1); | ||
312 | float aR = *(ptrA + 2); | ||
313 | |||
314 | float bB = *(ptrB + 0); | ||
315 | float bG = *(ptrB + 1); | ||
316 | float bR = *(ptrB + 2); | ||
317 | |||
318 | float layerDiff = layer - l0; | ||
319 | |||
320 | // Interpolate between the two selected textures | ||
321 | *(ptrO + 0) = (byte)Math.Floor(aB + layerDiff * (bB - aB)); | ||
322 | *(ptrO + 1) = (byte)Math.Floor(aG + layerDiff * (bG - aG)); | ||
323 | *(ptrO + 2) = (byte)Math.Floor(aR + layerDiff * (bR - aR)); | ||
324 | } | ||
325 | } | ||
326 | |||
327 | for (int i = 0; i < detailTexture.Length; i++) | ||
328 | detailTexture[i].UnlockBits(datas[i]); | ||
322 | } | 329 | } |
323 | 330 | ||
331 | for (int i = 0; i < detailTexture.Length; i++) | ||
332 | if (detailTexture[i] != null) | ||
333 | detailTexture[i].Dispose(); | ||
334 | |||
324 | output.UnlockBits(outputData); | 335 | output.UnlockBits(outputData); |
325 | 336 | ||
326 | // We generated the texture upside down, so flip it | 337 | // We generated the texture upside down, so flip it |
@@ -331,6 +342,17 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
331 | return output; | 342 | return output; |
332 | } | 343 | } |
333 | 344 | ||
345 | public static Bitmap ResizeBitmap(Bitmap b, int nWidth, int nHeight) | ||
346 | { | ||
347 | m_log.DebugFormat("{0} ResizeBitmap. From <{1},{2}> to <{3},{4}>", | ||
348 | LogHeader, b.Width, b.Height, nWidth, nHeight); | ||
349 | Bitmap result = new Bitmap(nWidth, nHeight); | ||
350 | using (Graphics g = Graphics.FromImage(result)) | ||
351 | g.DrawImage(b, 0, 0, nWidth, nHeight); | ||
352 | b.Dispose(); | ||
353 | return result; | ||
354 | } | ||
355 | |||
334 | public static Bitmap SplatSimple(float[] heightmap) | 356 | public static Bitmap SplatSimple(float[] heightmap) |
335 | { | 357 | { |
336 | const float BASE_HSV_H = 93f / 360f; | 358 | const float BASE_HSV_H = 93f / 360f; |
diff --git a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs index ed2b06a..5728731 100644 --- a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs +++ b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs | |||
@@ -31,21 +31,25 @@ using System.Drawing; | |||
31 | using System.Drawing.Imaging; | 31 | using System.Drawing.Imaging; |
32 | using System.IO; | 32 | using System.IO; |
33 | using System.Reflection; | 33 | using System.Reflection; |
34 | |||
34 | using CSJ2K; | 35 | using CSJ2K; |
35 | using Nini.Config; | 36 | using Nini.Config; |
36 | using log4net; | 37 | using log4net; |
37 | using Rednettle.Warp3D; | 38 | using Rednettle.Warp3D; |
38 | using Mono.Addins; | 39 | using Mono.Addins; |
39 | using OpenMetaverse; | 40 | |
40 | using OpenMetaverse.Imaging; | ||
41 | using OpenMetaverse.Rendering; | ||
42 | using OpenMetaverse.StructuredData; | ||
43 | using OpenSim.Framework; | 41 | using OpenSim.Framework; |
44 | using OpenSim.Region.Framework.Interfaces; | 42 | using OpenSim.Region.Framework.Interfaces; |
45 | using OpenSim.Region.Framework.Scenes; | 43 | using OpenSim.Region.Framework.Scenes; |
46 | using OpenSim.Region.Physics.Manager; | 44 | using OpenSim.Region.Physics.Manager; |
47 | using OpenSim.Services.Interfaces; | 45 | using OpenSim.Services.Interfaces; |
48 | 46 | ||
47 | using OpenMetaverse; | ||
48 | using OpenMetaverse.Assets; | ||
49 | using OpenMetaverse.Imaging; | ||
50 | using OpenMetaverse.Rendering; | ||
51 | using OpenMetaverse.StructuredData; | ||
52 | |||
49 | using WarpRenderer = global::Warp3D.Warp3D; | 53 | using WarpRenderer = global::Warp3D.Warp3D; |
50 | 54 | ||
51 | namespace OpenSim.Region.CoreModules.World.Warp3DMap | 55 | namespace OpenSim.Region.CoreModules.World.Warp3DMap |
@@ -57,12 +61,20 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
57 | private static readonly Color4 WATER_COLOR = new Color4(29, 72, 96, 216); | 61 | private static readonly Color4 WATER_COLOR = new Color4(29, 72, 96, 216); |
58 | 62 | ||
59 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 63 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
64 | private static string LogHeader = "[WARP 3D IMAGE MODULE]"; | ||
60 | 65 | ||
61 | private Scene m_scene; | 66 | private Scene m_scene; |
62 | private IRendering m_primMesher; | 67 | private IRendering m_primMesher; |
63 | private IConfigSource m_config; | ||
64 | private Dictionary<UUID, Color4> m_colors = new Dictionary<UUID, Color4>(); | 68 | private Dictionary<UUID, Color4> m_colors = new Dictionary<UUID, Color4>(); |
65 | private bool m_useAntiAliasing = false; // TODO: Make this a config option | 69 | |
70 | private IConfigSource m_config; | ||
71 | private bool m_drawPrimVolume = true; // true if should render the prims on the tile | ||
72 | private bool m_textureTerrain = true; // true if to create terrain splatting texture | ||
73 | private bool m_texturePrims = true; // true if should texture the rendered prims | ||
74 | private float m_texturePrimSize = 48f; // size of prim before we consider texturing it | ||
75 | private bool m_renderMeshes = false; // true if to render meshes rather than just bounding boxes | ||
76 | private bool m_useAntiAliasing = false; // true if to anti-alias the rendered image | ||
77 | |||
66 | private bool m_Enabled = false; | 78 | private bool m_Enabled = false; |
67 | 79 | ||
68 | #region Region Module interface | 80 | #region Region Module interface |
@@ -71,11 +83,27 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
71 | { | 83 | { |
72 | m_config = source; | 84 | m_config = source; |
73 | 85 | ||
86 | string[] configSections = new string[] { "Map", "Startup" }; | ||
87 | |||
74 | if (Util.GetConfigVarFromSections<string>( | 88 | if (Util.GetConfigVarFromSections<string>( |
75 | m_config, "MapImageModule", new string[] { "Startup", "Map" }, "MapImageModule") != "Warp3DImageModule") | 89 | m_config, "MapImageModule", configSections, "MapImageModule") != "Warp3DImageModule") |
76 | return; | 90 | return; |
77 | 91 | ||
78 | m_Enabled = true; | 92 | m_Enabled = true; |
93 | |||
94 | m_drawPrimVolume | ||
95 | = Util.GetConfigVarFromSections<bool>(m_config, "DrawPrimOnMapTile", configSections, m_drawPrimVolume); | ||
96 | m_textureTerrain | ||
97 | = Util.GetConfigVarFromSections<bool>(m_config, "TextureOnMapTile", configSections, m_textureTerrain); | ||
98 | m_texturePrims | ||
99 | = Util.GetConfigVarFromSections<bool>(m_config, "TexturePrims", configSections, m_texturePrims); | ||
100 | m_texturePrimSize | ||
101 | = Util.GetConfigVarFromSections<float>(m_config, "TexturePrimSize", configSections, m_texturePrimSize); | ||
102 | m_renderMeshes | ||
103 | = Util.GetConfigVarFromSections<bool>(m_config, "RenderMeshes", configSections, m_renderMeshes); | ||
104 | m_useAntiAliasing | ||
105 | = Util.GetConfigVarFromSections<bool>(m_config, "UseAntiAliasing", configSections, m_useAntiAliasing); | ||
106 | |||
79 | } | 107 | } |
80 | 108 | ||
81 | public void AddRegion(Scene scene) | 109 | public void AddRegion(Scene scene) |
@@ -127,29 +155,28 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
127 | 155 | ||
128 | public Bitmap CreateMapTile() | 156 | public Bitmap CreateMapTile() |
129 | { | 157 | { |
130 | Vector3 camPos = new Vector3(127.5f, 127.5f, 221.7025033688163f); | 158 | // Vector3 camPos = new Vector3(127.5f, 127.5f, 221.7025033688163f); |
131 | Viewport viewport = new Viewport(camPos, -Vector3.UnitZ, 1024f, 0.1f, (int)Constants.RegionSize, (int)Constants.RegionSize, (float)Constants.RegionSize, (float)Constants.RegionSize); | 159 | // Camera above the middle of the region |
160 | Vector3 camPos = new Vector3( | ||
161 | m_scene.RegionInfo.RegionSizeX/2 - 0.5f, | ||
162 | m_scene.RegionInfo.RegionSizeY/2 - 0.5f, | ||
163 | 221.7025033688163f); | ||
164 | // Viewport viewing down onto the region | ||
165 | Viewport viewport = new Viewport(camPos, -Vector3.UnitZ, 1024f, 0.1f, | ||
166 | (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY, | ||
167 | (float)m_scene.RegionInfo.RegionSizeX, (float)m_scene.RegionInfo.RegionSizeY ); | ||
168 | // Fill the viewport and return the image | ||
132 | return CreateMapTile(viewport, false); | 169 | return CreateMapTile(viewport, false); |
133 | } | 170 | } |
134 | 171 | ||
135 | public Bitmap CreateViewImage(Vector3 camPos, Vector3 camDir, float fov, int width, int height, bool useTextures) | 172 | public Bitmap CreateViewImage(Vector3 camPos, Vector3 camDir, float fov, int width, int height, bool useTextures) |
136 | { | 173 | { |
137 | Viewport viewport = new Viewport(camPos, camDir, fov, (float)Constants.RegionSize, 0.1f, width, height); | 174 | Viewport viewport = new Viewport(camPos, camDir, fov, Constants.RegionSize, 0.1f, width, height); |
138 | return CreateMapTile(viewport, useTextures); | 175 | return CreateMapTile(viewport, useTextures); |
139 | } | 176 | } |
140 | 177 | ||
141 | public Bitmap CreateMapTile(Viewport viewport, bool useTextures) | 178 | public Bitmap CreateMapTile(Viewport viewport, bool useTextures) |
142 | { | 179 | { |
143 | bool drawPrimVolume = true; | ||
144 | bool textureTerrain = true; | ||
145 | |||
146 | string[] configSections = new string[] { "Map", "Startup" }; | ||
147 | |||
148 | drawPrimVolume | ||
149 | = Util.GetConfigVarFromSections<bool>(m_config, "DrawPrimOnMapTile", configSections, drawPrimVolume); | ||
150 | textureTerrain | ||
151 | = Util.GetConfigVarFromSections<bool>(m_config, "TextureOnMapTile", configSections, textureTerrain); | ||
152 | |||
153 | m_colors.Clear(); | 180 | m_colors.Clear(); |
154 | 181 | ||
155 | int width = viewport.Width; | 182 | int width = viewport.Width; |
@@ -193,8 +220,8 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
193 | renderer.Scene.addLight("Light2", new warp_Light(new warp_Vector(-1f, -1f, 1f), 0xffffff, 0, 100, 40)); | 220 | renderer.Scene.addLight("Light2", new warp_Light(new warp_Vector(-1f, -1f, 1f), 0xffffff, 0, 100, 40)); |
194 | 221 | ||
195 | CreateWater(renderer); | 222 | CreateWater(renderer); |
196 | CreateTerrain(renderer, textureTerrain); | 223 | CreateTerrain(renderer, m_textureTerrain); |
197 | if (drawPrimVolume) | 224 | if (m_drawPrimVolume) |
198 | CreateAllPrims(renderer, useTextures); | 225 | CreateAllPrims(renderer, useTextures); |
199 | 226 | ||
200 | renderer.Render(); | 227 | renderer.Render(); |
@@ -210,6 +237,16 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
210 | // afterwards. It's generally regarded as a bad idea to manually GC. If Warp3D is using lots of memory | 237 | // afterwards. It's generally regarded as a bad idea to manually GC. If Warp3D is using lots of memory |
211 | // then this may be some issue with the Warp3D code itself, though it's also quite possible that generating | 238 | // then this may be some issue with the Warp3D code itself, though it's also quite possible that generating |
212 | // this map tile simply takes a lot of memory. | 239 | // this map tile simply takes a lot of memory. |
240 | foreach (var o in renderer.Scene.objectData.Values) | ||
241 | { | ||
242 | warp_Object obj = (warp_Object)o; | ||
243 | obj.vertexData = null; | ||
244 | obj.triangleData = null; | ||
245 | } | ||
246 | renderer.Scene.removeAllObjects(); | ||
247 | renderer = null; | ||
248 | viewport = null; | ||
249 | m_colors.Clear(); | ||
213 | GC.Collect(); | 250 | GC.Collect(); |
214 | m_log.Debug("[WARP 3D IMAGE MODULE]: GC.Collect()"); | 251 | m_log.Debug("[WARP 3D IMAGE MODULE]: GC.Collect()"); |
215 | 252 | ||
@@ -236,61 +273,74 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
236 | 273 | ||
237 | #region Rendering Methods | 274 | #region Rendering Methods |
238 | 275 | ||
276 | // Add a water plane to the renderer. | ||
239 | private void CreateWater(WarpRenderer renderer) | 277 | private void CreateWater(WarpRenderer renderer) |
240 | { | 278 | { |
241 | float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight; | 279 | float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight; |
242 | 280 | ||
243 | renderer.AddPlane("Water", 256f * 0.5f); | 281 | renderer.AddPlane("Water", m_scene.RegionInfo.RegionSizeX * 0.5f); |
244 | renderer.Scene.sceneobject("Water").setPos(127.5f, waterHeight, 127.5f); | 282 | renderer.Scene.sceneobject("Water").setPos(m_scene.RegionInfo.RegionSizeX/2 - 0.5f, |
283 | waterHeight, | ||
284 | m_scene.RegionInfo.RegionSizeY/2 - 0.5f ); | ||
245 | 285 | ||
246 | renderer.AddMaterial("WaterColor", ConvertColor(WATER_COLOR)); | 286 | warp_Material waterColorMaterial = new warp_Material(ConvertColor(WATER_COLOR)); |
247 | renderer.Scene.material("WaterColor").setReflectivity(0); // match water color with standard map module thanks lkalif | 287 | waterColorMaterial.setReflectivity(0); // match water color with standard map module thanks lkalif |
248 | renderer.Scene.material("WaterColor").setTransparency((byte)((1f - WATER_COLOR.A) * 255f)); | 288 | waterColorMaterial.setTransparency((byte)((1f - WATER_COLOR.A) * 255f)); |
289 | renderer.Scene.addMaterial("WaterColor", waterColorMaterial); | ||
249 | renderer.SetObjectMaterial("Water", "WaterColor"); | 290 | renderer.SetObjectMaterial("Water", "WaterColor"); |
250 | } | 291 | } |
251 | 292 | ||
293 | // Add a terrain to the renderer. | ||
294 | // Note that we create a 'low resolution' 256x256 vertex terrain rather than trying for | ||
295 | // full resolution. This saves a lot of memory especially for very large regions. | ||
252 | private void CreateTerrain(WarpRenderer renderer, bool textureTerrain) | 296 | private void CreateTerrain(WarpRenderer renderer, bool textureTerrain) |
253 | { | 297 | { |
254 | ITerrainChannel terrain = m_scene.Heightmap; | 298 | ITerrainChannel terrain = m_scene.Heightmap; |
255 | float[] heightmap = terrain.GetFloatsSerialised(); | 299 | |
300 | // 'diff' is the difference in scale between the real region size and the size of terrain we're buiding | ||
301 | float diff = (float)m_scene.RegionInfo.RegionSizeX / 256f; | ||
256 | 302 | ||
257 | warp_Object obj = new warp_Object(256 * 256, 255 * 255 * 2); | 303 | warp_Object obj = new warp_Object(256 * 256, 255 * 255 * 2); |
258 | 304 | ||
259 | for (int y = 0; y < 256; y++) | 305 | // Create all the vertices for the terrain |
306 | for (float y = 0; y < m_scene.RegionInfo.RegionSizeY; y += diff) | ||
260 | { | 307 | { |
261 | for (int x = 0; x < 256; x++) | 308 | for (float x = 0; x < m_scene.RegionInfo.RegionSizeX; x += diff) |
262 | { | 309 | { |
263 | int v = y * 256 + x; | 310 | warp_Vector pos = ConvertVector(x, y, (float)terrain[(int)x, (int)y]); |
264 | float height = heightmap[v]; | 311 | obj.addVertex(new warp_Vertex(pos, |
265 | 312 | x / (float)m_scene.RegionInfo.RegionSizeX, | |
266 | warp_Vector pos = ConvertVector(new Vector3(x, y, height)); | 313 | (((float)m_scene.RegionInfo.RegionSizeY) - y) / m_scene.RegionInfo.RegionSizeY) ); |
267 | obj.addVertex(new warp_Vertex(pos, (float)x / 255f, (float)(255 - y) / 255f)); | ||
268 | } | 314 | } |
269 | } | 315 | } |
270 | 316 | ||
271 | for (int y = 0; y < 256; y++) | 317 | // Now that we have all the vertices, make another pass and create |
318 | // the normals for each of the surface triangles and | ||
319 | // create the list of triangle indices. | ||
320 | for (float y = 0; y < m_scene.RegionInfo.RegionSizeY; y += diff) | ||
272 | { | 321 | { |
273 | for (int x = 0; x < 256; x++) | 322 | for (float x = 0; x < m_scene.RegionInfo.RegionSizeX; x += diff) |
274 | { | 323 | { |
275 | if (x < 255 && y < 255) | 324 | float newX = x / diff; |
325 | float newY = y / diff; | ||
326 | if (newX < 255 && newY < 255) | ||
276 | { | 327 | { |
277 | int v = y * 256 + x; | 328 | int v = (int)newY * 256 + (int)newX; |
278 | 329 | ||
279 | // Normal | 330 | // Normal for a triangle made up of three adjacent vertices |
280 | Vector3 v1 = new Vector3(x, y, heightmap[y * 256 + x]); | 331 | Vector3 v1 = new Vector3(newX, newY, (float)terrain[(int)x, (int)y]); |
281 | Vector3 v2 = new Vector3(x + 1, y, heightmap[y * 256 + x + 1]); | 332 | Vector3 v2 = new Vector3(newX + 1, newY, (float)terrain[(int)(x + 1), (int)y]); |
282 | Vector3 v3 = new Vector3(x, y + 1, heightmap[(y + 1) * 256 + x]); | 333 | Vector3 v3 = new Vector3(newX, newY + 1, (float)terrain[(int)x, ((int)(y + 1))]); |
283 | warp_Vector norm = ConvertVector(SurfaceNormal(v1, v2, v3)); | 334 | warp_Vector norm = ConvertVector(SurfaceNormal(v1, v2, v3)); |
284 | norm = norm.reverse(); | 335 | norm = norm.reverse(); |
285 | obj.vertex(v).n = norm; | 336 | obj.vertex(v).n = norm; |
286 | 337 | ||
287 | // Triangle 1 | 338 | // Make two triangles for each of the squares in the grid of vertices |
288 | obj.addTriangle( | 339 | obj.addTriangle( |
289 | v, | 340 | v, |
290 | v + 1, | 341 | v + 1, |
291 | v + 256); | 342 | v + 256); |
292 | 343 | ||
293 | // Triangle 2 | ||
294 | obj.addTriangle( | 344 | obj.addTriangle( |
295 | v + 256 + 1, | 345 | v + 256 + 1, |
296 | v + 256, | 346 | v + 256, |
@@ -305,7 +355,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
305 | float[] startHeights = new float[4]; | 355 | float[] startHeights = new float[4]; |
306 | float[] heightRanges = new float[4]; | 356 | float[] heightRanges = new float[4]; |
307 | 357 | ||
308 | RegionSettings regionInfo = m_scene.RegionInfo.RegionSettings; | 358 | OpenSim.Framework.RegionSettings regionInfo = m_scene.RegionInfo.RegionSettings; |
309 | 359 | ||
310 | textureIDs[0] = regionInfo.TerrainTexture1; | 360 | textureIDs[0] = regionInfo.TerrainTexture1; |
311 | textureIDs[1] = regionInfo.TerrainTexture2; | 361 | textureIDs[1] = regionInfo.TerrainTexture2; |
@@ -323,14 +373,12 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
323 | heightRanges[3] = (float)regionInfo.Elevation2NE; | 373 | heightRanges[3] = (float)regionInfo.Elevation2NE; |
324 | 374 | ||
325 | uint globalX, globalY; | 375 | uint globalX, globalY; |
326 | Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out globalX, out globalY); | 376 | Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle, out globalX, out globalY); |
327 | 377 | ||
328 | warp_Texture texture; | 378 | warp_Texture texture; |
329 | |||
330 | using ( | 379 | using ( |
331 | Bitmap image | 380 | Bitmap image |
332 | = TerrainSplat.Splat( | 381 | = TerrainSplat.Splat(terrain, textureIDs, startHeights, heightRanges, |
333 | heightmap, textureIDs, startHeights, heightRanges, | ||
334 | new Vector3d(globalX, globalY, 0.0), m_scene.AssetService, textureTerrain)) | 382 | new Vector3d(globalX, globalY, 0.0), m_scene.AssetService, textureTerrain)) |
335 | { | 383 | { |
336 | texture = new warp_Texture(image); | 384 | texture = new warp_Texture(image); |
@@ -368,8 +416,48 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
368 | if (prim.Scale.LengthSquared() < MIN_SIZE * MIN_SIZE) | 416 | if (prim.Scale.LengthSquared() < MIN_SIZE * MIN_SIZE) |
369 | return; | 417 | return; |
370 | 418 | ||
419 | FacetedMesh renderMesh = null; | ||
371 | Primitive omvPrim = prim.Shape.ToOmvPrimitive(prim.OffsetPosition, prim.RotationOffset); | 420 | Primitive omvPrim = prim.Shape.ToOmvPrimitive(prim.OffsetPosition, prim.RotationOffset); |
372 | FacetedMesh renderMesh = m_primMesher.GenerateFacetedMesh(omvPrim, DetailLevel.Medium); | 421 | |
422 | if (m_renderMeshes) | ||
423 | { | ||
424 | if (omvPrim.Sculpt != null && omvPrim.Sculpt.SculptTexture != UUID.Zero) | ||
425 | { | ||
426 | // Try fetchinng the asset | ||
427 | byte[] sculptAsset = m_scene.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); | ||
428 | if (sculptAsset != null) | ||
429 | { | ||
430 | // Is it a mesh? | ||
431 | if (omvPrim.Sculpt.Type == SculptType.Mesh) | ||
432 | { | ||
433 | AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); | ||
434 | FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out renderMesh); | ||
435 | meshAsset = null; | ||
436 | } | ||
437 | else // It's sculptie | ||
438 | { | ||
439 | IJ2KDecoder imgDecoder = m_scene.RequestModuleInterface<IJ2KDecoder>(); | ||
440 | if (imgDecoder != null) | ||
441 | { | ||
442 | Image sculpt = imgDecoder.DecodeToImage(sculptAsset); | ||
443 | if (sculpt != null) | ||
444 | { | ||
445 | renderMesh = m_primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt, | ||
446 | DetailLevel.Medium); | ||
447 | sculpt.Dispose(); | ||
448 | } | ||
449 | } | ||
450 | } | ||
451 | } | ||
452 | } | ||
453 | } | ||
454 | |||
455 | // If not a mesh or sculptie, try the regular mesher | ||
456 | if (renderMesh == null) | ||
457 | { | ||
458 | renderMesh = m_primMesher.GenerateFacetedMesh(omvPrim, DetailLevel.Medium); | ||
459 | } | ||
460 | |||
373 | if (renderMesh == null) | 461 | if (renderMesh == null) |
374 | return; | 462 | return; |
375 | 463 | ||
@@ -428,7 +516,11 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
428 | 516 | ||
429 | Primitive.TextureEntryFace teFace = prim.Shape.Textures.GetFace((uint)i); | 517 | Primitive.TextureEntryFace teFace = prim.Shape.Textures.GetFace((uint)i); |
430 | Color4 faceColor = GetFaceColor(teFace); | 518 | Color4 faceColor = GetFaceColor(teFace); |
431 | string materialName = GetOrCreateMaterial(renderer, faceColor); | 519 | string materialName = String.Empty; |
520 | if (m_texturePrims && prim.Scale.LengthSquared() > m_texturePrimSize*m_texturePrimSize) | ||
521 | materialName = GetOrCreateMaterial(renderer, faceColor, teFace.TextureID); | ||
522 | else | ||
523 | materialName = GetOrCreateMaterial(renderer, faceColor); | ||
432 | 524 | ||
433 | faceObj.transform(m); | 525 | faceObj.transform(m); |
434 | faceObj.setPos(primPos); | 526 | faceObj.setPos(primPos); |
@@ -517,10 +609,51 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap | |||
517 | return name; | 609 | return name; |
518 | } | 610 | } |
519 | 611 | ||
612 | public string GetOrCreateMaterial(WarpRenderer renderer, Color4 faceColor, UUID textureID) | ||
613 | { | ||
614 | string materialName = "Color-" + faceColor.ToString() + "-Texture-" + textureID.ToString(); | ||
615 | |||
616 | if (renderer.Scene.material(materialName) == null) | ||
617 | { | ||
618 | renderer.AddMaterial(materialName, ConvertColor(faceColor)); | ||
619 | if (faceColor.A < 1f) | ||
620 | { | ||
621 | renderer.Scene.material(materialName).setTransparency((byte) ((1f - faceColor.A)*255f)); | ||
622 | } | ||
623 | warp_Texture texture = GetTexture(textureID); | ||
624 | if (texture != null) | ||
625 | renderer.Scene.material(materialName).setTexture(texture); | ||
626 | } | ||
627 | |||
628 | return materialName; | ||
629 | } | ||
630 | |||
631 | private warp_Texture GetTexture(UUID id) | ||
632 | { | ||
633 | warp_Texture ret = null; | ||
634 | byte[] asset = m_scene.AssetService.GetData(id.ToString()); | ||
635 | if (asset != null) | ||
636 | { | ||
637 | IJ2KDecoder imgDecoder = m_scene.RequestModuleInterface<IJ2KDecoder>(); | ||
638 | Bitmap img = (Bitmap) imgDecoder.DecodeToImage(asset); | ||
639 | if (img != null) | ||
640 | { | ||
641 | return new warp_Texture(img); | ||
642 | } | ||
643 | } | ||
644 | return ret; | ||
645 | } | ||
646 | |||
520 | #endregion Rendering Methods | 647 | #endregion Rendering Methods |
521 | 648 | ||
522 | #region Static Helpers | 649 | #region Static Helpers |
523 | 650 | ||
651 | // Note: axis change. | ||
652 | private static warp_Vector ConvertVector(float x, float y, float z) | ||
653 | { | ||
654 | return new warp_Vector(x, z, y); | ||
655 | } | ||
656 | |||
524 | private static warp_Vector ConvertVector(Vector3 vector) | 657 | private static warp_Vector ConvertVector(Vector3 vector) |
525 | { | 658 | { |
526 | return new warp_Vector(vector.X, vector.Z, vector.Y); | 659 | return new warp_Vector(vector.X, vector.Z, vector.Y); |
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs index 708a9a2..1fb1aba 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs | |||
@@ -184,8 +184,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
184 | data.Name = info.RegionName; | 184 | data.Name = info.RegionName; |
185 | data.RegionFlags = 0; // TODO not used? | 185 | data.RegionFlags = 0; // TODO not used? |
186 | data.WaterHeight = 0; // not used | 186 | data.WaterHeight = 0; // not used |
187 | data.X = (ushort)(info.RegionLocX / Constants.RegionSize); | 187 | data.X = (ushort)Util.WorldToRegionLoc((uint)info.RegionLocX); |
188 | data.Y = (ushort)(info.RegionLocY / Constants.RegionSize); | 188 | data.Y = (ushort)Util.WorldToRegionLoc((uint)info.RegionLocY); |
189 | blocks.Add(data); | 189 | blocks.Add(data); |
190 | } | 190 | } |
191 | } | 191 | } |
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index cdf1467..e925f0d 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs | |||
@@ -277,11 +277,12 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
277 | { | 277 | { |
278 | List<MapBlockData> mapBlocks = new List<MapBlockData>(); ; | 278 | List<MapBlockData> mapBlocks = new List<MapBlockData>(); ; |
279 | 279 | ||
280 | // Get regions that are within 8 regions of here | ||
280 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, | 281 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, |
281 | (int)(m_scene.RegionInfo.RegionLocX - 8) * (int)Constants.RegionSize, | 282 | (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX - 8), |
282 | (int)(m_scene.RegionInfo.RegionLocX + 8) * (int)Constants.RegionSize, | 283 | (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX + 8), |
283 | (int)(m_scene.RegionInfo.RegionLocY - 8) * (int)Constants.RegionSize, | 284 | (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY - 8), |
284 | (int)(m_scene.RegionInfo.RegionLocY + 8) * (int)Constants.RegionSize); | 285 | (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY + 8) ); |
285 | foreach (GridRegion r in regions) | 286 | foreach (GridRegion r in regions) |
286 | { | 287 | { |
287 | MapBlockData block = new MapBlockData(); | 288 | MapBlockData block = new MapBlockData(); |
@@ -405,7 +406,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
405 | } | 406 | } |
406 | uint xstart = 0; | 407 | uint xstart = 0; |
407 | uint ystart = 0; | 408 | uint ystart = 0; |
408 | Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out xstart, out ystart); | 409 | Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle, out xstart, out ystart); |
409 | if (itemtype == 6) // Service 6 right now (MAP_ITEM_AGENTS_LOCATION; green dots) | 410 | if (itemtype == 6) // Service 6 right now (MAP_ITEM_AGENTS_LOCATION; green dots) |
410 | { | 411 | { |
411 | if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) | 412 | if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle) |
@@ -803,7 +804,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
803 | if (httpserver.Length == 0) | 804 | if (httpserver.Length == 0) |
804 | { | 805 | { |
805 | uint x = 0, y = 0; | 806 | uint x = 0, y = 0; |
806 | Utils.LongToUInts(regionhandle, out x, out y); | 807 | Util.RegionHandleToWorldLoc(regionhandle, out x, out y); |
807 | GridRegion mreg = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); | 808 | GridRegion mreg = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); |
808 | 809 | ||
809 | if (mreg != null) | 810 | if (mreg != null) |
@@ -1011,17 +1012,15 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
1011 | // on an unloaded square. | 1012 | // on an unloaded square. |
1012 | // But make sure: Look whether the one we requested is in there | 1013 | // But make sure: Look whether the one we requested is in there |
1013 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, | 1014 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, |
1014 | minX * (int)Constants.RegionSize, | 1015 | (int)Util.RegionToWorldLoc((uint)minX), (int)Util.RegionToWorldLoc((uint)maxX), |
1015 | maxX * (int)Constants.RegionSize, | 1016 | (int)Util.RegionToWorldLoc((uint)minY), (int)Util.RegionToWorldLoc((uint)maxY) ); |
1016 | minY * (int)Constants.RegionSize, | ||
1017 | maxY * (int)Constants.RegionSize); | ||
1018 | 1017 | ||
1019 | if (regions != null) | 1018 | if (regions != null) |
1020 | { | 1019 | { |
1021 | foreach (GridRegion r in regions) | 1020 | foreach (GridRegion r in regions) |
1022 | { | 1021 | { |
1023 | if ((r.RegionLocX == minX * (int)Constants.RegionSize) && | 1022 | if (r.RegionLocX == Util.RegionToWorldLoc((uint)minX) |
1024 | (r.RegionLocY == minY * (int)Constants.RegionSize)) | 1023 | && r.RegionLocY == Util.RegionToWorldLoc((uint)minY) ) |
1025 | { | 1024 | { |
1026 | // found it => add it to response | 1025 | // found it => add it to response |
1027 | MapBlockData block = new MapBlockData(); | 1026 | MapBlockData block = new MapBlockData(); |
@@ -1055,10 +1054,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
1055 | { | 1054 | { |
1056 | List<MapBlockData> mapBlocks = new List<MapBlockData>(); | 1055 | List<MapBlockData> mapBlocks = new List<MapBlockData>(); |
1057 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, | 1056 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, |
1058 | (minX - 4) * (int)Constants.RegionSize, | 1057 | (int)Util.RegionToWorldLoc((uint)(minX - 4)), (int)Util.RegionToWorldLoc((uint)(maxX + 4)), |
1059 | (maxX + 4) * (int)Constants.RegionSize, | 1058 | (int)Util.RegionToWorldLoc((uint)(minY - 4)), (int)Util.RegionToWorldLoc((uint)(maxY + 4)) ); |
1060 | (minY - 4) * (int)Constants.RegionSize, | ||
1061 | (maxY + 4) * (int)Constants.RegionSize); | ||
1062 | foreach (GridRegion r in regions) | 1059 | foreach (GridRegion r in regions) |
1063 | { | 1060 | { |
1064 | MapBlockData block = new MapBlockData(); | 1061 | MapBlockData block = new MapBlockData(); |
@@ -1086,8 +1083,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
1086 | break; | 1083 | break; |
1087 | } | 1084 | } |
1088 | block.Name = r.RegionName; | 1085 | block.Name = r.RegionName; |
1089 | block.X = (ushort)(r.RegionLocX / Constants.RegionSize); | 1086 | block.X = (ushort)Util.WorldToRegionLoc((uint)r.RegionLocX); |
1090 | block.Y = (ushort)(r.RegionLocY / Constants.RegionSize); | 1087 | block.Y = (ushort)Util.WorldToRegionLoc((uint)r.RegionLocY); |
1091 | } | 1088 | } |
1092 | 1089 | ||
1093 | public Hashtable OnHTTPThrottled(Hashtable keysvals) | 1090 | public Hashtable OnHTTPThrottled(Hashtable keysvals) |
@@ -1218,10 +1215,10 @@ namespace OpenSim.Region.CoreModules.World.WorldMap | |||
1218 | 1215 | ||
1219 | List<MapBlockData> mapBlocks = new List<MapBlockData>(); | 1216 | List<MapBlockData> mapBlocks = new List<MapBlockData>(); |
1220 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, | 1217 | List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID, |
1221 | (int)(m_scene.RegionInfo.RegionLocX - 9) * (int)Constants.RegionSize, | 1218 | (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX - 9), |
1222 | (int)(m_scene.RegionInfo.RegionLocX + 9) * (int)Constants.RegionSize, | 1219 | (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX + 9), |
1223 | (int)(m_scene.RegionInfo.RegionLocY - 9) * (int)Constants.RegionSize, | 1220 | (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY - 9), |
1224 | (int)(m_scene.RegionInfo.RegionLocY + 9) * (int)Constants.RegionSize); | 1221 | (int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY + 9)); |
1225 | List<AssetBase> textures = new List<AssetBase>(); | 1222 | List<AssetBase> textures = new List<AssetBase>(); |
1226 | List<Image> bitImages = new List<Image>(); | 1223 | List<Image> bitImages = new List<Image>(); |
1227 | 1224 | ||