Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
WallGeneratorEntity.c
Go to the documentation of this file.
1 [EntityEditorProps(category: "GameLib/Scripted/Generator", description: "WallGeneratorEntity", dynamicBox: true, visible: false)]
3 {
4 }
5 
6 class WallGeneratorEntity : SCR_GeneratorBaseEntity
7 {
8  /*
9  Middle Object
10  */
11 
12  [Attribute(defvalue: "1", desc: "Enable middle object", category: "Middle Object")]
13  protected bool m_bEnableMiddleObject;
14 
15  [Attribute("", UIWidgets.ResourcePickerThumbnail, "Middle Object Prefab", "et", category: "Middle Object")]
16  protected ResourceName MiddleObject;
17 
18  [Attribute(defvalue: "1", desc: "Place middle prefab at vertex", category: "Middle Object")]
19  protected bool PlaceMiddleAtVertex;
20 
21  [Attribute(defvalue: "0", desc: "Place middle prefab at vertex only", category: "Middle Object")]
22  protected bool PlaceMiddleAtVertexOnly;
23 
24  [Attribute("0", UIWidgets.Slider, "Middle object pre-padding, essentially a gap between previous prefab and this", params: "-5 5 0.01", category: "Middle Object")]
25  protected float MiddleObjectPrePadding;
26 
27  [Attribute("0", UIWidgets.Slider,"Middle object offset to the side", params: "-5 5 0.01", category: "Middle Object")]
28  protected float MiddleObjectOffsetRight;
29 
30  [Attribute("0", UIWidgets.Slider, "Middle object post-padding, essentially a gap between this asset and the next one", params: "-5 5 0.01", category: "Middle Object")]
31  protected float MiddleObjectPostPadding;
32 
33  [Attribute("0", UIWidgets.Slider, "Middle object offset up/down", params: "-10 10 0.01", category: "Middle Object")]
34  protected float MiddleObjectOffsetUp;
35 
36  /*
37  First Object
38  */
39 
40  [Attribute(defvalue: "1", desc: "Enable first object", category: "First Object")]
41  protected bool m_bEnableFirstObject;
42 
43  [Attribute("", UIWidgets.ResourcePickerThumbnail, "First Object Prefab", "et", category: "First Object")]
44  protected ResourceName FirstObject;
45 
46  [Attribute("0", UIWidgets.Slider, "First object pre-padding, essentially a gap between previous vertex first object",params: "-5 5 0.01", category: "First Object")]
47  protected float FirstObjectPrePadding;
48 
49  [Attribute("0", UIWidgets.Slider, "First object post-padding, essentially a gap between first object and the following one", params: "-5 5 0.01", category: "First Object")]
50  protected float FirstObjectPostPadding;
51 
52  [Attribute("0", UIWidgets.Slider, "First object offset to the side", params: "-5 5 0.01", category: "First Object")]
53  protected float FirstObjectOffsetRight;
54 
55  [Attribute("0", UIWidgets.Slider, "First object offset up/down", params: "-10 10 0.01", category: "First Object")]
56  protected float FirstObjectOffsetUp;
57 
58  /*
59  Last Object
60  */
61 
62  [Attribute(defvalue: "1", desc: "Enable last object", category: "Last Object")]
63  protected bool m_bEnableLastObject;
64 
65  [Attribute("", UIWidgets.ResourcePickerThumbnail, "Last Object Prefab", "et", category: "Last Object")]
66  protected ResourceName LastObject;
67 
68  [Attribute("0", UIWidgets.Slider, "Last object pre-padding, essentially a gap between previous vertex first object",params: "-5 5 0.01", category: "Last Object")]
69  protected float LastObjectPrePadding;
70 
71  [Attribute("0", UIWidgets.Slider, "Last object post-padding, essentially a gap between first object and the following one", params: "-5 5 0.01", category: "Last Object")]
72  protected float LastObjectPostPadding;
73 
74  [Attribute("0", UIWidgets.Slider,"Last object offset to the side", params: "-5 5 0.01", category: "Last Object")]
75  protected float LastObjectOffsetRight;
76 
77  [Attribute("0", UIWidgets.Slider, "Last object offset up/down", params: "-10 10 0.01", category: "Last Object")]
78  protected float LastObjectOffsetUp;
79 
80  /*
81  Global
82  */
83 
84  [Attribute("0", UIWidgets.Slider, "Global object pre-padding, essentially a gap between previous prefab and this", params: "-2 2 0.01", category: "Global")]
85  protected float PrePadding;
86 
87  [Attribute("0", UIWidgets.Slider, "Allow pre-padding on first wall asset in each line segment", params: "-2 2 0.01", category: "Global")]
88  protected float PostPadding;
89 
90  [Attribute("0.5", UIWidgets.Slider, "Allow overshooting the segment line by this amount when placing assets", params: "-5 5 0.01", category: "Global")]
91  protected float m_fOvershoot;
92 
93  [Attribute("0", UIWidgets.Slider, "Objects offset to the side", params: "-5 5 0.01", category: "Global")]
94  protected float m_fOffsetRight;
95 
96  [Attribute("0", UIWidgets.Slider, "Object offset up/down", params: "-5 5 0.01", category: "Global")]
97  protected float m_fOffsetUp;
98 
99  [Attribute(defvalue: "", uiwidget: UIWidgets.Object, "Contains wall groups which group Wall/Weight pairs by length", category: "Global")]
100  protected ref array<ref WallLengthGroup> m_aWallGroups;
101 
102  /*
103  Other
104  */
105 
106  [Attribute(defvalue: "1", desc: "Allow pre-padding on first wall asset in each line segment", category: "Other")]
107  protected bool PrePadFirst;
108 
109  [Attribute(defvalue: "0", desc: "Copy the polyline precisely while sacrificing wall assets contact", category: "Other")]
110  protected bool ExactPlacement;
111 
112  [Attribute(defvalue: "0", desc: "Start the wall from the other end of the polyline", category: "Other")]
113  protected bool m_bStartFromTheEnd;
114 
115  [Attribute(defvalue: "1", desc: "Rotate object so that its X axis is facing in the direction of the polyline segment", category: "Other")]
116  protected bool UseXAsForward;
117 
118  [Attribute(defvalue: "0", desc: "Rotate object 180° around the Yaw axis", category: "Other")]
119  protected bool Rotate180;
120 
121  [Attribute(defvalue: "0", desc: "If you want to generate objects smaller than 10 centimetres", category: "Other")]
122  protected bool UseForVerySmallObjects;
123 
124  [Attribute(defvalue: "0", desc: "Draw developer debug", category: "Other")]
125  bool m_bDebug;
126 
127  [Attribute(defvalue: "0", desc: "Whether or not walls should be snapped to the terrain", category: "Other")]
128  protected bool m_bSnapToTerrain;
129 
130  [Attribute(uiwidget: UIWidgets.None)] // obsolete, kept for Prefabs and layers retrocompatibility
131  protected ref array<ref ResourceName> WallPrefabs;
132 
133 #ifdef WORKBENCH
134 
135  protected IEntitySource m_ParentSource;
136 
137  protected ref SCR_WallGroupContainer m_WallGroupContainer;
138 
139  protected ref array<ref SCR_WallGeneratorPoint> m_aPoints = {};
140  protected static ref array<ref Shape> s_aDebugShapes = {};
141 
142  //------------------------------------------------------------------------------------------------
147  static float MeasureEntity(ResourceName entityName, int measureAxis, WorldEditorAPI api)
148  {
149  float result = float.MAX;
150 
151  if (entityName.IsEmpty())
152  return result;
153 
154  Resource resource = Resource.Load(entityName);
155  if (!resource.IsValid())
156  return result;
157 
158  GenericEntity wallEntity = GenericEntity.Cast(GetGame().SpawnEntityPrefab(resource, api.GetWorld()));
159  if (!wallEntity)
160  return result;
161 
162  vector minBB;
163  vector maxBB;
164  wallEntity.GetBounds(minBB, maxBB);
165  delete wallEntity;
166 
167  result = (maxBB - minBB)[measureAxis];
168  if (result < 0.000001)
169  {
170  Print("Wall asset " + entityName + " is too small, does it have a valid mesh?", LogLevel.ERROR);
171  return 1; // generating is invalid, just avoid infinite loop
172  }
173 
174  return result;
175  }
176 
177  //------------------------------------------------------------------------------------------------
178  override bool _WB_OnKeyChanged(BaseContainer src, string key, BaseContainerList ownerContainers, IEntity parent)
179  {
180  super._WB_OnKeyChanged(src, key, ownerContainers, parent);
181 
182  if (key == "coords")
183  return false;
184 
185  WorldEditorAPI api = _WB_GetEditorAPI();
186  if (!api || api.UndoOrRedoIsRestoring())
187  return false;
188 
189  IEntitySource thisSrc = api.EntityToSource(this);
190  IEntitySource parentSrc = thisSrc.GetParent();
191 
192  BaseContainerTools.WriteToInstance(this, thisSrc);
193  OnShapeChanged(parentSrc, ShapeEntity.Cast(parent), {}, {});
194 
195  return true;
196  }
197 
198  //------------------------------------------------------------------------------------------------
200  protected void OffsetPoints(array<vector> points, float offset, bool debugAllowed = false)
201  {
202  array<vector> pointsTemp = {};
203  pointsTemp.Copy(points);
204  points.Clear();
205  int lastIndex = pointsTemp.Count() - 1;
206 
207  vector matWrld[4];
208  if (m_bDebug && debugAllowed)
209  GetWorldTransform(matWrld);
210 
211  vector forwardPrev = "1 1 1";
212  foreach (int i, vector pointTemp : pointsTemp)
213  {
214  vector forwardNext;
215 
216  if (i < lastIndex)
217  forwardNext = pointsTemp[i + 1] - pointTemp;
218  else
219  forwardNext = -forwardPrev;
220 
221  if (i == 0)
222  forwardPrev = -forwardNext;
223 
224  forwardNext.Normalize();
225  forwardPrev.Normalize();
226 
227  float dotProductPrevNext = vector.Dot(forwardPrev, forwardNext);
228  bool almostLine = dotProductPrevNext < -0.95;
229  vector diagonal = forwardNext + forwardPrev;
230 
231  vector normalRight = -forwardPrev * "0 1 0";
232  normalRight.Normalize();
233  float dotProductNormNext = vector.Dot(normalRight, forwardNext);
234  bool isLeft = dotProductNormNext > 0;
235 
236  vector nextModified = dotProductPrevNext * forwardNext;
237  float dist = vector.Distance(nextModified, forwardPrev);
238  float diff;
239  if (dist != 0)
240  diff = offset / dist;
241 
242  diagonal *= diff;
243 
244  if (!isLeft)
245  diagonal = diagonal * -1;
246 
247  if (almostLine)
248  {
249  vector vec = forwardNext - forwardPrev;
250  vector right = vec * "0 1 0";
251  right.Normalize();
252  diagonal = right * offset;
253  }
254 
255  points.Insert(pointsTemp[i] + diagonal);
256  forwardPrev = -forwardNext;
257 
258  // debug
259  if (m_bDebug && debugAllowed)
260  {
261  pointTemp = pointTemp.Multiply4(matWrld); // variable reuse
262  s_aDebugShapes.Insert(Shape.Create(ShapeType.LINE, ARGB(255, 255, 255, 255), ShapeFlags.NOZBUFFER, pointTemp, pointTemp + forwardNext));
263  s_aDebugShapes.Insert(Shape.Create(ShapeType.LINE, ARGB(255, 0, 255, 0), ShapeFlags.NOZBUFFER, pointTemp, pointTemp + forwardPrev));
264  s_aDebugShapes.Insert(Shape.Create(ShapeType.LINE, ARGB(255, 255, 0, 0), ShapeFlags.NOZBUFFER, pointTemp, pointTemp + diagonal));
265  }
266  }
267  }
268 
269  //------------------------------------------------------------------------------------------------
270  override void OnShapeInitInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity)
271  {
272  super.OnShapeInitInternal(shapeEntitySrc, shapeEntity);
273 
274  // TODO: auto-trigger generation here as well
275  WorldEditorAPI api = _WB_GetEditorAPI();
276  if (!api || api.UndoOrRedoIsRestoring())
277  return;
278 
279  Preprocess(shapeEntitySrc);
280  Generate(shapeEntity);
281  }
282 
283  //------------------------------------------------------------------------------------------------
284  protected void Preprocess(IEntitySource shapeEntitySrc)
285  {
286  m_aPoints.Clear();
287  WorldEditorAPI api = _WB_GetEditorAPI();
288 
289  m_WallGroupContainer = new SCR_WallGroupContainer(api, m_aWallGroups, UseXAsForward, MiddleObject, this);
290  BaseContainerList points = shapeEntitySrc.GetObjectArray("Points");
291  if (points != null && points.Count() >= 2 && m_WallGroupContainer.m_bGenerated != 0)
292  {
293  bool isShapeClosed = false;
294  shapeEntitySrc.Get("IsClosed", isShapeClosed);
295  array<vector> pointsVec = {};
296  int pointCount = points.Count();
297  bool addFirstAsLast = false;
298 
299  if (isShapeClosed && pointCount > 2) // no reason to "loop" for 2 points
300  addFirstAsLast = true;
301 
302  // offset start
303  BaseContainer point;
304  vector pos;
305  for (int i = 0; i < pointCount; i++)
306  {
307  point = points.Get(i);
308  point.Get("Position", pos);
309  pointsVec.Insert(pos);
310  }
311 
312  if (addFirstAsLast)
313  pointsVec.Insert(pointsVec[0]);
314 
315  if (m_fOffsetRight != 0)
316  OffsetPoints(pointsVec,m_fOffsetRight, true);
317  // offset end
318 
319  ResourceName customMesh;
320  float prePadding, postPadding, offsetUp;
321  bool generate, clipping, align;
322  BaseContainerList dataArr;
323  BaseContainer data;
324  int dataCount, lastPointIndex;
325  SCR_WallGeneratorPoint genPoint;
326 
327  for (int i = 0; i < pointCount; i++)
328  {
329  point = points.Get(i);
330  pos = pointsVec[i];
331  customMesh = string.Empty;
332  prePadding = 0;
333  postPadding = 0;
334  generate = true;
335  clipping = false;
336  offsetUp = 0;
337  align = false;
338  dataArr = point.GetObjectArray("Data");
339  dataCount = dataArr.Count();
340 
341  for (int j = 0; j < dataCount; ++j)
342  {
343  data = dataArr.Get(j);
344  if (data.GetClassName() == "WallGeneratorPointData")
345  {
346  data.Get("MeshAtPoint", customMesh);
347  data.Get("PrePadding", prePadding);
348  data.Get("PostPadding", postPadding);
349  data.Get("m_bGenerate", generate);
350  data.Get("m_bAllowClipping", clipping);
351  data.Get("m_fOffsetUp", offsetUp);
352  data.Get("m_bAlignWithNext", align);
353  break;
354  }
355  }
356 
357  genPoint = new SCR_WallGeneratorPoint();
358  genPoint.m_vPos = pos;
359  genPoint.m_sCustomMesh = customMesh;
360  genPoint.m_fPrePadding = prePadding;
361  genPoint.m_fPostPadding = postPadding;
362  genPoint.m_bGenerate = generate;
363  genPoint.m_bClip = clipping;
364  genPoint.m_fOffsetUp = offsetUp;
365  genPoint.m_bAlignNext = align;
366  m_aPoints.Insert(genPoint);
367  }
368 
369  if (addFirstAsLast)
370  {
371  m_aPoints.Insert(m_aPoints[0]);
372  lastPointIndex = m_aPoints.Count() - 1;
373  m_aPoints[lastPointIndex].m_vPos = pointsVec[lastPointIndex];
374  }
375  }
376  }
377 
378  //------------------------------------------------------------------------------------------------
379  protected override void OnShapeChangedInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity, array<vector> mins, array<vector> maxes)
380  {
381  if (!shapeEntitySrc || _WB_GetEditorAPI().UndoOrRedoIsRestoring())
382  return;
383 
384  Preprocess(shapeEntitySrc);
385  Generate(shapeEntity);
386  }
387 
388  //------------------------------------------------------------------------------------------------
389  protected IEntitySource PlacePrefab(
390  bool generate,
391  ResourceName name,
392  out vector pos,
393  vector dir,
394  vector prevDir,
395  float rotationAdjustment,
396  bool isGeneratorVisible,
397  float length,
398  float prePadding,
399  float postPadding,
400  float offsetUp,
401  bool alignNext,
402  bool prepadNext,
403  bool snapToGround = false,
404  bool allowClipping = false,
405  vector offsetRight = "0 0 0")
406  {
407  if (name.IsEmpty())
408  return null;
409 
410  vector prepadDirection;
411  vector orientation;
412 
413  if (alignNext)
414  orientation = dir;
415  else
416  orientation = prevDir;
417 
418  if (prepadNext)
419  prepadDirection = dir;
420  else
421  prepadDirection = prevDir;
422 
423  pos += prepadDirection * prePadding;
424  IEntitySource ent;
425  WorldEditorAPI api = _WB_GetEditorAPI();
426  IEntitySource thisSource = api.EntityToSource(this);
427  int layerID = api.GetCurrentEntityLayerId();
428 
429  if (generate)
430  {
431  vector rotMat[4];
432  Math3D.DirectionAndUpMatrix(orientation, "0 1 0", rotMat);
433  vector rot = Math3D.MatrixToAngles(rotMat);
434  rot[1] = rot[0] + rotationAdjustment;
435  rot[0] = 0;
436  rot[2] = 0;
437 
438  if (m_bSnapToTerrain)
439  {
440  vector world = CoordToParent(pos);
441  pos[1] = api.GetTerrainSurfaceY(world[0], world[2]);
442  if (m_ParentSource)
443  pos[1] = pos[1] - api.SourceToEntity(m_ParentSource).GetOrigin()[1];
444  }
445 
446  if (snapToGround)
447  {
448  vector matWrld[4];
449  GetWorldTransform(matWrld);
450 
451  ent = api.CreateEntityExt(name, "", layerID, thisSource, (pos + offsetRight), rot, TraceFlags.WORLD);
452  api.ParentEntity(thisSource, ent, true);
453  }
454  else
455  {
456  ent = api.CreateEntity(name, "", layerID, thisSource, pos + offsetRight, rot);
457  }
458 
459  if (offsetUp != 0)
460  {
461  vector entPos;
462  ent.Get("coords", entPos);
463  entPos[1] = entPos[1] + offsetUp;
464  string coords = entPos[0].ToString() + " " + entPos[1].ToString() + " " + entPos[2].ToString();
465  api.SetVariableValue(ent, null, "coords", coords);
466  }
467 
468  api.SetEntityVisible(ent, isGeneratorVisible, false);
469  }
470 
471  if (allowClipping)
472  length = 0;
473 
474  if (UseForVerySmallObjects)
475  pos += dir * (length + postPadding);
476  else
477  // if objects are big, advancement lower than 0.1 (10cm) is probably a bug
478  // and we may end up freezing by generating outrageous amout of entities
479  pos += dir * Math.Max(0.1, length + postPadding);
480 
481  return ent;
482  }
483 
484  //------------------------------------------------------------------------------------------------
485  protected void Generate(ShapeEntity shapeEntity)
486  {
487  if (!m_WallGroupContainer || m_WallGroupContainer.IsEmpty())
488  return;
489 
490  WorldEditorAPI api = _WB_GetEditorAPI();
491  if (api == null || m_WallGroupContainer.IsEmpty())
492  return;
493 
494  IEntitySource entSrc = api.EntityToSource(this);
495  m_ParentSource = entSrc.GetParent();
496  int childCount = entSrc.GetNumChildren();
497 
498  for (int i = childCount - 1; i >= 0; --i)
499  {
500  api.DeleteEntity(entSrc.GetChild(i));
501  }
502 
503  if (m_aPoints.Count() < 2)
504  return;
505 
506  int forwardAxis = 2;
507  if (UseXAsForward)
508  forwardAxis = 0;
509 
510  float lastObjectLength;
511 
512  if (m_bEnableLastObject && LastObject)
513  lastObjectLength = MeasureEntity(LastObject, forwardAxis, api);
514 
515  bool isGeneratorVisible = api.IsEntityVisible(entSrc);
516 
517  // copy points so we have them after the entity is reinitialised
518  array<ref SCR_WallGeneratorPoint> localPoints = {};
519  foreach (SCR_WallGeneratorPoint wgPoint : m_aPoints)
520  {
521  localPoints.Insert(wgPoint);
522  }
523 
524  if (m_bStartFromTheEnd)
525  SCR_ArrayHelperT<ref SCR_WallGeneratorPoint>.Reverse(localPoints);
526 
527  float rotationAdjustment = 0;
528 
529  if (UseXAsForward)
530  rotationAdjustment = -90;
531 
532  if (Rotate180)
533  rotationAdjustment += 180;
534 
535  if (m_bStartFromTheEnd)
536  rotationAdjustment += 180;
537 
538  vector from = localPoints[0].m_vPos;
539  vector to, dir, prevDir, rightVec;
540 
541  bool firstUsed, exhausted, lastPoint, lastSegment, generate, firstPass;
542  ResourceName customMesh;
543  float remaining;
544 
545  // while-loop variables
546  string bestWall;
547  float bestLen, prePaddingToUse, postPaddingToUse, offsetUp, lengthRequirement;
548  bool allowClipping, alignNext, prepadNext, custom;
549  bool firstPlaced, placeMiddle, placeLast, lastPlaced, lastInSegmentDoNotPlace, middleOfSegmentDoNotPlace;
550  vector offsetRight;
551  SCR_WallPair wall;
552 
553  for (int i, count = localPoints.Count(); i < count; i++)
554  {
555  exhausted = false;
556  lastPoint = i == count - 1;
557  lastSegment = i == count - 2;
558 
559  prevDir = dir;
560 
561  if (ExactPlacement)
562  {
563  if (i == 1)
564  from = localPoints[i].m_vPos;
565  else
566  from = localPoints[i].m_vPos + (dir * PrePadding);
567  }
568 
569  if (lastPoint)
570  {
571  to = localPoints[i].m_vPos;
572  dir = (localPoints[i].m_vPos - localPoints[i - 1].m_vPos).Normalized();
573  }
574  else
575  {
576  to = localPoints[i + 1].m_vPos;
577  dir = (to - from).Normalized();
578  if (i == 0)
579  prevDir = dir;
580  }
581 
582  customMesh = localPoints[i].m_sCustomMesh;
583  generate = localPoints[i].m_bGenerate;
584  remaining = vector.Distance(from, to) + m_fOvershoot;
585 
586  firstPass = true; // first segment on the polyline
587 
588  rightVec = dir * "0 1 0";
589 
590  // walking the polyline line segment and populating it with assets
591  // as long as there is enough room for at least the smallest wall available
592  while (!exhausted)
593  {
594  bestWall = string.Empty;
595  bestLen = 0;
596  prePaddingToUse = PrePadding;
597  postPaddingToUse = PostPadding;
598  allowClipping = false;
599  alignNext = true;
600  prepadNext = true;
601  offsetUp = m_fOffsetUp;
602  custom = false;
603  offsetRight = vector.Zero;
604  firstPlaced = false;
605  placeMiddle = false;
606  placeLast = false;
607  lengthRequirement = 0;
608  lastPlaced = false;
609  lastInSegmentDoNotPlace = false;
610  middleOfSegmentDoNotPlace = false;
611 
612  // first object
613  if (i == 0 && firstPass && m_bEnableFirstObject && !FirstObject.IsEmpty())
614  {
615  bestWall = FirstObject;
616  bestLen = MeasureEntity(FirstObject, forwardAxis, api);
617  prePaddingToUse = FirstObjectPrePadding;
618  postPaddingToUse = FirstObjectPostPadding;
619  firstPlaced = true;
620  offsetRight = rightVec * FirstObjectOffsetRight;
621  offsetUp = FirstObjectOffsetUp;
622  }
623  // custom mesh from the vertex data
624  else if (!customMesh.IsEmpty())
625  {
626  bestWall = customMesh;
627  prePaddingToUse = localPoints[i].m_fPrePadding;
628  postPaddingToUse = localPoints[i].m_fPostPadding;
629  allowClipping = localPoints[i].m_bClip;
630  offsetUp = localPoints[i].m_fOffsetUp;
631  alignNext = localPoints[i].m_bAlignNext;
632  prepadNext = false;
633  bestLen = MeasureEntity(customMesh, forwardAxis, api);
634  customMesh = string.Empty;
635  custom = true;
636  }
637  else if (!lastPoint)
638  {
639  wall = m_WallGroupContainer.GetRandomWall(remaining);
640  if (wall)
641  {
642  bestLen = wall.m_fWallLength;
643  bestWall = wall.m_sWallAsset;
644  prePaddingToUse += wall.m_fPrePadding;
645  postPaddingToUse += wall.m_fPostPadding;
646  }
647  }
648  else
649  {
650  // get here when the vertex has wall data with a mesh object and it's a last point on the polyline
651  break;
652  }
653 
654  if (bestLen + PrePadding <= 0)
655  {
656  prePaddingToUse = 0;
657  Print("PrePadding is set too low, not using it in this instance", LogLevel.WARNING);
658  }
659 
660  if (!PrePadFirst && firstPass) // do not prepad the first asset in the segment
661  prePaddingToUse = 0;
662 
663  PlacePrefab(generate, bestWall, from, dir, prevDir, rotationAdjustment, isGeneratorVisible, bestLen, prePaddingToUse, postPaddingToUse, offsetUp, alignNext, prepadNext, false, allowClipping, offsetRight);
664 
665  remaining -= (bestLen * !allowClipping) + prePaddingToUse + postPaddingToUse; // TODO: fix bool multiplier
666 
667  placeMiddle = !custom && m_bEnableMiddleObject && !MiddleObject.IsEmpty();
668  placeLast = lastSegment && m_bEnableLastObject && !LastObject.IsEmpty();
669 
670  lengthRequirement = m_WallGroupContainer.m_fSmallestWall; // the minimal space required to place the next wall asset
671 
672  if (placeMiddle)
673  lengthRequirement += m_WallGroupContainer.m_fMiddleObjectLength;
674 
675  if (placeLast)
676  lengthRequirement += lastObjectLength;
677 
678  if (remaining < lengthRequirement)
679  exhausted = true;
680 
681  lastPlaced = false;
682 
683  // no more room for 'normal' assets + placing last object
684  if (exhausted && placeLast)
685  {
686  bestWall = LastObject;
687  bestLen = lastObjectLength;
688  prePaddingToUse = LastObjectPrePadding;
689  postPaddingToUse = LastObjectPostPadding;
690  offsetRight = rightVec * LastObjectOffsetRight;
691  offsetUp = LastObjectOffsetUp;
692 
693  PlacePrefab(generate, bestWall, from, dir, prevDir, rotationAdjustment, isGeneratorVisible, bestLen, prePaddingToUse, postPaddingToUse, offsetUp, alignNext, prepadNext, false, allowClipping, offsetRight);
694  lastPlaced = true;
695  remaining -= (bestLen * !allowClipping) + prePaddingToUse + postPaddingToUse;
696  }
697 
698  // placing middle object
699  if (placeMiddle)
700  {
701  lastInSegmentDoNotPlace = exhausted && !(PlaceMiddleAtVertex || PlaceMiddleAtVertexOnly);
702 
703  // do not place middle object after first/last assets and any other assets which do not close a line segment
704  middleOfSegmentDoNotPlace = (!exhausted && PlaceMiddleAtVertexOnly) || (PlaceMiddleAtVertexOnly && (lastPlaced || firstPlaced));
705 
706  if (!lastInSegmentDoNotPlace && !middleOfSegmentDoNotPlace)
707  {
708  from += dir * MiddleObjectPrePadding;
709  offsetRight = rightVec * MiddleObjectOffsetRight;
710  PlacePrefab(generate, MiddleObject, from, dir, prevDir, rotationAdjustment, isGeneratorVisible, m_WallGroupContainer.m_fMiddleObjectLength, MiddleObjectPrePadding, MiddleObjectPostPadding, MiddleObjectOffsetUp,true, prepadNext, true, false, offsetRight);
711  remaining -= m_WallGroupContainer.m_fMiddleObjectLength + MiddleObjectPrePadding + MiddleObjectPostPadding;
712  }
713  }
714 
715  firstPass = false;
716  }
717  }
718 
719  // get the array back to normal
720  if (m_bStartFromTheEnd)
721  SCR_ArrayHelperT<ref SCR_WallGeneratorPoint>.Reverse(localPoints);
722  }
723 #endif // WORKBENCH
724 
725  //------------------------------------------------------------------------------------------------
726  // constructor
727  void WallGeneratorEntity(IEntitySource src, IEntity parent)
728  {
729 #ifdef WORKBENCH
730  SetEventMask(EntityEvent.INIT);
731 #endif // WORKBENCH
732  }
733 }
SCR_GeneratorBaseEntity
SCR_GeneratorBaseEntityClass GeneratorBaseEntityClass SCR_GeneratorBaseEntity(IEntitySource src, IEntity parent)
Definition: SCR_GeneratorBaseEntity.c:335
EntityEditorProps
enum EQueryType EntityEditorProps(category:"GameScripted/Sound", description:"THIS IS THE SCRIPT DESCRIPTION.", color:"0 0 255 255")
Definition: SCR_AmbientSoundsComponent.c:12
m_fOffsetUp
protected float m_fOffsetUp
Definition: PrefabGeneratorEntity.c:50
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
desc
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
Definition: SCR_RespawnBriefingComponent.c:17
GenericEntity
SCR_GenericBoxEntityClass GenericEntity
m_fOffsetRight
protected float m_fOffsetRight
Definition: PrefabGeneratorEntity.c:38
WallGeneratorEntityClass
Definition: WallGeneratorEntity.c:2
SCR_WallGeneratorPoint
Wall Generator point metadata that is being operated on with the generator after the data gets extrac...
Definition: SCR_WallGeneratorPoint.c:2
Attribute
WallGeneratorEntityClass SCR_GeneratorBaseEntityClass Attribute(defvalue:"1", desc:"Enable middle object", category:"Middle Object")
Definition: WallGeneratorEntity.c:12
data
Get all prefabs that have the spawner data
Definition: SCR_EntityCatalogManagerComponent.c:305
params
Configs ServerBrowser KickDialogs params
Definition: SCR_NotificationSenderComponent.c:24
SCR_WallPair
Definition: SCR_WallPair.c:1
SCR_GeneratorBaseEntityClass
Definition: SCR_GeneratorBaseEntity.c:1
category
params category
Definition: SCR_VehicleDamageManagerComponent.c:180