diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs | 100 |
1 files changed, 95 insertions, 5 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index 2e9db39..e8040d8 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs | |||
@@ -337,6 +337,54 @@ public sealed class BSTerrainManager : IDisposable | |||
337 | return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ); | 337 | return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ); |
338 | } | 338 | } |
339 | 339 | ||
340 | // Return a new position that is over known terrain if the position is outside our terrain. | ||
341 | public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos) | ||
342 | { | ||
343 | Vector3 ret = pPos; | ||
344 | |||
345 | // Can't do this function if we don't know about any terrain. | ||
346 | if (m_terrains.Count == 0) | ||
347 | return ret; | ||
348 | |||
349 | int loopPrevention = 5; | ||
350 | Vector3 terrainBaseXYZ; | ||
351 | BSTerrainPhys physTerrain; | ||
352 | while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ)) | ||
353 | { | ||
354 | // The passed position is not within a known terrain area. | ||
355 | |||
356 | // First, base addresses are never negative so correct for that possible problem. | ||
357 | if (ret.X < 0f || ret.Y < 0f) | ||
358 | { | ||
359 | if (ret.X < 0f) | ||
360 | ret.X = 0f; | ||
361 | if (ret.Y < 0f) | ||
362 | ret.Y = 0f; | ||
363 | DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}", | ||
364 | BSScene.DetailLogZero, pPos, ret); | ||
365 | } | ||
366 | else | ||
367 | { | ||
368 | // Must be off the top of a region. Find an adjacent region to move into. | ||
369 | Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ); | ||
370 | |||
371 | ret.X = Math.Min(ret.X, adjacentTerrainBase.X + DefaultRegionSize.X); | ||
372 | ret.Y = Math.Min(ret.Y, adjacentTerrainBase.Y + DefaultRegionSize.Y); | ||
373 | DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}", | ||
374 | BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret); | ||
375 | } | ||
376 | if (loopPrevention-- < 0f) | ||
377 | { | ||
378 | // The 'while' is a little dangerous so this prevents looping forever if the | ||
379 | // mapping of the terrains ever gets messed up (like nothing at <0,0>) or | ||
380 | // the list of terrains is in transition. | ||
381 | DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero); | ||
382 | break; | ||
383 | } | ||
384 | } | ||
385 | return ret; | ||
386 | } | ||
387 | |||
340 | // Given an X and Y, find the height of the terrain. | 388 | // Given an X and Y, find the height of the terrain. |
341 | // Since we could be handling multiple terrains for a mega-region, | 389 | // Since we could be handling multiple terrains for a mega-region, |
342 | // the base of the region is calcuated assuming all regions are | 390 | // the base of the region is calcuated assuming all regions are |
@@ -400,18 +448,60 @@ public sealed class BSTerrainManager : IDisposable | |||
400 | // the descriptor class and the 'base' fo the addresses therein. | 448 | // the descriptor class and the 'base' fo the addresses therein. |
401 | private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase) | 449 | private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase) |
402 | { | 450 | { |
403 | int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; | 451 | bool ret = false; |
404 | int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; | 452 | |
405 | Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); | 453 | Vector3 terrainBaseXYZ = Vector3.Zero; |
454 | if (pos.X < 0f || pos.Y < 0f) | ||
455 | { | ||
456 | // We don't handle negative addresses so just make up a base that will not be found. | ||
457 | terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f); | ||
458 | } | ||
459 | else | ||
460 | { | ||
461 | int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; | ||
462 | int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; | ||
463 | terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); | ||
464 | } | ||
406 | 465 | ||
407 | BSTerrainPhys physTerrain = null; | 466 | BSTerrainPhys physTerrain = null; |
408 | lock (m_terrains) | 467 | lock (m_terrains) |
409 | { | 468 | { |
410 | m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); | 469 | ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); |
411 | } | 470 | } |
412 | outTerrainBase = terrainBaseXYZ; | 471 | outTerrainBase = terrainBaseXYZ; |
413 | outPhysTerrain = physTerrain; | 472 | outPhysTerrain = physTerrain; |
414 | return (physTerrain != null); | 473 | return ret; |
474 | } | ||
475 | |||
476 | // Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than | ||
477 | // this one. Usually used to return an out of bounds object to a known place. | ||
478 | private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase) | ||
479 | { | ||
480 | Vector3 ret = pTerrainBase; | ||
481 | ret.Z = 0f; | ||
482 | lock (m_terrains) | ||
483 | { | ||
484 | // Once down to the <0,0> region, we have to be done. | ||
485 | while (ret.X > 0f && ret.Y > 0f) | ||
486 | { | ||
487 | if (ret.X > 0f) | ||
488 | { | ||
489 | ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X); | ||
490 | DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret); | ||
491 | if (m_terrains.ContainsKey(ret)) | ||
492 | break; | ||
493 | } | ||
494 | if (ret.Y > 0f) | ||
495 | { | ||
496 | ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y); | ||
497 | DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret); | ||
498 | if (m_terrains.ContainsKey(ret)) | ||
499 | break; | ||
500 | } | ||
501 | } | ||
502 | } | ||
503 | |||
504 | return ret; | ||
415 | } | 505 | } |
416 | 506 | ||
417 | // Although no one seems to check this, I do support combining. | 507 | // Although no one seems to check this, I do support combining. |