7class PrefabGeneratorEntity : SCR_LineTerrainShaperGeneratorBaseEntity
13 [
Attribute(
category:
"Mirrors", defvalue:
"0",
desc:
"Generate mirrored Prefabs - matching according to the shape (duplicate values are ignored).\n- Empty = normal Prefab generation\n- Number # = mirror at +# and -#\n- Use 0 to have the usual central line",
params:
"0 inf 0.01",
precision: 2)]
14 protected ref array<float> m_aMirrorDistances;
16 [
Attribute(
category:
"Mirrors", defvalue:
"0",
desc:
"Use a random (weighted) Prefab instead of the same Prefab on both sides\nThis does not apply when Perlin Asset Distribution is used")]
17 protected bool m_bMirrorRandomPrefabs;
24 protected ref array<ResourceName> m_PrefabNames;
27 protected ref array<float> m_Weights;
30 protected bool m_bOnlyToVertices;
35 [
Attribute(
category:
"Prefabs", defvalue:
"1",
desc:
"Orient Prefabs to the shape's direction - if Yaw Rotation Step below is set, it will start from shape's direction")]
36 protected bool m_bAlignWithShape;
39 protected bool m_bUseXAsForward;
42 protected bool m_bFlipForward;
44 [
Attribute(
category:
"Prefabs", defvalue:
"0",
desc:
"Rotation step starting from 0 / shape direction (if Align With Shape above is used)\n- 0 = disabled, default Prefab yaw behaviour\n- 45 = 0, 45, 90, 135, 180, 225, 270 or 335°\n- 90 = 0, 90, 180 or 270°\n- 135 = 0, 135 or 270° (NOT 405-45°)\n- 180 = front or back",
params:
"0 180")]
45 protected float m_fYawRotationStep;
54 [
Attribute(
category:
"Offset", defvalue:
"0",
desc:
"How much offset variability we want in meters when using offset from the center")]
55 protected float m_fOffsetVariance;
58 protected float m_fGap;
61 protected bool m_fRandomSpacing;
64 protected float m_fOffsetUp;
67 protected float m_fOffsetForward;
74 protected bool m_bPerlinDens;
76 [
Attribute(
category:
"Perlin", defvalue:
"0",
desc:
"Spawns prefabs if perlin value is above this threshold")]
77 protected float m_fPerlinThreshold;
79 [
Attribute(
category:
"Perlin", defvalue:
"0",
desc:
"Prefab spawn type uses Perlin distribution. Prefabs in the prefab array are stacked up from lower to higher indicies on the Y axis")]
80 protected bool m_bPerlinAssetDistribution;
83 protected bool m_bPerlinSize;
85 [
Attribute(
category:
"Perlin", defvalue:
"40",
desc:
"Perlin frequency, higher values mean smoother transitions")]
86 protected float m_fPerlinFrequency;
89 protected float m_fPerlinSeed;
92 protected float m_fPerlinAmplitude;
95 protected float m_fPerlinOffset;
97 [
Attribute(
category:
"Perlin", defvalue:
"0",
desc:
"Disables asset generation below perlin threshold")]
98 protected bool m_fPerlinThrowAway;
105 protected bool m_bDrawDebug;
109 protected ref array<ref SCR_PrefabGeneratorAssetPoint> m_aPoints = {};
111 protected static ref array<ref Shape> s_aDebugShapes = {};
113 protected static const float PERLIN_STEP_LENGTH = 0.01;
116 protected override bool _WB_OnKeyChanged(BaseContainer src,
string key, BaseContainerList ownerContainers,
IEntity parent)
118 if (!super._WB_OnKeyChanged(src, key, ownerContainers, parent))
124 WorldEditorAPI worldEditorAPI = _WB_GetEditorAPI();
125 if (!worldEditorAPI || worldEditorAPI.UndoOrRedoIsRestoring())
128 IEntitySource thisSrc = worldEditorAPI.EntityToSource(
this);
129 IEntitySource parentSrc = thisSrc.GetParent();
130 BaseContainerTools.WriteToInstance(
this, thisSrc);
137 protected override void OnShapeInitInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity)
139 super.OnShapeInitInternal(shapeEntitySrc, shapeEntity);
142 shapeEntity = ShapeEntity.Cast(_WB_GetEditorAPI().SourceToEntity(shapeEntitySrc));
149 protected float SamplePerlin(
float time,
float frequency = 20,
float seed = 1,
float amplitude = 1,
float phaseOffset = 0)
151 if (frequency == 0 || amplitude == 0)
154 return Math.PerlinNoise(time / frequency, seed * 100, seed * 1000) * amplitude;
159 protected void GenerateAssetPoints(notnull array<ref SCR_PrefabGeneratorPointMeta> metas)
164 stepDistance = PERLIN_STEP_LENGTH;
166 float distanceWalked;
167 if (m_fOffsetForward)
168 stepDistance = m_fOffsetForward;
172 bool firstPoint =
true;
174 for (
int i, countMinus1 = metas.Count() - 1; i < countMinus1; ++i)
176 vector posThis = metas[i].m_vPos;
177 vector forward = vector.Direction(posThis, metas[i + 1].m_vPos);
178 vector lastPos = posThis;
179 float dist = forward.Length();
183 bool draw = metas[i].m_bGenerate;
184 SCR_PrefabGeneratorAssetPoint genPoint;
186 while (space >= stepDistance)
188 float leftOver = space - dist;
197 if (m_fOffsetForward)
199 stepDistance = m_fOffsetForward;
200 moveDist = dist - (space - stepDistance);
207 if (m_fRandomSpacing)
210 if (leftOver> stepDistance)
214 moveDist = stepDistance - leftOver;
217 space -= moveDist + leftOver;
218 distanceWalked += stepDistance;
221 float perlinValue = SamplePerlin(distanceWalked + m_fPerlinOffset, m_fPerlinFrequency, m_fPerlinSeed, m_fPerlinAmplitude);
223 newPos = lastPos + forward.Normalized() * moveDist;
225 genPoint =
new SCR_PrefabGeneratorAssetPoint();
226 genPoint.m_vPos = newPos;
227 genPoint.m_vForward = forward;
228 genPoint.m_fPerlinWeight = perlinValue;
233 if (m_fPerlinThreshold == 1)
234 invValue = Math.InverseLerp(0, 1, perlinValue);
236 invValue = Math.InverseLerp(m_fPerlinThreshold, 1, perlinValue);
238 invValue = Math.Clamp(invValue, 0, 1);
239 stepDistance = Math.Lerp(
m_fDistance, 1, invValue);
242 bool throwAway =
false;
243 if (m_fPerlinThrowAway)
245 if (perlinValue < m_fPerlinThreshold)
247 stepDistance = PERLIN_STEP_LENGTH;
252 genPoint.m_bDraw = draw && !throwAway;
253 m_aPoints.Insert(genPoint);
259 protected array<ref SCR_PrefabGeneratorPointMeta> GetMetaListLineFromOffsetShape()
261 array<ref SCR_PrefabGeneratorPointMeta> result = {};
263 array<vector> anchorPoints = m_ShapeNextPointHelper.GetAnchorPoints();
264 map<int, ref ShapePointDataScriptBase> pointDataMap = GetFirstPointDataMap(PrefabGeneratorPointData);
265 PrefabGeneratorPointData pointData;
266 SCR_PrefabGeneratorPointMeta pointMeta;
267 foreach (
int i, vector point : anchorPoints)
269 pointMeta =
new SCR_PrefabGeneratorPointMeta();
270 pointMeta.m_vPos = point;
272 pointData = PrefabGeneratorPointData.Cast(pointDataMap.Get(i));
274 pointMeta.m_bGenerate = pointData.m_bGenerate;
276 pointMeta.m_bGenerate =
true;
278 result.Insert(pointMeta);
285 protected array<ref SCR_PrefabGeneratorPointMeta> GetMetaListSplineFromShapeOffset()
287 array<ref SCR_PrefabGeneratorPointMeta> result = {};
289 bool generate =
true;
290 SCR_PrefabGeneratorPointMeta tmpMeta;
291 array<int> anchorTesselatedIndices = m_ShapeNextPointHelper.GetAnchorPointIndices();
292 map<int, ref ShapePointDataScriptBase> pointDataMap = GetFirstPointDataMap(PrefabGeneratorPointData);
293 PrefabGeneratorPointData pointData;
294 foreach (
int i, vector tesselatedPoint : m_ShapeNextPointHelper.GetTesselatedPoints())
296 if (anchorTesselatedIndices.Contains(i))
298 pointData = PrefabGeneratorPointData.Cast(pointDataMap.Get(i));
300 generate = pointData.m_bGenerate;
303 tmpMeta =
new SCR_PrefabGeneratorPointMeta();
304 tmpMeta.m_bGenerate = generate;
305 tmpMeta.m_vPos = tesselatedPoint;
306 result.Insert(tmpMeta);
313 protected override void OnShapeChangedInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity, array<vector> mins, array<vector> maxes)
315 s_aDebugShapes.Clear();
321 if (!m_bEnableGeneration)
323 Print(
"Prefab generation is disabled for this shape - tick it back on before saving",
LogLevel.NORMAL);
330 BaseContainerList points = shapeEntitySrc.GetObjectArray(
"Points");
333 array<ref SCR_PrefabGeneratorPointMeta> pointsMetaLine = GetMetaListLineFromOffsetShape();
335 int pointCount = points.Count();
340 shapeEntitySrc.Get(
"IsClosed", isShapeClosed);
342 if (pointCount > 2 && isShapeClosed)
343 pointsMetaLine.Insert(pointsMetaLine[0]);
345 typename shapeTypename = shapeEntitySrc.GetClassName().ToType();
346 if (!m_bOnlyToVertices &&
m_fDistance > 0 && shapeTypename && shapeTypename.IsInherited(PolylineShapeEntity))
348 GenerateAssetPoints(pointsMetaLine);
350 DrawCurveDebug(pointsMetaLine);
352 else if (!m_bOnlyToVertices &&
m_fDistance > 0 && shapeTypename && shapeTypename.IsInherited(SplineShapeEntity))
354 array<ref SCR_PrefabGeneratorPointMeta> pointsMetaSpline = GetMetaListSplineFromShapeOffset();
356 if (pointCount > 2 && isShapeClosed)
357 pointsMetaSpline.Insert(pointsMetaSpline[0]);
359 GenerateAssetPoints(pointsMetaSpline);
362 DrawCurveDebug(pointsMetaSpline);
364 else if (m_bOnlyToVertices)
367 DrawCurveDebug(pointsMetaLine);
370 SCR_PrefabGeneratorAssetPoint genPoint =
new SCR_PrefabGeneratorAssetPoint();
371 genPoint.m_vPos = pointsMetaLine[0].m_vPos;
372 genPoint.m_bDraw = pointsMetaLine[0].m_bGenerate;
374 if (isShapeClosed && pointCount > 2)
375 genPoint.m_vForward = pointsMetaLine[1].m_vPos - pointsMetaLine[pointCount - 1].m_vPos.Normalized();
376 else if (pointCount > 1)
377 genPoint.m_vForward = vector.Direction(pointsMetaLine[0].m_vPos, pointsMetaLine[1].m_vPos).Normalized();
379 m_aPoints.Insert(genPoint);
382 for (
int i = 1, count = pointsMetaLine.Count(); i < count; i++)
384 genPoint =
new SCR_PrefabGeneratorAssetPoint();
385 genPoint.m_vPos = pointsMetaLine[i % pointCount].m_vPos;
387 genPoint.m_bDraw = pointsMetaLine[i].m_bGenerate;
389 if (isShapeClosed || i < count - 1)
390 genPoint.m_vForward = vector.Direction(pointsMetaLine[i - 1].m_vPos, pointsMetaLine[(i + 1) % pointCount].m_vPos).Normalized();
391 else if (i == count - 1)
392 genPoint.m_vForward = vector.Direction(pointsMetaLine[i - 1].m_vPos, pointsMetaLine[i % pointCount].m_vPos).Normalized();
394 m_aPoints.Insert(genPoint);
410 WorldEditorAPI worldEditorAPI = _WB_GetEditorAPI();
411 if (!worldEditorAPI || worldEditorAPI.UndoOrRedoIsRestoring())
414 int prefabNamesCountMinus1 = m_PrefabNames.Count() - 1;
415 if (prefabNamesCountMinus1 < 0)
419 int weightsCountMinus1 = m_Weights.Count() - 1;
420 if (prefabNamesCountMinus1 > weightsCountMinus1)
422 for (
int i = weightsCountMinus1 + 1; i <= prefabNamesCountMinus1; ++i)
425 weightsCountMinus1 ++;
430 foreach (
int i, ResourceName prefabName : m_PrefabNames)
436 bool hasMoreThanZeroWeight;
437 foreach (
float weight : m_Weights)
441 hasMoreThanZeroWeight =
true;
446 if (!hasMoreThanZeroWeight)
449 set<float> mirrorDistances =
new set<float>();
450 foreach (
float mirrorDistance : m_aMirrorDistances)
452 mirrorDistances.Insert(mirrorDistance);
455 if (mirrorDistances.IsEmpty())
456 mirrorDistances.Insert(0);
460 map<ResourceName, ref SCR_RandomisationEditorData> randomValuesMap =
new map<ResourceName, ref SCR_RandomisationEditorData>();
461 SCR_RandomisationEditorData randomnessData;
463 int maxRandomYawStep;
464 bool useYawStep = m_fYawRotationStep > 0;
466 maxRandomYawStep = 360 / m_fYawRotationStep;
468 bool isGeneratorVisible = worldEditorAPI.IsEntityVisible(m_Source);
470 vector upOffset = m_vShapeOffset[1] * vector.Up;
472 IEntitySource entitySource;
473 BaseContainerList editorData;
474 foreach (SCR_PrefabGeneratorAssetPoint localPoint : m_aPoints)
476 if (!localPoint.m_bDraw)
479 vector relPos = localPoint.m_vPos;
482 Math3D.DirectionAndUpMatrix(localPoint.m_vForward, vector.Up, mat);
483 vector right = mat[0];
484 vector
angles = Math3D.MatrixToAngles(mat);
486 if (m_fOffsetVariance != 0)
488 float min = -m_fOffsetVariance * 0.5 + m_fGap * 0.5;
489 float max = m_fOffsetVariance * 0.5 - m_fGap * 0.5;
499 if (offsetRandom < 0)
500 offsetRandom -= m_fGap * 0.5;
502 offsetRandom += m_fGap * 0.5;
504 relPos += offsetRandom * right;
507 if (m_bAlignWithShape)
509 if (m_bUseXAsForward)
519 if (m_bPerlinAssetDistribution)
521 float perlinValue = Math.Clamp(localPoint.m_fPerlinWeight, m_fPerlinThreshold, 1);
522 if (m_fPerlinThreshold == 1)
523 value01 = Math.InverseLerp(0, 1, perlinValue);
525 value01 = Math.InverseLerp(m_fPerlinThreshold, 1, perlinValue);
532 int index = Math.Clamp(SCR_ArrayHelper.GetWeightedIndex(m_Weights, value01), 0, prefabNamesCountMinus1);
533 ResourceName prefabToUse = m_PrefabNames[
index];
535 foreach (
int i,
float mirrorDistance : mirrorDistances)
537 vector worldPos = CoordToParent(relPos + mirrorDistance * right);
538 if (m_bSnapOffsetShapeToTheGround)
539 worldPos[1] = worldEditorAPI.GetTerrainSurfaceY(worldPos[0], worldPos[2]) + m_vShapeOffset[1];
541 worldPos += upOffset;
543 vector finalRelPos = CoordToLocal(worldPos);
545 entitySource = worldEditorAPI.CreateEntity(prefabToUse,
string.Empty, m_iSourceLayerID, m_Source, finalRelPos, rot);
547 if (!randomValuesMap.Find(prefabToUse, randomnessData))
549 randomnessData = SCR_RandomisationEditorData.CreateFromEntitySource(entitySource);
550 if (randomnessData && (m_bAlignWithShape || useYawStep))
551 randomnessData.m_bRandomYaw =
false;
553 randomValuesMap.Insert(prefabToUse, randomnessData);
558 if (m_bPerlinSize && i == 0)
560 float perlinValue = Math.Clamp(localPoint.m_fPerlinWeight, m_fPerlinThreshold, 1);
563 if (m_fPerlinThreshold == 1)
564 invValue = Math.InverseLerp(0, 1, perlinValue);
566 invValue = Math.InverseLerp(m_fPerlinThreshold, 1, perlinValue);
568 float resultScale = Math.Lerp(randomnessData.m_vRandomScale[0], randomnessData.m_vRandomScale[1], invValue);
569 randomnessData.m_vRandomScale = { resultScale, resultScale, 0 };
578 float stepYaw = Math.Repeat(
m_RandomGenerator.RandInt(0, maxRandomYawStep) * m_fYawRotationStep, 360);
579 if (entitySource.Get(
"angles",
angles))
582 worldEditorAPI.SetVariableValue(entitySource, null,
"angles",
angles.ToString(
false));
586 if (!isGeneratorVisible)
587 worldEditorAPI.SetEntityVisible(entitySource,
false,
false);
589 if (mirrorDistance == 0)
592 if (m_fOffsetVariance != 0)
594 float offsetRandom =
m_RandomGenerator.RandFloatXY(-m_fOffsetVariance * 0.5 + m_fGap * 0.5, m_fOffsetVariance * 0.5 - m_fGap * 0.5);
595 if (offsetRandom < 0)
596 offsetRandom -= m_fGap * 0.5;
598 offsetRandom += m_fGap * 0.5;
600 relPos = localPoint.m_vPos + offsetRandom * right;
603 worldPos = CoordToParent(relPos + mirrorDistance * -right);
604 if (m_bSnapOffsetShapeToTheGround)
605 worldPos[1] = worldEditorAPI.GetTerrainSurfaceY(worldPos[0], worldPos[2]) + m_vShapeOffset[1];
607 worldPos += upOffset;
609 finalRelPos = CoordToLocal(worldPos);
611 if (m_bMirrorRandomPrefabs && !m_bPerlinAssetDistribution)
614 index = Math.Clamp(SCR_ArrayHelper.GetWeightedIndex(m_Weights, value01), 0, prefabNamesCountMinus1);
615 prefabToUse = m_PrefabNames[
index];
618 entitySource = worldEditorAPI.CreateEntity(prefabToUse,
string.Empty, m_iSourceLayerID, m_Source, finalRelPos, rot);
625 float stepYaw = Math.Repeat(
m_RandomGenerator.RandInt(0, maxRandomYawStep) * m_fYawRotationStep, 360);
626 if (entitySource.Get(
"angles",
angles))
629 worldEditorAPI.SetVariableValue(entitySource, null,
"angles",
string.Format(
"%1 %2 %3",
angles[0],
angles[1],
angles[2]));
633 if (!isGeneratorVisible)
634 worldEditorAPI.SetEntityVisible(entitySource,
false,
false);
641 protected void DrawCurveDebug(array<ref SCR_PrefabGeneratorPointMeta> metas)
643 const int DEBUG_CURVE_LINE_SIZE = 8192;
644 const float DEBUG_Y_MULTIPLIER = 5;
645 static vector m_PerlinDebugLine[DEBUG_CURVE_LINE_SIZE];
646 static vector m_ZeroDebugLine[DEBUG_CURVE_LINE_SIZE];
647 static vector m_EdgeDebugLine[DEBUG_CURVE_LINE_SIZE];
648 static vector m_ThresholdDebugLine[DEBUG_CURVE_LINE_SIZE];
650 const float stepDistance = 0.1;
651 float distanceWalked;
655 array<vector> line = {};
659 GetWorldTransform(matWrld);
662 for (
int countMinus1 = metas.Count() - 1; i < countMinus1; ++i)
664 vector posThis = metas[i].m_vPos;
665 vector lastPos = posThis;
666 vector forward = vector.Direction(posThis, metas[i + 1].m_vPos);
667 float dist = forward.Length();
670 m_ZeroDebugLine[i] = posThis.Multiply4(matWrld);
672 if (i == countMinus1 - 1)
673 m_ZeroDebugLine[i + 1] = metas[i + 1].m_vPos.Multiply4(matWrld);
675 while (space >= stepDistance)
677 float leftOver = space - dist;
681 moveDist = stepDistance - leftOver;
683 space -= moveDist + leftOver;
684 distanceWalked += stepDistance;
686 vector perlinPointPos;
688 stepPos = lastPos + forward.Normalized() * moveDist;
692 Math3D.DirectionAndUpMatrix(forward, vector.Up, mat);
693 vector right = mat[0];
695 float perlinValue = SamplePerlin(distanceWalked + m_fPerlinOffset, m_fPerlinFrequency, m_fPerlinSeed, m_fPerlinAmplitude);
696 perlinPointPos = stepPos + right * perlinValue * DEBUG_Y_MULTIPLIER;
698 if (itemsNum < DEBUG_CURVE_LINE_SIZE)
700 m_PerlinDebugLine[itemsNum] = perlinPointPos.Multiply4(matWrld);
701 m_EdgeDebugLine[itemsNum] = (stepPos + right * DEBUG_Y_MULTIPLIER).Multiply4(matWrld);
702 m_ThresholdDebugLine[itemsNum] = (stepPos + right * DEBUG_Y_MULTIPLIER * m_fPerlinThreshold).Multiply4(matWrld);
708 s_aDebugShapes.Insert(Shape.CreateLines(
ARGB(255, 255, 255, 0),
ShapeFlags.NOZBUFFER, m_PerlinDebugLine, itemsNum));
709 s_aDebugShapes.Insert(Shape.CreateLines(
ARGB(255, 0, 255, 0),
ShapeFlags.NOZBUFFER, m_ZeroDebugLine, i + 1));
710 s_aDebugShapes.Insert(Shape.CreateLines(
ARGB(255, 255, 0, 0),
ShapeFlags.NOZBUFFER, m_EdgeDebugLine, itemsNum));
711 s_aDebugShapes.Insert(Shape.CreateLines(
ARGB(255, 0, 0, 255),
ShapeFlags.NOZBUFFER, m_ThresholdDebugLine, itemsNum));
718 protected void PrefabGeneratorEntity(IEntitySource src,
IEntity parent);
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 ...
SCR_DestructionSynchronizationComponentClass ScriptComponentClass int index
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
enum EVehicleType IEntity
proto void Print(void var, LogLevel level=LogLevel.NORMAL)
Prints content of variable to console/log.
LogLevel
Enum with severity of the logging message.
SCR_FieldOfViewSettings Attribute
void OnShapeInitInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity)
proto external void OnShapeChanged(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity, array< vector > mins, array< vector > maxes)
void OnShapeChangedInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity, array< vector > mins, array< vector > maxes)
proto int ARGB(int a, int r, int g, int b)