1 [
EntityEditorProps(
category:
"GameScripted/Components", description:
"Allows player to spawn entities configured in EntityCatalogs, usually found on factions. Requires SCR_EntitySpawnerSlotComponent in vicinity.", color:
"0 0 255 255")]
4 [
Attribute(defvalue:
"{56EBF5038622AC95}Assets/Conflict/CanBuild.emat",
params:
"emat",
desc:
"Material used on entity previews, visible to local players only",
category:
"Entity Spawner")]
5 ResourceName m_sPreviewEntityMaterial;
7 [
Attribute(defvalue:
"{14A9DCEA57D1C381}Assets/Conflict/CannotBuild.emat",
params:
"emat",
desc:
"Material used on unavailable entity previews, visible to local players only",
category:
"Entity Spawner")]
8 ResourceName m_sPreviewEntityMaterialUnavailable;
10 [
Attribute(defvalue :
"{000CD338713F2B5A}Prefabs/AI/Groups/Group_Base.et", UIWidgets.ResourceNamePicker,
"Default group to be initially assigned to created units",
"et",
category:
"Entity Spawner")]
11 protected ResourceName m_sDefaultGroupPrefab;
13 [
Attribute(defvalue:
"{FFF9518F73279473}PrefabsEditable/Auto/AI/Waypoints/E_AIWaypoint_Move.et", UIWidgets.ResourceNamePicker,
"Defend waypoint prefab",
"et",
category:
"Entity Spawner")]
14 protected ResourceName m_sDefaultWaypointPrefab;
17 protected float m_fSupplyComponentSearchRadius;
20 protected float m_fMoveWaypointCompletionRadius;
22 [
Attribute(defvalue:
"10",
params:
"0 inf",
desc:
"How long should be vehicle locked after spawn",
category:
"Vehicle lock protection")]
23 protected int m_iVehicleLockedDuration;
27 ResourceName GetDefaultWaypointPrefab()
34 ResourceName GetDefaultGroupPrefab()
36 return m_sDefaultGroupPrefab;
41 float GetSupplySearchRadius()
43 return m_fSupplyComponentSearchRadius;
48 float GetMoveWaypointCompletionRadius()
50 return m_fMoveWaypointCompletionRadius;
55 int GetVehicleLockedDuration()
57 return m_iVehicleLockedDuration;
63 class SCR_CatalogEntitySpawnerComponent : SCR_SlotServiceComponent
66 static const ref array<SCR_CatalogEntitySpawnerComponent>
INSTANCES = {};
70 [
Attribute(
category:
"Catalog Parameters",
desc:
"Type of entity catalogs that will be allowed on this spawner.", uiwidget: UIWidgets.SearchComboBox, enums: ParamEnumArray.FromEnum(
EEntityCatalogType))]
88 [
Attribute(defvalue:
"1",
desc:
"If true, Spawner will require from entities that they have all allowed labels.",
category:
"Catalog Parameters")]
106 [
Attribute(
params:
"0 inf",
desc:
"Multiplier used to affect the resource usage of the refund actions after the grace period has expired.",
category:
"Supplies")]
119 static const int SLOT_CHECK_INTERVAL = 60;
155 RplId entityId = Replication.FindId(entity);
157 if (entityId.IsValid())
168 if (entityId.IsValid())
180 if (!entityId.IsValid() || !userId.IsValid())
194 bool CanRefund(notnull IEntity entity, notnull IEntity user)
196 RplId entityId = Replication.FindId(entity);
197 RplId userId = Replication.FindId(user);
199 if (!entityId.IsValid() || !userId.IsValid())
214 RplId entityId = Replication.FindId(entity);
216 if (!entityId.IsValid())
226 ClearEventMask(
GetOwner(), EntityEvent.FRAME);
228 Replication.BumpMe();
236 if (!entityId.IsValid())
246 ClearEventMask(
GetOwner(), EntityEvent.FRAME);
248 Replication.BumpMe();
258 RplId entityId = Replication.FindId(entity);
259 RplId userId = Replication.FindId(user);
261 if (!entityId.IsValid())
264 if (!userId.IsValid())
267 if (startingTime == FLT_INF)
268 startingTime =
GetGame().GetWorld().GetWorldTime() / 1000.0;
271 SetEventMask(
GetOwner(), EntityEvent.FRAME);
276 Replication.BumpMe();
286 if (startingTime == FLT_INF)
287 startingTime =
GetGame().GetWorld().GetWorldTime() / 1000.0;
290 SetEventMask(
GetOwner(), EntityEvent.FRAME);
295 Replication.BumpMe();
311 if (campaign.CanRequestVehicleWithoutRank())
314 int playerId =
GetGame().GetPlayerManager().GetPlayerIdFromControlledEntity(user);
318 IEntity playerController =
GetGame().GetPlayerManager().GetPlayerController(playerId);
319 if (!playerController)
327 return spawnerData && spawnerData.HasRequiredRank(rank);
346 catalog = faction.GetFactionEntityCatalogOfType(catalogType);
362 array<SCR_EntityCatalogEntry> newAssets = {};
363 array<typename> includedDataClasses = {};
395 array<BaseUserAction> userActions = {};
399 Print(
"There is not enough of SCR_CatalogSpawnerUserAction attached to actionManager. Some assets won't appear.", LogLevel.WARNING);
406 if (!spawnerUserAction)
412 spawnerUserAction.SetSpawnerData(
null);
426 [
Obsolete(
"SCR_CatalogEntitySpawnerComponent.AssignSupplyComponent() should be used instead.")]
429 m_SupplyComponent = supplyComp;
465 WorldTimestamp currentTime = world.GetServerTimestamp();
468 if (currentTime.DiffMilliseconds(timestamp) > (SLOT_CHECK_INTERVAL * 100))
471 occupiedSlots.Insert(slot);
483 WorldTimestamp currentTime = world.GetServerTimestamp();
484 foreach (SCR_EntitySpawnerSlotComponent slot, WorldTimestamp timestamp :
m_mKnownFreeSlots)
486 if (currentTime.DiffMilliseconds(timestamp) > (SLOT_CHECK_INTERVAL * 100))
488 else if (spawnerData.CanSpawnInSlot(slot.GetSlotType()))
502 foreach (SCR_EntitySpawnerSlotComponent slot : slots)
504 if (!spawnerData.CanSpawnInSlot(slot.GetSlotType()) || occupiedSlots.Contains(slot))
507 if (!slot.IsOccupied())
535 array<SCR_EntitySpawnerSlotComponent> occupiedSlots = {};
553 IEntity user =
GetGame().GetPlayerManager().GetPlayerControlledEntity(userId);
588 if (consumer && entitySpawnerData && (entitySpawnerData.GetSupplyCost() > consumer.GetAggregatedResourceValue()))
590 else if (!consumer && entitySpawnerData && (entitySpawnerData.GetSupplyCost() >
m_iCustomSupplies))
613 BaseGameMode gameMode =
GetGame().GetGameMode();
617 SCR_SpawnerAIGroupManagerComponent groupSpawningManager = SCR_SpawnerAIGroupManagerComponent.Cast(gameMode.FindComponent(SCR_SpawnerAIGroupManagerComponent));
618 if (!groupSpawningManager || groupSpawningManager.IsAtAILimit())
626 SCR_PlayerControllerGroupComponent groupController = SCR_PlayerControllerGroupComponent.Cast(controller.FindComponent(SCR_PlayerControllerGroupComponent));
627 if (!groupController || !groupController.IsPlayerLeaderOwnGroup())
630 if (!
CanRequestAI(user, entitySpawnerData.GetEntityCount()))
654 if (!commandingManager)
658 if (!playerController)
661 SCR_PlayerControllerGroupComponent groupController = SCR_PlayerControllerGroupComponent.Cast(playerController.FindComponent(SCR_PlayerControllerGroupComponent));
662 if (!groupController)
665 SCR_AIGroup group = groupController.GetPlayersGroup();
673 SCR_SpawnerRequestComponent reqComponent = SCR_SpawnerRequestComponent.Cast(playerController.FindComponent(SCR_SpawnerRequestComponent));
677 int queuedAICount = reqComponent.GetQueuedAIs();
679 return commandingManager.GetMaxAIPerGroup() >= (slaveGroup.GetAIMembers().Count() + queuedAICount + aiCount);
697 if (groups.param1 == group)
699 playerGroup = groups.param2;
709 if (!playerController)
712 SCR_PlayerControllerGroupComponent groupController = SCR_PlayerControllerGroupComponent.Cast(playerController.FindComponent(SCR_PlayerControllerGroupComponent));
713 if (!groupController)
716 array<AIAgent> agents = {};
717 group.GetAgents(agents);
720 SCR_ChimeraCharacter aiCharacter;
721 foreach (AIAgent agent : agents)
723 aiCharacter = SCR_ChimeraCharacter.Cast(agent.GetControlledEntity());
727 groupController.AddAIToSlaveGroup(agent.GetControlledEntity(), playerGroup);
730 SCR_SpawnerRequestComponent spawnerReqComponent = SCR_SpawnerRequestComponent.Cast(playerController.FindComponent(SCR_SpawnerRequestComponent));
731 if (spawnerReqComponent)
732 spawnerReqComponent.AddQueuedAI(-1);
750 SCR_PlayerControllerGroupComponent groupController = SCR_PlayerControllerGroupComponent.Cast(controller.FindComponent(SCR_PlayerControllerGroupComponent));
751 if (!groupController)
754 groupController.RequestAddAIAgent(ai, controller.GetPlayerId());
762 SCR_ChimeraCharacter player = SCR_ChimeraCharacter.Cast(user);
766 return player.GetFaction();
799 int playerId = playerManager.GetPlayerIdFromControlledEntity(userEntity);
811 if (!playerController)
814 return SCR_SpawnerRequestComponent.Cast(playerController.FindComponent(SCR_SpawnerRequestComponent));
819 protected void SendNotification(
int msgId, notnull IEntity user,
int assetId = -1,
int catalogType = -1)
825 reqComponent.SendPlayerFeedback(msgId, assetId, catalogType);
849 Resource resource = Resource.Load(spawnData.GetPrefab());
851 if (!resource || !resource.IsValid())
854 EntitySpawnParams
params =
new EntitySpawnParams();
855 params.TransformMode = ETransformMode.WORLD;
857 slot.GetOwner().GetTransform(
params.Transform);
859 ResourceName material;
861 material = prefabData.m_sPreviewEntityMaterial;
863 material = prefabData.m_sPreviewEntityMaterialUnavailable;
905 SCR_EntitySpawnerSlotComponent slot;
906 if (preferredSlot && spawnerData.CanSpawnInSlot(preferredSlot.GetSlotType()) && !preferredSlot.IsOccupied())
908 slot = preferredSlot;
947 array<SCR_EntityCatalogEntry> entityList = {};
948 parentCatalog.GetEntityList(entityList);
949 int assetIndex = entityList.Find(entityEntry);
952 SendNotification(0, user, entityList.Find(entityEntry), parentCatalog.GetCatalogType());
958 CarControllerComponent_SA carController = CarControllerComponent_SA.Cast(
m_SpawnedEntity.FindComponent(CarControllerComponent_SA));
960 carController.SetPersistentHandBrake(
true);
963 if (physicsComponent)
964 physicsComponent.SetVelocity(
"0 -0.1 0");
968 ActionsManagerComponent actionsManagerComponent = ActionsManagerComponent.Cast(
m_SpawnedEntity.FindComponent(ActionsManagerComponent));
970 if (!actionsManagerComponent)
974 array<BaseUserAction> outActions = {};
976 actionsManagerComponent.GetActionsList(outActions);
991 if (!requestComponent)
995 requestComponent.AddQueuedAI(spawnerData.GetEntityCount());
999 slot.MoveCharactersFromSlot();
1008 protected IEntity
SpawnEntity(ResourceName entityResourceName, notnull IEntity slotOwner)
1010 Resource entityResource = Resource.Load(entityResourceName);
1011 if (!entityResource || !entityResource.IsValid())
1013 Print(
"CatalogEntitySpawnerComponent - SpawnEntity cannot spawn new entity without valid resource. Used SCR_EntityCatalogEntry is probably set incorrectly", LogLevel.ERROR);
1017 EntitySpawnParams
params =
new EntitySpawnParams();
1018 params.TransformMode = ETransformMode.WORLD;
1019 slotOwner.GetTransform(
params.Transform);
1030 SCR_VehicleSpawnProtectionComponent protectionComp = SCR_VehicleSpawnProtectionComponent.Cast(
m_SpawnedEntity.FindComponent(SCR_VehicleSpawnProtectionComponent));
1031 if (!protectionComp)
1038 protectionComp.SetVehicleOwner(
GetGame().GetPlayerManager().GetPlayerIdFromControlledEntity(owningUser));
1039 protectionComp.SetProtectionTime(prefabData.GetVehicleLockedDuration());
1053 [
Obsolete(
"SCR_CatalogEntitySpawnerComponent.GetSpawnerResourceComponent() should be used instead.")]
1056 return m_SupplyComponent;
1072 return consumer.GetAggregatedResourceValue();
1078 [
Obsolete(
"SCR_CatalogEntitySpawnerComponent.GetSpawnerResourceValue() should be used instead.")]
1081 if (!m_SupplyComponent)
1084 return m_SupplyComponent.GetSupplies();
1094 SCR_ResourceInteractor interactor;
1103 interactor = generator;
1105 generator.RequestGeneration(supplies);
1114 interactor = consumer;
1116 consumer.RequestConsumtion(-supplies);
1124 Replication.BumpMe();
1135 int userId =
GetGame().GetPlayerManager().GetPlayerIdFromControlledEntity(user);
1140 if (!playerController)
1143 SCR_CampaignNetworkComponent networkComponent = SCR_CampaignNetworkComponent.Cast(playerController.FindComponent(SCR_CampaignNetworkComponent));
1144 if (!networkComponent)
1147 SCR_CampaignFactionManager factionManager = SCR_CampaignFactionManager.Cast(
GetGame().GetFactionManager());
1148 if (!factionManager)
1152 WorldTimestamp lastTimestamp = networkComponent.GetLastRequestTimestamp();
1153 WorldTimestamp timeout = lastTimestamp.PlusMilliseconds(factionManager.GetRankRequestCooldown(rank));
1155 return (lastTimestamp == 0 || timeout.Less(world.GetServerTimestamp()));
1166 protected void OnAIGroupSpawned(notnull
SCR_AIGroup group, notnull IEntity user, notnull IEntity slotEntity, SCR_EntityLabelPointComponent rallyPoint =
null)
1169 if (!requestComponent)
1172 BaseGameMode gameMode =
GetGame().GetGameMode();
1176 SCR_SpawnerAIGroupManagerComponent groupSpawningManager = SCR_SpawnerAIGroupManagerComponent.Cast(gameMode.FindComponent(SCR_SpawnerAIGroupManagerComponent));
1177 if (!groupSpawningManager)
1180 foreach (
int i, ResourceName resName : group.m_aUnitPrefabSlots)
1182 groupSpawningManager.QueueSpawn(
this, resName, user, slotEntity, rallyPoint);
1185 requestComponent.AddQueuedAI(group.m_aUnitPrefabSlots.Count());
1195 void SpawnAIGroupMember(ResourceName resName, notnull IEntity user, IEntity slotEntity, SCR_EntityLabelPointComponent rallyPoint =
null)
1197 SCR_ChimeraCharacter ai = SCR_ChimeraCharacter.Cast(
SpawnEntity(resName, slotEntity));
1211 if (groups.param1 != group)
1214 playerGroup = groups.param2;
1218 if (!playerController)
1221 SCR_SpawnerRequestComponent spawnerReqComponent = SCR_SpawnerRequestComponent.Cast(playerController.FindComponent(SCR_SpawnerRequestComponent));
1222 if (spawnerReqComponent)
1223 spawnerReqComponent.AddQueuedAI(-1);
1228 protected void OnChimeraCharacterSpawned(notnull SCR_ChimeraCharacter ai, notnull IEntity user, SCR_EntityLabelPointComponent rallyPoint =
null)
1230 AIControlComponent control = AIControlComponent.Cast(ai.FindComponent(AIControlComponent));
1234 control.ActivateAI();
1248 wp.SetCompletionRadius(prefabData.GetMoveWaypointCompletionRadius());
1250 AIAgent agent = control.GetAIAgent();
1257 Resource res = Resource.Load(prefabData.GetDefaultGroupPrefab());
1263 group.AddAgent(agent);
1264 group.AddWaypoint(wp);
1278 if (!playerController)
1285 m_aGroupsToAssign.Insert(
new Tuple2<SCR_AIGroup, SCR_AIGroup>(group, groupManager.GetPlayerGroup(playerController.GetPlayerId())));
1296 EntitySpawnParams wpParams =
new EntitySpawnParams();
1297 wpParams.TransformMode = ETransformMode.WORLD;
1298 rallyPoint.GetOwner().GetTransform(wpParams.Transform);
1300 Resource wpRes = Resource.Load(prefabData.GetDefaultWaypointPrefab());
1301 if (!wpRes.IsValid())
1313 SCR_ResourceComponent resourceComponent = SCR_ResourceComponent.FindResourceComponent(ent);
1315 if (resourceComponent)
1336 float worldTime =
GetGame().GetWorld().GetWorldTime() / 1000.0;
1340 vector entityMat[4];
1346 entity = IEntity.Cast(Replication.FindItem(
id));
1352 idx = Math.Max(0, idx - 1);
1353 count = Math.Max(0, count - 1);
1358 entity.GetBounds(entityMins, entityMaxs);
1359 entity.GetWorldTransform(entityMat);
1365 idx = Math.Max(0, idx - 1);
1366 count = Math.Max(0, count - 1);
1376 super.EOnInit(owner);
1381 Print(
"SCR_CatalogEntitySpawnerComponent requires RplComponent for its functionality!", LogLevel.WARNING);
1385 m_ActionManager = ActionsManagerComponent.Cast(owner.FindComponent(ActionsManagerComponent));
1387 Print(
"No Action Manager detected on owner of Spawner Component!", LogLevel.WARNING);
1398 SCR_CatalogEntitySpawnerComponent.INSTANCES.Insert(
this);
1404 super.OnDelete(owner);
1406 SCR_CatalogEntitySpawnerComponent.INSTANCES.RemoveItem(
this);
1415 super.OnPostInit(owner);
1417 SetEventMask(owner, EntityEvent.INIT);