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
5 [
Attribute(
"1", UIWidgets.CheckBox,
"Find *.et files in given folder")]
6 protected bool m_bFindEntities;
8 [
Attribute(
"1", UIWidgets.CheckBox,
"Find *.xob files in given folder")]
9 protected bool m_bFindXOBs;
12 protected bool m_bShowPlacement;
14 [
Attribute(
"0", UIWidgets.CheckBox,
"Attach a comment with entity path")]
15 protected bool m_bGenerateComment;
18 protected float m_fCommentYOffset;
20 [
Attribute(
"10", UIWidgets.Slider,
"Number of objects in a row.",
"1 100 1")]
21 protected int m_iObjectsPerRow;
23 [
Attribute(
"1", UIWidgets.EditBox,
"Spawn the selection this many times",
"1 1000 1")]
24 protected int m_iSpawnMultiplier;
26 [
Attribute(
"1", UIWidgets.CheckBox,
"Align by largest bounding box")]
27 protected bool m_bAlignByBoundingBox;
29 [
Attribute(
"0", UIWidgets.Slider,
"Additional X axis offset",
"0 150 1")]
30 protected float m_fXOffset;
32 [
Attribute(
"0", UIWidgets.Slider,
"Additional Z axis offset",
"0 150 1")]
33 protected float m_fZOffset;
35 [
Attribute(
"0", UIWidgets.Slider,
"Y axis offset",
"-50 50 1")]
36 protected float m_fYOffset;
38 [
Attribute(
"0", UIWidgets.Slider,
"Cumulative object rotation.",
"0 180 1")]
39 protected float m_fCumulativeRotation;
41 [
Attribute(
"", UIWidgets.FileNamePicker,
"Select *.txt file with resource names to spawn")]
42 protected string m_sPrefabList;
44 protected ref array<ResourceName> m_aSelection = {};
45 protected ref array<ResourceName> m_aSelectedEntities = {};
46 protected ref array<ResourceName> m_aSelectedXOBs = {};
49 protected ref array<IEntitySource> m_aPlacedEntityHistory = {};
50 protected ref array<int> m_aSpawnHistory = {};
51 protected ref array<int> m_aSpawnHistoryChunks = {};
53 protected int m_iEntityId;
54 protected int m_iEntityIdPrev;
56 protected ref Shape m_PlacementRect;
57 protected vector m_vPlacementRectSize =
"1 0 1";
59 protected int m_iRowSizeX = 1;
60 protected int m_iRowSizeZ = 1;
62 protected float m_fLargestBBoxX;
63 protected float m_fLargestBBoxZ;
67 protected void SpawnFromPrefabList()
69 if (!FileIO.FileExists(m_sPrefabList))
72 FileHandle file = FileIO.OpenFile(m_sPrefabList,
FileMode.READ);
79 while (file.ReadLine(temp) > -1)
81 m_aSelectedEntities.Insert(temp);
93 if (m_aSpawnHistoryChunks.IsEmpty())
96 int chunkSize = m_aSpawnHistoryChunks[m_aSpawnHistoryChunks.Count()-1];
97 int bottomIndex = m_aPlacedEntityHistory.Count() - chunkSize - 1;
99 m_API.BeginEntityAction();
101 for (
int i = m_aPlacedEntityHistory.Count() - 1; i > bottomIndex; i--)
103 m_API.DeleteEntity(m_aPlacedEntityHistory[i]);
104 m_aPlacedEntityHistory.Remove(i);
107 m_API.EndEntityAction();
109 m_aSpawnHistoryChunks.Remove(m_aSpawnHistoryChunks.Count() - 1);
116 protected void FolderScan()
122 Debug.BeginTimeMeasure();
124 WorldEditor worldEditor = Workbench.GetModule(WorldEditor);
125 worldEditor.GetResourceBrowserSelection(m_aSelection.Insert,
true);
127 m_aSpawnHistory.Insert(m_iEntityId);
128 m_iEntityIdPrev = m_aSpawnHistory[m_aSpawnHistory.Count() - 1];
130 foreach (
string s : m_aSelection)
133 FindFilesByExtension(s,
".et", m_aSelectedEntities);
136 FindFilesByExtension(s,
".xob", m_aSelectedXOBs);
139 Debug.EndTimeMeasure(
"Folder scan done");
141 Print(
"Number of *.et files: " + m_aSelectedEntities.Count(),
LogLevel.NORMAL);
142 Print(
"Number of *.xob files: " + m_aSelectedXOBs.Count(),
LogLevel.NORMAL);
144 for (
int i = 1; i <= m_iSpawnMultiplier; ++i)
151 protected void Preload()
165 m_API.SourceToEntity(ent).GetBounds(min, max);
167 float cur_bbox_x = Math.AbsFloat(min[0] - max[0]);
168 float cur_bbox_z = Math.AbsFloat(min[2] - max[2]);
170 if (cur_bbox_x > m_fLargestBBoxX)
171 m_fLargestBBoxX = cur_bbox_x;
173 if (cur_bbox_z > m_fLargestBBoxZ)
174 m_fLargestBBoxZ = cur_bbox_z;
177 m_iRowSizeX = m_iObjectsPerRow;
182 protected void LoadXOBs()
184 m_API.BeginEntityAction();
185 foreach (ResourceName xob_path : m_aSelectedXOBs)
187 IEntitySource src = m_API.CreateEntity(
"GenericEntity",
string.Empty, m_API.GetCurrentEntityLayerId(), null, vector.Zero, vector.Zero);
189 m_API.CreateComponent(src,
"MeshObject");
190 IEntityComponentSource compSource;
191 for (
int i, count = src.GetComponentCount(); i < count; i++)
193 compSource = src.GetComponent(i);
194 if (compSource.GetClassName() ==
"MeshObject")
201 if (m_bGenerateComment)
202 GenerateComment(src, xob_path);
207 m_API.EndEntityAction();
211 protected void LoadEntities()
213 m_API.BeginEntityAction();
214 foreach (ResourceName entity_path : m_aSelectedEntities)
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);
223 m_API.EndEntityAction();
226 protected void GenerateComment(IEntitySource ent, ResourceName res_name)
228 IEntitySource comment = m_API.CreateEntity(
"CommentEntity",
string.Empty, 0, ent, vector.Zero, vector.Zero);
231 m_API.SourceToEntity(ent).GetBounds(min, max);
234 pos[1] = max[1] - min[1] + m_fCommentYOffset;
236 m_API.SetVariableValue(comment, null,
"coords", pos.ToString(
false));
237 m_API.SetVariableValue(comment, null,
"m_Comment", res_name.GetPath());
242 protected int PlaceSelection(vector trace_end,
bool isOnClick)
248 m_API.BeginEntityAction();
254 if (j % m_iRowSizeX == 0)
259 vector pos = trace_end;
261 float offset_x = m_fXOffset;
262 float offset_z = m_fZOffset;
264 if (m_bAlignByBoundingBox ==
true)
266 offset_x += m_fLargestBBoxX;
267 offset_z += m_fLargestBBoxZ;
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;
277 float height = m_API.GetWorld().GetSurfaceY(pos[0], pos[2]);
278 pos[1] = pos[1] - height;
281 m_API.SetVariableValue(ent, null,
"coords", pos.ToString(
false));
283 if (ent.Get(
"angles",
angles))
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]));
290 m_aPlacedEntityHistory.Insert(ent);
295 m_API.EndEntityAction();
301 override void OnMousePressEvent(
float x,
float y, WETMouseButtonFlag buttons)
306 int historyChunkSize = 0;
308 if (m_API.TraceWorldPos(x, y,
TraceFlags.WORLD |
TraceFlags.ENTS, trace_start, trace_end, trace_dir))
310 historyChunkSize = PlaceSelection(trace_end,
true);
312 if (historyChunkSize > 0)
313 m_aSpawnHistoryChunks.Insert(historyChunkSize);
319 override void OnMouseMoveEvent(
float x,
float y)
325 float rect_size_x = m_iRowSizeX;
326 float rect_size_z = m_iRowSizeZ;
328 if (m_bAlignByBoundingBox)
330 rect_size_x = m_iRowSizeX * (m_fLargestBBoxX + m_fXOffset);
331 rect_size_z = m_iRowSizeZ * (m_fLargestBBoxZ + m_fZOffset);
334 m_vPlacementRectSize[0] = rect_size_x;
335 m_vPlacementRectSize[2] = rect_size_z;
337 if (m_aSelectedXOBs.Count() > 0 || m_aSelectedEntities.Count() > 0)
339 if (m_API.TraceWorldPos(x, y,
TraceFlags.WORLD |
TraceFlags.ENTS, trace_start, trace_end, trace_dir))
343 if (m_bShowPlacement)
345 PlaceSelection(trace_end,
false);
349 m_API.BeginEntityAction();
352 m_API.SetVariableValue(ent, null,
"coords",
"0 0 0");
354 m_API.EndEntityAction();
360 delete m_PlacementRect;
365 protected void FindFilesByExtension(ResourceName
path,
string extension, out array<ResourceName> list)
367 if (
path.EndsWith(extension))
372 protected void ClearSelection()
374 m_aSelection.Clear();
375 m_aSelectedEntities.Clear();
376 m_aSelectedXOBs.Clear();
381 protected string FormatEntityIndex()
383 string id = m_iEntityId.ToString();
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);
SCR_EAIThreatSectorFlags flags
void ContainerIdPathEntry(string propertyName, int index=-1)
ref array< string > angles
ref array< IEntity > m_aSpawnedEntities
class WorkbenchDialog_AbortRetryIgnore ButtonAttribute("OK", true)
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
EntityFlags
Various entity flags.
FileMode
Mode for opening file. See FileSystem::Open.