0
0
mirror of https://github.com/sp-tarkov/modules.git synced 2025-02-13 09:50:43 -05:00
DrakiaXYZ 4dee774efc Refactor trader services into its own manager in Aki.Singleplayer (!61)
I've moved trader services handling from Aki.Debugging BTR code into Aki.SinglePlayer
This simplifies some of the code, and allows a more "generic" implementation.

I've also patched the GetTraderServicesDataFromServer and TryPurchaseTraderService methods to properly utilize the TraderServicesManager for storing service state

For now, this makes Aki.Debugging depend on Aki.SinglePlayer, this can be reverted once the BTR stuff is moved

Co-authored-by: DrakiaXYZ <565558+TheDgtl@users.noreply.github.com>
Reviewed-on: SPT-AKI/Modules#61
Co-authored-by: DrakiaXYZ <drakiaxyz@noreply.dev.sp-tarkov.com>
Co-committed-by: DrakiaXYZ <drakiaxyz@noreply.dev.sp-tarkov.com>
2024-01-15 09:09:31 +00:00

165 lines
6.2 KiB
C#

using Aki.Common.Http;
using Comfort.Common;
using EFT;
using HarmonyLib;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using static BackendConfigSettingsClass;
using TraderServiceClass = GClass1789;
namespace Aki.SinglePlayer.Utils.TraderServices
{
public class TraderServicesManager
{
private static TraderServicesManager _instance;
public static TraderServicesManager Instance
{
get
{
if (_instance == null)
{
_instance = new TraderServicesManager();
}
return _instance;
}
}
private Dictionary<ETraderServiceType, Dictionary<string, bool>> _servicePurchased { get; set; }
private HashSet<string> _cachedTraders = new HashSet<string>();
public TraderServicesManager()
{
_servicePurchased = new Dictionary<ETraderServiceType, Dictionary<string, bool>>();
}
public void GetTraderServicesDataFromServer(string traderId)
{
Dictionary<ETraderServiceType, ServiceData> servicesData = Singleton<BackendConfigSettingsClass>.Instance.ServicesData;
var gameWorld = Singleton<GameWorld>.Instance;
var player = gameWorld?.MainPlayer;
if (gameWorld == null || player == null)
{
Debug.LogError("GetTraderServicesDataFromServer - Error fetching game objects");
return;
}
if (!player.Profile.TradersInfo.TryGetValue(traderId, out Profile.TraderInfo traderInfo))
{
Debug.LogError("GetTraderServicesDataFromServer - Error fetching profile trader info");
return;
}
// Only request data from the server if it's not already cached
if (!_cachedTraders.Contains(traderId))
{
var json = RequestHandler.GetJson($"/singleplayer/traderServices/getTraderServices/{traderId}");
var traderServiceModels = JsonConvert.DeserializeObject<List<TraderServiceModel>>(json);
foreach (var traderServiceModel in traderServiceModels)
{
ETraderServiceType serviceType = traderServiceModel.ServiceType;
ServiceData serviceData;
// Only populate trader services that don't exist yet
if (!servicesData.ContainsKey(traderServiceModel.ServiceType))
{
TraderServiceClass traderService = new TraderServiceClass();
traderService.TraderId = traderId;
traderService.ServiceType = serviceType;
traderService.ItemsToPay = new Dictionary<MongoID, int>();
if (traderServiceModel.ItemsToPay != null)
{
foreach (var item in traderServiceModel.ItemsToPay)
{
traderService.ItemsToPay[item.Key] = item.Value;
}
}
// SubServices seem to be populated dynamically in the client (For BTR taxi atleast), so we can just ignore it
// NOTE: For future reference, this is a dict of `point id` to `price` for the BTR taxi
traderService.SubServices = new Dictionary<string, int>();
// TODO: What is this used for? Maybe lightkeeper?
traderService.UniqueItems = new MongoID[] { };
// Convert our format to the backend settings format and store it
serviceData = new ServiceData(traderService);
servicesData[serviceData.ServiceType] = serviceData;
}
}
_cachedTraders.Add(traderId);
}
// Update service availability
foreach (var servicesDataPair in servicesData)
{
// Only update this trader's services
if (servicesDataPair.Value.TraderId != traderId)
{
continue;
}
// TODO: We should probably actually calculate this?
var CanAfford = true;
// Check whether we've purchased this service yet
var traderService = servicesDataPair.Key;
var WasPurchasedInThisRaid = IsServicePurchased(traderService, traderId);
traderInfo.SetServiceAvailability(traderService, CanAfford, WasPurchasedInThisRaid);
}
}
public void AfterPurchaseTraderService(ETraderServiceType serviceType, AbstractQuestControllerClass questController, string subServiceId = null)
{
GameWorld gameWorld = Singleton<GameWorld>.Instance;
Player player = gameWorld?.MainPlayer;
if (gameWorld == null || player == null)
{
Debug.LogError("TryPurchaseTraderService - Error fetching game objects");
return;
}
// Service doesn't exist
if (!Singleton<BackendConfigSettingsClass>.Instance.ServicesData.TryGetValue(serviceType, out var serviceData))
{
return;
}
SetServicePurchased(serviceType, serviceData.TraderId);
}
public void SetServicePurchased(ETraderServiceType serviceType, string traderId)
{
if (_servicePurchased.TryGetValue(serviceType, out var traderDict))
{
traderDict[traderId] = true;
}
else
{
_servicePurchased[serviceType] = new Dictionary<string, bool>();
_servicePurchased[serviceType][traderId] = true;
}
}
public bool IsServicePurchased(ETraderServiceType serviceType, string traderId)
{
if (_servicePurchased.TryGetValue(serviceType, out var traderDict))
{
if (traderDict.TryGetValue(traderId, out var result))
{
return result;
}
}
return false;
}
}
}