3class SCR_FloatersFixerPlugin : WorkbenchPlugin
5 [
Attribute(defvalue:
"1",
desc:
"Set object's origin from OBJECTS or terrain (2× slower as it uses Trace)")]
6 protected bool m_bSetOnTerrainAndEntitiesSurface;
8 [
Attribute(defvalue:
"50",
desc:
"Trace origin's distance from above the object/terrain", uiwidget: UIWidgets.Slider,
params:
"10 500 10")]
9 protected int m_iTraceOriginDistance;
11 [
Attribute(defvalue:
"0",
desc:
"If set, uses the Prefab's vertical offset range; otherwise, uses below settings")]
12 protected bool m_bUsePrefabVerticalOffset;
14 [
Attribute(defvalue:
"1",
desc:
"If set, uses the Prefab's align to normal setting; otherwise uses Align To Normal Override")]
15 protected bool m_bUsePrefabAlignToNormal;
17 [
Attribute(defvalue:
"0",
desc:
"Forces Align To Normal; requires Use Prefab Align To Normal above to be off")]
18 protected bool m_bAlignToNormalOverride;
20 protected BaseWorld m_BaseWorld;
22 protected static const ResourceName BUSH_BASE =
"{D7163D1B571F4C0C}Prefabs/Vegetation/Core/Bush_Base.et";
23 protected static const ResourceName TREE_BASE =
"{388AE316D09D0680}Prefabs/Vegetation/Core/Tree_Base.et";
24 protected static const int MANY_ENTITIES_THRESHOLD = 10;
32 Print(
"Floaters Fixer - Run method started",
LogLevel.NORMAL);
35 IEntitySource entitySource;
36 BaseContainerList editorData;
37 BaseContainer firstEditorData;
38 vector entityPos, entityPosOffset, entityYawPitchRoll, normalAngles, randomVerticalOffset;
39 float altitude, terrainY;
40 bool alignToSurfaceNormal;
41 TraceParam traceParam =
new TraceParam();
43 float minVerticalOffset, maxVerticalOffset, maxPitch, maxRoll;
45 WorldEditorAPI worldEditorAPI = ((WorldEditor)Workbench.GetModule(WorldEditor)).GetApi();
47 int selectedEntitiesCount = worldEditorAPI.GetSelectedEntitiesCount();
48 bool manyEntities = selectedEntitiesCount > MANY_ENTITIES_THRESHOLD;
49 RandomGenerator randomGenerator =
new RandomGenerator();
51 if (selectedEntitiesCount < 1)
54 int firstTick = System.GetTickCount();
55 worldEditorAPI.BeginEntityAction();
56 for (
int i; i < selectedEntitiesCount; i++)
58 entitySource = worldEditorAPI.GetSelectedEntity(i);
62 entity = worldEditorAPI.SourceToEntity(entitySource);
64 alignToSurfaceNormal = m_bAlignToNormalOverride;
65 minVerticalOffset = 0;
66 maxVerticalOffset = 0;
70 editorData = entitySource.GetObjectArray(
"editorData");
71 if (editorData && editorData.Count() )
73 firstEditorData = editorData.Get(0);
75 randomVerticalOffset = vector.Zero;
76 firstEditorData.Get(
"randomVertOffset", randomVerticalOffset);
77 minVerticalOffset = randomVerticalOffset[0];
78 maxVerticalOffset = randomVerticalOffset[1];
80 firstEditorData.Get(
"randomPitchAngle", maxPitch);
81 firstEditorData.Get(
"randomRollAngle", maxRoll);
83 if (!m_bAlignToNormalOverride && m_bUsePrefabAlignToNormal)
84 firstEditorData.Get(
"alignToNormal", alignToSurfaceNormal);
99 entityPosOffset = vector.Zero;
101 entityPosOffset = entityPos - SCR_BaseContainerTools.GetLocalCoords(entitySource.GetParent(), entityPos);
104 terrainY = worldEditorAPI.GetTerrainSurfaceY(entityPos[0], entityPos[2]);
105 altitude = entityPos[1] - terrainY;
107 entityPos[1] = terrainY;
110 if (m_bUsePrefabAlignToNormal || alignToSurfaceNormal || m_bSetOnTerrainAndEntitiesSurface)
112 traceParam.Exclude = entity;
114 if (m_bSetOnTerrainAndEntitiesSurface)
116 traceParam.Start = { entityPos[0], entityPos[1] + m_iTraceOriginDistance, entityPos[2] };
117 traceParam.End = { entityPos[0], terrainY, entityPos[2] };
120 traceRatio = m_BaseWorld.TraceMove(traceParam, FilterNonVegetationCallback);
126 Print(
string.Format(
"FROM %1", traceParam.Start),
LogLevel.NORMAL);
127 Print(
string.Format(
"..TO %1", traceParam.End),
LogLevel.NORMAL);
128 Print(
string.Format(
"DIST %1", traceParam.Start[1] - terrainY),
LogLevel.NORMAL);
129 Print(
string.Format(
"DONE %1pct (%2m)", Math.Round(traceRatio * 10000) * 0.01, (traceParam.Start[1] - terrainY) * traceRatio),
LogLevel.NORMAL);
134 traceParam.Start = { entityPos[0], terrainY + 1, entityPos[2] };
135 traceParam.End = { entityPos[0], terrainY - 1, entityPos[2] };
138 traceRatio = m_BaseWorld.TraceMove(traceParam, null);
141 if (alignToSurfaceNormal)
143 normalAngles = GetXYZAnglesFromNormal(entity, traceParam.TraceNorm);
144 worldEditorAPI.SetVariableValue(entitySource, null,
"angles", normalAngles.ToString(
false));
147 if (m_bSetOnTerrainAndEntitiesSurface)
148 entityPos[1] = traceParam.Start[1] - (traceParam.Start[1] - traceParam.End[1]) * traceRatio;
150 entityPos[1] = terrainY;
153 entityPos -= entityPosOffset;
157 entityPos[1] = entityPos[1] - terrainY;
159 if (m_bUsePrefabVerticalOffset && (minVerticalOffset != 0 || maxVerticalOffset != 0))
160 entityPos[1] = entityPos[1] + randomGenerator.RandFloatXY(minVerticalOffset, maxVerticalOffset);
162 worldEditorAPI.SetVariableValue(entitySource, null,
"coords", entityPos.ToString(
false));
164 worldEditorAPI.EndEntityAction();
166 Print(
string.Format(
"Fixed %1 floating entities in %2ms", selectedEntitiesCount, System.GetTickCount() - firstTick),
LogLevel.NORMAL);
171 protected bool Init()
173 if (!SCR_Global.IsEditMode())
175 Print(
"Floaters Fixer - Run method stopped because non-Workbench run",
LogLevel.NORMAL);
179 WorldEditor worldEditor = Workbench.GetModule(WorldEditor);
182 Print(
"Floaters Fixer - Run method stopped because… World Editor is unavailable from World Editor? o_o",
LogLevel.WARNING);
186 if (worldEditor.IsPrefabEditMode())
188 Print(
"Floaters Fixer - Run method stopped because World Editor is in Prefab edit mode",
LogLevel.NORMAL);
192 WorldEditorAPI worldEditorAPI = worldEditor.GetApi();
195 Print(
"Floaters Fixer - Run method stopped because World Editor API was not found",
LogLevel.WARNING);
199 BaseWorld baseWorld = worldEditorAPI.GetWorld();
202 Print(
"Floaters Fixer - Run method stopped because base world was not found",
LogLevel.WARNING);
206 m_BaseWorld = baseWorld;
212 protected bool FilterNonVegetationCallback(notnull
IEntity entity, vector start =
"0 0 0", vector dir =
"0 0 0")
214 if (entity.IsInherited(GenericTerrainEntity))
217 WorldEditorAPI worldEditorAPI = ((WorldEditor)Workbench.GetModule(WorldEditor)).GetApi();
218 IEntitySource source = worldEditorAPI.EntityToSource(entity);
222 string resourceName = SCR_BaseContainerTools.GetTopMostAncestor(source).GetResourceName();
229 protected vector GetXYZAnglesFromNormal(
IEntity entity, vector normal)
232 vector worldTransform[4];
234 Math3D.DirectionAndUpMatrix(worldTransform[2], normal, worldTransform);
245 Workbench.ScriptDialog(
"Configure 'Floaters Finder' plugin",
"",
this);
ResourceName resourceName
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
enum EVehicleType IEntity
class WorkbenchDialog_AbortRetryIgnore ButtonAttribute("OK", true)
proto external EntityFlags GetFlags()
proto external vector GetOrigin()
proto external void GetWorldTransform(out vector mat[])
See IEntity::GetTransform.
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
EntityFlags
Various entity flags.