5 float suppliesCost = 0.0;
16 static override array<typename> Requires(IEntityComponentSource src)
18 array<typename> requires = {};
20 requires.Insert(SerializerInventoryStorageManagerComponent);
28 protected static SCR_ArsenalManagerComponent
s_Instance;
30 protected static const ref array<string> ARSENALLOADOUT_COMPONENTS_TO_CHECK = {
31 "SCR_CharacterInventoryStorageComponent",
32 "SCR_UniversalInventoryStorageComponent",
33 "EquipedWeaponStorageComponent",
34 "ClothNodeStorageComponent"
37 [
Attribute(
"{27F28CF7C6698FF8}Configs/Arsenal/ArsenalSaveTypeInfoHolder.conf",
desc:
"Holds a list of save types than can be used for arsenals. Any new arsenal save type should be added to the config to allow it to be set by Editor",
params:
"conf class=SCR_ArsenalSaveTypeInfoHolder")]
40 [
Attribute(
"{183361B6DA2C304F}Configs/Arsenal/ArsenalLoadoutSaveBlacklists.conf",
desc:
"This is server only, A blacklist of entities that are not allowed to be saved at arsenals if the blacklist the item is in is enabled. Can be null.",
params:
"conf class=SCR_LoadoutSaveBlackListHolder")]
44 protected bool m_bDisable
47 protected ref map<string, ref SCR_ArsenalPlayerLoadout>
m_aPlayerLoadouts =
new map<string, ref SCR_ArsenalPlayerLoadout>();
50 protected ref ScriptInvokerBase<SCR_ArsenalManagerComponent_OnPlayerLoadoutChanged>
m_OnPlayerLoadoutUpdated =
new ScriptInvokerBase<SCR_ArsenalManagerComponent_OnPlayerLoadoutChanged>();
58 [
Attribute(
"0",
desc:
"Cost multiplier for supplies on spawning. 0 means the cost is free. Only used in gamemodes that support supply cost on spawning",
params:
"-1 inf")]
64 static bool GetArsenalManager(out SCR_ArsenalManagerComponent arsenalManager)
87 string playerUID =
GetGame().GetBackendApi().GetPlayerIdentityId(playerId);
113 if (editorPlayerIdClearedLoadout > 0)
114 SCR_NotificationsComponent.SendToEveryone(
ENotification.EDITOR_CHANGED_LOADOUT_SAVE_BLACKLIST, editorPlayerIdClearedLoadout);
119 if (clearExistingLoadouts)
131 [
RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
144 if (playerIdClearedLoadout > 0)
145 SCR_NotificationsComponent.SendLocal(
ENotification.PLAYER_LOADOUT_CLEARED_BY_EDITOR);
147 SCR_NotificationsComponent.SendLocal(
ENotification.PLAYER_LOADOUT_CLEARED);
171 return m_aPlayerLoadouts.Find(playerUID, playerLoadout) && playerLoadout.loadout !=
string.Empty;
234 float multiplier = 1;
235 SCR_ArsenalManagerComponent arsenalManager;
236 if (!GetArsenalManager(arsenalManager))
239 multiplier = arsenalManager.GetLoadoutSpawnSupplyCostMultiplier();
246 if (resourceComponent && !resourceComponent.IsResourceTypeEnabled())
251 float baseMultiplier = 0;
256 if (!base.CostSuppliesToSpawn())
259 baseMultiplier = base.GetBaseSpawnCostFactor();
264 if (playerArsenalLoadout)
269 if (getLocalPlayer && arsenalManager.m_bLocalPlayerLoadoutData)
271 if (baseMultiplier > 0)
272 return Math.Clamp(arsenalManager.m_bLocalPlayerLoadoutData.LoadoutCost * baseMultiplier, 0,
float.MAX);
274 return Math.Clamp(arsenalManager.m_bLocalPlayerLoadoutData.LoadoutCost, 0,
float.MAX);
277 else if ((gameMode && gameMode.IsMaster()) || (!gameMode && Replication.IsServer()))
279 if (baseMultiplier > 0)
280 return Math.Clamp(playerArsenalLoadout.GetLoadoutSuppliesCost(playerID) * baseMultiplier, 0,
float.MAX);
282 return Math.Clamp(playerArsenalLoadout.GetLoadoutSuppliesCost(playerID), 0,
float.MAX);
287 return Math.Clamp(base.GetBaseSpawnCost(), 0,
float.MAX);
294 SCR_EntityCatalogManagerComponent entityCatalogManager = SCR_EntityCatalogManagerComponent.GetInstance();
295 if (!entityCatalogManager)
298 ResourceName loadoutResource = playerLoadout.GetLoadoutResource();
299 if (!loadoutResource)
302 Resource resource = Resource.Load(loadoutResource);
309 Print(
"Loadout: '" + resource.GetResource().GetResourceName() +
"' is not in catalog so supply cost is 0!", LogLevel.WARNING);
318 supplyCost =
data.GetLoadoutSpawnCost();
323 Print(
"Loadout: '" + resource.GetResource().GetResourceName() +
"' has no 'SCR_EntityCatalogLoadoutData' assigned in catalog so supply cost is taken from Campaign budget on prefab!", LogLevel.WARNING);
329 array<ref SCR_EntityBudgetValue> budgets = {};
331 if (!editableUIInfo.GetEntityBudgetCost(budgets))
339 supplyCost = budget.GetBudgetValue();
350 if (baseMultiplier > 0)
351 return Math.Clamp((supplyCost * multiplier) * baseMultiplier, 0,
float.MAX);
353 return Math.Clamp(supplyCost * multiplier, 0,
float.MAX);
361 protected bool CanSaveLoadout(
int playerId, notnull GameEntity characterEntity, FactionAffiliationComponent playerFactionAffiliation,
SCR_ArsenalComponent arsenalComponent,
bool sendNotificationOnFailed)
367 SCR_InventoryStorageManagerComponent characterInventory = SCR_InventoryStorageManagerComponent.Cast(characterEntity.FindComponent(SCR_InventoryStorageManagerComponent));
368 if (!characterInventory)
370 Print(
"'SCR_ArsenalManagerComponent' is checking 'CanSaveArsenal()' but character has no inventory manager!", LogLevel.ERROR);
372 if (sendNotificationOnFailed)
373 SCR_NotificationsComponent.SendToPlayer(playerId,
ENotification.PLAYER_LOADOUT_NOT_SAVED);
379 SCR_ArsenalInventoryStorageManagerComponent arsenalInventory;
382 if (arsenalComponent.GetArsenalSaveType() == SCR_EArsenalSaveType.FACTION_ITEMS_ONLY || arsenalComponent.GetArsenalSaveType() == SCR_EArsenalSaveType.IN_ARSENAL_ITEMS_ONLY)
384 if (arsenalComponent.GetArsenalSaveType() == SCR_EArsenalSaveType.FACTION_ITEMS_ONLY)
387 if (!playerFactionAffiliation)
389 Print(
"'SCR_ArsenalManagerComponent' is checking 'CanSaveArsenal()' but player has no faction affiliation component, arsenal saving will simply be allowed", LogLevel.WARNING);
397 Print(
"'SCR_ArsenalManagerComponent' is checking 'CanSaveArsenal()' but player has no SCR_Faction, arsenal saving will simply be allowed", LogLevel.WARNING);
404 Print(
string.Format(
"'SCR_ArsenalManagerComponent' is checking 'CanSaveArsenal()' but player faction '%1' has no ITEM catalog!", playerFaction.GetFactionKey()), LogLevel.ERROR);
406 if (sendNotificationOnFailed)
407 SCR_NotificationsComponent.SendToPlayer(playerId,
ENotification.PLAYER_LOADOUT_NOT_SAVED);
414 arsenalInventory = SCR_ArsenalInventoryStorageManagerComponent.Cast(arsenalComponent.GetArsenalInventoryComponent());
415 if (!arsenalInventory)
417 Print(
"'SCR_ArsenalManagerComponent' is checking 'CanSaveArsenal()' and arsenal check type is 'IN_ARSENAL_ITEMS_ONLY' but arsenal has no SCR_ArsenalInventoryStorageManagerComponent, so saving is simply allowed", LogLevel.WARNING);
423 set<string> checkedEntities =
new set<string>();
424 array<IEntity> allPlayerItems = {};
425 characterInventory.GetAllRootItems(allPlayerItems);
427 EntityPrefabData prefabData;
428 RplComponent itemRplComponent;
431 int invalidItemCount = 0;
433 foreach (IEntity item : allPlayerItems)
435 prefabData = item.GetPrefabData();
442 resourceName = prefabData.GetPrefabName();
443 if (resourceName.IsEmpty())
447 if (checkedEntities.Contains(resourceName))
450 checkedEntities.Insert(resourceName);
458 if (sendNotificationOnFailed)
460 itemRplComponent = RplComponent.Cast(item.FindComponent(RplComponent));
461 if (itemRplComponent)
462 SCR_NotificationsComponent.SendToPlayer(playerId,
ENotification.PLAYER_LOADOUT_ITEM_FAILED_ITEM_BLACKLISTED, itemRplComponent.Id());
471 if (arsenalInventory)
474 if (!arsenalInventory.IsPrefabInArsenalStorage(resourceName))
476 if (sendNotificationOnFailed)
478 itemRplComponent = RplComponent.Cast(item.FindComponent(RplComponent));
479 if (itemRplComponent)
480 SCR_NotificationsComponent.SendToPlayer(playerId,
ENotification.PLAYER_LOADOUT_ITEM_FAILED_NOT_IN_ARSENAL, itemRplComponent.Id());
488 else if (itemCatalog)
491 if (!itemCatalog.GetEntryWithPrefab(resourceName))
493 if (sendNotificationOnFailed)
495 itemRplComponent = RplComponent.Cast(item.FindComponent(RplComponent));
496 if (itemRplComponent)
497 SCR_NotificationsComponent.SendToPlayer(playerId,
ENotification.PLAYER_LOADOUT_ITEM_FAILED_NOT_FACTION, itemRplComponent.Id());
507 if (invalidItemCount > 0 && sendNotificationOnFailed)
508 SCR_NotificationsComponent.SendToPlayer(playerId,
ENotification.PLAYER_LOADOUT_NOT_SAVED_INVALID_ITEMS, invalidItemCount);
510 return invalidItemCount == 0;
525 string playerUID =
GetGame().GetBackendApi().GetPlayerIdentityId(playerId);
526 if (!characterEntity)
533 if (!clientPlayerController || clientPlayerController.IsPossessing())
537 FactionAffiliationComponent factionAffiliation = FactionAffiliationComponent.Cast(characterEntity.FindComponent(FactionAffiliationComponent));
538 if (factionAffiliation)
539 factionKey = factionAffiliation.GetAffiliatedFaction().GetFactionKey();
541 if (!
CanSaveLoadout(playerId, characterEntity, factionAffiliation, arsenalComponent,
true))
544 SCR_JsonSaveContext context =
new SCR_JsonSaveContext();
548 DoSetPlayerLoadout(playerId, context.ExportToString(), characterEntity, arsenalSupplyType);
556 EquipedLoadoutStorageComponent loadoutStorage = EquipedLoadoutStorageComponent.Cast(characterEntity.FindComponent(EquipedLoadoutStorageComponent));
559 int slotsCount = loadoutStorage.GetSlotsCount();
560 for (
int i = 0; i < slotsCount; ++i)
566 IEntity attachedEntity = slot.GetAttachedEntity();
570 ResourceName prefabName;
571 BaseContainer prefab = attachedEntity.GetPrefabData().GetPrefab();
572 while (prefabName.IsEmpty() && prefab)
574 prefabName = prefab.GetResourceName();
575 prefab = prefab.GetAncestor();
578 if (prefabName.IsEmpty())
581 SCR_ClothingLoadoutData clothingData();
582 clothingData.SlotIdx = i;
583 clothingData.ClothingPrefab = prefabName;
589 EquipedWeaponStorageComponent weaponStorage = EquipedWeaponStorageComponent.Cast(characterEntity.FindComponent(EquipedWeaponStorageComponent));
592 int slotsCount = weaponStorage.GetSlotsCount();
593 for (
int i = 0; i < slotsCount; ++i)
599 IEntity attachedEntity = slot.GetAttachedEntity();
603 ResourceName prefabName;
604 BaseContainer prefab = attachedEntity.GetPrefabData().GetPrefab();
605 while (prefabName.IsEmpty() && prefab)
607 prefabName = prefab.GetResourceName();
608 prefab = prefab.GetAncestor();
611 if (prefabName.IsEmpty())
615 weaponData.SlotIdx = i;
616 weaponData.WeaponPrefab = prefabName;
628 playerLoadout.suppliesCost = 0.0;
630 SCR_JsonLoadContext context =
new SCR_JsonLoadContext(
false);
631 if (!context.ImportFromString(playerLoadout.loadout))
640 if (!context.StartObject(storageName))
643 if (!context.StartObject(
"Native"))
649 if (!context.StartObject(
"slots"))
657 if (!context.ReadValue(
"itemsCount", itemsCount))
660 for (
int i = 0; i < itemsCount; ++i)
663 if (!context.ReadValue(
"slot-" + i +
"-valid", valid))
669 if (!context.StartObject(
"slot-" + i))
674 if (!context.EndObject())
678 if (!context.EndObject())
681 if (!context.EndObject())
684 if (!context.EndObject())
691 if (!context.StartObject(
"entity"))
695 if (!context.ReadValue(
"prefabGUID", prefab))
698 SCR_EntityCatalogManagerComponent entityCatalogManager = SCR_EntityCatalogManagerComponent.GetInstance();
704 playerLoadout.suppliesCost +=
data.GetSupplyCost(arsenalSupplyType);
707 ComputeEntity(context, faction, playerLoadout,
"entity", arsenalSupplyType);
709 if (!context.EndObject())
716 if (!context.StartObject(entityName))
719 if (!context.StartObject(
"Native"))
722 if (!context.StartObject(
"components"))
725 foreach (
string componentName: ARSENALLOADOUT_COMPONENTS_TO_CHECK)
727 ComputeStorage(context, faction, playerLoadout, componentName, arsenalSupplyType);
730 if (!context.EndObject())
733 if (!context.EndObject())
736 if (!context.EndObject())
741 protected void DoSetPlayerLoadout(
int playerId,
string loadoutString, GameEntity characterEntity, SCR_EArsenalSupplyCostType arsenalSupplyType)
743 bool loadoutValid = !loadoutString.IsEmpty();
745 string playerUID =
GetGame().GetBackendApi().GetPlayerIdentityId(playerId);
750 bool loadoutChanged = loadoutValid && loadoutString != playerLoadout.loadout;
752 playerLoadout.loadout = loadoutString;
758 FactionAffiliationComponent factionAffiliation = FactionAffiliationComponent.Cast(characterEntity.FindComponent(FactionAffiliationComponent));
759 if (factionAffiliation && factionAffiliation.GetAffiliatedFaction())
763 if (loadoutValid && loadoutChanged)
778 super.OnPlayerAuditSuccess(playerId);
780 string playerUID =
GetGame().GetBackendApi().GetPlayerIdentityId(playerId);
785 bool loadoutValid = !playerLoadout.loadout.IsEmpty();
797 [
RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
811 SCR_NotificationsComponent.SendLocal(
ENotification.PLAYER_LOADOUT_SAVED);
815 SCR_NotificationsComponent.SendLocal(
ENotification.PLAYER_LOADOUT_NOT_SAVED_UNCHANGED);
825 [
RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
833 [
RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
863 s_Instance = SCR_ArsenalManagerComponent.Cast(
GetGameMode().FindComponent(SCR_ArsenalManagerComponent));
864 SetEventMask(owner, EntityEvent.INIT);
869 Print(
"'SCR_ArsenalManagerComponent' failed to load Arsenal Save Type Holder config!", LogLevel.ERROR);