1 [
ComponentEditorProps(
category:
"GameScripted/Editor", description:
"Content browser component. Works only with SCR_EditorBaseEntity!", icon:
"WBData/ComponentEditorProps/componentEditor.png")]
7 [
Attribute(
category:
"Placing", uiwidget: UIWidgets.ResourcePickerThumbnail,
desc:
"Editable entity used for testing. Should be a sphere 1 m in diameter.")]
8 protected ResourceName m_TestPrefab;
11 protected ref array<ref SCR_PlaceableEntitiesRegistry> m_Registries;
14 protected ref array<ref SCR_BaseEditorEffect> m_EffectsPlaceStart;
17 protected ref array<ref SCR_BaseEditorEffect> m_EffectsPlaceConfirm;
20 protected ref array<ref SCR_BaseEditorEffect> m_EffectsPlaceCancel;
22 protected int m_iPrefabCount;
23 protected ref array<int> m_aIndexes = {};
25 array<ref SCR_BaseEditorEffect> GetEffectsPlaceStart()
27 return m_EffectsPlaceStart;
29 array<ref SCR_BaseEditorEffect> GetEffectsPlaceConfirm()
31 return m_EffectsPlaceConfirm;
33 array<ref SCR_BaseEditorEffect> GetEffectsPlaceCancel()
35 return m_EffectsPlaceCancel;
43 ResourceName GetPrefab(
int index)
45 for (
int i = m_aIndexes.Count() - 1; i >= 0; i--)
47 int registryIndex = m_aIndexes[i];
48 if (
index >= registryIndex)
49 return m_Registries[i].GetPrefabs()[
index - registryIndex];
51 return ResourceName.Empty;
58 int GetPrefabID(ResourceName prefab)
62 int index = registry.GetPrefabs().Find(prefab);
64 return index + m_aIndexes[i];
74 return m_iPrefabCount;
81 int GetPrefabs(out notnull array<ResourceName> outPrefabs,
bool onlyExposed =
false)
85 outPrefabs.InsertAll(registry.GetPrefabs(onlyExposed));
87 return outPrefabs.Count();
95 return SCR_Enum.HasFlag(m_AllowedPlacingFlags, flag);
101 ResourceName GetTestPrefab()
110 m_aIndexes.Insert(m_iPrefabCount);
111 m_iPrefabCount += registry.GetPrefabs().Count();
120 [
Attribute(defvalue:
"10",
category:
"Placing",
desc:
"Spacing between entities placed for multiple recipients")]
121 protected float m_fSpacing;
123 private ResourceName m_SelectedPrefab;
129 private int m_iEntityIndex;
130 private ref map<int, IEntity> m_WaitingPreviews =
new map<int, IEntity>;
131 private vector m_vFixedPosition;
132 private float m_fPreviewAnimationProgress = -1;
135 private ref set<SCR_EditableEntityComponent> m_Recipients;
138 protected bool m_bBlockPlacing;
140 private ref ScriptInvoker Event_OnSelectedPrefabChange =
new ScriptInvoker;
141 private ref ScriptInvoker Event_OnPlacingPlayerChange =
new ScriptInvoker;
142 private ref ScriptInvoker Event_OnPlacingFlagsChange =
new ScriptInvoker;
144 private ref ScriptInvoker Event_OnRequestEntity =
new ScriptInvoker;
145 private ref ScriptInvoker Event_OnPlaceEntity =
new ScriptInvoker;
147 private ref ScriptInvoker Event_OnPlaceEntityServer =
new ScriptInvoker;
152 void SetPlacingBlocked(
bool blocked)
154 m_bBlockPlacing = blocked;
162 int GetPrefabID(ResourceName prefab)
164 if (prefab.IsEmpty())
171 return prefabData.GetPrefabID(prefab);
181 bool CreateEntity(
bool unselectPrefab =
true,
bool canBePlayer =
false)
185 if (!CanCreateEntity(notification))
187 if (notification != -1)
193 if (!prefabData || !m_SelectedPrefab)
return false;
198 SetSelectedPrefab(ResourceName.Empty,
true);
202 int prefabID = prefabData.GetPrefabID(m_SelectedPrefab);
205 Print(
string.Format(
"Cannot place prefab @\"%1\", it's not registered in placeable entities!", m_SelectedPrefab.GetPath()), LogLevel.WARNING);
206 SetSelectedPrefab(ResourceName.Empty,
true);
211 int playerID = GetManager().GetPlayerID();
218 Resource prefabResource = Resource.Load(m_SelectedPrefab);
223 SetSelectedPrefab(ResourceName.Empty,
true);
231 array<ref SCR_EntityBudgetValue> budgetCosts = {};
232 Resource resource = Resource.Load(m_SelectedPrefab);
233 if (!resource.IsValid())
235 Print(
"Cannot load prefab " + m_SelectedPrefab +
" | " + FilePath.StripPath(__FILE__) +
":" + __LINE__, LogLevel.WARNING);
240 m_BudgetManager.GetVehicleOccupiedBudgetCosts(source, m_PlacingFlags, budgetCosts,
false);
243 if (!m_BudgetManager.CanPlace(budgetCosts, blockingBudget))
244 SCR_NotificationsComponent.SendLocal(
ENotification.EDITOR_PLACING_BUDGET_MAX_FOR_VEHICLE_OCCUPANTS);
249 if (m_InstantPlacingParam)
251 params = m_InstantPlacingParam;
258 parent = layersManager.GetCurrentLayer();
267 params.m_PlacingFlags = m_PlacingFlags;
270 int simulatedDelay = DiagMenu.GetValue(
SCR_DebugMenuID.DEBUGUI_EDITOR_NETWORK_DELAY) * 100;
272 if (
IsProxy() || simulatedDelay > 0)
273 m_WaitingPreviews.Insert(m_iEntityIndex,
m_PreviewManager.CreateWaitingPreview());
275 array<RplId> recipientIds;
281 RplId
id = Replication.FindId(entity);
283 recipientIds.Insert(
id);
289 Event_OnRequestEntity.Invoke(prefabID,
params.m_vTransform,
null);
291 if (simulatedDelay > 0 && !Replication.IsRunning())
292 GetGame().GetCallqueue().CallLater(CreateEntityServer, simulatedDelay,
false,
params, prefabID, playerID, m_iEntityIndex, !unselectPrefab, recipientIds, canBePlayer);
294 Rpc(CreateEntityServer,
params, prefabID, playerID, m_iEntityIndex, !unselectPrefab, recipientIds, canBePlayer);
300 m_InstantPlacingParam =
null;
303 if (unselectPrefab || m_InstantPlacingParam)
304 SetSelectedPrefab(ResourceName.Empty,
true);
317 bool CreateEntity(ResourceName prefab,
SCR_EditorPreviewParams param,
bool unselectPrefab =
true,
bool canBePlayer =
false, set<SCR_EditableEntityComponent> recipients =
null)
322 m_SelectedPrefab = prefab;
323 m_Recipients = recipients;
324 SetInstantPlacing(param);
325 return CreateEntity(unselectPrefab, canBePlayer);
328 [
RplRpc(RplChannel.Reliable, RplRcver.Server)]
329 protected void CreateEntityServer(
SCR_EditorPreviewParams params, RplId prefabID,
int playerID,
int entityIndex,
bool isQueue, array<RplId> recipientIds,
bool canBePlayer)
335 if (RplSession.Mode() == RplMode.Client || !prefabData)
return;
337 array<RplId> entityIds = {};
339 if (!CanCreateEntity() || !
params.Deserialize())
341 Rpc(CreateEntityOwner, prefabID, entityIds, entityIndex,
false,
false, RplId.Invalid(), 0);
346 ResourceName prefab = prefabData.GetPrefab(prefabID);
347 if (prefab.IsEmpty())
349 Print(
"Cannot create entity, prefab not defined!", LogLevel.ERROR);
350 Rpc(CreateEntityOwner, prefabID, entityIds, entityIndex,
false,
false, RplId.Invalid(), 0);
353 Resource prefabResource = Resource.Load(prefab);
354 if (!prefabResource || !prefabResource.IsValid())
356 Print(
string.Format(
"Cannot create entity, error when loading prefab '%1'!", prefab), LogLevel.ERROR);
357 Rpc(CreateEntityOwner, prefabID, entityIds, entityIndex,
false,
false, RplId.Invalid(), 0);
361 if (!editableEntitySource)
363 Print(
string.Format(
"Cannot create entity, prefab '%1' does not contain SCR_EditableEntityComponent!", prefab), LogLevel.ERROR);
364 Rpc(CreateEntityOwner, prefabID, entityIds, entityIndex,
false,
false, RplId.Invalid(), 0);
369 if (!CanPlaceEntityServer(editableEntitySource, blockingBudget,
false,
false))
371 Print(
string.Format(
"Entity budget exceeded for player!"), LogLevel.ERROR);
372 Rpc(CreateEntityOwner, prefabID, entityIds, entityIndex,
false,
false, RplId.Invalid(), 0);
376 OnBeforeEntityCreatedServer(prefab);
379 bool hasRecipients =
false;
380 RplId currentLayerID;
381 array<SCR_EditableEntityComponent> entities = {};
382 if (recipientIds && !recipientIds.IsEmpty())
385 array<SCR_EditableEntityComponent> recipients = {};
386 foreach (RplId
id: recipientIds)
390 recipients.Insert(recipient);
392 array<vector> offsets = GetOffsets(recipients.Count());
393 array<ref array<int>> distances = {};
395 for (
int i = 0; i < recipients.Count(); i++)
397 array<int> distToPosition = {};
400 for (
int j = 0; j < offsets.Count(); j++)
403 distToPosition.Insert(Math.Clamp(vector.DistanceSq(
position, offsets[j]), 0,
int.MAX));
405 distances.Insert(distToPosition);
410 array<int> permutation = {};
411 AssignmentSolver.Solve(distances, permutation);
415 params.m_Offset = offsets[permutation[i]];
416 entity = SpawnEntityResource(
params, prefabResource, playerID, isQueue, recipient, canBePlayer);
417 entities.Insert(entity);
418 entityIds.Insert(Replication.FindId(entity));
420 hasRecipients =
true;
421 currentLayerID = Replication.FindId(recipients[0].GetParentEntity());
426 entity = SpawnEntityResource(
params, prefabResource, playerID, isQueue,
null, canBePlayer);
427 entities.Insert(entity);
428 entityIds.Insert(Replication.FindId(entity));
429 currentLayerID = Replication.FindId(
params.m_CurrentLayer);
432 entity.OnCreatedServer(
this);
433 OnEntityCreatedServer(entities);
435 Rpc(CreateEntityOwner, prefabID, entityIds, entityIndex, isQueue, hasRecipients, currentLayerID, 0);
436 Event_OnPlaceEntityServer.Invoke(prefabID, entity, playerID);
438 [
RplRpc(RplChannel.Reliable, RplRcver.Owner)]
439 protected void CreateEntityOwner(
int prefabID, array<RplId> entityIds,
int entityIndex,
int isQueue,
bool hasRecipients, RplId currentLayerID,
int attempt)
453 IEntity waitingPreview;
454 if (m_WaitingPreviews.Find(entityIndex, waitingPreview))
456 m_WaitingPreviews.Remove(entityIndex);
457 delete waitingPreview;
466 set<SCR_EditableEntityComponent> entities =
new set<SCR_EditableEntityComponent>();
468 for (
int i, count = entityIds.Count(); i < count; i++)
472 entities.Insert(entity);
476 if (entities.IsEmpty())
480 GetGame().GetCallqueue().CallLater(CreateEntityOwner, 1,
false, prefabID, entityIds, entityIndex, isQueue, hasRecipients, currentLayerID, attempt + 1);
485 Print(
string.Format(
"Error when creating entity from prefab '%1' (id = %2)!", prefabData.GetPrefab(prefabID), prefabID), LogLevel.ERROR);
494 selectedFilter.Replace(entities);
498 if (!currentLayerID.IsValid() || currentLayer)
502 layerManager.SetCurrentLayer(currentLayer);
508 GetGame().GetCallqueue().CallLater(CheckBudgetOwner, 100,
false);
512 m_BudgetManager.ResetPreviewCost();
516 Event_OnPlaceEntity.Invoke(prefabID, entity);
520 entities[0].GetPos(pos);
523 if (prefabData)
SCR_BaseEditorEffect.Activate(prefabData.GetEffectsPlaceConfirm(),
this, pos, entities);
534 return !m_bBlockPlacing;
541 protected void OnBeforeEntityCreatedServer(ResourceName prefab);
547 protected void OnEntityCreatedServer(array<SCR_EditableEntityComponent> entities);
549 protected void CheckBudgetOwner()
552 if (!CanSelectEntityPrefab(m_SelectedPrefab, blockingBudget,
true))
554 m_BudgetManager.ResetPreviewCost();
555 SetSelectedPrefab(ResourceName.Empty,
true);
562 SetSelectedPrefab(ResourceName.Empty,
true);
586 if (Replication.IsClient() || !prefabResource|| !prefabResource.IsValid())
595 if (!respawnComponent)
608 owner = slot.SpawnEntityInSlot(prefabResource, Math3D.MatrixToAngles(
params.m_vTransform)[0], -1);
613 EntitySpawnParams spawnParams =
new EntitySpawnParams();
614 spawnParams.TransformMode = ETransformMode.WORLD;
615 targetOwner.GetWorldTransform(spawnParams.Transform);
616 owner =
GetGame().SpawnEntityPrefab(prefabResource,
GetGame().GetWorld(), spawnParams);
623 EntitySpawnParams spawnParams =
new EntitySpawnParams();
624 spawnParams.TransformMode = ETransformMode.WORLD;
625 params.GetWorldTransform(spawnParams.Transform);
626 owner =
GetGame().SpawnEntityPrefab(prefabResource,
GetGame().GetWorld(), spawnParams);
631 if (!respawnComponent.RequestSpawn(spawnData))
632 Print(
string.Format(
"@\"%1\" control cannot be given to playerID=%2, error in RequestSpawn!", prefabResource.GetResource().GetResourceName().GetPath(), playerID), LogLevel.ERROR);
641 SCR_EditableCommentComponent comment = SCR_EditableCommentComponent.Cast(
params.m_Target);
642 SCR_CompositionSlotManagerComponent slotManager = SCR_CompositionSlotManagerComponent.GetInstance();
643 if (comment && slotManager)
644 slotManager.SetOccupant(comment.GetOwnerScripted(), owner);
660 SCR_EditableVehicleComponent vehicle = SCR_EditableVehicleComponent.Cast(
params.m_Parent);
662 entity.ForceVehicleCompartments(SCR_BaseCompartmentManagerComponent.PASSENGER_COMPARTMENT_TYPES);
667 childEntity.SetParentEntity(
params.m_Parent);
672 if (childEntity != entity)
673 params.m_Parent = childEntity;
676 params.m_CurrentLayer = childEntity.GetParentEntity();
694 m_DelayedSpawnEntity = entity;
695 m_DelayedSpawnPreviewParams =
params;
696 group.GetOnAllDelayedEntitySpawned().Insert(OnAIGroupAllEntitiesSpawned);
706 vector logTransform[4];
708 owner.GetWorldTransform(logTransform);
710 params.GetWorldTransform(logTransform);
714 Print(
string.Format(
"@\"%1\" placed for %3 at %2", prefabResource.GetResource().GetResourceName().GetPath(), logTransform, recipient.GetDisplayName()), LogLevel.VERBOSE);
715 else if (prefabResource)
716 Print(
string.Format(
"@\"%1\" placed at %2", prefabResource.GetResource().GetResourceName().GetPath(), logTransform), LogLevel.VERBOSE);
718 Print(
string.Format(
"@\"%1\" placed at %2",
"Entity", logTransform), LogLevel.VERBOSE);
725 protected static void OnAIGroupAllEntitiesSpawned(
SCR_AIGroup group)
730 m_DelayedSpawnEntity =
null;
731 m_DelayedSpawnPreviewParams =
null;
732 group.GetOnAllDelayedEntitySpawned().Remove(OnAIGroupAllEntitiesSpawned);
754 if (uiInfo.CanFillWithCrew())
758 if (uiInfo.CanFillWithPassengers())
761 return vehiclePlacingFlags;
770 protected bool CanPlaceEntityServer(IEntityComponentSource editableEntitySource, out
EEditableEntityBudget blockingBudget,
bool updatePreview,
bool showNotification)
772 if (!m_BudgetManager)
775 if (!m_BudgetManager)
779 return m_BudgetManager.CanPlaceEntitySource(editableEntitySource, blockingBudget, HasPlacingFlag(
EEditorPlacingFlags.CHARACTER_PLAYER), updatePreview, showNotification);
782 protected bool CanSelectEntityPrefab(ResourceName prefab, out
EEditableEntityBudget blockingBudget,
bool updatePreview =
true,
bool showBudgetMaxNotification =
true)
784 if (!m_BudgetManager || prefab.IsEmpty())
788 Resource entityPrefab = Resource.Load(prefab);
793 return CanPlaceEntityServer(editableEntitySource, blockingBudget, updatePreview, showBudgetMaxNotification);
796 protected array<vector> GetOffsets(
int count)
798 array<vector> result = {};
804 result.Insert(vector.Zero);
808 int rowCount = Math.Round(Math.Sqrt(count));
809 int columnCount = Math.Ceil(Math.Sqrt(count));
810 vector offset = -Vector((rowCount - 1) * m_fSpacing / 2, 0, (columnCount - 1) * m_fSpacing / 2);
813 for (
int i = 0; i < count; i++)
815 row = Math.Floor(i / columnCount);
816 column = i % columnCount;
817 result.Insert(offset + Vector(row * m_fSpacing, 0, column * m_fSpacing));
823 int index = m_Recipients.Find(entity);
826 m_Recipients.Remove(
index);
829 if (m_Recipients.IsEmpty())
841 m_InstantPlacingParam = param;
849 bool SetSelectedPrefab(ResourceName prefab =
"",
bool onConfirm =
false,
bool showBudgetMaxNotification =
true, set<SCR_EditableEntityComponent> recipients =
null)
851 if (prefab == m_SelectedPrefab)
return true;
855 if (!prefab.IsEmpty() && !CanSelectEntityPrefab(prefab, blockingBudget, showBudgetMaxNotification))
861 if (m_InstantPlacingParam && !prefab.IsEmpty())
865 m_SelectedPrefab = prefab;
866 m_Recipients = recipients;
873 if (!prefab.IsEmpty() && prefabData.GetPrefabID(prefab) == -1)
875 Print(
string.Format(
"Cannot initiate placing of prefab @\"%1\", it's not registered in placeable entities!", prefab), LogLevel.WARNING);
881 m_BudgetManager.ResetPreviewCost();
897 if (prefab && recipients)
900 core.Event_OnEntityUnregistered.Insert(OnEntityUnregistered);
902 else if (!prefab && m_Recipients)
905 core.Event_OnEntityUnregistered.Remove(OnEntityUnregistered);
909 ResourceName prefabPrev = m_SelectedPrefab;
910 m_SelectedPrefab = prefab;
911 m_Recipients = recipients;
914 int instanceCount = 1;
915 if (recipients) instanceCount = recipients.Count();
916 IEntity previewEntity =
m_PreviewManager.CreatePreview(prefab, GetOffsets(instanceCount));
927 if (teleportComponent) teleportComponent.TeleportCamera(previewEntity.GetOrigin(),
true,
true);
930 m_CompatiblePlacingFlags = GetCompatiblePlacingFlags(Resource.Load(m_SelectedPrefab));
938 Event_OnSelectedPrefabChange.Invoke(prefab, prefabPrev);
940 if (prefab && !prefabPrev)
942 else if (!prefab && prefabPrev && !onConfirm)
951 ResourceName GetSelectedPrefab()
953 return m_SelectedPrefab;
957 return !m_SelectedPrefab.IsEmpty();
983 if (toAdd && !IsPlacingFlagAllowed(flag))
985 Print(
string.Format(
"Cannot enable placing flag %1, placing manager does not allow it!",
typename.EnumToString(
EEditorPlacingFlags, flag)), LogLevel.WARNING);
992 m_PlacingFlags |= flag;
994 m_PlacingFlags &= ~flag;
997 if (m_PlacingFlags != prevPlacingFlag)
998 Event_OnPlacingFlagsChange.Invoke(flag, toAdd);
1001 UpdatePlacingFlagBudget(m_SelectedPrefab, flag, m_PlacingFlags, prevPlacingFlag);
1013 if (m_SelectedPrefab.IsEmpty())
1020 Resource resource = Resource.Load(selectedPrefab);
1021 if (!resource.IsValid())
1023 Print(
"Cannot load " + selectedPrefab +
" | " + FilePath.StripPath(__FILE__) +
":" + __LINE__, LogLevel.WARNING);
1027 m_BudgetManager.CanPlaceEntitySource(
SCR_EditableEntityComponentClass.GetEditableEntitySource(resource.GetResource().ToEntitySource()), blockingBudget, isPlacingPlayer);
1032 array<ref SCR_EntityBudgetValue> budgetCosts = {};
1033 Resource resource = Resource.Load(selectedPrefab);
1034 if ( !resource.IsValid())
1036 Print(
"Cannot load " + selectedPrefab +
" | " + FilePath.StripPath(__FILE__) +
":" + __LINE__, LogLevel.WARNING);
1041 m_BudgetManager.GetVehicleOccupiedBudgetCosts(source, currentPlacingFlag, budgetCosts);
1042 m_BudgetManager.UpdatePreviewCost(budgetCosts);
1052 SetPlacingFlag(flag, !HasPlacingFlag(flag));
1061 return SCR_Enum.HasFlag(m_PlacingFlags, flag);
1070 return SCR_Enum.HasFlag(m_CompatiblePlacingFlags, flag);
1080 return prefabData && prefabData.HasPlacingFlag(flag);
1086 ScriptInvoker GetOnSelectedPrefabChange()
1088 return Event_OnSelectedPrefabChange;
1095 ScriptInvoker GetOnPlacingFlagsChange()
1097 return Event_OnPlacingFlagsChange;
1104 ScriptInvoker GetOnRequestEntity()
1106 return Event_OnRequestEntity;
1113 ScriptInvoker GetOnPlaceEntity()
1115 return Event_OnPlaceEntity;
1118 ScriptInvoker GetOnPlaceEntityServer()
1120 return Event_OnPlaceEntityServer;
1123 override void EOnEditorDebug(array<string> debugTexts)
1126 if (m_SelectedPrefab)
1128 debugTexts.Insert(
string.Format(
"Placing prefab: %1", FilePath.StripPath(m_SelectedPrefab.GetPath())));
1132 debugTexts.Insert(
"Placing prefab: N/A");
1136 override void EOnEditorActivate()
1141 if (m_BudgetManager)
1143 m_BudgetManager.Event_OnBudgetMaxReached.Insert(OnBudgetMaxReached);
1149 override void EOnEditorDeactivate()
1151 m_SelectedPrefab = ResourceName.Empty;
1153 if (m_BudgetManager)
1155 m_BudgetManager.Event_OnBudgetMaxReached.Remove(OnBudgetMaxReached);