7 class SCR_ObstacleDetector
9 protected bool m_bAvoidObjects;
10 protected float m_fAvoidObjectsDetectionRadius;
11 protected float m_fAvoidObjectsDetectionHeight;
12 protected bool m_bAvoidRoads;
13 protected bool m_bAvoidRivers;
14 protected bool m_bAvoidPowerLines;
15 protected bool m_bAvoidTracks;
16 protected bool m_bAvoidForests;
17 protected bool m_bAvoidLakes;
18 protected bool m_bAvoidLand;
19 protected bool m_bAvoidOcean;
20 protected float m_fAvoidLandOceanOffset;
21 protected ref array<ref SCR_ObstacleDetectorSplineInfo> m_aAvoidInfoRoads;
22 protected ref array<ref SCR_ObstacleDetectorSplineInfo> m_aAvoidInfoRivers;
23 protected ref array<ref SCR_ObstacleDetectorSplineInfo> m_aAvoidInfoPowerLines;
24 protected ref array<ref SCR_ObstacleDetectorSplineInfo> m_aAvoidInfoTracks;
25 protected ref array<ref SCR_ObstacleDetectorSplineInfo> m_aAvoidInfoLakes;
26 protected ref array<ref SCR_ObstacleDetectorSplineInfo> m_aAvoidInfoForests;
28 protected float m_fOceanLevel;
29 protected ref TraceSphere m_AvoidObjectTraceSphere;
31 protected WorldEditorAPI m_WorldEditorAPI;
38 return m_WorldEditorAPI !=
null;
42 void SetAvoidObjects(
bool avoidObjects)
44 m_bAvoidObjects = avoidObjects;
49 void SetAvoidObjectsDetectionRadius(
float radius)
54 m_fAvoidObjectsDetectionRadius = radius;
55 if (m_AvoidObjectTraceSphere)
56 m_AvoidObjectTraceSphere.Radius = m_fAvoidObjectsDetectionRadius;
60 void SetAvoidObjectsDetectionHeight(
float height)
62 m_fAvoidObjectsDetectionHeight = height;
63 if (m_AvoidObjectTraceSphere)
64 m_AvoidObjectTraceSphere.End[1] = m_AvoidObjectTraceSphere.Start[1] + m_fAvoidObjectsDetectionHeight;
68 void SetAvoidRoads(
bool avoidRoads)
70 m_bAvoidRoads = avoidRoads;
74 void SetAvoidRivers(
bool avoidRivers)
76 m_bAvoidRivers = avoidRivers;
80 void SetAvoidPowerLines(
bool avoidPowerLines)
82 m_bAvoidPowerLines = avoidPowerLines;
86 void SetAvoidTracks(
bool avoidTracks)
88 m_bAvoidTracks = avoidTracks;
92 void SetAvoidForests(
bool avoidForests)
94 m_bAvoidForests = avoidForests;
98 void SetAvoidLakes(
bool avoidLakes)
100 m_bAvoidLakes = avoidLakes;
104 void SetAvoidLand(
bool avoidLand)
106 m_bAvoidLand = avoidLand;
110 void SetAvoidOcean(
bool avoidOcean)
112 m_bAvoidOcean = avoidOcean;
118 void SetAvoidLandOceanOffset(
float offset)
120 m_fAvoidLandOceanOffset = offset;
125 void RefreshObstaclesByAABB(vector worldMin, vector worldMax)
127 if (!m_WorldEditorAPI.GetWorld())
130 SetupObstacleArrays(
true,
true);
131 m_fOceanLevel = m_WorldEditorAPI.GetWorld().GetOceanBaseHeight();
132 m_WorldEditorAPI.GetWorld().QueryEntitiesByAABB(worldMin, worldMax, AllSplineQueryFilter);
137 void RefreshObstaclesByWorld()
139 if (!m_WorldEditorAPI.GetWorld())
143 m_WorldEditorAPI.GetWorld().GetBoundBox(min, max);
144 RefreshObstaclesByAABB(min, max);
149 void RefreshRoadObstaclesBySphere(vector worldPos,
float radius)
151 if (!m_WorldEditorAPI.GetWorld())
154 SetupObstacleArrays(
true,
false);
155 m_fOceanLevel = m_WorldEditorAPI.GetWorld().GetOceanBaseHeight();
156 m_WorldEditorAPI.GetWorld().QueryEntitiesBySphere(worldPos, radius, RoadSplineQueryFilter);
161 void RefreshAreaObstaclesBySphere(vector worldPos,
float radius)
163 if (!m_WorldEditorAPI.GetWorld())
166 SetupObstacleArrays(
false,
true);
167 m_fOceanLevel = m_WorldEditorAPI.GetWorld().GetOceanBaseHeight();
168 m_WorldEditorAPI.GetWorld().QueryEntitiesBySphere(worldPos, radius, AreaSplineQueryFilter);
173 void RefreshAreaObstaclesByWorld()
175 if (!m_WorldEditorAPI.GetWorld())
178 SetupObstacleArrays(
false,
true);
179 m_fOceanLevel = m_WorldEditorAPI.GetWorld().GetOceanBaseHeight();
181 m_WorldEditorAPI.GetWorld().GetBoundBox(min, max);
182 m_WorldEditorAPI.GetWorld().QueryEntitiesByAABB(min, max, AreaSplineQueryFilter);
190 bool HasObstacle(vector worldPos, array<IEntity> exclusionList =
null)
192 if (!m_aAvoidInfoRoads)
194 Print(
"SCR_ObstacleDetector.HasObstacle() method requires obtaining obstacles info through SCR_ObstacleDetector.RefreshObstaclesBy*() method first", LogLevel.ERROR);
198 BaseWorld world = m_WorldEditorAPI.GetWorld();
204 if (m_bAvoidLand && m_bAvoidOcean)
207 float terrainY = world.GetSurfaceY(worldPos[0], worldPos[2]);
209 if (m_bAvoidOcean && terrainY < m_fOceanLevel + m_fAvoidLandOceanOffset)
212 if (m_bAvoidLand && terrainY > m_fOceanLevel + m_fAvoidLandOceanOffset)
218 foreach (SCR_ObstacleDetectorSplineInfo info : m_aAvoidInfoForests)
220 if (Math2D.IsPointInPolygon(info.m_a2DPoints, worldPos[0], worldPos[2]))
227 foreach (SCR_ObstacleDetectorSplineInfo info : m_aAvoidInfoLakes)
229 if (worldPos[1] < info.m_fLakeSurfaceY && Math2D.IsPointInPolygon(info.m_a2DPoints, worldPos[0], worldPos[2]))
236 foreach (SCR_ObstacleDetectorSplineInfo info : m_aAvoidInfoRoads)
238 if (info.IsNearRoadSplineXZ(worldPos) &&
SCR_Math3D.IsPointWithinSplineDistanceXZ(info.m_aTesselatedPoints, worldPos, info.m_fClearance))
245 foreach (SCR_ObstacleDetectorSplineInfo info : m_aAvoidInfoRivers)
247 if (info.IsNearRoadSplineXZ(worldPos) &&
SCR_Math3D.IsPointWithinSplineDistanceXZ(info.m_aTesselatedPoints, worldPos, info.m_fClearance))
252 if (m_bAvoidPowerLines)
254 foreach (SCR_ObstacleDetectorSplineInfo info : m_aAvoidInfoPowerLines)
256 if (info.IsNearRoadSplineXZ(worldPos) &&
SCR_Math3D.IsPointWithinSplineDistanceXZ(info.m_aTesselatedPoints, worldPos, info.m_fClearance))
263 foreach (SCR_ObstacleDetectorSplineInfo info : m_aAvoidInfoTracks)
265 if (info.IsNearRoadSplineXZ(worldPos) &&
SCR_Math3D.IsPointWithinSplineDistanceXZ(info.m_aTesselatedPoints, worldPos, info.m_fClearance))
270 if (m_bAvoidObjects && (m_fAvoidObjectsDetectionHeight != 0 || m_fAvoidObjectsDetectionHeight > 0))
272 if (!m_AvoidObjectTraceSphere)
274 m_AvoidObjectTraceSphere =
new TraceSphere();
275 m_AvoidObjectTraceSphere.Radius = m_fAvoidObjectsDetectionRadius;
276 m_AvoidObjectTraceSphere.LayerMask = EPhysicsLayerPresets.Main | EPhysicsLayerDefs.Water;
277 m_AvoidObjectTraceSphere.Flags = TraceFlags.ENTS;
280 m_AvoidObjectTraceSphere.Start = worldPos;
281 m_AvoidObjectTraceSphere.End = { worldPos[0], worldPos[1] + m_fAvoidObjectsDetectionHeight, worldPos[2] };
284 m_AvoidObjectTraceSphere.ExcludeArray = exclusionList;
285 else if (m_AvoidObjectTraceSphere.ExcludeArray)
286 m_AvoidObjectTraceSphere.ExcludeArray.Clear();
288 world.TraceMove(m_AvoidObjectTraceSphere,
null);
290 if (m_AvoidObjectTraceSphere.TraceEnt)
300 bool HasObstaclesList()
302 return m_aAvoidInfoRoads !=
null;
309 protected void SetupObstacleArrays(
bool setupRoadSplines,
bool setupAreaSplines)
312 if (setupRoadSplines || !m_aAvoidInfoRoads)
313 m_aAvoidInfoRoads = {};
315 if (setupRoadSplines || !m_aAvoidInfoRivers)
316 m_aAvoidInfoRivers = {};
318 if (setupRoadSplines || !m_aAvoidInfoPowerLines)
319 m_aAvoidInfoPowerLines = {};
321 if (setupRoadSplines || !m_aAvoidInfoTracks)
322 m_aAvoidInfoTracks = {};
325 if (setupAreaSplines || !m_aAvoidInfoForests)
326 m_aAvoidInfoForests = {};
328 if (setupAreaSplines || !m_aAvoidInfoLakes)
329 m_aAvoidInfoLakes = {};
336 array<ref SCR_ObstacleDetectorSplineInfo> GetObstacles()
338 if (!m_aAvoidInfoRoads)
341 array<ref SCR_ObstacleDetectorSplineInfo> result = {};
342 array<array<ref SCR_ObstacleDetectorSplineInfo>> arrays = {
345 m_aAvoidInfoPowerLines,
351 foreach (array<ref SCR_ObstacleDetectorSplineInfo> arr : arrays)
353 foreach (SCR_ObstacleDetectorSplineInfo info : arr)
364 void ClearObstacles()
366 m_aAvoidInfoRoads =
null;
367 m_aAvoidInfoRivers =
null;
368 m_aAvoidInfoPowerLines =
null;
369 m_aAvoidInfoTracks =
null;
370 m_aAvoidInfoForests =
null;
371 m_aAvoidInfoLakes =
null;
380 protected bool BaseSplineQueryFilter(IEntity entity,
bool getRoadSplines,
bool getAreaSplines)
382 if (!getRoadSplines && !getAreaSplines)
385 ShapeEntity shapeEntity = ShapeEntity.Cast(entity);
389 if (!m_WorldEditorAPI)
392 IEntitySource shapeSource = m_WorldEditorAPI.EntityToSource(shapeEntity);
396 IEntitySource generatorSource;
397 typename generatorTypename;
399 for (
int i, count = shapeSource.GetNumChildren(); i < count; ++i)
401 generatorSource = shapeSource.GetChild(i);
402 generatorTypename = generatorSource.GetClassName().ToType();
403 if (!generatorTypename)
408 if (generatorTypename.IsInherited(RoadGeneratorEntity))
410 m_aAvoidInfoRoads.Insert(
new SCR_ObstacleDetectorSplineInfo(shapeSource, shapeEntity, generatorSource));
414 if (generatorTypename.IsInherited(RiverEntity))
416 m_aAvoidInfoRivers.Insert(
new SCR_ObstacleDetectorSplineInfo(shapeSource, shapeEntity, generatorSource));
422 m_aAvoidInfoPowerLines.Insert(
new SCR_ObstacleDetectorSplineInfo(shapeSource, shapeEntity, generatorSource));
428 m_aAvoidInfoTracks.Insert(
new SCR_ObstacleDetectorSplineInfo(shapeSource, shapeEntity, generatorSource));
435 if (generatorTypename.IsInherited(ForestGeneratorEntity))
437 m_aAvoidInfoForests.Insert(
new SCR_ObstacleDetectorSplineInfo(shapeSource, shapeEntity, generatorSource));
441 if (generatorTypename.IsInherited(LakeGeneratorEntity) && generatorSource.Get(
"m_bIsLake", isLake) && isLake)
443 m_aAvoidInfoLakes.Insert(
new SCR_ObstacleDetectorSplineInfo(shapeSource, shapeEntity, generatorSource));
454 protected bool AllSplineQueryFilter(IEntity entity)
456 return BaseSplineQueryFilter(entity,
true,
true);
461 protected bool RoadSplineQueryFilter(IEntity entity)
463 return BaseSplineQueryFilter(entity,
true,
false);
468 protected bool AreaSplineQueryFilter(IEntity entity)
470 return BaseSplineQueryFilter(entity,
false,
true);
475 void SCR_ObstacleDetector(WorldEditorAPI worldEditorAPI)
477 m_WorldEditorAPI = worldEditorAPI;
478 if (!m_WorldEditorAPI)
479 Print(
"Something went wrong with SCR_ObstacleDetector init: passed worldEditorAPI is null", LogLevel.ERROR);
483 class SCR_ObstacleDetectorSplineInfo
486 float m_fLakeSurfaceY;
487 ref array<float> m_a2DPoints;
488 ref array<vector> m_aTesselatedPoints;
489 ref array<vector> m_aMinsWithClearance;
490 ref array<vector> m_aMaxsWithClearance;
491 vector m_vMinWithClearance;
492 vector m_vMaxWithClearance;
497 bool IsNearRoadSplineXZ(vector point)
502 if (x < m_vMinWithClearance[0] || m_vMaxWithClearance[0] < x ||
503 z < m_vMinWithClearance[2] || m_vMaxWithClearance[2] < z)
507 foreach (
int index, vector min : m_aMinsWithClearance)
509 max = m_aMaxsWithClearance[
index];
510 if (min[0] <= x && x <= max[0])
512 if (min[2] <= z && z <= max[2])
526 protected void GetAndSetMinMaxWithClearance(inout notnull array<vector> mins, inout notnull array<vector> maxs, out vector min, out vector max)
528 vector vectorClearance = { m_fClearance, 0, m_fClearance };
529 int minsCount = mins.Count();
530 int maxsCount = maxs.Count();
532 if (minsCount < 1 || maxsCount < 1 || minsCount != maxsCount)
534 min = -vectorClearance;
535 max = vectorClearance;
540 for (
int i; i < minsCount; i++)
542 mins[i] = mins[i] - vectorClearance;
543 for (
int j; j < 3; j++)
545 if (min[j] > mins[i][j])
551 for (
int i; i < maxsCount; i++)
553 maxs[i] = maxs[i] + vectorClearance;
554 for (
int j; j < 3; j++)
556 if (max[j] < maxs[i][j])
568 protected static int GetPoints2D3D(notnull ShapeEntity shapeEntity, out array<float> pos2D, out array<vector> pos3D)
570 if (!pos2D && !pos3D)
573 array<vector> points3D = {};
574 shapeEntity.GetPointsPositions(points3D);
579 foreach (vector point : points3D)
581 pos2D.Insert(point[0]);
582 pos2D.Insert(point[2]);
587 pos3D.Copy(points3D);
589 return points3D.Count();
593 protected array<vector> GetTesselatedWorldPoints(notnull ShapeEntity shapeEntity)
595 array<vector> result = {};
597 shapeEntity.GenerateTesselatedShape(result);
598 for (
int i, count = result.Count(); i < count; i++)
600 result[i] = shapeEntity.CoordToParent(result[i]);
608 void SCR_ObstacleDetectorSplineInfo(notnull IEntitySource shapeEntitySource, notnull ShapeEntity shapeEntity, notnull IEntitySource generatorSource)
610 typename generatorTypeName = generatorSource.GetClassName().ToType();
611 if (!generatorTypeName)
614 m_aMinsWithClearance = {};
615 m_aMaxsWithClearance = {};
620 if (generatorTypeName.IsInherited(RoadGeneratorEntity))
622 generatorSource.Get(
"RoadClearance", m_fClearance);
623 m_aTesselatedPoints = GetTesselatedWorldPoints(shapeEntity);
624 shapeEntity.GetAllInfluenceBBoxes(shapeEntitySource, m_aMinsWithClearance, m_aMaxsWithClearance);
625 GetAndSetMinMaxWithClearance(m_aMinsWithClearance, m_aMaxsWithClearance, m_vMinWithClearance, m_vMaxWithClearance);
633 if (generatorTypeName.IsInherited(RiverEntity) ||
636 generatorSource.Get(
"Clearance", m_fClearance);
637 m_aTesselatedPoints = GetTesselatedWorldPoints(shapeEntity);
638 shapeEntity.GetAllInfluenceBBoxes(shapeEntitySource, m_aMinsWithClearance, m_aMaxsWithClearance);
639 GetAndSetMinMaxWithClearance(m_aMinsWithClearance, m_aMaxsWithClearance, m_vMinWithClearance, m_vMaxWithClearance);
648 generatorSource.Get(
"m_fClearance", m_fClearance);
649 m_aTesselatedPoints = GetTesselatedWorldPoints(shapeEntity);
650 shapeEntity.GetAllInfluenceBBoxes(shapeEntitySource, m_aMinsWithClearance, m_aMaxsWithClearance);
651 GetAndSetMinMaxWithClearance(m_aMinsWithClearance, m_aMaxsWithClearance, m_vMinWithClearance, m_vMaxWithClearance);
658 if (generatorTypeName.IsInherited(ForestGeneratorEntity))
661 GetPoints2D3D(shapeEntity, m_a2DPoints,
null);
668 if (generatorTypeName.IsInherited(LakeGeneratorEntity))
671 array<vector> a3DPoints = {};
672 GetPoints2D3D(shapeEntity, m_a2DPoints, a3DPoints);
674 bool flattenByBottomPlane;
675 generatorSource.Get(
"m_bFlattenByBottomPlane", flattenByBottomPlane);
677 if (a3DPoints.IsEmpty())
681 float minOrMaxY = a3DPoints[0][1];
682 foreach (vector a3DPoint : a3DPoints)
684 if (flattenByBottomPlane)
686 if (a3DPoint[1] < minOrMaxY)
687 minOrMaxY = a3DPoint[1];
691 if (a3DPoint[1] > minOrMaxY)
692 minOrMaxY = a3DPoint[1];
696 m_fLakeSurfaceY = minOrMaxY;