Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_AutoSpawnerTool.c
Go to the documentation of this file.
1#ifdef WORKBENCH
2[WorkbenchToolAttribute("Autospawner Tool", "Spawns selected prefabs/XOBs on a grid into an active layer.\n1. Select folders/files in Resource Browser\n2. Click on 'Scan Folders'\n3. Place objects into the scene", awesomeFontCode: 0xF468)]
3class SCR_AutoSpawnerTool : WorldEditorTool
4{
5 [Attribute("1", UIWidgets.CheckBox, "Find *.et files in given folder")]
6 protected bool m_bFindEntities;
7
8 [Attribute("1", UIWidgets.CheckBox, "Find *.xob files in given folder")]
9 protected bool m_bFindXOBs;
10
11 [Attribute("1", UIWidgets.CheckBox)]
12 protected bool m_bShowPlacement;
13
14 [Attribute("0", UIWidgets.CheckBox, "Attach a comment with entity path")]
15 protected bool m_bGenerateComment;
16
17 [Attribute("0", UIWidgets.EditBox)]
18 protected float m_fCommentYOffset;
19
20 [Attribute("10", UIWidgets.Slider, "Number of objects in a row.", "1 100 1")]
21 protected int m_iObjectsPerRow;
22
23 [Attribute("1", UIWidgets.EditBox, "Spawn the selection this many times", "1 1000 1")]
24 protected int m_iSpawnMultiplier;
25
26 [Attribute("1", UIWidgets.CheckBox, "Align by largest bounding box")]
27 protected bool m_bAlignByBoundingBox;
28
29 [Attribute("0", UIWidgets.Slider, "Additional X axis offset", "0 150 1")]
30 protected float m_fXOffset;
31
32 [Attribute("0", UIWidgets.Slider, "Additional Z axis offset", "0 150 1")]
33 protected float m_fZOffset;
34
35 [Attribute("0", UIWidgets.Slider, "Y axis offset", "-50 50 1")]
36 protected float m_fYOffset;
37
38 [Attribute("0", UIWidgets.Slider, "Cumulative object rotation.", "0 180 1")]
39 protected float m_fCumulativeRotation;
40
41 [Attribute("", UIWidgets.FileNamePicker, "Select *.txt file with resource names to spawn")]
42 protected string m_sPrefabList;
43
44 protected ref array<ResourceName> m_aSelection = {};
45 protected ref array<ResourceName> m_aSelectedEntities = {};
46 protected ref array<ResourceName> m_aSelectedXOBs = {};
47
48 protected ref array<IEntitySource> m_aSpawnedEntities = {};
49 protected ref array<IEntitySource> m_aPlacedEntityHistory = {};
50 protected ref array<int> m_aSpawnHistory = {};
51 protected ref array<int> m_aSpawnHistoryChunks = {};
52
53 protected int m_iEntityId;
54 protected int m_iEntityIdPrev;
55
56 protected ref Shape m_PlacementRect;
57 protected vector m_vPlacementRectSize = "1 0 1";
58
59 protected int m_iRowSizeX = 1;
60 protected int m_iRowSizeZ = 1;
61
62 protected float m_fLargestBBoxX;
63 protected float m_fLargestBBoxZ;
64
65 //------------------------------------------------------------------------------------------------
66 [ButtonAttribute("Spawn prefab list")]
67 protected void SpawnFromPrefabList()
68 {
69 if (!FileIO.FileExists(m_sPrefabList))
70 return;
71
72 FileHandle file = FileIO.OpenFile(m_sPrefabList, FileMode.READ);
73 if (!file)
74 return;
75
76 ClearSelection();
77
78 string temp;
79 while (file.ReadLine(temp) > -1)
80 {
81 m_aSelectedEntities.Insert(temp);
82 }
83
84 file.Close();
85
86 Preload();
87 }
88
89 //------------------------------------------------------------------------------------------------
90 [ButtonAttribute("Undo")]
91 protected void Undo()
92 {
93 if (m_aSpawnHistoryChunks.IsEmpty())
94 return;
95
96 int chunkSize = m_aSpawnHistoryChunks[m_aSpawnHistoryChunks.Count()-1];
97 int bottomIndex = m_aPlacedEntityHistory.Count() - chunkSize - 1;
98
99 m_API.BeginEntityAction();
100
101 for (int i = m_aPlacedEntityHistory.Count() - 1; i > bottomIndex; i--)
102 {
103 m_API.DeleteEntity(m_aPlacedEntityHistory[i]);
104 m_aPlacedEntityHistory.Remove(i);
105 }
106
107 m_API.EndEntityAction();
108
109 m_aSpawnHistoryChunks.Remove(m_aSpawnHistoryChunks.Count() - 1);
110
111 ClearSelection();
112 }
113
114 //------------------------------------------------------------------------------------------------
115 [ButtonAttribute("Scan Folders")]
116 protected void FolderScan()
117 {
118 m_fLargestBBoxX = 0;
119 m_fLargestBBoxZ = 0;
120
121 ClearSelection();
122 Debug.BeginTimeMeasure();
123
124 WorldEditor worldEditor = Workbench.GetModule(WorldEditor);
125 worldEditor.GetResourceBrowserSelection(m_aSelection.Insert, true);
126
127 m_aSpawnHistory.Insert(m_iEntityId);
128 m_iEntityIdPrev = m_aSpawnHistory[m_aSpawnHistory.Count() - 1];
129
130 foreach (string s : m_aSelection)
131 {
132 if (m_bFindEntities)
133 FindFilesByExtension(s, ".et", m_aSelectedEntities);
134
135 if (m_bFindXOBs)
136 FindFilesByExtension(s, ".xob", m_aSelectedXOBs);
137 }
138
139 Debug.EndTimeMeasure("Folder scan done");
140
141 Print("Number of *.et files: " + m_aSelectedEntities.Count(), LogLevel.NORMAL);
142 Print("Number of *.xob files: " + m_aSelectedXOBs.Count(), LogLevel.NORMAL);
143
144 for (int i = 1; i <= m_iSpawnMultiplier; ++i)
145 {
146 Preload();
147 }
148 }
149
150 //------------------------------------------------------------------------------------------------
151 protected void Preload()
152 {
153 if (m_bFindEntities)
154 LoadEntities();
155
156 if (m_bFindXOBs)
157 LoadXOBs();
158
159 vector min, max;
160 foreach (IEntitySource ent : m_aSpawnedEntities)
161 {
162 if (!ent)
163 continue;
164
165 m_API.SourceToEntity(ent).GetBounds(min, max);
166
167 float cur_bbox_x = Math.AbsFloat(min[0] - max[0]);
168 float cur_bbox_z = Math.AbsFloat(min[2] - max[2]);
169
170 if (cur_bbox_x > m_fLargestBBoxX)
171 m_fLargestBBoxX = cur_bbox_x;
172
173 if (cur_bbox_z > m_fLargestBBoxZ)
174 m_fLargestBBoxZ = cur_bbox_z;
175 }
176
177 m_iRowSizeX = m_iObjectsPerRow;
178 m_iRowSizeZ = m_aSpawnedEntities.Count() / m_iRowSizeX + 1;
179 }
180
181 //------------------------------------------------------------------------------------------------
182 protected void LoadXOBs()
183 {
184 m_API.BeginEntityAction();
185 foreach (ResourceName xob_path : m_aSelectedXOBs)
186 {
187 IEntitySource src = m_API.CreateEntity("GenericEntity", string.Empty, m_API.GetCurrentEntityLayerId(), null, vector.Zero, vector.Zero);
188
189 m_API.CreateComponent(src, "MeshObject");
190 IEntityComponentSource compSource;
191 for (int i, count = src.GetComponentCount(); i < count; i++)
192 {
193 compSource = src.GetComponent(i);
194 if (compSource.GetClassName() == "MeshObject")
195 {
196 m_API.SetVariableValue(src, { new ContainerIdPathEntry("components", i) }, "Object", xob_path);
197 break;
198 }
199 }
200
201 if (m_bGenerateComment)
202 GenerateComment(src, xob_path);
203
204 m_aSpawnedEntities.Insert(src);
205 m_iEntityId++;
206 }
207 m_API.EndEntityAction();
208 }
209
210 //------------------------------------------------------------------------------------------------
211 protected void LoadEntities()
212 {
213 m_API.BeginEntityAction();
214 foreach (ResourceName entity_path : m_aSelectedEntities)
215 {
216 IEntitySource ent = m_API.CreateEntity(entity_path, string.Empty, m_API.GetCurrentEntityLayerId(), null, vector.Zero, vector.Zero);
217 if (m_bGenerateComment)
218 GenerateComment(ent, entity_path);
219
220 m_aSpawnedEntities.Insert(ent);
221 m_iEntityId++;
222 }
223 m_API.EndEntityAction();
224 }
225
226 protected void GenerateComment(IEntitySource ent, ResourceName res_name)
227 {
228 IEntitySource comment = m_API.CreateEntity("CommentEntity", string.Empty, 0, ent, vector.Zero, vector.Zero);
229
230 vector min, max;
231 m_API.SourceToEntity(ent).GetBounds(min, max);
232
233 vector pos;
234 pos[1] = max[1] - min[1] + m_fCommentYOffset;
235
236 m_API.SetVariableValue(comment, null, "coords", pos.ToString(false));
237 m_API.SetVariableValue(comment, null, "m_Comment", res_name.GetPath());
238 // m_API.SetVariableValue(comment, null, "m_FaceCamera", "1");
239 }
240
241 //------------------------------------------------------------------------------------------------
242 protected int PlaceSelection(vector trace_end, bool isOnClick)
243 {
244 int j = 0;
245 int k = 0;
246 int chunkSize = 0;
247
248 m_API.BeginEntityAction();
249 foreach (IEntitySource ent : m_aSpawnedEntities)
250 {
251 if (!ent)
252 continue;
253
254 if (j % m_iRowSizeX == 0)
255 {
256 j = 0;
257 k++;
258 }
259 vector pos = trace_end;
260
261 float offset_x = m_fXOffset;
262 float offset_z = m_fZOffset;
263
264 if (m_bAlignByBoundingBox == true)
265 {
266 offset_x += m_fLargestBBoxX;
267 offset_z += m_fLargestBBoxZ;
268 }
269
270 pos[0] = pos[0] + j * offset_x + offset_x;
271 pos[2] = pos[2] + k * offset_z - offset_z * 0.5;
272 pos[1] = m_API.GetTerrainSurfaceY(pos[0], pos[2]) + m_fYOffset;
273
274 EntityFlags flags = m_API.SourceToEntity(ent).GetFlags();
275 if ((flags & EntityFlags.RELATIVE_Y) != 0)
276 {
277 float height = m_API.GetWorld().GetSurfaceY(pos[0], pos[2]);
278 pos[1] = pos[1] - height;
279 }
280
281 m_API.SetVariableValue(ent, null, "coords", pos.ToString(false));
282 vector angles;
283 if (ent.Get("angles", angles))
284 {
285 angles[1] = m_fCumulativeRotation * (m_iRowSizeX * (k - 1) + j);
286 m_API.SetVariableValue(ent, null, "angles", string.Format("%1 %2 %3", angles[0], angles[1], angles[2]));
287 }
288
289 if (isOnClick)
290 m_aPlacedEntityHistory.Insert(ent);
291
292 chunkSize++;
293 j++;
294 }
295 m_API.EndEntityAction();
296
297 return chunkSize;
298 }
299
300 //------------------------------------------------------------------------------------------------
301 override void OnMousePressEvent(float x, float y, WETMouseButtonFlag buttons)
302 {
303 vector trace_start;
304 vector trace_end;
305 vector trace_dir;
306 int historyChunkSize = 0;
307
308 if (m_API.TraceWorldPos(x, y, TraceFlags.WORLD | TraceFlags.ENTS, trace_start, trace_end, trace_dir))
309 {
310 historyChunkSize = PlaceSelection(trace_end, true);
311 }
312 if (historyChunkSize > 0)
313 m_aSpawnHistoryChunks.Insert(historyChunkSize);
314
315 ClearSelection();
316 }
317
318 //------------------------------------------------------------------------------------------------
319 override void OnMouseMoveEvent(float x, float y)
320 {
321 vector trace_start;
322 vector trace_end;
323 vector trace_dir;
324
325 float rect_size_x = m_iRowSizeX;
326 float rect_size_z = m_iRowSizeZ;
327
328 if (m_bAlignByBoundingBox)
329 {
330 rect_size_x = m_iRowSizeX * (m_fLargestBBoxX + m_fXOffset);
331 rect_size_z = m_iRowSizeZ * (m_fLargestBBoxZ + m_fZOffset);
332 }
333
334 m_vPlacementRectSize[0] = rect_size_x;
335 m_vPlacementRectSize[2] = rect_size_z;
336
337 if (m_aSelectedXOBs.Count() > 0 || m_aSelectedEntities.Count() > 0)
338 {
339 if (m_API.TraceWorldPos(x, y, TraceFlags.WORLD | TraceFlags.ENTS, trace_start, trace_end, trace_dir))
340 {
341 m_PlacementRect = Shape.Create(ShapeType.BBOX, COLOR_YELLOW, ShapeFlags.NOOUTLINE, trace_end, trace_end + m_vPlacementRectSize);
342
343 if (m_bShowPlacement)
344 {
345 PlaceSelection(trace_end, false);
346 }
347 else
348 {
349 m_API.BeginEntityAction();
350 foreach (IEntitySource ent : m_aSpawnedEntities)
351 {
352 m_API.SetVariableValue(ent, null, "coords", "0 0 0");
353 }
354 m_API.EndEntityAction();
355 }
356 }
357 }
358 else
359 {
360 delete m_PlacementRect;
361 }
362 }
363
364 //------------------------------------------------------------------------------------------------
365 protected void FindFilesByExtension(ResourceName path, string extension, out array<ResourceName> list)
366 {
367 if (path.EndsWith(extension))
368 list.Insert(path);
369 }
370
371 //------------------------------------------------------------------------------------------------
372 protected void ClearSelection()
373 {
374 m_aSelection.Clear();
375 m_aSelectedEntities.Clear();
376 m_aSelectedXOBs.Clear();
377 m_aSpawnedEntities.Clear();
378 }
379
380 //------------------------------------------------------------------------------------------------
381 protected string FormatEntityIndex()
382 {
383 string id = m_iEntityId.ToString();
384
385 if (m_iEntityId < 10)
386 id = string.Format("000%1", m_iEntityId);
387 else if (m_iEntityId < 100)
388 id = string.Format("00%1", m_iEntityId);
389 else if (m_iEntityId < 1000)
390 id = string.Format("0%1", m_iEntityId);
391
392 return id;
393 }
394}
395#endif // WORKBENCH
SCR_EAIThreatSectorFlags flags
string path
AddonBuildInfoTool id
void ContainerIdPathEntry(string propertyName, int index=-1)
Definition worldEditor.c:30
ref array< string > angles
ref array< IEntity > m_aSpawnedEntities
class WorkbenchDialog_AbortRetryIgnore ButtonAttribute("OK", true)
const int COLOR_YELLOW
Definition constants.c:24
proto void Print(void var, LogLevel level=LogLevel.NORMAL)
Prints content of variable to console/log.
ShapeType
Definition ShapeType.c:13
LogLevel
Enum with severity of the logging message.
Definition LogLevel.c:14
ShapeFlags
Definition ShapeFlags.c:13
SCR_FieldOfViewSettings Attribute
EntityFlags
Various entity flags.
Definition EntityFlags.c:14
FileMode
Mode for opening file. See FileSystem::Open.
Definition FileMode.c:14
void Debug()
Definition Types.c:327
TraceFlags
Definition TraceFlags.c:13