diff --git a/README.md b/README.md index 6e8a369..1926bf9 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ git config --local user.email "USERNAME@SOMETHING.com" ``` ## Requirements -- Escape From Tarkov 29197 +- Escape From Tarkov 29862 - Visual Studio Code -OR- Visual Studio 2022 - .NET 6 SDK - [PowerShell v7](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows) diff --git a/project/Aki.Build/Aki.Build.csproj b/project/Aki.Build/Aki.Build.csproj index c4e1d46..fede346 100644 --- a/project/Aki.Build/Aki.Build.csproj +++ b/project/Aki.Build/Aki.Build.csproj @@ -6,8 +6,8 @@ - SPT Aki - Copyright @ SPT Aki 2024 + SPT + Copyright @ SPT 2024 diff --git a/project/Aki.Common/Aki.Common.csproj b/project/Aki.Common/Aki.Common.csproj index 137a581..5e684cc 100644 --- a/project/Aki.Common/Aki.Common.csproj +++ b/project/Aki.Common/Aki.Common.csproj @@ -3,12 +3,13 @@ 1.0.0.0 net471 - Release + spt-common + Release - Aki - Copyright @ Aki 2024 + SPT + Copyright @ SPT 2024 diff --git a/project/Aki.Common/Http/Request.cs b/project/Aki.Common/Http/Request.cs deleted file mode 100644 index 0b92c5a..0000000 --- a/project/Aki.Common/Http/Request.cs +++ /dev/null @@ -1,85 +0,0 @@ -#region DEPRECATED, REMOVE IN 3.8.1 - -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using Aki.Common.Utils; - -namespace Aki.Common.Http -{ - [Obsolete("Request is deprecated, please use Aki.Common.Http.Client instead.")] - public class Request - { - [Obsolete("Request.Send() is deprecated, please use Aki.Common.Http.Client instead.")] - public byte[] Send(string url, string method, byte[] data = null, bool compress = true, string mime = null, Dictionary headers = null) - { - if (!WebConstants.IsValidMethod(method)) - { - throw new ArgumentException("request method is invalid"); - } - - Uri uri = new Uri(url); - HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); - - if (uri.Scheme == "https") - { - ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; - request.ServerCertificateValidationCallback = delegate { return true; }; - } - - request.Timeout = 15000; - request.Method = method; - request.Headers.Add("Accept-Encoding", "deflate"); - - if (headers != null) - { - foreach (KeyValuePair item in headers) - { - request.Headers.Add(item.Key, item.Value); - } - } - - if (method != WebConstants.Get && method != WebConstants.Head && data != null) - { - byte[] body = (compress) ? Zlib.Compress(data, ZlibCompression.Maximum) : data; - - request.ContentType = WebConstants.IsValidMime(mime) ? mime : "application/octet-stream"; - request.ContentLength = body.Length; - - if (compress) - { - request.Headers.Add("Content-Encoding", "deflate"); - } - - using (Stream stream = request.GetRequestStream()) - { - stream.Write(body, 0, body.Length); - } - } - - using (WebResponse response = request.GetResponse()) - { - using (MemoryStream ms = new MemoryStream()) - { - response.GetResponseStream().CopyTo(ms); - byte[] body = ms.ToArray(); - - if (body.Length == 0) - { - return null; - } - - if (Zlib.IsCompressed(body)) - { - return Zlib.Decompress(body); - } - - return body; - } - } - } - } -} - -#endregion \ No newline at end of file diff --git a/project/Aki.Common/Http/RequestHandler.cs b/project/Aki.Common/Http/RequestHandler.cs index 498ecee..0917a5c 100644 --- a/project/Aki.Common/Http/RequestHandler.cs +++ b/project/Aki.Common/Http/RequestHandler.cs @@ -129,89 +129,5 @@ namespace Aki.Common.Http { return Task.Run(() => PutJsonAsync(path, json)).Result; } - -#region DEPRECATED, REMOVE IN 3.8.1 - [Obsolete("GetData(path, isHost) is deprecated, please use GetData(path) instead.")] - public static byte[] GetData(string path, bool hasHost) - { - var url = (hasHost) ? path : Host + path; - _logger.LogInfo($"Request GET data: {SessionId}:{url}"); - - var headers = new Dictionary() - { - { "Cookie", $"PHPSESSID={SessionId}" }, - { "SessionId", SessionId } - }; - - var request = new Request(); - var data = request.Send(url, "GET", null, headers: headers); - - ValidateData(url, data); - return data; - - } - - [Obsolete("GetJson(path, isHost) is deprecated, please use GetJson(path) instead.")] - public static string GetJson(string path, bool hasHost) - { - var url = (hasHost) ? path : Host + path; - _logger.LogInfo($"Request GET json: {SessionId}:{url}"); - - var headers = new Dictionary() - { - { "Cookie", $"PHPSESSID={SessionId}" }, - { "SessionId", SessionId } - }; - - var request = new Request(); - var data = request.Send(url, "GET", headers: headers); - var body = Encoding.UTF8.GetString(data); - - ValidateJson(url, body); - return body; - - } - - [Obsolete("PostJson(path, json, isHost) is deprecated, please use PostJson(path, json) instead.")] - public static string PostJson(string path, string json, bool hasHost) - { - var url = (hasHost) ? path : Host + path; - _logger.LogInfo($"Request POST json: {SessionId}:{url}"); - - var payload = Encoding.UTF8.GetBytes(json); - var mime = WebConstants.Mime[".json"]; - var headers = new Dictionary() - { - { "Cookie", $"PHPSESSID={SessionId}" }, - { "SessionId", SessionId } - }; - - var request = new Request(); - var data = request.Send(url, "POST", payload, true, mime, headers); - var body = Encoding.UTF8.GetString(data); - - ValidateJson(url, body); - return body; - - } - - [Obsolete("PutJson(path, json, isHost) is deprecated, please use PutJson(path, json) instead.")] - public static void PutJson(string path, string json, bool hasHost) - { - var url = (hasHost) ? path : Host + path; - _logger.LogInfo($"Request PUT json: {SessionId}:{url}"); - - var payload = Encoding.UTF8.GetBytes(json); - var mime = WebConstants.Mime[".json"]; - var headers = new Dictionary() - { - { "Cookie", $"PHPSESSID={SessionId}" }, - { "SessionId", SessionId } - }; - - var request = new Request(); - request.Send(url, "PUT", payload, true, mime, headers); - } -#endregion } } diff --git a/project/Aki.Common/Http/WebConstants.cs b/project/Aki.Common/Http/WebConstants.cs deleted file mode 100644 index 57b797e..0000000 --- a/project/Aki.Common/Http/WebConstants.cs +++ /dev/null @@ -1,78 +0,0 @@ -#region DEPRECATED, REMOVE IN 3.8.1 - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Aki.Common.Http -{ - [Obsolete("WebConstants is deprecated, please use System.Net.Http functionality instead.")] - public static class WebConstants - { - [Obsolete("Get is deprecated, please use HttpMethod.Get instead.")] - public const string Get = "GET"; - - [Obsolete("Head is deprecated, please use HttpMethod.Head instead.")] - public const string Head = "HEAD"; - - [Obsolete("Post is deprecated, please use HttpMethod.Post instead.")] - public const string Post = "POST"; - - [Obsolete("Put is deprecated, please use HttpMethod.Put instead.")] - public const string Put = "PUT"; - - [Obsolete("Delete is deprecated, please use HttpMethod.Delete instead.")] - public const string Delete = "DELETE"; - - [Obsolete("Connect is deprecated, please use HttpMethod.Connect instead.")] - public const string Connect = "CONNECT"; - - [Obsolete("Options is deprecated, please use HttpMethod.Options instead.")] - public const string Options = "OPTIONS"; - - [Obsolete("Trace is deprecated, please use HttpMethod.Trace instead.")] - public const string Trace = "TRACE"; - - [Obsolete("Mime is deprecated, there is sadly no replacement.")] - public static Dictionary Mime { get; private set; } - - static WebConstants() - { - Mime = new Dictionary() - { - { ".bin", "application/octet-stream" }, - { ".txt", "text/plain" }, - { ".htm", "text/html" }, - { ".html", "text/html" }, - { ".css", "text/css" }, - { ".js", "text/javascript" }, - { ".jpeg", "image/jpeg" }, - { ".jpg", "image/jpeg" }, - { ".png", "image/png" }, - { ".ico", "image/vnd.microsoft.icon" }, - { ".json", "application/json" } - }; - } - - [Obsolete("IsValidMethod is deprecated, please check against HttpMethod entries instead.")] - public static bool IsValidMethod(string method) - { - return method == Get - || method == Head - || method == Post - || method == Put - || method == Delete - || method == Connect - || method == Options - || method == Trace; - } - - [Obsolete("isValidMime is deprecated, there is sadly no replacement available.")] - public static bool IsValidMime(string mime) - { - return Mime.Any(x => x.Value == mime); - } - } -} - -#endregion \ No newline at end of file diff --git a/project/Aki.Core/Aki.Core.csproj b/project/Aki.Core/Aki.Core.csproj index f762b57..a4622ed 100644 --- a/project/Aki.Core/Aki.Core.csproj +++ b/project/Aki.Core/Aki.Core.csproj @@ -2,13 +2,13 @@ net471 - aki-core + spt-core Release - Aki - Copyright @ Aki 2024 + SPT + Copyright @ SPT 2024 diff --git a/project/Aki.Core/AkiCorePlugin.cs b/project/Aki.Core/AkiCorePlugin.cs index db5436d..d8c2648 100644 --- a/project/Aki.Core/AkiCorePlugin.cs +++ b/project/Aki.Core/AkiCorePlugin.cs @@ -15,7 +15,7 @@ namespace Aki.Core { _logger = Logger; - Logger.LogInfo("Loading: Aki.Core"); + Logger.LogInfo("Loading: SPT.Core"); try { @@ -36,7 +36,7 @@ namespace Aki.Core throw; } - Logger.LogInfo("Completed: Aki.Core"); + Logger.LogInfo("Completed: SPT.Core"); } } } diff --git a/project/Aki.Core/Patches/GameValidationPatch.cs b/project/Aki.Core/Patches/GameValidationPatch.cs index 0311cb4..e427df5 100644 --- a/project/Aki.Core/Patches/GameValidationPatch.cs +++ b/project/Aki.Core/Patches/GameValidationPatch.cs @@ -8,7 +8,7 @@ namespace Aki.Core.Patches { public class GameValidationPatch : ModulePatch { - private const string PluginName = "Aki.Core"; + private const string PluginName = "SPT.Core"; private const string ErrorMessage = "Validation failed"; private static BepInEx.Logging.ManualLogSource _logger = null; private static bool _hasRun = false; diff --git a/project/Aki.Core/Utils/ValidationUtil.cs b/project/Aki.Core/Utils/ValidationUtil.cs index b51dfee..a6b09df 100644 --- a/project/Aki.Core/Utils/ValidationUtil.cs +++ b/project/Aki.Core/Utils/ValidationUtil.cs @@ -27,9 +27,9 @@ namespace Aki.Core.Utils new FileInfo(Path.Combine(v2, "UnityCrashHandler64.exe")) }; - ServerLog.Debug("Aki.Core", Gfs(v2, "UnityCrashHandler64.exe")?.Length.ToString() ?? "0"); - ServerLog.Debug("Aki.Core", Gfs(v2, "Uninstall.exe")?.Length.ToString() ?? "0"); - ServerLog.Debug("Aki.Core", Gfs(v2, "Register.bat")?.Length.ToString() ?? "0"); + ServerLog.Debug("SPT.Core", Gfs(v2, "UnityCrashHandler64.exe")?.Length.ToString() ?? "0"); + ServerLog.Debug("SPT.Core", Gfs(v2, "Uninstall.exe")?.Length.ToString() ?? "0"); + ServerLog.Debug("SPT.Core", Gfs(v2, "Register.bat")?.Length.ToString() ?? "0"); v0 = v4.Length - 1; diff --git a/project/Aki.Custom/Airdrops/AirdropsManager.cs b/project/Aki.Custom/Airdrops/AirdropsManager.cs index ad5cded..538cf81 100644 --- a/project/Aki.Custom/Airdrops/AirdropsManager.cs +++ b/project/Aki.Custom/Airdrops/AirdropsManager.cs @@ -35,7 +35,7 @@ namespace Aki.Custom.Airdrops } catch { - Debug.LogError("[AKI-AIRDROPS]: Unable to get config from server, airdrop won't occur"); + Debug.LogError("[SPT-AIRDROPS]: Unable to get config from server, airdrop won't occur"); Destroy(this); throw; } @@ -52,7 +52,7 @@ namespace Aki.Custom.Airdrops } catch { - Debug.LogError("[AKI-AIRDROPS]: Unable to create plane or crate, airdrop won't occur"); + Debug.LogError("[SPT-AIRDROPS]: Unable to create plane or crate, airdrop won't occur"); Destroy(this); throw; } @@ -98,7 +98,7 @@ namespace Aki.Custom.Airdrops } catch { - Debug.LogError("[AKI-AIRDROPS]: An error occurred during the airdrop FixedUpdate process"); + Debug.LogError("[SPT-AIRDROPS]: An error occurred during the airdrop FixedUpdate process"); Destroy(airdropBox.gameObject); Destroy(airdropPlane.gameObject); Destroy(this); diff --git a/project/Aki.Custom/Airdrops/Utils/AirdropUtil.cs b/project/Aki.Custom/Airdrops/Utils/AirdropUtil.cs index f102606..5dad29e 100644 --- a/project/Aki.Custom/Airdrops/Utils/AirdropUtil.cs +++ b/project/Aki.Custom/Airdrops/Utils/AirdropUtil.cs @@ -69,7 +69,7 @@ namespace Aki.Custom.Airdrops.Utils break; } default: - Debug.LogError($"[AKI-AIRDROPS]: Map with name {playerLocation} not handled, defaulting spawn chance to 25%"); + Debug.LogError($"[SPT-AIRDROPS]: Map with name {playerLocation} not handled, defaulting spawn chance to 25%"); result = 25; break; } @@ -104,7 +104,7 @@ namespace Aki.Custom.Airdrops.Utils if (flareAirdropPoints.Count == 0 && isFlare) { - Debug.LogError($"[AKI-AIRDROPS]: Airdrop called in by flare, Unable to find an airdropPoint within {flareSpawnRadiusDistance}m, defaulting to normal drop"); + Debug.LogError($"[SPT-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()); } diff --git a/project/Aki.Custom/Airdrops/Utils/ItemFactoryUtil.cs b/project/Aki.Custom/Airdrops/Utils/ItemFactoryUtil.cs index 031413f..b0ecbb7 100644 --- a/project/Aki.Custom/Airdrops/Utils/ItemFactoryUtil.cs +++ b/project/Aki.Custom/Airdrops/Utils/ItemFactoryUtil.cs @@ -31,7 +31,7 @@ namespace Aki.Custom.Airdrops.Utils } else { - Debug.LogError($"[AKI-AIRDROPS]: unable to find template: {containerId}"); + Debug.LogError($"[SPT-AIRDROPS]: unable to find template: {containerId}"); } } diff --git a/project/Aki.Custom/Aki.Custom.csproj b/project/Aki.Custom/Aki.Custom.csproj index e5d4afe..7802d72 100644 --- a/project/Aki.Custom/Aki.Custom.csproj +++ b/project/Aki.Custom/Aki.Custom.csproj @@ -2,13 +2,13 @@ net471 - aki-custom + spt-custom Release - Aki - Copyright @ Aki 2024 + SPT + Copyright @ SPT 2024 diff --git a/project/Aki.Custom/AkiCustomPlugin.cs b/project/Aki.Custom/AkiCustomPlugin.cs index 0c4e4ae..20e1f83 100644 --- a/project/Aki.Custom/AkiCustomPlugin.cs +++ b/project/Aki.Custom/AkiCustomPlugin.cs @@ -16,7 +16,7 @@ namespace Aki.Custom { public void Awake() { - Logger.LogInfo("Loading: Aki.Custom"); + Logger.LogInfo("Loading: SPT.Custom"); try { @@ -56,6 +56,7 @@ namespace Aki.Custom new RagfairFeePatch().Enable(); new ScavQuestPatch().Enable(); new FixBrokenSpawnOnSandboxPatch().Enable(); + new BTRControllerInitPatch().Enable(); new BTRPathLoadPatch().Enable(); new BTRActivateTraderDialogPatch().Enable(); new BTRInteractionPatch().Enable(); @@ -70,11 +71,13 @@ namespace Aki.Custom new BTREndRaidItemDeliveryPatch().Enable(); new BTRDestroyAtRaidEndPatch().Enable(); new BTRVehicleMovementSpeedPatch().Enable(); + new BTRPathConfigMapPrefixPatch().Enable(); new ScavItemCheckmarkPatch().Enable(); new ResetTraderServicesPatch().Enable(); new CultistAmuletRemovalPatch().Enable(); new HalloweenExtractPatch().Enable(); new ClampRagdollPatch().Enable(); + new DisablePvEPatch().Enable(); HookObject.AddOrGetComponent(); } diff --git a/project/Aki.Custom/BTR/BTRManager.cs b/project/Aki.Custom/BTR/BTRManager.cs index 36a7d80..63b3723 100644 --- a/project/Aki.Custom/BTR/BTRManager.cs +++ b/project/Aki.Custom/BTR/BTRManager.cs @@ -6,11 +6,10 @@ using EFT.InventoryLogic; using EFT.UI; using EFT.Vehicle; using HarmonyLib; -using System; using System.Collections; using System.Collections.Generic; using System.Linq; -using System.Reflection; +using System.Threading.Tasks; using UnityEngine; using Random = UnityEngine.Random; @@ -27,6 +26,7 @@ namespace Aki.Custom.BTR private BTRView btrClientSide; private BotOwner btrBotShooter; private BTRDataPacket btrDataPacket = default; + private bool btrInitialized = false; private bool btrBotShooterInitialized = false; private float coverFireTime = 90f; @@ -48,17 +48,9 @@ namespace Aki.Custom.BTR private Player.FirearmController firearmController; private WeaponSoundPlayer weaponSoundPlayer; - private MethodInfo _updateTaxiPriceMethod; + private float originalDamageCoeff; - private float originalDamageCoeff; - - BTRManager() - { - Type btrControllerType = typeof(BTRControllerClass); - _updateTaxiPriceMethod = AccessTools.GetDeclaredMethods(btrControllerType).Single(IsUpdateTaxiPriceMethod); - } - - private void Awake() + private async void Awake() { try { @@ -76,11 +68,11 @@ namespace Aki.Custom.BTR btrController = gameWorld.BtrController; - InitBtr(); + await InitBtr(); } catch { - ConsoleScreen.LogError("[AKI-BTR] Unable to spawn BTR. Check logs."); + ConsoleScreen.LogError("[SPT-BTR] Unable to spawn BTR. Check logs."); Destroy(this); throw; } @@ -108,7 +100,7 @@ namespace Aki.Custom.BTR } else if (interactPacket.SideId == 1 && playerGoIn) { - if (interactPacket.SlotId == 0) + if (interactPacket.SlotId == 0) { btrServerSide.RightSlot0State = 1; } @@ -118,29 +110,25 @@ namespace Aki.Custom.BTR } } - // If the player is going into the BTR, store their damage coefficient - // and set it to 0, so they don't die while inside the BTR - if (interactPacket.InteractionType == EInteractionType.GoIn) - { - originalDamageCoeff = gameWorld.MainPlayer.ActiveHealthController.DamageCoeff; - gameWorld.MainPlayer.ActiveHealthController.SetDamageCoeff(0f); + // If the player is going into the BTR, store their damage coefficient + // and set it to 0, so they don't die while inside the BTR + if (interactPacket.InteractionType == EInteractionType.GoIn) + { + originalDamageCoeff = gameWorld.MainPlayer.ActiveHealthController.DamageCoeff; + gameWorld.MainPlayer.ActiveHealthController.SetDamageCoeff(0f); - } - // Otherwise restore the damage coefficient - else if (interactPacket.InteractionType == EInteractionType.GoOut) - { - gameWorld.MainPlayer.ActiveHealthController.SetDamageCoeff(originalDamageCoeff); - } - } - - // Find `BTRControllerClass.method_9(PathDestination currentDestinationPoint, bool lastRoutePoint)` - private bool IsUpdateTaxiPriceMethod(MethodInfo method) - { - return (method.GetParameters().Length == 2 && method.GetParameters()[0].ParameterType == typeof(PathDestination)); + } + // Otherwise restore the damage coefficient + else if (interactPacket.InteractionType == EInteractionType.GoOut) + { + gameWorld.MainPlayer.ActiveHealthController.SetDamageCoeff(originalDamageCoeff); + } } private void Update() { + if (!btrInitialized) return; + btrController.SyncBTRVehicleFromServer(UpdateDataPacket()); if (btrController.BotShooterBtr == null) return; @@ -169,9 +157,11 @@ namespace Aki.Custom.BTR } } - private void InitBtr() + private async Task InitBtr() { // Initial setup + await btrController.InitBtrController(); + botEventHandler = Singleton.Instance; var botsController = Singleton.Instance.BotsController; btrBotService = botsController.BotTradersServices.BTRServices; @@ -187,6 +177,11 @@ namespace Aki.Custom.BTR ConfigureSettingsFromServer(); var btrMapConfig = btrController.MapPathsConfiguration; + if (btrMapConfig == null) + { + ConsoleScreen.LogError($"{nameof(btrController.MapPathsConfiguration)}"); + return; + } btrServerSide.CurrentPathConfig = btrMapConfig.PathsConfiguration.pathsConfigurations.RandomElement(); btrServerSide.Initialization(btrMapConfig); btrController.method_14(); // creates and assigns the BTR a fake stash @@ -206,13 +201,15 @@ namespace Aki.Custom.BTR // Initialise turret variables btrTurretServer = btrServerSide.BTRTurret; var btrTurretDefaultTargetTransform = (Transform)AccessTools.Field(btrTurretServer.GetType(), "defaultTargetTransform").GetValue(btrTurretServer); - isTurretInDefaultRotation = btrTurretServer.targetTransform == btrTurretDefaultTargetTransform + isTurretInDefaultRotation = btrTurretServer.targetTransform == btrTurretDefaultTargetTransform && btrTurretServer.targetPosition == btrTurretServer.defaultAimingPosition; btrMachineGunAmmo = (BulletClass)BTRUtil.CreateItem(BTRUtil.BTRMachineGunAmmoTplId); btrMachineGunWeapon = BTRUtil.CreateItem(BTRUtil.BTRMachineGunWeaponTplId); // Pull services data for the BTR from the server TraderServicesManager.Instance.GetTraderServicesDataFromServer(BTRUtil.BTRTraderId); + + btrInitialized = true; } private void ConfigureSettingsFromServer() @@ -249,7 +246,7 @@ namespace Aki.Custom.BTR TraderServicesManager.Instance.RemovePurchasedService(ETraderServiceType.PlayerTaxi, BTRUtil.BTRTraderId); // Update the prices for the taxi service - _updateTaxiPriceMethod.Invoke(btrController, new object[] { destinationPoint, isFinal }); + btrController.UpdateTaxiPrice(destinationPoint, isFinal); // Update the UI TraderServicesManager.Instance.GetTraderServicesDataFromServer(BTRUtil.BTRTraderId); @@ -257,14 +254,9 @@ namespace Aki.Custom.BTR private bool IsBtrService(ETraderServiceType serviceType) { - if (serviceType == ETraderServiceType.BtrItemsDelivery - || serviceType == ETraderServiceType.PlayerTaxi - || serviceType == ETraderServiceType.BtrBotCover) - { - return true; - } - - return false; + return serviceType == ETraderServiceType.BtrItemsDelivery + || serviceType == ETraderServiceType.PlayerTaxi + || serviceType == ETraderServiceType.BtrBotCover; } private void BtrTraderServicePurchased(ETraderServiceType serviceType, string subserviceId) @@ -338,7 +330,7 @@ namespace Aki.Custom.BTR } catch { - ConsoleScreen.LogError("[AKI-BTR] lastInteractedBtrSide is null when it shouldn't be. Check logs."); + ConsoleScreen.LogError($"[SPT-BTR] {nameof(lastInteractedBtrSide)} is null when it shouldn't be. Check logs."); throw; } } @@ -349,8 +341,8 @@ namespace Aki.Custom.BTR btrDataPacket.rotation = btrServerSide.transform.rotation; if (btrTurretServer != null && btrTurretServer.gunsBlockRoot != null) { - btrDataPacket.turretRotation = btrTurretServer.transform.rotation; - btrDataPacket.gunsBlockRotation = btrTurretServer.gunsBlockRoot.rotation; + btrDataPacket.turretRotation = btrTurretServer.transform.localEulerAngles.y; + btrDataPacket.gunsBlockRotation = btrTurretServer.gunsBlockRoot.localEulerAngles.x; } btrDataPacket.State = (byte)btrServerSide.BtrState; btrDataPacket.RouteState = (byte)btrServerSide.VehicleRouteState; @@ -390,16 +382,11 @@ namespace Aki.Custom.BTR private bool HasTarget() { - if (currentTarget != null) - { - return true; - } - - return false; + return currentTarget != null; } private void SetAim() - { + { if (currentTarget.IsVisible) { Vector3 targetPos = currentTarget.CurrPosition; @@ -412,8 +399,8 @@ namespace Aki.Custom.BTR else { Vector3 targetLastPos = currentTarget.EnemyLastPositionReal; - if (btrTurretServer.CheckPositionInAimingZone(targetLastPos) - && Time.time - currentTarget.PersonalLastSeenTime < 3f + if (btrTurretServer.CheckPositionInAimingZone(targetLastPos) + && Time.time - currentTarget.PersonalLastSeenTime < 3f && btrTurretServer.targetPosition != targetLastPos) { btrTurretServer.EnableAimingPosition(targetLastPos); @@ -428,12 +415,7 @@ namespace Aki.Custom.BTR private bool CanShoot() { - if (currentTarget.IsVisible && btrBotShooter.BotBtrData.CanShoot()) - { - return true; - } - - return false; + return currentTarget.IsVisible && btrBotShooter.BotBtrData.CanShoot(); } private void StartShooting() @@ -469,16 +451,18 @@ namespace Aki.Custom.BTR { targetHeadPos = currentTarget.Person.PlayerBones.Head.position; } + Vector3 aimDirection = Vector3.Normalize(targetHeadPos - machineGunMuzzle.position); ballisticCalculator.Shoot(btrMachineGunAmmo, machineGunMuzzle.position, aimDirection, btrBotShooter.ProfileId, btrMachineGunWeapon, 1f, 0); - firearmController.method_54(weaponSoundPlayer, btrMachineGunAmmo, machineGunMuzzle.position, aimDirection, false); + firearmController.PlayWeaponSound(weaponSoundPlayer, btrMachineGunAmmo, machineGunMuzzle.position, aimDirection, false); + burstCount--; yield return new WaitForSecondsRealtime(0.092308f); // 650 RPM } float waitTime = Random.Range(machineGunRecoveryTime.x, machineGunRecoveryTime.y); yield return new WaitForSecondsRealtime(waitTime); - + isShooting = false; } @@ -504,13 +488,13 @@ namespace Aki.Custom.BTR if (btrClientSide != null) { - Debug.LogWarning("[AKI-BTR] BTRManager - Destroying btrClientSide"); + Debug.LogWarning($"[SPT-BTR] {nameof(BTRManager)} - Destroying btrClientSide"); Destroy(btrClientSide.gameObject); } if (btrServerSide != null) { - Debug.LogWarning("[AKI-BTR] BTRManager - Destroying btrServerSide"); + Debug.LogWarning($"[SPT-BTR] {nameof(BTRManager)} - Destroying btrServerSide"); Destroy(btrServerSide.gameObject); } } diff --git a/project/Aki.Custom/BTR/BTRRoadKillTrigger.cs b/project/Aki.Custom/BTR/BTRRoadKillTrigger.cs index 8b819eb..44e2896 100644 --- a/project/Aki.Custom/BTR/BTRRoadKillTrigger.cs +++ b/project/Aki.Custom/BTR/BTRRoadKillTrigger.cs @@ -8,7 +8,7 @@ namespace Aki.Custom.BTR { public override bool IsStatic => false; - public override void AddPenalty(GInterface94 player) + public override void AddPenalty(GInterface106 player) { } @@ -16,7 +16,7 @@ namespace Aki.Custom.BTR { } - public override void ProceedDamage(GInterface94 player, BodyPartCollider bodyPart) + public override void ProceedDamage(GInterface106 player, BodyPartCollider bodyPart) { bodyPart.ApplyInstantKill(new DamageInfo() { @@ -31,7 +31,7 @@ namespace Aki.Custom.BTR }); } - public override void RemovePenalty(GInterface94 player) + public override void RemovePenalty(GInterface106 player) { } } diff --git a/project/Aki.Custom/BTR/Patches/BTRActivateTraderDialogPatch.cs b/project/Aki.Custom/BTR/Patches/BTRActivateTraderDialogPatch.cs index d0c44a1..5eb3772 100644 --- a/project/Aki.Custom/BTR/Patches/BTRActivateTraderDialogPatch.cs +++ b/project/Aki.Custom/BTR/Patches/BTRActivateTraderDialogPatch.cs @@ -6,7 +6,7 @@ using EFT.Vehicle; using HarmonyLib; using System; using System.Reflection; -using BTRDialog = EFT.UI.TraderDialogScreen.GClass3132; +using BTRDialog = EFT.UI.TraderDialogScreen.GClass3153; namespace Aki.Custom.BTR.Patches { @@ -28,12 +28,7 @@ namespace Aki.Custom.BTR.Patches { FieldInfo btrField = type.GetField("btr"); - if (btrField != null && btrField.FieldType == typeof(BTRSide)) - { - return true; - } - - return false; + return btrField != null && btrField.FieldType == typeof(BTRSide); } [PatchPrefix] diff --git a/project/Aki.Custom/BTR/Patches/BTRBotAttachPatch.cs b/project/Aki.Custom/BTR/Patches/BTRBotAttachPatch.cs index 7c8312f..ab6a6c0 100644 --- a/project/Aki.Custom/BTR/Patches/BTRBotAttachPatch.cs +++ b/project/Aki.Custom/BTR/Patches/BTRBotAttachPatch.cs @@ -60,7 +60,7 @@ namespace Aki.Custom.BTR.Patches var valueTuple = (ValueTuple)_valueTuple0Field.GetValue(__instance); if (!valueTuple.Item2 && !InitTurretView(__instance, turretPlayer)) { - Logger.LogError("[AKI-BTR] BTRBotAttachPatch - BtrBot initialization failed"); + Logger.LogError("[SPT-BTR] BTRBotAttachPatch - BtrBot initialization failed"); return false; } diff --git a/project/Aki.Custom/BTR/Patches/BTRControllerInitPatch.cs b/project/Aki.Custom/BTR/Patches/BTRControllerInitPatch.cs new file mode 100644 index 0000000..44ca79e --- /dev/null +++ b/project/Aki.Custom/BTR/Patches/BTRControllerInitPatch.cs @@ -0,0 +1,34 @@ +using Aki.Reflection.Patching; +using HarmonyLib; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; + +namespace Aki.Custom.BTR.Patches +{ + public class BTRControllerInitPatch : ModulePatch + { + protected override MethodBase GetTargetMethod() + { + return AccessTools.FirstMethod(typeof(BTRControllerClass), IsTargetMethod); + } + + private bool IsTargetMethod(MethodInfo method) + { + ParameterInfo[] parameters = method.GetParameters(); + + return method.ReturnType == typeof(Task) + && parameters.Length == 1 + && parameters[0].ParameterType == typeof(CancellationToken); + } + + [PatchPrefix] + private static bool PatchPrefix(ref Task __result) + { + // The BTRControllerClass constructor expects the original method to return a Task, + // as it calls another method on said Task. + __result = Task.CompletedTask; + return false; + } + } +} diff --git a/project/Aki.Custom/BTR/Patches/BTRDestroyAtRaidEndPatch.cs b/project/Aki.Custom/BTR/Patches/BTRDestroyAtRaidEndPatch.cs index ab399eb..ccb5abd 100644 --- a/project/Aki.Custom/BTR/Patches/BTRDestroyAtRaidEndPatch.cs +++ b/project/Aki.Custom/BTR/Patches/BTRDestroyAtRaidEndPatch.cs @@ -11,7 +11,7 @@ namespace Aki.Custom.BTR.Patches { protected override MethodBase GetTargetMethod() { - return AccessTools.Method(typeof(BaseLocalGame), nameof(BaseLocalGame.Stop)); + return AccessTools.Method(typeof(BaseLocalGame), nameof(BaseLocalGame.Stop)); } [PatchPrefix] @@ -26,7 +26,7 @@ namespace Aki.Custom.BTR.Patches var btrManager = gameWorld.GetComponent(); if (btrManager != null) { - Logger.LogWarning("[AKI-BTR] BTRDestroyAtRaidEndPatch - Raid Ended: Destroying BTRManager"); + Logger.LogWarning("[SPT-BTR] BTRDestroyAtRaidEndPatch - Raid Ended: Destroying BTRManager"); Object.Destroy(btrManager); } } diff --git a/project/Aki.Custom/BTR/Patches/BTREndRaidItemDeliveryPatch.cs b/project/Aki.Custom/BTR/Patches/BTREndRaidItemDeliveryPatch.cs index 8eec3b3..7758b28 100644 --- a/project/Aki.Custom/BTR/Patches/BTREndRaidItemDeliveryPatch.cs +++ b/project/Aki.Custom/BTR/Patches/BTREndRaidItemDeliveryPatch.cs @@ -32,13 +32,13 @@ namespace Aki.Custom.BTR.Patches GameWorld gameWorld = Singleton.Instance; if (gameWorld == null) { - Logger.LogError("[AKI-BTR] BTREndRaidItemDeliveryPatch - GameWorld is null"); + Logger.LogError("[SPT-BTR] BTREndRaidItemDeliveryPatch - GameWorld is null"); return; } var player = gameWorld.MainPlayer; if (player == null) { - Logger.LogError("[AKI-BTR] BTREndRaidItemDeliveryPatch - Player is null"); + Logger.LogError("[SPT-BTR] BTREndRaidItemDeliveryPatch - Player is null"); return; } @@ -50,7 +50,7 @@ namespace Aki.Custom.BTR.Patches if (!gameWorld.BtrController.HasNonEmptyTransferContainer(player.Profile.Id)) { - Logger.LogDebug("[AKI-BTR] BTREndRaidItemDeliveryPatch - No items in transfer container"); + Logger.LogDebug("[SPT-BTR] BTREndRaidItemDeliveryPatch - No items in transfer container"); return; } diff --git a/project/Aki.Custom/BTR/Patches/BTRExtractPassengersPatch.cs b/project/Aki.Custom/BTR/Patches/BTRExtractPassengersPatch.cs index 68e5744..75c0002 100644 --- a/project/Aki.Custom/BTR/Patches/BTRExtractPassengersPatch.cs +++ b/project/Aki.Custom/BTR/Patches/BTRExtractPassengersPatch.cs @@ -35,7 +35,7 @@ namespace Aki.Custom.BTR.Patches BTRView btrView = gameWorld.BtrController.BtrView; if (btrView == null) { - Logger.LogError($"[AKI-BTR] BTRExtractPassengersPatch - btrView is null"); + Logger.LogError($"[SPT-BTR] BTRExtractPassengersPatch - btrView is null"); return; } diff --git a/project/Aki.Custom/BTR/Patches/BTRInteractionPatch.cs b/project/Aki.Custom/BTR/Patches/BTRInteractionPatch.cs index 82727d2..e92f5cc 100644 --- a/project/Aki.Custom/BTR/Patches/BTRInteractionPatch.cs +++ b/project/Aki.Custom/BTR/Patches/BTRInteractionPatch.cs @@ -46,7 +46,7 @@ namespace Aki.Custom.BTR.Patches BTRView btrView = gameWorld.BtrController.BtrView; if (btrView == null) { - Logger.LogError("[AKI-BTR] BTRInteractionPatch - btrView is null"); + Logger.LogError("[SPT-BTR] BTRInteractionPatch - btrView is null"); return; } diff --git a/project/Aki.Custom/BTR/Patches/BTRIsDoorsClosedPatch.cs b/project/Aki.Custom/BTR/Patches/BTRIsDoorsClosedPatch.cs index 379b893..f747290 100644 --- a/project/Aki.Custom/BTR/Patches/BTRIsDoorsClosedPatch.cs +++ b/project/Aki.Custom/BTR/Patches/BTRIsDoorsClosedPatch.cs @@ -19,14 +19,14 @@ namespace Aki.Custom.BTR.Patches var gameWorld = Singleton.Instance; if (gameWorld == null) { - Logger.LogError("[AKI-BTR] BTRIsDoorsClosedPatch - GameWorld is null"); + Logger.LogError("[SPT-BTR] BTRIsDoorsClosedPatch - GameWorld is null"); return true; } var serverSideBTR = gameWorld.BtrController.BtrVehicle; if (serverSideBTR == null) { - Logger.LogError("[AKI-BTR] BTRIsDoorsClosedPatch - serverSideBTR is null"); + Logger.LogError("[SPT-BTR] BTRIsDoorsClosedPatch - serverSideBTR is null"); return true; } diff --git a/project/Aki.Custom/BTR/Patches/BTRPatch.cs b/project/Aki.Custom/BTR/Patches/BTRPatch.cs index 8a5d782..e6e6f6e 100644 --- a/project/Aki.Custom/BTR/Patches/BTRPatch.cs +++ b/project/Aki.Custom/BTR/Patches/BTRPatch.cs @@ -39,7 +39,7 @@ namespace Aki.Custom.BTR.Patches } catch (System.Exception) { - ConsoleScreen.LogError("[AKI-BTR] Exception thrown, check logs."); + ConsoleScreen.LogError("[SPT-BTR] Exception thrown, check logs."); throw; } } diff --git a/project/Aki.Custom/BTR/Patches/BTRPathConfigMapPrefixPatch.cs b/project/Aki.Custom/BTR/Patches/BTRPathConfigMapPrefixPatch.cs new file mode 100644 index 0000000..41ea27f --- /dev/null +++ b/project/Aki.Custom/BTR/Patches/BTRPathConfigMapPrefixPatch.cs @@ -0,0 +1,53 @@ +using System; +using System.Reflection; +using Aki.Reflection.Patching; +using Comfort.Common; +using EFT; +using EFT.UI; +using HarmonyLib; + +namespace Aki.Custom.BTR.Patches +{ + /// + /// Fixes an issue where in a pathConfig.once type, finding destination path points was impossible because destinationID would be prefixed with "Map/", which the pathPoints do not contain. + /// + public class BTRPathConfigMapPrefixPatch : ModulePatch + { + protected override MethodBase GetTargetMethod() + { + return AccessTools.FirstMethod(typeof(BTRControllerClass), IsTargetMethod); + } + + private bool IsTargetMethod(MethodInfo method) + { + ParameterInfo[] parameters = method.GetParameters(); + + // BTRControllerClass.method_8 + return method.ReturnType == typeof(int) + && parameters.Length == 2 + && parameters[0].ParameterType == typeof(string) + && parameters[0].Name == "destinationID" + && parameters[1].ParameterType == typeof(int) + && parameters[1].Name == "currentDestinationIndex"; + } + + [PatchPrefix] + private static void PatchPrefix(ref string destinationID) + { + try + { + var locationIdSlash = Singleton.Instance.LocationId + "/"; + + if (destinationID.Contains(locationIdSlash)) + { + // destinationID is in the form of "Map/pX", strip the "Map/" part. + destinationID = destinationID.Replace(locationIdSlash, ""); + } + } + catch (Exception) + { + ConsoleScreen.LogError($"[SPT-BTR] Exception in {nameof(BTRPathConfigMapPrefixPatch)}, check logs."); + } + } + } +} \ No newline at end of file diff --git a/project/Aki.Custom/BTR/Patches/BTRReceiveDamageInfoPatch.cs b/project/Aki.Custom/BTR/Patches/BTRReceiveDamageInfoPatch.cs index 427a064..6fa3fe3 100644 --- a/project/Aki.Custom/BTR/Patches/BTRReceiveDamageInfoPatch.cs +++ b/project/Aki.Custom/BTR/Patches/BTRReceiveDamageInfoPatch.cs @@ -14,7 +14,16 @@ namespace Aki.Custom.BTR.Patches { protected override MethodBase GetTargetMethod() { - return AccessTools.Method(typeof(BTRView), nameof(BTRView.method_1)); + return AccessTools.FirstMethod(typeof(BTRView), IsTargetMethod); + } + + private bool IsTargetMethod(MethodBase method) + { + var parameters = method.GetParameters(); + + return parameters.Length == 1 + && parameters[0].ParameterType == typeof(DamageInfo) + && parameters[0].Name == "damageInfo"; } [PatchPrefix] @@ -23,12 +32,15 @@ namespace Aki.Custom.BTR.Patches var botEventHandler = Singleton.Instance; if (botEventHandler == null) { - Logger.LogError($"[AKI-BTR] BTRReceiveDamageInfoPatch - BotEventHandler is null"); + Logger.LogError($"[SPT-BTR] {nameof(BTRReceiveDamageInfoPatch)} - BotEventHandler is null"); return; } var shotBy = (Player)damageInfo.Player.iPlayer; - botEventHandler.InterruptTraderServiceBtrSupportByBetrayer(shotBy); + if (shotBy != null) + { + botEventHandler.InterruptTraderServiceBtrSupportByBetrayer(shotBy); + } } } } diff --git a/project/Aki.Custom/BTR/Utils/BTRReflectionHelper.cs b/project/Aki.Custom/BTR/Utils/BTRReflectionHelper.cs new file mode 100644 index 0000000..75deab2 --- /dev/null +++ b/project/Aki.Custom/BTR/Utils/BTRReflectionHelper.cs @@ -0,0 +1,66 @@ +using EFT; +using EFT.Vehicle; +using HarmonyLib; +using System; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using UnityEngine; + +namespace Aki.Custom.BTR.Utils +{ + public static class BTRReflectionHelper + { + private static Type _btrControllerType = typeof(BTRControllerClass); + private static Type _firearmControllerType = typeof(Player.FirearmController); + + private static MethodInfo _initBtrControllerMethod = AccessTools.GetDeclaredMethods(_btrControllerType).Single(IsInitBtrControllerMethod); + private static MethodInfo _updateTaxiPriceMethod = AccessTools.GetDeclaredMethods(_btrControllerType).Single(IsUpdateTaxiPriceMethod); + + private static MethodInfo _playWeaponSoundMethod = AccessTools.GetDeclaredMethods(_firearmControllerType).Single(IsPlayWeaponSoundMethod); + + public static Task InitBtrController(this BTRControllerClass controller) + { + return (Task)_initBtrControllerMethod.Invoke(controller, null); + } + + public static void UpdateTaxiPrice(this BTRControllerClass controller, PathDestination destinationPoint, bool isFinal) + { + _updateTaxiPriceMethod.Invoke(controller, new object[] { destinationPoint, isFinal }); + } + + public static void PlayWeaponSound(this Player.FirearmController controller, WeaponSoundPlayer weaponSoundPlayer, BulletClass ammo, Vector3 shotPosition, Vector3 shotDirection, bool multiShot) + { + _playWeaponSoundMethod.Invoke(controller, new object[] { weaponSoundPlayer, ammo, shotPosition, shotDirection, multiShot }); + } + + // Find `BTRControllerClass.method_1()` + private static bool IsInitBtrControllerMethod(MethodInfo method) + { + return method.ReturnType == typeof(Task) + && method.GetParameters().Length == 0; + } + + // Find `BTRControllerClass.method_9(PathDestination currentDestinationPoint, bool lastRoutePoint)` + private static bool IsUpdateTaxiPriceMethod(MethodInfo method) + { + ParameterInfo[] parameters = method.GetParameters(); + + return parameters.Length == 2 + && parameters[0].ParameterType == typeof(PathDestination); + } + + // Find `Player.FirearmController.method_54(WeaponSoundPlayer weaponSoundPlayer, BulletClass ammo, Vector3 shotPosition, Vector3 shotDirection, bool multiShot)` + private static bool IsPlayWeaponSoundMethod(MethodInfo method) + { + ParameterInfo[] parameters = method.GetParameters(); + + return parameters.Length == 5 + && parameters[0].ParameterType == typeof(WeaponSoundPlayer) + && parameters[1].ParameterType == typeof(BulletClass) + && parameters[2].ParameterType == typeof(Vector3) + && parameters[3].ParameterType == typeof(Vector3) + && parameters[4].ParameterType == typeof(bool); + } + } +} diff --git a/project/Aki.Custom/Models/BundleInfo.cs b/project/Aki.Custom/Models/BundleInfo.cs deleted file mode 100644 index b393746..0000000 --- a/project/Aki.Custom/Models/BundleInfo.cs +++ /dev/null @@ -1,23 +0,0 @@ -#region DEPRECATED, REMOVE IN 3.8.1 - -using System; - -namespace Aki.Custom.Models -{ - [Obsolete("BundleInfo is deprecated, please use BundleItem instead.")] - public class BundleInfo - { - public string Key { get; } - public string Path { get; set; } - public string[] DependencyKeys { get; } - - public BundleInfo(string key, string path, string[] dependencyKeys) - { - Key = key; - Path = path; - DependencyKeys = dependencyKeys; - } - } -} - -#endregion \ No newline at end of file diff --git a/project/Aki.Custom/Models/DifficultyInfo.cs b/project/Aki.Custom/Models/DifficultyInfo.cs new file mode 100644 index 0000000..721111a --- /dev/null +++ b/project/Aki.Custom/Models/DifficultyInfo.cs @@ -0,0 +1,43 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace Aki.Custom.Models +{ + [Serializable] + public struct DifficultyInfo + { + public Dictionary this[string key] + { + get + { + switch (key) + { + case "easy": + return easy; + case "hard": + return hard; + case "impossible": + return impossible; + case "normal": + return normal; + default: + throw new ArgumentException($"Difficulty '{key}' does not exist in DifficultyInfo."); + } + } + } + + [JsonProperty("easy")] + public Dictionary easy; + + [JsonProperty("hard")] + public Dictionary hard; + + [JsonProperty("impossible")] + public Dictionary impossible; + + [JsonProperty("normal")] + public Dictionary normal; + } +} \ No newline at end of file diff --git a/project/Aki.Custom/Patches/BetaLogoPatch.cs b/project/Aki.Custom/Patches/BetaLogoPatch.cs index c978d90..90c88b1 100644 --- a/project/Aki.Custom/Patches/BetaLogoPatch.cs +++ b/project/Aki.Custom/Patches/BetaLogoPatch.cs @@ -13,7 +13,7 @@ namespace Aki.SinglePlayer.Patches.MainMenu { protected override MethodBase GetTargetMethod() { - return AccessTools.Method(typeof(TarkovApplication), nameof(TarkovApplication.method_27)); + return AccessTools.Method(typeof(TarkovApplication), nameof(TarkovApplication.method_28)); } [PatchPrefix] diff --git a/project/Aki.Custom/Patches/BotDifficultyPatch.cs b/project/Aki.Custom/Patches/BotDifficultyPatch.cs index 2f5ebe3..ad9ee13 100644 --- a/project/Aki.Custom/Patches/BotDifficultyPatch.cs +++ b/project/Aki.Custom/Patches/BotDifficultyPatch.cs @@ -1,4 +1,4 @@ -using Aki.Common.Http; +using Aki.Custom.Utils; using Aki.Reflection.Patching; using Aki.Reflection.Utils; using EFT; @@ -21,7 +21,7 @@ namespace Aki.Custom.Patches [PatchPrefix] private static bool PatchPrefix(ref string __result, BotDifficulty botDifficulty, WildSpawnType role) { - __result = RequestHandler.GetJson($"/singleplayer/settings/bot/difficulty/{role}/{botDifficulty}"); + __result = DifficultyManager.Get(botDifficulty, role); var resultIsNullEmpty = string.IsNullOrWhiteSpace(__result); if (resultIsNullEmpty) { diff --git a/project/Aki.Custom/Patches/CoreDifficultyPatch.cs b/project/Aki.Custom/Patches/CoreDifficultyPatch.cs index 4dc2d70..6c243c4 100644 --- a/project/Aki.Custom/Patches/CoreDifficultyPatch.cs +++ b/project/Aki.Custom/Patches/CoreDifficultyPatch.cs @@ -2,6 +2,7 @@ using Aki.Reflection.Patching; using Aki.Reflection.Utils; using Aki.Common.Http; using System.Reflection; +using Aki.Custom.Utils; namespace Aki.Custom.Patches { @@ -19,6 +20,11 @@ namespace Aki.Custom.Patches [PatchPrefix] private static bool PatchPrefix(ref string __result) { + // fetch all bot difficulties to be used in BotDifficultyPatch + // this is called here since core difficulties are fetched before bot-specific difficulties are + DifficultyManager.Update(); + + // update core difficulty __result = RequestHandler.GetJson("/singleplayer/settings/bot/difficulty/core/core"); return string.IsNullOrWhiteSpace(__result); } diff --git a/project/Aki.Custom/Patches/DisablePvEPatch.cs b/project/Aki.Custom/Patches/DisablePvEPatch.cs new file mode 100644 index 0000000..afe0b90 --- /dev/null +++ b/project/Aki.Custom/Patches/DisablePvEPatch.cs @@ -0,0 +1,29 @@ +using Aki.Common.Http; +using Aki.Reflection.Patching; +using System.Reflection; +using EFT; +using EFT.UI; +using HarmonyLib; +using UnityEngine; +using TMPro; +using System.Linq; + +namespace Aki.Custom.Patches +{ + public class DisablePvEPatch : ModulePatch + { + protected override MethodBase GetTargetMethod() + { + return AccessTools.Method(typeof(ChangeGameModeButton), nameof(ChangeGameModeButton.Show)); + } + + [PatchPrefix] + private static bool PatchPrefix(ESessionMode sessionMode, Profile profile, ref GameObject ____notAvailableState) + { + ____notAvailableState.SetActive(true); + Object.FindObjectsOfType().Where(o => o.name == "Locked").SingleOrDefault()?.SetMessageText("SPT-AKI is already PvE."); + + return false; + } + } +} diff --git a/project/Aki.Custom/Patches/EasyAssetsPatch.cs b/project/Aki.Custom/Patches/EasyAssetsPatch.cs index c62465c..b8dfd8f 100644 --- a/project/Aki.Custom/Patches/EasyAssetsPatch.cs +++ b/project/Aki.Custom/Patches/EasyAssetsPatch.cs @@ -12,8 +12,8 @@ using Aki.Common.Utils; using Aki.Custom.Models; using Aki.Custom.Utils; using Aki.Reflection.Patching; -using Aki.Reflection.Utils; using DependencyGraph = DependencyGraph; +using Aki.Reflection.Utils; namespace Aki.Custom.Patches { @@ -23,7 +23,7 @@ namespace Aki.Custom.Patches static EasyAssetsPatch() { - _bundlesField = typeof(EasyAssets).GetField($"{EasyBundleHelper.Type.Name.ToLowerInvariant()}_0", PatchConstants.PrivateFlags); + _bundlesField = typeof(EasyAssets).GetFields(PatchConstants.PrivateFlags).FirstOrDefault(field => field.FieldType == typeof(EasyAssetHelperClass[])); } public EasyAssetsPatch() diff --git a/project/Aki.Custom/Patches/ExitWhileLootingPatch.cs b/project/Aki.Custom/Patches/ExitWhileLootingPatch.cs index c4ecb70..ff44028 100644 --- a/project/Aki.Custom/Patches/ExitWhileLootingPatch.cs +++ b/project/Aki.Custom/Patches/ExitWhileLootingPatch.cs @@ -13,7 +13,7 @@ namespace Aki.Custom.Patches { protected override MethodBase GetTargetMethod() { - return AccessTools.Method(typeof(BaseLocalGame), nameof(BaseLocalGame.Stop)); + return AccessTools.Method(typeof(BaseLocalGame), nameof(BaseLocalGame.Stop)); } // Look at BaseLocalGame and find a method named "Stop" @@ -31,7 +31,7 @@ namespace Aki.Custom.Patches var player = Singleton.Instance.MainPlayer; if (profileId == player?.Profile.Id) { - GClass3107.Instance.CloseAllScreensForced(); + GClass3127.Instance.CloseAllScreensForced(); } return true; diff --git a/project/Aki.Custom/Patches/LocationLootCacheBustingPatch.cs b/project/Aki.Custom/Patches/LocationLootCacheBustingPatch.cs index ed4e38d..b988e2f 100644 --- a/project/Aki.Custom/Patches/LocationLootCacheBustingPatch.cs +++ b/project/Aki.Custom/Patches/LocationLootCacheBustingPatch.cs @@ -12,7 +12,7 @@ namespace Aki.Custom.Patches { protected override MethodBase GetTargetMethod() { - var desiredType = typeof(BaseLocalGame); + var desiredType = typeof(BaseLocalGame); var desiredMethod = desiredType.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public).SingleCustom(IsTargetMethod); // method_6 Logger.LogDebug($"{this.GetType().Name} Type: {desiredType?.Name}"); diff --git a/project/Aki.Custom/Patches/RagfairFeePatch.cs b/project/Aki.Custom/Patches/RagfairFeePatch.cs index 188ee5e..f66fde8 100644 --- a/project/Aki.Custom/Patches/RagfairFeePatch.cs +++ b/project/Aki.Custom/Patches/RagfairFeePatch.cs @@ -17,8 +17,8 @@ namespace Aki.Custom.Patches public RagfairFeePatch() { // Remember to update prefix parameter if below lines are broken - _ = nameof(GClass3069.IsAllSelectedItemSame); - _ = nameof(GClass3069.AutoSelectSimilar); + _ = nameof(GClass3087.IsAllSelectedItemSame); + _ = nameof(GClass3087.AutoSelectSimilar); } protected override MethodBase GetTargetMethod() @@ -30,18 +30,18 @@ namespace Aki.Custom.Patches /// Calculate tax to charge player and send to server before the offer is sent /// /// Item sold - /// OfferItemCount + /// OfferItemCount /// RequirementsPrice /// SellInOnePiece [PatchPrefix] - private static void PatchPrefix(ref Item ___item_0, ref GClass3069 ___gclass3069_0, ref double ___double_0, ref bool ___bool_0) + private static void PatchPrefix(ref Item ___item_0, ref GClass3087 ___gclass3087_0, ref double ___double_0, ref bool ___bool_0) { RequestHandler.PutJson("/client/ragfair/offerfees", new { id = ___item_0.Id, tpl = ___item_0.TemplateId, - count = ___gclass3069_0.OfferItemCount, - fee = Mathf.CeilToInt((float)GClass2089.CalculateTaxPrice(___item_0, ___gclass3069_0.OfferItemCount, ___double_0, ___bool_0)) + count = ___gclass3087_0.OfferItemCount, + fee = Mathf.CeilToInt((float)GClass2103.CalculateTaxPrice(___item_0, ___gclass3087_0.OfferItemCount, ___double_0, ___bool_0)) }.ToJson()); } } diff --git a/project/Aki.Custom/Patches/ResetTraderServicesPatch.cs b/project/Aki.Custom/Patches/ResetTraderServicesPatch.cs index ff8731d..64c6287 100644 --- a/project/Aki.Custom/Patches/ResetTraderServicesPatch.cs +++ b/project/Aki.Custom/Patches/ResetTraderServicesPatch.cs @@ -10,7 +10,7 @@ namespace Aki.Custom.Patches { protected override MethodBase GetTargetMethod() { - return AccessTools.Method(typeof(BaseLocalGame), nameof(BaseLocalGame.Stop)); + return AccessTools.Method(typeof(BaseLocalGame), nameof(BaseLocalGame.Stop)); } [PatchPrefix] diff --git a/project/Aki.Custom/Patches/SessionIdPatch.cs b/project/Aki.Custom/Patches/SessionIdPatch.cs index ef2190e..4bcf5ea 100644 --- a/project/Aki.Custom/Patches/SessionIdPatch.cs +++ b/project/Aki.Custom/Patches/SessionIdPatch.cs @@ -14,7 +14,7 @@ namespace Aki.Custom.Patches protected override MethodBase GetTargetMethod() { - return AccessTools.Method(typeof(BaseLocalGame), nameof(BaseLocalGame.method_5)); + return AccessTools.Method(typeof(BaseLocalGame), nameof(BaseLocalGame.method_5)); } [PatchPostfix] diff --git a/project/Aki.Custom/Utils/DifficultyManager.cs b/project/Aki.Custom/Utils/DifficultyManager.cs new file mode 100644 index 0000000..e7a3349 --- /dev/null +++ b/project/Aki.Custom/Utils/DifficultyManager.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using EFT; +using Aki.Common.Http; +using Aki.Common.Utils; +using Aki.Custom.Models; + +namespace Aki.Custom.Utils +{ + public static class DifficultyManager + { + public static Dictionary Difficulties { get; private set; } + + static DifficultyManager() + { + Difficulties = new Dictionary(); + } + + public static void Update() + { + // remove existing list + Difficulties.Clear(); + + // get new difficulties + var json = RequestHandler.GetJson("/singleplayer/settings/bot/difficulties"); + Difficulties = Json.Deserialize>(json); + } + + public static string Get(BotDifficulty botDifficulty, WildSpawnType role) + { + var difficultyMatrix = Difficulties[role.ToString().ToLower()]; + return Json.Serialize(difficultyMatrix[botDifficulty.ToString().ToLower()]); + } + } +} diff --git a/project/Aki.Debugging/Aki.Debugging.csproj b/project/Aki.Debugging/Aki.Debugging.csproj index e6b446e..bde54d6 100644 --- a/project/Aki.Debugging/Aki.Debugging.csproj +++ b/project/Aki.Debugging/Aki.Debugging.csproj @@ -2,13 +2,13 @@ net471 - aki-debugging + spt-debugging Release - Aki - Copyright @ Aki 2024 + SPT + Copyright @ SPT 2024 diff --git a/project/Aki.Debugging/AkiDebuggingPlugin.cs b/project/Aki.Debugging/AkiDebuggingPlugin.cs index 68834ea..eb4b7f1 100644 --- a/project/Aki.Debugging/AkiDebuggingPlugin.cs +++ b/project/Aki.Debugging/AkiDebuggingPlugin.cs @@ -14,7 +14,7 @@ namespace Aki.Debugging public void Awake() { - Logger.LogInfo("Loading: Aki.Debugging"); + Logger.LogInfo("Loading: SPT.Debugging"); try { diff --git a/project/Aki.Debugging/Patches/BTRDebugCommandPatch.cs b/project/Aki.Debugging/Patches/BTRDebugCommandPatch.cs index a9b7a37..01c4b07 100644 --- a/project/Aki.Debugging/Patches/BTRDebugCommandPatch.cs +++ b/project/Aki.Debugging/Patches/BTRDebugCommandPatch.cs @@ -5,7 +5,7 @@ using EFT; using EFT.UI; using HarmonyLib; using System.Reflection; -using DialogControlClass = GClass1957; +using DialogControlClass = GClass1971; namespace Aki.Debugging.Patches { diff --git a/project/Aki.Debugging/Patches/CoordinatesPatch.cs b/project/Aki.Debugging/Patches/CoordinatesPatch.cs index 70927d5..c553a92 100644 --- a/project/Aki.Debugging/Patches/CoordinatesPatch.cs +++ b/project/Aki.Debugging/Patches/CoordinatesPatch.cs @@ -14,11 +14,11 @@ namespace Aki.Debugging.Patches protected override MethodBase GetTargetMethod() { - return AccessTools.Method(typeof(BaseLocalGame), nameof(BaseLocalGame.Update)); + return AccessTools.Method(typeof(BaseLocalGame), nameof(BaseLocalGame.Update)); } [PatchPrefix] - private static void PatchPrefix(BaseLocalGame __instance) + private static void PatchPrefix(BaseLocalGame __instance) { if (!Input.GetKeyDown(KeyCode.LeftControl)) return; diff --git a/project/Aki.Debugging/Patches/ExfilDumper.cs b/project/Aki.Debugging/Patches/ExfilDumper.cs index d665687..a84d9f1 100644 --- a/project/Aki.Debugging/Patches/ExfilDumper.cs +++ b/project/Aki.Debugging/Patches/ExfilDumper.cs @@ -9,7 +9,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; -using ExitSettingsClass = GClass1225; +using ExitSettingsClass = GClass1234; namespace Aki.Debugging.Patches { diff --git a/project/Aki.Debugging/Patches/PMCBotSpawnLocationPatch.cs b/project/Aki.Debugging/Patches/PMCBotSpawnLocationPatch.cs index 68edd96..c96918b 100644 --- a/project/Aki.Debugging/Patches/PMCBotSpawnLocationPatch.cs +++ b/project/Aki.Debugging/Patches/PMCBotSpawnLocationPatch.cs @@ -17,11 +17,11 @@ namespace Aki.Debugging.Patches { private readonly List playerSpawnPoints; private readonly Random _rnd = new Random(); - private readonly GStruct380 _spawnSettings = new GStruct380(); + private readonly GStruct381 _spawnSettings = new GStruct381(); public SptSpawnHelper() { - IEnumerable locationSpawnPoints = GClass2928.CreateFromScene(); + IEnumerable locationSpawnPoints = GClass2946.CreateFromScene(); var playerSpawns = locationSpawnPoints.Where(x => x.Categories.HasFlag(ESpawnCategoryMask.Player)).ToList(); this.playerSpawnPoints = locationSpawnPoints.Where(x => x.Categories.HasFlag(ESpawnCategoryMask.Player)).ToList(); @@ -62,7 +62,7 @@ namespace Aki.Debugging.Patches } [PatchPrefix] - public static bool PatchPrefix(GClass1472 __instance, GClass591 data) + public static bool PatchPrefix(GClass1483 __instance, GClass591 data) { var firstBotRole = data.Profiles[0].Info.Settings.Role; diff --git a/project/Aki.Debugging/Patches/ReloadClientPatch.cs b/project/Aki.Debugging/Patches/ReloadClientPatch.cs index 4904417..247864d 100644 --- a/project/Aki.Debugging/Patches/ReloadClientPatch.cs +++ b/project/Aki.Debugging/Patches/ReloadClientPatch.cs @@ -38,7 +38,7 @@ namespace Aki.Debugging.Patches { tarkovapp.HideoutControllerAccess.UnloadHideout(); } - tarkovapp.method_48(); + tarkovapp.method_49(); } } } diff --git a/project/Aki.PrePatch/Aki.PrePatch.csproj b/project/Aki.PrePatch/Aki.PrePatch.csproj index 6d84740..2ee1c9c 100644 --- a/project/Aki.PrePatch/Aki.PrePatch.csproj +++ b/project/Aki.PrePatch/Aki.PrePatch.csproj @@ -3,13 +3,13 @@ net471 - aki_PrePatch + spt-prepatch Release - Aki - Copyright @ Aki 2024 + SPT + Copyright @ SPT 2024 diff --git a/project/Aki.PrePatch/AkiBotsPrePatcher.cs b/project/Aki.PrePatch/AkiBotsPrePatcher.cs index f2ab1dc..7c1c4c0 100644 --- a/project/Aki.PrePatch/AkiBotsPrePatcher.cs +++ b/project/Aki.PrePatch/AkiBotsPrePatcher.cs @@ -11,8 +11,8 @@ namespace Aki.PrePatch { public static IEnumerable TargetDLLs { get; } = new[] { "Assembly-CSharp.dll" }; - public static int sptUsecValue = 47; - public static int sptBearValue = 48; + public static int sptUsecValue = 100; + public static int sptBearValue = 101; private static string _sptPluginFolder = "plugins/spt"; @@ -86,14 +86,14 @@ namespace Aki.PrePatch } // Validate that the folder exists, and contains our plugins - string[] sptPlugins = new string[] { "aki-core.dll", "aki-custom.dll", "aki-singleplayer.dll" }; + string[] sptPlugins = new string[] { "spt-common.dll", "spt-reflection.dll", "spt-core.dll", "spt-custom.dll", "spt-singleplayer.dll" }; string[] foundPlugins = Directory.GetFiles(sptPluginPath).Select(x => Path.GetFileName(x)).ToArray(); - foreach (string plugin in sptPlugins) + foreach (string pluginNameAndSuffix in sptPlugins) { - if (!foundPlugins.Contains(plugin)) + if (!foundPlugins.Contains(pluginNameAndSuffix)) { - message = $"Required SPT plugins missing from '{sptPluginPath}'{exitMessage}"; + message = $"Required SPT plugin: {pluginNameAndSuffix} missing from '{sptPluginPath}' {exitMessage}"; logger.LogError(message); return false; } diff --git a/project/Aki.Reflection/Aki.Reflection.csproj b/project/Aki.Reflection/Aki.Reflection.csproj index 053968c..661945e 100644 --- a/project/Aki.Reflection/Aki.Reflection.csproj +++ b/project/Aki.Reflection/Aki.Reflection.csproj @@ -1,13 +1,14 @@  - net471 - Release + net471 + Release + spt-reflection - Aki - Copyright @ Aki 2024 + SPT + Copyright @ SPT 2024 diff --git a/project/Aki.SinglePlayer/Aki.SinglePlayer.csproj b/project/Aki.SinglePlayer/Aki.SinglePlayer.csproj index a43eb3f..7d75937 100644 --- a/project/Aki.SinglePlayer/Aki.SinglePlayer.csproj +++ b/project/Aki.SinglePlayer/Aki.SinglePlayer.csproj @@ -2,13 +2,13 @@ net471 - aki-singleplayer + spt-singleplayer Release - Aki - Copyright @ Aki 2024 + SPT + Copyright @ SPT 2024 diff --git a/project/Aki.SinglePlayer/AkiSingleplayerPlugin.cs b/project/Aki.SinglePlayer/AkiSingleplayerPlugin.cs index 86cdb5b..4634041 100644 --- a/project/Aki.SinglePlayer/AkiSingleplayerPlugin.cs +++ b/project/Aki.SinglePlayer/AkiSingleplayerPlugin.cs @@ -16,7 +16,7 @@ namespace Aki.SinglePlayer { public void Awake() { - Logger.LogInfo("Loading: Aki.SinglePlayer"); + Logger.LogInfo("Loading: SPT.SinglePlayer"); try { diff --git a/project/Aki.SinglePlayer/Patches/MainMenu/InsuranceScreenPatch.cs b/project/Aki.SinglePlayer/Patches/MainMenu/InsuranceScreenPatch.cs index 7486144..6ec4bca 100644 --- a/project/Aki.SinglePlayer/Patches/MainMenu/InsuranceScreenPatch.cs +++ b/project/Aki.SinglePlayer/Patches/MainMenu/InsuranceScreenPatch.cs @@ -32,7 +32,7 @@ namespace Aki.SinglePlayer.Patches.MainMenu // this.method_41(); //} - return AccessTools.Method(typeof(MainMenuController), nameof(MainMenuController.method_72)); + return AccessTools.Method(typeof(MainMenuController), nameof(MainMenuController.method_73)); } [PatchPrefix] diff --git a/project/Aki.SinglePlayer/Patches/Quests/EndByTimerPatch.cs b/project/Aki.SinglePlayer/Patches/Quests/EndByTimerPatch.cs index 1c1184d..d441547 100644 --- a/project/Aki.SinglePlayer/Patches/Quests/EndByTimerPatch.cs +++ b/project/Aki.SinglePlayer/Patches/Quests/EndByTimerPatch.cs @@ -14,7 +14,7 @@ namespace Aki.SinglePlayer.Patches.Quests { protected override MethodBase GetTargetMethod() { - return AccessTools.Method(typeof(BaseLocalGame), nameof(BaseLocalGame.Stop)); + return AccessTools.Method(typeof(BaseLocalGame), nameof(BaseLocalGame.Stop)); } // Unused, but left here in case patch breaks and finding the intended method is difficult diff --git a/project/Aki.SinglePlayer/Patches/ScavMode/LoadOfflineRaidScreenPatch.cs b/project/Aki.SinglePlayer/Patches/ScavMode/LoadOfflineRaidScreenPatch.cs index 28ff7ea..644450c 100644 --- a/project/Aki.SinglePlayer/Patches/ScavMode/LoadOfflineRaidScreenPatch.cs +++ b/project/Aki.SinglePlayer/Patches/ScavMode/LoadOfflineRaidScreenPatch.cs @@ -32,7 +32,7 @@ namespace Aki.SinglePlayer.Patches.ScavMode _ = MatchmakerPlayerControllerClass.MAX_SCAV_COUNT; // UPDATE REFS TO THIS CLASS BELOW !!! // `MatchmakerInsuranceScreen` OnShowNextScreen - _onReadyScreenMethod = AccessTools.Method(typeof(MainMenuController), nameof(MainMenuController.method_43)); + _onReadyScreenMethod = AccessTools.Method(typeof(MainMenuController), nameof(MainMenuController.method_44)); _isLocalField = AccessTools.Field(typeof(MainMenuController), "bool_0"); _menuControllerField = typeof(TarkovApplication).GetFields(PatchConstants.PrivateFlags).FirstOrDefault(x => x.FieldType == typeof(MainMenuController)); @@ -46,65 +46,66 @@ namespace Aki.SinglePlayer.Patches.ScavMode protected override MethodBase GetTargetMethod() { // `MatchMakerSelectionLocationScreen` OnShowNextScreen - return AccessTools.Method(typeof(MainMenuController), nameof(MainMenuController.method_69)); + return AccessTools.Method(typeof(MainMenuController), nameof(MainMenuController.method_71)); } [PatchTranspiler] private static IEnumerable PatchTranspiler(ILGenerator generator, IEnumerable instructions) { + /* The original msil looks something like this: + * 0 0000 ldarg.0 + * 1 0001 call instance void MainMenuController::method_69() + * 2 0006 ldarg.0 + * 3 0007 call instance void MainMenuController::method_41() + * 4 000C ldarg.0 + * 5 000D call instance bool MainMenuController::method_46() + * 6 0012 brtrue.s 8 (0015) ldarg.0 + * 7 0014 ret + * 8 0015 ldarg.0 + * 9 0016 ldfld class EFT.RaidSettings MainMenuController::raidSettings_0 + * 10 001B callvirt instance bool EFT.RaidSettings::get_IsPmc() + * 11 0020 brfalse.s 15 (0029) ldarg.0 + * 12 0022 ldarg.0 + * 13 0023 call instance void MainMenuController::method_42() + * 14 0028 ret + * 15 0029 ldarg.0 + * 16 002A call instance void MainMenuController::method_44() + * 17 002F ret + * + * The goal is to replace the call to method_44 with our own LoadOfflineRaidScreenForScav function. + * method_44 expects one argument which is the implicit "this" pointer. + * The ldarg.0 instruction loads "this" onto the stack and the function call will consume it. + * But because our own LoadOfflineRaidScreenForScav method is static + * it won't consume a "this" pointer from the stack, so we have to remove the ldarg.0 instruction. + * But the brfalse instruction at 0020 jumps to the ldarg.0, so we can not simply delete it. + * Instead, we first need to transfer the jump label from the ldarg.0 instruction to our new + * call instruction and only then we remove it. + */ var codes = new List(instructions); + var onReadyScreenMethodOperand = AccessTools.Method(typeof(MainMenuController), _onReadyScreenMethod.Name); - // The original method call that we want to replace - var onReadyScreenMethodIndex = -1; - var onReadyScreenMethodCode = new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(MainMenuController), _onReadyScreenMethod.Name)); + var callCodeIndex = codes.FindLastIndex(code => code.opcode == OpCodes.Call + && (MethodInfo)code.operand == onReadyScreenMethodOperand); - // We additionally need to replace an instruction that jumps to a label on certain conditions, since we change the jump target instruction - var jumpWhenFalse_Index = -1; - - for (var i = 0; i < codes.Count; i++) - { - if (codes[i].opcode == onReadyScreenMethodCode.opcode && codes[i].operand == onReadyScreenMethodCode.operand) - { - onReadyScreenMethodIndex = i; - continue; - } - - if (codes[i].opcode == OpCodes.Brfalse) - { - if (jumpWhenFalse_Index != -1) - { - // If this warning is ever logged, the condition for locating the exact brfalse instruction will have to be updated - Logger.LogWarning($"[{nameof(LoadOfflineRaidScreenPatch)}] Found extra instructions with the brfalse opcode! " + - "This breaks an old assumption that there is only one such instruction in the method body and is now very likely to cause bugs!"); - } - jumpWhenFalse_Index = i; - } - } - - if (onReadyScreenMethodIndex == -1) + if (callCodeIndex == -1) { throw new Exception($"{nameof(LoadOfflineRaidScreenPatch)} failed: Could not find {nameof(_onReadyScreenMethod)} reference code."); } - if (jumpWhenFalse_Index == -1) + var loadThisIndex = callCodeIndex - 1; + if (codes[loadThisIndex].opcode != OpCodes.Ldarg_0) { - throw new Exception($"{nameof(LoadOfflineRaidScreenPatch)} failed: Could not find jump (brfalse) reference code."); + throw new Exception($"{nameof(LoadOfflineRaidScreenPatch)} failed: Expected ldarg.0 before call instruction but found {codes[loadThisIndex]}"); } - // Define the new jump label - var brFalseLabel = generator.DefineLabel(); + // Overwrite the call instruction with the call to LoadOfflineRaidScreenForScav, preserving the label for the 0020 brfalse jump + codes[callCodeIndex] = new CodeInstruction(OpCodes.Call, + AccessTools.Method(typeof(LoadOfflineRaidScreenPatch), nameof(LoadOfflineRaidScreenForScav))) { + labels = codes[loadThisIndex].labels + }; - // We build the method call for our substituted method and replace the initial method call with our own, also adding our new label - var callCode = new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(LoadOfflineRaidScreenPatch), nameof(LoadOfflineRaidScreenForScav))) { labels = { brFalseLabel } }; - codes[onReadyScreenMethodIndex] = callCode; - - // We build a new brfalse instruction and give it our new label, then replace the original brfalse instruction - var newBrFalseCode = new CodeInstruction(OpCodes.Brfalse, brFalseLabel); - codes[jumpWhenFalse_Index] = newBrFalseCode; - - // This will remove a stray ldarg.0 instruction. It's only needed if we wanted to reference something from `this` in the method body. - // This is done last to ensure that previous instruction indexes don't shift around (probably why this used to just turn it into a Nop OpCode) - codes.RemoveAt(onReadyScreenMethodIndex - 1); + // Remove the ldarg.0 instruction which we no longer need because LoadOfflineRaidScreenForScav is static + codes.RemoveAt(loadThisIndex); return codes.AsEnumerable(); } @@ -123,12 +124,12 @@ namespace Aki.SinglePlayer.Patches.ScavMode .Single(field => field.FieldType == typeof(MatchmakerPlayerControllerClass)) ?.GetValue(menuController) as MatchmakerPlayerControllerClass; - var gclass = new MatchmakerOfflineRaidScreen.GClass3155(profile?.Info, ref raidSettings, matchmakerPlayersController); + var gclass = new MatchmakerOfflineRaidScreen.GClass3178(profile?.Info, ref raidSettings, matchmakerPlayersController, ESessionMode.Regular); gclass.OnShowNextScreen += LoadOfflineRaidNextScreen; // `MatchmakerOfflineRaidScreen` OnShowReadyScreen - gclass.OnShowReadyScreen += (OfflineRaidAction)Delegate.CreateDelegate(typeof(OfflineRaidAction), menuController, nameof(MainMenuController.method_73)); + gclass.OnShowReadyScreen += (OfflineRaidAction)Delegate.CreateDelegate(typeof(OfflineRaidAction), menuController, nameof(MainMenuController.method_75)); gclass.ShowScreen(EScreenState.Queued); } diff --git a/project/Aki.SinglePlayer/Patches/ScavMode/ScavRepAdjustmentPatch.cs b/project/Aki.SinglePlayer/Patches/ScavMode/ScavRepAdjustmentPatch.cs index 2543b21..57072ab 100644 --- a/project/Aki.SinglePlayer/Patches/ScavMode/ScavRepAdjustmentPatch.cs +++ b/project/Aki.SinglePlayer/Patches/ScavMode/ScavRepAdjustmentPatch.cs @@ -12,7 +12,7 @@ namespace Aki.SinglePlayer.Patches.ScavMode // TODO: REMAP/UPDATE GCLASS REF protected override MethodBase GetTargetMethod() { - return AccessTools.Method(typeof(GClass1790), nameof(GClass1790.OnEnemyKill)); + return AccessTools.Method(typeof(GClass1799), nameof(GClass1799.OnEnemyKill)); } [PatchPrefix] diff --git a/project/Aki.SinglePlayer/Utils/TraderServices/LightKeeperServicesManager.cs b/project/Aki.SinglePlayer/Utils/TraderServices/LightKeeperServicesManager.cs index b13f584..d6c74d8 100644 --- a/project/Aki.SinglePlayer/Utils/TraderServices/LightKeeperServicesManager.cs +++ b/project/Aki.SinglePlayer/Utils/TraderServices/LightKeeperServicesManager.cs @@ -19,7 +19,7 @@ namespace Aki.SinglePlayer.Utils.TraderServices gameWorld = Singleton.Instance; if (gameWorld == null || TraderServicesManager.Instance == null) { - logger.LogError("[AKI-LKS] GameWorld or TraderServices null"); + logger.LogError("[SPT-LKS] GameWorld or TraderServices null"); Destroy(this); return; } @@ -27,7 +27,7 @@ namespace Aki.SinglePlayer.Utils.TraderServices botsController = Singleton.Instance.BotsController; if (botsController == null) { - logger.LogError("[AKI-LKS] BotsController null"); + logger.LogError("[SPT-LKS] BotsController null"); Destroy(this); return; } diff --git a/project/Aki.SinglePlayer/Utils/TraderServices/TraderServicesManager.cs b/project/Aki.SinglePlayer/Utils/TraderServices/TraderServicesManager.cs index b1758e2..f28787c 100644 --- a/project/Aki.SinglePlayer/Utils/TraderServices/TraderServicesManager.cs +++ b/project/Aki.SinglePlayer/Utils/TraderServices/TraderServicesManager.cs @@ -10,9 +10,9 @@ using System.Linq; using System.Reflection; using UnityEngine; using static BackendConfigSettingsClass; -using TraderServiceClass = GClass1794; -using QuestDictClass = GClass2133; -using StandingListClass = GClass2135; +using TraderServiceClass = GClass1805; +using QuestDictClass = GClass2145; +using StandingListClass = GClass2147; namespace Aki.SinglePlayer.Utils.TraderServices { diff --git a/project/Shared/Hollowed/hollowed.dll b/project/Shared/Hollowed/hollowed.dll index ae4d932..b4e5c95 100644 Binary files a/project/Shared/Hollowed/hollowed.dll and b/project/Shared/Hollowed/hollowed.dll differ diff --git a/project/build.ps1 b/project/build.ps1 index e741fd3..6b6c990 100644 --- a/project/build.ps1 +++ b/project/build.ps1 @@ -3,8 +3,6 @@ $bepinexFolder = "..\Build\BepInEx" $bepinexPatchFolder = "..\Build\BepInEx\patchers" $bepinexPluginFolder = "..\Build\BepInEx\plugins" $bepinexSptFolder = "..\Build\BepInEx\plugins\spt" -$eftDataFolder = "..\Build\EscapeFromTarkov_Data" -$managedFolder = "..\Build\EscapeFromTarkov_Data\Managed" $projReleaseFolder = ".\bin\Release\net471" $licenseFile = "..\..\LICENSE.md" @@ -12,19 +10,19 @@ $licenseFile = "..\..\LICENSE.md" if (Test-Path "$buildFolder") { Remove-Item -Path "$buildFolder" -Recurse -Force } # Create build folder and subfolders if they don't exist -$foldersToCreate = @("$buildFolder", "$bepinexFolder", "$bepinexPatchFolder", "$bepinexPluginFolder", "$bepinexSptFolder", "$eftDataFolder", "$managedFolder") +$foldersToCreate = @("$buildFolder", "$bepinexFolder", "$bepinexPatchFolder", "$bepinexPluginFolder", "$bepinexSptFolder") foreach ($folder in $foldersToCreate) { if (-not (Test-Path "$folder")) { New-Item -Path "$folder" -ItemType Directory } } # Move DLLs from project's bin-release folder to the build folder -Copy-Item "$projReleaseFolder\Aki.Common.dll" -Destination "$managedFolder" -Copy-Item "$projReleaseFolder\Aki.Reflection.dll" -Destination "$managedFolder" -Copy-Item "$projReleaseFolder\aki_PrePatch.dll" -Destination "$bepinexPatchFolder" -Copy-Item "$projReleaseFolder\aki-core.dll" -Destination "$bepinexSptFolder" -Copy-Item "$projReleaseFolder\aki-custom.dll" -Destination "$bepinexSptFolder" -Copy-Item "$projReleaseFolder\aki-debugging.dll" -Destination "$bepinexSptFolder" -Copy-Item "$projReleaseFolder\aki-singleplayer.dll" -Destination "$bepinexSptFolder" +Copy-Item "$projReleaseFolder\spt-common.dll" -Destination "$bepinexSptFolder" +Copy-Item "$projReleaseFolder\spt-reflection.dll" -Destination "$bepinexSptFolder" +Copy-Item "$projReleaseFolder\spt-prepatch.dll" -Destination "$bepinexPatchFolder" +Copy-Item "$projReleaseFolder\spt-core.dll" -Destination "$bepinexSptFolder" +Copy-Item "$projReleaseFolder\spt-custom.dll" -Destination "$bepinexSptFolder" +Copy-Item "$projReleaseFolder\spt-debugging.dll" -Destination "$bepinexSptFolder" +Copy-Item "$projReleaseFolder\spt-singleplayer.dll" -Destination "$bepinexSptFolder" # If any new DLLs need to be copied, add here # Write the contents of the license file to a txt