0
0
mirror of https://github.com/sp-tarkov/modules.git synced 2025-02-13 02:50:45 -05:00

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
This commit is contained in:
Dev 2023-11-27 15:07:10 +00:00
parent cbd0cf5ef4
commit 47b6f926f5
3 changed files with 145 additions and 27 deletions

View File

@ -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; }
}
}

View File

@ -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> 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; }
}
}

View File

@ -2,20 +2,28 @@
using Aki.Common.Utils; using Aki.Common.Utils;
using Aki.Reflection.Patching; using Aki.Reflection.Patching;
using Aki.Reflection.Utils; using Aki.Reflection.Utils;
using Comfort.Common;
using EFT; using EFT;
using EFT.UI;
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
namespace Aki.SinglePlayer.Patches.ScavMode namespace Aki.SinglePlayer.Patches.ScavMode
{ {
/// <summary> /// <summary>
/// Just before converting the `EscapeTimeLimit` value from _raidsettings.SelectedLocation.EscapeTimeLimit /// Make alterations to the _raidSettings values prior to them being used to create a local game
/// into a TimeSpam, call into server and get a different value /// ____raidSettings.SelectedLocation.EscapeTimeLimit
/// If -1 is passed in return the original value /// ____raidSettings.SelectedLocation.exits
/// Singleton<BackendConfigSettingsClass>.Instance.Experience.MatchEnd.SurvivedTimeRequirement
/// </summary> /// </summary>
public class ScavLateStartPatch : ModulePatch public class ScavLateStartPatch : ModulePatch
{ {
// A cache of Location settings before any edits were made
private static readonly Dictionary<string, LocationSettingsClass.Location> originalLocationSettings = new Dictionary<string, LocationSettingsClass.Location>();
protected override MethodBase GetTargetMethod() protected override MethodBase GetTargetMethod()
{ {
var desiredType = PatchConstants.EftTypes.Single(x => x.Name == "TarkovApplication"); var desiredType = PatchConstants.EftTypes.Single(x => x.Name == "TarkovApplication");
@ -29,45 +37,118 @@ namespace Aki.SinglePlayer.Patches.ScavMode
private bool IsTargetMethod(MethodInfo arg) private bool IsTargetMethod(MethodInfo arg)
{ {
// method_44 as of 26535 // method_43 as of 26535
var parameters = arg.GetParameters(); var parameters = arg.GetParameters();
return parameters.Length == 1 return parameters.Length == 2
&& parameters[0]?.Name == "defaultMinutes" && parameters[0]?.Name == "timeAndWeather"
&& arg.ReturnType == typeof(TimeSpan); && parameters[1]?.Name == "timeHasComeScreenController"
&& arg.ReturnType == typeof(Task);
} }
[PatchPrefix] [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 json = RequestHandler.PostJson("/singleplayer/settings/getRaidTime", Json.Serialize(request));
var serverResult = Json.Deserialize<RaidTimeResponse>(json); var serverResult = Json.Deserialize<RaidTimeResponse>(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 AdjustSurviveTimeForExtraction(serverResult.NewSurviveTimeSeconds.Value);
return true; }
ResetMapExits(____raidSettings.SelectedLocation, originalLocationSettings[currentMapId]);
if (serverResult.ExitChanges != null && serverResult.ExitChanges.Count > 0)
{
AdjustExtracts(____raidSettings.SelectedLocation, serverResult.ExitChanges);
} }
__result = TimeSpan.FromSeconds(60 * serverResult.RaidTimeMinutes); ConsoleScreen.LogError($"Finished");
return false; // Skip original return true; // Do original method
} }
public class RaidTimeResponse private static void AdjustExtracts(LocationSettingsClass.Location location, List<ExitChanges> exitChangesToApply)
{ {
public int RaidTimeMinutes { get; set; } // Loop over each exit change from server
} foreach (var exitChange in exitChangesToApply)
public class RaidTimeRequest
{
public RaidTimeRequest(ESideType side, string location)
{ {
Side = side; // Find the client exit we want to make changes to
Location = location; 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; } continue;
public string Location { get; set; } }
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<BackendConfigSettingsClass>.Instance.Experience.MatchEnd;
ConsoleScreen.LogError($"Changed survive time to {newSurvivalTimeSeconds}");
matchEndConfig.SurvivedTimeRequirement = newSurvivalTimeSeconds;
} }
} }
} }