Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
WorldExporterPlugin.c
Go to the documentation of this file.
1/*
2TODO:
3-Set default class flags on root/base prefabs (currently setting only when IsVariableSetDirectly is true)
4*/
5//#define WE_LOGGING_ENABLED
6
7[BaseContainerProps(configRoot: true)]
9{
10 [Attribute(defvalue: "c:/Reforger/Data/Arland", desc: "Folder of the map to export")]
11 string m_sExportMapDir;
12
13 [Attribute(defvalue: "Assets/_SharedData", desc: "Relative paths to shared data to be copied over")]
14 ref array<string> m_aCopyPathsMixed;
15
16 [Attribute(defvalue: "edds;emat;gamemat", desc: "Shared data extensions, only these will be copied over")]
17 string m_sCopyPathsMixedExtensions;
18
19 [Attribute(defvalue: "", desc: "Paths to copy .xob files from")]
20 ref TStringArray m_aModelPaths;
21
22 [Attribute(defvalue: "Tree::StaticModelEntity", desc: "Classname to Classname conversion mapping during the export process. First class will be converted to the second class, the separator is ::")]
23 ref TStringArray m_aClassMappings;
24
25 [Attribute(defvalue: "RoadGeneratorEntity", desc: "Entities/Prefabs inheriting classes in this list are not converted, even if they match any other criteria")]
26 ref TStringArray m_aEntityClassWhitelist;
27
28 [Attribute(defvalue: "", desc: "Entities/Prefabs inheriting classes containing keywords from this list are converted to their corresponding classes")]
29 ref TStringArray m_aEntityClassBlacklistKeywords;
30
31 [Attribute(defvalue: "MeshObject", desc: "Components inheriting these classes in this list are not converted, even if they match any other criteria")]
32 ref TStringArray m_aComponentClassWhitelist;
33
34 [Attribute(defvalue: "export-cache", desc: "Path prefix added to the resources that are converted during the export process, typically prefabs")]
35 string m_sExportCachePrefix;
36
37 [Attribute(defvalue: "true", desc: "After export is finished, automatically delete temporary files created during the export")]
38 bool m_bDeleteTempFiles;
39
40 [Attribute(defvalue: "", desc: "Resources with these GUIDs will not be copied over")]
41 ref TResourceNameArray m_aResourceExcludeGUIDs;
42
43 [Attribute(defvalue: "", desc: "When cloning prefabs, ignore the ones coming from PrefabLibrary and alter prefab inheritance accordingly")]
44 bool m_bSkipPrefabLibrary;
45
46 [Attribute(defvalue: "false", desc: "Export source files along with the resource files. (will export FBX, TIF etc.. which are not used at run time)")]
47 bool m_bExportSourceFiles;
48
49 [Attribute(defvalue: "true", desc: "Export files belonging to map (terrain tiles, etc.)")]
50 bool m_ExportMapData;
51
52 [Attribute(defvalue: "$ArmaReforger", desc: "FIlesystem of the project we are exporting world from.")]
53 string m_sFilesystem;
54
55 [Attribute(desc: "Root resources to start reference crawling from.")]
56 ref TResourceNameArray m_RootResources;
57
58 bool IsValid()
59 {
60 if (m_aModelPaths == null || m_aModelPaths.Count() == 0)
61 return false;
62
63 if (m_aCopyPathsMixed == null || m_aCopyPathsMixed.Count() == 0)
64 return false;
65
66 if (m_sCopyPathsMixedExtensions.IsEmpty())
67 return false;
68
69 if (m_aClassMappings == null || m_aClassMappings.Count() == 0)
70 return false;
71
72 if (m_aEntityClassWhitelist == null || m_aEntityClassWhitelist.Count() == 0)
73 return false;
74
75 if (m_aEntityClassBlacklistKeywords == null || m_aEntityClassBlacklistKeywords.Count() == 0)
76 return false;
77
78 if (m_aComponentClassWhitelist == null || m_aComponentClassWhitelist.Count() == 0)
79 return false;
80
81 if (m_aResourceExcludeGUIDs == null || m_aResourceExcludeGUIDs.Count() == 0)
82 return false;
83
84 return true;
85 }
86
87}
88
89
90#ifdef WORKBENCH
91enum ExporterAssetType
92{
93 PREFAB,
94 XOB,
95 MAT,
96 GAMEMAT,
97 TXT,
98 MISC,
99}
100
101#ifdef WE_LOGGING_ENABLED
102class WorldExporterLogItem
103{
104 string messageA, messageB;
105 int StartTime, EndTime;
106
107 int GetTime()
108 {
109 return EndTime - StartTime;
110 }
111}
112#endif
113
114class ResourceExportCrawler
115{
116 ResourceManager m_ResourceManager = Workbench.GetModule(ResourceManager);
117 ref set<ResourceName> m_Visited = new set<ResourceName>();
118
119 bool InsertFirstTime(ResourceName resourceName)
120 {
121 if (resourceName.IsEmpty() || resourceName.GetPath().IsEmpty())
122 return false;
123
124 return m_Visited.Insert(resourceName);
125 }
126
127 void Crawl(ResourceName resourceName)
128 {
129 if (resourceName.IsEmpty() || resourceName.GetPath().IsEmpty())
130 return;
131
132 if (resourceName.EndsWith(".gamemat"))
133 CrawlGamemat(resourceName);
134 else if (resourceName.EndsWith(".physmat"))
135 CrawlPhysmat(resourceName);
136 // else if (resourceName.EndsWith(".et"))
137 // m_sPrefabsToMigrate.Insert(resourceName);
138 else if (resourceName.EndsWith(".xob"))
139 CrawlXob(resourceName);
140 else if (resourceName.EndsWith(".emat"))
141 CrawlEmat(resourceName);
142 else if (resourceName.EndsWith(".edds"))
143 CrawlEdds(resourceName);
144 else if (resourceName.EndsWith(".conf"))
145 CrawlConf(resourceName);
146 else if (resourceName.EndsWith(".vhcsurf"))
147 CrawlVhcsurf(resourceName);
148 else
149 PrintFormat("Unrecognized resource suffix: %1", resourceName);
150 }
151
152 //-----------------------------------------------------------------------------------------------
153 void CrawlGamemat(ResourceName resourceName, BaseContainer container = null)
154 {
155 bool isFirstTime = InsertFirstTime(resourceName);
156 if (!isFirstTime)
157 return;
158
159 Resource resource;
160 if (!container)
161 {
162 resource = BaseContainerTools.LoadContainer(resourceName);
163 container = resource.GetResource().ToBaseContainer();
164 }
165
166 ResourceName physicsMaterial;
167 container.Get("Physics material", physicsMaterial);
168 if (physicsMaterial && physicsMaterial.GetPath())
169 CrawlPhysmat(physicsMaterial);
170
171 ResourceName vhcsurf;
172 container.Get("Vehicle contact surface", vhcsurf);
173 if (vhcsurf && vhcsurf.GetPath())
174 CrawlVhcsurf(vhcsurf);
175
176 BaseContainer baseGamemat = container.GetAncestor();
177 if (baseGamemat)
178 CrawlGamemat(baseGamemat.GetResourceName(), baseGamemat);
179 }
180
181 //-----------------------------------------------------------------------------------------------
182 void CrawlPhysmat(ResourceName resourceName)
183 {
184 InsertFirstTime(resourceName);
185 }
186
187 //-----------------------------------------------------------------------------------------------
188 void CrawlVhcsurf(ResourceName resourceName)
189 {
190 InsertFirstTime(resourceName);
191 }
192
193 //-----------------------------------------------------------------------------------------------
194 void CrawlXob(ResourceName resourceName)
195 {
196 bool isFirstTime = InsertFirstTime(resourceName);
197 if (!isFirstTime)
198 return;
199
200 MetaFile meta = m_ResourceManager.GetMetaFile(resourceName.GetPath());
201 BaseContainerList configurations = meta.GetObjectArray("Configurations");
202 for (int cfgIdx = 0, cfgCount = configurations.Count(); cfgIdx < cfgCount; cfgIdx++)
203 {
204 BaseContainer cfg = configurations.Get(cfgIdx);
205
206 string materialAssigns;
207 array<string> pairs = new array<string>;
208 cfg.Get("MaterialAssigns", materialAssigns);
209 materialAssigns.Split(";", pairs, true);
210
211 foreach (string pair : pairs)
212 {
213 array<string> keyValue = new array<string>;
214 pair.Split(",", keyValue, true);
215 CrawlEmat(keyValue[1]);
216 }
217
218 BaseContainerList geometryParams = cfg.GetObjectArray("GeometryParams");
219 for (int i = 0, iCount = geometryParams.Count(); i < iCount; i++)
220 {
221 BaseContainer geometryParam = geometryParams.Get(i);
222 array<ResourceName> surfaceProperties;
223 geometryParam.Get("SurfaceProperties", surfaceProperties);
224 foreach(ResourceName gamematOrPhysmat : surfaceProperties)
225 {
226 Crawl(gamematOrPhysmat);
227 }
228 }
229 }
230 }
231
232 //-----------------------------------------------------------------------------------------------
233 void CrawlEmat(ResourceName resourceName)
234 {
235 bool isFirstTime = InsertFirstTime(resourceName);
236 if (!isFirstTime)
237 return;
238
239 Resource resource = BaseContainerTools.LoadContainer(resourceName);
240 BaseContainer container = resource.GetResource().ToBaseContainer();
241 for (int i = 0, count = container.GetNumVars(); i < count; i++)
242 {
243 if (container.GetDataVarType(i) != DataVarType.TEXTURE)
244 continue;
245
246 string varName = container.GetVarName(i);
247 ResourceName texture;
248 container.Get(varName, texture);
249
250 array<string> textures = new array<string>;
251 texture.Split(" ", textures, true);
252 if (textures.Count() > 1)
253 {
254 foreach (string txt : textures)
255 {
256 if (txt.Get(0) == "{")
257 {
258 CrawlEdds(txt);
259 }
260 }
261 }
262 else
263 {
264 CrawlEdds(texture);
265 }
266 }
267
268 ResourceName surfaceProperties;
269 container.Get("SurfaceProperties", surfaceProperties);
270 if (surfaceProperties && surfaceProperties.GetPath())
271 CrawlGamemat(surfaceProperties);
272
273 ResourceName plantMat;
274 container.Get("PlantMat", plantMat);
275 if (plantMat && plantMat.GetPath())
276 CrawlEmat(plantMat);
277
278 ResourceName clutterConfig;
279 container.Get("ClutterConfig", clutterConfig);
280 if (clutterConfig && clutterConfig.GetPath())
281 CrawlConf(clutterConfig);
282 }
283
284 //-----------------------------------------------------------------------------------------------
285 void CrawlEdds(ResourceName resourceName)
286 {
287 InsertFirstTime(resourceName);
288 }
289
290 //-----------------------------------------------------------------------------------------------
291 void CrawlConf(ResourceName resourceName, BaseContainer container = null)
292 {
293 bool isFirstTime = InsertFirstTime(resourceName);
294 if (!isFirstTime)
295 return;
296
297 Resource resource;
298 if (!container)
299 {
300 resource = BaseContainerTools.LoadContainer(resourceName);
301 container = resource.GetResource().ToBaseContainer();
302 }
303
304 CrawlConfObject(container);
305 }
306
307 //-----------------------------------------------------------------------------------------------
308 void CrawlConfObject(BaseContainer container)
309 {
310 BaseContainer ancestor = container.GetAncestor();
311 if (ancestor)
312 {
313 ResourceName myName = container.GetResourceName();
314 ResourceName ancestorName = ancestor.GetResourceName();
315 // If names differ, this container is object instantiated based on another
316 // container which is independent resource.
317 // TODO(kroslakmar): Fakes native function "IsExternal()" on resource name.
318 if (myName != ancestorName)
319 CrawlConf(ancestorName, ancestor);
320 }
321
322 for (int i = 0, iCount = container.GetNumVars(); i < iCount; i++)
323 {
324 string varName = container.GetVarName(i);
325 switch (container.GetDataVarType(i))
326 {
327 case DataVarType.OBJECT:
328 BaseContainer obj = container.GetObject(varName);
329 if (obj)
330 CrawlConfObject(obj);
331 break;
332 case DataVarType.RESOURCE_NAME:
333 ResourceName varVal;
334 container.Get(varName, varVal);
335 Crawl(varVal);
336 break;
337 case DataVarType.OBJECT_ARRAY:
338 BaseContainerList objects = container.GetObjectArray(varName);
339 for (int j = 0, jCount = objects.Count(); j < jCount; j++)
340 {
341 BaseContainer obj = objects.Get(j);
342 if (obj)
343 CrawlConfObject(obj);
344 }
345 break;
346 case DataVarType.RESOURCE_NAME_ARRAY:
347 auto varVal = new array<ResourceName>();
348 container.Get(varName, varVal);
349 foreach(ResourceName entry : varVal)
350 Crawl(entry);
351 break;
352 }
353 }
354 }
355};
356
357// Separate class from WorldExporterPlugin, since modding plugin class directly doesn't work well.
358class WorldExportScript
359{
360 void OnBeforeEntityProcessed(WorldExporterPlugin plugin, IEntitySource source)
361 {
362 }
363
364 void OnAfterEntityProcessed(WorldExporterPlugin plugin, IEntitySource source)
365 {
366 }
367
368 void OnAfterEntityCloned(WorldExporterPlugin plugin, IEntitySource oldEntSrc, IEntitySource newEntSrc)
369 {
370 }
371
372 void OnAfterEntityReparented(WorldExporterPlugin plugin, IEntitySource source, IEntitySource newParent)
373 {
374 }
375}
376
377[WorkbenchPluginAttribute(name: "Map Exporter", wbModules: { "WorldEditor" }, shortcut: "Ctrl+`", awesomeFontCode: 0xF338)] // 0xF338 = ↨
378class WorldExporterPlugin : WorkbenchPlugin
379{
380 [Attribute(defvalue: "", desc: "'WorldExporterConfig' type config", params: "conf")]
381 ResourceName m_ConfigResource;
382
383 [Attribute(defvalue: "c:/Work/MapExport/", desc: "Destination folder for the export")]
384 string m_ExportDestination;
385
386 [Attribute(defvalue: "true", desc: "Mostly for debug purposes, enables/disables copying of files identified during export, for normal export, leave enabled")]
387 bool m_AllowResourceCopy;
388
389 [Attribute(desc: "Export using root resources.")]
390 bool m_CrawlFromRootResources;
391
392 ref WorldExporterConfig m_Config;
393 WorldEditor m_WorldEditor;
394 ref map<string, string> m_mEntityClassBlacklist;
395 ref map<ResourceName,ResourceName> m_mCreatedPrefabs;
396 ref TStringArray m_aCreatedFiles;
397 ref set<BaseContainer> m_sDiscoveredPrefabs;
398 ref map<ResourceName,bool> m_mPrefabsNeedingReplace;//when prefab is inside this container, that means it's been processed, 'true' value means it needs to be replaced, 'false' it does not
399
400 ref set<ResourceName> m_sPrefabsToMigrate;
401 ref set<ResourceName> m_sModelsToMigrate;
402 ref set<ResourceName> m_sMaterialsToMigrate;
403 ref set<ResourceName> m_sTexturesToMigrate;
404 ref set<ResourceName> m_sMiscToMigrate;
405 ref set<ResourceName> m_sResourceExcludeGUIDs;//for faster ref
406 ref set<ResourceName> m_sGamematsToMigrate;
407 #ifdef WE_LOGGING_ENABLED
408 ref array<ref WorldExporterLogItem> m_aLogItems;
409 #endif
410
411
412 ref WorldExportScript MapSpecificScript;
413 WorldEditorAPI m_WEapi;
414 ResourceManager resourceManager;
415 bool m_PerformExport;
416 string m_sFilesystem;
417
418
419 //------------------------------------------------------------------------------------------------
420 [ButtonAttribute("Run Export", true)]
421 protected bool ButtonExport()
422 {
423 // if(!IsExportTargetFolderEmpty())
424 // {
425 // Print(string.Format("Export target folder'%1' not empty, clear before export", m_ExportDestination), LogLevel.ERROR);
426 // return true;
427 // }
428 m_PerformExport = true;
429 return false;
430 }
431 //-----------------------------------------------------------------------------------------------
432 protected bool Init()
433 {
434 m_Config = GetConfig(m_ConfigResource);
435 if (!m_Config || !m_Config.IsValid())
436 {
437 Print("Config load failed", LogLevel.ERROR);
438 return false;
439 }
440
441 m_sFilesystem = m_Config.m_sFilesystem + ":";
442
443 m_WorldEditor = Workbench.GetModule(WorldEditor);
444 m_WEapi = m_WorldEditor.GetApi();
445 resourceManager = Workbench.GetModule(ResourceManager);
446
447 m_mEntityClassBlacklist = new map<string, string>();
448 m_sResourceExcludeGUIDs = new set<ResourceName> ();
449
450 foreach(string turnInto:m_Config.m_aClassMappings)
451 {
452 TStringArray output = {};
453 turnInto.Split("::",output, true);
454 m_mEntityClassBlacklist.Insert(output[0], output[1]);
455 }
456
457 foreach(ResourceName resName: m_Config.m_aResourceExcludeGUIDs)
458 {
459 m_sResourceExcludeGUIDs.Insert(resName);
460 }
461
462 MapSpecificScript = new WorldExportScript();
463 return true;
464 }
465
466 protected void InitVars()
467 {
468 m_PerformExport = false;
469 m_sDiscoveredPrefabs = new set<BaseContainer>;
470 m_mCreatedPrefabs = new map<ResourceName, ResourceName>;
471 m_aCreatedFiles = {};
472 m_mPrefabsNeedingReplace = new map<ResourceName,bool>;
473 m_sPrefabsToMigrate = new set<ResourceName>;
474 m_sModelsToMigrate = new set<ResourceName>;
475 m_sMaterialsToMigrate = new set<ResourceName>;
476 m_sTexturesToMigrate = new set<ResourceName>;
477 m_sMiscToMigrate = new set<ResourceName>;
478 m_sGamematsToMigrate = new set<ResourceName>;
479 #ifdef WE_LOGGING_ENABLED
480 m_aLogItems = new array<ref WorldExporterLogItem>;
481 #endif
482
483
484
485 }
486 //-----------------------------------------------------------------------------------------------
487 override void Run()
488 {
489 InitVars();
490
491 bool reload = true;
492 while(reload)
493 {
494 reload = Workbench.ScriptDialog("Map Exporter", "This tool coverts the assets used on a map as well as the map \nentities based on the predefined rules, many of which can be adjusted in the config file.\nThe result is a folder containing the converted assets, as well as map data.\nIt's meant to strip the map of any gameplay specific features,\nleaving only the bare minimum to aproach a visual parity with the original map.\n\nAfter loading the map in the project the export is meant for, it's recommended to run the Re-save plugin which cleans the data by\ngetting rid of some properties of uknown types,\nreducing the number of errors displayed when loading the map.\n\n!!! This Tool expects to be provided a configuration file, as well as external script. \nThe script needs to be placed in the same folder as the config file !!!", this);
495 }
496
497 if(m_PerformExport)
498 {
499 if (!Init())//we need access to the config, which gets set in the ScriptDialog
500 {
501 Print("Init failed", LogLevel.ERROR);
502 return;
503 }
504 if (m_CrawlFromRootResources)
505 {
506 auto crawler = new ResourceExportCrawler();
507 foreach(ResourceName resourceName : m_Config.m_RootResources)
508 {
509 crawler.Crawl(resourceName);
510 }
511
512 ExportFiles(crawler.m_Visited);
513 }
514 else
515 {
516 PerformExport();
517 }
518 }
519 }
520 //-----------------------------------------------------------------------------------------------
521 void PerformExport()
522 {
523 if (m_WEapi)
524 {
525 array<IEntitySource> entitiesToProcess = {};
526
527 int selectedEntCount = m_WEapi.GetSelectedEntitiesCount();
528 if(selectedEntCount > 0)
529 {
530 for (int i = 0; i < selectedEntCount; i++)
531 {
532 IEntitySource entitySource = m_WEapi.GetSelectedEntity(i);
533 if(!entitySource.GetParent())
534 entitiesToProcess.Insert(entitySource);
535 }
536 }
537 else
538 {
539 int countAll = m_WEapi.GetEditorEntityCount();
540
541 Print("Entities overall:"+countAll);
542 for (int i = 0; i < countAll; i++)
543 {
544 IEntitySource entitySource = m_WEapi.GetEditorEntity(i);
545 if(!entitySource.GetParent())
546 entitiesToProcess.Insert(entitySource);
547 }
548 }
549
550 Print("walk entities array count: "+entitiesToProcess.Count());
551 m_WEapi.BeginEntityAction("MAP_EXPORT");
552 WBProgressDialog progress = new WBProgressDialog("Exporting map...", m_WorldEditor);
553 foreach(int x, IEntitySource entSource:entitiesToProcess)
554 {
555 if(x % 100 == 0)
556 {
557 Print("Entities processed: " + x + "/"+entitiesToProcess.Count());
558 progress.SetProgress((x / entitiesToProcess.Count()) * 0.9);
559 }
560
561 IEntitySource parent = entSource.GetParent();
562 if(!parent)
563 {
564 ProcessEntityRecur(entSource,null,false);
565 }
566 }
567 m_WEapi.EndEntityAction("MAP_EXPORT");
568
569 if(m_AllowResourceCopy)
570 PerformResourceExport(progress);
571 if(m_Config.m_bDeleteTempFiles)
572 ClearExportSourceData();
573 #ifdef WE_LOGGING_ENABLED
574 PrintLogs();
575 #endif
576 }
577 }
578 //-----------------------------------------------------------------------------------------------
579 override void Configure()
580 {
581 Workbench.ScriptDialog("Configure Map Exporter plugin", "", this);
582 }
583
584 //-----------------------------------------------------------------------------------------------
586 {
587 Resource configResource = Resource.Load(configPath);
588 if (!configResource.IsValid())
589 {
590 Print(string.Format("Cannot load config '%1'!", configPath), LogLevel.ERROR);
591 return null;
592 }
593
594 BaseResourceObject configContainer = configResource.GetResource();
595 if (!configContainer)
596 return null;
597
598 BaseContainer configBase = configContainer.ToBaseContainer();
599 if (!configBase)
600 return null;
601
602 if (configBase.GetClassName() != "WorldExporterConfig")
603 {
604 Print(string.Format("Config '%1' is of type '%2', must be 'WorldExporterConfig'!", configPath, configBase.GetClassName()), LogLevel.ERROR);
605 return null;
606 }
607
608 return WorldExporterConfig.Cast(BaseContainerTools.CreateInstanceFromContainer(configBase));
609 }
610
611
612 //-----------------------------------------------------------------------------------------------
613 bool AddAssetToMigrate(ExporterAssetType type, ResourceName resource, ResourceName resSource = string.Empty)
614 {
615 if (!resource)
616 return false;
617
618 if (!resource.GetPath())
619 {
620 return false;
621 }
622
623 bool registered = false;
624
625 switch (type)
626 {
627 case ExporterAssetType.PREFAB:
628 registered = m_sPrefabsToMigrate.Insert(resource);
629 break;
630 case ExporterAssetType.XOB:
631 registered = m_sModelsToMigrate.Insert(resource);
632 break;
633 case ExporterAssetType.MAT:
634 registered = m_sMaterialsToMigrate.Insert(resource);
635 break;
636 case ExporterAssetType.GAMEMAT:
637 registered = m_sGamematsToMigrate.Insert(resource);
638 break;
639 case ExporterAssetType.TXT:
640 registered = m_sTexturesToMigrate.Insert(resource);
641 break;
642 case ExporterAssetType.MISC:
643 registered = m_sMiscToMigrate.Insert(resource);
644 break;
645 default:
646 return false;
647 }
648
649 return registered;
650 }
651 //-----------------------------------------------------------------------------------------------
652 bool IsEntityClassBlacklisted(IEntitySource entSource)
653 {
654 string entClassName = entSource.GetClassName();
655
656 if(m_Config.m_aEntityClassWhitelist.Contains(entClassName))//first check whitelist, as some checks later on can be quite broad
657 return false;
658 if(m_mEntityClassBlacklist.Contains(entClassName))
659 return true;
660
661 foreach(string keyword:m_Config.m_aEntityClassBlacklistKeywords)
662 if(entClassName.Contains(keyword))
663 return true;
664
665 return false;
666 }
667 //-----------------------------------------------------------------------------------------------
668 string GetAlternateClassName(string currentName)
669 {
670 if(m_mEntityClassBlacklist.Contains(currentName))
671 return m_mEntityClassBlacklist.Get(currentName);
672 return "GenericEntity";
673 }
674 //-----------------------------------------------------------------------------------------------
675 bool IsComponentClassBlacklisted(string className)
676 {
677 return !m_Config.m_aComponentClassWhitelist.Contains(className);
678 }
679
680 //-----------------------------------------------------------------------------------------------
681 bool IsAnyComponentIncompatible(notnull IEntitySource entSource)
682 {
683 int componentsCount = entSource.GetComponentCount();
684 for (int i = 0; i < componentsCount; i++)
685 {
686 IEntityComponentSource componentSource = entSource.GetComponent(i);
687 if(IsComponentClassBlacklisted(componentSource.GetClassName()))
688 return true;
689
690 }
691 return false;
692 }
693 //-----------------------------------------------------------------------------------------------
694 bool DoesEntityNeedReplacing(IEntitySource entSource)
695 {
696 if(IsEntityClassBlacklisted(entSource))
697 return true;
698 if(IsAnyComponentIncompatible(entSource))
699 return true;
700 IEntitySource prefab = entSource.GetAncestor();
701 if(prefab)
702 return DoesPrefabNeedReplacingFast(prefab);
703 return false;
704 }
705 //-----------------------------------------------------------------------------------------------
706
707 //cached version, use this as it's faster
708 bool DoesPrefabNeedReplacingFast(BaseContainer prefab)
709 {
710 ResourceName resource = prefab.GetResourceName();
711 if(m_mPrefabsNeedingReplace.Contains(resource))
712 {
713 return m_mPrefabsNeedingReplace.Get(resource);
714 }
715 else
716 {
717 bool result = DoesPrefabNeedReplacing(prefab);
718 m_mPrefabsNeedingReplace.Insert(resource, result);
719 return result;
720 }
721 }
722 //-----------------------------------------------------------------------------------------------
723 //uncached version, only use from inside the cached version
724 bool DoesPrefabNeedReplacing(BaseContainer prefab)
725 {
726 //first check the class, that's the cheapest disqualifier
727 if(IsEntityClassBlacklisted(prefab))
728 {
729 return true;
730 }
731
732 // check components
733 if(IsAnyComponentIncompatible(prefab))
734 return true;
735
736 //now check immediate children
737 int childCount = prefab.GetNumChildren();
738
739 for(int i = 0; i < childCount; i++)
740 {
741 BaseContainer child = prefab.GetChild(i);
742 if(DoesEntityNeedReplacing(child))
743 {
744 return true;
745 }
746 }
747
748 RunPrefabDiscovery(prefab);//there may be a more optimal position for this call
749 return false;
750 }
751
752 void RegisterXob(BaseContainer meshObjectComp)
753 {
755 meshObjectComp.Get("Object", resourceName);
756
757 if(resourceName)
758 {
759 AddAssetToMigrate(ExporterAssetType.XOB, resourceName);
760 }
761
762 DiscoverMeshObjectMaterialOverrides(meshObjectComp, resourceName);
763 }
764 //-----------------------------------------------------------------------------------------------
765 //takes in an entity or prefab source, saves the xob and checks for any material overrides
766 //TODO:ideally should only do anything if the xob or the materials are overriden on the specific container, if it's at all possible check that
767 void RegisterPrefabXob(IEntitySource entSource)
768 {
769 BaseContainer container = FindComponentSource(entSource, "MeshObject");
770 //-------------------------- MeshObject ---------------------------
771 if (container)
772 {
773 BaseContainer ancestor = entSource.GetAncestor();
774
775 if(ancestor)
776 {
777 BaseContainer componentSourceAnc = FindComponentSource(ancestor, "MeshObject");
778 if(container == componentSourceAnc)
779 return;//no override
780 }
781
782 RegisterXob(container);
783 }
784 }
785 //-----------------------------------------------------------------------------------------------
786 void DiscoverMeshObjectMaterialOverrides(BaseContainer meshContainer, ResourceName resourceName)
787 {
788 BaseContainerList materials = meshContainer.GetObjectArray("Materials");
789 if (materials)
790 {
791 for (int i = 0; i < materials.Count(); i++)
792 {
793 BaseContainer materialData = materials.Get(i);
794 ResourceName matTgt;
795 materialData.Get("AssignedMaterial", matTgt);
796 if(matTgt)
797 {
798 RegisterMaterial(matTgt);
799 }
800 }
801 }
802 }
803 //-----------------------------------------------------------------------------------------------
804 void GetMaterialsFromXobs()
805 {
806 foreach(ResourceName res:m_sModelsToMigrate)
807 {
808 MetaFile meta = resourceManager.GetMetaFile(res.GetPath());
809 if(!meta)
810 {
811 return;
812 }
813 BaseContainerList configurations = meta.GetObjectArray("Configurations");
814 for (int cfgIdx = 0, cfgCount = configurations.Count(); cfgIdx < cfgCount; cfgIdx++)
815 {
816 BaseContainer cfg = configurations.Get(cfgIdx);
817
818 string materialAssigns;
819 array<string> pairs = new array<string>;
820 cfg.Get("MaterialAssigns", materialAssigns);
821 materialAssigns.Split(";", pairs, true);
822
823 foreach (string pair : pairs)
824 {
825 array<string> keyValue = new array<string>;
826 pair.Split(",", keyValue, true);
827 ResourceName resName = keyValue[1];
828 RegisterMaterial(resName);
829 }
830
831 BaseContainerList geometryParams = cfg.GetObjectArray("GeometryParams");
832 for (int i = 0, count = geometryParams.Count(); i < count; i++)
833 {
834 BaseContainer geometryParam = geometryParams.Get(i);
835 array<ResourceName> surfaceProperties;
836 geometryParam.Get("SurfaceProperties", surfaceProperties);
837 foreach(ResourceName gamemat : surfaceProperties)
838 {
839 RegisterGamemat(gamemat);
840 }
841 }
842 }
843 }
844 }
845
846 //-----------------------------------------------------------------------------------------------
847 void GetTexturesFromMaterials()
848 {
849 for(int j = 0; j < m_sMaterialsToMigrate.Count();j++)
850 {
851 ResourceName resName = m_sMaterialsToMigrate.Get(j);
852 Resource resource = BaseContainerTools.LoadContainer(resName);
853
854 if(!resource || !resource.IsValid())
855 return;
856
857 BaseResourceObject bro = resource.GetResource();
858
859 BaseContainer container = bro.ToBaseContainer();
860 if(!container)
861 return;
862 int varCount = container.GetNumVars();
863
864 for(int i = 0; i < varCount; i++)
865 {
866 if(container.GetDataVarType(i) == DataVarType.TEXTURE)
867 {
868 string varName = container.GetVarName(i);
869 ResourceName texture;
870 container.Get(varName,texture);
871
872 array<string> textures = new array<string>;
873 texture.Split(" ", textures, true);
874 if(textures.Count() > 1)
875 {
876 foreach(string txt:textures)
877 {
878 if(txt.Get(0) == "{")
879 {
880 AddAssetToMigrate(ExporterAssetType.TXT,txt, resName);
881 }
882 }
883 }
884 else
885 {
886 AddAssetToMigrate(ExporterAssetType.TXT,texture, resName);
887 }
888 }
889 }
890 }
891 }
892 //-----------------------------------------------------------------------------------------------
893 void RegisterMaterial(ResourceName resName)
894 {
895 if(m_sMaterialsToMigrate.Contains(resName))
896 return;
897 AddAssetToMigrate(ExporterAssetType.MAT,resName);
898
899 Resource res = BaseContainerTools.LoadContainer(resName);
900 if(!res)
901 return;
902 BaseResourceObject bro = res.GetResource();
903 if(!bro)
904 return;
905 BaseContainer containerMaterial = bro.ToBaseContainer();
906 if(!containerMaterial)
907 return;
908 BaseContainer anc = containerMaterial.GetAncestor();
909 if(anc)
910 RegisterMaterial(containerMaterial.GetAncestor().GetResourceName());
911
912 int varCount = containerMaterial.GetNumVars();
913
914 for(int i = 0; i < varCount; i++)
915 {
916 if(containerMaterial.GetDataVarType(i) == DataVarType.RESOURCE_NAME)
917 {
918 string varName = containerMaterial.GetVarName(i);
919 ResourceName material;
920 containerMaterial.Get(varName,material);
921 if(!material.GetPath() || !material.GetPath().Contains(".emat"))
922 continue;
923 RegisterMaterial(material);
924
925 }
926 }
927 }
928
929 //-----------------------------------------------------------------------------------------------
930 void RegisterGamemat(ResourceName resName)
931 {
932 bool registered = AddAssetToMigrate(ExporterAssetType.GAMEMAT, resName);
933 if (!registered)
934 return;
935
936 Resource res = BaseContainerTools.LoadContainer(resName);
937 if (!res)
938 return;
939
940 BaseResourceObject bro = res.GetResource();
941 if (!bro)
942 return;
943
944 BaseContainer container = bro.ToBaseContainer();
945 if (!container)
946 return;
947
948 BaseContainer anc = container.GetAncestor();
949 if (anc)
950 RegisterGamemat(anc.GetResourceName());
951 }
952
953 //-----------------------------------------------------------------------------------------------
954 //this method tries to identify(discover) prefabs that have not been discovered yet
955 void RunPrefabDiscovery(IEntitySource prefab)
956 {
957 #ifdef WE_LOGGING_ENABLED
958 int indx = LogTimedStart("RunPrefabDiscovery:"+prefab);
959 #endif
960
961 RegisterPrefabXob(prefab);//this is for prefab instance, inside another prefab, which can have model override
962
963 if(m_sDiscoveredPrefabs.Contains(prefab))
964 {
965 return;
966 }
967 ResourceName resName = prefab.GetResourceName();
968 if(resName && resName.GetPath())
969 {
970 m_sDiscoveredPrefabs.Insert(prefab);
971 }
972
973 int childCount = prefab.GetNumChildren();
974 for(int i = 0; i < childCount; i++)
975 {
976 IEntitySource child = prefab.GetChild(i);
977 RunPrefabDiscovery(child);
978 }
979
980 IEntitySource ancestor = prefab.GetAncestor();
981 if(ancestor)
982 RunPrefabDiscovery(ancestor);
983 #ifdef WE_LOGGING_ENABLED
984 LogTimedEnd(indx);
985 #endif
986
987 }
988 //-----------------------------------------------------------------------------------------------
989
990 void ProcessEntityRecur(IEntitySource entSource, IEntitySource parent, bool parentToBeDeleted, array<IEntitySource> toReparent = null)
991 {
992 int childCount = entSource.GetNumChildren();
993
994 IEntitySource newEntitySrc = entSource;
995 OnBeforeEntityProcessed(entSource);
996 bool isPrefabChild = IsPartOfPrefab(entSource);
997 bool toBeDeleted;
998 RegisterPrefabXob(entSource);//this is here because an entity placed in the world can have either xob override and/or material override
999 if(!isPrefabChild)
1000 {
1001 if(DoesEntityNeedReplacing(entSource))
1002 {
1003 newEntitySrc = CloneEntityFull(entSource, parent);
1004 if(!parentToBeDeleted)
1005 toBeDeleted = true;
1006 }
1007 else
1008 {
1009 if (entSource.GetParent() != parent)
1010 {
1011 IEntity entParent = m_WEapi.SourceToEntity(parent);
1012 IEntity entChild = m_WEapi.SourceToEntity(entSource);
1013 if(entParent && entChild)
1014 {
1015 toReparent.Insert(entSource);
1016 }
1017 }
1018 }
1019 }
1020
1021 array<IEntitySource> children = new array<IEntitySource>();
1022 for(int x = 0; x < childCount; x++)
1023 {
1024 IEntitySource childSource = entSource.GetChild(x);
1025 children.Insert(childSource);
1026 }
1027
1028 if(!children.IsEmpty())
1029 {
1030 array<IEntitySource> entitiesToReparent = {};
1031 foreach(IEntitySource child:children)
1032 {
1033 ProcessEntityRecur(child, newEntitySrc, toBeDeleted, entitiesToReparent);
1034 }
1035 #ifdef WE_LOGGING_ENABLED
1036 int indx = LogTimedStart("Reparenting:"+children.Count());
1037 #endif
1038 if(!entitiesToReparent.IsEmpty())
1039 {
1040 m_WEapi.ParentEntities(newEntitySrc, entitiesToReparent, false);
1041 foreach(IEntitySource ent: entitiesToReparent)
1042 OnAfterEntityReparented(ent,newEntitySrc);
1043 }
1044
1045 #ifdef WE_LOGGING_ENABLED
1046 LogTimedEnd(indx);
1047 #endif
1048 }
1049 if(toBeDeleted)
1050 {
1051 string name = entSource.GetName();
1052 m_WEapi.DeleteEntity(entSource);
1053 if(name)
1054 {
1055 newEntitySrc.SetName(name);
1056 }
1057 OnAfterEntityProcessed(newEntitySrc);
1058 }
1059 else if(!parentToBeDeleted)
1060 {
1061 OnAfterEntityProcessed(entSource);
1062 }
1063 }
1064
1065
1066 //-----------------------------------------------------------------------------------------------
1067 IEntitySource CloneEntityFull(IEntitySource entSource, IEntitySource parent)
1068 {
1069 string className = entSource.GetClassName();
1070
1071 if(IsEntityClassBlacklisted(entSource))
1072 {
1073 className = GetAlternateClassName(className);
1074 }
1075
1076 BaseContainer prefab = entSource.GetAncestor();
1077 if(prefab)
1078 {
1079 if(DoesPrefabNeedReplacingFast(prefab))
1080 {
1081 ResourceName newPrefab = ClonePrefabFast(prefab);
1082
1083 if(newPrefab)
1084 {
1085 //string fileName = FilePath.StripPath(newPrefab.GetPath());
1086 className = newPrefab.GetPath();
1087 }
1088 else
1089 Print("Something went wrong with prefab replace:" + prefab.GetResourceName(), LogLevel.ERROR);
1090 }
1091 }
1092
1093 IEntitySource newEntSrc = CloneSingleEntity(className, entSource, parent, entSource.GetLayerID());
1094
1095 CopyComponents(entSource, newEntSrc);
1096 return newEntSrc;
1097 }
1098 //-----------------------------------------------------------------------------------------------
1099 protected ResourceName ClonePrefabFast(BaseContainer prefab)
1100 {
1101 ResourceName newPrefab;
1102 ResourceName prefabResName = prefab.GetResourceName();
1103
1104 if(!m_mCreatedPrefabs.Contains(prefabResName))
1105 {
1106 newPrefab = ClonePrefabSlow(prefab);
1107 }
1108 else
1109 {
1110 newPrefab = m_mCreatedPrefabs.Get(prefabResName);
1111 }
1112 return newPrefab;
1113 }
1114 //-----------------------------------------------------------------------------------------------
1115 bool IsFromPrefabLibrary(ResourceName prefab)
1116 {
1117 return prefab.GetPath().Contains("PrefabLibrary");
1118 }
1119
1120 //-----------------------------------------------------------------------------------------------
1121 protected ResourceName ClonePrefabSlow(notnull BaseContainer originalPrefab)
1122 {
1123 ResourceName originalPrefabName = originalPrefab.GetResourceName();
1124 #ifdef WE_LOGGING_ENABLED
1125 int indx = LogTimedStart("ClonePrefabSlow:"+originalPrefabName);
1126 #endif
1127 BaseContainer ancestorPrefab = originalPrefab.GetAncestor();//prefab container this prefab container is inheriting from
1128
1129 ResourceName ancestorPrefabName;
1130 if(ancestorPrefab)
1131 {
1132 if(DoesPrefabNeedReplacingFast(ancestorPrefab))
1133 {
1134 ancestorPrefabName = ClonePrefabFast(ancestorPrefab);
1135 }
1136 else
1137 {
1138 ancestorPrefabName = ancestorPrefab.GetResourceName();
1139 }
1140 }
1141
1142 //this skips over the prefabs from PrefabLibrary in the inheritence of the newly created prefabs
1143 //...by returning the ancestor prefab as the cloned prefab, instead of the prefab from the PrefabLibrary
1144 if(m_Config.m_bSkipPrefabLibrary && IsFromPrefabLibrary(originalPrefabName) && ancestorPrefabName)
1145 {
1146 #ifdef WE_LOGGING_ENABLED
1147 LogTimedEnd(indx);
1148 #endif
1149 RegisterNewPrefab(originalPrefabName,ancestorPrefabName);
1150 return ancestorPrefabName;
1151 }
1152
1153 string originalPrefabPath = originalPrefabName.GetPath();
1154 string newPrefabPath = FilePath.Concat(m_Config.m_sExportCachePrefix, originalPrefabPath);
1155 string newPrefabPathAbs;
1156 Workbench.GetAbsolutePath(newPrefabPath, newPrefabPathAbs, false);
1157 IEntitySource entSrc;
1158 if(newPrefabPathAbs)
1159 {
1160 PrintFormat("New prefab alternative not found for %1, lets create it", originalPrefabName);
1161
1162 entSrc = DeepPrefabEntityCloneRecur(originalPrefab, null, ancestorPrefabName);
1163
1164 FileIO.MakeDirectory(FilePath.StripFileName(newPrefabPathAbs));
1165 m_WEapi.CreateEntityTemplate(entSrc, newPrefabPathAbs);//<------------ CREATE PREFAB
1166 resourceManager.WaitForFile(m_sFilesystem + newPrefabPath, 10000);
1167 ResourceName newPrefabName = Workbench.GetResourceName(newPrefabPath);//variable re-use
1168
1169 AddAssetToMigrate(ExporterAssetType.PREFAB, newPrefabName);
1170 RegisterNewPrefab(originalPrefabName, newPrefabName);
1171
1172 PrintFormat("new prefab ready for:%1, new resource name:%2", originalPrefabName, newPrefabName);
1173
1174 // Delete ent.
1175 if(entSrc)
1176 m_WEapi.DeleteEntity(entSrc);
1177 #ifdef WE_LOGGING_ENABLED
1178 LogTimedEnd(indx);
1179 #endif
1180 return newPrefabName;
1181 }
1182 return string.Empty;
1183 }
1184
1185 //-----------------------------------------------------------------------------------------------
1186 IEntitySource DeepPrefabEntityCloneRecur(IEntitySource prefab, IEntitySource parent, ResourceName ancestor)
1187 {
1188 IEntitySource newEntSrc;
1189 if(!IsPartOfPrefab(prefab))
1190 {
1191 string className = prefab.GetClassName();
1192
1193 if(IsEntityClassBlacklisted(prefab))
1194 {
1195 className = GetAlternateClassName(className);
1196 }
1197
1198 BaseContainer anc = GetPrefab(prefab);//okno_old_prefab
1199 if(anc)
1200 {
1201 if(DoesPrefabNeedReplacingFast(anc))
1202 {
1203 ResourceName newPrefab = ClonePrefabFast(anc);//okno_new_prefab
1204
1205 if(newPrefab)
1206 className = newPrefab;
1207 else
1208 Print("Something went wrong with prefab replace:" + anc.GetResourceName(), LogLevel.ERROR);
1209 }
1210 else
1211 {
1212 className = GetPrefabName(prefab);
1213 }
1214 }
1215
1216 newEntSrc = CloneSingleEntity(className, prefab, parent);//okno_new_prefab_instance
1217 if(ancestor && ancestor.GetPath())
1218 {
1219 newEntSrc.SetAncestor(ancestor);
1220
1221 }
1222 CopyComponents(prefab, newEntSrc);
1223 }
1224
1225 int childCount = prefab.GetNumChildren();
1226
1227 for(int i = 0; i < childCount;i++)
1228 {
1229 IEntitySource child = prefab.GetChild(i);
1230 if(!newEntSrc)
1231 {
1232 newEntSrc = parent.GetChild(i);
1233 }
1234
1235 DeepPrefabEntityCloneRecur(child,newEntSrc,string.Empty);
1236 }
1237 return newEntSrc;
1238 }
1239
1240
1241 //-----------------------------------------------------------------------------------------------
1242 void RegisterNewPrefab(ResourceName resNameOriginal, ResourceName resNameNew)
1243 {
1244 m_mCreatedPrefabs.Insert(resNameOriginal, resNameNew);
1245 m_aCreatedFiles.Insert(resNameNew.GetPath());
1246 }
1247
1248 //-----------------------------------------------------------------------------------------------
1249 bool IsPartOfPrefab(IEntitySource entSource)
1250 {
1251 BaseContainer thisEntPrefabRoot;
1252 if(entSource.GetAncestor() && entSource.GetAncestor().GetParent())
1253 thisEntPrefabRoot = entSource.GetAncestor().GetParent();
1254
1255 IEntitySource parentSource = entSource.GetParent();
1256
1257 BaseContainer parentPrefab;
1258 if(parentSource && parentSource.GetAncestor())
1259 parentPrefab = parentSource.GetAncestor();
1260
1261 return (thisEntPrefabRoot && parentPrefab && parentPrefab == thisEntPrefabRoot);
1262 }
1263 //-----------------------------------------------------------------------------------------------
1264 static BaseContainer GetPrefab(BaseContainer source)
1265 {
1266 BaseContainer container = source.GetAncestor();
1267 BaseContainer prefab;
1268 while(container)
1269 {
1270 if(container.GetResourceName() != ResourceName.Empty)
1271 {
1272 prefab = container;
1273 break;
1274 }
1275 container = container.GetAncestor();
1276 }
1277 return prefab;
1278 }
1279 //-----------------------------------------------------------------------------------------------
1280 static ResourceName GetPrefabName(BaseContainer source)
1281 {
1282 BaseContainer container = source.GetAncestor();
1283 ResourceName prefabRes;
1284 while(container)
1285 {
1286 if(container.GetResourceName() != ResourceName.Empty)
1287 {
1288 prefabRes = container.GetResourceName();
1289 break;
1290 }
1291 container = container.GetAncestor();
1292 }
1293 return prefabRes;
1294 }
1295
1296 //-----------------------------------------------------------------------------------------------
1297 void CopyContainerProperties(BaseContainer sourceContainer, BaseContainer targetContainer, BaseContainer targetEntity, array<ref ContainerIdPathEntry> path)
1298 {
1299 string varName;
1300 for (int v = 0, varCount = sourceContainer.GetNumVars(); v < varCount; v++)
1301 {
1302 varName = sourceContainer.GetVarName(v);
1303 if (!sourceContainer.IsVariableSetDirectly(varName))
1304 continue;
1305 switch (sourceContainer.GetDataVarType(v))
1306 {
1307 case DataVarType.SCALAR_ARRAY:
1308 {
1309 break;
1310 }
1311
1312 case DataVarType.RESOURCE_NAME:
1313 {
1314 ResourceName valueSrc, valueTrg;
1315 sourceContainer.Get(varName, valueSrc);
1316 targetContainer.Get(varName, valueTrg);
1317 if(valueSrc != valueTrg)
1318 m_WEapi.SetVariableValue(targetEntity, path, varName, valueSrc);
1319
1320 break;
1321 }
1322
1323 case DataVarType.STRING:
1324 {
1325 string valueSrc, valueTrg;
1326 sourceContainer.Get(varName, valueSrc);
1327 targetContainer.Get(varName, valueTrg);
1328 if(valueSrc != valueTrg)
1329 m_WEapi.SetVariableValue(targetEntity, path, varName, valueSrc);
1330
1331 break;
1332 }
1333 case DataVarType.INTEGER:
1334 {
1335 int valueSrc, valueTrg;
1336 sourceContainer.Get(varName, valueSrc);
1337 targetContainer.Get(varName, valueTrg);
1338
1339 if(valueSrc != valueTrg)
1340 m_WEapi.SetVariableValue(targetEntity, path, varName, valueSrc.ToString());
1341 break;
1342 }
1343 case DataVarType.SCALAR:
1344 {
1345 float valueSrc, valueTrg;
1346 sourceContainer.Get(varName, valueSrc);
1347 targetContainer.Get(varName, valueTrg);
1348
1349 if(valueSrc != valueTrg)
1350 m_WEapi.SetVariableValue(targetEntity, path, varName, valueSrc.ToString());
1351 break;
1352 }
1353 case DataVarType.VECTOR3:
1354 {
1355 vector valueSrc, valueTrg;
1356 sourceContainer.Get(varName, valueSrc);
1357 targetContainer.Get(varName, valueTrg);
1358
1359 if(valueSrc != valueTrg)
1360 m_WEapi.SetVariableValue(targetEntity, path, varName, valueSrc.ToString(false));
1361 break;
1362 }
1363 case DataVarType.BOOLEAN:
1364 {
1365 int valueSrc, valueTrg;
1366 sourceContainer.Get(varName, valueSrc);
1367 targetContainer.Get(varName, valueTrg);
1368
1369 if(valueSrc != valueTrg)
1370 {
1371 m_WEapi.SetVariableValue(targetEntity, path, varName, valueSrc.ToString());
1372 }
1373 break;
1374 }
1375 case DataVarType.FLAGS:
1376 {
1377 int valueSrc, valueTrg;
1378 sourceContainer.Get(varName, valueSrc);
1379 targetContainer.Get(varName, valueTrg);
1380
1381 if(valueSrc != valueTrg)
1382 m_WEapi.SetVariableValue(targetEntity, path, varName, valueSrc.ToString());
1383 break;
1384 }
1385 default:
1386 {
1387 Print(string.Format("Cannot copy variable '%1' from template, it has unsupported type %2!", varName, typename.EnumToString(DataVarType, sourceContainer.GetDataVarType(v))), LogLevel.ERROR);
1388 }
1389 }
1390 }
1391 }
1392 //-----------------------------------------------------------------------------------------------
1393 void CopyComponents(IEntitySource source, IEntitySource target)
1394 {
1395 array<string> componentsToCopy = {"MeshObject", "Hierarchy", "RigidBody"};
1396 foreach (string componentName : componentsToCopy)
1397 {
1398 CopyComponent(componentName, source, target);
1399 }
1400 }
1401
1402 //-----------------------------------------------------------------------------------------------
1403 void CopyComponent(string componentName, IEntitySource source, IEntitySource target)
1404 {
1405 BaseContainer componentSource = FindComponentSource(source, componentName);
1406 BaseContainer ancestor = source.GetAncestor();
1407
1408 if(ancestor)
1409 {
1410 BaseContainer componentSourceAnc = FindComponentSource(ancestor, componentName);
1411 if(componentSource == componentSourceAnc)
1412 return;//no override
1413 }
1414
1415 if (componentSource)
1416 {
1417 array<ref ContainerIdPathEntry> containerPath = {new ContainerIdPathEntry(componentName)};
1418 BaseContainer componentTarget = FindComponentSource(target, componentName);
1419
1420 if (!componentTarget)
1421 {
1422 componentTarget = m_WEapi.CreateComponent(target, componentName);
1423 }
1424
1425 CopyContainerProperties(componentSource, componentTarget, target, containerPath);
1426 CopyContainerPropertiesSpecial(componentName, componentSource, componentTarget, target, containerPath);
1427 }
1428 }
1429 //-----------------------------------------------------------------------------------------------
1430 void CopyContainerPropertiesSpecial(string componentName, BaseContainer sourceComponent, BaseContainer targetComponent, BaseContainer targetEntity, array<ref ContainerIdPathEntry> path)
1431 {
1432 if(componentName == "MeshObject")
1433 {
1434 RegisterXob(sourceComponent);
1435 if(!sourceComponent.IsVariableSetDirectly("Materials"))
1436 return;
1437
1438 BaseContainerList materialsSource = sourceComponent.GetObjectArray("Materials");
1439 BaseContainerList materialsTarget = targetComponent.GetObjectArray("Materials");
1440
1441 if (materialsSource)
1442 {
1443 for (int i = 0; i < materialsSource.Count(); i++)
1444 {
1445 BaseContainer materialDataSource = materialsSource.Get(i);
1446
1447 ResourceName matSrc, nameSrc;
1448 materialDataSource.Get("AssignedMaterial", matSrc);
1449 materialDataSource.Get("SourceMaterial", nameSrc);
1450
1451 m_WEapi.CreateObjectArrayVariableMember(targetEntity, path, "Materials", "MaterialAssignClass", i);
1452
1453 array<ref ContainerIdPathEntry> containerPath = {};
1454 foreach(ContainerIdPathEntry entry: path)
1455 containerPath.Insert(entry);
1456 containerPath.Insert(new ContainerIdPathEntry("Materials", i)); // Take the first point
1457
1458 m_WEapi.SetVariableValue(targetEntity, containerPath, "SourceMaterial", nameSrc);
1459 m_WEapi.SetVariableValue(targetEntity, containerPath, "AssignedMaterial", matSrc);
1460 }
1461 }
1462 }
1463 }
1464 //-----------------------------------------------------------------------------------------------
1465 void ExportFiles(set<ResourceName> resourceNames)
1466 {
1467 foreach(ResourceName name:resourceNames)
1468 {
1469 if(m_sResourceExcludeGUIDs.Contains(name))
1470 continue;//skip resource when excluded
1471 string filePath = name.GetPath();
1472 ExportFile(filePath);
1473 }
1474 }
1475 //-----------------------------------------------------------------------------------------------
1476 void ExportFile(string srcFilePath)
1477 {
1478 string dstFilePath = srcFilePath;
1479 if (dstFilePath.StartsWith(m_Config.m_sExportCachePrefix))
1480 {
1481 int prefixLen = m_Config.m_sExportCachePrefix.Length() + 1; // +1 for path separator
1482 dstFilePath = dstFilePath.Substring(prefixLen, dstFilePath.Length() - prefixLen);
1483 }
1484 dstFilePath = FilePath.Concat(m_ExportDestination, dstFilePath);
1485
1486 FileIO.MakeDirectory(FilePath.StripFileName(dstFilePath));
1487
1488 string srcMetaPath = srcFilePath + ".meta";
1489 string dstMetaPath = dstFilePath + ".meta";
1490
1491 if (FileIO.FileExists(srcFilePath))
1492 FileIO.CopyFile(srcFilePath, dstFilePath);
1493
1494 if (FileIO.FileExists(srcMetaPath))
1495 FileIO.CopyFile(srcMetaPath, dstMetaPath);
1496
1497 if (m_Config.m_bExportSourceFiles)
1498 {
1499 MetaFile meta = resourceManager.GetMetaFile(srcFilePath);
1500 if (meta)
1501 {
1502 string sourceFilePath = meta.GetSourceFilePath();
1503 string fsName = FilePath.FileSystemNameFromFileName(sourceFilePath);
1504 string fsComplete = "$"+fsName+":";
1505 sourceFilePath.Replace(fsComplete,"");
1506 string sourceFilename = FilePath.StripPath(sourceFilePath);
1507 if(!sourceFilename.IsEmpty())
1508 {
1509 string destination3 = m_ExportDestination+sourceFilePath;
1510 if (FileIO.FileExists(sourceFilePath))
1511 FileIO.CopyFile(sourceFilePath, destination3);
1512 }
1513 meta.Release();
1514 }
1515 }
1516 }
1517 //-----------------------------------------------------------------------------------------------
1518 void ExportMapData()
1519 {
1520 TStringArray files = {};
1521 FileIO.FindFiles(files.Insert,m_Config.m_sExportMapDir,string.Empty);
1522 foreach(string filePath:files)
1523 ExportFile(filePath);
1524 }
1525 //-----------------------------------------------------------------------------------------------
1526 void ExportSharedData()
1527 {
1528 set<ResourceName> foundResources = new set<ResourceName>();
1529
1530 array<string> extensions = {};
1531 m_Config.m_sCopyPathsMixedExtensions.Split(";",extensions, true);
1532
1533 foreach(string path: m_Config.m_aCopyPathsMixed)
1534 {
1536 filter.rootPath = m_sFilesystem + path;
1537 filter.fileExtensions = extensions;
1538
1539 ResourceDatabase.SearchResources(filter, foundResources.Insert);
1540 }
1541
1542 foreach(string path: m_Config.m_aModelPaths)
1543 {
1545 filter.rootPath = m_sFilesystem + path;
1546 filter.fileExtensions = {"xob"};
1547
1548 ResourceDatabase.SearchResources(filter, foundResources.Insert);
1549 }
1550
1551 ExportFiles(foundResources);
1552 }
1553 //-----------------------------------------------------------------------------------------------
1554 #ifdef WE_LOGGING_ENABLED
1555 int LogTimedStart(string message)
1556 {
1557 WorldExporterLogItem item = new WorldExporterLogItem();
1558 if(item)
1559 {
1560 if(message)
1561 item.messageA = message;
1562 item.StartTime = System.GetTickCount();
1563 }
1564 return m_aLogItems.Insert(item);
1565 }
1566 //-----------------------------------------------------------------------------------------------
1567 void LogTimedEnd(int index, string message = string.Empty)
1568 {
1569 if(m_aLogItems.IsIndexValid(index))
1570 {
1571 WorldExporterLogItem item = m_aLogItems.Get(index);
1572
1573 if(item)
1574 {
1575 if(message)
1576 item.messageB = message;
1577 item.EndTime = System.GetTickCount();
1578 }
1579 }
1580 }
1581 //-----------------------------------------------------------------------------------------------
1582 void PrintLogs()
1583 {
1584 foreach(WorldExporterLogItem item: m_aLogItems)
1585 {
1586 Print(string.Format("Timed:,%1,%2,took(ms):,%3,", item.messageA, item.messageB, item.GetTime().ToString()));
1587 }
1588 }
1589
1590 #endif
1591 //-----------------------------------------------------------------------------------------------
1592 IEntitySource CloneSingleEntity(string className, IEntitySource oldEntSrc, IEntitySource parent, int layerID = 0)
1593 {
1594 #ifdef WE_LOGGING_ENABLED
1595 int indx = LogTimedStart("CloneSingleEntity:"+className);
1596 #endif
1597
1598 vector angles;
1599
1600 oldEntSrc.Get("angles", angles);
1601
1602 IEntitySource newEntSrc = m_WEapi.CreateEntityExt(className, string.Empty, layerID, parent, vector.Zero, angles, 0);
1603 if(newEntSrc)
1604 OnAfterEntityCloned(oldEntSrc, newEntSrc);
1605 else
1606 {
1607 //cloning failed TODO: add print
1608 }
1609 #ifdef WE_LOGGING_ENABLED
1610 LogTimedEnd(indx);
1611 #endif
1612 return newEntSrc;
1613 }
1614 //-----------------------------------------------------------------------------------------------
1615 void OnBeforeEntityProcessed(IEntitySource source)
1616 {
1617 MapSpecificScript.OnBeforeEntityProcessed(this, source);
1618 }
1619 //-----------------------------------------------------------------------------------------------
1620 void OnAfterEntityProcessed(IEntitySource source)
1621 {
1622 MapSpecificScript.OnAfterEntityProcessed(this, source);
1623 }
1624 //-----------------------------------------------------------------------------------------------
1625 void OnAfterEntityCloned(IEntitySource oldEntSrc, IEntitySource newEntSrc)
1626 {
1627 CopyEntityProperties(oldEntSrc, newEntSrc);
1628 MapSpecificScript.OnAfterEntityCloned(this, oldEntSrc, newEntSrc);
1629 }
1630 //-----------------------------------------------------------------------------------------------
1631 void OnAfterEntityReparented(IEntitySource source, IEntitySource newParent)
1632 {
1633 MapSpecificScript.OnAfterEntityReparented(this, source, newParent);
1634 }
1635 //-----------------------------------------------------------------------------------------------
1636 void CopyEntityProperties( IEntitySource oldEntSrc, IEntitySource newEntSrc)
1637 {
1638 if(oldEntSrc.IsVariableSetDirectly("Flags"))
1639 {
1641 oldEntSrc.Get("Flags", flags);
1642 m_WEapi.SetVariableValue(newEntSrc, {}, "Flags", flags.ToString()); // Set Name to given value
1643 }
1644 if(oldEntSrc.IsVariableSetDirectly("scale"))
1645 {
1646 float scale;
1647 oldEntSrc.Get("scale", scale);
1648 m_WEapi.SetVariableValue(newEntSrc, {}, "scale", scale.ToString()); // Set Name to given value
1649 }
1650 if(oldEntSrc.IsVariableSetDirectly("coords"))
1651 {
1652 vector coords;
1653 oldEntSrc.Get("coords", coords);
1654 m_WEapi.SetVariableValue(newEntSrc, {}, "coords", coords.ToString(false)); // Set Name to given value
1655 }
1656 if(oldEntSrc.IsVariableSetDirectly("placement"))
1657 {
1658 string placement;
1659 oldEntSrc.Get("placement", placement);
1660 m_WEapi.SetVariableValue(newEntSrc, {}, "placement", placement); // Set Name to given value
1661 }
1662 }
1663
1664 //-----------------------------------------------------------------------------------------------
1665 // this iterates through all prefabs seen on the map
1666 void ProcessDiscoveredPrefabs()
1667 {
1668 foreach(BaseContainer prefab:m_sDiscoveredPrefabs)
1669 {
1670 RegisterPrefabXob(prefab);
1671 ResourceName resName = prefab.GetResourceName();
1672 if(!m_mCreatedPrefabs.Contains(resName))//exclude prefabs that are being replaced by a new prefab
1673 {
1674 AddAssetToMigrate(ExporterAssetType.PREFAB,resName);
1675 }
1676 }
1677 }
1678 //-----------------------------------------------------------------------------------------------
1679 void PerformResourceExport(WBProgressDialog dialog)
1680 {
1681 ProcessDiscoveredPrefabs();
1682 GetMaterialsFromXobs();
1683 GetTexturesFromMaterials();
1684
1685 auto crawler = new ResourceExportCrawler();
1686
1687 ExportFiles(m_sPrefabsToMigrate);
1688 dialog.SetProgress(0.91);
1689 ExportFiles(m_sModelsToMigrate);
1690 dialog.SetProgress(0.92);
1691 // ExportFiles(m_sMaterialsToMigrate);
1692 // dialog.SetProgress(0.93);
1693 ExportFiles(m_sTexturesToMigrate);
1694 dialog.SetProgress(0.94);
1695 // ExportFiles(m_sMiscToMigrate);
1696 // dialog.SetProgress(0.95);
1697
1698 foreach (ResourceName resourceName : m_sMiscToMigrate) crawler.Crawl(resourceName);
1699 foreach (ResourceName resourceName : m_sMaterialsToMigrate) crawler.Crawl(resourceName);
1700 foreach (ResourceName resourceName : m_sGamematsToMigrate) crawler.Crawl(resourceName);
1701 foreach (ResourceName resourceName : m_Config.m_RootResources) crawler.Crawl(resourceName);
1702
1703 ExportFiles(crawler.m_Visited);
1704 dialog.SetProgress(0.96);
1705
1706 #ifdef WE_LOGGING_ENABLED
1707 Print("---------------------------Models------------------------------");
1708 foreach(ResourceName name:m_sModelsToMigrate)
1709 Print(name);
1710
1711 Print("---------------------------Materials------------------------------");
1712 foreach(ResourceName name:m_sMaterialsToMigrate)
1713 Print(name);
1714
1715 Print("---------------------------Textures------------------------------");
1716 foreach(ResourceName name:m_sTexturesToMigrate)
1717 Print(name);
1718
1719 Print("-------------------------Prefabs --------------------------------");
1720 foreach(ResourceName name:m_sPrefabsToMigrate)
1721 Print(name);
1722
1723 Print("-------------------------Misc --------------------------------");
1724 foreach(ResourceName name:m_sMiscToMigrate)
1725 Print(name);
1726 #endif
1727
1728 // ExportSharedData();
1729 dialog.SetProgress(0.98);
1730 m_WorldEditor.Save();//Save the world
1731 if (m_Config.m_ExportMapData)
1732 ExportMapData();
1733 dialog.SetProgress(0.99);
1734 }
1735 //-----------------------------------------------------------------------------------------------
1736 void ClearExportSourceData()
1737 {
1738 foreach(ResourceName resName:m_mCreatedPrefabs)
1739 {
1740 DeleteFilePlus(resName.GetPath());
1741 }
1742 foreach(string filePath:m_aCreatedFiles)
1743 {
1744 DeleteFilePlus(filePath);
1745 }
1746 }
1747 //-----------------------------------------------------------------------------------------------
1748 void DeleteFilePlus(string path)
1749 {
1750 string pathMeta = path +".meta";
1751
1752 FileIO.DeleteFile(path);
1753 FileIO.DeleteFile(pathMeta);
1754 }
1755 //-----------------------------------------------------------------------------------------------
1756 bool IsExportTargetFolderEmpty()
1757 {
1758 TStringArray filesAndDirs = {};
1759 FileIO.FindFiles(filesAndDirs.Insert,m_ExportDestination, string.Empty);
1760 return filesAndDirs.Count() == 0;
1761 }
1762 //--------------------------------------------------------
1763 static IEntityComponentSource FindComponentSource(IEntitySource prefabEntity, string componentClassName)
1764 {
1765 if (!prefabEntity)
1766 return null;
1767
1768 IEntityComponentSource componentSource;
1769 for (int i, componentsCount = prefabEntity.GetComponentCount(); i < componentsCount; i++)
1770 {
1771 componentSource = prefabEntity.GetComponent(i);
1772 if (componentSource.GetClassName() == componentClassName)
1773 return componentSource;
1774 }
1775
1776 return null;
1777 }
1778}
1779#endif
SCR_EAIThreatSectorFlags flags
string path
vector scale
override void Init()
void ContainerIdPathEntry(string propertyName, int index=-1)
Definition worldEditor.c:30
@ PREFAB
GenerateFlowMaps WorkbenchPlugin WorkbenchPluginAttribute("Regenerate river flow-maps", "Generate and save/overwrite river flow-maps", "", "", {"WorldEditor"}, "", 0xf773)
Definition FlowmapTool.c:59
ref array< string > coords
ref array< string > angles
SCR_AIAnimation_Loitering BaseContainerProps
Commanding menu commanding element class.
ResourceName resourceName
Definition SCR_AIGroup.c:66
EDamageType type
SCR_DestructionSynchronizationComponentClass ScriptComponentClass int index
override void Run()
ResourceName GetConfig()
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
enum EAmmoType MISC
override void Configure()
class WorkbenchDialog_AbortRetryIgnore ButtonAttribute("OK", true)
Object holding reference to resource. In destructor release the resource.
Definition Resource.c:25
Object used for holding filtering params for ResourceDatabase.SearchResources() method.
Definition System.c:9
Definition Types.c:486
DataVarType
Definition DataVarType.c:18
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
EntityFlags
Various entity flags.
Definition EntityFlags.c:14
PerceptionManagerClass GenericEntityClass GetTime()
array< string > TStringArray
Definition Types.c:385
array< ResourceName > TResourceNameArray
Definition Types.c:394