Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_PlayerArsenalLoadout.c
Go to the documentation of this file.
1[BaseContainerProps(configRoot: true), BaseContainerCustomTitleField("m_sLoadoutName")]
3{
4 static const string ARSENALLOADOUT_FACTIONKEY_NONE = "none";
5 static const string ARSENALLOADOUT_KEY = "arsenalLoadout";
6 static const string ARSENALLOADOUT_FACTION_KEY = "faction";
7 static ref array<typename> ARSENALLOADOUT_COMPONENTS_TO_CHECK;
8
9 //------------------------------------------------------------------------------------------------
10 override bool IsLoadoutAvailable(int playerId)
11 {
12 SCR_ArsenalManagerComponent arsenalManager;
13 if (SCR_ArsenalManagerComponent.GetArsenalManager(arsenalManager))
14 {
15 SCR_ArsenalPlayerLoadout arsenalLoadout;
16 return arsenalManager.GetPlayerArsenalLoadout(SCR_PlayerIdentityUtils.GetPlayerIdentityId(playerId), arsenalLoadout);
17 }
18 return false;
19 }
20
21 //------------------------------------------------------------------------------------------------
22 override bool IsLoadoutAvailableClient()
23 {
24 SCR_ArsenalManagerComponent arsenalManager;
25 if (SCR_ArsenalManagerComponent.GetArsenalManager(arsenalManager))
26 return arsenalManager.GetLocalPlayerLoadoutAvailable();
27
28 return false;
29 }
30
31 //------------------------------------------------------------------------------------------------
34 static float GetLoadoutSuppliesCost(string playerUID)
35 {
36 SCR_ArsenalManagerComponent arsenalManager;
37 if (SCR_ArsenalManagerComponent.GetArsenalManager(arsenalManager))
38 {
39 float supplyCostMulti = arsenalManager.GetCalculatedLoadoutSpawnSupplyCostMultiplier();
40
41 //~ No need to get supply cost if multiplier is 0
42 if (supplyCostMulti <= 0)
43 return 0;
44
45 SCR_ArsenalPlayerLoadout arsenalLoadout;
46 if (arsenalManager.GetPlayerArsenalLoadout(playerUID, arsenalLoadout))
47 return arsenalLoadout.suppliesCost * supplyCostMulti;
48 }
49
50 return 0;
51 }
52
53 //------------------------------------------------------------------------------------------------
56 static float GetLoadoutSuppliesCost(int playerID)
57 {
58 const UUID playerUID = SCR_PlayerIdentityUtils.GetPlayerIdentityId(playerID);
59 return GetLoadoutSuppliesCost(playerUID);
60 }
61
62 //------------------------------------------------------------------------------------------------
65 static float GetLoadoutMilitarySupplyAllocationCost(string playerUID)
66 {
67 SCR_ArsenalManagerComponent arsenalManager;
68 if (SCR_ArsenalManagerComponent.GetArsenalManager(arsenalManager))
69 {
70 SCR_ArsenalPlayerLoadout arsenalLoadout;
71 if (arsenalManager.GetPlayerArsenalLoadout(playerUID, arsenalLoadout))
72 return arsenalLoadout.m_fMilitarySupplyAllocationCost;
73 }
74
75 return 0;
76 }
77
78 //------------------------------------------------------------------------------------------------
81 SCR_ECharacterRank GetRequiredRank(int playerId)
82 {
83 SCR_ArsenalManagerComponent arsenalManager;
84 if (!SCR_ArsenalManagerComponent.GetArsenalManager(arsenalManager))
85 return SCR_ECharacterRank.PRIVATE;
86
87 const UUID playerUID = SCR_PlayerIdentityUtils.GetPlayerIdentityId(playerId);
88 SCR_ArsenalPlayerLoadout arsenalLoadout;
89 if (!arsenalManager.GetPlayerArsenalLoadout(playerUID, arsenalLoadout))
90 return SCR_ECharacterRank.PRIVATE;
91
92 return arsenalLoadout.m_eRequiredRank;
93 }
94
95 //------------------------------------------------------------------------------------------------
96 override void OnLoadoutSpawned(GenericEntity pOwner, int playerId)
97 {
98 super.OnLoadoutSpawned(pOwner, playerId);
99 SCR_ArsenalManagerComponent arsenalManager;
100 if (!SCR_ArsenalManagerComponent.GetArsenalManager(arsenalManager))
101 return;
102
103 const UUID playerUID = SCR_PlayerIdentityUtils.GetPlayerIdentityId(playerId);
104 GameEntity playerEntity = GameEntity.Cast(pOwner);
105 SCR_ArsenalPlayerLoadout playerArsenalItems;
106 if (!playerEntity || !arsenalManager.GetPlayerArsenalLoadout(playerUID, playerArsenalItems))
107 return;
108
109 FactionAffiliationComponent factionComponent = FactionAffiliationComponent.Cast(playerEntity.FindComponent(FactionAffiliationComponent));
110 if (!factionComponent)
111 return;
112
113 auto context = new JsonLoadContext();
114 bool loadSuccess = true;
115 loadSuccess &= context.LoadFromString(playerArsenalItems.loadout);
116 // Read faction key and ensure same faction, otherwise delete saved arsenal loadout
117 string factionKey;
118 loadSuccess &= context.ReadValue(ARSENALLOADOUT_FACTION_KEY, factionKey) && factionKey != ARSENALLOADOUT_FACTIONKEY_NONE;
119 loadSuccess &= factionKey == factionComponent.GetAffiliatedFaction().GetFactionKey();
120 loadSuccess &= ApplyLoadoutString(playerEntity, context);
121
122 // Deserialisation failed, delete saved arsenal loadout
123 if (!loadSuccess)
124 arsenalManager.SetPlayerArsenalLoadout(playerId, null, null, SCR_EArsenalSupplyCostType.RESPAWN_COST);
125 }
126
127 //------------------------------------------------------------------------------------------------
128 static bool ReadLoadoutString(IEntity owner, SaveContext context)
129 {
130 if (!context.StartObject(ARSENALLOADOUT_KEY))
131 return false;
132
133 if (!ReadEntityLoadoutString(owner, context))
134 return false;
135
136 if (!ReadCharacterDataLoadoutString(owner, context))
137 return false;
138
139 return context.EndObject();
140 }
141
142 //------------------------------------------------------------------------------------------------
143 protected static bool ReadEntityLoadoutString(IEntity owner, SaveContext context)
144 {
145 context.WriteValue("prefab", SCR_ResourceNameUtils.GetPrefabName(owner));
146
147 if (!ReadEntityCustomDataString(owner, context))
148 return false;
149
150 return ReadEntityStorageString(owner, context);
151 }
152
153 //------------------------------------------------------------------------------------------------
155 protected static bool ReadEntityCustomDataString(IEntity owner, SaveContext context)
156 {
157 return true;
158 }
159
160 //------------------------------------------------------------------------------------------------
161 static void FindStorageComponents(IEntity owner, notnull set<BaseInventoryStorageComponent> storages)
162 {
163 array<Managed> outComponents = {};
164 owner.FindComponents(BaseInventoryStorageComponent, outComponents);
165 foreach (Managed component : outComponents)
166 {
167 BaseInventoryStorageComponent storage = BaseInventoryStorageComponent.Cast(component);
168 storages.Insert(storage);
169 FindStorageComponents(storage, storages);
170 }
171 }
172
173 //------------------------------------------------------------------------------------------------
174 static void FindStorageComponents(GenericComponent parentComponent, notnull set<BaseInventoryStorageComponent> storages)
175 {
176 array<GenericComponent> outComponents = {};
177 parentComponent.FindComponents(BaseInventoryStorageComponent, outComponents);
178 foreach (GenericComponent component : outComponents)
179 {
180 BaseInventoryStorageComponent storage = BaseInventoryStorageComponent.Cast(component);
181 storages.Insert(storage);
182 FindStorageComponents(storage, storages);
183 }
184 }
185
186 //------------------------------------------------------------------------------------------------
187 protected static bool ShouldSaveStorage(BaseInventoryStorageComponent candidate)
188 {
189 foreach (typename toCheck : ARSENALLOADOUT_COMPONENTS_TO_CHECK)
190 {
191 if (candidate.Type() == toCheck)
192 return true;
193 }
194
195 return false;
196 }
197
198 //------------------------------------------------------------------------------------------------
199 protected static bool ReadEntityStorageString(IEntity owner, SaveContext context)
200 {
201 set<BaseInventoryStorageComponent> storageCandiates();
202 FindStorageComponents(owner, storageCandiates);
203
204 array<BaseInventoryStorageComponent> storages = {};
205 foreach (BaseInventoryStorageComponent candidate : storageCandiates)
206 {
207 if (ShouldSaveStorage(candidate))
208 storages.Insert(candidate);
209 }
210
211 int storageCount = storages.Count();
212 if (storageCount == 0)
213 return true;
214
215 context.StartArray("storages", storageCount);
216 foreach (BaseInventoryStorageComponent storage : storages)
217 {
218 context.StartObject();
219 context.WriteValue("id", GetComponentIdentifier(owner, storage));
220 const array<InventoryItemComponent> slotItems = GetSlotItems(storage);
221 int slotCount = slotItems.Count();
222 context.StartMap("slots", slotCount);
223 foreach (InventoryItemComponent item : slotItems)
224 {
225 context.WriteMapKey(item.GetParentSlot().GetID().ToString());
226 context.StartObject();
227
228 if (!ReadEntityLoadoutString(item.GetOwner(), context))
229 return false;
230
231 context.EndObject();
232 }
233 context.EndMap();
234 context.EndObject();
235 }
236 return context.EndArray();
237 }
238
239 //------------------------------------------------------------------------------------------------
242 protected static array<InventoryItemComponent> GetSlotItems(const BaseInventoryStorageComponent storage)
243 {
244 array<InventoryItemComponent> outItemsComponents = {};
245 storage.GetOwnedItems(outItemsComponents, false);
246
247 // For weapon attachments we need to load back slots without requirements first and those who rely on them later, regardless of slot index they are in
248 // Example: Bayonet needs muzzle flash hider.
249 const SCR_WeaponAttachmentsStorageComponent weaponAttachments = SCR_WeaponAttachmentsStorageComponent.Cast(storage);
250 if (weaponAttachments)
251 {
252 array<ref SCR_SortableItem<InventoryItemComponent>> sortSlots = {};
253 foreach (InventoryItemComponent item : outItemsComponents)
254 {
255 int numRequirements = 0;
257 if (obstructionAttributes)
258 numRequirements = obstructionAttributes.GetRequiredAttachmentTypes().Count();
259
260 SCR_SortableItem<InventoryItemComponent> sortable(item, numRequirements);
261 sortSlots.Insert(sortable);
262 }
263 sortSlots.Sort();
264 outItemsComponents.Clear();
265 foreach (SCR_SortableItem<InventoryItemComponent> sortedSlot : sortSlots)
266 {
267 outItemsComponents.Insert(sortedSlot.m_Item);
268 }
269 }
270
271 return outItemsComponents;
272 }
273
274 //------------------------------------------------------------------------------------------------
277 protected static bool ReadCharacterDataLoadoutString(IEntity owner, SaveContext context)
278 {
279 // By default just the chars active weapon is stored as additional meta data
280 int activeWeaponIdx = -1;
281 const BaseWeaponManagerComponent weaponManager = BaseWeaponManagerComponent.Cast(owner.FindComponent(BaseWeaponManagerComponent));
282 if (weaponManager)
283 {
284 const WeaponSlotComponent currentSlot = weaponManager.GetCurrentSlot();
285 if (currentSlot)
286 activeWeaponIdx = currentSlot.GetWeaponSlotIndex();
287 }
288 return context.WriteDefault(activeWeaponIdx, -1);
289 }
290
291 //------------------------------------------------------------------------------------------------
292 protected static string GetComponentIdentifier(IEntity owner, GenericComponent component)
293 {
294 const BaseContainer source = component.GetComponentSource(owner);
295 const string storeName = source.GetResourceName();
296 return component.ClassName() + ":" + SCR_ResourceNameUtils.GetPrefabGUID(storeName);
297 }
298
299 //------------------------------------------------------------------------------------------------
300 static bool ApplyLoadoutString(IEntity owner, LoadContext context)
301 {
302 if (!context.StartObject(ARSENALLOADOUT_KEY))
303 return false;
304
306 if (!manager || !ApplyEntityLoadoutString(owner, context, manager))
307 return false;
308
309 if (!ApplyCharacterDataLoadoutString(owner, context))
310 return false;
311
312 return context.EndObject();
313 }
314
315 //------------------------------------------------------------------------------------------------
316 protected static bool ApplyEntityLoadoutString(
317 IEntity owner,
318 LoadContext context,
320 BaseInventoryStorageComponent parentStorage = null,
321 int slotId = -1)
322 {
323 if (parentStorage && slotId != -1)
324 {
325 ResourceName prefab;
326 if (!context.Read(prefab))
327 return false;
328
329 const ResourceName currentPrefab = SCR_ResourceNameUtils.GetPrefabName(owner);
330 if (prefab != currentPrefab)
331 {
332 if (owner && !manager.TryDeleteItem(owner))
333 return false;
334
335 if (!manager.TrySpawnPrefabToStorage(prefab, parentStorage, slotId))
336 return false;
337
338 owner = parentStorage.Get(slotId);
339 if (!owner)
340 return false;
341 }
342 }
343
344 if (!ApplyEntityCustomDataString(owner, context))
345 return false;
346
347 return ApplyEntityStorageString(owner, context, manager, parentStorage, slotId);
348 }
349
350 //------------------------------------------------------------------------------------------------
351 // Read back any custom data per entity that was written by ReadEntityCustomDataString
352 protected static bool ApplyEntityCustomDataString(IEntity owner, LoadContext context)
353 {
354 return true;
355 }
356
357 //------------------------------------------------------------------------------------------------
358 protected static bool ApplyEntityStorageString(
359 IEntity owner,
360 LoadContext context,
362 BaseInventoryStorageComponent parentStorage = null,
363 int slotId = -1)
364 {
365 int storageCount;
366 context.StartArray("storages", storageCount);
367 if (storageCount == 0)
368 return true; // No substorages so we are done here
369
370 set<BaseInventoryStorageComponent> storageCandiates();
371 FindStorageComponents(owner, storageCandiates);
372
373 for (int nStorage = 0; nStorage < storageCount; ++nStorage)
374 {
375 if (!context.StartObject())
376 return false;
377
378 string id;
379 if (!context.Read(id))
380 return false;
381
382 // Find the right storage by it's id
383 BaseInventoryStorageComponent storage;
384 foreach (BaseInventoryStorageComponent candidate : storageCandiates)
385 {
386 const string componentId = GetComponentIdentifier(owner, candidate);
387 if (componentId == id)
388 {
389 storage = candidate;
390 break;
391 }
392 }
393 if (!storage)
394 return false;
395
396 // Quick access to all currently stored items to apply data and remove those who are not part of loadodut at the end
397 map<int, IEntity> slottetItems = new map<int, IEntity>();
398 array<InventoryItemComponent> outItemsComponents = {};
399 storage.GetOwnedItems(outItemsComponents, false);
400 foreach (InventoryItemComponent item : outItemsComponents)
401 {
402 slottetItems.Insert(item.GetParentSlot().GetID(), item.GetOwner());
403 }
404
405 int slotCount = 0;
406 if (!context.StartMap("slots", slotCount))
407 return false;
408
409 for (int i = 0; i < slotCount; ++i)
410 {
411 // Read back the order they were written in.
412 // NOTE: This may not be in numerical ascending order but logic for e.g. attachment dependency
413 string idxStr;
414 if (!context.ReadMapKey(i, idxStr))
415 return false;
416
417 const int childSlotId = idxStr.ToInt(-1);
418 if (childSlotId == -1)
419 return false;
420
421 IEntity existing;
422 slottetItems.Take(childSlotId, existing);
423
424 if (!context.StartObject(idxStr))
425 return false;
426
427 if (!ApplyEntityLoadoutString(existing, context, manager, storage, childSlotId))
428 return false;
429
430 if (!context.EndObject())
431 return false;
432 }
433 if (!context.EndMap())
434 return false;
435
436 // Remove any existing entity whos slot was not mentioned in the loadout data.
437 foreach (int idx, IEntity entity : slottetItems)
438 {
439 if (entity && !manager.TryDeleteItem(entity))
440 return false;
441 }
442
443 if (!context.EndObject())
444 return false;
445 }
446
447 return context.EndArray();
448 }
449
450 //------------------------------------------------------------------------------------------------
451 protected static bool ApplyCharacterDataLoadoutString(IEntity owner, LoadContext context)
452 {
453 int activeWeaponIdx;
454 context.ReadDefault(activeWeaponIdx, -1);
455 const BaseWeaponManagerComponent weaponManager = BaseWeaponManagerComponent.Cast(owner.FindComponent(BaseWeaponManagerComponent));
456 const CharacterControllerComponent charController = CharacterControllerComponent.Cast(owner.FindComponent(CharacterControllerComponent));
457 if (!weaponManager || !charController) // If neither is present we have some special char who apparently does not need the data
458 return true;
459
460 if (activeWeaponIdx != -1)
461 {
462 array<WeaponSlotComponent> outSlots = {};
463 if (weaponManager.GetWeaponsSlots(outSlots))
464 {
465 WeaponSlotComponent desiredSlot, fallbackSlot;
466 foreach (WeaponSlotComponent slot : outSlots)
467 {
468 const int slotIdx = slot.GetWeaponSlotIndex();
469 if (slotIdx == activeWeaponIdx)
470 {
471 desiredSlot = slot;
472 break;
473 }
474
475 if (!fallbackSlot && slotIdx < 3 && slot.GetWeaponEntity())
476 fallbackSlot = slot;
477 }
478
479 IEntity weaponEntity;
480 if (desiredSlot)
481 {
482 weaponEntity = desiredSlot.GetWeaponEntity();
483 }
484 else if (fallbackSlot)
485 {
486 weaponEntity = fallbackSlot.GetWeaponEntity();
487 }
488
489 charController.TryEquipRightHandItem(weaponEntity, EEquipItemType.EEquipTypeWeapon, true);
490 }
491 }
492 else
493 {
494 charController.TryEquipRightHandItem(null, EEquipItemType.EEquipTypeUnarmedDeliberate, true);
495 }
496
497 return true;
498 }
499
500 //------------------------------------------------------------------------------------------------
502 LoadContext context,
503 SCR_Faction faction,
504 SCR_ArsenalPlayerLoadout playerLoadout,
505 SCR_EArsenalSupplyCostType arsenalSupplyType,
506 int depth = 0)
507 {
508 ResourceName prefab;
509 if (!context.Read(prefab))
510 return;
511
512 if (depth > 0)
513 {
514 SCR_EntityCatalogManagerComponent entityCatalogManager = SCR_EntityCatalogManagerComponent.GetInstance();
515 if (entityCatalogManager)
516 {
517 SCR_EntityCatalogEntry entry = entityCatalogManager.GetEntryWithPrefabFromGeneralOrFactionCatalog(EEntityCatalogType.ITEM, prefab, faction);
518 if (entry)
519 {
521 if (data)
522 {
523 const float cost = data.GetSupplyCost(arsenalSupplyType);
524 playerLoadout.suppliesCost += cost;
525 playerLoadout.m_eRequiredRank = Math.Max(playerLoadout.m_eRequiredRank, data.GetRequiredRank());
526 if (data.GetUseMilitarySupplyAllocation())
527 playerLoadout.m_fMilitarySupplyAllocationCost += cost;
528 }
529 }
530 }
531 }
532
533 int storageCount;
534 context.StartArray("storages", storageCount);
535 if (storageCount == 0)
536 return; // No substorages so we are done here
537
538 for (int nStorage = 0; nStorage < storageCount; ++nStorage)
539 {
540 if (!context.StartObject())
541 return;
542
543 string id;
544 if (!context.Read(id))
545 return;
546
547 int slotCount = 0;
548 context.StartMap("slots", slotCount);
549 for (int i = 0; i < slotCount; ++i)
550 {
551 string idxStr;
552 if (!context.ReadMapKey(i, idxStr))
553 return;
554
555 const int childSlotId = idxStr.ToInt(-1);
556 if (childSlotId == -1)
557 return;
558
559 context.StartObject(idxStr);
560 ComputeSuppliesCost(context, faction, playerLoadout, arsenalSupplyType, depth + 1);
561 context.EndObject();
562 }
563 context.EndMap();
564 context.EndObject();
565 }
566 context.EndArray();
567 }
568}
AddonBuildInfoTool id
EEntityCatalogType
SCR_AIAnimation_Loitering BaseContainerProps
Commanding menu commanding element class.
SCR_ECharacterRank GetRequiredRank()
Get all prefabs that have the spawner data
class SCR_KeyBindingFilter BaseContainerCustomTitleField("m_sBindString")
proto external int FindComponents(typename typeName, notnull array< GenericComponent > outComponents)
proto external Managed FindComponent(typename typeName)
proto external int FindComponents(typename typeName, notnull array< Managed > outComponents)
Container context loading JSON format.
Definition Math.c:13
Get prefab entity Data of type Ignores disabled Data s param dataType class of Data type you with to obtain return Entity Data of given type Null if not found *SCR_BaseEntityCatalogData GetEntityDataOfType(typename dataType)
static bool ApplyEntityCustomDataString(IEntity owner, LoadContext context)
static string GetComponentIdentifier(IEntity owner, GenericComponent component)
static bool ReadEntityLoadoutString(IEntity owner, SaveContext context)
static bool ApplyLoadoutString(IEntity owner, LoadContext context)
static bool ReadEntityCustomDataString(IEntity owner, SaveContext context)
Add your modded logic here for custom components to store their data and read back later....
static array< InventoryItemComponent > GetSlotItems(const BaseInventoryStorageComponent storage)
static bool ApplyEntityStorageString(IEntity owner, LoadContext context, InventoryStorageManagerComponent manager, BaseInventoryStorageComponent parentStorage=null, int slotId=-1)
static bool ApplyEntityLoadoutString(IEntity owner, LoadContext context, InventoryStorageManagerComponent manager, BaseInventoryStorageComponent parentStorage=null, int slotId=-1)
static void FindStorageComponents(IEntity owner, notnull set< BaseInventoryStorageComponent > storages)
static bool ReadEntityStorageString(IEntity owner, SaveContext context)
static void ComputeSuppliesCost(LoadContext context, SCR_Faction faction, SCR_ArsenalPlayerLoadout playerLoadout, SCR_EArsenalSupplyCostType arsenalSupplyType, int depth=0)
static void FindStorageComponents(GenericComponent parentComponent, notnull set< BaseInventoryStorageComponent > storages)
static bool ApplyCharacterDataLoadoutString(IEntity owner, LoadContext context)
static bool ShouldSaveStorage(BaseInventoryStorageComponent candidate)
static bool ReadCharacterDataLoadoutString(IEntity owner, SaveContext context)
Definition UUID.c:28
Definition Types.c:486
EEquipItemType