Files
SPT-Server-Build/Libraries/Core/Services/AirdropService.cs
T
2025-01-28 21:30:57 +00:00

187 lines
7.4 KiB
C#

using SptCommon.Annotations;
using Core.Models.Eft.Common.Tables;
using Core.Models.Eft.Location;
using Core.Models.Enums;
using Core.Models.Spt.Services;
using Core.Servers;
using Core.Models.Spt.Config;
using Core.Models.Utils;
using Core.Generators;
using Core.Utils;
using Core.Helpers;
using LogLevel = Core.Models.Spt.Logging.LogLevel;
namespace Core.Services;
[Injectable]
public class AirdropService(
ConfigServer configServer,
ISptLogger<AirdropService> _logger,
LootGenerator _lootGenerator,
HashUtil _hashUtil,
WeightedRandomHelper _weightedRandomHelper,
LocalisationService _localisationService,
ItemFilterService _itemFilterService,
ItemHelper _itemHelper)
{
protected AirdropConfig _airdropConfig = configServer.GetConfig<AirdropConfig>();
public GetAirdropLootResponse GenerateCustomAirdropLoot(GetAirdropLootRequest request)
{
if (!_airdropConfig.CustomAirdropMapping.TryGetValue(request.ContainerId, out var customAirdropInformation)) {
_logger.Warning(
$"Unable to find data for custom airdrop {request.ContainerId}, returning random airdrop instead"
);
return GenerateAirdropLoot();
}
return GenerateAirdropLoot(customAirdropInformation);
}
/// <summary>
/// Handle client/location/getAirdropLoot
/// Get loot for an airdrop container
/// Generates it randomly based on config/airdrop.json values
/// </summary>
/// <param name="forcedAirdropType">OPTIONAL - Desired airdrop type, randomised when not provided</param>
/// <returns>List of LootItem objects</returns>
public GetAirdropLootResponse GenerateAirdropLoot(SptAirdropTypeEnum? forcedAirdropType = null)
{
var airdropType = forcedAirdropType != null ? forcedAirdropType : ChooseAirdropType();
if (_logger.IsLogEnabled(LogLevel.Debug))
{
_logger.Debug($"Chose: {airdropType} for airdrop loot");
}
// Common/weapon/etc
var airdropConfig = GetAirdropLootConfigByType(airdropType);
// generate loot to put into airdrop crate
var crateLoot = airdropConfig.UseForcedLoot.GetValueOrDefault(false)
? _lootGenerator.CreateForcedLoot(airdropConfig.ForcedLoot)
: _lootGenerator.CreateRandomLoot(airdropConfig);
// Create airdrop crate and add to result in first spot
var airdropCrateItem = GetAirdropCrateItem((SptAirdropTypeEnum)airdropType);
// Add crate to front of list
crateLoot.Insert(0, airdropCrateItem);
// Reparent loot items to crate we added above
foreach (var item in crateLoot) {
if (item.Id == airdropCrateItem.Id) {
// Crate itself, don't alter
continue;
}
// no parentId = root item, make item have create as parent
if (item.ParentId is null) {
item.ParentId = airdropCrateItem.Id;
item.SlotId = "main";
}
}
return new GetAirdropLootResponse { Icon = airdropConfig.Icon, Container = crateLoot };
}
/// <summary>
/// Create a container create item based on passed in airdrop type
/// </summary>
/// <param name="airdropType">What type of container: weapon/common etc</param>
/// <returns>Item</returns>
protected Item GetAirdropCrateItem(SptAirdropTypeEnum airdropType)
{
var airdropContainer = new Item {
Id = _hashUtil.Generate(),
Template = "", // picked later
Upd = new Upd()
{
SpawnedInSession = true,
StackObjectsCount = 1,
},
};
switch (airdropType) {
case SptAirdropTypeEnum.foodMedical:
airdropContainer.Template = ItemTpl.LOOTCONTAINER_AIRDROP_MEDICAL_CRATE;
break;
case SptAirdropTypeEnum.barter:
airdropContainer.Template = ItemTpl.LOOTCONTAINER_AIRDROP_SUPPLY_CRATE;
break;
case SptAirdropTypeEnum.weaponArmor:
airdropContainer.Template = ItemTpl.LOOTCONTAINER_AIRDROP_WEAPON_CRATE;
break;
case SptAirdropTypeEnum.mixed:
airdropContainer.Template = ItemTpl.LOOTCONTAINER_AIRDROP_COMMON_SUPPLY_CRATE;
break;
case SptAirdropTypeEnum.radar:
airdropContainer.Template = ItemTpl.LOOTCONTAINER_AIRDROP_TECHNICAL_SUPPLY_CRATE_EVENT_1;
break;
default:
airdropContainer.Template = ItemTpl.LOOTCONTAINER_AIRDROP_COMMON_SUPPLY_CRATE;
break;
}
return airdropContainer;
}
/// <summary>
/// Randomly pick a type of airdrop loot using weighted values from config
/// </summary>
/// <returns>airdrop type value</returns>
protected SptAirdropTypeEnum ChooseAirdropType()
{
var possibleAirdropTypes = _airdropConfig.AirdropTypeWeightings;
return _weightedRandomHelper.GetWeightedValue(possibleAirdropTypes);
}
/// <summary>
/// Get the configuration for a specific type of airdrop
/// </summary>
/// <param name="airdropType">Type of airdrop to get settings for</param>
/// <returns>LootRequest</returns>
protected AirdropLootRequest GetAirdropLootConfigByType(SptAirdropTypeEnum? airdropType)
{
var lootSettingsByType = _airdropConfig.Loot[airdropType.ToString()];
if (lootSettingsByType is null) {
_logger.Error(
_localisationService.GetText("location-unable_to_find_airdrop_drop_config_of_type", airdropType)
);
// TODO: Get Radar airdrop to work. Atm Radar will default to common supply drop (mixed)
// Default to common
lootSettingsByType = _airdropConfig.Loot[AirdropTypeEnum.Common.ToString()];
}
// Get all items that match the blacklisted types and fold into item blacklist
var itemTypeBlacklist = _itemFilterService.GetItemRewardBaseTypeBlacklist();
var itemsMatchingTypeBlacklist = _itemHelper.GetItems()
.Where(templateItem => !string.IsNullOrEmpty(templateItem.Parent))
.Where(templateItem => _itemHelper.IsOfBaseclasses(templateItem.Parent, itemTypeBlacklist))
.Select(templateItem => templateItem.Id);
var itemBlacklist = new HashSet<string>();
itemBlacklist.UnionWith(lootSettingsByType.ItemBlacklist);
itemBlacklist.UnionWith(_itemFilterService.GetItemRewardBlacklist());
itemBlacklist.UnionWith(_itemFilterService.GetBossItems());
itemBlacklist.UnionWith(itemsMatchingTypeBlacklist);
return new AirdropLootRequest {
Icon = lootSettingsByType.Icon,
WeaponPresetCount = lootSettingsByType.WeaponPresetCount,
ArmorPresetCount = lootSettingsByType.ArmorPresetCount,
ItemCount = lootSettingsByType.ItemCount,
WeaponCrateCount = lootSettingsByType.WeaponCrateCount,
ItemBlacklist = itemBlacklist.ToList(),
ItemTypeWhitelist = lootSettingsByType.ItemTypeWhitelist,
ItemLimits = lootSettingsByType.ItemLimits,
ItemStackLimits = lootSettingsByType.ItemStackLimits,
ArmorLevelWhitelist = lootSettingsByType.ArmorLevelWhitelist,
AllowBossItems = lootSettingsByType.AllowBossItems,
UseForcedLoot = lootSettingsByType.UseForcedLoot,
ForcedLoot = lootSettingsByType.ForcedLoot,
};
}
}