3 [
EntityEditorProps(
category:
"GameScripted/Editor", description:
"Slot in which entities can be placed in", color:
"255 0 0 255")]
6 [
Attribute(defvalue:
"-1",
category:
"Slot",
desc:
"Forced rotation step. 0 means unlimited rotation, -1 disables rotation.")]
7 private float m_fRotationStep;
13 float GetRotationStep()
15 return m_fRotationStep;
38 if (GetOccupant())
return null;
40 ArmaReforgerScripted game =
GetGame();
41 if (!game)
return null;
44 EntitySpawnParams spawnParams =
new EntitySpawnParams;
45 GetWorldTransform(spawnParams.Transform);
46 spawnParams.TransformMode = ETransformMode.WORLD;
51 vector angles = Math3D.MatrixToAngles(spawnParams.Transform);
53 Math3D.AnglesToMatrix(angles, spawnParams.Transform);
57 string resourceName = resource.GetResource().GetResourceName();
58 IEntity baseEntity = game.SpawnEntityPrefab(resource, GetWorld(), spawnParams);
59 if (!baseEntity)
return null;
62 SetOccupant(baseEntity);
65 bool updateNavmesh =
true;
66 if (verticalMode != -1)
73 updateNavmesh =
false;
88 aiWorld.RequestNavmeshRebuildEntity(baseEntity);
91 Print(
string.Format(
"Entity @\"%1\" spawned in slot '%2'.", resourceName,
GetName()), LogLevel.VERBOSE);
99 float GetRotationStep()
102 if (!prefabData)
return 0;
104 return prefabData.GetRotationStep();
111 IEntity GetOccupant()
113 SCR_CompositionSlotManagerComponent manager = SCR_CompositionSlotManagerComponent.GetInstance();
116 return manager.GetOccupant(
this);
120 Debug.Error2(Type().ToString(),
"Cannot get slot occupant, SCR_CompositionSlotManagerComponent is missing in the game mode entity!");
130 SCR_CompositionSlotManagerComponent manager = SCR_CompositionSlotManagerComponent.GetInstance();
133 return manager.IsOccupied(
this);
137 Debug.Error2(Type().ToString(),
"Cannot check if a slot is occupied, SCR_CompositionSlotManagerComponent is missing in the game mode entity!");
147 void SetOccupant(IEntity occupant)
149 SCR_CompositionSlotManagerComponent manager = SCR_CompositionSlotManagerComponent.GetInstance();
152 manager.SetOccupant(
this, occupant);
156 Debug.Error2(Type().ToString(),
"Cannot set slot occupant, SCR_CompositionSlotManagerComponent is missing in the game mode entity!");
164 ClearFlags(EntityFlags.TRACEABLE,
false);
165 SetFlags(EntityFlags.STATIC,
false);
169 const string NAME_FORMAT =
"%1_%2";
170 const int ITERATOR_DIGITS = 3;
171 const int ITERATORS_LIMIT = 1000;
173 void _WB_SnapToTerrain(IEntitySource entitySource)
176 pos[1] = GetWorld().GetSurfaceY(pos[0], pos[2]);
177 if (entitySource.GetParent())
180 WorldEditorAPI api = _WB_GetEditorAPI();
181 IEntitySource src = api.EntityToSource(
this);
182 api.SetVariableValue(src,
null,
"coords", pos.ToString(
false));
184 void _WB_OrientToTerrain(IEntitySource entitySource)
186 WorldEditorAPI api = _WB_GetEditorAPI();
187 IEntitySource src = api.EntityToSource(
this);
189 api.SetVariableValue(src,
null,
"angleX",
"0");
190 api.SetVariableValue(src,
null,
"angleZ",
"0");
193 GetWorldTransform(transform);
194 vector pos = transform[3];
197 vector min, max, posChild;
199 #ifdef SLOT_ENTITY_DEBUG
200 m_DebugShapes.Clear();
203 for (
int i = 0, count = entitySource.GetNumChildren(); i < count; i++)
205 IEntitySource childSrc = entitySource.GetChild(i);
206 child = api.SourceToEntity(childSrc);
207 child.GetBounds(min, max);
209 float posY = -
float.MAX;
210 float angleZ = _WB_GetAngle(api, pos + transform[0] * min[0], pos + transform[0] * max[0], posY);
211 float angleX = _WB_GetAngle(api, pos + transform[2] * min[2], pos + transform[2] * max[2], posY);
215 posChild = CoordToLocal(posChild);
217 api.SetVariableValue(childSrc,
null,
"coords", posChild.ToString(
false));
218 api.SetVariableValue(childSrc,
null,
"angleX", angleX.ToString());
219 api.SetVariableValue(childSrc,
null,
"angleZ", (-angleZ).ToString());
222 float _WB_GetAngle(WorldEditorAPI api, vector posA, vector posB, out
float posY)
224 float dis = vector.Distance(posA, posB);
227 Print(
string.Format(
"Slot entity %1 at position %2 has zero size!",
this, GetWorldTransformAxis(3)), LogLevel.WARNING);
231 posA[1] = api.GetTerrainSurfaceY(posA[0], posA[2]);
232 posB[1] = api.GetTerrainSurfaceY(posB[0], posB[2]);
234 vector posCenter = vector.Lerp(posA, posB, 0.5);
235 posY = Math.Max(posY, posCenter[1]);
237 #ifdef SLOT_ENTITY_DEBUG
238 m_DebugShapes.Insert(Shape.CreateSphere(Color.RED, ShapeFlags.VISIBLE, posA, 0.5));
239 m_DebugShapes.Insert(Shape.CreateSphere(Color.GREEN, ShapeFlags.VISIBLE, posB, 0.5));
240 m_DebugShapes.Insert(Shape.CreateSphere(Color.BLUE, ShapeFlags.VISIBLE, posCenter, 0.5));
243 return Math.Tan((posB[1] - posA[1]) / dis) * Math.RAD2DEG;
246 override array<ref WB_UIMenuItem> _WB_GetContextMenuItems()
248 array<ref WB_UIMenuItem> items = {
new WB_UIMenuItem(
"Snap and orient to terrain", 0) };
251 items.Insert(
new WB_UIMenuItem(
"Auto-assign slot name", 1));
255 override void _WB_OnContextMenu(
int id)
261 WorldEditorAPI api = _WB_GetEditorAPI();
263 api.BeginEntityAction();
264 IEntitySource entitySource = _WB_GetEditorAPI().EntityToSource(
this);
265 _WB_SnapToTerrain(entitySource);
266 _WB_OrientToTerrain(entitySource);
267 api.EndEntityAction();
272 WorldEditorAPI api = _WB_GetEditorAPI();
273 api.BeginEntityAction();
274 api.EndEntityAction();
279 #ifdef SLOT_ENTITY_DEBUG
280 protected ref array<ref Shape> m_DebugShapes = {};
282 override bool _WB_OnKeyChanged(BaseContainer src,
string key, BaseContainerList ownerContainers, IEntity parent)
286 WorldEditorAPI api = _WB_GetEditorAPI();
287 if (!api.UndoOrRedoIsRestoring())
289 IEntitySource entitySource = src.ToEntitySource();
290 _WB_OrientToTerrain(entitySource);