Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
RoadGeneratorEntity.c
Go to the documentation of this file.
1//-----------------------------------------------------------------------
2[EntityEditorProps(category: "GameLib/Scripted/Generator", description:"RoadGeneratorEntity", dynamicBox: true, visible: false)]
6
7//-----------------------------------------------------------------------
8class RoadGeneratorEntity : GeneratorBaseEntity
9{
10 [Attribute(defvalue: "0", uiwidget: UIWidgets.CheckBox, desc: "If enabled, adjust terrain height map to road", category: "Terrain")]
11 private bool AdjustHeightMap;
12
13 [Attribute(defvalue: "0", desc: "Priority of terrain heightmap adjust", category: "Terrain")]
14 private int AdjustHeightMapPriority;
15
16 [Attribute(defvalue: "1", uiwidget: UIWidgets.CheckBox, desc: "If enabled, generate RoadEntity", category: "Road")]
17 private bool GenerateRoad;
18
19 [Attribute(defvalue: "2", uiwidget: UIWidgets.EditBox, desc: "Width of the clearance by the road", category: "Road")]
20 private float RoadClearance;
21
22 [Attribute(defvalue: "10", uiwidget: UIWidgets.EditBox, desc: "Width of the road", category: "Road", params: "0.1 100.0 0.1")]
23 private float RoadWidth;
24
25 [Attribute(defvalue: "2", uiwidget: UIWidgets.EditBox, desc: "Distance between road edge and start of fall-off", category: "Terrain")]
26 private float FalloffStartWidth;
27
28 [Attribute(defvalue: "20", uiwidget: UIWidgets.EditBox, desc: "Width of the road fall-off", category: "Terrain")]
29 private float RoadFalloffWidth;
30
31#ifdef WORKBENCH
32 private ShapeEntity m_ShapeEntity;
33 private IEntitySource m_ShapeSrc;
34 private IEntitySource m_RoadGenSrc;
35
36 //-----------------------------------------------------------------------
37 float GetRoadClearance()
38 {
39 return RoadClearance;
40 }
41
42 //-----------------------------------------------------------------------
43 float GetRoadWidth()
44 {
45 return RoadWidth;
46 }
47
48 //-----------------------------------------------------------------------
49 protected void RoadGeneratorEntity(IEntitySource src, IEntity parent)
50 {
51 if (_WB_GetEditorAPI())
52 {
53 SetEventMask(EntityEvent.INIT);
54
55 m_RoadGenSrc = src;
56
57 IEntitySource parentSrc = m_RoadGenSrc.GetParent();
58 ShapeEntity shapeEnt = ShapeEntity.Cast(parent);
59 if (parentSrc && shapeEnt)
60 {
61 OnShapeInit(parentSrc, shapeEnt);
62 }
63 }
64 }
65
66 //-----------------------------------------------------------------------
67 protected void ~RoadGeneratorEntity()
68 {
69 WorldEditorAPI api = _WB_GetEditorAPI();
70
71 if (api)
72 {
73 api.RemoveTerrainFlatterEntity(this, false);
74 }
75 }
76
77 //-----------------------------------------------------------------------
78 override bool _WB_IsTraceable(IEntitySource src)
79 {
80 return false;
81 }
82
83 //-----------------------------------------------------------------------
84 override void _WB_OnDelete(IEntitySource src)
85 {
86 WorldEditorAPI api = _WB_GetEditorAPI();
87 if (api)
88 {
89 api.RemoveTerrainFlatterEntity(this, true);
90 }
91 }
92
93 //-----------------------------------------------------------------------
94 override bool _WB_OnKeyChanged(BaseContainer src, string key, BaseContainerList ownerContainers, IEntity parent)
95 {
96 WorldEditorAPI api = _WB_GetEditorAPI();
97 if (!api.AreGeneratorEventsEnabled())
98 return false;
99
100 BaseContainerTools.WriteToInstance(this, src);
101
102 // if there is no legit spline entity
103 if( !m_ShapeEntity )
104 {
105 Print("RoadGeneratorEntity requires a SplineShapeEntity!", LogLevel.ERROR);
106 return false;
107 }
108
109 array<vector> updateMins = new array<vector>();
110 array<vector> updateMaxes = new array<vector>();
111
112 m_ShapeEntity.GetAllInfluenceBBoxes(m_ShapeSrc, updateMins, updateMaxes);
113
114 bool bForceUpdate = false;
115
116 if (key == "AdjustHeightMap")
117 {
118 if (AdjustHeightMap)
119 {
120 bForceUpdate = true;
121 }
122 else
123 {
124 api.RemoveTerrainFlatterEntity(this, true);
125 }
126 }
127
128 UpdateTerrain(m_ShapeEntity, bForceUpdate, updateMins, updateMaxes);
129 UpdateRoad(m_ShapeSrc);
130
131 return true;
132 }
133
134 //-----------------------------------------------------------------------
135 override void _WB_OnCreate(IEntitySource src)
136 {
137 WorldEditorAPI api = _WB_GetEditorAPI();
138
139 if (api && m_ShapeEntity)
140 {
141 IEntitySource shapeEntitySrc = src.GetParent();
142 array<vector> updateMins = new array<vector>();
143 array<vector> updateMaxes = new array<vector>();
144 m_ShapeEntity.GetAllInfluenceBBoxes(m_ShapeSrc, updateMins, updateMaxes);
145
146 UpdateRoad(m_ShapeSrc, false);
147 UpdateTerrain(m_ShapeEntity, false, updateMins, updateMaxes);
148 }
149 }
150
151 //-----------------------------------------------------------------------
152 protected override void OnShapeInitInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity)
153 {
154 m_ShapeEntity = shapeEntity;
155 m_ShapeSrc = shapeEntitySrc;
156
157 WorldEditorAPI api = _WB_GetEditorAPI();
158
159 if (api)
160 {
161 array<vector> updateMins = new array<vector>();
162 array<vector> updateMaxes = new array<vector>();
163 shapeEntity.GetAllInfluenceBBoxes(m_ShapeSrc, updateMins, updateMaxes);
164
165 UpdateTerrain(m_ShapeEntity, false, updateMins, updateMaxes);
166 }
167 }
168
169 //-----------------------------------------------------------------------
170 protected override void OnShapeTransformInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity, array<vector> mins, array<vector> maxes)
171 {
172 UpdateTerrain(shapeEntity, false, mins, maxes);
173 UpdateRoad(shapeEntitySrc);
174
175 }
176
177 //-----------------------------------------------------------------------
178 protected override void OnShapeChangedInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity, array<vector> mins, array<vector> maxes)
179 {
180 UpdateTerrain(shapeEntity, false, mins, maxes);
181 UpdateRoad(shapeEntitySrc);
182 }
183
184 //-----------------------------------------------------------------------
185
186 protected void UpdateRoad(IEntitySource shapeEntitySrc, bool requireRoad = true)
187 {
188 if (GenerateRoad)
189 {
190 UpdateRoadEntity(_WB_GetEditorAPI(), shapeEntitySrc, m_RoadGenSrc, RoadWidth, requireRoad);
191 }
192 }
193
194 //-----------------------------------------------------------------------
195 protected void UpdateTerrain(ShapeEntity shapeEntity, bool bForceUpdate, array<vector> updateMins, array<vector> updateMaxes)
196 {
197 WorldEditorAPI api = _WB_GetEditorAPI();
198
199 // update terrain
200 if (!api || !AdjustHeightMap)
201 return;
202
203 vector mins = vector.One * 100000;
204 vector maxs = -mins;
205
206 array<vector> roadPoints = new array<vector>;
207 vector mat[4];
208
209 m_ShapeEntity.GenerateTesselatedShape(roadPoints);
210 m_ShapeEntity.GetWorldTransform(mat);
211
212 for (int i = 0; i < roadPoints.Count(); i++)
213 {
214 vector pos = roadPoints[i].Multiply4(mat);
215 mins[0] = Math.Min(mins[0], pos[0]);
216 mins[1] = Math.Min(mins[1], pos[1]);
217 mins[2] = Math.Min(mins[2], pos[2]);
218
219 maxs[0] = Math.Max(maxs[0], pos[0]);
220 maxs[1] = Math.Max(maxs[1], pos[1]);
221 maxs[2] = Math.Max(maxs[2], pos[2]);
222 }
223
224 api.AddTerrainFlatterEntity(this, mins, maxs, AdjustHeightMapPriority, RoadWidth * 0.5 + FalloffStartWidth, RoadFalloffWidth, bForceUpdate, updateMins, updateMaxes);
225 }
226
227 //-----------------------------------------------------------------------
228 // this method modify entities, so it is static works just with sources
229 static void UpdateRoadEntity(WorldEditorAPI api, IEntitySource splineSrc, IEntitySource genSrc, float roadWidth, bool requireRoad)
230 {
231 if (api.UndoOrRedoIsRestoring() || !api.IsModifyingData())
232 return;
233
234 // spline
235 SplineShapeEntity splineEntity = SplineShapeEntity.Cast(api.SourceToEntity(splineSrc));
236 if (!splineEntity)
237 {
238 Print("RoadGeneratorEntity requires a SplineShapeEntity!", LogLevel.ERROR);
239 return;
240 }
241
242 // road
243 IEntitySource roadSrc;
244 if (genSrc)
245 {
246 IEntitySource child = null;
247 int numChildren = genSrc.GetNumChildren();
248 for (int i = 0; i < numChildren; i++)
249 {
250 child = genSrc.GetChild(i);
251 if (child.GetClassName() == "RoadEntity")
252 {
253 roadSrc = child;
254 break;
255 }
256 }
257 }
258 if (!roadSrc)
259 {
260 if (requireRoad)
261 {
262 Print("RoadGeneratorEntity requires RoadEntity as child in hierarchy to be able to generate the road!", LogLevel.ERROR);
263 }
264 return;
265 }
266
267 // All good, update the road entity!
268
269 //optimization. Entity roadSrc will not be re-initialized until the api.EndEditSequence(roadSrc) bellow will be called
270 api.BeginEditSequence(roadSrc);
271
272 // set some properties
273 bool isClosed;
274 splineSrc.Get("IsClosed", isClosed);
275
276 if (isClosed)
277 api.SetVariableValue(roadSrc, null, "IsClosedSpline", "true");
278 else
279 api.SetVariableValue(roadSrc, null, "IsClosedSpline", "false");
280 api.SetVariableValue(roadSrc, null, "Width", roadWidth.ToString());
281 api.SetVariableValue(roadSrc, null, "Points", "@@@"); // clear obsolete Points property
282
283 // Copy the points:
284
285 // spline world transform
286 vector wTrans[4];
287 splineEntity.GetWorldTransform(wTrans);
288
289 // spline anchors positions
290 array<vector> positions = new array<vector>;
291 splineEntity.GetPointsPositions(positions);
292 auto roadPoints = roadSrc.GetObjectArray("SplinePoints");
293
294 // for each anchor of the spline...
295 int i=0;
296 for (; i<positions.Count(); i++)
297 {
298 // insert point to the road if needed
299 if (i >= roadPoints.Count())
300 {
301 api.CreateObjectArrayVariableMember(roadSrc, null, "SplinePoints", "ShapePoint", i);
302 roadPoints = roadSrc.GetObjectArray("SplinePoints"); // needs to be updated after the source change
303 }
304
305 auto roadPoint = roadPoints.Get(i);
306
307 auto containerPath = new array<ref ContainerIdPathEntry>();
308 containerPath.Insert(new ContainerIdPathEntry("SplinePoints", i));
309
310 // get the position, transform it to the road's space
311 positions[i] = positions[i].Multiply4(wTrans);
312 positions[i] = api.SourceToEntity(roadSrc).CoordToLocal(positions[i]);
313
314
315 // set the position if changed
316 vector oldPos;
317 roadPoint.Get("Position", oldPos);
318 if (oldPos != positions[i]) // just to save some unneeded change on the undostack, possible TODO compare with some tolerance
319 api.SetVariableValue(roadSrc, containerPath, "Position", positions[i].ToString(false));
320
321 // update point data
322 // (should be empty if there are not explicit tangents in the source point, contain one entry with the tangents otherwise)
323 int numPointData = roadPoint.GetObjectArray("Data").Count();
324 if (splineEntity.HasPointExplicitTangents(i))
325 {
326 // ensure there is just one item of time SplinePointData
327 bool createSplineData = numPointData < 1 || roadPoint.GetObjectArray("Data").Get(0).GetClassName() != "SplinePointData";
328 if (createSplineData)
329 api.CreateObjectArrayVariableMember(roadSrc, containerPath, "Data", "SplinePointData", 0);
330 for (int j=numPointData-1; j>0; j--)
331 api.RemoveObjectArrayVariableMember(roadSrc, containerPath, "Data", j);
332 roadPoints = roadSrc.GetObjectArray("SplinePoints"); // needs to be updated after the source change
333 roadPoint = roadPoints.Get(i); // ditto
334
335 // update the tangents if needed
336
337 vector tIn, tOut;
338 splineEntity.GetTangents(i, tIn, tOut);
339
340 vector tInOld, tOutOld;
341 auto oldTangents = roadPoint.GetObjectArray("Data").Get(0);
342 oldTangents.Get("InTangent", tInOld);
343 oldTangents.Get("OutTangent", tOutOld);
344
345 if (tIn != tInOld || tOut != tOutOld) // just to save some unneeded change on the undostack, possible TODO: compare with some tolerance
346 {
347 containerPath.Insert(new ContainerIdPathEntry("Data", 0));
348 api.SetVariableValue(roadSrc, containerPath, "InTangent", tIn.ToString(false));
349 api.SetVariableValue(roadSrc, containerPath, "OutTangent", tOut.ToString(false));
350 roadPoints = roadSrc.GetObjectArray("SplinePoints"); // needs to be updated after the source change
351 roadPoint = roadPoints.Get(i); // ditto
352 }
353
354 }
355 else
356 {
357 // no explicit tangents -> clear the point data
358 for (int j=numPointData-1; j>=0; j--)
359 api.RemoveObjectArrayVariableMember(roadSrc, containerPath, "Data", j);
360 }
361 }
362
363 // remove the abundant points in road entity (if any)
364 while (i < roadPoints.Count())
365 api.RemoveObjectArrayVariableMember(roadSrc, null, "SplinePoints", roadPoints.Count() - 1);
366
367 api.EndEditSequence(roadSrc);
368 }
369 #endif
370}
371
void ContainerIdPathEntry(string propertyName, int index=-1)
Definition worldEditor.c:30
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 ...
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
enum EVehicleType IEntity
proto external vector CoordToLocal(vector coord)
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
SCR_FieldOfViewSettings Attribute
void OnShapeTransformInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity, array< vector > mins, array< vector > maxes)
void OnShapeInitInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity)
void OnShapeChangedInternal(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity, array< vector > mins, array< vector > maxes)
EntityEvent
Various entity events.
Definition EntityEvent.c:14
GeneratorBaseEntityClass GenericEntityClass OnShapeInit(IEntitySource shapeEntitySrc, ShapeEntity shapeEntity)
proto external string ToString()
Plain C++ pointer, no weak pointers, no memory management.