Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
PrefabGeneratorEntity.c
Go to the documentation of this file.
1[EntityEditorProps(category: "GameScripted/Generators", description: "Prefab Generator", dynamicBox: true, visible: false)]
5
6// TODO: make it use SCR_ObstacleDetector?
7class PrefabGeneratorEntity : SCR_LineTerrainShaperGeneratorBaseEntity
8{
9 /*
10 Category: Mirrors
11 */
12
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;
15
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;
18
19 /*
20 Category: Prefabs
21 */
22
23 [Attribute(category: "Prefabs", uiwidget: UIWidgets.ResourcePickerThumbnail, desc: "Prefab list", params: "et")]
24 protected ref array<ResourceName> m_PrefabNames; // m_a
25
26 [Attribute(category: "Prefabs", defvalue: "0", desc: "Weights", params: "0 inf")]
27 protected ref array<float> m_Weights; // m_a
28
29 [Attribute(category: "Prefabs", defvalue: "0", desc: "Only place Prefabs to shape's anchor points")]
30 protected bool m_bOnlyToVertices;
31
32 [Attribute(category: "Prefabs", defvalue: "5", desc: "Distance between spawned assets along the spline/polyline", params: "0 inf")]
33 protected float m_fDistance;
34
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;
37
38 [Attribute(category: "Prefabs", defvalue: "0", desc: "Only when aligning with shape")]
39 protected bool m_bUseXAsForward;
40
41 [Attribute(category: "Prefabs", defvalue: "0", desc: "Rotate 180°")]
42 protected bool m_bFlipForward;
43
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;
46
47 /*
48 Category: Offset
49 */
50
51 [Attribute(uiwidget: UIWidgets.None)] // obsolete, kept for Prefabs and layers retrocompatibility (since 2024-10-01)
52 protected float m_fOffsetRight;
53
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;
56
57 [Attribute(category: "Offset", defvalue: "0", desc: "Gap from the centerline")]
58 protected float m_fGap;
59
60 [Attribute(category: "Offset", defvalue: "0", desc: "Random Spacing Offset")]
61 protected bool m_fRandomSpacing; // m_b
62
63 [Attribute(uiwidget: UIWidgets.None)] // obsolete, kept for Prefabs and layers retrocompatibility (since 2024-10-01)
64 protected float m_fOffsetUp;
65
66 [Attribute(category: "Offset", defvalue: "0", desc: "Forward offset")]
67 protected float m_fOffsetForward;
68
69 /*
70 Category: Perlin
71 */
72
73 [Attribute(category: "Perlin", defvalue: "0", desc: "Prefab spawn density uses Perlin distribution")]
74 protected bool m_bPerlinDens;
75
76 [Attribute(category: "Perlin", defvalue: "0", desc: "Spawns prefabs if perlin value is above this threshold")]
77 protected float m_fPerlinThreshold;
78
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;
81
82 [Attribute(category: "Perlin", defvalue: "0", desc: "Prefab size uses Perlin")]
83 protected bool m_bPerlinSize;
84
85 [Attribute(category: "Perlin", defvalue: "40", desc: "Perlin frequency, higher values mean smoother transitions")]
86 protected float m_fPerlinFrequency;
87
88 [Attribute(category: "Perlin", defvalue: "0", desc: "Perlin seed", params: "0 1000")]
89 protected float m_fPerlinSeed;
90
91 [Attribute(category: "Perlin", defvalue: "1", desc: "Perlin Amplitude")]
92 protected float m_fPerlinAmplitude;
93
94 [Attribute(category: "Perlin", defvalue: "0", desc: "Perlin Phase Offset")]
95 protected float m_fPerlinOffset;
96
97 [Attribute(category: "Perlin", defvalue: "0", desc: "Disables asset generation below perlin threshold")]
98 protected bool m_fPerlinThrowAway; // m_b
99
100 /*
101 Category: Debug
102 */
103
104 [Attribute(category: "Debug", defvalue: "0", desc: "Draw developer debug")]
105 protected bool m_bDrawDebug;
106
107#ifdef WORKBENCH
108
109 protected ref array<ref SCR_PrefabGeneratorAssetPoint> m_aPoints = {};
110
111 protected static ref array<ref Shape> s_aDebugShapes = {};
112
113 protected static const float PERLIN_STEP_LENGTH = 0.01;
114
115 //------------------------------------------------------------------------------------------------
116 protected override bool _WB_OnKeyChanged(BaseContainer src, string key, BaseContainerList ownerContainers, IEntity parent)
117 {
118 if (!super._WB_OnKeyChanged(src, key, ownerContainers, parent))
119 return false;
120
121 if (key == "coords")
122 return false;
123
124 WorldEditorAPI worldEditorAPI = _WB_GetEditorAPI();
125 if (!worldEditorAPI || worldEditorAPI.UndoOrRedoIsRestoring())
126 return false;
127
128 IEntitySource thisSrc = worldEditorAPI.EntityToSource(this);
129 IEntitySource parentSrc = thisSrc.GetParent();
130 BaseContainerTools.WriteToInstance(this, thisSrc);
131
132 OnShapeChanged(parentSrc, ShapeEntity.Cast(parent), {}, {});
133 return true;
134 }
135
136 //------------------------------------------------------------------------------------------------
137 protected override void OnShapeInitInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity)
138 {
139 super.OnShapeInitInternal(shapeEntitySrc, shapeEntity);
140
141 if (!shapeEntity)
142 shapeEntity = ShapeEntity.Cast(_WB_GetEditorAPI().SourceToEntity(shapeEntitySrc));
143
144 OnShapeChanged(shapeEntitySrc, shapeEntity, {}, {});
145 }
146
147 //------------------------------------------------------------------------------------------------
149 protected float SamplePerlin(float time, float frequency = 20, float seed = 1, float amplitude = 1, float phaseOffset = 0)
150 {
151 if (frequency == 0 || amplitude == 0) // division/multiplication by zero protection
152 return 0;
153
154 return Math.PerlinNoise(time / frequency, seed * 100, seed * 1000) * amplitude;
155 }
156
157 //------------------------------------------------------------------------------------------------
159 protected void GenerateAssetPoints(notnull array<ref SCR_PrefabGeneratorPointMeta> metas)
160 {
161 float stepDistance = m_fDistance;
162
163 if (m_bPerlinDens)
164 stepDistance = PERLIN_STEP_LENGTH;
165
166 float distanceWalked;
167 if (m_fOffsetForward)
168 stepDistance = m_fOffsetForward;
169
170 float space;
171 float moveDist;
172 bool firstPoint = true;
173
174 for (int i, countMinus1 = metas.Count() - 1; i < countMinus1; ++i)
175 {
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();
180 space += dist;
181
182 // check for disabled generation on line segment
183 bool draw = metas[i].m_bGenerate;
184 SCR_PrefabGeneratorAssetPoint genPoint;
185
186 while (space >= stepDistance)
187 {
188 float leftOver = space - dist;
189 if (leftOver < 0)
190 leftOver = 0;
191
192 if (firstPoint)
193 {
194 moveDist = 0;
195 stepDistance = 0;
196 firstPoint = false;
197 if (m_fOffsetForward)
198 {
199 stepDistance = m_fOffsetForward;
200 moveDist = dist - (space - stepDistance);
201 }
202 }
203 else
204 {
205 stepDistance = m_fDistance;
206
207 if (m_fRandomSpacing)
208 {
209 stepDistance = m_fDistance + m_RandomGenerator.RandFloatXY(-m_fDistance * 0.5, m_fDistance * 0.5);
210 if (leftOver> stepDistance)
211 leftOver = 0;
212 }
213
214 moveDist = stepDistance - leftOver;
215 }
216
217 space -= moveDist + leftOver;
218 distanceWalked += stepDistance;
219
220 vector newPos;
221 float perlinValue = SamplePerlin(distanceWalked + m_fPerlinOffset, m_fPerlinFrequency, m_fPerlinSeed, m_fPerlinAmplitude);
222
223 newPos = lastPos + forward.Normalized() * moveDist;
224 lastPos = newPos;
225 genPoint = new SCR_PrefabGeneratorAssetPoint();
226 genPoint.m_vPos = newPos;
227 genPoint.m_vForward = forward;
228 genPoint.m_fPerlinWeight = perlinValue;
229
230 if (m_bPerlinDens)
231 {
232 float invValue;
233 if (m_fPerlinThreshold == 1) // prevent an exception
234 invValue = Math.InverseLerp(0, 1, perlinValue);
235 else
236 invValue = Math.InverseLerp(m_fPerlinThreshold, 1, perlinValue);
237
238 invValue = Math.Clamp(invValue, 0, 1);
239 stepDistance = Math.Lerp(m_fDistance, 1, invValue); // TODO: expose values
240 }
241
242 bool throwAway = false;
243 if (m_fPerlinThrowAway)
244 {
245 if (perlinValue < m_fPerlinThreshold)
246 {
247 stepDistance = PERLIN_STEP_LENGTH;
248 throwAway = true;
249 }
250 }
251
252 genPoint.m_bDraw = draw && !throwAway;
253 m_aPoints.Insert(genPoint);
254 }
255 }
256 }
257
258 //------------------------------------------------------------------------------------------------
259 protected array<ref SCR_PrefabGeneratorPointMeta> GetMetaListLineFromOffsetShape()
260 {
261 array<ref SCR_PrefabGeneratorPointMeta> result = {};
262
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)
268 {
269 pointMeta = new SCR_PrefabGeneratorPointMeta();
270 pointMeta.m_vPos = point;
271
272 pointData = PrefabGeneratorPointData.Cast(pointDataMap.Get(i));
273 if (pointData)
274 pointMeta.m_bGenerate = pointData.m_bGenerate;
275 else
276 pointMeta.m_bGenerate = true;
277
278 result.Insert(pointMeta);
279 }
280
281 return result;
282 }
283
284 //------------------------------------------------------------------------------------------------
285 protected array<ref SCR_PrefabGeneratorPointMeta> GetMetaListSplineFromShapeOffset()
286 {
287 array<ref SCR_PrefabGeneratorPointMeta> result = {};
288
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())
295 {
296 if (anchorTesselatedIndices.Contains(i))
297 {
298 pointData = PrefabGeneratorPointData.Cast(pointDataMap.Get(i));
299 if (pointData)
300 generate = pointData.m_bGenerate;
301 }
302
303 tmpMeta = new SCR_PrefabGeneratorPointMeta();
304 tmpMeta.m_bGenerate = generate;
305 tmpMeta.m_vPos = tesselatedPoint;
306 result.Insert(tmpMeta);
307 }
308
309 return result;
310 }
311
312 //------------------------------------------------------------------------------------------------
313 protected override void OnShapeChangedInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity, array<vector> mins, array<vector> maxes)
314 {
315 s_aDebugShapes.Clear();
316 m_aPoints.Clear();
317
318 if (!shapeEntitySrc)
319 return;
320
321 if (!m_bEnableGeneration) // should rather be in Generate()
322 {
323 Print("Prefab generation is disabled for this shape - tick it back on before saving", LogLevel.NORMAL);
324 return;
325 }
326
327 SetSeed();
328
329 // TODO: move this code to a "PrepareData" method or something
330 BaseContainerList points = shapeEntitySrc.GetObjectArray("Points");
331 if (points != null) // TODO: save a scope
332 {
333 array<ref SCR_PrefabGeneratorPointMeta> pointsMetaLine = GetMetaListLineFromOffsetShape();
334
335 int pointCount = points.Count();
336 if (pointCount < 1)
337 return;
338
339 bool isShapeClosed;
340 shapeEntitySrc.Get("IsClosed", isShapeClosed);
341
342 if (pointCount > 2 && isShapeClosed)
343 pointsMetaLine.Insert(pointsMetaLine[0]);
344
345 typename shapeTypename = shapeEntitySrc.GetClassName().ToType();
346 if (!m_bOnlyToVertices && m_fDistance > 0 && shapeTypename && shapeTypename.IsInherited(PolylineShapeEntity))
347 {
348 GenerateAssetPoints(pointsMetaLine);
349 if (m_bDrawDebug)
350 DrawCurveDebug(pointsMetaLine);
351 }
352 else if (!m_bOnlyToVertices && m_fDistance > 0 && shapeTypename && shapeTypename.IsInherited(SplineShapeEntity))
353 {
354 array<ref SCR_PrefabGeneratorPointMeta> pointsMetaSpline = GetMetaListSplineFromShapeOffset();
355
356 if (pointCount > 2 && isShapeClosed)
357 pointsMetaSpline.Insert(pointsMetaSpline[0]);
358
359 GenerateAssetPoints(pointsMetaSpline);
360
361 if (m_bDrawDebug)
362 DrawCurveDebug(pointsMetaSpline);
363 }
364 else if (m_bOnlyToVertices) // TODO: move up so there are no !m_bOnlyToVertices checks
365 {
366 if (m_bDrawDebug)
367 DrawCurveDebug(pointsMetaLine);
368
369 // First point special care
370 SCR_PrefabGeneratorAssetPoint genPoint = new SCR_PrefabGeneratorAssetPoint();
371 genPoint.m_vPos = pointsMetaLine[0].m_vPos;
372 genPoint.m_bDraw = pointsMetaLine[0].m_bGenerate;
373
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();
378
379 m_aPoints.Insert(genPoint);
380
381 // Middle and end points
382 for (int i = 1, count = pointsMetaLine.Count(); i < count; i++)
383 {
384 genPoint = new SCR_PrefabGeneratorAssetPoint();
385 genPoint.m_vPos = pointsMetaLine[i % pointCount].m_vPos;
386
387 genPoint.m_bDraw = pointsMetaLine[i].m_bGenerate;
388
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();
393
394 m_aPoints.Insert(genPoint);
395 }
396 }
397 else
398 {
399 return;
400 }
401 }
402
403 Generate();
404 }
405
406 //------------------------------------------------------------------------------------------------
408 protected void Generate()
409 {
410 WorldEditorAPI worldEditorAPI = _WB_GetEditorAPI();
411 if (!worldEditorAPI || worldEditorAPI.UndoOrRedoIsRestoring())
412 return;
413
414 int prefabNamesCountMinus1 = m_PrefabNames.Count() - 1;
415 if (prefabNamesCountMinus1 < 0)
416 return;
417
418 // adjust weights array size with 1
419 int weightsCountMinus1 = m_Weights.Count() - 1;
420 if (prefabNamesCountMinus1 > weightsCountMinus1)
421 {
422 for (int i = weightsCountMinus1 + 1; i <= prefabNamesCountMinus1; ++i)
423 {
424 m_Weights.Insert(1);
425 weightsCountMinus1 ++;
426 }
427 }
428
429 // set empty Prefabs a weight of zero
430 foreach (int i, ResourceName prefabName : m_PrefabNames)
431 {
432 if (!prefabName) // .IsEmpty()
433 m_Weights[i] = 0;
434 }
435
436 bool hasMoreThanZeroWeight;
437 foreach (float weight : m_Weights)
438 {
439 if (weight > 0)
440 {
441 hasMoreThanZeroWeight = true;
442 break;
443 }
444 }
445
446 if (!hasMoreThanZeroWeight)
447 return;
448
449 set<float> mirrorDistances = new set<float>();
450 foreach (float mirrorDistance : m_aMirrorDistances)
451 {
452 mirrorDistances.Insert(mirrorDistance);
453 }
454
455 if (mirrorDistances.IsEmpty())
456 mirrorDistances.Insert(0);
457
458 DeleteAllChildren();
459
460 map<ResourceName, ref SCR_RandomisationEditorData> randomValuesMap = new map<ResourceName, ref SCR_RandomisationEditorData>();
461 SCR_RandomisationEditorData randomnessData;
462
463 int maxRandomYawStep;
464 bool useYawStep = m_fYawRotationStep > 0;
465 if (useYawStep)
466 maxRandomYawStep = 360 / m_fYawRotationStep; // int, so it floors the value (2.9 = 2)
467
468 bool isGeneratorVisible = worldEditorAPI.IsEntityVisible(m_Source);
469
470 vector upOffset = m_vShapeOffset[1] * vector.Up;
471
472 IEntitySource entitySource;
473 BaseContainerList editorData;
474 foreach (SCR_PrefabGeneratorAssetPoint localPoint : m_aPoints)
475 {
476 if (!localPoint.m_bDraw)
477 continue;
478
479 vector relPos = localPoint.m_vPos;
480 vector rot;
481 vector mat[4];
482 Math3D.DirectionAndUpMatrix(localPoint.m_vForward, vector.Up, mat);
483 vector right = mat[0];
484 vector angles = Math3D.MatrixToAngles(mat);
485
486 if (m_fOffsetVariance != 0)
487 {
488 float min = -m_fOffsetVariance * 0.5 + m_fGap * 0.5;
489 float max = m_fOffsetVariance * 0.5 - m_fGap * 0.5;
490 float offsetRandom;
491 if (min == max)
492 offsetRandom = max;
493 else
494 if (min < max)
495 offsetRandom = m_RandomGenerator.RandFloatXY(min, max);
496 else
497 offsetRandom = m_RandomGenerator.RandFloatXY(max, min);
498
499 if (offsetRandom < 0)
500 offsetRandom -= m_fGap * 0.5;
501 else
502 offsetRandom += m_fGap * 0.5;
503
504 relPos += offsetRandom * right;
505 }
506
507 if (m_bAlignWithShape)
508 {
509 if (m_bUseXAsForward)
510 angles[0] = angles[0] - 90;
511
512 if (m_bFlipForward)
513 angles[0] = angles[0] + 180;
514
515 rot = { angles[1], angles[0], angles[2] };
516 }
517
518 float value01;
519 if (m_bPerlinAssetDistribution)
520 {
521 float perlinValue = Math.Clamp(localPoint.m_fPerlinWeight, m_fPerlinThreshold, 1);
522 if (m_fPerlinThreshold == 1) // prevent an exception
523 value01 = Math.InverseLerp(0, 1, perlinValue);
524 else
525 value01 = Math.InverseLerp(m_fPerlinThreshold, 1, perlinValue);
526 }
527 else
528 {
529 value01 = m_RandomGenerator.RandFloat01();
530 }
531
532 int index = Math.Clamp(SCR_ArrayHelper.GetWeightedIndex(m_Weights, value01), 0, prefabNamesCountMinus1);
533 ResourceName prefabToUse = m_PrefabNames[index];
534
535 foreach (int i, float mirrorDistance : mirrorDistances)
536 {
537 vector worldPos = CoordToParent(relPos + mirrorDistance * right); // right mirror element
538 if (m_bSnapOffsetShapeToTheGround)
539 worldPos[1] = worldEditorAPI.GetTerrainSurfaceY(worldPos[0], worldPos[2]) + m_vShapeOffset[1];
540 else
541 worldPos += upOffset;
542
543 vector finalRelPos = CoordToLocal(worldPos);
544
545 entitySource = worldEditorAPI.CreateEntity(prefabToUse, string.Empty, m_iSourceLayerID, m_Source, finalRelPos, rot);
546
547 if (!randomValuesMap.Find(prefabToUse, randomnessData))
548 {
549 randomnessData = SCR_RandomisationEditorData.CreateFromEntitySource(entitySource);
550 if (randomnessData && (m_bAlignWithShape || useYawStep))
551 randomnessData.m_bRandomYaw = false;
552
553 randomValuesMap.Insert(prefabToUse, randomnessData);
554 }
555
556 if (randomnessData)
557 {
558 if (m_bPerlinSize && i == 0) // set "random" scale to Perlin value
559 {
560 float perlinValue = Math.Clamp(localPoint.m_fPerlinWeight, m_fPerlinThreshold, 1);
561
562 float invValue;
563 if (m_fPerlinThreshold == 1) // prevent an exception
564 invValue = Math.InverseLerp(0, 1, perlinValue);
565 else
566 invValue = Math.InverseLerp(m_fPerlinThreshold, 1, perlinValue);
567
568 float resultScale = Math.Lerp(randomnessData.m_vRandomScale[0], randomnessData.m_vRandomScale[1], invValue);
569 randomnessData.m_vRandomScale = { resultScale, resultScale, 0 };
570 }
571
572 randomnessData.RandomiseExt(worldEditorAPI, entitySource, m_RandomGenerator);
573 }
574
575 if (useYawStep)
576 {
577 // I never knew my real yaw
578 float stepYaw = Math.Repeat(m_RandomGenerator.RandInt(0, maxRandomYawStep) * m_fYawRotationStep, 360);
579 if (entitySource.Get("angles", angles))
580 {
581 angles[1] = Math.Repeat(angles[1] + stepYaw, 360);
582 worldEditorAPI.SetVariableValue(entitySource, null, "angles", angles.ToString(false));
583 }
584 }
585
586 if (!isGeneratorVisible)
587 worldEditorAPI.SetEntityVisible(entitySource, false, false);
588
589 if (mirrorDistance == 0)
590 continue;
591
592 if (m_fOffsetVariance != 0)
593 {
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;
597 else
598 offsetRandom += m_fGap * 0.5;
599
600 relPos = localPoint.m_vPos + offsetRandom * right;
601 }
602
603 worldPos = CoordToParent(relPos + mirrorDistance * -right); // left mirror element
604 if (m_bSnapOffsetShapeToTheGround)
605 worldPos[1] = worldEditorAPI.GetTerrainSurfaceY(worldPos[0], worldPos[2]) + m_vShapeOffset[1];
606 else
607 worldPos += upOffset;
608
609 finalRelPos = CoordToLocal(worldPos);
610
611 if (m_bMirrorRandomPrefabs && !m_bPerlinAssetDistribution)
612 {
613 value01 = m_RandomGenerator.RandFloat01();
614 index = Math.Clamp(SCR_ArrayHelper.GetWeightedIndex(m_Weights, value01), 0, prefabNamesCountMinus1);
615 prefabToUse = m_PrefabNames[index];
616 }
617
618 entitySource = worldEditorAPI.CreateEntity(prefabToUse, string.Empty, m_iSourceLayerID, m_Source, finalRelPos, rot);
619
620 if (randomnessData)
621 randomnessData.RandomiseExt(worldEditorAPI, entitySource, m_RandomGenerator);
622
623 if (useYawStep)
624 {
625 float stepYaw = Math.Repeat(m_RandomGenerator.RandInt(0, maxRandomYawStep) * m_fYawRotationStep, 360);
626 if (entitySource.Get("angles", angles))
627 {
628 angles[1] = Math.Repeat(angles[1] + stepYaw, 360);
629 worldEditorAPI.SetVariableValue(entitySource, null, "angles", string.Format("%1 %2 %3", angles[0], angles[1], angles[2]));
630 }
631 }
632
633 if (!isGeneratorVisible)
634 worldEditorAPI.SetEntityVisible(entitySource, false, false);
635 }
636 }
637 }
638
639 //------------------------------------------------------------------------------------------------
641 protected void DrawCurveDebug(array<ref SCR_PrefabGeneratorPointMeta> metas)
642 {
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];
649
650 const float stepDistance = 0.1;
651 float distanceWalked;
652 float space;
653 float moveDist;
654
655 array<vector> line = {};
656 int itemsNum;
657
658 vector matWrld[4];
659 GetWorldTransform(matWrld);
660
661 int i;
662 for (int countMinus1 = metas.Count() - 1; i < countMinus1; ++i)
663 {
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();
668 space += dist;
669
670 m_ZeroDebugLine[i] = posThis.Multiply4(matWrld);
671
672 if (i == countMinus1 - 1)
673 m_ZeroDebugLine[i + 1] = metas[i + 1].m_vPos.Multiply4(matWrld);
674
675 while (space >= stepDistance)
676 {
677 float leftOver = space - dist;
678 if (leftOver < 0)
679 leftOver = 0;
680
681 moveDist = stepDistance - leftOver;
682
683 space -= moveDist + leftOver;
684 distanceWalked += stepDistance;
685 vector stepPos;
686 vector perlinPointPos;
687
688 stepPos = lastPos + forward.Normalized() * moveDist;
689 lastPos = stepPos;
690
691 vector mat[4];
692 Math3D.DirectionAndUpMatrix(forward, vector.Up, mat);
693 vector right = mat[0];
694
695 float perlinValue = SamplePerlin(distanceWalked + m_fPerlinOffset, m_fPerlinFrequency, m_fPerlinSeed, m_fPerlinAmplitude);
696 perlinPointPos = stepPos + right * perlinValue * DEBUG_Y_MULTIPLIER;
697
698 if (itemsNum < DEBUG_CURVE_LINE_SIZE)
699 {
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);
703 itemsNum++;
704 }
705 }
706 }
707
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));
712 }
713
714#endif // WORKBENCH
715
716 //------------------------------------------------------------------------------------------------
717 // constructor
718 protected void PrefabGeneratorEntity(IEntitySource src, IEntity parent);
719}
ref array< string > angles
params precision
float m_fDistance
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
void Generate()
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.
Definition LogLevel.c:14
ShapeFlags
Definition ShapeFlags.c:13
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)