diff --git a/project/Aki.Custom/AkiCustomPlugin.cs b/project/Aki.Custom/AkiCustomPlugin.cs index 7fe005f..e43c9a5 100644 --- a/project/Aki.Custom/AkiCustomPlugin.cs +++ b/project/Aki.Custom/AkiCustomPlugin.cs @@ -67,7 +67,9 @@ namespace Aki.Custom new BTRDestroyAtRaidEndPatch().Enable(); new BTRVehicleMovementSpeedPatch().Enable(); new ScavItemCheckmarkPatch().Enable(); - } + new ResetTraderServicesPatch().Enable(); + + } catch (Exception ex) { Logger.LogError($"A PATCH IN {GetType().Name} FAILED. SUBSEQUENT PATCHES HAVE NOT LOADED"); diff --git a/project/Aki.Custom/BTR/BTRManager.cs b/project/Aki.Custom/BTR/BTRManager.cs index 10ad4cb..a19168b 100644 --- a/project/Aki.Custom/BTR/BTRManager.cs +++ b/project/Aki.Custom/BTR/BTRManager.cs @@ -491,7 +491,6 @@ namespace Aki.Custom.BTR if (TraderServicesManager.Instance != null) { TraderServicesManager.Instance.OnTraderServicePurchased -= BtrTraderServicePurchased; - TraderServicesManager.Instance.Clear(); } if (gameWorld.MainPlayer != null) diff --git a/project/Aki.Custom/Patches/ResetTraderServicesPatch.cs b/project/Aki.Custom/Patches/ResetTraderServicesPatch.cs new file mode 100644 index 0000000..ff8731d --- /dev/null +++ b/project/Aki.Custom/Patches/ResetTraderServicesPatch.cs @@ -0,0 +1,22 @@ +using Aki.Reflection.Patching; +using Aki.SinglePlayer.Utils.TraderServices; +using EFT; +using HarmonyLib; +using System.Reflection; + +namespace Aki.Custom.Patches +{ + public class ResetTraderServicesPatch : ModulePatch + { + protected override MethodBase GetTargetMethod() + { + return AccessTools.Method(typeof(BaseLocalGame), nameof(BaseLocalGame.Stop)); + } + + [PatchPrefix] + private static void PatchPrefix() + { + TraderServicesManager.Instance.Clear(); + } + } +} diff --git a/project/Aki.SinglePlayer/AkiSingleplayerPlugin.cs b/project/Aki.SinglePlayer/AkiSingleplayerPlugin.cs index c4eb11a..430c2fc 100644 --- a/project/Aki.SinglePlayer/AkiSingleplayerPlugin.cs +++ b/project/Aki.SinglePlayer/AkiSingleplayerPlugin.cs @@ -63,6 +63,7 @@ namespace Aki.SinglePlayer new ScavSellAllPriceStorePatch().Enable(); new ScavSellAllRequestPatch().Enable(); new HideoutQuestIgnorePatch().Enable(); + new LightKeeperServicesPatch().Enable(); } catch (Exception ex) { diff --git a/project/Aki.SinglePlayer/Patches/TraderServices/LightKeeperServicesPatch.cs b/project/Aki.SinglePlayer/Patches/TraderServices/LightKeeperServicesPatch.cs new file mode 100644 index 0000000..71a370c --- /dev/null +++ b/project/Aki.SinglePlayer/Patches/TraderServices/LightKeeperServicesPatch.cs @@ -0,0 +1,27 @@ +using Aki.Reflection.Patching; +using Aki.SinglePlayer.Utils.TraderServices; +using Comfort.Common; +using EFT; +using System.Reflection; + +namespace Aki.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.Instance; + + if (gameWorld != null) + { + gameWorld.gameObject.AddComponent(); + } + } + } +} diff --git a/project/Aki.SinglePlayer/Utils/TraderServices/LightKeeperServicesManager.cs b/project/Aki.SinglePlayer/Utils/TraderServices/LightKeeperServicesManager.cs new file mode 100644 index 0000000..b13f584 --- /dev/null +++ b/project/Aki.SinglePlayer/Utils/TraderServices/LightKeeperServicesManager.cs @@ -0,0 +1,64 @@ +using BepInEx.Logging; +using Comfort.Common; +using EFT; +using HarmonyLib.Tools; +using UnityEngine; + +namespace Aki.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.Instance; + if (gameWorld == null || TraderServicesManager.Instance == null) + { + logger.LogError("[AKI-LKS] GameWorld or TraderServices null"); + Destroy(this); + return; + } + + botsController = Singleton.Instance.BotsController; + if (botsController == null) + { + logger.LogError("[AKI-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; + } + } + } +} diff --git a/project/Aki.SinglePlayer/Utils/TraderServices/TraderServiceModel.cs b/project/Aki.SinglePlayer/Utils/TraderServices/TraderServiceModel.cs index facc783..7e81955 100644 --- a/project/Aki.SinglePlayer/Utils/TraderServices/TraderServiceModel.cs +++ b/project/Aki.SinglePlayer/Utils/TraderServices/TraderServiceModel.cs @@ -10,9 +10,12 @@ namespace Aki.SinglePlayer.Utils.TraderServices public ETraderServiceType ServiceType { get; set; } [JsonProperty("itemsToPay")] - public Dictionary ItemsToPay { get; set; } + public Dictionary ItemsToPay { get; set; } [JsonProperty("subServices")] public Dictionary SubServices { get; set; } + + [JsonProperty("itemsToReceive")] + public MongoID[] ItemsToReceive { get; set; } } } \ No newline at end of file diff --git a/project/Aki.SinglePlayer/Utils/TraderServices/TraderServicesManager.cs b/project/Aki.SinglePlayer/Utils/TraderServices/TraderServicesManager.cs index 6f49a8a..81048e1 100644 --- a/project/Aki.SinglePlayer/Utils/TraderServices/TraderServicesManager.cs +++ b/project/Aki.SinglePlayer/Utils/TraderServices/TraderServicesManager.cs @@ -78,24 +78,17 @@ namespace Aki.SinglePlayer.Utils.TraderServices // 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(); - if (traderServiceModel.ItemsToPay != null) + TraderServiceClass traderService = new TraderServiceClass { - foreach (var item in traderServiceModel.ItemsToPay) - { - traderService.ItemsToPay[item.Key] = item.Value; - } - } + TraderId = traderId, + ServiceType = serviceType, + UniqueItems = traderServiceModel.ItemsToReceive ?? new MongoID[0], + ItemsToPay = traderServiceModel.ItemsToPay ?? new Dictionary(), - // 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(); - - // TODO: What is this used for? Maybe lightkeeper? - traderService.UniqueItems = new MongoID[] { }; + // 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() + }; // Convert our format to the backend settings format and store it serviceData = new ServiceData(traderService); @@ -156,7 +149,11 @@ namespace Aki.SinglePlayer.Utils.TraderServices _servicePurchased[serviceType] = new Dictionary(); _servicePurchased[serviceType][traderId] = true; } - OnTraderServicePurchased.Invoke(serviceType, subserviceId); + + if (OnTraderServicePurchased != null) + { + OnTraderServicePurchased.Invoke(serviceType, subserviceId); + } } public void RemovePurchasedService(ETraderServiceType serviceType, string traderId)