5 static const string PREFAB_BASE_SUFFIX =
"_base";
7 protected static const string MESHOBJECT_CLASSNAME =
"MeshObject";
8 protected static const string DEFAULT_PARENT_PREFAB =
"GenericEntity";
9 protected static const string PREFAB_DOTTED_EXTENSION =
".et";
11 protected static const ref array<ResourceName> PREFAB_SEARCH_DIRECTORIES = {
22 static ResourceName ClonePrefab(ResourceName sourcePrefab,
string absoluteFilePath)
24 if (SCR_StringHelper.IsEmptyOrWhiteSpace(sourcePrefab))
30 if (SCR_StringHelper.IsEmptyOrWhiteSpace(absoluteFilePath))
36 WorldEditorAPI worldEditorAPI = SCR_WorldEditorToolHelper.GetWorldEditorAPI();
43 if (!absoluteFilePath.EndsWith(PREFAB_DOTTED_EXTENSION))
44 absoluteFilePath += PREFAB_DOTTED_EXTENSION;
46 string absoluteDirPath = FilePath.StripFileName(absoluteFilePath);
47 if (!FileIO.FileExists(absoluteDirPath))
49 if (!FileIO.MakeDirectory(absoluteDirPath))
51 Print(
"Cannot create the destination directory (" + absoluteDirPath +
")",
LogLevel.ERROR);
56 IEntitySource entitySource = CreateEntitySourceWithoutEntity(sourcePrefab);
59 Print(
"Prefab's entity source cannot be created",
LogLevel.ERROR);
63 IEntitySource actualPrefab = IEntitySource.Cast(entitySource.GetAncestor());
66 Print(
"Created entity's source does not have an ancestor",
LogLevel.ERROR);
70 if (!worldEditorAPI.CreateEntityTemplate(actualPrefab, absoluteFilePath))
76 MetaFile metaFile = SCR_WorldEditorToolHelper.GetResourceManager().GetMetaFile(absoluteFilePath);
79 Print(
"Created Prefab's meta file cannot be found",
LogLevel.WARNING);
83 return metaFile.GetResourceID();
91 static ResourceName CreateChildPrefab(ResourceName sourcePrefab,
string absoluteFilePath)
93 if (SCR_StringHelper.IsEmptyOrWhiteSpace(sourcePrefab))
99 if (SCR_StringHelper.IsEmptyOrWhiteSpace(absoluteFilePath))
105 WorldEditorAPI worldEditorAPI = SCR_WorldEditorToolHelper.GetWorldEditorAPI();
112 if (!absoluteFilePath.EndsWith(PREFAB_DOTTED_EXTENSION))
113 absoluteFilePath += PREFAB_DOTTED_EXTENSION;
115 string absoluteDirPath = FilePath.StripFileName(absoluteFilePath);
116 if (!FileIO.FileExists(absoluteDirPath))
118 if (!FileIO.MakeDirectory(absoluteDirPath))
120 Print(
"Cannot create directory \"" + absoluteDirPath +
"\"",
LogLevel.ERROR);
125 IEntitySource entitySource = CreateEntitySourceWithoutEntity(sourcePrefab);
128 Print(
"Prefab's entity source cannot be created",
LogLevel.ERROR);
132 if (!worldEditorAPI.CreateEntityTemplate(entitySource, absoluteFilePath))
138 MetaFile metaFile = SCR_WorldEditorToolHelper.GetResourceManager().GetMetaFile(absoluteFilePath);
141 Print(
"Created Prefab's meta file cannot be found",
LogLevel.WARNING);
145 return metaFile.GetResourceID();
157 static array<ResourceName> CreatePrefabsFromXOBs(notnull array<ResourceName> xobs,
string absoluteDirPath, ResourceName parentPrefab =
string.Empty,
bool createBasePrefab =
false)
162 WorldEditorAPI worldEditorAPI = SCR_WorldEditorToolHelper.GetWorldEditorAPI();
169 if (!FileIO.FileExists(absoluteDirPath))
171 if (!FileIO.MakeDirectory(absoluteDirPath))
173 Print(
"Cannot create directory \"" + absoluteDirPath +
"\"",
LogLevel.ERROR);
178 bool manageEditAction = BeginEntityAction();
180 IEntitySource entitySource = CreateEntitySourceWithoutEntity(parentPrefab);
183 Print(
"Prefab's entity source cannot be created",
LogLevel.ERROR);
184 EndEntityAction(manageEditAction);
189 if (!CreateEntitySourceComponentIfNeeded(entitySource, MESHOBJECT_CLASSNAME))
192 EndEntityAction(manageEditAction);
196 array<ResourceName> result = {};
197 array<ref ContainerIdPathEntry> meshObjectPath = {
new ContainerIdPathEntry(MESHOBJECT_CLASSNAME) };
199 foreach (ResourceName
xob : xobs)
201 if (SCR_StringHelper.IsEmptyOrWhiteSpace(
xob))
207 string prefabFileName = FilePath.StripExtension(FilePath.StripPath(
xob.GetPath())) + PREFAB_DOTTED_EXTENSION;
210 if (!worldEditorAPI.SetVariableValue(entitySource, meshObjectPath,
"Object",
xob))
212 Print(
"Cannot apply XOB model to " + prefabFileName,
LogLevel.ERROR);
216 ResourceName
resourceName = SaveEntitySourceAsPrefab(entitySource, absoluteDirPath, prefabFileName, createBasePrefab);
219 Print(
"Cannot save Prefab " + prefabFileName,
LogLevel.WARNING);
226 EndEntityAction(manageEditAction);
241 static ResourceName CreatePrefabFromXOB(ResourceName
xob,
string absoluteDestinationPath, ResourceName parentPrefab =
string.Empty,
bool createBasePrefab =
false)
243 if (SCR_StringHelper.IsEmptyOrWhiteSpace(
xob))
249 if (!absoluteDestinationPath.EndsWith(PREFAB_DOTTED_EXTENSION))
251 array<ResourceName> result = CreatePrefabsFromXOBs({
xob }, absoluteDestinationPath, parentPrefab, createBasePrefab);
252 if (result.IsEmpty())
258 string absoluteDirPath = FilePath.StripFileName(absoluteDestinationPath);
259 if (absoluteDirPath.EndsWith(
"/"))
260 absoluteDirPath = absoluteDirPath.Substring(0, absoluteDirPath.Length() - 1);
262 if (!FileIO.MakeDirectory(absoluteDirPath))
264 Print(
"Cannot create directory \"" + absoluteDirPath +
"\"",
LogLevel.ERROR);
268 WorldEditorAPI worldEditorAPI = SCR_WorldEditorToolHelper.GetWorldEditorAPI();
275 bool manageEditAction = BeginEntityAction();
277 IEntitySource entitySource = CreateEntitySourceFromXOB(
xob, parentPrefab);
278 SCR_WorldEditorToolHelper.DeleteEntityFromSource(entitySource);
280 EndEntityAction(manageEditAction);
284 Print(
"Prefab's entity source cannot be created",
LogLevel.ERROR);
288 string prefabFileName = FilePath.StripPath(absoluteDestinationPath);
289 return SaveEntitySourceAsPrefab(entitySource, absoluteDirPath, prefabFileName, createBasePrefab);
297 static bool CreatePrefabStructure(notnull SCR_PrefabHelper_Structure structure,
string addonPathPrefix)
299 structure.m_sName.TrimInPlace();
300 if (!structure.m_sName)
306 if (!SCR_FileIOHelper.IsValidFileName(structure.m_sName))
308 Print(
"Name is invalid - " + structure.m_sName,
LogLevel.ERROR);
312 if (!structure.m_Directory)
319 if (!Workbench.GetAbsolutePath(addonPathPrefix, absolutePath,
false))
321 Print(
"Cannot get absolute path for " + addonPathPrefix + structure.m_Directory.m_sRelativePath,
LogLevel.ERROR);
325 return CreatePrefabStructureDirectory(structure.m_sName, structure.m_Directory, absolutePath);
334 protected static bool CreatePrefabStructureDirectory(
string structureName, notnull SCR_PrefabHelper_StructureDirectory directory,
string absoluteParentPath)
336 string absoluteDirectoryPath =
string.Format(FilePath.Concat(absoluteParentPath, directory.m_sRelativePath), structureName);
337 if (!FileIO.MakeDirectory(absoluteDirectoryPath))
339 Print(
"Cannot create directory " + absoluteDirectoryPath,
LogLevel.ERROR);
343 foreach (SCR_PrefabHelper_StructureFile file : directory.m_aFiles)
345 string absoluteFilePath =
string.Format(FilePath.Concat(absoluteDirectoryPath, file.m_sFileName), structureName);
346 ResourceName createdResource = CreateChildPrefab(file.m_sParentResource, absoluteFilePath);
347 if (!createdResource)
349 Print(
"Cannot create file " + absoluteFilePath,
LogLevel.WARNING);
354 foreach (SCR_PrefabHelper_StructureDirectory subDirectory : directory.m_aSubDirectories)
356 string absoluteSubDirectoryPath =
string.Format(FilePath.Concat(absoluteDirectoryPath, subDirectory.m_sRelativePath), structureName);
357 if (!FileIO.MakeDirectory(absoluteSubDirectoryPath))
359 Print(
"Cannot create directory " + absoluteSubDirectoryPath,
LogLevel.WARNING);
363 CreatePrefabStructureDirectory(structureName, subDirectory, absoluteSubDirectoryPath);
374 static IEntitySource CreateEntitySource(ResourceName parentPrefab =
string.Empty)
376 WorldEditorAPI worldEditorAPI = SCR_WorldEditorToolHelper.GetWorldEditorAPI();
383 if (SCR_StringHelper.IsEmptyOrWhiteSpace(parentPrefab))
384 parentPrefab = DEFAULT_PARENT_PREFAB;
386 bool manageEditAction = BeginEntityAction();
388 IEntitySource entitySource = worldEditorAPI.CreateEntity(parentPrefab,
"", worldEditorAPI.GetCurrentEntityLayerId(), null, vector.Zero, vector.Zero);
391 Print(
"Entity cannot be created (parent = " + parentPrefab +
")",
LogLevel.ERROR);
392 EndEntityAction(manageEditAction);
396 EndEntityAction(manageEditAction);
405 protected static IEntitySource CreateEntitySourceWithoutEntity(ResourceName parentPrefab =
string.Empty)
407 WorldEditorAPI worldEditorAPI = SCR_WorldEditorToolHelper.GetWorldEditorAPI();
409 bool manageEditAction = BeginEntityAction();
411 IEntitySource entitySource = CreateEntitySource(parentPrefab);
412 SCR_WorldEditorToolHelper.DeleteEntityFromSource(entitySource);
414 EndEntityAction(manageEditAction);
426 protected static IEntitySource CreateEntitySourceFromXOB(ResourceName
xob, ResourceName parentPrefab =
string.Empty)
428 if (SCR_StringHelper.IsEmptyOrWhiteSpace(
xob))
434 WorldEditorAPI worldEditorAPI = SCR_WorldEditorToolHelper.GetWorldEditorAPI();
441 string xobName = FilePath.StripPath(
xob.GetPath());
443 bool manageEditAction = BeginEntityAction();
445 IEntitySource entitySource = CreateEntitySource(parentPrefab);
448 Print(
"Prefab's entity source cannot be created for xob " + xobName,
LogLevel.ERROR);
449 EndEntityAction(manageEditAction);
454 if (!CreateEntitySourceComponentIfNeeded(entitySource, MESHOBJECT_CLASSNAME))
457 EndEntityAction(manageEditAction);
462 if (!worldEditorAPI.SetVariableValue(entitySource, { new ContainerIdPathEntry(MESHOBJECT_CLASSNAME) },
"Object",
xob))
464 Print(
"Cannot apply XOB model to IEntitySource for xob " + xobName,
LogLevel.ERROR);
465 EndEntityAction(manageEditAction);
469 EndEntityAction(manageEditAction);
479 static IEntityComponentSource CreateEntitySourceComponentIfNeeded(notnull IEntitySource entitySource,
string componentClassname)
481 if (SCR_StringHelper.IsEmptyOrWhiteSpace(componentClassname))
483 Print(
"Provided componentClassname is empty",
LogLevel.WARNING);
487 IEntityComponentSource result = SCR_BaseContainerTools.FindComponentSource(entitySource, componentClassname);
491 WorldEditorAPI worldEditorAPI = SCR_WorldEditorToolHelper.GetWorldEditorAPI();
493 bool manageEditAction = BeginEntityAction();
495 result = worldEditorAPI.CreateComponent(entitySource, componentClassname);
497 Print(
"Cannot add the " + MESHOBJECT_CLASSNAME +
" component to the Prefab",
LogLevel.ERROR);
499 EndEntityAction(manageEditAction);
513 static map<int, ref array<ResourceName>> GetPrefabs(
int addonIndex = -1,
int getMode = -1)
515 array<string> addonIDs;
518 addonIDs = SCR_AddonTool.GetAllAddonIDs();
522 string addonID = SCR_AddonTool.GetAddonID(addonIndex);
526 addonIDs = SCR_AddonTool.GetAllAddonIDs();
530 addonIDs = { addonID };
534 map<int, ref array<ResourceName>> result =
new map<int, ref array<ResourceName>>();
536 SearchResourcesFilter searchFilter =
new SearchResourcesFilter();
537 searchFilter.fileExtensions = {
"et" };
539 array<ResourceName> resourceNames;
540 foreach (
int index,
string addonID : addonIDs)
545 if (PREFAB_SEARCH_DIRECTORIES.IsIndexValid(getMode))
546 searchFilter.rootPath = SCR_AddonTool.GetAddonFileSystem(
index) + PREFAB_SEARCH_DIRECTORIES[getMode];
548 searchFilter.rootPath = SCR_AddonTool.GetAddonFileSystem(
index);
551 ResourceDatabase.SearchResources(searchFilter, resourceNames.Insert);
552 result.Insert(
index, resourceNames);
563 static string GetResourceNameAbsolutePath(ResourceName
resourceName,
bool mustExist =
true)
566 if (!Workbench.GetAbsolutePath(
resourceName.GetPath(), result, mustExist))
585 static string GetRelativeParentDirectory(
string relativeSourceDirectory,
string relativeTargetDirectory)
587 if (relativeSourceDirectory.IsEmpty())
588 return FormatRelativePath(relativeTargetDirectory);
590 if (relativeTargetDirectory.IsEmpty())
591 return FormatRelativePath(relativeSourceDirectory);
593 relativeSourceDirectory = FormatRelativePath(relativeSourceDirectory);
594 relativeTargetDirectory = FormatRelativePath(relativeTargetDirectory);
597 if (!relativeSourceDirectory.Contains(
"/") && !relativeTargetDirectory.Contains(
"/"))
598 return relativeTargetDirectory;
602 for (
int i, length = relativeSourceDirectory.Length(); i < length; i++)
604 string character = relativeSourceDirectory[i];
607 if (character ==
"/")
617 path = relativeSourceDirectory;
619 return relativeTargetDirectory +
"/" +
path;
626 protected static string FormatRelativePath(
string relativePath)
628 if (relativePath.IsEmpty())
631 relativePath.Replace(SCR_StringHelper.ANTISLASH, SCR_StringHelper.SLASH);
632 relativePath.Replace(SCR_StringHelper.DOUBLE_SLASH, SCR_StringHelper.SLASH);
634 if (relativePath.StartsWith(
"/"))
635 relativePath = relativePath.Substring(1, relativePath.Length() - 1);
637 if (relativePath.EndsWith(
"/"))
638 relativePath = relativePath.Substring(0, relativePath.Length() - 1);
647 static bool UpdatePrefabFromEntitySourceAncestor(notnull BaseContainer actualPrefab)
649 WorldEditorAPI worldEditorAPI = SCR_WorldEditorToolHelper.GetWorldEditorAPI();
656 bool manageEditAction = BeginEntityAction();
657 bool result = worldEditorAPI.SaveEntityTemplate(actualPrefab);
658 EndEntityAction(manageEditAction);
670 static ResourceName SaveEntitySourceAsPrefab(notnull IEntitySource entitySource,
string absoluteDirPath,
string prefabFileName,
bool createBasePrefab =
false)
672 if (SCR_StringHelper.IsEmptyOrWhiteSpace(absoluteDirPath))
678 if (SCR_StringHelper.IsEmptyOrWhiteSpace(prefabFileName))
684 WorldEditorAPI worldEditorAPI = SCR_WorldEditorToolHelper.GetWorldEditorAPI();
691 if (!absoluteDirPath.EndsWith(
"/"))
692 absoluteDirPath +=
"/";
694 if (!FileIO.FileExists(absoluteDirPath) && !FileIO.MakeDirectory(absoluteDirPath))
696 Print(
"Cannot create the destination directory (" + absoluteDirPath +
")",
LogLevel.ERROR);
700 if (!prefabFileName.EndsWith(PREFAB_DOTTED_EXTENSION))
701 prefabFileName += PREFAB_DOTTED_EXTENSION;
703 string absoluteFilePath = absoluteDirPath + prefabFileName;
706 if (createBasePrefab)
708 string basePrefabFileName = FilePath.StripExtension(prefabFileName) + PREFAB_BASE_SUFFIX + PREFAB_DOTTED_EXTENSION;
709 string absoluteBaseFilePath = absoluteDirPath + basePrefabFileName;
712 if (!worldEditorAPI.CreateEntityTemplate(entitySource, absoluteBaseFilePath))
714 Print(
"Cannot save base prefab " + basePrefabFileName +
" at " + absoluteBaseFilePath,
LogLevel.WARNING);
718 metaFile = SCR_WorldEditorToolHelper.GetResourceManager().GetMetaFile(absoluteBaseFilePath);
721 Print(
"Created base Prefab's meta file cannot be found",
LogLevel.WARNING);
727 entitySource = CreateEntitySourceWithoutEntity(metaFile.GetResourceID());
730 Print(
"Prefab's child entity source cannot be created",
LogLevel.ERROR);
736 if (!worldEditorAPI.CreateEntityTemplate(entitySource, absoluteFilePath))
738 Print(
"Cannot save prefab " + prefabFileName +
" at " + absoluteFilePath,
LogLevel.WARNING);
742 metaFile = SCR_WorldEditorToolHelper.GetResourceManager().GetMetaFile(absoluteFilePath);
745 Print(
"Created Prefab's meta file cannot be found",
LogLevel.WARNING);
749 return metaFile.GetResourceID();
756 static bool UpdatePrefab(IEntitySource actualPrefab)
758 WorldEditorAPI worldEditorAPI = SCR_WorldEditorToolHelper.GetWorldEditorAPI();
765 return worldEditorAPI.SaveEntityTemplate(actualPrefab);
771 protected static bool BeginEntityAction()
773 WorldEditorAPI worldEditorAPI = SCR_WorldEditorToolHelper.GetWorldEditorAPI();
774 if (worldEditorAPI.IsDoingEditAction())
780 worldEditorAPI.BeginEntityAction();
788 protected static void EndEntityAction(
bool manageEditAction)
790 if (manageEditAction)
791 SCR_WorldEditorToolHelper.GetWorldEditorAPI().EndEntityAction();
796class SCR_PrefabHelper_Structure
798 [
Attribute(defvalue:
"Structure name",
desc:
"Config type's friendly display name")]
802 ref SCR_PrefabHelper_StructureDirectory m_Directory;
806class SCR_PrefabHelper_StructureDirectory
808 [
Attribute(defvalue:
"Prefabs/Category/SubCategory/%1",
desc:
"Directory path - can be empty (root), a simple name (one directory) or multiple (sub)directories separated by a slash\n%1 = project name (e.g S105)")]
809 string m_sRelativePath;
812 ref array<ref SCR_PrefabHelper_StructureDirectory> m_aSubDirectories;
815 ref array<ref SCR_PrefabHelper_StructureFile> m_aFiles;
819class SCR_PrefabHelper_StructureFile
821 [
Attribute(defvalue:
"%1_base.et",
desc:
"Relative file path in which this Prefab is created - extension is optional and will be defined from parent Prefab\n%1 = project name (e.g S105)")]
824 [
Attribute(defvalue:
"",
desc:
"The parent resource from which this one inherits", uiwidget: UIWidgets.ResourceNamePicker,
params:
"et conf")]
825 ResourceName m_sParentResource;
void ContainerIdPathEntry(string propertyName, int index=-1)
SCR_AIAnimation_Loitering BaseContainerProps
Commanding menu commanding element class.
ResourceName resourceName
SCR_DestructionSynchronizationComponentClass ScriptComponentClass int index
SCR_Faction ScriptedFaction SCR_BaseContainerCustomTitleField("m_sCallsign")
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
Attribute to use a ResourceName filename.
proto void Print(void var, LogLevel level=LogLevel.NORMAL)
Prints content of variable to console/log.
LogLevel
Enum with severity of the logging message.
SCR_FieldOfViewSettings Attribute