Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
ResourceProcessorTool.c
Go to the documentation of this file.
1[WorkbenchPluginAttribute("Batch resource processor", "Perform simple checks and fixes on resource files", "", "", {"ResourceManager"},"",0xf15b)]
2class ResourceProcessorPlugin: WorkbenchPlugin
3{
4 [Attribute(uiwidget: UIWidgets.EditBox, desc: "Types (file extensions) to process")]
5 ref array<string> FileTypes;
6
7 [Attribute("", UIWidgets.FileNamePicker, "Check only textures whose path starts with given filter string.", params:"folders")]
8 string PathStartsWith;
9
10 [Attribute("", UIWidgets.EditBox, "Check only textures whose path contains given filter string.")]
11 string PathContains;
12
13 [Attribute("", UIWidgets.EditBox, "Check only textures whose path ends with given filter string.")]
14 string PathEndsWith;
15
16 [Attribute("true", UIWidgets.CheckBox, "Change configuration inheritance etc")]
17 bool FixMetaFile;
18
19 [Attribute("true", UIWidgets.CheckBox, "Resaves metafile even if it's without changes")]
20 bool ForceResaveMetaFile;
21
22 [Attribute("true", UIWidgets.CheckBox, "Report missing meta-file")]
23 bool ReportMissingMetaFile;
24
25 [Attribute("true", UIWidgets.CheckBox, "Report missing configurations")]
26 bool ReportMissingConfigurations;
27
28 [Attribute("true", UIWidgets.CheckBox, "Report custom property values")]
29 bool ReportCustomPropertyValues;
30
31 [Attribute("false", UIWidgets.CheckBox, "Fix custom property values (sets all PC custom changes to all other platforms)")]
32 bool FixCustomPropertyValues;
33
34 ref array<string> m_Resources = new array<string>;
35
36 //----------------------------------------------------------------------------------------------
37 void ResourceProcessorPlugin()
38 {
39 }
40
41 //----------------------------------------------------------------------------------------------
42 [ButtonAttribute("Run", true)]
43 bool OK()
44 {
45 return true;
46 }
47
48 //----------------------------------------------------------------------------------------------
49 [ButtonAttribute("Cancel")]
50 bool Cancel()
51 {
52 return false;
53 }
54
55
56 static const string MeshObjectCommon = "Common";
57
58
59 //----------------------------------------------------------------------------------------------
60 bool TestAgainstFilter(string resource)
61 {
62 int resourceLength = resource.Length();
63
64 int prefixLength = PathStartsWith.Length();
65 if (resourceLength < prefixLength)
66 return false;
67
68 int suffixLength = PathEndsWith.Length();
69 if (resourceLength < suffixLength)
70 return false;
71
72 int subLength = PathContains.Length();
73 if (resourceLength < subLength)
74 return false;
75
76 resource.ToLower();
77 if (!resource.StartsWith(PathStartsWith))
78 return false;
79
80 if (!resource.EndsWith(PathEndsWith))
81 return false;
82
83 if (!resource.Contains(PathContains))
84 return false;
85
86 return true;
87 }
88
89 //----------------------------------------------------------------------------------------------
90 void Find(ResourceName resName, string filePath)
91 {
92 if (TestAgainstFilter(filePath))
93 m_Resources.Insert(filePath);
94 }
95
96 //----------------------------------------------------------------------------------------------
97 bool CheckContainersVar(string resource, notnull array<string> platformPrefixes, notnull array<BaseContainer> containers, string varName, DataVarType type)
98 {
99 BaseContainer pc = containers[0];
100 bool isSetOnPC = pc.IsVariableSetDirectly(varName);
101 bool bRes = true;
102
103 if (type == DataVarType.OBJECT)
104 {
105 array<BaseContainer> subContainers = {};
106 array<string> subPlatformPrefixes = {};
107
108 for (int iPlatform = 0; iPlatform < containers.Count(); iPlatform++)
109 {
110 BaseContainer platform = containers[iPlatform];
111 subContainers.Insert(platform.GetObject(varName));
112 subPlatformPrefixes.Insert(platformPrefixes[iPlatform] + "." + varName);
113 }
114
115 BaseContainer pcSubContainer = subContainers[0];
116 if (pcSubContainer)
117 {
118 int nVars = pcSubContainer.GetNumVars();
119 for (int iVar = 0; iVar < nVars; iVar++)
120 {
121 string subVarName = pcSubContainer.GetVarName(iVar);
122
123 if (!CheckContainersVar(resource, subPlatformPrefixes, subContainers, subVarName, pcSubContainer.GetDataVarType(iVar)))
124 {
125 bRes = false;
126 }
127 }
128 return bRes;
129 }
130 }
131
132 for (int iPlatform = 1; iPlatform < containers.Count(); iPlatform++)
133 {
134 BaseContainer platform = containers[iPlatform];
135 bool isSet = platform.IsVariableSetDirectly(varName);
136 bool isInherited = false;
137
138 if (platformPrefixes[iPlatform].StartsWith("HEADLESS"))
139 continue;
140
141 if (platform.GetAncestor() && platform.GetAncestor().GetName() == pc.GetName())
142 {
143 isInherited = true;
144 }
145
146 //--
147
148 if (isSetOnPC)
149 {
150 if (isInherited)
151 {
152 if (isSet)
153 {
154 string valPC;
155 string valPlatform;
156
157 if (type != DataVarType.OBJECT_ARRAY)
158 {
159 pc.Get(varName, valPC);
160 pc.Get(varName, valPlatform);
161 }
162
163 if (valPC != valPlatform)
164 {
165 if (FixCustomPropertyValues)
166 {
167 FixIssue(resource, pc, platform, platformPrefixes[iPlatform], varName);
168 }
169 else
170 {
171 ReportIssue(resource, "Property inherited from PC, but overridden on platform: " + platformPrefixes[iPlatform] + "." + varName);
172 }
173 bRes = false;
174 }
175 }
176 }
177 else
178 {
179 if (!isSet)
180 {
181 if (FixCustomPropertyValues)
182 {
183 FixIssue(resource, pc, platform, platformPrefixes[iPlatform], varName);
184 }
185 else
186 {
187 ReportIssue(resource, "Property set on PC, but not set on platform: " + platformPrefixes[iPlatform] + "." + varName);
188 }
189 bRes = false;
190 }
191 }
192 }
193 else
194 {
195 if (isSet)
196 {
197 if (FixCustomPropertyValues)
198 {
199 FixIssue(resource, pc, platform, platformPrefixes[iPlatform], varName);
200 }
201 else
202 {
203 ReportIssue(resource, "Property not set on PC, but set on plarform: " + platformPrefixes[iPlatform] + "." + varName);
204 }
205 bRes = false;
206 }
207 }
208 }
209
210 return bRes;
211 }
212
213 //----------------------------------------------------------------------------------------------
214 bool Execute()
215 {
216 PathStartsWith.ToLower();
217 PathContains.ToLower();
218 PathEndsWith.ToLower();
219
220 m_Resources.Clear();
221
223 filter.fileExtensions = FileTypes;
224 ResourceDatabase.SearchResources(filter, Find);
225
226 m_Resources.Sort();
227
228 bool bRes = true;
229 ResourceManager rb = Workbench.GetModule(ResourceManager);
230 WBProgressDialog progress = new WBProgressDialog("Processing...", rb);
231
232 Print("Batch resource processor - BEGIN");
233
234 float count = m_Resources.Count();
235
236 foreach (int resourceIdx, string resource : m_Resources)
237 {
238 progress.SetProgress(resourceIdx / count);
239
240 MetaFile meta = rb.GetMetaFile(resource);
241 if (!meta)
242 {
243 if (ReportMissingMetaFile)
244 {
245 ReportIssue(resource, "meta-file is missing");
246 bRes = false;
247 }
248 continue;
249 }
250
251 BaseContainerList configurations = meta.GetObjectArray("Configurations");
252 if (!configurations)
253 {
254 if (ReportMissingConfigurations)
255 {
256 ReportIssue(resource, "meta-file is missing 'Configurations' property");
257 bRes = false;
258 }
259 meta.Release();
260 continue;
261 }
262
263 bool anyChangeInMetaFile = ForceResaveMetaFile;
264
265 if (ReportCustomPropertyValues || FixCustomPropertyValues)
266 {
267 int nPlatforms = configurations.Count();
268
269 ResourceName pcConfigName = configurations[0].GetResourceName();
270 array<string> pcConfigVarsChanged = {};
271 BaseContainer pcPlatformConf = configurations.Get(0);
272
273 //---
274 array<BaseContainer> containers = {};
275 array<string> platformPrefixes = {};
276
277 for (int iPlatform = 0; iPlatform < nPlatforms; iPlatform++)
278 {
279 BaseContainer platformConf = configurations.Get(iPlatform);
280 containers.Insert(platformConf);
281 platformPrefixes.Insert(platformConf.GetName());
282 }
283
284 int nVars = pcPlatformConf.GetNumVars();
285 for (int iVar = 0; iVar < nVars; iVar++)
286 {
287 string varName = pcPlatformConf.GetVarName(iVar);
288
289 if (!CheckContainersVar(resource, platformPrefixes, containers, varName, pcPlatformConf.GetDataVarType(iVar)))
290 {
291 bRes = false;
292 if (FixCustomPropertyValues)
293 anyChangeInMetaFile = true;
294 }
295 }
296 }
297
298 if(FixMetaFile)
299 {
300 BaseContainer conf = configurations.Get(0);
301 string className = conf.GetClassName();
302 if( IsMeshObject(className) )
303 {
304 if( FixMeshObjectMetaFile(meta, resource) )
305 {
306 bRes = false;
307 anyChangeInMetaFile = true;
308 }
309 }
310 else if( IsSound(className) )
311 {
312 if( FixSoundMetaFile(meta, resource) )
313 anyChangeInMetaFile = true;
314 }
315 else if( IsParticleEffect(className) )
316 {
317 if( FixParticleEffectMetaFile(meta, resource) )
318 anyChangeInMetaFile = true;
319 }
320 }
321
322 if(anyChangeInMetaFile )
323 {
324// Print(resource);
325 meta.Save();
326 }
327 meta.Release();
328 }
329
330 Print("Batch resource processor - END");
331
332 return bRes;
333 }
334
335 //----------------------------------------------------------------------------------------------
336 override void Run()
337 {
338 if (!Workbench.ScriptDialog("Batch resource processor", "", this))
339 return;
340
341 Execute();
342 }
343
344 //----------------------------------------------------------------------------------------------
345 // CLI: -FileTypes="xob,edds" PathStartsWith="$ArmaReforger:Assets/Structures/Houses"
346 override void RunCommandline()
347 {
348 FixCustomPropertyValues = false;
349 FixMetaFile = false;
350 ForceResaveMetaFile = false;
351
352 ReportMissingMetaFile = true;
353 ReportMissingConfigurations = true;
354 ReportCustomPropertyValues = true;
355
356 FileTypes.Clear();
357 PathStartsWith = string.Empty;
358 PathContains = string.Empty;
359 PathEndsWith = string.Empty;
360
361 ResourceManager rm = Workbench.GetModule(ResourceManager);
362 string cli;
363
364 rm.GetCmdLine("-FileTypes", cli);
365 cli.Split(",", FileTypes, true);
366
367 rm.GetCmdLine("-PathStartsWith", PathStartsWith);
368 rm.GetCmdLine("-PathContains", PathContains);
369 rm.GetCmdLine("-PathEndsWith", PathEndsWith);
370
371 Print("BatchMeshObjectProcessorPlugin commandline:");
372 Print(PathStartsWith);
373 Print(PathContains);
374 Print(PathEndsWith);
375 FileTypes.Debug();
376
377 if (Execute())
378 Workbench.Exit(0);
379 else
380 Workbench.Exit(-1);
381 }
382
383 //----------------------------------------------------------------------------------------------
384 static void ReportIssue(string resource, string issue)
385 {
386 string msg = string.Format("@\"%1\" : %2", resource, issue);
387 Print(string.ToString(msg, false, false, false), LogLevel.ERROR);
388 }
389
390 //----------------------------------------------------------------------------------------------
391 static void FixIssue(string resource, BaseContainer pc, BaseContainer platform, string prefix, string varName)
392 {
393 string val;
394 pc.Get(varName, val);
395 platform.Set(varName, val);
396 ReportIssue(resource, "Property fixed: " + prefix + "." + varName);
397 }
398
399 //----------------------------------------------------------------------------------------------
400 static bool FixMeshObjectMetaFile(MetaFile meta, string absFileName)
401 {
402 BaseContainerList configurations = meta.GetObjectArray("Configurations");
403 if(!configurations)
404 return false;
405
406 bool metaModified = false;
407 int pcIdx = -1;
408 for(int c = 0; c < configurations.Count(); c++)
409 {
410 BaseContainer cfg = configurations.Get(c);
411
412 string cfgName = cfg.GetName();
413 if (cfgName == "PC")
414 pcIdx = c;
415
416 //ensure that object which we want set ancestor to does exist. Create new instance if it's missing
417 bool IsSet = cfg.IsVariableSetDirectly(MeshObjectCommon);
418 if( !IsSet )
419 {
420 Resource res = BaseContainerTools.CreateContainer("TXOCommonClass");
421 BaseResourceObject root = res.GetResource();
422 BaseContainer cont = root.ToBaseContainer();
423 cfg.SetObject(MeshObjectCommon, cont);
424 }
425
426 //get an object which must be inherited from base configs
427 BaseContainer commonObj = cfg.GetObject(MeshObjectCommon);
428 if(!commonObj)
429 {
430 ReportIssue(absFileName, "Cannot set configuration ancestor (" + cfgName + ")" );
431 continue;
432 }
433
434 ResourceName ancestor = "";
435
436 switch(cfgName)
437 {
438 case "PC":
439 ancestor = "{0877E7C4BB2B2C9A}configs/ResourceTypes/PC/MeshObjectCommon.conf";
440 break;
441 case "XBOX_ONE":
442 ancestor = "{9D5B6207F7628CE2}configs/ResourceTypes/XBOX_ONE/MeshObjectCommon.conf";
443 break;
444 case "XBOX_SERIES":
445 ancestor = "{DD9F02115C764647}configs/ResourceTypes/XBOX_SERIES/MeshObjectCommon.conf";
446 break;
447 case "PS4":
448 ancestor = "{53EC476BC921D99A}configs/ResourceTypes/PS4/MeshObjectCommon.conf";
449 break;
450 case "PS5":
451 ancestor = "{F62AA8E7B8EA9D26}configs/ResourceTypes/PS5/MeshObjectCommon.conf";
452 break;
453 case "HEADLESS":
454 ancestor = "{3A5B3356978039E8}configs/ResourceTypes/HEADLESS/MeshObjectCommon.conf";
455 break;
456 }
457
458 if(ancestor != "")
459 {
460 commonObj.SetAncestor(ancestor);
461 metaModified = true;
462 }
463 }
464
465 if (pcIdx >= 0)
466 {
467 BaseContainer confPc_ = configurations[pcIdx];
468 BaseContainer commonPc = confPc_.GetObject(MeshObjectCommon);
469 for (int iConf = 0, countConf = configurations.Count(); iConf < countConf; iConf++)
470 {
471 if (iConf == pcIdx)
472 continue;
473
474 BaseContainer confDerived_ = configurations.Get(iConf);
475 BaseContainer commonDerived = confDerived_.GetObject(MeshObjectCommon);
476 if (!commonDerived)
477 continue;
478
479 for (int iVar = 0, countVar = commonPc.GetNumVars(); iVar < countVar; iVar++)
480 {
481 string namePc = commonPc.GetVarName(iVar);
482 string nameDerived = commonDerived.GetVarName(iVar);
483 if (namePc != nameDerived)
484 continue;
485
486 DataVarType varType = commonPc.GetDataVarType(iVar);
487 bool isSetDirectlyPc = commonPc.IsVariableSetDirectly(namePc);
488 bool isSetDirectlyDerived = commonDerived.IsVariableSetDirectly(nameDerived);
489 if (isSetDirectlyPc)
490 {
491 if (varType == DataVarType.SCALAR)
492 {
493 float propValPc, propValDerived;
494 if (!commonPc.Get(namePc, propValPc))
495 continue;
496
497 if (!commonDerived.Get(nameDerived, propValDerived))
498 continue;
499
500 if (propValPc != propValDerived)
501 {
502 metaModified = true;
503 commonDerived.Set(nameDerived, propValPc);
504 }
505 }
506 else
507 {
508 int propValPc, propValDerived;
509 if (!commonPc.Get(namePc, propValPc))
510 continue;
511
512 if (!commonDerived.Get(nameDerived, propValDerived))
513 continue;
514
515 if (propValPc != propValDerived)
516 {
517 metaModified = true;
518 commonDerived.Set(nameDerived, propValPc);
519 }
520 }
521 }
522 else if (isSetDirectlyDerived)
523 {
524 metaModified = true;
525 commonDerived.ClearVariable(nameDerived);
526 }
527 }
528 }
529 }
530
531 return metaModified;
532 }
533
534 //----------------------------------------------------------------------------------------------
535 static bool FixSoundMetaFile(MetaFile meta, string absFileName)
536 {
537 BaseContainerList configurations = meta.GetObjectArray("Configurations");
538 if(!configurations)
539 return false;
540
541 bool anyChangeInMetaFile = false;
542
543 for(int c = 0; c < configurations.Count(); c++)
544 {
545 BaseContainer cfg = configurations.Get(c);
546
547 string cfgName = cfg.GetName();
548 ResourceName ancestor = "";
549
550 switch(cfgName)
551 {
552 case "PC":
553 ancestor = "{F72B05D02F3F135E}configs/ResourceTypes/PC/Sound.conf";
554 break;
555 case "XBOX_ONE":
556 ancestor = "{A0776163143143AC}configs/ResourceTypes/XBOX_ONE/Sound.conf";
557 break;
558 case "XBOX_SERIES":
559 ancestor = "{382981CA1FC1C8DB}configs/ResourceTypes/XBOX_SERIES/Sound.conf";
560 break;
561 case "PS4":
562 ancestor = "{89EB939911B4C093}configs/ResourceTypes/PS4/Sound.conf";
563 break;
564 case "PS5":
565 ancestor = "{A584A3B556D4A981}configs/ResourceTypes/PS5/Sound.conf";
566 break;
567 case "HEADLESS":
568 ancestor = "{D63592CA950AF3A8}configs/ResourceTypes/HEADLESS/Sound.conf";
569 break;
570 }
571
572 if(ancestor != "")
573 {
574 cfg.SetAncestor(ancestor);
575 anyChangeInMetaFile = true;
576 }
577 }
578
579 return anyChangeInMetaFile;
580 }
581
582 //----------------------------------------------------------------------------------------------
583 static bool FixParticleEffectMetaFile(MetaFile meta, string absFileName)
584 {
585 BaseContainerList configurations = meta.GetObjectArray("Configurations");
586 if(!configurations)
587 return false;
588
589 bool anyChangeInMetaFile = false;
590
591 for(int c = 0; c < configurations.Count(); c++)
592 {
593 BaseContainer cfg = configurations.Get(c);
594
595 string cfgName = cfg.GetName();
596 ResourceName ancestor = "";
597
598 switch(cfgName)
599 {
600 case "PC":
601 ancestor = "{4B4500E061CCD624}configs/ResourceTypes/PC/ParticleEffect.conf";
602 break;
603 case "XBOX_ONE":
604 ancestor = "{73FE8562A95EBA36}configs/ResourceTypes/XBOX_ONE/ParticleEffect.conf";
605 break;
606 case "XBOX_SERIES":
607 ancestor = "{DC1673718B31CF7E}configs/ResourceTypes/XBOX_SERIES/ParticleEffect.conf";
608 break;
609 case "PS4":
610 ancestor = "{B94602D6C3160C98}configs/ResourceTypes/PS4/ParticleEffect.conf";
611 break;
612 case "PS5":
613 ancestor = "{E8F9F77ECEB75947}configs/ResourceTypes/PS5/ParticleEffect.conf";
614 break;
615 case "HEADLESS":
616 ancestor = "{EED8908A9A55ED1C}configs/ResourceTypes/HEADLESS/ParticleEffect.conf";
617 break;
618 }
619
620 if(ancestor != "")
621 {
622 cfg.SetAncestor(ancestor);
623 anyChangeInMetaFile = true;
624 }
625 }
626
627 return anyChangeInMetaFile;
628 }
629
630 //--------------------------------------------------------------------
631 static bool IsMeshObject(string className)
632 {
633 return className == "FBXResourceClass" || className == "TXOResourceClass";
634 }
635
636 //--------------------------------------------------------------------
637 static bool IsSound(string className)
638 {
639 return className == "WAVResourceClass";
640 }
641
642 //--------------------------------------------------------------------
643 static bool IsParticleEffect(string className)
644 {
645 return className == "PTCResourceClass";
646 }
647}
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
bool Execute(notnull SCR_AIGroupUtilityComponent groupUtility, vector targetPosition, SCR_AIActivitySmokeCoverFeatureProperties smokeCoverProperties, notnull array< AIAgent > avoidAgents, notnull array< AIAgent > excludeAgents, int maxPositionCount=1, SCR_AIActivityBase contextActivity=null)
EDamageType type
override void Run()
Configs ServerBrowser KickDialogs conf
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
SCR_RespawnComponentClass OK
Result code for request/assign response.
Definition EMoveError.c:14
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
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
SCR_FieldOfViewSettings Attribute
proto int Find(T value)
proto external string ToString()
Plain C++ pointer, no weak pointers, no memory management.