From 47b6f926f5ef3ca44aec0ee7cae91ad42eec53fe Mon Sep 17 00:00:00 2001 From: Dev Date: Mon, 27 Nov 2023 15:07:10 +0000 Subject: [PATCH] Reworked ScavLateStart patch Removed majority of logic from client code in favour of having it in server Targets different method, method_43 Processes changes provided by server --- .../Models/ScavMode/RaidTimeRequest.cs | 16 +++ .../Models/ScavMode/RaidTimeResponse.cs | 21 +++ .../Patches/ScavMode/ScavLateStartPatch.cs | 135 ++++++++++++++---- 3 files changed, 145 insertions(+), 27 deletions(-) create mode 100644 project/Aki.SinglePlayer/Models/ScavMode/RaidTimeRequest.cs create mode 100644 project/Aki.SinglePlayer/Models/ScavMode/RaidTimeResponse.cs diff --git a/project/Aki.SinglePlayer/Models/ScavMode/RaidTimeRequest.cs b/project/Aki.SinglePlayer/Models/ScavMode/RaidTimeRequest.cs new file mode 100644 index 0000000..8f42a49 --- /dev/null +++ b/project/Aki.SinglePlayer/Models/ScavMode/RaidTimeRequest.cs @@ -0,0 +1,16 @@ +using EFT; + +namespace Aki.SinglePlayer.Patches.ScavMode +{ + public class RaidTimeRequest + { + public RaidTimeRequest(ESideType side, string location) + { + Side = side; + Location = location; + } + + public ESideType Side { get; set; } + public string Location { get; set; } + } +} diff --git a/project/Aki.SinglePlayer/Models/ScavMode/RaidTimeResponse.cs b/project/Aki.SinglePlayer/Models/ScavMode/RaidTimeResponse.cs new file mode 100644 index 0000000..45701e8 --- /dev/null +++ b/project/Aki.SinglePlayer/Models/ScavMode/RaidTimeResponse.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; + +namespace Aki.SinglePlayer.Patches.ScavMode +{ + public class RaidTimeResponse + { + public int RaidTimeMinutes { get; set; } + public int? NewSurviveTimeSeconds { get; set; } + public int OriginalSurvivalTimeSeconds { get; set; } + public List ExitChanges { get; set; } + + } + + public class ExitChanges + { + public string Name{ get; set; } + public int? MinTime { get; set; } + public int? MaxTime { get; set; } + public int? Chance { get; set; } + } +} \ No newline at end of file diff --git a/project/Aki.SinglePlayer/Patches/ScavMode/ScavLateStartPatch.cs b/project/Aki.SinglePlayer/Patches/ScavMode/ScavLateStartPatch.cs index 8478a39..a51d1d2 100644 --- a/project/Aki.SinglePlayer/Patches/ScavMode/ScavLateStartPatch.cs +++ b/project/Aki.SinglePlayer/Patches/ScavMode/ScavLateStartPatch.cs @@ -2,20 +2,28 @@ using Aki.Common.Utils; using Aki.Reflection.Patching; using Aki.Reflection.Utils; +using Comfort.Common; using EFT; +using EFT.UI; using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Threading.Tasks; namespace Aki.SinglePlayer.Patches.ScavMode { /// - /// Just before converting the `EscapeTimeLimit` value from _raidsettings.SelectedLocation.EscapeTimeLimit - /// into a TimeSpam, call into server and get a different value - /// If -1 is passed in return the original value + /// Make alterations to the _raidSettings values prior to them being used to create a local game + /// ____raidSettings.SelectedLocation.EscapeTimeLimit + /// ____raidSettings.SelectedLocation.exits + /// Singleton.Instance.Experience.MatchEnd.SurvivedTimeRequirement /// public class ScavLateStartPatch : ModulePatch { + // A cache of Location settings before any edits were made + private static readonly Dictionary originalLocationSettings = new Dictionary(); + protected override MethodBase GetTargetMethod() { var desiredType = PatchConstants.EftTypes.Single(x => x.Name == "TarkovApplication"); @@ -29,45 +37,118 @@ namespace Aki.SinglePlayer.Patches.ScavMode private bool IsTargetMethod(MethodInfo arg) { - // method_44 as of 26535 + // method_43 as of 26535 var parameters = arg.GetParameters(); - return parameters.Length == 1 - && parameters[0]?.Name == "defaultMinutes" - && arg.ReturnType == typeof(TimeSpan); + return parameters.Length == 2 + && parameters[0]?.Name == "timeAndWeather" + && parameters[1]?.Name == "timeHasComeScreenController" + && arg.ReturnType == typeof(Task); } [PatchPrefix] - private static bool PatchPrefix(int defaultMinutes, ref TimeSpan __result, RaidSettings ____raidSettings) + private static bool PatchPrefix(ref RaidSettings ____raidSettings) { - var request = new RaidTimeRequest(____raidSettings.Side, ____raidSettings.SelectedLocation.Id); + var currentMapId = ____raidSettings.SelectedLocation.Id; + + // Cache map info for use later + if (!originalLocationSettings.ContainsKey(currentMapId)) + { + originalLocationSettings.Add(currentMapId, ____raidSettings.SelectedLocation); + } + + // Create request and send to server, parse response + var request = new RaidTimeRequest(____raidSettings.Side, currentMapId); var json = RequestHandler.PostJson("/singleplayer/settings/getRaidTime", Json.Serialize(request)); var serverResult = Json.Deserialize(json); - if (serverResult.RaidTimeMinutes == -1) + // Set new raid time + ____raidSettings.SelectedLocation.EscapeTimeLimit = serverResult.RaidTimeMinutes; + + // Reset survival time + AdjustSurviveTimeForExtraction(serverResult.OriginalSurvivalTimeSeconds); + if (serverResult.NewSurviveTimeSeconds.HasValue) { - // Default value passed in, make no changes - return true; + AdjustSurviveTimeForExtraction(serverResult.NewSurviveTimeSeconds.Value); + } + ResetMapExits(____raidSettings.SelectedLocation, originalLocationSettings[currentMapId]); + if (serverResult.ExitChanges != null && serverResult.ExitChanges.Count > 0) + { + AdjustExtracts(____raidSettings.SelectedLocation, serverResult.ExitChanges); } - __result = TimeSpan.FromSeconds(60 * serverResult.RaidTimeMinutes); - return false; // Skip original + ConsoleScreen.LogError($"Finished"); + return true; // Do original method } - public class RaidTimeResponse + private static void AdjustExtracts(LocationSettingsClass.Location location, List exitChangesToApply) { - public int RaidTimeMinutes { get; set; } - } - - public class RaidTimeRequest - { - public RaidTimeRequest(ESideType side, string location) + // Loop over each exit change from server + foreach (var exitChange in exitChangesToApply) { - Side = side; - Location = location; - } + // Find the client exit we want to make changes to + var exitToChange = location.exits.First(x => x.Name == exitChange.Name); + if (exitToChange == null) + { + ConsoleScreen.LogError($"Exit with Id: {exitChange.Name} not found, skipping"); - public ESideType Side { get; set; } - public string Location { get; set; } + continue; + } + + if (exitChange.Chance.HasValue) + { + ConsoleScreen.LogError($"Changed exit ${exitChange.Name} chance from {exitToChange.Chance} to {exitChange.Chance.Value}"); + exitToChange.Chance = exitChange.Chance.Value; + } + + if (exitChange.MinTime.HasValue) + { + ConsoleScreen.LogError($"Changed exit ${exitChange.Name} MinTime from {exitToChange.MinTime} to {exitChange.MinTime.Value}"); + ConsoleScreen.LogError($"Changed exit ${exitChange.Name} MaxTime from {exitToChange.MaxTime} to {exitChange.MaxTime.Value}"); + exitToChange.MinTime = exitChange.MinTime.Value; + exitToChange.MaxTime = exitChange.MaxTime.Value; + } + } + } + + private static void ResetMapExits(LocationSettingsClass.Location clientLocation, LocationSettingsClass.Location cachedLocation) + { + // Iterate over cached original map data + foreach (var cachedExit in cachedLocation.exits) + { + // Find client exit + var clientLocationExit = clientLocation.exits.FirstOrDefault(x => x.Name == cachedExit.Name); + if (clientLocationExit == null) + { + ConsoleScreen.LogError($"Unable to find exit with name: {cachedExit.Name}, skipping"); + + continue; + } + + // Reset values to those from cache + if (clientLocationExit.Chance != cachedExit.Chance) + { + ConsoleScreen.LogError($"Reset exit ${cachedExit.Name} Chance from {cachedExit.Chance} to {clientLocationExit.Chance}"); + clientLocationExit.Chance = cachedExit.Chance; + } + if (clientLocationExit.MinTime != cachedExit.MinTime) + { + ConsoleScreen.LogError($"Reset exit ${cachedExit.Name} MinTime from {cachedExit.MinTime} to {clientLocationExit.MinTime}"); + clientLocationExit.MinTime = cachedExit.MinTime; + } + + if (clientLocationExit.MaxTime != cachedExit.MaxTime) + { + ConsoleScreen.LogError($"Reset exit ${cachedExit.Name} MaxTime from {cachedExit.MaxTime} to {clientLocationExit.MaxTime}"); + clientLocationExit.MaxTime = cachedExit.MaxTime; + } + } + } + + private static void AdjustSurviveTimeForExtraction(int newSurvivalTimeSeconds) + { + var matchEndConfig = Singleton.Instance.Experience.MatchEnd; + ConsoleScreen.LogError($"Changed survive time to {newSurvivalTimeSeconds}"); + matchEndConfig.SurvivedTimeRequirement = newSurvivalTimeSeconds; } } -} +} \ No newline at end of file