15class SCR_PowerlineGeneratorEntity : SCR_LineTerrainShaperGeneratorEntity
21 [
Attribute(defvalue:
"30",
desc:
"How far should the poles be from each other",
params:
"1 " + MAX_CABLE_LENGTH,
category:
"Pole Setup")]
42 [
Attribute(defvalue:
"0",
desc:
"Expected empty space around the poles line by other generators",
params:
"0 100 1",
category:
"Pole Setup")]
49 [
Attribute(defvalue:
"0",
desc:
"Maximum random yaw angle (×2, -value to +value) - only applied to default poles",
params:
"0 180 1",
category:
"Randomisation")]
58 [
Attribute(defvalue:
"0",
desc:
"Apply pitch and roll randomisation to default poles",
category:
"Randomisation")]
77 [
Attribute(defvalue:
"{836210B285A81785}Assets/Structures/Infrastructure/Power/Powerlines/data/default_powerline_wire.emat",
desc:
"Default cable material if none above match",
params:
"emat",
category:
"Cables")]
87 protected static const string POWER_LINE_CLASS =
"PowerlineEntity";
88 protected static const ResourceName DEFAULT_CABLE_PREFAB =
"{613763D114E7CD1C}Prefabs/WEGenerators/Powerline/Powerline.et";
89 protected static const int MAX_CABLE_LENGTH = 500;
95 protected static const float JUNCTION_DISTANCEXZ = 0.1;
96 protected static const float JUNCTION_DISTANCEXZ_SQ = JUNCTION_DISTANCEXZ * JUNCTION_DISTANCEXZ;
99 protected static const float MIN_CABLE_LENGTH_SQ = 0.01;
100 protected static const float MAX_CABLE_LENGTH_SQ = MAX_CABLE_LENGTH * MAX_CABLE_LENGTH;
101 protected static const float CABLE_DEFAULT_DETECTION_BBOX_SIDE = 5;
103 protected static const float POLE_SAFEZONE_DISTANCE = 1.0;
107 protected static const int DEBUG_POLE_COLOUR_POS = Color.BLUE & 0x00FFFFFF | 0x88000000;
108 protected static const int DEBUG_POLE_COLOUR_ERROR = Color.RED & 0x00FFFFFF | 0x88000000;
109 protected static const float DEBUG_POLE_SIZE = 1;
110 protected static const vector DEBUG_POLE_POS =
"0 5 0";
112 protected static const int DEBUG_SLOT_COLOUR_POS = Color.DARK_GREEN & 0x00FFFFFF | 0x88000000;
114 protected static const int DEBUG_SLOT_COLOUR_UNUSED = Color.ORANGE & 0x00FFFFFF | 0x88000000;
115 protected static const float DEBUG_SLOT_SIZE = 0.1;
117 protected static const int DEBUG_CABLE_LENGTH_COLOUR_ERROR_SPHERE = Color.RED & 0x00FFFFFF | 0xAA000000;
118 protected static const int DEBUG_CABLE_LENGTH_COLOUR_ERROR_LINE = Color.RED;
119 protected static const vector DEBUG_CABLE_LENGTH_POS =
"0 3 0";
120 protected static const float DEBUG_CABLE_LENGTH_POS_MAX_DIST = DEBUG_CABLE_LENGTH_POS.Length();
121 protected static const float DEBUG_CABLE_LENGTH_SIZE = 0.5;
123 protected static const int DEBUG_CABLE_COLOUR_POS = Color.YELLOW & 0x00FFFFFF | 0x88000000;
129 if (!m_ParentShapeSource)
132 if (!m_bEnableGeneration)
134 Print(
"Power line generation is disabled for this shape (beware of junction issues with other lines) - tick it back on before saving",
LogLevel.NORMAL);
138 WorldEditorAPI worldEditorAPI = _WB_GetEditorAPI();
139 if (!worldEditorAPI || worldEditorAPI.UndoOrRedoIsRestoring() || !worldEditorAPI.AreGeneratorEventsEnabled())
142 bool manageEntityAction = !worldEditorAPI.IsDoingEditAction();
143 if (manageEntityAction)
144 worldEditorAPI.BeginEntityAction();
148 int childrenCount = m_Source.GetNumChildren();
149 if (childrenCount > 0)
151 Debug.BeginTimeMeasure();
153 Debug.EndTimeMeasure(
"Delete " + childrenCount +
" children");
158 if (s_DebugShapeManager)
159 s_DebugShapeManager.Clear();
161 s_DebugShapeManager =
new SCR_DebugShapeManager();
165 s_DebugShapeManager = null;
169 array<vector> worldAnchorPoints = GetWorldAnchorPoints(m_ParentShapeSource);
170 int worldAnchorPointsCount = worldAnchorPoints.Count();
171 if (worldAnchorPointsCount < 2)
174 map<IEntitySource, IEntitySource> existingJunctions =
new map<IEntitySource, IEntitySource>();
177 IEntitySource existingObjectSource, existingPoleSource;
178 if (GetObjectAndPoleSourceAt(worldAnchorPoints[0], existingObjectSource, existingPoleSource))
179 existingJunctions.Insert(existingObjectSource, existingPoleSource);
181 if (GetObjectAndPoleSourceAt(worldAnchorPoints[worldAnchorPointsCount - 1], existingObjectSource, existingPoleSource))
182 existingJunctions.Insert(existingObjectSource, existingPoleSource);
185 map<IEntitySource, ref map<IEntitySource, vector>> junctionGeneratorAndPoleAndPosMap =
new map<IEntitySource, ref map<IEntitySource, vector>>();
186 foreach (IEntitySource objectSource, IEntitySource poleSource : existingJunctions)
188 IEntitySource otherGenerator = objectSource.GetParent();
192 map<IEntitySource, vector> otherJunctionPositions;
193 if (!junctionGeneratorAndPoleAndPosMap.Find(otherGenerator, otherJunctionPositions))
195 otherJunctionPositions =
new map<IEntitySource, vector>();
196 junctionGeneratorAndPoleAndPosMap.Insert(otherGenerator, otherJunctionPositions);
199 otherJunctionPositions.Insert(poleSource, worldEditorAPI.SourceToEntity(objectSource).
GetOrigin());
202 Debug.BeginTimeMeasure();
203 map<IEntitySource, IEntitySource> createdJunctions = GenerateJunctions();
204 Debug.EndTimeMeasure(createdJunctions.Count().ToString() +
" junctions generation");
206 map<IEntitySource, vector> junctionPositions =
new map<IEntitySource, vector>();
207 foreach (IEntitySource objectSource, IEntitySource poleSource : createdJunctions)
209 junctionPositions.Insert(poleSource, worldEditorAPI.SourceToEntity(objectSource).
GetOrigin());
212 junctionGeneratorAndPoleAndPosMap.Insert(m_Source, junctionPositions);
214 Debug.BeginTimeMeasure();
215 GeneratePoles(junctionGeneratorAndPoleAndPosMap);
216 Debug.EndTimeMeasure(
"Poles generation");
218 ReconnectOtherGenerators(m_Source, createdJunctions);
220 if (manageEntityAction)
221 worldEditorAPI.EndEntityAction();
225 protected static bool GetObjectAndPoleSourceAt(vector worldPos, out IEntitySource parentSource, out IEntitySource poleSource)
227 WorldEditorAPI worldEditorAPI = GetWorldEditorAPI();
228 set<IEntity> entities =
new set<IEntity>();
229 worldEditorAPI.GetWorld().QueryEntitiesByAABB(worldPos - JUNCTION_SEARCH_RANGE, worldPos + JUNCTION_SEARCH_RANGE, entities.Insert);
231 foreach (
IEntity entity : entities)
233 if (vector.DistanceSqXZ(worldPos, entity.GetOrigin()) > JUNCTION_DISTANCEXZ_SQ)
238 parentSource = worldEditorAPI.EntityToSource(entity);
239 poleSource = parentSource;
243 IEntity child = entity.GetChildren();
248 parentSource = worldEditorAPI.EntityToSource(entity);
249 poleSource = worldEditorAPI.EntityToSource(child);
263 protected void ReconnectOtherGenerators(notnull IEntitySource generator, notnull map<IEntitySource, IEntitySource> junctions)
265 WorldEditorAPI worldEditorAPI = GetWorldEditorAPI();
269 BaseWorld world = worldEditorAPI.GetWorld();
270 foreach (IEntitySource parentSource, IEntitySource poleSource : junctions)
272 vector parentPos = worldEditorAPI.SourceToEntity(parentSource).
GetOrigin();
274 set<IEntity> entitiesSet =
new set<IEntity>();
275 world.QueryEntitiesByAABB(parentPos - JUNCTION_SEARCH_RANGE, parentPos + JUNCTION_SEARCH_RANGE, entitiesSet.Insert);
277 set<IEntitySource> otherGeneratorSources =
new set<IEntitySource>();
278 foreach (
IEntity entity : entitiesSet)
280 if (!SCR_PowerlineGeneratorEntity.Cast(entity))
283 IEntitySource otherGeneratorSource = worldEditorAPI.EntityToSource(entity);
284 if (!otherGeneratorSource)
287 if (otherGeneratorSource == generator)
290 IEntitySource shapeSource = otherGeneratorSource.GetParent();
294 ShapeEntity parentShape = ShapeEntity.Cast(worldEditorAPI.SourceToEntity(shapeSource));
298 array<vector> shapePoints = GetWorldAnchorPoints(shapeSource);
302 int shapesPointCount = shapePoints.Count();
303 if (shapesPointCount < 2)
306 if (vector.DistanceSqXZ(shapePoints[0], parentPos) > JUNCTION_DISTANCEXZ_SQ
307 && vector.DistanceSqXZ(shapePoints[shapesPointCount - 1], parentPos) > JUNCTION_DISTANCEXZ_SQ)
310 otherGeneratorSources.Insert(otherGeneratorSource);
313 foreach (IEntitySource otherGeneratorSource : otherGeneratorSources)
315 if (!ReconnectGeneratorToPole(otherGeneratorSource, poleSource))
316 Print(
"Cannot reconnect generator to pole " +
Debug.GetEntityLinkString(worldEditorAPI.SourceToEntity(poleSource)),
LogLevel.WARNING);
328 protected static bool ReconnectGeneratorToPole(notnull IEntitySource generatorSource, notnull IEntitySource otherLinePoleSource)
330 BaseContainer parentShape = generatorSource.GetParent();
331 if (!parentShape || !parentShape.GetClassName().ToType() || !parentShape.GetClassName().ToType().IsInherited(ShapeEntity))
334 int childrenCount = generatorSource.GetNumChildren();
335 if (childrenCount < 1)
338 WorldEditorAPI worldEditorAPI = GetWorldEditorAPI();
348 array<vector> worldAnchorPoints = GetWorldAnchorPoints(parentShape);
349 int worldAnchorPointsCount = worldAnchorPoints.Count();
350 if (worldAnchorPointsCount < 2)
354 if (vector.DistanceSqXZ(worldAnchorPoints[0], otherLinePole.GetOrigin()) <= JUNCTION_DISTANCEXZ_SQ)
356 searchPos = worldAnchorPoints[0];
360 SCR_PowerlineGeneratorEntity generator = SCR_PowerlineGeneratorEntity.Cast(worldEditorAPI.SourceToEntity(generatorSource));
364 array<vector> relPolePos = {};
365 map<int, ref SCR_PowerlineGeneratorPointData> pointDataMap =
new map<int, ref SCR_PowerlineGeneratorPointData>();
366 if (!generator.GetPolesRelPosition(relPolePos, pointDataMap) || relPolePos.Count() < 2)
369 searchPos = generator.CoordToParent(relPolePos[relPolePos.Count() - 2]);
372 IEntitySource entitySource, localPoleSource;
373 if (!GetObjectAndPoleSourceAt(searchPos, entitySource, localPoleSource))
376 array<IEntitySource> cablesToDelete = GetCablesBetweenPoleSources(localPoleSource, otherLinePoleSource);
377 worldEditorAPI.DeleteEntities(cablesToDelete);
379 return CreatePowerLines(generatorSource, localPoleSource, otherLinePoleSource) != null;
386 protected static array<IEntitySource> GetCablesBetweenPoleSources(notnull IEntitySource generatorPoleSource, notnull IEntitySource otherPoleSource)
388 array<IEntitySource> result = {};
389 set<IEntity> entitiesAroundGeneratorPole =
new set<IEntity>();
390 set<IEntity> entitiesAroundOtherPole =
new set<IEntity>();
393 WorldEditorAPI worldEditorAPI = GetWorldEditorAPI();
394 BaseWorld world = worldEditorAPI.GetWorld();
396 worldEditorAPI.SourceToEntity(generatorPoleSource).
GetWorldBounds(mins, maxes);
402 mins = worldEditorAPI.SourceToEntity(generatorPoleSource).
GetOrigin() - vector.One * CABLE_DEFAULT_DETECTION_BBOX_SIDE;
403 maxes = worldEditorAPI.SourceToEntity(generatorPoleSource).
GetOrigin() + vector.One * CABLE_DEFAULT_DETECTION_BBOX_SIDE;
407 if (!world.QueryEntitiesByAABB(mins, maxes, entitiesAroundGeneratorPole.Insert))
410 worldEditorAPI.SourceToEntity(otherPoleSource).
GetWorldBounds(mins, maxes);
416 mins = worldEditorAPI.SourceToEntity(otherPoleSource).
GetOrigin() - vector.One * CABLE_DEFAULT_DETECTION_BBOX_SIDE;
417 maxes = worldEditorAPI.SourceToEntity(otherPoleSource).
GetOrigin() + vector.One * CABLE_DEFAULT_DETECTION_BBOX_SIDE;
421 if (!world.QueryEntitiesByAABB(mins, maxes, entitiesAroundOtherPole.Insert))
424 IEntitySource generatorSource = generatorPoleSource.GetParent();
425 foreach (
IEntity entityAroundGeneratorPole : entitiesAroundGeneratorPole)
427 if (!entitiesAroundOtherPole.Contains(entityAroundGeneratorPole))
430 if (!entityAroundGeneratorPole.Type() || !entityAroundGeneratorPole.Type().IsInherited(PowerlineEntity))
433 IEntitySource entitySource = worldEditorAPI.EntityToSource(entityAroundGeneratorPole);
434 if (!entitySource || entitySource.GetParent() != generatorSource)
437 result.Insert(entitySource);
446 protected map<IEntitySource, IEntitySource> GenerateJunctions()
448 array<vector> anchorPoints = m_ShapeNextPointHelper.GetAnchorPoints();
449 int anchorPointsCountMinus1 = anchorPoints.Count() - 1;
451 if (anchorPointsCountMinus1 < 1)
452 return new map<IEntitySource, IEntitySource>();
454 WorldEditorAPI worldEditorAPI = _WB_GetEditorAPI();
456 map<IEntitySource, IEntitySource> result =
new map<IEntitySource, IEntitySource>();
458 SCR_PowerlineGeneratorPointData pointData;
459 SCR_PowerlineGeneratorJunctionData junctionData;
460 IEntitySource objectSource;
461 IEntitySource poleSource;
462 map<int, ref ShapePointDataScriptBase> pointDataMap = GetFirstPointDataMap(SCR_PowerlineGeneratorPointData);
463 foreach (
int i, vector anchorPoint : anchorPoints)
465 pointData = SCR_PowerlineGeneratorPointData.Cast(pointDataMap.Get(i));
469 junctionData = pointData.m_JunctionData;
473 ResourceName junctionResourceName = junctionData.m_sJunctionPrefab;
474 if (junctionResourceName.IsEmpty())
485 vectorDir = vector.Direction(anchorPoint, anchorPoints[1]);
487 vectorDir = -vectorDir;
489 else if (i == anchorPointsCountMinus1)
491 vectorDir = vector.Direction(anchorPoints[i - 1], anchorPoint);
493 vectorDir = -vectorDir;
497 vectorDir = vector.Direction(
498 vector.Direction(anchorPoint, anchorPoints[i - 1]).Normalized(),
499 vector.Direction(anchorPoint, anchorPoints[i + 1]).Normalized());
502 vectorDir = vectorDir.VectorToAngles();
503 vectorDir = { 0, Math.Repeat(vectorDir[0] + junctionData.m_fYawOffset, 360), 0 };
505 if (junctionData.m_bApplyPitchAndRollRandomisation)
514 if (junctionData.m_fYOffset)
515 anchorPoint[1] = anchorPoint[1] + junctionData.m_fYOffset;
517 objectSource = worldEditorAPI.CreateEntity(junctionResourceName,
string.Empty, m_iSourceLayerID, m_Source, anchorPoint, vectorDir);
521 poleSource = GetPowerPoleSourceFromEntitySource(objectSource);
524 worldEditorAPI.DeleteEntity(objectSource);
528 if (junctionData.m_bPowerSource)
529 worldEditorAPI.SetVariableValue(poleSource, null,
"PowerSource",
"1");
531 result.Insert(objectSource, poleSource);
538 protected override bool _WB_OnKeyChanged(BaseContainer src,
string key, BaseContainerList ownerContainers,
IEntity parent)
540 if (!super._WB_OnKeyChanged(src, key, ownerContainers, parent))
546 WorldEditorAPI worldEditorAPI = _WB_GetEditorAPI();
547 if (!worldEditorAPI || worldEditorAPI.UndoOrRedoIsRestoring())
550 BaseContainerTools.WriteToInstance(
this, worldEditorAPI.EntityToSource(
this));
561 protected void GeneratePoles(notnull map<IEntitySource, ref map<IEntitySource, vector>> junctionGeneratorAndPoleAndPosMap)
563 if (!m_ParentShapeSource)
565 Print(
"Parent Shape Source is null, cannot generate power poles",
LogLevel.ERROR);
569 WorldEditorAPI worldEditorAPI = _WB_GetEditorAPI();
573 if (!ShapeEntity.Cast(worldEditorAPI.SourceToEntity(m_ParentShapeSource)))
575 Print(
"Parent Shape is null, cannot generate power poles",
LogLevel.ERROR);
579 array<vector> anchorPointsRelPos = m_ShapeNextPointHelper.GetAnchorPoints();
580 if (anchorPointsRelPos.Count() < 2)
587 array<vector> polePointsRelPos = {};
588 map<int, ref SCR_PowerlineGeneratorPointData> pointDataMap =
new map<int, ref SCR_PowerlineGeneratorPointData>();
590 if (!GetPolesRelPosition(polePointsRelPos, pointDataMap))
593 if (polePointsRelPos.IsEmpty())
595 Print(
"Power Line Generator shape is invalid; no poles will be generated",
LogLevel.ERROR);
600 CreatePolesAndCables(polePointsRelPos, anchorPointsRelPos, pointDataMap, junctionGeneratorAndPoleAndPosMap);
608 protected bool GetPolesRelPosition(
609 notnull out array<vector> polePointsRelPos,
610 notnull out map<int, ref SCR_PowerlineGeneratorPointData> pointDataMap)
612 if (!m_ShapeNextPointHelper || !m_ShapeNextPointHelper.IsValid())
614 Print(
"[SCR_PowerlineGeneratorEntity.GetPolesRelPosition] invalid shapeNextPointHelper (" + __FILE__ +
" L" + __LINE__ +
")",
LogLevel.ERROR);
622 map<int, ref ShapePointDataScriptBase> pointsData = GetFirstPointDataMap(SCR_PowerlineGeneratorPointData);
624 IEntity parentShapeEntity = _WB_GetEditorAPI().SourceToEntity(m_ParentShapeSource);
627 bool generatePerPoint;
628 vector lastPoleRelPos;
629 SCR_PowerlineGeneratorPointData pointData;
630 array<vector> anchorPointsRelPos = m_ShapeNextPointHelper.GetAnchorPoints();
631 int anchorPointsCountMinus1 = anchorPointsRelPos.Count() - 1;
632 foreach (
int i, vector anchorPointRelPos : anchorPointsRelPos)
634 bool isStart = i == 0;
635 bool isEnd = i == anchorPointsCountMinus1;
638 bool wasGeneratedPerPoint = generatePerPoint;
639 float previousOffset = poleOffset;
641 pointData = SCR_PowerlineGeneratorPointData.Cast(pointsData.Get(i));
644 poleOffset = pointData.m_fPoleOffset;
645 generatePerPoint = pointData.m_bGeneratePerPoint;
648 if (
m_fDistance + poleOffset < POLE_SAFEZONE_DISTANCE)
651 hasJunction = pointData.m_JunctionData != null && (
m_DefaultJunctionPole || pointData.m_JunctionData.m_sJunctionPrefab);
658 if (!isStart && !wasGeneratedPerPoint)
661 if (previousOffset != 0 && m_ShapeNextPointHelper.GetNextPoint(
m_fDistance + previousOffset, lastPoleRelPos, i, xzMode: m_bNextPointMeasurementXZ))
662 polePointsRelPos.Insert(lastPoleRelPos);
665 while (m_ShapeNextPointHelper.GetNextPoint(
m_fDistance, lastPoleRelPos, i, xzMode: m_bNextPointMeasurementXZ))
667 polePointsRelPos.Insert(lastPoleRelPos);
671 if (wasGeneratedPerPoint || generatePerPoint || hasJunction || isEnd || isStart || vector.DistanceSq(lastPoleRelPos, anchorPointRelPos) == 0)
673 int pointsCount = polePointsRelPos.Count();
677 pointDataMap.Insert(pointsCount, pointData);
681 if (pointsCount > 0 && vector.DistanceSq(lastPoleRelPos, anchorPointRelPos) < POLE_SAFEZONE_DISTANCE)
682 polePointsRelPos.Remove(pointsCount - 1);
685 polePointsRelPos.Insert(anchorPointRelPos);
687 m_ShapeNextPointHelper.SetOnAnchor(i);
688 lastPoleRelPos = anchorPointRelPos;
701 protected void CreatePolesAndCables(
702 notnull array<vector> polePointsRelPos,
703 notnull array<vector> anchorPointsRelPos,
704 notnull map<int, ref SCR_PowerlineGeneratorPointData> pointsData,
705 notnull map<IEntitySource, ref map<IEntitySource, vector>> junctionGeneratorAndPoleAndPosMap)
707 bool snapToGround = m_bSnapOffsetShapeToTheGround && !m_bSculptTerrain;
708 WorldEditorAPI worldEditorAPI = _WB_GetEditorAPI();
709 int poleWorldPointsCountMinus1 = polePointsRelPos.Count() - 1;
710 vector prevPoleRelPoint;
714 IEntitySource currPoleObject;
715 IEntitySource prevPoleSource;
716 IEntitySource currPoleSource;
720 foreach (
int i, vector currPoleRelPoint : polePointsRelPos)
722 bool applyRandomPitchAndRoll;
723 bool isStart = i == 0;
724 bool isEnd = i == poleWorldPointsCountMinus1;
725 bool isAnchor = isStart || isEnd;
728 foreach (vector anchorPointRelPos : anchorPointsRelPos)
730 if (currPoleRelPoint == anchorPointRelPos)
738 bool isSameLine =
true;
744 currPoleSource = FindJunctionOnPosXZ(junctionGeneratorAndPoleAndPosMap, m_Source, CoordToParent(currPoleRelPoint), isSameLine);
748 if (s_DebugShapeManager)
749 s_DebugShapeManager.AddSphere(CoordToParent(currPoleRelPoint), 2, 0x88800080);
751 applyRandomPitchAndRoll = isSameLine;
760 vectorDir = vector.Direction(currPoleRelPoint, polePointsRelPos[1]);
764 vectorDir = -vectorDir;
768 vectorDir = vector.Direction(prevPoleRelPoint, currPoleRelPoint);
772 vectorDir = -vectorDir;
776 vectorDir = vector.Direction(
777 vector.Direction(currPoleRelPoint, prevPoleRelPoint).Normalized(),
778 vector.Direction(currPoleRelPoint, polePointsRelPos[i + 1]).Normalized());
787 vectorDir = vector.Direction(
788 vector.Direction(currPoleRelPoint, prevPoleRelPoint).Normalized(),
789 vector.Direction(currPoleRelPoint, polePointsRelPos[i + 1]).Normalized());
799 vector worldPos = CoordToParent(currPoleRelPoint);
800 worldPos[1] = worldEditorAPI.GetTerrainSurfaceY(worldPos[0], worldPos[2]);
801 currPoleRelPoint = CoordToLocal(worldPos) + vector.Up * m_vShapeOffset[1];
804 vector
angles = { 0, vectorDir.ToYaw(), 0 };
809 if (applyRandomPitchAndRoll)
818 currPoleObject = worldEditorAPI.CreateEntity(prefab,
string.Empty, m_iSourceLayerID, m_Source, currPoleRelPoint,
angles);
819 currPoleSource = GetPowerPoleSourceFromEntitySource(currPoleObject);
821 if (s_DebugShapeManager)
823 s_DebugShapeManager.AddSphere(CoordToParent(currPoleRelPoint), DEBUG_POLE_SIZE, DEBUG_POLE_COLOUR_POS,
ShapeFlags.NOOUTLINE);
824 s_DebugShapeManager.AddArrow(CoordToParent(currPoleRelPoint), CoordToParent(currPoleRelPoint + 3 * vector.FromYaw(
angles[1])));
830 prevPoleEntity =
SCR_PowerPole.Cast(worldEditorAPI.SourceToEntity(prevPoleSource));
833 currPoleEntity =
SCR_PowerPole.Cast(worldEditorAPI.SourceToEntity(currPoleSource));
834 if (currPoleEntity && prevPoleEntity != currPoleEntity)
835 CreatePowerLines(m_Source, prevPoleSource, currPoleSource);
839 prevPoleSource = currPoleSource;
840 prevPoleRelPoint = currPoleRelPoint;
841 currPoleObject = null;
842 currPoleSource = null;
853 protected static IEntitySource FindJunctionOnPosXZ(
854 map<IEntitySource, ref map<IEntitySource, vector>> generatorAndPolesPlusParentWorldPosMap,
855 notnull IEntitySource generatorSource,
859 map<IEntitySource, vector> selfMap = generatorAndPolesPlusParentWorldPosMap.Get(generatorSource);
863 foreach (IEntitySource poleSource, vector poleWorldPos : selfMap)
865 if (vector.DistanceSqXZ(worldPos, poleWorldPos) < JUNCTION_DISTANCEXZ_SQ)
872 foreach (IEntitySource otherGeneratorSource, map<IEntitySource, vector> junctionPosMap : generatorAndPolesPlusParentWorldPosMap)
874 if (otherGeneratorSource == generatorSource)
877 foreach (IEntitySource poleSource, vector poleWorldPos : junctionPosMap)
879 if (vector.DistanceSqXZ(worldPos, poleWorldPos) < JUNCTION_DISTANCEXZ_SQ)
897 protected static array<IEntitySource> CreatePowerLines(notnull IEntitySource generatorSource, notnull IEntitySource existingPoleSource, notnull IEntitySource addedPoleSource)
899 WorldEditorAPI worldEditorAPI = GetWorldEditorAPI();
905 vector existingPoleWorldPos = existingPole.GetOrigin();
906 vector addedPoleWorldPos = addedPole.GetOrigin();
908 bool isSameLine = existingPoleSource.GetParent() == addedPoleSource.GetParent();
910 map<SCR_EPoleCableType, ref SCR_PoleCableSlotGroup> existingPoleGroups = existingPole.GetClosestCableSlotGroupsForEachCableType(addedPoleWorldPos, isSameLine);
911 if (existingPoleGroups.IsEmpty())
913 Print(
"No valid slots found on the existing power pole, please check the setup of your power poles.",
LogLevel.WARNING);
915 if (s_DebugShapeManager)
916 s_DebugShapeManager.AddSphere(existingPoleWorldPos + DEBUG_POLE_POS, DEBUG_POLE_SIZE, DEBUG_POLE_COLOUR_ERROR,
ShapeFlags.NOOUTLINE);
921 map<SCR_EPoleCableType, ref SCR_PoleCableSlotGroup> addedPoleGroups = addedPole.GetClosestCableSlotGroupsForEachCableType(existingPoleWorldPos, isSameLine);
922 if (addedPoleGroups.IsEmpty())
924 Print(
"No valid slots found on the new power pole, please check the setup of your power poles.",
LogLevel.WARNING);
926 if (s_DebugShapeManager)
927 s_DebugShapeManager.AddSphere(addedPoleWorldPos + DEBUG_POLE_POS, DEBUG_POLE_SIZE, DEBUG_POLE_COLOUR_ERROR,
ShapeFlags.NOOUTLINE);
932 array<SCR_EPoleCableType> cableTypes = {};
936 array<SCR_EPoleCableType> cableTypesInCommon = {};
939 if (existingPoleGroups.Contains(cableType) && addedPoleGroups.Contains(cableType))
940 cableTypesInCommon.Insert(cableType);
945 if (cableTypesInCommon.IsEmpty())
947 Print(
"No cable types in common between two poles - be sure to select compatible poles in Generator Prefab at " +
Debug.GetEntityLinkString(existingPole),
LogLevel.WARNING);
949 if (s_DebugShapeManager)
951 s_DebugShapeManager.AddSphere(existingPoleWorldPos + DEBUG_POLE_POS, DEBUG_POLE_SIZE, DEBUG_POLE_COLOUR_ERROR,
ShapeFlags.NOOUTLINE);
952 s_DebugShapeManager.AddSphere(addedPoleWorldPos + DEBUG_POLE_POS, DEBUG_POLE_SIZE, DEBUG_POLE_COLOUR_ERROR,
ShapeFlags.NOOUTLINE);
953 s_DebugShapeManager.AddLine(existingPoleWorldPos + DEBUG_POLE_POS, addedPoleWorldPos + DEBUG_POLE_POS, DEBUG_POLE_COLOUR_ERROR);
959 ResourceName powerLineMaterial;
960 generatorSource.Get(
"m_PowerlineMaterial", powerLineMaterial);
962 ResourceName cablePrefab;
963 generatorSource.Get(
"m_sPowerLinePrefab", cablePrefab);
965 int generatorLayerID = generatorSource.GetLayerID();
967 array<ref SCR_PoleCable> poleCables;
968 generatorSource.Get(
"m_aCables", poleCables);
970 string powerLineEntity;
972 powerLineEntity = cablePrefab;
974 powerLineEntity = DEFAULT_CABLE_PREFAB;
976 array<IEntitySource> result = {};
978 array<vector> startPoints = {};
979 array<vector> endPoints = {};
980 SCR_PoleCableSlotGroup existingGroup;
981 SCR_PoleCableSlotGroup addedGroup;
982 IEntitySource powerLineEntitySource;
984 array<ref ContainerIdPathEntry> containerPath;
987 existingGroup = existingPoleGroups.Get(cableType);
988 int existingPoleCableCount = existingGroup.m_aSlots.Count();
990 addedGroup = addedPoleGroups.Get(cableType);
991 int addedPoleCableCount = addedGroup.m_aSlots.Count();
994 if (existingPoleCableCount < addedPoleCableCount)
995 cableCount = existingPoleCableCount;
997 cableCount = addedPoleCableCount;
1001 for (
int i; i < cableCount; ++i)
1003 startPoints.Insert(existingPole.CoordToParent(existingGroup.m_aSlots[i].m_vPosition));
1004 endPoints.Insert(addedPole.CoordToParent(addedGroup.m_aSlots[i].m_vPosition));
1007 if (s_DebugShapeManager)
1009 for (
int i = cableCount; i < existingPoleCableCount; ++i)
1011 s_DebugShapeManager.AddSphere(existingPole.CoordToParent(existingGroup.m_aSlots[i].m_vPosition), DEBUG_SLOT_SIZE, DEBUG_SLOT_COLOUR_UNUSED,
ShapeFlags.NOOUTLINE);
1014 for (
int i = cableCount; i < addedPoleCableCount; ++i)
1016 s_DebugShapeManager.AddSphere(addedPole.CoordToParent(addedGroup.m_aSlots[i].m_vPosition), DEBUG_SLOT_SIZE, DEBUG_SLOT_COLOUR_UNUSED,
ShapeFlags.NOOUTLINE);
1020 float normalLengthSq;
1021 float reversedLengthSq;
1022 foreach (
int i, vector startPoint : startPoints)
1024 normalLengthSq += vector.DistanceSq(startPoint, endPoints[i]);
1025 reversedLengthSq += vector.DistanceSq(startPoint, endPoints[cableCount - i - 1]);
1029 if (reversedLengthSq < normalLengthSq)
1030 SCR_ArrayHelperT<vector>.Reverse(endPoints);
1032 if (s_DebugShapeManager)
1034 foreach (
int i, vector startPoint : startPoints)
1036 s_DebugShapeManager.AddSphere(startPoint, DEBUG_SLOT_SIZE, DEBUG_SLOT_COLOUR_POS,
ShapeFlags.NOOUTLINE);
1037 s_DebugShapeManager.AddSphere(endPoints[i], DEBUG_SLOT_SIZE, DEBUG_SLOT_COLOUR_POS,
ShapeFlags.NOOUTLINE);
1038 s_DebugShapeManager.AddLine(startPoint, endPoints[i], DEBUG_CABLE_COLOUR_POS);
1043 powerLineEntitySource = null;
1045 vector startPos, endPos;
1049 foreach (
int i, vector startPoint : startPoints)
1051 vector endPoint = endPoints[i];
1053 if (powerLineEntitySource)
1055 referenceEntity = worldEditorAPI.SourceToEntity(powerLineEntitySource);
1061 referenceEntity = worldEditorAPI.SourceToEntity(generatorSource);
1066 if (vector.DistanceSqXZ(startPos, endPos) < MIN_CABLE_LENGTH_SQ)
1068 PrintFormat(
"Cable's 2D length is too small! Skipping (%1m < %2m)", vector.DistanceXZ(startPos, endPos).ToString(-1, 2), Math.Sqrt(MIN_CABLE_LENGTH_SQ), level:
LogLevel.WARNING);
1070 if (s_DebugShapeManager)
1072 float localX = existingPole.CoordToLocal(startPoint)[0];
1073 vector forward = vector.Direction(startPoint, endPoint);
1075 forward[0] * Math.Cos(Math.PI_HALF) - forward[2] * Math.Sin(Math.PI_HALF),
1077 forward[0] * Math.Sin(Math.PI_HALF) + forward[2] * Math.Cos(Math.PI_HALF),
1080 if (localX > DEBUG_CABLE_LENGTH_POS_MAX_DIST)
1081 right *= DEBUG_CABLE_LENGTH_POS_MAX_DIST;
1085 vector spherePos = (startPoint + endPoint) * 0.5 + DEBUG_CABLE_LENGTH_POS + right;
1087 s_DebugShapeManager.AddSphere(spherePos, DEBUG_CABLE_LENGTH_SIZE, DEBUG_CABLE_LENGTH_COLOUR_ERROR_SPHERE,
ShapeFlags.NOOUTLINE);
1088 s_DebugShapeManager.AddLine(spherePos, startPoint, DEBUG_CABLE_LENGTH_COLOUR_ERROR_LINE);
1089 s_DebugShapeManager.AddLine(spherePos, endPoint, DEBUG_CABLE_LENGTH_COLOUR_ERROR_LINE);
1095 if (vector.DistanceSq(startPos, endPos) > MAX_CABLE_LENGTH_SQ)
1097 PrintFormat(
"Cable's 3D length is too big! Skipping (%1m > %2m)", vector.Distance(startPos, endPos).ToString(-1, 2), Math.Sqrt(MAX_CABLE_LENGTH_SQ), level:
LogLevel.WARNING);
1099 if (s_DebugShapeManager)
1100 s_DebugShapeManager.AddLine(startPoint, endPoint, DEBUG_CABLE_LENGTH_COLOUR_ERROR_LINE);
1105 if (!powerLineEntitySource)
1107 powerLineEntitySource = worldEditorAPI.CreateEntity(powerLineEntity,
string.Empty, generatorLayerID, generatorSource, referenceEntity.
CoordToLocal(existingPoleWorldPos), vector.Zero);
1108 if (!powerLineEntitySource)
1110 if (powerLineEntity != POWER_LINE_CLASS)
1112 Print(
"CreateEntity returned null trying to create " + powerLineEntity,
LogLevel.ERROR);
1113 powerLineEntity = POWER_LINE_CLASS;
1114 powerLineEntitySource = worldEditorAPI.CreateEntity(powerLineEntity,
string.Empty, generatorLayerID, generatorSource, referenceEntity.
CoordToLocal(existingPoleWorldPos), vector.Zero);
1117 if (!powerLineEntitySource)
1119 Print(
"CreateEntity returned null trying to create " + powerLineEntity,
LogLevel.ERROR);
1125 ResourceName cableMaterial;
1126 foreach (SCR_PoleCable cable : poleCables)
1128 if (cable.m_eType == cableType && cable.m_sMaterial)
1130 cableMaterial = cable.m_sMaterial;
1136 cableMaterial = powerLineMaterial;
1138 worldEditorAPI.BeginEditSequence(powerLineEntitySource);
1141 worldEditorAPI.SetVariableValue(powerLineEntitySource, null,
"Material", cableMaterial);
1143 referenceEntity = worldEditorAPI.SourceToEntity(powerLineEntitySource);
1149 worldEditorAPI.BeginEditSequence(powerLineEntitySource);
1152 worldEditorAPI.CreateObjectArrayVariableMember(powerLineEntitySource, null,
"Cables",
"Cable", cableIndex);
1154 worldEditorAPI.SetVariableValue(powerLineEntitySource, containerPath,
"StartPoint", startPos.ToString(
false));
1155 worldEditorAPI.SetVariableValue(powerLineEntitySource, containerPath,
"EndPoint", endPos.ToString(
false));
1157 worldEditorAPI.EndEditSequence(powerLineEntitySource);
1162 if (powerLineEntitySource)
1163 result.Insert(powerLineEntitySource);
1173 protected static IEntitySource GetPowerPoleSourceFromEntitySource(notnull IEntitySource powerPoleEntitySource)
1175 WorldEditorAPI worldEditorAPI = GetWorldEditorAPI();
1176 if (powerPoleEntitySource.GetClassName().ToType().IsInherited(
SCR_PowerPole))
1177 return powerPoleEntitySource;
1180 for (
int i, childrenCount = powerPoleEntitySource.GetNumChildren(); i < childrenCount; i++)
1182 childType = powerPoleEntitySource.GetChild(i).GetClassName().ToType();
1184 return powerPoleEntitySource.GetChild(i);
1191 protected override void _WB_OnParentChange(IEntitySource src, IEntitySource prevParentSrc)
1193 super._WB_OnParentChange(src, prevParentSrc);
1194 if (!m_ParentShapeSource)
1201 protected override void OnShapeChangedInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity, array<vector> mins, array<vector> maxes)
1203 super.OnShapeChangedInternal(shapeEntitySrc, shapeEntity, mins, maxes);
void ContainerIdPathEntry(string propertyName, int index=-1)
float m_fRandomPitchAngle
ref array< string > angles
ref RandomGenerator m_RandomGenerator
enum SCR_ECompassType EntityEditorProps(category:"GameScripted/Gadgets", description:"Compass", color:"0 0 255 255")
Prefab data class for compass component.
override bool _WB_OnKeyChanged(IEntity owner, BaseContainer src, string key, BaseContainerList ownerContainers, IEntity parent)
Any property value has been changed. You can use editor API here and do some additional edit actions ...
void SCR_PowerPole(IEntitySource src, IEntity parent)
ResourceName m_sPowerLinePrefab
ResourceName m_PowerlineMaterial
float Clearance
Used by Obstacle Detector.
bool m_bRotate180DegreeYawEndPole
ResourceName m_DefaultJunctionPole
ref array< ref SCR_PoleCable > m_aCables
ResourceName m_DefaultPole
bool m_bApplyPitchAndRollEnd
bool m_bApplyPitchAndRollDefault
bool m_bApplyPitchAndRollStart
bool m_bRotate180DegreeYawStartPole
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
enum EVehicleType IEntity
proto external vector GetOrigin()
proto external void GetWorldBounds(out vector mins, out vector maxs)
proto external IEntity GetSibling()
proto external vector CoordToLocal(vector coord)
proto external IEntity GetRootParent()
proto void Print(void var, LogLevel level=LogLevel.NORMAL)
Prints content of variable to console/log.
LogLevel
Enum with severity of the logging message.
proto void PrintFormat(string fmt, void param1=NULL, void param2=NULL, void param3=NULL, void param4=NULL, void param5=NULL, void param6=NULL, void param7=NULL, void param8=NULL, void param9=NULL, LogLevel level=LogLevel.NORMAL)
SCR_FieldOfViewSettings Attribute
void OnShapeChangedInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity, array< vector > mins, array< vector > maxes)