Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_TerrainEntityVariantReplacementPlugin.c
Go to the documentation of this file.
1// #define DEBUG_TEVR_DUPLICATION
2
3#ifdef WORKBENCH
15 name: "Terrain Entity Variant Replacement",
16 description: "Convert a terrain to a variant with conversion config",
17 wbModules: { "WorldEditor" },
18 category: "World Setup",
19 awesomeFontCode: 0xF06C)]
20class SCR_TerrainEntityVariantReplacementPlugin : WorkbenchPlugin
21{
22 /*
23 Debug
24 */
25
26 [Attribute(category: "Debug", defvalue: "0", desc: "Read Only - all calculations are done but no edits happen")]
27 protected bool m_bReadOnly;
28
29 /*
30 Replacement
31 */
32
33 [Attribute(category: "Replacement", defvalue: "0", uiwidget: UIWidgets.ComboBox, desc: "Only replace entities in the current layer", enums: SCR_ParamEnumArray.FromString("All entities;Current layer;Selected entities"))]
34 protected int m_iReplacedEntities;
35
36 [Attribute(category: "Replacement", defvalue: SET_ANCESTOR_FORCE_RELOAD.ToString(), uiwidget: UIWidgets.ComboBox, desc: "Entity replacement mode - various modes, same (visual) results", enums: SCR_ParamEnumArray.FromString("Delete/create entity (SLOW - 2x);SetAncestor + visual refresh (slow - 1x);SetAncestor (fast - 0.01x - almost instant but requires world reload);SetAncestor + Save/Load world;SetAncestor + save and force reload"))]
37 protected int m_iReplacementMode;
38
39 [Attribute(category: "Replacement", defvalue: SCR_ETerrainEntityVariant.AUTUMN.ToString(), desc: "Expected terrain season (DEFAULT = reset XOB only)", uiwidget: UIWidgets.ComboBox, enumType: SCR_ETerrainEntityVariant)]
40 protected SCR_ETerrainEntityVariant m_eWantedVariant;
41
42 [Attribute(category: "Replacement", desc: "Config object - takes precedence over Config File if defined")]
43 protected ref SCR_TerrainEntityVariantConfig m_Config;
44
45 [Attribute(category: "Replacement", defvalue: "{E10A32BEF1F9E157}Configs/Workbench/WorldEditor/TerrainEntityVariantReplacementTool/Autumn.conf", desc: "Config file - if Config above is defined, this field is ignored", params: "conf class=SCR_TerrainEntityVariantConfig")]
46 protected ResourceName m_sConfigFile;
47
48#ifdef DEBUG_TEVR_DUPLICATION
49 [Attribute(category: "Duplication Debug", params: "ent")]
50 protected ResourceName m_sTerrainToDuplicate;
51
52 [Attribute(category: "Duplication Debug", defvalue: SCR_ETerrainEntityVariant.AUTUMN.ToString(), uiwidget: UIWidgets.ComboBox, enumType: SCR_ETerrainEntityVariant)]
53 protected SCR_ETerrainEntityVariant m_eDuplicationVariant;
54
55 [Attribute(category: "Duplication Debug", defvalue: "1")]
56 protected bool m_bDuplicationDebug;
57#else // let's not lose Workbench-stored user values
58 [Attribute(uiwidget: UIWidgets.None)]
59 protected ResourceName m_sTerrainToDuplicate;
60
61 [Attribute(uiwidget: UIWidgets.None)]
62 protected SCR_ETerrainEntityVariant m_eDuplicationVariant;
63
64 [Attribute(uiwidget: UIWidgets.None)]
65 protected bool m_bDuplicationDebug;
66#endif
67
68 protected ref map<ResourceName, ResourceName> m_mReplacementMap = new map<ResourceName, ResourceName>();
69
70 protected bool m_bIsUI;
71
72 protected static const int ALL_ENTITIES = 0;
73 protected static const int CURRENT_LAYER_MODE = 1;
74 protected static const int SELECTED_ENTITIES_MODE = 2;
75
76 protected static const int CREATE_AND_DELETE = 0;
77 protected static const int SET_ANCESTOR_REFRESH = 1;
78 protected static const int SET_ANCESTOR = 2;
79 protected static const int SET_ANCESTOR_SAVELOAD = 3;
80 protected static const int SET_ANCESTOR_FORCE_RELOAD = 4;
81
82 protected static const string PARAM_WORLD = "tevrWorld";
83 protected static const string PARAM_VARIANT = "tevrVariant";
84 protected static const string PARAM_CONFIG = "tevrConfig";
85
86 //------------------------------------------------------------------------------------------------
87 protected override void Run()
88 {
89 m_bIsUI = true;
90
91 if (Workbench.ScriptDialog("Terrain Entity Variant Replacement", "", this) == 0)
92 return;
93
94 WorldEditor worldEditor = Workbench.GetModule(WorldEditor);
95 if (!worldEditor)
96 return;
97
98 WorldEditorAPI worldEditorAPI = worldEditor.GetApi();
99 if (!worldEditorAPI)
100 return;
101
102 if (worldEditorAPI.IsGameMode())
103 {
104 Print("In Game mode", LogLevel.ERROR);
105 return;
106 }
107
108 if (worldEditorAPI.IsPrefabEditMode())
109 {
110 Print("In Prefab edit mode", LogLevel.ERROR);
111 return;
112 }
113
114 if (!m_Config || !LoadConfig(m_Config, m_eWantedVariant))
115 {
116 if (!LoadConfig(m_sConfigFile, m_eWantedVariant))
117 return;
118 }
119
120#ifdef DEBUG_TEVR_DUPLICATION
121 if (m_sTerrainToDuplicate)
122 {
123 DebugDuplication();
124 return;
125 }
126#endif
127
128 if (!ConvertCurrentTerrain(m_iReplacedEntities, m_iReplacementMode))
129 return;
130
131 if (m_iReplacementMode == SET_ANCESTOR_REFRESH || m_iReplacementMode == SET_ANCESTOR)
132 return;
133
134 if (m_iReplacementMode != SET_ANCESTOR_FORCE_RELOAD && Workbench.ScriptDialog("Save/Load operation", "SetAncestor requires a terrain save/load. Proceed?", new WorkbenchDialog_OKCancel()) == 0)
135 return;
136
137 if (!worldEditor.Save())
138 {
139 Print("World Editor cannot save the current world - please proceed manually", LogLevel.ERROR);
140 Workbench.Dialog("Error saving world", "World Editor cannot save the current world - please proceed manually");
141 return;
142 }
143
144 string worldPath;
145 worldEditorAPI.GetWorldPath(worldPath);
146
147 if (!worldPath || !worldEditor.SetOpenedResource(worldPath))
148 {
149 Print("World Editor cannot load the world - please proceed manually", LogLevel.ERROR);
150 Workbench.Dialog("Error loading world", "World Editor cannot load the saved world - please proceed manually");
151 return;
152 }
153
154 // success
155 }
156
157#ifdef DEBUG_TEVR_DUPLICATION
158 //------------------------------------------------------------------------------------------------
159 protected void DebugDuplication()
160 {
161 string terrainFilePath;
162 if (!Workbench.GetAbsolutePath(m_sTerrainToDuplicate.GetPath(), terrainFilePath, true))
163 {
164 Print("Cannot get world path for " + m_sTerrainToDuplicate, LogLevel.ERROR);
165 return;
166 }
167
168 const string newTerrainFilePath = GetNewWorldFilePath(terrainFilePath, m_eDuplicationVariant);
169
170 if (m_bDuplicationDebug)
171 {
172 Print("target = " + terrainFilePath, LogLevel.NORMAL);
173 Print("destination = " + newTerrainFilePath, LogLevel.NORMAL);
174 return;
175 }
176
177 if (!SCR_WorldFilesHelper.DuplicateWorld(terrainFilePath, newTerrainFilePath))
178 {
179 Print("Duplication error", LogLevel.ERROR);
180 return;
181 }
182
183 Print("Duplication success", LogLevel.NORMAL);
184 }
185#endif
186
187 //------------------------------------------------------------------------------------------------
188 protected override void RunCommandline()
189 {
190 m_bIsUI = false;
191
192 Print("[SCR_TerrainEntityVariantReplacementPlugin.RunCommandline] STARTED", level: LogLevel.NORMAL);
193
194 WorldEditor worldEditor = Workbench.GetModule(WorldEditor);
195
196 string terrainFilePath;
197 SCR_ETerrainEntityVariant variant;
198 ResourceName configResourceName;
199 if (!GetCLIParameterValues(worldEditor, terrainFilePath, variant, configResourceName))
200 return;
201
202 PrintFormat("Converting %1 terrain to %2 variant using config %3", terrainFilePath, variant, configResourceName, level: LogLevel.NORMAL);
203
204 if (!LoadConfig(configResourceName, variant))
205 return;
206
207 Print("Conversion config loaded", LogLevel.NORMAL);
208
209 string newTerrainFilePath = GetNewWorldFilePath(terrainFilePath, variant);
210
211 Print("Terrain duplication destination: " + newTerrainFilePath, LogLevel.NORMAL);
212
213 if (!SCR_WorldFilesHelper.DuplicateWorld(terrainFilePath, newTerrainFilePath))
214 {
215 PrintFormat("Cannot duplicate world from %1 to %2", terrainFilePath, newTerrainFilePath, level: LogLevel.ERROR);
216 return;
217 }
218
219 Print("Terrain duplication OK", LogLevel.NORMAL);
220
221 if (!worldEditor.SetOpenedResource(newTerrainFilePath))
222 {
223 PrintFormat("Cannot open duplicated terrain in World Editor (%1)", newTerrainFilePath, level: LogLevel.ERROR);
224 return;
225 }
226
227 Print("Duplicated terrain loading OK", LogLevel.NORMAL);
228
229 if (!ConvertCurrentTerrain())
230 {
231 Print("Error during terrain conversion", LogLevel.ERROR);
232 return;
233 }
234
235 if (!worldEditor.Save())
236 {
237 PrintFormat("Error saving duplicated terrain (%1)", newTerrainFilePath, level: LogLevel.ERROR);
238 return;
239 }
240
241 Print("Converted terrain successfully saved - " + newTerrainFilePath, LogLevel.NORMAL);
242 Print("[SCR_TerrainEntityVariantReplacementPlugin.RunCommandline] FINISHED", level: LogLevel.NORMAL);
243 }
244
245 //------------------------------------------------------------------------------------------------
246 // Show all errors at once to save time
247 protected bool GetCLIParameterValues(notnull WorldEditor worldEditor, out string worldPath, out SCR_ETerrainEntityVariant variant, out ResourceName config)
248 {
249 bool result = true;
250
251 string error;
252
253 worldPath = GetCLIWorldPath(worldEditor, error);
254 if (error)
255 {
256 Print(error, LogLevel.ERROR);
257 error = string.Empty;
258 result = false;
259 }
260
261 variant = GetCLIVariant(worldEditor, error);
262 if (error)
263 {
264 Print(error, LogLevel.ERROR);
265 error = string.Empty;
266 result = false;
267 }
268
269 config = GetCLIConfig(worldEditor, config);
270 if (error)
271 {
272 Print(error, LogLevel.ERROR);
273 error = string.Empty;
274 result = false;
275 }
276
277 return result;
278 }
279
280 //------------------------------------------------------------------------------------------------
281 protected string GetCLIWorldPath(notnull WorldEditor worldEditor, out string error)
282 {
283 string result;
284
285 if (!worldEditor.GetCmdLine("-" + PARAM_WORLD, result))
286 {
287 error = string.Format("-%1 not provided", PARAM_WORLD);
288 return string.Empty;
289 }
290
291 if (!result.EndsWith(".ent") || !FileIO.FileExists(result))
292 {
293 error = string.Format("-%1 value is not a valid file (%2)", PARAM_WORLD, result);
294 return string.Empty;
295 }
296
297 error = string.Empty;
298 return result;
299 }
300
301 //------------------------------------------------------------------------------------------------
302 protected SCR_ETerrainEntityVariant GetCLIVariant(notnull WorldEditor worldEditor, out string error)
303 {
304 SCR_ETerrainEntityVariant result;
305
306 string variantStr;
307 if (!worldEditor.GetCmdLine("-" + PARAM_VARIANT, variantStr))
308 {
309 error = string.Format("-%1 not provided - see SCR_ETerrainEntityVariant for possible values", PARAM_VARIANT);
310 return -1;
311 }
312
313 variantStr.ToUpper(); // let's be kind
314 result = typename.StringToEnum(SCR_ETerrainEntityVariant, variantStr);
315
316 if (result < 0)
317 {
318 error = string.Format("-%1 value is invalid - see SCR_ETerrainEntityVariant for possible values (provided %2)", PARAM_VARIANT, variantStr);
319 return -1;
320 }
321
322 error = string.Empty;
323 return result;
324 }
325
326 //------------------------------------------------------------------------------------------------
327 protected ResourceName GetCLIConfig(notnull WorldEditor worldEditor, out string error)
328 {
329 string config;
330 if (!worldEditor.GetCmdLine("-" + PARAM_CONFIG, config))
331 {
332 error = string.Format("-%1 not provided - config must be of type SCR_TerrainEntityVariantConfig", PARAM_CONFIG);
333 return ResourceName.Empty;
334 }
335
336 if (!config) // .IsEmpty()
337 {
338 error = string.Format("-%1 is empty - config must be of type SCR_TerrainEntityVariantConfig", PARAM_CONFIG);
339 return ResourceName.Empty;
340 }
341
342 ResourceName result;
343 if (config.StartsWith("{")) // }
344 {
345 result = config;
346 }
347 else
348 {
349 if (!Workbench.GetAbsolutePath(config, config, true) || !FileIO.FileExists(config))
350 {
351 error = string.Format("-%1 provided file does not exist (%2)", PARAM_CONFIG, config);
352 return ResourceName.Empty;
353 }
354
355 ResourceManager resourceManager = Workbench.GetModule(ResourceManager);
356 if (!resourceManager)
357 {
358 error = "Cannot obtain Resource Manager";
359 return ResourceName.Empty;
360 }
361
362 MetaFile metaFile = resourceManager.GetMetaFile(config);
363 if (!metaFile)
364 {
365 error = string.Format("-%1 provided file is not registered (%2)", PARAM_CONFIG, config);
366 return ResourceName.Empty;
367 }
368
369 result = metaFile.GetResourceID();
370 }
371
372 if (!Resource.Load(result).IsValid())
373 {
374 error = string.Format("-%1 is not a valid/registered config (%2)", PARAM_CONFIG, config);
375 return ResourceName.Empty;
376 }
377
378 error = string.Empty;
379 return result;
380 }
381
382 //------------------------------------------------------------------------------------------------
383 protected bool LoadConfig(ResourceName configResourceName, SCR_ETerrainEntityVariant variant)
384 {
385 if (!configResourceName) // .IsEmpty()
386 {
387 Print("Provided config ResourceName is empty", LogLevel.ERROR);
388 return false;
389 }
390
391 Managed managedInstance = SCR_BaseContainerTools.CreateInstanceFromPrefab(configResourceName, true);
392 if (!managedInstance)
393 {
394 Print("Provided config cannot be loaded - " + configResourceName, LogLevel.ERROR);
395 return false;
396 }
397
399 if (!config)
400 {
401 PrintFormat("Config is not of type %1 - %2", SCR_TerrainEntityVariantConfig, configResourceName, level: LogLevel.ERROR);
402 return false;
403 }
404
405 return LoadConfig(config, variant);
406 }
407
408 //------------------------------------------------------------------------------------------------
409 protected bool LoadConfig(notnull SCR_TerrainEntityVariantConfig config, SCR_ETerrainEntityVariant variant)
410 {
411 if (config.m_aEntries.IsEmpty())
412 {
413 Print("Empty config provided", LogLevel.ERROR);
414 return false;
415 }
416
417 m_mReplacementMap.Clear();
418
419 foreach (SCR_TerrainEntityVariantConfigEntry configEntry : config.m_aEntries)
420 {
421 if (m_mReplacementMap.Contains(configEntry.m_sResourceName))
422 {
423 Print("Config definition duplicate of " + configEntry.m_sResourceName, LogLevel.WARNING);
424 continue;
425 }
426
427 foreach (SCR_TerrainEntityVariantConfigValue variantValue : configEntry.m_aVariants)
428 {
429 if (variantValue.m_eVariant == variant) // we have a winner
430 {
431 m_mReplacementMap.Insert(configEntry.m_sResourceName, variantValue.m_sResourceName);
432 break;
433 }
434 }
435 }
436
437 if (m_mReplacementMap.IsEmpty())
438 {
439 Print("Conversion config is empty", LogLevel.ERROR);
440 return false;
441 }
442
443 return true;
444 }
445
446 //------------------------------------------------------------------------------------------------
447 protected bool ConvertCurrentTerrain(int replacedEntities = ALL_ENTITIES, int replacementMode = SET_ANCESTOR)
448 {
449 Debug.BeginTimeMeasure();
450 bool result = ConvertCurrentTerrainMeasured(replacedEntities, replacementMode);
451 Debug.EndTimeMeasure("Total conversion time");
452
453 return result;
454 }
455
456 //------------------------------------------------------------------------------------------------
458 protected bool ConvertCurrentTerrainMeasured(int replacedEntities, int replacementMode)
459 {
460 WorldEditor worldEditor = Workbench.GetModule(WorldEditor);
461 WorldEditorAPI worldEditorAPI = worldEditor.GetApi();
462
463 Debug.BeginTimeMeasure();
464 array<IEntitySource> entitiesToProcess = GetentitiesToProcess(replacedEntities);
465 Debug.EndTimeMeasure("Get entities to process");
466
467 int entitiesToProcessCount = entitiesToProcess.Count();
468 if (entitiesToProcessCount < 1)
469 {
470 Print("No terrain entities were found to be replaced", LogLevel.NORMAL);
471 if (m_bIsUI)
472 Workbench.Dialog("No entities found to replace", "No terrain entities were found to be replaced");
473
474 return true;
475 }
476
477 if (replacementMode == CREATE_AND_DELETE)
478 {
479 Debug.BeginTimeMeasure();
480 array<ref SCR_TEVR_Data> creationDataList = GetCreationData(entitiesToProcess);
481 Debug.EndTimeMeasure(entitiesToProcessCount.ToString() + " entities replacement data creation");
482
483 if (m_bReadOnly)
484 {
485 Print("Read Only mode - no terrain entities were modified", LogLevel.NORMAL);
486 if (m_bIsUI)
487 Workbench.Dialog("Read Only mode", "No terrain entities were modified");
488
489 return true;
490 }
491
492 worldEditorAPI.BeginEntityAction();
493
494 Debug.BeginTimeMeasure();
495 DeleteEntities(worldEditorAPI, entitiesToProcess);
496 Debug.EndTimeMeasure(entitiesToProcessCount.ToString() + " entities deletion");
497
498 Debug.BeginTimeMeasure();
499 array<IEntitySource> createdEntitySources = CreateEntities(creationDataList);
500 Debug.EndTimeMeasure(string.Format("%1/%2 entities (re-)creation", createdEntitySources.Count(), entitiesToProcessCount));
501
502 worldEditorAPI.EndEntityAction();
503 }
504 else // set ancestor (w/ or w/o refresh)
505 {
506 if (m_bReadOnly)
507 {
508 Print("Read Only mode - no terrain entities were modified", LogLevel.NORMAL);
509 if (m_bIsUI)
510 Workbench.Dialog("Read Only mode", "No terrain entities were modified");
511
512 return true;
513 }
514
515 worldEditorAPI.BeginEntityAction();
516
517 Debug.BeginTimeMeasure();
518 SetAncestor(entitiesToProcess, replacementMode == 1);
519 Debug.EndTimeMeasure(string.Format("%1/%1 entities re-ancestored", entitiesToProcessCount));
520
521 worldEditorAPI.EndEntityAction();
522 }
523
524 return true;
525 }
526
527 //------------------------------------------------------------------------------------------------
528 protected array<IEntitySource> GetentitiesToProcess(int replacedEntities)
529 {
530 WorldEditor worldEditor = Workbench.GetModule(WorldEditor);
531 WorldEditorAPI worldEditorAPI = worldEditor.GetApi();
532
533 array<IEntitySource> result = {};
534
535 int currentLayerID;
536 if (replacedEntities == CURRENT_LAYER_MODE)
537 currentLayerID = worldEditorAPI.GetCurrentEntityLayerId();
538
539 IEntitySource entitySource;
540 IEntitySource ancestor;
541 WBProgressDialog progress;
542 int count = worldEditorAPI.GetEditorEntityCount();
543 float prevProgress, currProgress;
544 if (m_bIsUI)
545 progress = new WBProgressDialog("Finding entities to replace...", worldEditor);
546
547 for (int i; i < count; ++i)
548 {
549 if (m_bIsUI)
550 {
551 currProgress = i / count;
552 if (currProgress - prevProgress >= 0.01) // min 1%
553 {
554 progress.SetProgress(currProgress); // expensive
555 prevProgress = currProgress;
556 }
557 }
558
559 entitySource = worldEditorAPI.GetEditorEntity(i);
560
561 if (replacedEntities == SELECTED_ENTITIES_MODE && !worldEditorAPI.IsEntitySelected(entitySource))
562 continue;
563
564 if (!entitySource)
565 continue; // huh?
566
567 int entitySourceLayerID = entitySource.GetLayerID();
568 if (replacedEntities == CURRENT_LAYER_MODE && entitySourceLayerID != currentLayerID)
569 continue;
570
571 ancestor = entitySource.GetAncestor(); // a raw GenericEntity, not a Prefab
572 if (!ancestor)
573 continue;
574
575 if (!ancestor.GetResourceName()) // IsEmpty()
576 continue;
577
578 if (!m_mReplacementMap.Contains(ancestor.GetResourceName()))
579 continue;
580
581 result.Insert(entitySource);
582 }
583
584 return result;
585 }
586
587 //------------------------------------------------------------------------------------------------
588 protected array<ref SCR_TEVR_Data> GetCreationData(notnull array<IEntitySource> entitySources)
589 {
590 WorldEditor worldEditor = Workbench.GetModule(WorldEditor);
591 WorldEditorAPI worldEditorAPI = worldEditor.GetApi();
592
593 array<ref SCR_TEVR_Data> result = {};
594
595 SCR_TEVR_Data creationData;
596 foreach (IEntitySource entitySource : entitySources)
597 {
599 if (!entitySource.Get("coords", coords))
600 {
601 Print("Cannot get coords from entity", LogLevel.WARNING);
602 continue;
603 }
604
606 if (!entitySource.Get("angles", angles))
607 {
608 Print("Cannot get angleX/Y/Z from entity", LogLevel.WARNING);
609 continue;
610 }
611
612 float scale;
613 if (!entitySource.Get("scale", scale))
614 {
615 Print("Cannot get scale from entity", LogLevel.WARNING);
616 continue;
617 }
618
620 if (!entitySource.Get("Flags", flags))
621 {
622 Print("Cannot get Flags from entity", LogLevel.WARNING);
623 continue;
624 }
625
626 creationData = new SCR_TEVR_Data();
627
628 creationData.m_sResourceName = m_mReplacementMap[entitySource.GetAncestor().GetResourceName()];
629 if (!creationData.m_sResourceName)
630 continue;
631
632 creationData.m_Parent = entitySource.GetParent();
633 creationData.m_iLayerID = entitySource.GetLayerID();
634 creationData.m_vCoords = coords;
635 creationData.m_vAngles = angles;
636 creationData.m_fScale = scale;
637 creationData.m_eFlags = flags;
638
639 creationData.m_bSelected = worldEditorAPI.IsEntitySelected(entitySource);
640
641 result.Insert(creationData);
642 }
643
644 return result;
645 }
646
647 //------------------------------------------------------------------------------------------------
648 // wrap method for Tracy
649 protected void DeleteEntities(notnull WorldEditorAPI worldEditorAPI, notnull array<IEntitySource> entitySources)
650 {
651 worldEditorAPI.DeleteEntities(entitySources);
652 }
653
654 //------------------------------------------------------------------------------------------------
655 protected array<IEntitySource> CreateEntities(notnull array<ref SCR_TEVR_Data> creationDataList)
656 {
657 WorldEditor worldEditor = Workbench.GetModule(WorldEditor);
658 WorldEditorAPI worldEditorAPI = worldEditor.GetApi();
659
660 array<IEntitySource> result = {};
661
662 IEntitySource createdSource;
663 foreach (SCR_TEVR_Data creationData : creationDataList)
664 {
665 createdSource = worldEditorAPI.CreateEntity(
666 creationData.m_sResourceName,
667 "",
668 creationData.m_iLayerID,
669 creationData.m_Parent,
670 creationData.m_vCoords,
671 creationData.m_vAngles);
672 if (!createdSource)
673 {
674 Print("cannot create Prefab " + creationData.m_sResourceName, LogLevel.ERROR);
675 continue;
676 }
677
678 float scale;
679 if (createdSource.Get("scale", scale) && scale != creationData.m_fScale)
680 {
681 if (!worldEditorAPI.SetVariableValue(createdSource, null, "scale", creationData.m_fScale.ToString()))
682 Print("Cannot set scale to newly created entity", LogLevel.WARNING);
683 }
684
686 if (createdSource.Get("Flags", flags) && flags != creationData.m_eFlags)
687 {
688 if (!worldEditorAPI.SetVariableValue(createdSource, null, "Flags", creationData.m_eFlags.ToString()))
689 Print("Cannot set Flags to newly created entity", LogLevel.WARNING);
690 }
691
692 if (creationData.m_bSelected)
693 worldEditorAPI.AddToEntitySelection(createdSource);
694
695 result.Insert(createdSource);
696 }
697
698 return result;
699 }
700
701 //------------------------------------------------------------------------------------------------
702 protected void SetAncestor(notnull array<IEntitySource> entitySources, bool forceRefresh)
703 {
704 WorldEditor worldEditor = Workbench.GetModule(WorldEditor);
705 WorldEditorAPI worldEditorAPI = worldEditor.GetApi();
706
707 set<int> updatedLayers;
708 if (!forceRefresh)
709 updatedLayers = new set<int>();
710
711 int entityLayerID;
714
715 WBProgressDialog progress;
716 int count;
717 float prevProgress, currProgress;
718 if (m_bIsUI)
719 {
720 if (forceRefresh)
721 progress = new WBProgressDialog("Setting entity ancestors with visual refresh", worldEditor);
722 else
723 progress = new WBProgressDialog("Setting entity ancestors w/o visual refresh", worldEditor);
724
725 count = entitySources.Count();
726 }
727
728 foreach (int i, IEntitySource entitySource : entitySources)
729 {
730 // one SHOULD normally use the World Editor API for entity source operations
731 // unfortunately there is no API equivalent to SetAncestor
732 entitySource.SetAncestor(m_mReplacementMap[entitySource.GetAncestor().GetResourceName()]);
733
734 entityLayerID = entitySource.GetLayerID();
735 if (forceRefresh || !updatedLayers.Contains(entityLayerID))
736 {
737 // force visual update / force layer save
738 if (
739 !entitySource.Get("coords", coords)
740 || !worldEditorAPI.SetVariableValue(entitySource, null, "coords", string.Format("%1 %2 %3", coords[0], coords[1], coords[2])))
741 {
742 Print("Cannot refresh layer using coords!", LogLevel.WARNING);
743 }
744 else
745 {
746 if (!forceRefresh)
747 updatedLayers.Insert(entityLayerID);
748 }
749 }
750
751 if (m_bIsUI)
752 {
753 currProgress = i / count;
754 if (currProgress - prevProgress >= 0.01) // min 1%
755 {
756 progress.SetProgress(currProgress); // expensive
757 prevProgress = currProgress;
758 }
759 }
760 }
761 }
762
763 //------------------------------------------------------------------------------------------------
767 static string GetNewWorldFilePath(string terrainFilePath, SCR_ETerrainEntityVariant variant)
768 {
769 string variantStr = typename.EnumToString(SCR_ETerrainEntityVariant, variant);
770 variantStr.ToLower();
771
772 terrainFilePath.Replace(SCR_StringHelper.ANTISLASH, SCR_StringHelper.SLASH); // cleaner
773 string newTerrainFilePath = FilePath.StripFileName(terrainFilePath);
774 if (newTerrainFilePath) // !.IsEmpty()
775 {
776 newTerrainFilePath = newTerrainFilePath.Substring(0, newTerrainFilePath.Length() - 1); // slash or antislash
777 if (newTerrainFilePath.EndsWith(":")) // Windows's drive format (C:)
778 newTerrainFilePath += SCR_StringHelper.SLASH;
779 else
780 newTerrainFilePath = string.Format("%1_%2/", newTerrainFilePath, variantStr);
781 }
782
783 return string.Format("%1%2_%3.ent", newTerrainFilePath, FilePath.StripExtension(FilePath.StripPath(terrainFilePath)), variantStr);
784
785 }
786
787 //------------------------------------------------------------------------------------------------
788 [ButtonAttribute("OK", true)]
789 protected int ButtonOK()
790 {
791 return 1;
792 }
793
794 //------------------------------------------------------------------------------------------------
795 [ButtonAttribute("Cancel")]
796 protected int ButtonCancel()
797 {
798 return 0;
799 }
800}
801
802class SCR_TEVR_Data
803{
804 ResourceName m_sResourceName;
805 IEntitySource m_Parent;
806 int m_iLayerID;
807 vector m_vCoords;
808 vector m_vAngles;
809 float m_fScale;
811 bool m_bSelected;
812}
813#endif
814
815[BaseContainerProps(configRoot: true)]
817{
818 [Attribute(desc: "If multiple entries are of the same variant, only the first one is used")]
819 ref array<ref SCR_TerrainEntityVariantConfigEntry> m_aEntries;
820}
821
823class SCR_TerrainEntityVariantConfigEntry
824{
825 [Attribute(uiwidget: UIWidgets.ResourcePickerThumbnail, params: "et")]
827
828 [Attribute(desc: "If multiple entries are of the same variant, only the first one is used")]
829 ref array<ref SCR_TerrainEntityVariantConfigValue> m_aVariants;
830}
831
832[BaseContainerProps(), SCR_BaseContainerCustomTitleEnum(SCR_ETerrainEntityVariant, "m_eVariant")]
834{
835 [Attribute(defvalue: SCR_ETerrainEntityVariant.AUTUMN.ToString(), desc: "Variant type", uiwidget: UIWidgets.ComboBox, enums: SCR_ParamEnumArray.FromEnumSkip(SCR_ETerrainEntityVariant, 1))]
836 SCR_ETerrainEntityVariant m_eVariant;
837
838 [Attribute(desc: "The wanted resource name\n- XOB for a model swap\n- Prefab for a Prefab swap\n- left empty for entity deletion", uiwidget: UIWidgets.ResourcePickerThumbnail, params: "et xob")]
839 ResourceName m_sResourceName;
840}
841
842[EnumLinear()]
843enum SCR_ETerrainEntityVariant
845 DEFAULT,
846
847 // seasons
848 SPRING,
849 SUMMER,
850 AUTUMN, // not FALL
851 WINTER,
852
853 // settings
854 // EASTERN_EUROPE,
855 // MEDITERRANEAN,
856
857 // states
858 // FLOODED,
859 // DESTROYED,
860 // NUCLEAR_APOCALYPSE,
861}
SCR_EAIThreatSectorFlags flags
vector scale
string error
override void RunCommandline()
Definition FlowmapTool.c:60
GenerateFlowMaps WorkbenchPlugin WorkbenchPluginAttribute("Regenerate river flow-maps", "Generate and save/overwrite river flow-maps", "", "", {"WorldEditor"}, "", 0xf773)
Definition FlowmapTool.c:59
float m_fScale
ref array< string > coords
ref array< string > angles
SCR_EAIThreatSectorFlags m_eFlags
class SCR_CampaignHintStorage SCR_BaseContainerCustomTitleEnum(EHint, "m_eHintId")
ref array< ref SCR_EditableEntityVariant > m_aVariants
override void Run()
bool ButtonCancel()
bool ButtonOK()
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
class SCR_TerrainEntityVariantConfigValue EnumLinear()] enum SCR_ETerrainEntityVariant
class SCR_TerrainEntityVariantConfig SCR_BaseContainerCustomTitleResourceName("m_sResourceName", true)
class SCR_TerrainEntityVariantConfig BaseContainerProps()
class WorkbenchDialog_AbortRetryIgnore ButtonAttribute("OK", true)
Definition Debug.c:13
Object holding reference to resource. In destructor release the resource.
Definition Resource.c:25
static ParamEnumArray FromString(string input)
static ParamEnumArray FromEnumSkip(typename enumTypeName, int skipFirst, int skipLast=0)
Definition Types.c:486
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)
@ DEFAULT
Use currently set main RT format (based on game options).
SCR_FieldOfViewSettings Attribute
EntityFlags
Various entity flags.
Definition EntityFlags.c:14
@ SPRING
Spring condition effect.