Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_PrefabEditingPlugin.c
Go to the documentation of this file.
1#ifdef WORKBENCH
2[WorkbenchPluginAttribute(name: "Edit Selected Prefab(s)", shortcut: "Ctrl+Shift+E", wbModules: { "WorldEditor" }, awesomeFontCode: 0xF1B2)]
3class SCR_PrefabEditingPlugin : SCR_PrefabEditingPluginBase
4{
5 [Attribute(defvalue: "{F636AAB9EE015E5F}Configs/Workbench/PrefabEditingPlugin/PrefabEditingPluginConfig.conf", params: "conf", desc: "Config with rules defining which worlds will be used for which folders.")]
6 protected ResourceName m_Config;
7
8 protected static const string WARNING_CAPTION = "Edit Selected Prefab plugin";
9 protected static const string WARNING_TEXT = "You are about to generate and load a world to edit selected Prefabs. Saving current World Editor changes will be offered if needed if you click OK.\n\nDo you want to proceed?";
10
11 //------------------------------------------------------------------------------------------------
12 protected IEntitySource CreateEntity(WorldEditorAPI api, ResourceName prefab, vector position, vector rotation)
13 {
14 string extension;
15 string prefabName = FilePath.StripPath(FilePath.StripExtension(prefab.GetPath(), extension));
16 if (extension == "ct")
17 {
18 IEntitySource entity = api.CreateEntity("GenericEntity", prefabName, api.GetCurrentEntityLayerId(), null, position, rotation);
19 api.CreateComponent(entity, prefab);
20 return entity;
21 }
22 else
23 {
24 return api.CreateEntity(prefab, prefabName, api.GetCurrentEntityLayerId(), null, position, rotation);
25 }
26 }
27
28 //------------------------------------------------------------------------------------------------
29 protected bool CreateWorldFiles(ResourceName worldPrefab, string targetPath)
30 {
31 //--- ToDo: Use more legit way to create the world?
32 string worldPath = worldPrefab.GetPath();
33
34 if (!FileIO.FileExists(worldPath))
35 {
36 Print(string.Format("Cannot load prefab, selected world '%2' doesn't exist!", worldPath), LogLevel.ERROR);
37 return false;
38 }
39
40 if (!FileIO.MakeDirectory("$profile:worlds"))
41 return false;
42
43 //--- World file
44 FileHandle file = FileIO.OpenFile(targetPath + ".ent", FileMode.WRITE);
45 if (!file)
46 return false;
47
48 file.WriteLine("SubScene {");
49 file.WriteLine(string.Format(" Parent \"%1\"", worldPrefab));
50 file.WriteLine("}");
51 file.WriteLine("Layer default {");
52 file.WriteLine(" Index 0");
53 file.WriteLine("}");
54 file.Close();
55
56 if (!FileIO.MakeDirectory(targetPath + "_Layers"))
57 return false;
58
59 //--- Layer file
60 file = FileIO.OpenFile(targetPath + "_Layers/default.layer", FileMode.WRITE);
61 if (!file)
62 return false;
63
64 file.Close();
65
66 return true;
67 }
68
69 //------------------------------------------------------------------------------------------------
70 protected void SetCamera(WorldEditorAPI api, IEntity entity)
71 {
72 IEntitySource source = api.EntityToSource(entity);
73 vector boundsMin = { float.MAX, float.MAX, float.MAX };
74 vector boundsMax;
75 GetEntitySourceBounds(api, source, boundsMin, boundsMax);
76
77 vector size = boundsMax - boundsMin;
78 float distance = Math.Max(size.Length() * 1.5, 1);
79 if (distance > 100)
80 {
81 size = vector.Zero;
82 distance = 100;
83 }
84
85 vector rotation = ((vector){ -135, -30, 0 }).AnglesToVector();
86 vector pivot = entity.GetOrigin() + { 0, size[1] * 0.5, 0 };
87 api.SetCamera(pivot - rotation * distance, rotation);
88 }
89
90 //------------------------------------------------------------------------------------------------
91 protected void GetEntitySourceBounds(WorldEditorAPI api, IEntitySource source, out vector boundsMin, out vector boundsMax)
92 {
93 IEntity entity = api.SourceToEntity(source);
94 if (!entity)
95 return;
96
97 if (entity.GetVObject())
98 {
99 vector entityMin, entityMax;
100 entity.GetBounds(entityMin, entityMax);
101 entityMin = entity.CoordToParent(entityMin);
102 entityMax = entity.CoordToParent(entityMax);
103
104 boundsMin[0] = Math.Min(boundsMin[0], entityMin[0]);
105 boundsMin[1] = Math.Min(boundsMin[1], entityMin[1]);
106 boundsMin[2] = Math.Min(boundsMin[2], entityMin[2]);
107
108 boundsMax[0] = Math.Max(boundsMax[0], entityMax[0]);
109 boundsMax[1] = Math.Max(boundsMax[1], entityMax[1]);
110 boundsMax[2] = Math.Max(boundsMax[2], entityMax[2]);
111 }
112
113 for (int i, childrenCount = source.GetNumChildren(); i < childrenCount; i++)
114 {
115 GetEntitySourceBounds(api, source.GetChild(i), boundsMin, boundsMax);
116 }
117 }
118
119 //------------------------------------------------------------------------------------------------
120 protected PrefabEditingPluginConfig GetConfig(ResourceName configPath)
121 {
122 Resource configResource = Resource.Load(configPath);
123 if (!configResource.IsValid())
124 {
125 PrintFormat("Cannot load config '%1'!", configPath, level: LogLevel.ERROR);
126 return null;
127 }
128
129 BaseResourceObject configContainer = configResource.GetResource();
130 if (!configContainer)
131 return null;
132
133 BaseContainer configBase = configContainer.ToBaseContainer();
134 if (!configBase)
135 return null;
136
137 PrefabEditingPluginConfig result = PrefabEditingPluginConfig.Cast(BaseContainerTools.CreateInstanceFromContainer(configBase));
138 if (!result)
139 {
140 PrintFormat("Config '%1' is of type '%2', must be inheriting from 'PrefabEditingPluginConfig'!", configPath, configBase.GetClassName(), level: LogLevel.ERROR);
141 return null;
142 }
143
144 return result;
145 }
146
147 //------------------------------------------------------------------------------------------------
148 override void Run()
149 {
150 if (!SCR_Global.IsEditMode() || !Workbench.OpenModule(WorldEditor))
151 return;
152
153 if (Workbench.ScriptDialog(WARNING_CAPTION, WARNING_TEXT, new WorkbenchDialog_OKCancel()) == 0)
154 return;
155
156 WorldEditor worldEditor = Workbench.GetModule(WorldEditor);
157 if (!worldEditor)
158 return;
159
160 WorldEditorAPI api = worldEditor.GetApi();
161 if (!api)
162 return;
163
164 array<ResourceName> compatiblePrefabs = {};
165 if (!GetPrefabs(compatiblePrefabs, true))
166 return;
167
168 //--- Load config
169 PrefabEditingPluginConfig config = GetConfig(m_Config);
170 if (!config)
171 return;
172
173 PrefabEditingPluginConfigFolder folderSettings = config.GetFolderSettings(compatiblePrefabs[0]);
174 if (!folderSettings)
175 return;
176
177 //--- Create world
178 string targetPath = config.GetPath();
179 if (!CreateWorldFiles(folderSettings.GetWorld(), targetPath))
180 return;
181
182 if (!worldEditor.SetOpenedResource(targetPath + ".ent"))
183 {
184 PrintFormat("Cannot load world '%1'!", folderSettings.GetWorld(), level: LogLevel.ERROR);
185 return;
186 }
187
188 //--- Create entities
189 api.BeginEntityAction();
190 api.ClearEntitySelection();
191 array<IEntitySource> entities = {};
192
193 vector pos, rot, size, boundsMin, boundsMax, boundsSize;
194 pos = folderSettings.GetPosition();
195 rot = folderSettings.GetRotation();
196
197 bool usePrefabPosition = folderSettings.UsePrefabPosition();
198
199 Resource resource;
200 IEntitySource source;
201 foreach (int i, ResourceName prefab : compatiblePrefabs)
202 {
203 resource = Resource.Load(prefab);
204 if (!resource.IsValid())
205 {
206 Print(string.Format("Cannot load prefab '%1'!", prefab), LogLevel.ERROR);
207 api.EndEntityAction();
208 return;
209 }
210
211 if (usePrefabPosition)
212 {
213 source = SCR_BaseContainerTools.FindEntitySource(resource);
214 source.Get("coords", pos);
215 rot = vector.Zero;
216 }
217
218 source = CreateEntity(api, prefab, pos, rot); //--- ToDo: Smarter placement of multiple entities?
219 if (!source)
220 {
221 Print(string.Format("Cannot create entity for prefab '%1'!", prefab), LogLevel.ERROR);
222 api.EndEntityAction();
223 return;
224 }
225
226 entities.Insert(source);
227
228 //--- Get bounding box
229 boundsMin = { float.MAX, float.MAX, float.MAX };
230 boundsMax = -boundsMin;
231 GetEntitySourceBounds(api, source, boundsMin, boundsMax);
232 boundsSize = boundsMax - boundsMin;
233 for (int n = 0; n < 3; n++)
234 {
235 if (size[n] < boundsSize[n])
236 size[n] = boundsSize[n];
237 }
238 }
239
240 float spacing = folderSettings.GetSpacing();
241 size += { spacing, spacing, spacing };
242
243 //--- Select entities (start from the back, because the last one has transformation gizmo on it)
244 int entitiesCount = entities.Count();
245 int length = Math.Ceil(Math.Sqrt(entitiesCount));
246 int row;
247 int column;
248 for (int i = entitiesCount; i >= 0; --i)
249 {
250 row = Math.Floor(i / length);
251 column = i % length;
252 IEntitySource e = entities[i];
253 api.AddToEntitySelection(e);
254 if (!usePrefabPosition)
255 api.SetVariableValue(e, null, "coords", string.Format("%1 %2 %3", pos[0] - size[0] * column, pos[1], pos[2] - size[2] * row));
256 }
257
258 SetCamera(api, api.SourceToEntity(entities[0]));
259 api.EndEntityAction();
260
261 //--- Save to make sure that only user changes are marked
262 worldEditor.Save();
263 }
264
265 //------------------------------------------------------------------------------------------------
266 override void Configure()
267 {
268 Workbench.ScriptDialog("Configure 'Edit Selected Prefab(s)' plugin", "", this);
269 }
270
271 //------------------------------------------------------------------------------------------------
272 [ButtonAttribute("Close")]
273 protected int ButtonClose()
274 {
275 return 0;
276 }
277}
278
279[WorkbenchPluginAttribute(name: "Edit Selected Prefab(s)", shortcut: "Ctrl+Shift+E", wbModules: { "ResourceManager" }, category: "Prefabs", awesomeFontCode: 0xF1B2)]
280class SCR_PrefabEditingPluginResourceManager : SCR_PrefabEditingPlugin
281{
282 //------------------------------------------------------------------------------------------------
283 override void GetSelected(out array<ResourceName> selection)
284 {
285 GetSelectedResourceBrowser(selection);
286 }
287}
288
289[BaseContainerProps(configRoot: true)]
290class PrefabEditingPluginConfig
291{
292 [Attribute(defvalue: "$profile:worlds/PrefabEditingPlugin")]
293 protected string m_sPath;
294
295 [Attribute()]
296 protected ref array<ref PrefabEditingPluginConfigFolder> m_Folders;
297
298 //------------------------------------------------------------------------------------------------
300 string GetPath()
301 {
302 return m_sPath;
303 }
304
305 //------------------------------------------------------------------------------------------------
308 PrefabEditingPluginConfigFolder GetFolderSettings(ResourceName prefab)
309 {
310 string prefabPath = prefab.GetPath();
311
312 PrefabEditingPluginConfigFolder folderSettings = null;
313 int pathLengthMax = -1;
314 foreach (PrefabEditingPluginConfigFolder folderSettingsTemp : m_Folders)
315 {
316 string folderPath = folderSettingsTemp.GetFolder();
317 int pathLength = folderPath.Length();
318 if (pathLength > pathLengthMax && prefabPath.StartsWith(folderPath))
319 {
320 folderSettings = folderSettingsTemp;
321 pathLengthMax = pathLength;
322 }
323 }
324
325 return folderSettings;
326 }
327}
328
330class PrefabEditingPluginConfigFolder
331{
332 [Attribute(params: "folders")]
333 protected ResourceName m_Folder;
334
335 [Attribute(defvalue: "{70ABDE49D02BA4F4}worlds/TestMaps/PrefabEditingPlugin/PrefabEditingPlugin.ent", uiwidget: UIWidgets.ResourceNamePicker, params: "ent")]
336 protected ResourceName m_World;
337
338 [Attribute(desc: "When enabled, prefabs will be used on their own coordinates.")]
339 protected bool m_bUsePrefabPosition;
340
341 [Attribute()]
342 protected vector m_vPosition;
343
344 [Attribute(desc: "Rotation pitch, yaw, roll")]
345 protected vector m_vRotation;
346
347 [Attribute(defvalue: "0.1", desc: "Minimal spacing [m] between spawned entities")]
348 protected float m_fSpacing;
349
350 //------------------------------------------------------------------------------------------------
352 string GetFolder()
353 {
354 return m_Folder.GetPath();
355 }
356
357 //------------------------------------------------------------------------------------------------
359 ResourceName GetWorld()
360 {
361 return m_World;
362 }
363
364 //------------------------------------------------------------------------------------------------
367 bool UsePrefabPosition()
368 {
369 return m_bUsePrefabPosition;
370 }
371
372 //------------------------------------------------------------------------------------------------
374 vector GetPosition()
375 {
376 return m_vPosition;
377 }
378
379 //------------------------------------------------------------------------------------------------
381 vector GetRotation()
382 {
383 return m_vRotation;
384 }
385
386 //------------------------------------------------------------------------------------------------
388 float GetSpacing()
389 {
390 return m_fSpacing;
391 }
392}
393#endif // WORKBENCH
GenerateFlowMaps WorkbenchPlugin WorkbenchPluginAttribute("Regenerate river flow-maps", "Generate and save/overwrite river flow-maps", "", "", {"WorldEditor"}, "", 0xf773)
Definition FlowmapTool.c:59
int size
SCR_AIAnimation_Loitering BaseContainerProps
Commanding menu commanding element class.
vector m_vPosition
SCR_CampaignMilitaryBaseComponent SCR_MilitaryBaseComponent SCR_BaseContainerCustomTitleResourceName("m_sBaseName", true)
float distance
vector position
override void Run()
ResourceName GetConfig()
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
override void Configure()
class WorkbenchDialog_AbortRetryIgnore ButtonAttribute("OK", true)
proto external vector GetOrigin()
proto external void GetBounds(out vector mins, out vector maxs)
proto external vector CoordToParent(vector coord)
proto external VObject GetVObject()
Returns visual object set to this Entity. No reference is added.
Definition Math.c:13
Object holding reference to resource. In destructor release the resource.
Definition Resource.c:25
static bool IsEditMode()
Definition Functions.c:1566
proto external bool SetCamera(CameraBase pCam)
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
proto void PrintFormat(string fmt, void param1=NULL, void param2=NULL, void param3=NULL, void param4=NULL, void param5=NULL, void param6=NULL, void param7=NULL, void param8=NULL, void param9=NULL, LogLevel level=LogLevel.NORMAL)
SCR_FieldOfViewSettings Attribute
RespawnSystemComponentClass GameComponentClass vector vector rotation
proto external int GetSelected(out notnull array< MapItem > outItems)
Get all selected entities.
FileMode
Mode for opening file. See FileSystem::Open.
Definition FileMode.c:14