aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs)244
1 files changed, 185 insertions, 59 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs
index 2e9db39..d11baa6 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.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 *
@@ -30,15 +30,14 @@ using System.Text;
30 30
31using OpenSim.Framework; 31using OpenSim.Framework;
32using OpenSim.Region.Framework; 32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules; 33using OpenSim.Region.PhysicsModules.SharedBase;
34using OpenSim.Region.Physics.Manager;
35 34
36using Nini.Config; 35using Nini.Config;
37using log4net; 36using log4net;
38 37
39using OpenMetaverse; 38using OpenMetaverse;
40 39
41namespace OpenSim.Region.Physics.BulletSPlugin 40namespace OpenSim.Region.PhysicsModule.BulletS
42{ 41{
43 42
44// The physical implementation of the terrain is wrapped in this class. 43// The physical implementation of the terrain is wrapped in this class.
@@ -50,14 +49,14 @@ public abstract class BSTerrainPhys : IDisposable
50 Mesh = 1 49 Mesh = 1
51 } 50 }
52 51
53 public BSScene PhysicsScene { get; private set; } 52 protected BSScene m_physicsScene { get; private set; }
54 // Base of the region in world coordinates. Coordinates inside the region are relative to this. 53 // Base of the region in world coordinates. Coordinates inside the region are relative to this.
55 public Vector3 TerrainBase { get; private set; } 54 public Vector3 TerrainBase { get; private set; }
56 public uint ID { get; private set; } 55 public uint ID { get; private set; }
57 56
58 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id) 57 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id)
59 { 58 {
60 PhysicsScene = physicsScene; 59 m_physicsScene = physicsScene;
61 TerrainBase = regionBase; 60 TerrainBase = regionBase;
62 ID = id; 61 ID = id;
63 } 62 }
@@ -86,7 +85,7 @@ public sealed class BSTerrainManager : IDisposable
86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); 85 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
87 86
88 // The scene that I am part of 87 // The scene that I am part of
89 private BSScene PhysicsScene { get; set; } 88 private BSScene m_physicsScene { get; set; }
90 89
91 // The ground plane created to keep thing from falling to infinity. 90 // The ground plane created to keep thing from falling to infinity.
92 private BulletBody m_groundPlane; 91 private BulletBody m_groundPlane;
@@ -111,9 +110,11 @@ public sealed class BSTerrainManager : IDisposable
111 private Vector3 m_worldMax; 110 private Vector3 m_worldMax;
112 private PhysicsScene MegaRegionParentPhysicsScene { get; set; } 111 private PhysicsScene MegaRegionParentPhysicsScene { get; set; }
113 112
114 public BSTerrainManager(BSScene physicsScene) 113 public BSTerrainManager(BSScene physicsScene, Vector3 regionSize)
115 { 114 {
116 PhysicsScene = physicsScene; 115 m_physicsScene = physicsScene;
116 DefaultRegionSize = regionSize;
117
117 m_terrains = new Dictionary<Vector3,BSTerrainPhys>(); 118 m_terrains = new Dictionary<Vector3,BSTerrainPhys>();
118 119
119 // Assume one region of default size 120 // Assume one region of default size
@@ -132,32 +133,39 @@ public sealed class BSTerrainManager : IDisposable
132 // safe to call Bullet in real time. We hope no one is moving prims around yet. 133 // safe to call Bullet in real time. We hope no one is moving prims around yet.
133 public void CreateInitialGroundPlaneAndTerrain() 134 public void CreateInitialGroundPlaneAndTerrain()
134 { 135 {
136 DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
135 // The ground plane is here to catch things that are trying to drop to negative infinity 137 // The ground plane is here to catch things that are trying to drop to negative infinity
136 BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); 138 BulletShape groundPlaneShape = m_physicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
137 m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, 139 Vector3 groundPlaneAltitude = new Vector3(0f, 0f, BSParam.TerrainGroundPlane);
138 BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity); 140 m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
141 BSScene.GROUNDPLANE_ID, groundPlaneAltitude, Quaternion.Identity);
139 142
140 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_groundPlane);
141 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_groundPlane);
142 // Ground plane does not move
143 PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
144 // Everything collides with the ground plane. 143 // Everything collides with the ground plane.
145 m_groundPlane.collisionType = CollisionType.Groundplane; 144 m_groundPlane.collisionType = CollisionType.Groundplane;
146 m_groundPlane.ApplyCollisionMask(PhysicsScene);
147 145
148 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. 146 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane);
149 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); 147 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane);
150 m_terrains.Add(Vector3.Zero, initialTerrain); 148
149 // Ground plane does not move
150 m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
151
152 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(m_physicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
153 lock (m_terrains)
154 {
155 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
156 m_terrains.Add(Vector3.Zero, initialTerrain);
157 }
151 } 158 }
152 159
153 // Release all the terrain structures we might have allocated 160 // Release all the terrain structures we might have allocated
154 public void ReleaseGroundPlaneAndTerrain() 161 public void ReleaseGroundPlaneAndTerrain()
155 { 162 {
163 DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
156 if (m_groundPlane.HasPhysicalBody) 164 if (m_groundPlane.HasPhysicalBody)
157 { 165 {
158 if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane)) 166 if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane))
159 { 167 {
160 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane); 168 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane);
161 } 169 }
162 m_groundPlane.Clear(); 170 m_groundPlane.Clear();
163 } 171 }
@@ -183,7 +191,7 @@ public sealed class BSTerrainManager : IDisposable
183 float[] localHeightMap = heightMap; 191 float[] localHeightMap = heightMap;
184 // If there are multiple requests for changes to the same terrain between ticks, 192 // If there are multiple requests for changes to the same terrain between ticks,
185 // only do that last one. 193 // only do that last one.
186 PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() 194 m_physicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
187 { 195 {
188 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) 196 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
189 { 197 {
@@ -193,11 +201,9 @@ public sealed class BSTerrainManager : IDisposable
193 // the terrain is added to our parent 201 // the terrain is added to our parent
194 if (MegaRegionParentPhysicsScene is BSScene) 202 if (MegaRegionParentPhysicsScene is BSScene)
195 { 203 {
196 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", 204 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax);
197 BSScene.DetailLogZero, m_worldOffset, m_worldMax); 205 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.AddMegaRegionChildTerrain(
198 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain( 206 BSScene.CHILDTERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
199 BSScene.CHILDTERRAIN_ID, localHeightMap,
200 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
201 } 207 }
202 } 208 }
203 else 209 else
@@ -205,27 +211,34 @@ public sealed class BSTerrainManager : IDisposable
205 // If not doing the mega-prim thing, just change the terrain 211 // If not doing the mega-prim thing, just change the terrain
206 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); 212 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
207 213
208 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, 214 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
209 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
210 } 215 }
211 }); 216 });
212 } 217 }
213 218
214 // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain 219 // Another region is calling this region and passing a terrain.
220 // A region that is not the mega-region root will pass its terrain to the root region so the root region
221 // physics engine will have all the terrains.
222 private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
223 {
224 // Since we are called by another region's thread, the action must be rescheduled onto our processing thread.
225 m_physicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate()
226 {
227 UpdateTerrain(id, heightMap, minCoords, maxCoords);
228 });
229 }
230
231 // If called for terrain has has not been previously allocated, a new terrain will be built
215 // based on the passed information. The 'id' should be either the terrain id or 232 // based on the passed information. The 'id' should be either the terrain id or
216 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. 233 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
217 // The latter feature is for creating child terrains for mega-regions. 234 // The latter feature is for creating child terrains for mega-regions.
218 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new 235 // If there is an existing terrain body, a new
219 // terrain shape is created and added to the body. 236 // terrain shape is created and added to the body.
220 // This call is most often used to update the heightMap and parameters of the terrain. 237 // This call is most often used to update the heightMap and parameters of the terrain.
221 // (The above does suggest that some simplification/refactoring is in order.) 238 // (The above does suggest that some simplification/refactoring is in order.)
222 // Called during taint-time. 239 // Called during taint-time.
223 private void UpdateTerrain(uint id, float[] heightMap, 240 private void UpdateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
224 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
225 { 241 {
226 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
227 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime);
228
229 // Find high and low points of passed heightmap. 242 // Find high and low points of passed heightmap.
230 // The min and max passed in is usually the area objects can be in (maximum 243 // The min and max passed in is usually the area objects can be in (maximum
231 // object height, for instance). The terrain wants the bounding box for the 244 // object height, for instance). The terrain wants the bounding box for the
@@ -245,6 +258,9 @@ public sealed class BSTerrainManager : IDisposable
245 minCoords.Z = minZ; 258 minCoords.Z = minZ;
246 maxCoords.Z = maxZ; 259 maxCoords.Z = maxZ;
247 260
261 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3}",
262 BSScene.DetailLogZero, id, minCoords, maxCoords);
263
248 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); 264 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
249 265
250 lock (m_terrains) 266 lock (m_terrains)
@@ -253,8 +269,8 @@ public sealed class BSTerrainManager : IDisposable
253 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) 269 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
254 { 270 {
255 // There is already a terrain in this spot. Free the old and build the new. 271 // There is already a terrain in this spot. Free the old and build the new.
256 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", 272 DetailLog("{0},BSTerrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
257 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); 273 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, maxCoords);
258 274
259 // Remove old terrain from the collection 275 // Remove old terrain from the collection
260 m_terrains.Remove(terrainRegionBase); 276 m_terrains.Remove(terrainRegionBase);
@@ -263,6 +279,7 @@ public sealed class BSTerrainManager : IDisposable
263 279
264 if (MegaRegionParentPhysicsScene == null) 280 if (MegaRegionParentPhysicsScene == null)
265 { 281 {
282 // This terrain is not part of the mega-region scheme. Create vanilla terrain.
266 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); 283 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
267 m_terrains.Add(terrainRegionBase, newTerrainPhys); 284 m_terrains.Add(terrainRegionBase, newTerrainPhys);
268 285
@@ -291,8 +308,8 @@ public sealed class BSTerrainManager : IDisposable
291 if (newTerrainID >= BSScene.CHILDTERRAIN_ID) 308 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
292 newTerrainID = ++m_terrainCount; 309 newTerrainID = ++m_terrainCount;
293 310
294 DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", 311 DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
295 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); 312 BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords);
296 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); 313 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
297 m_terrains.Add(terrainRegionBase, newTerrainPhys); 314 m_terrains.Add(terrainRegionBase, newTerrainPhys);
298 315
@@ -304,26 +321,26 @@ public sealed class BSTerrainManager : IDisposable
304 // TODO: redo terrain implementation selection to allow other base types than heightMap. 321 // TODO: redo terrain implementation selection to allow other base types than heightMap.
305 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) 322 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
306 { 323 {
307 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", 324 m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
308 LogHeader, PhysicsScene.RegionName, terrainRegionBase, 325 LogHeader, m_physicsScene.RegionName, terrainRegionBase,
309 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); 326 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
310 BSTerrainPhys newTerrainPhys = null; 327 BSTerrainPhys newTerrainPhys = null;
311 switch ((int)BSParam.TerrainImplementation) 328 switch ((int)BSParam.TerrainImplementation)
312 { 329 {
313 case (int)BSTerrainPhys.TerrainImplementation.Heightmap: 330 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
314 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, 331 newTerrainPhys = new BSTerrainHeightmap(m_physicsScene, terrainRegionBase, id,
315 heightMap, minCoords, maxCoords); 332 heightMap, minCoords, maxCoords);
316 break; 333 break;
317 case (int)BSTerrainPhys.TerrainImplementation.Mesh: 334 case (int)BSTerrainPhys.TerrainImplementation.Mesh:
318 newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id, 335 newTerrainPhys = new BSTerrainMesh(m_physicsScene, terrainRegionBase, id,
319 heightMap, minCoords, maxCoords); 336 heightMap, minCoords, maxCoords);
320 break; 337 break;
321 default: 338 default:
322 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", 339 m_physicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
323 LogHeader, 340 LogHeader,
324 (int)BSParam.TerrainImplementation, 341 (int)BSParam.TerrainImplementation,
325 BSParam.TerrainImplementation, 342 BSParam.TerrainImplementation,
326 PhysicsScene.RegionName, terrainRegionBase); 343 m_physicsScene.RegionName, terrainRegionBase);
327 break; 344 break;
328 } 345 }
329 return newTerrainPhys; 346 return newTerrainPhys;
@@ -337,6 +354,64 @@ public sealed class BSTerrainManager : IDisposable
337 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ); 354 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
338 } 355 }
339 356
357 // Return a new position that is over known terrain if the position is outside our terrain.
358 public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos)
359 {
360 float edgeEpsilon = 0.1f;
361
362 Vector3 ret = pPos;
363
364 // First, base addresses are never negative so correct for that possible problem.
365 if (ret.X < 0f || ret.Y < 0f)
366 {
367 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
368 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
369 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}",
370 BSScene.DetailLogZero, pPos, ret);
371 }
372
373 // Can't do this function if we don't know about any terrain.
374 if (m_terrains.Count == 0)
375 return ret;
376
377 int loopPrevention = 10;
378 Vector3 terrainBaseXYZ;
379 BSTerrainPhys physTerrain;
380 while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ))
381 {
382 // The passed position is not within a known terrain area.
383 // NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region.
384
385 // Must be off the top of a region. Find an adjacent region to move into.
386 // The returned terrain is always 'lower'. That is, closer to <0,0>.
387 Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ);
388
389 if (adjacentTerrainBase.X < terrainBaseXYZ.X)
390 {
391 // moving down into a new region in the X dimension. New position will be the max in the new base.
392 ret.X = adjacentTerrainBase.X + DefaultRegionSize.X - edgeEpsilon;
393 }
394 if (adjacentTerrainBase.Y < terrainBaseXYZ.Y)
395 {
396 // moving down into a new region in the X dimension. New position will be the max in the new base.
397 ret.Y = adjacentTerrainBase.Y + DefaultRegionSize.Y - edgeEpsilon;
398 }
399 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}",
400 BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret);
401
402 if (loopPrevention-- < 0f)
403 {
404 // The 'while' is a little dangerous so this prevents looping forever if the
405 // mapping of the terrains ever gets messed up (like nothing at <0,0>) or
406 // the list of terrains is in transition.
407 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero);
408 break;
409 }
410 }
411
412 return ret;
413 }
414
340 // Given an X and Y, find the height of the terrain. 415 // Given an X and Y, find the height of the terrain.
341 // Since we could be handling multiple terrains for a mega-region, 416 // Since we could be handling multiple terrains for a mega-region,
342 // the base of the region is calcuated assuming all regions are 417 // the base of the region is calcuated assuming all regions are
@@ -368,8 +443,8 @@ public sealed class BSTerrainManager : IDisposable
368 } 443 }
369 else 444 else
370 { 445 {
371 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", 446 m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
372 LogHeader, PhysicsScene.RegionName, tX, tY); 447 LogHeader, m_physicsScene.RegionName, tX, tY);
373 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", 448 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
374 BSScene.DetailLogZero, pos, terrainBaseXYZ); 449 BSScene.DetailLogZero, pos, terrainBaseXYZ);
375 } 450 }
@@ -390,8 +465,8 @@ public sealed class BSTerrainManager : IDisposable
390 } 465 }
391 else 466 else
392 { 467 {
393 PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", 468 m_physicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
394 LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret); 469 LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret);
395 } 470 }
396 return ret; 471 return ret;
397 } 472 }
@@ -400,18 +475,69 @@ public sealed class BSTerrainManager : IDisposable
400 // the descriptor class and the 'base' fo the addresses therein. 475 // the descriptor class and the 'base' fo the addresses therein.
401 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase) 476 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
402 { 477 {
403 int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; 478 bool ret = false;
404 int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; 479
405 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); 480 Vector3 terrainBaseXYZ = Vector3.Zero;
481 if (pos.X < 0f || pos.Y < 0f)
482 {
483 // We don't handle negative addresses so just make up a base that will not be found.
484 terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f);
485 }
486 else
487 {
488 int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
489 int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
490 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
491 }
406 492
407 BSTerrainPhys physTerrain = null; 493 BSTerrainPhys physTerrain = null;
408 lock (m_terrains) 494 lock (m_terrains)
409 { 495 {
410 m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); 496 ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
411 } 497 }
412 outTerrainBase = terrainBaseXYZ; 498 outTerrainBase = terrainBaseXYZ;
413 outPhysTerrain = physTerrain; 499 outPhysTerrain = physTerrain;
414 return (physTerrain != null); 500 return ret;
501 }
502
503 // Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than
504 // this one. Usually used to return an out of bounds object to a known place.
505 private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase)
506 {
507 Vector3 ret = pTerrainBase;
508
509 // Can't do this function if we don't know about any terrain.
510 if (m_terrains.Count == 0)
511 return ret;
512
513 // Just some sanity
514 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
515 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
516 ret.Z = 0f;
517
518 lock (m_terrains)
519 {
520 // Once down to the <0,0> region, we have to be done.
521 while (ret.X > 0f || ret.Y > 0f)
522 {
523 if (ret.X > 0f)
524 {
525 ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X);
526 DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret);
527 if (m_terrains.ContainsKey(ret))
528 break;
529 }
530 if (ret.Y > 0f)
531 {
532 ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y);
533 DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret);
534 if (m_terrains.ContainsKey(ret))
535 break;
536 }
537 }
538 }
539
540 return ret;
415 } 541 }
416 542
417 // Although no one seems to check this, I do support combining. 543 // Although no one seems to check this, I do support combining.
@@ -452,7 +578,7 @@ public sealed class BSTerrainManager : IDisposable
452 578
453 private void DetailLog(string msg, params Object[] args) 579 private void DetailLog(string msg, params Object[] args)
454 { 580 {
455 PhysicsScene.PhysicsLogging.Write(msg, args); 581 m_physicsScene.PhysicsLogging.Write(msg, args);
456 } 582 }
457} 583}
458} 584}