2[
WorkbenchPluginAttribute(name:
"Edit Selected Prefab(s)", shortcut:
"Ctrl+Shift+E", wbModules: {
"WorldEditor" }, awesomeFontCode: 0xF1B2)]
3class SCR_PrefabEditingPlugin : SCR_PrefabEditingPluginBase
5 [
Attribute(defvalue:
"{F636AAB9EE015E5F}Configs/Workbench/PrefabEditingPlugin/PrefabEditingPluginConfig.conf",
params:
"conf",
desc:
"Config with rules defining which worlds will be used for which folders.")]
8 protected static const string WARNING_CAPTION =
"Edit Selected Prefab plugin";
9 protected static const string WARNING_TEXT =
"You are about to generate and load a world to edit selected Prefabs. Saving current World Editor changes will be offered if needed if you click OK.\n\nDo you want to proceed?";
15 string prefabName =
FilePath.StripPath(
FilePath.StripExtension(prefab.GetPath(), extension));
16 if (extension ==
"ct")
19 api.CreateComponent(entity, prefab);
24 return api.CreateEntity(prefab, prefabName, api.GetCurrentEntityLayerId(), null,
position,
rotation);
29 protected bool CreateWorldFiles(
ResourceName worldPrefab,
string targetPath)
32 string worldPath = worldPrefab.GetPath();
34 if (!
FileIO.FileExists(worldPath))
36 Print(
string.Format(
"Cannot load prefab, selected world '%2' doesn't exist!", worldPath),
LogLevel.ERROR);
40 if (!
FileIO.MakeDirectory(
"$profile:worlds"))
48 file.WriteLine(
"SubScene {");
49 file.WriteLine(
string.Format(
" Parent \"%1\"", worldPrefab));
51 file.WriteLine(
"Layer default {");
52 file.WriteLine(
" Index 0");
56 if (!
FileIO.MakeDirectory(targetPath +
"_Layers"))
60 file =
FileIO.OpenFile(targetPath +
"_Layers/default.layer",
FileMode.WRITE);
73 vector boundsMin = {
float.MAX,
float.MAX,
float.MAX };
75 GetEntitySourceBounds(api, source, boundsMin, boundsMax);
93 IEntity entity = api.SourceToEntity(source);
99 vector entityMin, entityMax;
104 boundsMin[0] =
Math.Min(boundsMin[0], entityMin[0]);
105 boundsMin[1] =
Math.Min(boundsMin[1], entityMin[1]);
106 boundsMin[2] =
Math.Min(boundsMin[2], entityMin[2]);
108 boundsMax[0] =
Math.Max(boundsMax[0], entityMax[0]);
109 boundsMax[1] =
Math.Max(boundsMax[1], entityMax[1]);
110 boundsMax[2] =
Math.Max(boundsMax[2], entityMax[2]);
113 for (
int i, childrenCount = source.GetNumChildren(); i < childrenCount; i++)
115 GetEntitySourceBounds(api, source.GetChild(i), boundsMin, boundsMax);
123 if (!configResource.IsValid())
130 if (!configContainer)
133 BaseContainer configBase = configContainer.ToBaseContainer();
137 PrefabEditingPluginConfig result = PrefabEditingPluginConfig.Cast(
BaseContainerTools.CreateInstanceFromContainer(configBase));
140 PrintFormat(
"Config '%1' is of type '%2', must be inheriting from 'PrefabEditingPluginConfig'!", configPath, configBase.GetClassName(), level:
LogLevel.ERROR);
153 if (Workbench.ScriptDialog(WARNING_CAPTION, WARNING_TEXT,
new WorkbenchDialog_OKCancel()) == 0)
156 WorldEditor worldEditor = Workbench.GetModule(WorldEditor);
164 array<ResourceName> compatiblePrefabs = {};
165 if (!GetPrefabs(compatiblePrefabs,
true))
169 PrefabEditingPluginConfig config =
GetConfig(m_Config);
173 PrefabEditingPluginConfigFolder folderSettings = config.GetFolderSettings(compatiblePrefabs[0]);
178 string targetPath = config.GetPath();
179 if (!CreateWorldFiles(folderSettings.GetWorld(), targetPath))
182 if (!worldEditor.SetOpenedResource(targetPath +
".ent"))
189 api.BeginEntityAction();
190 api.ClearEntitySelection();
191 array<IEntitySource> entities = {};
193 vector pos, rot,
size, boundsMin, boundsMax, boundsSize;
194 pos = folderSettings.GetPosition();
195 rot = folderSettings.GetRotation();
197 bool usePrefabPosition = folderSettings.UsePrefabPosition();
201 foreach (
int i,
ResourceName prefab : compatiblePrefabs)
204 if (!resource.IsValid())
206 Print(
string.Format(
"Cannot load prefab '%1'!", prefab),
LogLevel.ERROR);
207 api.EndEntityAction();
211 if (usePrefabPosition)
214 source.Get(
"coords", pos);
218 source = CreateEntity(api, prefab, pos, rot);
221 Print(
string.Format(
"Cannot create entity for prefab '%1'!", prefab),
LogLevel.ERROR);
222 api.EndEntityAction();
226 entities.Insert(source);
229 boundsMin = {
float.MAX,
float.MAX,
float.MAX };
230 boundsMax = -boundsMin;
231 GetEntitySourceBounds(api, source, boundsMin, boundsMax);
232 boundsSize = boundsMax - boundsMin;
233 for (
int n = 0; n < 3; n++)
235 if (
size[n] < boundsSize[n])
236 size[n] = boundsSize[n];
240 float spacing = folderSettings.GetSpacing();
241 size += { spacing, spacing, spacing };
244 int entitiesCount = entities.Count();
245 int length =
Math.Ceil(
Math.Sqrt(entitiesCount));
248 for (
int i = entitiesCount; i >= 0; --i)
250 row =
Math.Floor(i / length);
253 api.AddToEntitySelection(e);
254 if (!usePrefabPosition)
255 api.SetVariableValue(e, null,
"coords",
string.Format(
"%1 %2 %3", pos[0] -
size[0] * column, pos[1], pos[2] -
size[2] * row));
258 SetCamera(api, api.SourceToEntity(entities[0]));
259 api.EndEntityAction();
268 Workbench.ScriptDialog(
"Configure 'Edit Selected Prefab(s)' plugin",
"",
this);
273 protected int ButtonClose()
279[
WorkbenchPluginAttribute(name:
"Edit Selected Prefab(s)", shortcut:
"Ctrl+Shift+E", wbModules: {
"ResourceManager" },
category:
"Prefabs", awesomeFontCode: 0xF1B2)]
280class SCR_PrefabEditingPluginResourceManager : SCR_PrefabEditingPlugin
283 override void GetSelected(out array<ResourceName> selection)
285 GetSelectedResourceBrowser(selection);
290class PrefabEditingPluginConfig
292 [
Attribute(defvalue:
"$profile:worlds/PrefabEditingPlugin")]
293 protected string m_sPath;
296 protected ref array<ref PrefabEditingPluginConfigFolder> m_Folders;
308 PrefabEditingPluginConfigFolder GetFolderSettings(ResourceName prefab)
310 string prefabPath = prefab.GetPath();
312 PrefabEditingPluginConfigFolder folderSettings = null;
313 int pathLengthMax = -1;
314 foreach (PrefabEditingPluginConfigFolder folderSettingsTemp : m_Folders)
316 string folderPath = folderSettingsTemp.GetFolder();
317 int pathLength = folderPath.Length();
318 if (pathLength > pathLengthMax && prefabPath.StartsWith(folderPath))
320 folderSettings = folderSettingsTemp;
321 pathLengthMax = pathLength;
325 return folderSettings;
330class PrefabEditingPluginConfigFolder
333 protected ResourceName m_Folder;
335 [
Attribute(defvalue:
"{70ABDE49D02BA4F4}worlds/TestMaps/PrefabEditingPlugin/PrefabEditingPlugin.ent", uiwidget: UIWidgets.ResourceNamePicker,
params:
"ent")]
336 protected ResourceName
m_World;
338 [
Attribute(
desc:
"When enabled, prefabs will be used on their own coordinates.")]
339 protected bool m_bUsePrefabPosition;
345 protected vector m_vRotation;
347 [
Attribute(defvalue:
"0.1",
desc:
"Minimal spacing [m] between spawned entities")]
348 protected float m_fSpacing;
354 return m_Folder.GetPath();
359 ResourceName GetWorld()
367 bool UsePrefabPosition()
369 return m_bUsePrefabPosition;
SCR_AIAnimation_Loitering BaseContainerProps
Commanding menu commanding element class.
SCR_CampaignMilitaryBaseComponent SCR_MilitaryBaseComponent SCR_BaseContainerCustomTitleResourceName("m_sBaseName", true)
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
class WorkbenchDialog_AbortRetryIgnore ButtonAttribute("OK", true)
proto external vector GetOrigin()
proto external void GetBounds(out vector mins, out vector maxs)
proto external vector CoordToParent(vector coord)
proto external VObject GetVObject()
Returns visual object set to this Entity. No reference is added.
Object holding reference to resource. In destructor release the resource.
proto external bool SetCamera(CameraBase pCam)
proto void Print(void var, LogLevel level=LogLevel.NORMAL)
Prints content of variable to console/log.
LogLevel
Enum with severity of the logging message.
proto void PrintFormat(string fmt, void param1=NULL, void param2=NULL, void param3=NULL, void param4=NULL, void param5=NULL, void param6=NULL, void param7=NULL, void param8=NULL, void param9=NULL, LogLevel level=LogLevel.NORMAL)
SCR_FieldOfViewSettings Attribute
RespawnSystemComponentClass GameComponentClass vector vector rotation
proto external int GetSelected(out notnull array< MapItem > outItems)
Get all selected entities.
FileMode
Mode for opening file. See FileSystem::Open.