mirror of
https://github.com/sp-tarkov/modules.git
synced 2025-02-13 04:50:45 -05:00
Remove Redundant patches.
This commit is contained in:
parent
0848617e29
commit
303a43e2e7
@ -1,22 +0,0 @@
|
|||||||
using SPT.Reflection.Patching;
|
|
||||||
using SPT.SinglePlayer.Utils.TraderServices;
|
|
||||||
using EFT;
|
|
||||||
using HarmonyLib;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace SPT.Custom.Patches
|
|
||||||
{
|
|
||||||
public class ResetTraderServicesPatch : ModulePatch
|
|
||||||
{
|
|
||||||
protected override MethodBase GetTargetMethod()
|
|
||||||
{
|
|
||||||
return AccessTools.Method(typeof(BaseLocalGame<EftGamePlayerOwner>), nameof(BaseLocalGame<EftGamePlayerOwner>.Stop));
|
|
||||||
}
|
|
||||||
|
|
||||||
[PatchPrefix]
|
|
||||||
private static void PatchPrefix()
|
|
||||||
{
|
|
||||||
TraderServicesManager.Instance.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -35,7 +35,6 @@ namespace SPT.Custom
|
|||||||
new SetLocationIdOnRaidStartPatch().Enable();
|
new SetLocationIdOnRaidStartPatch().Enable();
|
||||||
new RagfairFeePatch().Enable();
|
new RagfairFeePatch().Enable();
|
||||||
new ScavQuestPatch().Enable();
|
new ScavQuestPatch().Enable();
|
||||||
new ResetTraderServicesPatch().Enable();
|
|
||||||
new ScavItemCheckmarkPatch().Enable();
|
new ScavItemCheckmarkPatch().Enable();
|
||||||
new CultistAmuletRemovalPatch().Enable();
|
new CultistAmuletRemovalPatch().Enable();
|
||||||
new HalloweenExtractPatch().Enable();
|
new HalloweenExtractPatch().Enable();
|
||||||
|
@ -1,192 +0,0 @@
|
|||||||
using Comfort.Common;
|
|
||||||
using EFT;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace SPT.SinglePlayer.Models.Progression
|
|
||||||
{
|
|
||||||
public class LighthouseProgressionClass : MonoBehaviour
|
|
||||||
{
|
|
||||||
private GameWorld _gameWorld;
|
|
||||||
private Player _player;
|
|
||||||
private float _timer;
|
|
||||||
private List<MineDirectional> _bridgeMines;
|
|
||||||
private RecodableItemClass _transmitter;
|
|
||||||
private readonly List<IPlayer> _zryachiyAndFollowers = new List<IPlayer>();
|
|
||||||
private bool _aggressor;
|
|
||||||
private bool _isDoorDisabled;
|
|
||||||
private readonly string _transmitterId = "62e910aaf957f2915e0a5e36";
|
|
||||||
private readonly string _lightKeeperTid = "638f541a29ffd1183d187f57";
|
|
||||||
|
|
||||||
public void Start()
|
|
||||||
{
|
|
||||||
_gameWorld = Singleton<GameWorld>.Instance;
|
|
||||||
_player = _gameWorld?.MainPlayer;
|
|
||||||
|
|
||||||
if (_gameWorld == null || _player == null)
|
|
||||||
{
|
|
||||||
Destroy(this);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Get transmitter from players inventory
|
|
||||||
_transmitter = GetTransmitterFromInventory();
|
|
||||||
|
|
||||||
// Exit if transmitter does not exist and isnt green
|
|
||||||
if (!PlayerHasActiveTransmitterInInventory())
|
|
||||||
{
|
|
||||||
Destroy(this);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var places = Singleton<IBotGame>.Instance.BotsController.CoversData.AIPlaceInfoHolder.Places;
|
|
||||||
|
|
||||||
places.First(x => x.name == "Attack").gameObject.SetActive(false);
|
|
||||||
|
|
||||||
// Zone was added in a newer version and the gameObject actually has a \
|
|
||||||
places.First(y => y.name == "CloseZone\\").gameObject.SetActive(false);
|
|
||||||
|
|
||||||
// Give access to Lightkeepers door
|
|
||||||
_gameWorld.BufferZoneController.SetPlayerAccessStatus(_player.ProfileId, true);
|
|
||||||
|
|
||||||
_bridgeMines = _gameWorld.MineManager.Mines;
|
|
||||||
|
|
||||||
// Set mines to be non-active
|
|
||||||
SetBridgeMinesStatus(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Update()
|
|
||||||
{
|
|
||||||
IncrementLastUpdateTimer();
|
|
||||||
|
|
||||||
// Exit early if last update() run time was < 10 secs ago
|
|
||||||
if (_timer < 10f)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip if:
|
|
||||||
// GameWorld missing
|
|
||||||
// Player not an enemy to Zryachiy
|
|
||||||
// Lk door not accessible
|
|
||||||
// Player has no transmitter on thier person
|
|
||||||
if (_gameWorld == null || _isDoorDisabled || _transmitter == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find Zryachiy and prep him
|
|
||||||
if (_zryachiyAndFollowers.Count == 0)
|
|
||||||
{
|
|
||||||
SetupZryachiyAndFollowerHostility();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If player becomes aggressor, block access to LK
|
|
||||||
if (_aggressor)
|
|
||||||
{
|
|
||||||
DisableAccessToLightKeeper();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets transmitter from players inventory
|
|
||||||
/// </summary>
|
|
||||||
private RecodableItemClass GetTransmitterFromInventory()
|
|
||||||
{
|
|
||||||
return (RecodableItemClass) _player.Profile.Inventory.AllRealPlayerItems.FirstOrDefault(x => x.TemplateId == _transmitterId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks for transmitter status and exists in players inventory
|
|
||||||
/// </summary>
|
|
||||||
private bool PlayerHasActiveTransmitterInInventory()
|
|
||||||
{
|
|
||||||
return _transmitter != null &&
|
|
||||||
_transmitter?.RecodableComponent?.Status == RadioTransmitterStatus.Green;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Update _time to diff from last run of update()
|
|
||||||
/// </summary>
|
|
||||||
private void IncrementLastUpdateTimer()
|
|
||||||
{
|
|
||||||
_timer += Time.deltaTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set all brdige mines to desire state
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="desiredMineState">What state should bridge mines be set to</param>
|
|
||||||
private void SetBridgeMinesStatus(bool desiredMineState)
|
|
||||||
{
|
|
||||||
// Find mines with opposite state of what we want
|
|
||||||
var mines = _bridgeMines.Where(mine => mine.gameObject.activeSelf == !desiredMineState && mine.transform.parent.gameObject.name == "Directional_mines_LHZONE");
|
|
||||||
foreach (var mine in mines)
|
|
||||||
{
|
|
||||||
mine.gameObject.SetActive(desiredMineState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Put Zryachiy and followers into a list and sub to their death event
|
|
||||||
/// Make player agressor if player kills them.
|
|
||||||
/// </summary>
|
|
||||||
private void SetupZryachiyAndFollowerHostility()
|
|
||||||
{
|
|
||||||
// Only process non-players (ai)
|
|
||||||
foreach (var aiBot in _gameWorld.AllAlivePlayersList.Where(x => !x.IsYourPlayer))
|
|
||||||
{
|
|
||||||
// Bots that die on mounted guns get stuck in AllAlivePlayersList, need to check health
|
|
||||||
if (!aiBot.HealthController.IsAlive)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Edge case of bossZryachiy not being hostile to player
|
|
||||||
if (aiBot.AIData.BotOwner.IsRole(WildSpawnType.bossZryachiy) || aiBot.AIData.BotOwner.IsRole(WildSpawnType.followerZryachiy))
|
|
||||||
{
|
|
||||||
// Subscribe to bots OnDeath event
|
|
||||||
aiBot.OnPlayerDeadOrUnspawn += OnZryachiyOrFollowerDeath;
|
|
||||||
|
|
||||||
// Save bot to list for later access
|
|
||||||
if (!_zryachiyAndFollowers.Contains(aiBot))
|
|
||||||
{
|
|
||||||
_zryachiyAndFollowers.Add(aiBot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set aggression + standing loss when Zryachiy/follower is killed by player
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="player">The player who killed Zryachiy/follower.</param>
|
|
||||||
private void OnZryachiyOrFollowerDeath(Player player)
|
|
||||||
{
|
|
||||||
// Check if zryachiy/follower was killed by player
|
|
||||||
if (player?.KillerId == _player?.ProfileId)
|
|
||||||
{
|
|
||||||
// If player kills zryachiy or follower, force aggressor state
|
|
||||||
// Also set players Lk standing to negative (allows access to quest chain (Making Amends))
|
|
||||||
_aggressor = true;
|
|
||||||
_player?.Profile.TradersInfo[_lightKeeperTid].SetStanding(-0.01);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Disable door + set transmitter to 'red'
|
|
||||||
/// </summary>
|
|
||||||
private void DisableAccessToLightKeeper()
|
|
||||||
{
|
|
||||||
// Disable access to Lightkeepers door for the player
|
|
||||||
_gameWorld.BufferZoneController.SetPlayerAccessStatus(_gameWorld.MainPlayer.ProfileId, false);
|
|
||||||
_transmitter?.RecodableComponent?.SetStatus(RadioTransmitterStatus.Yellow);
|
|
||||||
_transmitter?.RecodableComponent?.SetEncoded(false);
|
|
||||||
_isDoorDisabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
using SPT.Reflection.Patching;
|
|
||||||
using SPT.SinglePlayer.Models.Progression;
|
|
||||||
using Comfort.Common;
|
|
||||||
using EFT;
|
|
||||||
using System.Reflection;
|
|
||||||
using HarmonyLib;
|
|
||||||
|
|
||||||
namespace SPT.SinglePlayer.Patches.Progression
|
|
||||||
{
|
|
||||||
public class LighthouseBridgePatch : ModulePatch
|
|
||||||
{
|
|
||||||
protected override MethodBase GetTargetMethod()
|
|
||||||
{
|
|
||||||
return AccessTools.Method(typeof(GameWorld), nameof(GameWorld.OnGameStarted));
|
|
||||||
}
|
|
||||||
|
|
||||||
[PatchPostfix]
|
|
||||||
private static void PatchPostfix()
|
|
||||||
{
|
|
||||||
var gameWorld = Singleton<GameWorld>.Instance;
|
|
||||||
|
|
||||||
if (gameWorld == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gameWorld.MainPlayer.Location.ToLower() != "lighthouse" || gameWorld.MainPlayer.Side == EPlayerSide.Savage)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gameWorld.GetOrAddComponent<LighthouseProgressionClass>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
using SPT.Reflection.Patching;
|
|
||||||
using Comfort.Common;
|
|
||||||
using EFT;
|
|
||||||
using System.Reflection;
|
|
||||||
using HarmonyLib;
|
|
||||||
|
|
||||||
namespace SPT.SinglePlayer.Patches.Progression
|
|
||||||
{
|
|
||||||
public class LighthouseTransmitterPatch : ModulePatch
|
|
||||||
{
|
|
||||||
protected override MethodBase GetTargetMethod()
|
|
||||||
{
|
|
||||||
return AccessTools.Method(typeof(RadioTransmitterHandlerClass), nameof(RadioTransmitterHandlerClass.method_4));
|
|
||||||
}
|
|
||||||
|
|
||||||
[PatchPrefix]
|
|
||||||
private static bool PatchPrefix(RadioTransmitterHandlerClass __instance)
|
|
||||||
{
|
|
||||||
var gameWorld = Singleton<GameWorld>.Instance;
|
|
||||||
|
|
||||||
if (gameWorld == null) return false;
|
|
||||||
|
|
||||||
var transmitter = __instance.RecodableComponent;
|
|
||||||
|
|
||||||
if (transmitter.IsEncoded)
|
|
||||||
{
|
|
||||||
transmitter.SetStatus(RadioTransmitterStatus.Green);
|
|
||||||
}
|
|
||||||
else if (gameWorld.MainPlayer.IsAgressorInLighthouseTraderZone)
|
|
||||||
{
|
|
||||||
// this might need to be tested and changed as I don't think this currently is affect upon killing bosses
|
|
||||||
transmitter.SetStatus(RadioTransmitterStatus.Yellow);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
transmitter.SetStatus(RadioTransmitterStatus.Red);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
using SPT.Reflection.Patching;
|
|
||||||
using SPT.SinglePlayer.Utils.TraderServices;
|
|
||||||
using HarmonyLib;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace SPT.SinglePlayer.Patches.TraderServices
|
|
||||||
{
|
|
||||||
public class GetTraderServicesPatch : ModulePatch
|
|
||||||
{
|
|
||||||
protected override MethodBase GetTargetMethod()
|
|
||||||
{
|
|
||||||
return AccessTools.Method(typeof(InventoryControllerClass), nameof(InventoryControllerClass.GetTraderServicesDataFromServer));
|
|
||||||
}
|
|
||||||
|
|
||||||
[PatchPrefix]
|
|
||||||
public static bool PatchPrefix(string traderId)
|
|
||||||
{
|
|
||||||
Logger.LogInfo($"Loading {traderId} services from servers");
|
|
||||||
TraderServicesManager.Instance.GetTraderServicesDataFromServer(traderId);
|
|
||||||
|
|
||||||
// Skip original
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
using SPT.Reflection.Patching;
|
|
||||||
using SPT.SinglePlayer.Utils.TraderServices;
|
|
||||||
using Comfort.Common;
|
|
||||||
using EFT;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace SPT.SinglePlayer.Patches.TraderServices
|
|
||||||
{
|
|
||||||
public class LightKeeperServicesPatch : ModulePatch
|
|
||||||
{
|
|
||||||
protected override MethodBase GetTargetMethod()
|
|
||||||
{
|
|
||||||
return typeof(GameWorld).GetMethod(nameof(GameWorld.OnGameStarted));
|
|
||||||
}
|
|
||||||
|
|
||||||
[PatchPostfix]
|
|
||||||
public static void PatchPostFix()
|
|
||||||
{
|
|
||||||
var gameWorld = Singleton<GameWorld>.Instance;
|
|
||||||
|
|
||||||
if (gameWorld != null)
|
|
||||||
{
|
|
||||||
gameWorld.gameObject.AddComponent<LightKeeperServicesManager>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
using SPT.Reflection.Patching;
|
|
||||||
using SPT.SinglePlayer.Utils.TraderServices;
|
|
||||||
using EFT;
|
|
||||||
using HarmonyLib;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace SPT.SinglePlayer.Patches.TraderServices
|
|
||||||
{
|
|
||||||
public class PurchaseTraderServicePatch : ModulePatch
|
|
||||||
{
|
|
||||||
protected override MethodBase GetTargetMethod()
|
|
||||||
{
|
|
||||||
return AccessTools.Method(typeof(InventoryControllerClass), nameof(InventoryControllerClass.TryPurchaseTraderService));
|
|
||||||
}
|
|
||||||
|
|
||||||
[PatchPostfix]
|
|
||||||
public static async void PatchPostFix(Task<bool> __result, ETraderServiceType serviceType, AbstractQuestControllerClass questController, string subServiceId)
|
|
||||||
{
|
|
||||||
bool purchased = await __result;
|
|
||||||
if (purchased)
|
|
||||||
{
|
|
||||||
Logger.LogInfo($"Player purchased service {serviceType}");
|
|
||||||
TraderServicesManager.Instance.AfterPurchaseTraderService(serviceType, questController, subServiceId);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.LogInfo($"Player failed to purchase service {serviceType}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,7 +6,6 @@ using SPT.SinglePlayer.Patches.Progression;
|
|||||||
using SPT.SinglePlayer.Patches.Quests;
|
using SPT.SinglePlayer.Patches.Quests;
|
||||||
using SPT.SinglePlayer.Patches.RaidFix;
|
using SPT.SinglePlayer.Patches.RaidFix;
|
||||||
using SPT.SinglePlayer.Patches.ScavMode;
|
using SPT.SinglePlayer.Patches.ScavMode;
|
||||||
using SPT.SinglePlayer.Patches.TraderServices;
|
|
||||||
using BepInEx;
|
using BepInEx;
|
||||||
|
|
||||||
namespace SPT.SinglePlayer
|
namespace SPT.SinglePlayer
|
||||||
@ -41,11 +40,6 @@ namespace SPT.SinglePlayer
|
|||||||
new ScavProfileLoadPatch().Enable();
|
new ScavProfileLoadPatch().Enable();
|
||||||
new ScavPrefabLoadPatch().Enable();
|
new ScavPrefabLoadPatch().Enable();
|
||||||
new ScavExfilPatch().Enable();
|
new ScavExfilPatch().Enable();
|
||||||
new LighthouseBridgePatch().Enable();
|
|
||||||
new LighthouseTransmitterPatch().Enable();
|
|
||||||
new GetTraderServicesPatch().Enable();
|
|
||||||
new PurchaseTraderServicePatch().Enable();
|
|
||||||
new LightKeeperServicesPatch().Enable();
|
|
||||||
|
|
||||||
// Still need
|
// Still need
|
||||||
new DisableReadyLocationReadyPatch().Enable();
|
new DisableReadyLocationReadyPatch().Enable();
|
||||||
|
@ -1,64 +0,0 @@
|
|||||||
using BepInEx.Logging;
|
|
||||||
using Comfort.Common;
|
|
||||||
using EFT;
|
|
||||||
using HarmonyLib.Tools;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace SPT.SinglePlayer.Utils.TraderServices
|
|
||||||
{
|
|
||||||
internal class LightKeeperServicesManager : MonoBehaviour
|
|
||||||
{
|
|
||||||
private static ManualLogSource logger;
|
|
||||||
GameWorld gameWorld;
|
|
||||||
BotsController botsController;
|
|
||||||
|
|
||||||
private void Awake()
|
|
||||||
{
|
|
||||||
logger = BepInEx.Logging.Logger.CreateLogSource(nameof(LightKeeperServicesManager));
|
|
||||||
|
|
||||||
gameWorld = Singleton<GameWorld>.Instance;
|
|
||||||
if (gameWorld == null || TraderServicesManager.Instance == null)
|
|
||||||
{
|
|
||||||
logger.LogError("[SPT-LKS] GameWorld or TraderServices null");
|
|
||||||
Destroy(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
botsController = Singleton<IBotGame>.Instance.BotsController;
|
|
||||||
if (botsController == null)
|
|
||||||
{
|
|
||||||
logger.LogError("[SPT-LKS] BotsController null");
|
|
||||||
Destroy(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TraderServicesManager.Instance.OnTraderServicePurchased += OnTraderServicePurchased;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTraderServicePurchased(ETraderServiceType serviceType, string subserviceId)
|
|
||||||
{
|
|
||||||
switch (serviceType)
|
|
||||||
{
|
|
||||||
case ETraderServiceType.ExUsecLoyalty:
|
|
||||||
botsController.BotTradersServices.LighthouseKeeperServices.OnFriendlyExUsecPurchased(gameWorld.MainPlayer);
|
|
||||||
break;
|
|
||||||
case ETraderServiceType.ZryachiyAid:
|
|
||||||
botsController.BotTradersServices.LighthouseKeeperServices.OnFriendlyZryachiyPurchased(gameWorld.MainPlayer);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDestroy()
|
|
||||||
{
|
|
||||||
if (gameWorld == null || botsController == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TraderServicesManager.Instance != null)
|
|
||||||
{
|
|
||||||
TraderServicesManager.Instance.OnTraderServicePurchased -= OnTraderServicePurchased;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
using EFT;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace SPT.SinglePlayer.Utils.TraderServices
|
|
||||||
{
|
|
||||||
public class TraderServiceModel
|
|
||||||
{
|
|
||||||
[JsonProperty("serviceType")]
|
|
||||||
public ETraderServiceType ServiceType { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("itemsToPay")]
|
|
||||||
public Dictionary<MongoID, int> ItemsToPay { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("subServices")]
|
|
||||||
public Dictionary<string, int> SubServices { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("itemsToReceive")]
|
|
||||||
public MongoID[] ItemsToReceive { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("requirements")]
|
|
||||||
public TraderServiceRequirementsModel Requirements { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TraderServiceRequirementsModel
|
|
||||||
{
|
|
||||||
[JsonProperty("completedQuests")]
|
|
||||||
public string[] CompletedQuests { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("standings")]
|
|
||||||
public Dictionary<string, float> Standings { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("side")]
|
|
||||||
public ESideType Side { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,237 +0,0 @@
|
|||||||
using SPT.Common.Http;
|
|
||||||
using Comfort.Common;
|
|
||||||
using EFT;
|
|
||||||
using EFT.Quests;
|
|
||||||
using HarmonyLib;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using UnityEngine;
|
|
||||||
using static BackendConfigSettingsClass;
|
|
||||||
using StandingListClass = GClass2188<float>;
|
|
||||||
|
|
||||||
namespace SPT.SinglePlayer.Utils.TraderServices
|
|
||||||
{
|
|
||||||
public class TraderServicesManager
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Subscribe to this event to trigger trader service logic.
|
|
||||||
/// </summary>
|
|
||||||
public event Action<ETraderServiceType, string> OnTraderServicePurchased;
|
|
||||||
|
|
||||||
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>();
|
|
||||||
private FieldInfo _playerQuestControllerField;
|
|
||||||
|
|
||||||
public TraderServicesManager()
|
|
||||||
{
|
|
||||||
_servicePurchased = new Dictionary<ETraderServiceType, Dictionary<string, bool>>();
|
|
||||||
_playerQuestControllerField = AccessTools.Field(typeof(Player), "_questController");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
_servicePurchased.Clear();
|
|
||||||
_cachedTraders.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
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))
|
|
||||||
{
|
|
||||||
TraderServicesClass traderService = new TraderServicesClass
|
|
||||||
{
|
|
||||||
TraderId = traderId,
|
|
||||||
ServiceType = serviceType,
|
|
||||||
UniqueItems = traderServiceModel.ItemsToReceive ?? new MongoID[0],
|
|
||||||
ItemsToPay = traderServiceModel.ItemsToPay ?? new Dictionary<MongoID, int>(),
|
|
||||||
|
|
||||||
// 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
|
|
||||||
SubServices = new Dictionary<string, int>()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Convert our format to the backend settings format
|
|
||||||
serviceData = new ServiceData(traderService);
|
|
||||||
|
|
||||||
// Populate requirements if provided
|
|
||||||
if (traderServiceModel.Requirements != null)
|
|
||||||
{
|
|
||||||
if (traderServiceModel.Requirements.Standings != null)
|
|
||||||
{
|
|
||||||
serviceData.TraderServiceRequirements.Standings = new StandingListClass();
|
|
||||||
serviceData.TraderServiceRequirements.Standings.AddRange(traderServiceModel.Requirements.Standings);
|
|
||||||
|
|
||||||
// BSG has a bug in their code, we _need_ to initialize this if Standings isn't null
|
|
||||||
serviceData.TraderServiceRequirements.CompletedQuests = new QuestDictionaryClass<string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (traderServiceModel.Requirements.CompletedQuests != null)
|
|
||||||
{
|
|
||||||
serviceData.TraderServiceRequirements.CompletedQuests = new QuestDictionaryClass<string>();
|
|
||||||
serviceData.TraderServiceRequirements.CompletedQuests.Concat(traderServiceModel.Requirements.CompletedQuests);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
var IsServiceAvailable = this.IsServiceAvailable(player, servicesDataPair.Value.TraderServiceRequirements);
|
|
||||||
|
|
||||||
// Check whether we've purchased this service yet
|
|
||||||
var traderService = servicesDataPair.Key;
|
|
||||||
var WasPurchasedInThisRaid = IsServicePurchased(traderService, traderId);
|
|
||||||
traderInfo.SetServiceAvailability(traderService, IsServiceAvailable, WasPurchasedInThisRaid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsServiceAvailable(Player player, ServiceRequirements requirements)
|
|
||||||
{
|
|
||||||
// Handle standing requirements
|
|
||||||
if (requirements.Standings != null)
|
|
||||||
{
|
|
||||||
foreach (var entry in requirements.Standings)
|
|
||||||
{
|
|
||||||
if (!player.Profile.TradersInfo.ContainsKey(entry.Key) ||
|
|
||||||
player.Profile.TradersInfo[entry.Key].Standing < entry.Value)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle quest requirements
|
|
||||||
if (requirements.CompletedQuests != null)
|
|
||||||
{
|
|
||||||
AbstractQuestControllerClass questController = _playerQuestControllerField.GetValue(player) as AbstractQuestControllerClass;
|
|
||||||
foreach (string questId in requirements.CompletedQuests)
|
|
||||||
{
|
|
||||||
var conditional = questController.Quests.GetConditional(questId);
|
|
||||||
if (conditional == null || conditional.QuestStatus != EQuestStatus.Success)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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, subServiceId, serviceData.TraderId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetServicePurchased(ETraderServiceType serviceType, string subserviceId, string traderId)
|
|
||||||
{
|
|
||||||
if (_servicePurchased.TryGetValue(serviceType, out var traderDict))
|
|
||||||
{
|
|
||||||
traderDict[traderId] = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_servicePurchased[serviceType] = new Dictionary<string, bool>();
|
|
||||||
_servicePurchased[serviceType][traderId] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OnTraderServicePurchased != null)
|
|
||||||
{
|
|
||||||
OnTraderServicePurchased.Invoke(serviceType, subserviceId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemovePurchasedService(ETraderServiceType serviceType, string traderId)
|
|
||||||
{
|
|
||||||
if (_servicePurchased.TryGetValue(serviceType, out var traderDict))
|
|
||||||
{
|
|
||||||
traderDict[traderId] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user