0
0
mirror of https://github.com/sp-tarkov/modules.git synced 2025-02-12 22:50:44 -05:00
Co-authored-by: Dev <dev@noreply.dev.sp-tarkov.com>
Reviewed-on: SPT-AKI/Modules#14
This commit is contained in:
chomp 2023-07-07 20:24:02 +00:00
parent a62df7c9be
commit b3ba581b59
18 changed files with 111 additions and 92 deletions

View File

@ -23,7 +23,7 @@ git config --local user.email "USERNAME@SOMETHING.com"
## Requirements ## Requirements
- Escape From Tarkov 23043 - Escape From Tarkov 24605
- BepInEx 5.4.19 - BepInEx 5.4.19
- Visual Studio Code - Visual Studio Code
- .NET 6 SDK - .NET 6 SDK

View File

@ -15,7 +15,7 @@ namespace Aki.Core.Patches
{ {
try try
{ {
var type = PatchConstants.EftTypes.Single(t => t.Name == "Class229"); var type = PatchConstants.EftTypes.Single(t => t.Name == "Class226");
var value = Traverse.Create(type).Field("TransportPrefixes").GetValue<Dictionary<ETransportProtocolType, string>>(); var value = Traverse.Create(type).Field("TransportPrefixes").GetValue<Dictionary<ETransportProtocolType, string>>();
value[ETransportProtocolType.HTTPS] = "http://"; value[ETransportProtocolType.HTTPS] = "http://";
value[ETransportProtocolType.WSS] = "ws://"; value[ETransportProtocolType.WSS] = "ws://";
@ -34,7 +34,7 @@ namespace Aki.Core.Patches
} }
[PatchPrefix] [PatchPrefix]
private static bool PatchPrefix(ref GStruct22 legacyParams) private static bool PatchPrefix(ref GStruct21 legacyParams)
{ {
//Console.WriteLine($"Original url {legacyParams.Url}"); //Console.WriteLine($"Original url {legacyParams.Url}");
legacyParams.Url = legacyParams.Url legacyParams.Url = legacyParams.Url

View File

@ -27,52 +27,57 @@ namespace Aki.Custom.Airdrops.Utils
return 100; return 100;
} }
string location = gameWorld.RegisteredPlayers[0].Location; // Get players current location
string playerLocation = gameWorld.MainPlayer.Location;
int result = 25; int result = 0;
switch (location.ToLower()) switch (playerLocation.ToLower())
{ {
case "bigmap": case "bigmap":
{ {
result = config.AirdropChancePercent.Bigmap; result = config.AirdropChancePercent.Bigmap;
break; break;
} }
case "interchange": case "interchange":
{ {
result = config.AirdropChancePercent.Interchange; result = config.AirdropChancePercent.Interchange;
break; break;
} }
case "rezervbase": case "rezervbase":
{ {
result = config.AirdropChancePercent.Reserve; result = config.AirdropChancePercent.Reserve;
break; break;
} }
case "shoreline": case "shoreline":
{ {
result = config.AirdropChancePercent.Shoreline; result = config.AirdropChancePercent.Shoreline;
break; break;
} }
case "woods": case "woods":
{ {
result = config.AirdropChancePercent.Woods; result = config.AirdropChancePercent.Woods;
break; break;
} }
case "lighthouse": case "lighthouse":
{ {
result = config.AirdropChancePercent.Lighthouse; result = config.AirdropChancePercent.Lighthouse;
break; break;
} }
case "tarkovstreets": case "tarkovstreets":
{ {
result = config.AirdropChancePercent.TarkovStreets; result = config.AirdropChancePercent.TarkovStreets;
break;
}
default:
Debug.LogError($"[AKI-AIRDROPS]: Map with name {playerLocation} not handled, defaulting spawn chance to 25%");
result = 25;
break; break;
}
} }
return result; return result;
} }
public static bool ShouldAirdropOccur(int dropChance, List<AirdropPoint> airdropPoints) private static bool ShouldAirdropOccur(int dropChance, List<AirdropPoint> airdropPoints)
{ {
return airdropPoints.Count > 0 && Random.Range(0, 100) <= dropChance; return airdropPoints.Count > 0 && Random.Range(0, 100) <= dropChance;
} }
@ -81,15 +86,16 @@ namespace Aki.Custom.Airdrops.Utils
{ {
var serverConfig = GetConfigFromServer(); var serverConfig = GetConfigFromServer();
var allAirdropPoints = LocationScene.GetAll<AirdropPoint>().ToList(); var allAirdropPoints = LocationScene.GetAll<AirdropPoint>().ToList();
var playerPosition = gameWorld.RegisteredPlayers[0].Position; var playerPosition = gameWorld.MainPlayer.Position;
var flareAirdropPoints = new List<AirdropPoint>(); var flareAirdropPoints = new List<AirdropPoint>();
var dropChance = ChanceToSpawn(gameWorld, serverConfig, isFlare); var dropChance = ChanceToSpawn(gameWorld, serverConfig, isFlare);
var flareSpawnRadiusDistance = 100f;
if (isFlare && allAirdropPoints.Count > 0) if (isFlare && allAirdropPoints.Count > 0)
{ {
foreach (AirdropPoint point in allAirdropPoints) foreach (AirdropPoint point in allAirdropPoints)
{ {
if (Vector3.Distance(playerPosition, point.transform.position) <= 100f) if (Vector3.Distance(playerPosition, point.transform.position) <= flareSpawnRadiusDistance)
{ {
flareAirdropPoints.Add(point); flareAirdropPoints.Add(point);
} }
@ -98,7 +104,7 @@ namespace Aki.Custom.Airdrops.Utils
if (flareAirdropPoints.Count == 0 && isFlare) if (flareAirdropPoints.Count == 0 && isFlare)
{ {
Debug.LogError($"[AKI-AIRDROPS]: Airdrop called in by flare, Unable to find an airdropPoint within 100m, defaulting to normal drop"); Debug.LogError($"[AKI-AIRDROPS]: Airdrop called in by flare, Unable to find an airdropPoint within {flareSpawnRadiusDistance}m, defaulting to normal drop");
flareAirdropPoints.Add(allAirdropPoints.OrderBy(_ => Guid.NewGuid()).FirstOrDefault()); flareAirdropPoints.Add(allAirdropPoints.OrderBy(_ => Guid.NewGuid()).FirstOrDefault());
} }

View File

@ -25,7 +25,8 @@ namespace Aki.Custom
new BotDifficultyPatch().Enable(); new BotDifficultyPatch().Enable();
new CoreDifficultyPatch().Enable(); new CoreDifficultyPatch().Enable();
new OfflineRaidMenuPatch().Enable(); new OfflineRaidMenuPatch().Enable();
new RaidSettingsWindowPatch().Enable(); // Fixed in live, no need for patch
//new RaidSettingsWindowPatch().Enable();
new OfflineRaidSettingsMenuPatch().Enable(); new OfflineRaidSettingsMenuPatch().Enable();
new SessionIdPatch().Enable(); new SessionIdPatch().Enable();
new VersionLabelPatch().Enable(); new VersionLabelPatch().Enable();

View File

@ -98,7 +98,7 @@ namespace Aki.Custom.Patches
{ {
var gameWorld = Singleton<GameWorld>.Instance; var gameWorld = Singleton<GameWorld>.Instance;
return gameWorld.RegisteredPlayers[0].Location; return gameWorld.MainPlayer.Location;
} }
private static bool CacheIsStale() private static bool CacheIsStale()

View File

@ -49,9 +49,9 @@ namespace Aki.Custom.Patches
private static bool IsTargetMethod(MethodInfo mi) private static bool IsTargetMethod(MethodInfo mi)
{ {
var parameters = mi.GetParameters(); var parameters = mi.GetParameters();
return (parameters.Length == 6 return (parameters.Length == 6
&& parameters[0].Name == "bundleLock" && parameters[0].Name == "bundleLock"
&& parameters[1].Name == "defaultKey" && parameters[1].Name == "defaultKey"
&& parameters[4].Name == "shouldExclude"); && parameters[4].Name == "shouldExclude");
} }

View File

@ -33,7 +33,7 @@ namespace Aki.Custom.Patches
var player = Singleton<GameWorld>.Instance.MainPlayer; var player = Singleton<GameWorld>.Instance.MainPlayer;
if (profileId == player?.Profile.Id) if (profileId == player?.Profile.Id)
{ {
GClass2731.Instance.CloseAllScreensForced(); GClass2974.Instance.CloseAllScreensForced();
} }
return true; return true;

View File

@ -29,7 +29,6 @@ namespace Aki.Custom.Patches
var raidSettings = Traverse.Create(controller).Field<RaidSettings>("RaidSettings").Value; var raidSettings = Traverse.Create(controller).Field<RaidSettings>("RaidSettings").Value;
raidSettings.RaidMode = ERaidMode.Local; raidSettings.RaidMode = ERaidMode.Local;
raidSettings.BotSettings.IsEnabled = true;
// Default checkbox to be ticked // Default checkbox to be ticked
____offlineModeToggle.isOn = true; ____offlineModeToggle.isOn = true;

View File

@ -17,7 +17,7 @@ namespace Aki.Custom.Patches
protected override MethodBase GetTargetMethod() protected override MethodBase GetTargetMethod()
{ {
var desiredType = typeof(RaidSettingsWindow); var desiredType = typeof(RaidSettingsWindow);
var desiredMethod = desiredType.GetMethod("method_9", BindingFlags.NonPublic | BindingFlags.Instance); var desiredMethod = desiredType.GetMethod("method_8", BindingFlags.NonPublic | BindingFlags.Instance);
Logger.LogDebug($"{this.GetType().Name} Type: {desiredType?.Name}"); Logger.LogDebug($"{this.GetType().Name} Type: {desiredType?.Name}");
Logger.LogDebug($"{this.GetType().Name} Method: {desiredMethod?.Name}"); Logger.LogDebug($"{this.GetType().Name} Method: {desiredMethod?.Name}");

View File

@ -7,8 +7,8 @@ namespace Aki.PrePatch
{ {
public static IEnumerable<string> TargetDLLs { get; } = new[] { "Assembly-CSharp.dll" }; public static IEnumerable<string> TargetDLLs { get; } = new[] { "Assembly-CSharp.dll" };
public static int sptUsecValue = 32; public static int sptUsecValue = 33;
public static int sptBearValue = 33; public static int sptBearValue = 34;
public static void Patch(ref AssemblyDefinition assembly) public static void Patch(ref AssemblyDefinition assembly)
{ {

View File

@ -14,7 +14,7 @@ namespace Aki.SinglePlayer.Models.Progression
private bool _addedToEnemy; private bool _addedToEnemy;
private List<MineDirectionalColliders> _mines; private List<MineDirectionalColliders> _mines;
private RecodableItemClass _transmitter; private RecodableItemClass _transmitter;
private List<Player> _bosses; private List<IAIDetails> _bosses;
private bool _aggressor; private bool _aggressor;
private bool _disabledDoor; private bool _disabledDoor;
private readonly string _transmitterId = "62e910aaf957f2915e0a5e36"; private readonly string _transmitterId = "62e910aaf957f2915e0a5e36";
@ -22,10 +22,13 @@ namespace Aki.SinglePlayer.Models.Progression
public void Start() public void Start()
{ {
_gameWorld = Singleton<GameWorld>.Instance; _gameWorld = Singleton<GameWorld>.Instance;
_bosses = new List<Player>(); _bosses = new List<IAIDetails>();
_mines = GameObject.FindObjectsOfType<MineDirectionalColliders>().ToList(); _mines = GameObject.FindObjectsOfType<MineDirectionalColliders>().ToList();
if (_gameWorld == null || _gameWorld.MainPlayer.Location.ToLower() != "lighthouse") return; if (_gameWorld == null || !string.Equals(_gameWorld.MainPlayer.Location, "lighthouse", System.StringComparison.OrdinalIgnoreCase))
{
return;
}
// if player is a scav, there is no need to continue this method. // if player is a scav, there is no need to continue this method.
if (_gameWorld.MainPlayer.Side == EPlayerSide.Savage) if (_gameWorld.MainPlayer.Side == EPlayerSide.Savage)
@ -55,7 +58,10 @@ namespace Aki.SinglePlayer.Models.Progression
_timer += Time.deltaTime; _timer += Time.deltaTime;
if (_timer < 10f) return; if (_timer < 10f)
{
return;
}
if (_bosses.Count == 0) if (_bosses.Count == 0)
{ {
@ -100,22 +106,23 @@ namespace Aki.SinglePlayer.Models.Progression
private void SetupBosses() private void SetupBosses()
{ {
foreach (var player in _gameWorld.AllPlayers) foreach (var aiBot in _gameWorld.AllAlivePlayersList)
{ {
if (!player.IsYourPlayer) if (!aiBot.IsYourPlayer)
{ {
if (player.AIData.BotOwner.IsRole(WildSpawnType.bossZryachiy) || player.AIData.BotOwner.IsRole(WildSpawnType.followerZryachiy)) // Edge case of bossZryachiy not being hostile to player
if (aiBot.AIData.BotOwner.IsRole(WildSpawnType.bossZryachiy) || aiBot.AIData.BotOwner.IsRole(WildSpawnType.followerZryachiy))
{ {
// Sub to Bosses OnDeath event, Set mainplayer to aggressor on this script // Subscribe to Bosses OnDeath event
player.OnPlayerDeadOrUnspawn += player1 => aiBot.OnPlayerDeadOrUnspawn += player1 =>
{ {
if (player1.KillerId != null && player1.KillerId == _gameWorld.MainPlayer.ProfileId) if (player1?.KillerId == _gameWorld.MainPlayer.ProfileId)
{ {
_aggressor = true; _aggressor = true;
} }
}; };
_bosses.Add(player); _bosses.Add(aiBot);
} }
} }
} }

View File

@ -23,8 +23,12 @@ namespace Aki.SinglePlayer.Patches.RaidFix
public GetNewBotTemplatesPatch() public GetNewBotTemplatesPatch()
{ {
_getNewProfileMethod = typeof(BotsPresets) var desiredType = typeof(BotsPresets);
.GetMethod(nameof(BotsPresets.GetNewProfile), PatchConstants.PrivateFlags); _getNewProfileMethod = desiredType
.GetMethod(nameof(BotsPresets.GetNewProfile), BindingFlags.Instance | BindingFlags.NonPublic); // want the func with 2 params (protected)
Logger.LogDebug($"{this.GetType().Name} Type: {desiredType?.Name}");
Logger.LogDebug($"{this.GetType().Name} Method: {_getNewProfileMethod?.Name}");
} }
protected override MethodBase GetTargetMethod() protected override MethodBase GetTargetMethod()
@ -36,13 +40,14 @@ namespace Aki.SinglePlayer.Patches.RaidFix
private bool IsTargetMethod(MethodInfo mi) private bool IsTargetMethod(MethodInfo mi)
{ {
var parameters = mi.GetParameters(); var parameters = mi.GetParameters();
return (parameters.Length == 2 return (parameters.Length == 3
&& parameters[0].Name == "data" && parameters[0].Name == "data"
&& parameters[1].Name == "cancellationToken"); && parameters[1].Name == "cancellationToken"
&& parameters[2].Name == "withDelete");
} }
[PatchPrefix] [PatchPrefix]
private static bool PatchPrefix(ref Task<Profile> __result, BotsPresets __instance, IBotData data) private static bool PatchPrefix(ref Task<Profile> __result, BotsPresets __instance, GClass626 data, bool withDelete)
{ {
/* /*
in short when client wants new bot and GetNewProfile() return null (if not more available templates or they don't satisfy by Role and Difficulty condition) in short when client wants new bot and GetNewProfile() return null (if not more available templates or they don't satisfy by Role and Difficulty condition)
@ -57,7 +62,17 @@ namespace Aki.SinglePlayer.Patches.RaidFix
var taskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); var taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
var taskAwaiter = (Task<Profile>)null; var taskAwaiter = (Task<Profile>)null;
var profile = (Profile)_getNewProfileMethod.Invoke(__instance, new object[] { data });
try
{
_getNewProfileMethod.Invoke(__instance, new object[] { data, true });
}
catch (Exception e)
{
Logger.LogDebug($"getnewbot failed: {e.Message} {e.InnerException}");
throw;
}
// load from server // load from server
var source = data.PrepareToLoadBackend(1).ToList(); var source = data.PrepareToLoadBackend(1).ToList();

View File

@ -2,7 +2,7 @@
using HarmonyLib; using HarmonyLib;
using System; using System;
using System.Reflection; using System.Reflection;
using TraderInfo = EFT.Profile.GClass1666; using TraderInfo = EFT.Profile.GClass1726;
namespace Aki.SinglePlayer.Patches.RaidFix namespace Aki.SinglePlayer.Patches.RaidFix
{ {

View File

@ -2,7 +2,6 @@ using Aki.Reflection.Patching;
using Aki.Reflection.Utils; using Aki.Reflection.Utils;
using EFT; using EFT;
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
@ -10,10 +9,10 @@ namespace Aki.SinglePlayer.Patches.RaidFix
{ {
public class RemoveUsedBotProfilePatch : ModulePatch public class RemoveUsedBotProfilePatch : ModulePatch
{ {
private static BindingFlags _flags; private static readonly BindingFlags _flags;
private static Type _targetInterface; private static readonly Type _targetInterface;
private static Type _targetType; private static readonly Type _targetType;
private static FieldInfo _profilesField; private static readonly FieldInfo _profilesField;
static RemoveUsedBotProfilePatch() static RemoveUsedBotProfilePatch()
{ {
@ -21,7 +20,7 @@ namespace Aki.SinglePlayer.Patches.RaidFix
_flags = BindingFlags.Instance | BindingFlags.NonPublic; _flags = BindingFlags.Instance | BindingFlags.NonPublic;
_targetInterface = PatchConstants.EftTypes.Single(IsTargetInterface); _targetInterface = PatchConstants.EftTypes.Single(IsTargetInterface);
_targetType = PatchConstants.EftTypes.Single(IsTargetType); _targetType = typeof(BotsPresets);
_profilesField = _targetType.GetField("list_0", _flags); _profilesField = _targetType.GetField("list_0", _flags);
} }
@ -41,21 +40,11 @@ namespace Aki.SinglePlayer.Patches.RaidFix
} }
[PatchPrefix] [PatchPrefix]
private static bool PatchPrefix(ref Profile __result, object __instance, IBotData data) private static bool PatchPrefix(ref Profile __result, object __instance, GClass626 data, ref bool withDelete)
{ {
var profiles = (List<Profile>)_profilesField.GetValue(__instance); withDelete = true;
if (profiles.Count > 0) return true; // Do original method
{
// second parameter makes client remove used profiles
__result = data.ChooseProfile(profiles, true);
}
else
{
__result = null;
}
return false;
} }
} }
} }

View File

@ -21,7 +21,7 @@ namespace Aki.SinglePlayer.Patches.RaidFix
.GetMethod("FindActiveEffect", BindingFlags.Instance | BindingFlags.Public) .GetMethod("FindActiveEffect", BindingFlags.Instance | BindingFlags.Public)
.MakeGenericMethod(typeof(ActiveHealthControllerClass) .MakeGenericMethod(typeof(ActiveHealthControllerClass)
.GetNestedType("Stun", BindingFlags.Instance | BindingFlags.NonPublic)) .GetNestedType("Stun", BindingFlags.Instance | BindingFlags.NonPublic))
.Invoke(Singleton<GameWorld>.Instance.AllPlayers[0].ActiveHealthController, new object[] { EBodyPart.Common }) != null; .Invoke(Singleton<GameWorld>.Instance.MainPlayer.ActiveHealthController, new object[] { EBodyPart.Common }) != null;
return shouldInvoke; return shouldInvoke;
} }

View File

@ -32,8 +32,7 @@ namespace Aki.SinglePlayer.Patches.ScavMode
Logger.LogError("Unable to Find Gameworld or RegisterPlayers... Unable to Disable Extracts for Scav raid"); Logger.LogError("Unable to Find Gameworld or RegisterPlayers... Unable to Disable Extracts for Scav raid");
} }
// One of the RegisteredPlayers will have the IsYourPlayer flag set, which will be our own Player instance. Player player = gameWorld.MainPlayer;
Player player = gameWorld.RegisteredPlayers.Find(p => p.IsYourPlayer);
var exfilController = gameWorld.ExfiltrationController; var exfilController = gameWorld.ExfiltrationController;

View File

@ -111,13 +111,16 @@ namespace Aki.SinglePlayer.Patches.ScavMode
{ {
var profile = PatchConstants.BackEndSession.Profile; var profile = PatchConstants.BackEndSession.Profile;
var menuController = (object)GetMenuController(); var menuController = (object)GetMenuController();
// Get fields from MainMenuController.cs
var raidSettings = Traverse.Create(menuController).Field("raidSettings_0").GetValue<RaidSettings>(); var raidSettings = Traverse.Create(menuController).Field("raidSettings_0").GetValue<RaidSettings>();
var matchmakerPlayersController = Traverse.Create(menuController).Field("gclass2784_0").GetValue<GClass2784>(); var matchmakerPlayersController = Traverse.Create(menuController).Field("gclass3027_0").GetValue<GClass3027>();
var gclass = new MatchmakerOfflineRaidScreen.GClass2773(profile?.Info, ref raidSettings, matchmakerPlayersController);
var gclass = new MatchmakerOfflineRaidScreen.GClass3016(profile?.Info, ref raidSettings, matchmakerPlayersController);
gclass.OnShowNextScreen += LoadOfflineRaidNextScreen; gclass.OnShowNextScreen += LoadOfflineRaidNextScreen;
// ready method // Ready method
gclass.OnShowReadyScreen += (OfflineRaidAction)Delegate.CreateDelegate(typeof(OfflineRaidAction), menuController, "method_67"); gclass.OnShowReadyScreen += (OfflineRaidAction)Delegate.CreateDelegate(typeof(OfflineRaidAction), menuController, "method_67");
gclass.ShowScreen(EScreenState.Queued); gclass.ShowScreen(EScreenState.Queued);
} }
@ -132,10 +135,10 @@ namespace Aki.SinglePlayer.Patches.ScavMode
raidSettings.WavesSettings.IsBosses = true; raidSettings.WavesSettings.IsBosses = true;
} }
// set offline raid values // Set offline raid values
_isLocalField.SetValue(menuController, raidSettings.Local); _isLocalField.SetValue(menuController, raidSettings.Local);
// load ready screen method // Load ready screen method
_onReadyScreenMethod.Invoke(menuController, null); _onReadyScreenMethod.Invoke(menuController, null);
} }

Binary file not shown.