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