2class SCR_WorldEditorToolHelper
4 protected static ref array<IEntity> s_aTempEntities;
6 protected static const string WEB_PREFIX =
"https://enfusionengine.com/api/redirect?to=";
11 static ResourceManager GetResourceManager()
13 return Workbench.GetModule(ResourceManager);
19 static WorldEditor GetWorldEditor()
21 return Workbench.GetModule(WorldEditor);
27 static WorldEditorAPI GetWorldEditorAPI()
29 WorldEditor worldEditor = GetWorldEditor();
33 return worldEditor.GetApi();
39 static IEntitySource GetPrefabEditModeEntitySource()
41 WorldEditor worldEditor = GetWorldEditor();
45 if (!worldEditor.IsPrefabEditMode())
48 WorldEditorAPI worldEditorAPI = worldEditor.GetApi();
49 if (worldEditorAPI.GetEditorEntityCount() != 2)
52 return worldEditorAPI.GetEditorEntity(1);
58 static ResourceName GetPrefabEditModeResourceName()
60 IEntitySource entitySource = GetPrefabEditModeEntitySource();
64 BaseContainer ancestor = entitySource.GetAncestor();
68 return ancestor.GetResourceName();
75 static string GetCurrentWorldEditorLink(
bool useWebPrefix =
false)
77 WorldEditorAPI worldEditorAPI = GetWorldEditorAPI();
81 BaseWorld world = worldEditorAPI.GetWorld();
86 world.GetCurrentCamera(transform);
88 return SCR_WorldEditorToolHelper.GetCurrentWorldEditorLink(transform[3], Math3D.MatrixToAngles(transform), useWebPrefix);
98 static string GetCurrentWorldEditorLink(vector
position, vector
angles,
bool useWebPrefix =
false)
100 WorldEditorAPI worldEditorAPI = GetWorldEditorAPI();
105 worldEditorAPI.GetWorldPath(fullLink);
107 if (fullLink.IsEmpty())
110 string worldPath = fullLink;
111 if (worldPath[0] ==
"$")
112 worldPath =
"~" + worldPath.Substring(1, worldPath.Length() - 1);
114 if (worldPath[0] !=
"~")
121 string fullLinkLC = fullLink;
122 fullLinkLC.ToLower();
124 int begin = fullLinkLC.IndexOf(
"worlds\\");
126 begin = fullLinkLC.IndexOf(
"worlds/");
131 worldPath = fullLink.Substring(begin, fullLink.Length() - begin);
135 worldPath.Replace(
"\\",
"/");
138 return "enfusion://WorldEditor/" + worldPath;
140 string result =
string.Format(
141 "enfusion://WorldEditor/%1;%2,%3,%4;%5,%6,%7",
151 return WEB_PREFIX + result;
158 static string GetWorldName()
160 string result = FilePath.StripExtension(FilePath.StripPath(GetWorldPath()));
169 static string GetWorldPath()
171 WorldEditorAPI worldEditorAPI = GetWorldEditorAPI();
176 worldEditorAPI.GetWorldPath(result);
182 static bool IsWorldLoaded()
184 WorldEditor worldEditor = Workbench.GetModule(WorldEditor);
188 if (worldEditor.IsPrefabEditMode())
191 WorldEditorAPI worldEditorAPI = worldEditor.GetApi();
196 worldEditorAPI.GetWorldPath(worldPath);
197 return worldPath && worldEditorAPI.GetWorld() != null;
202 static bool HasTerrainMesh()
204 WorldEditor worldEditor = Workbench.GetModule(WorldEditor);
209 worldEditor.GetTerrainBounds(min, max);
210 return max != vector.Zero || min != vector.Zero;
215 static IEntitySource GetTerrainEntitySource()
217 WorldEditor worldEditor = GetWorldEditor();
221 if (worldEditor.IsPrefabEditMode())
224 WorldEditorAPI worldEditorAPI = worldEditor.GetApi();
225 if (worldEditorAPI.GetEditorEntityCount() < 2)
228 IEntitySource entitySource;
229 for (
int i, entitiesCount = worldEditorAPI.GetEditorEntityCount(); i < entitiesCount; ++i)
231 entitySource = worldEditorAPI.GetEditorEntity(i);
232 if (entitySource && entitySource.GetClassName().ToType() && entitySource.GetClassName().ToType().IsInherited(GenericTerrainEntity))
241 static vector GetTerrainDimensions()
243 WorldEditor worldEditor = Workbench.GetModule(WorldEditor);
245 worldEditor.GetTerrainBounds(min, max);
252 static void GetTerrainMinMaxY(out
float minY, out
float maxY)
254 WorldEditor worldEditor = Workbench.GetModule(WorldEditor);
256 worldEditor.GetTerrainBounds(min, max);
266 static bool GetTerrainMinMaxElevationPositions(out vector min, out vector max)
268 WorldEditorAPI worldEditorAPI = GetWorldEditorAPI();
269 if (!HasTerrainMesh())
273 GetTerrainMinMaxY(minY, maxY);
275 vector terrainPosition = GetTerrainPosition();
276 float minX = terrainPosition[0];
277 float minZ = terrainPosition[2];
279 vector terrainDimensions = GetTerrainDimensions();
280 float maxX = minX + terrainDimensions[0];
281 float maxZ = minZ + terrainDimensions[2];
283 float step = worldEditorAPI.GetTerrainUnitScale();
285 bool hasMinY, hasMaxY;
288 for (
float z = minZ, limitZ = maxZ; z <= limitZ; z += step)
290 for (
float x = minX, limitX = maxX; x <= limitX; x += step)
292 if (!worldEditorAPI.TryGetTerrainSurfaceY(x, z, y))
295 if (!hasMaxY && y == maxY)
301 if (!hasMinY && y == minY)
307 if (hasMinY && hasMaxY)
312 return hasMinY && hasMaxY;
319 static float GetTerrainLandArea(
int terrainIndex = 0)
321 if (terrainIndex < 0)
324 WorldEditorAPI worldEditorAPI = SCR_WorldEditorToolHelper.GetWorldEditorAPI();
326 BaseWorld world = worldEditorAPI.GetWorld();
330 const float cellSideSize = worldEditorAPI.GetTerrainUnitScale(terrainIndex);
331 if (cellSideSize <= 0)
334 const float cellSideSizeSq = cellSideSize * cellSideSize;
336 if (!world.IsOcean())
338 return cellSideSizeSq
339 * (worldEditorAPI.GetTerrainResolutionX(terrainIndex) - 1)
340 * (worldEditorAPI.GetTerrainResolutionY(terrainIndex) - 1);
343 const float oceanLevel = worldEditorAPI.GetWorld().GetOceanBaseHeight();
344 if (oceanLevel == -
float.
MAX)
346 return cellSideSizeSq
347 * (worldEditorAPI.GetTerrainResolutionX(terrainIndex) - 1)
348 * (worldEditorAPI.GetTerrainResolutionY(terrainIndex) - 1);
351 const int tileXCount = worldEditorAPI.GetTerrainTilesX(terrainIndex);
352 const int tileYCount = worldEditorAPI.GetTerrainTilesY(terrainIndex);
354 const int tileSideSizeX = (worldEditorAPI.GetTerrainResolutionX(terrainIndex) - 1) / tileXCount;
355 const int tileSideSizeY = (worldEditorAPI.GetTerrainResolutionY(terrainIndex) - 1) / tileYCount;
357 const int tileArea = tileSideSizeX * tileSideSizeY;
358 const int tileValuesCount = (tileSideSizeX + 1) * (tileSideSizeY + 1);
359 array<float> tileYs = {};
360 tileYs.Resize(tileValuesCount);
364 int bottomLeftIndex, bottomRightIndex;
365 float topLeftY, bottomLeftY, topRightY, bottomRightY;
366 bool aboveZeroTL, aboveZeroTR, aboveZeroBL, aboveZeroBR;
367 bool tileHasAboveZeroArea, tileHasBelowZeroArea;
368 for (
int tileY; tileY < tileYCount; ++tileY)
370 for (
int tileX; tileX < tileXCount; ++tileX)
372 if (!worldEditorAPI.GetTerrainSurfaceTile(terrainIndex, tileX, tileY, tileYs))
378 tileHasAboveZeroArea =
false;
379 tileHasBelowZeroArea =
false;
380 foreach (
float yValue : tileYs)
382 if (yValue >= oceanLevel)
384 tileHasAboveZeroArea =
true;
385 if (tileHasBelowZeroArea)
390 tileHasBelowZeroArea =
true;
391 if (tileHasAboveZeroArea)
396 if (!tileHasAboveZeroArea)
399 if (!tileHasBelowZeroArea)
401 result += tileArea * cellSideSizeSq;
406 for (
int tileValueY = 1; tileValueY <= tileSideSizeY; ++tileValueY)
408 for (
int tileValueX = 1; tileValueX <= tileSideSizeX; ++tileValueX)
412 bottomLeftIndex = tileValueX - 1 + tileSideSizeY * (tileValueY - 1);
413 topLeftY = tileYs[bottomLeftIndex + tileSideSizeY];
414 bottomLeftY = tileYs[bottomLeftIndex];
418 bottomLeftIndex = bottomRightIndex;
419 topLeftY = topRightY;
420 bottomLeftY = bottomRightY;
423 bottomRightIndex = bottomLeftIndex + 1;
424 topRightY = tileYs[bottomLeftIndex + tileSideSizeY + 1];
425 bottomRightY = tileYs[bottomRightIndex];
427 aboveZeroTL = topLeftY >= 0;
428 aboveZeroTR = topRightY >= 0;
429 aboveZeroBL = bottomLeftY >= 0;
430 aboveZeroBR = bottomRightY >= 0;
431 if (aboveZeroTL == aboveZeroTR && aboveZeroTL == aboveZeroBL && aboveZeroTL == aboveZeroBR)
440 if (aboveZeroTL == aboveZeroTR && aboveZeroTL == aboveZeroBR)
447 tileSurface += GetTriangle2DAreaAboveOceanLevel(topLeftY, topRightY, bottomRightY, oceanLevel);
451 if (aboveZeroTL == aboveZeroBL && aboveZeroTL == aboveZeroBR)
458 tileSurface += GetTriangle2DAreaAboveOceanLevel(topLeftY, bottomLeftY, bottomRightY, oceanLevel);
463 result += tileSurface * cellSideSizeSq;
477 protected static float GetTriangle2DAreaAboveOceanLevel(
float a,
float b,
float c,
float oceanLevel = 0)
479 array<float> heights = { a - oceanLevel, b - oceanLevel, c - oceanLevel };
485 const float area = 0.5;
494 float r1 = heights[2] / (heights[2] - heights[0]);
495 float r2 = heights[2] / (heights[2] - heights[1]);
496 return area * r1 * r2 * heights[2] / 3;
500 float s1 = -heights[0] / (heights[1] - heights[0]);
501 float s2 = -heights[0] / (heights[2] - heights[0]);
502 float negSubArea = area * s1 * s2;
505 return area * (heights[0] + heights[1] + heights[2]) / 3 - negSubArea * heights[0] / 3;
510 static vector GetTerrainPosition()
512 IEntitySource terrainEntitySource = GetTerrainEntitySource();
513 if (!terrainEntitySource)
517 terrainEntitySource.Get(
"coords", result);
523 static IEntitySource GetTimeAndWeatherManagerEntitySource()
525 WorldEditor worldEditor = GetWorldEditor();
529 if (worldEditor.IsPrefabEditMode())
532 WorldEditorAPI worldEditorAPI = worldEditor.GetApi();
533 if (worldEditorAPI.GetEditorEntityCount() < 2)
536 IEntitySource entitySource;
537 for (
int i, entitiesCount = worldEditorAPI.GetEditorEntityCount(); i < entitiesCount; ++i)
539 entitySource = worldEditorAPI.GetEditorEntity(i);
540 if (entitySource && entitySource.GetClassName().ToType() && entitySource.GetClassName().ToType().IsInherited(TimeAndWeatherManagerEntity))
550 static vector GetWorldEditorCameraPosition(out vector
direction = vector.Zero)
552 WorldEditorAPI worldEditorAPI = GetWorldEditorAPI();
556 vector result, traceEnd;
557 worldEditorAPI.TraceWorldPos(0, 0, 0, result, traceEnd,
direction);
565 static ResourceName GetResourceNameFromFile(
string absoluteFilePath)
567 MetaFile metaFile = GetResourceManager().GetMetaFile(absoluteFilePath);
571 return metaFile.GetResourceID();
577 static array<ResourceName> GetSelectedDirectories()
579 array<ResourceName> result = GetSelectedResources(
true);
583 for (
int i = result.Count() - 1; i >= 0; i--)
585 ResourceName selectedResource = result[i];
586 if (FilePath.StripExtension(selectedResource) != selectedResource)
587 result.RemoveOrdered(i);
598 static array<ResourceName> GetSelectedOrOpenedResources(
string wantedExtension, array<string> keywords = null)
600 return GetSelectedOrOpenedResources({ wantedExtension }, keywords);
605 static array<IEntitySource> GetSelectedWorldEntitySources()
607 WorldEditorAPI worldEditorAPI = GetWorldEditorAPI();
611 array<IEntitySource> result = {};
612 IEntitySource entitySource;
613 for (
int i, count = worldEditorAPI.GetSelectedEntitiesCount(); i < count; ++i)
615 entitySource = worldEditorAPI.GetSelectedEntity(i);
617 result.Insert(entitySource);
628 static array<ResourceName> GetSelectedOrOpenedResources(array<string> acceptedExtensions = null, array<string> keywords = null)
630 array<ResourceName> tempResult = GetSelectedResources(
true);
631 if (tempResult.IsEmpty())
633 ResourceName openedResource = GetPrefabEditModeResourceName();
634 if (!openedResource.IsEmpty())
635 tempResult.Insert(openedResource);
638 if (tempResult.IsEmpty())
641 if (acceptedExtensions && acceptedExtensions.IsEmpty())
642 acceptedExtensions = null;
644 if (acceptedExtensions)
646 foreach (
int i,
string wantedExtension : acceptedExtensions)
648 wantedExtension.ToLower();
649 acceptedExtensions[i] = wantedExtension;
653 array<string> keywordsLC;
654 if (keywords && !keywords.IsEmpty())
657 foreach (
string keyword : keywords)
659 if (keyword.IsEmpty())
663 keywordsLC.Insert(keyword);
667 array<ResourceName> result = {};
672 resourceNameLC.ToLower();
675 resourceNameLC = FilePath.StripExtension(
resourceName, extensionLC);
676 extensionLC.ToLower();
678 if (acceptedExtensions && !acceptedExtensions.Contains(extensionLC))
681 resourceNameLC = FilePath.StripPath(resourceNameLC);
683 if (!keywordsLC || SCR_StringHelper.ContainsEvery(resourceNameLC, keywordsLC))
694 static array<ResourceName> GetSelectedResources(
bool recursive =
true)
696 WorldEditor worldEditor = GetWorldEditor();
700 array<ResourceName> result = {};
701 worldEditor.GetResourceBrowserSelection(result.Insert, recursive);
706 [
Obsolete(
"Use SCR_WorkbenchHelper.SearchWorkbenchResources instead")]
707 static array<ResourceName> SearchWorkbenchResources(array<string> fileExtensions = null, array<string> searchStrArray = null,
string rootPath =
"",
bool recursive =
true)
709 return SCR_WorkbenchHelper.SearchWorkbenchResources(fileExtensions, searchStrArray, rootPath, recursive);
715 static void DeleteEntityFromSource(IEntitySource entitySource)
720 WorldEditorAPI worldEditorAPI = GetWorldEditorAPI();
727 bool manageEditAction = BeginEntityAction();
729 worldEditorAPI.DeleteEntity(entitySource);
731 EndEntityAction(manageEditAction);
737 static bool BeginEntityAction()
739 WorldEditorAPI worldEditorAPI = GetWorldEditorAPI();
746 if (worldEditorAPI.IsDoingEditAction())
749 return worldEditorAPI.BeginEntityAction();
755 static void EndEntityAction(
bool manageEditAction)
757 WorldEditorAPI worldEditorAPI = GetWorldEditorAPI();
764 if (manageEditAction)
765 worldEditorAPI.EndEntityAction();
777 s_aTempEntities = {};
778 if (!world.QueryEntitiesByAABB(mins, maxs, QueryEntitiesCallbackMethod, null, queryFlags))
781 array<IEntity> result = {};
782 result.Copy(s_aTempEntities);
783 s_aTempEntities = null;
796 array<IEntity> result = {};
797 s_aTempEntities = {};
798 world.QueryEntitiesBySphere(worldPos, radius, QueryEntitiesCallbackMethod, null, queryFlags);
799 result.Copy(s_aTempEntities);
800 s_aTempEntities = null;
809 static array<IEntity> TraceMoveEntitiesBySphere(notnull World world, notnull TraceSphere traceSphere)
811 array<IEntity> result = {};
813 s_aTempEntities = {};
814 world.TraceMove(traceSphere, TraceCallbackMethod);
816 result.Copy(s_aTempEntities);
817 s_aTempEntities = null;
827 static array<IEntity> TracePositionEntitiesBySphere(notnull World world, notnull TraceSphere traceSphere)
829 array<IEntity> result = {};
831 s_aTempEntities = {};
832 world.TracePosition(traceSphere, TraceCallbackMethod);
834 result.Copy(s_aTempEntities);
835 s_aTempEntities = null;
846 protected static bool QueryEntitiesCallbackMethod(
IEntity e)
848 s_aTempEntities.Insert(e);
854 protected static bool TraceCallbackMethod(notnull
IEntity e, vector start =
"0 0 0", vector dir =
"0 0 0")
856 s_aTempEntities.Insert(e);
ref array< string > angles
ResourceName resourceName
enum EVehicleType IEntity
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)