mirror of
https://github.com/sp-tarkov/modules.git
synced 2025-02-13 06:10:45 -05:00
commit
9b7154bded
@ -22,7 +22,7 @@ git config --local user.email "USERNAME@SOMETHING.com"
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
- Escape From Tarkov 29197
|
- Escape From Tarkov 29862
|
||||||
- Visual Studio Code -OR- Visual Studio 2022
|
- Visual Studio Code -OR- Visual Studio 2022
|
||||||
- .NET 6 SDK
|
- .NET 6 SDK
|
||||||
- [PowerShell v7](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows)
|
- [PowerShell v7](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows)
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Company>SPT Aki</Company>
|
<Company>SPT</Company>
|
||||||
<Copyright>Copyright @ SPT Aki 2024</Copyright>
|
<Copyright>Copyright @ SPT 2024</Copyright>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -3,12 +3,13 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>1.0.0.0</Version>
|
<Version>1.0.0.0</Version>
|
||||||
<TargetFramework>net471</TargetFramework>
|
<TargetFramework>net471</TargetFramework>
|
||||||
|
<AssemblyName>spt-common</AssemblyName>
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Company>Aki</Company>
|
<Company>SPT</Company>
|
||||||
<Copyright>Copyright @ Aki 2024</Copyright>
|
<Copyright>Copyright @ SPT 2024</Copyright>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -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<string, string> 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<string, string> 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
|
|
@ -129,89 +129,5 @@ namespace Aki.Common.Http
|
|||||||
{
|
{
|
||||||
return Task.Run(() => PutJsonAsync(path, json)).Result;
|
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<string, string>()
|
|
||||||
{
|
|
||||||
{ "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<string, string>()
|
|
||||||
{
|
|
||||||
{ "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<string, string>()
|
|
||||||
{
|
|
||||||
{ "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<string, string>()
|
|
||||||
{
|
|
||||||
{ "Cookie", $"PHPSESSID={SessionId}" },
|
|
||||||
{ "SessionId", SessionId }
|
|
||||||
};
|
|
||||||
|
|
||||||
var request = new Request();
|
|
||||||
request.Send(url, "PUT", payload, true, mime, headers);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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<string, string> Mime { get; private set; }
|
|
||||||
|
|
||||||
static WebConstants()
|
|
||||||
{
|
|
||||||
Mime = new Dictionary<string, string>()
|
|
||||||
{
|
|
||||||
{ ".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
|
|
@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net471</TargetFramework>
|
<TargetFramework>net471</TargetFramework>
|
||||||
<AssemblyName>aki-core</AssemblyName>
|
<AssemblyName>spt-core</AssemblyName>
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Company>Aki</Company>
|
<Company>SPT</Company>
|
||||||
<Copyright>Copyright @ Aki 2024</Copyright>
|
<Copyright>Copyright @ SPT 2024</Copyright>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -15,7 +15,7 @@ namespace Aki.Core
|
|||||||
{
|
{
|
||||||
_logger = Logger;
|
_logger = Logger;
|
||||||
|
|
||||||
Logger.LogInfo("Loading: Aki.Core");
|
Logger.LogInfo("Loading: SPT.Core");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -36,7 +36,7 @@ namespace Aki.Core
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.LogInfo("Completed: Aki.Core");
|
Logger.LogInfo("Completed: SPT.Core");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ namespace Aki.Core.Patches
|
|||||||
{
|
{
|
||||||
public class GameValidationPatch : ModulePatch
|
public class GameValidationPatch : ModulePatch
|
||||||
{
|
{
|
||||||
private const string PluginName = "Aki.Core";
|
private const string PluginName = "SPT.Core";
|
||||||
private const string ErrorMessage = "Validation failed";
|
private const string ErrorMessage = "Validation failed";
|
||||||
private static BepInEx.Logging.ManualLogSource _logger = null;
|
private static BepInEx.Logging.ManualLogSource _logger = null;
|
||||||
private static bool _hasRun = false;
|
private static bool _hasRun = false;
|
||||||
|
@ -27,9 +27,9 @@ namespace Aki.Core.Utils
|
|||||||
new FileInfo(Path.Combine(v2, "UnityCrashHandler64.exe"))
|
new FileInfo(Path.Combine(v2, "UnityCrashHandler64.exe"))
|
||||||
};
|
};
|
||||||
|
|
||||||
ServerLog.Debug("Aki.Core", Gfs(v2, "UnityCrashHandler64.exe")?.Length.ToString() ?? "0");
|
ServerLog.Debug("SPT.Core", Gfs(v2, "UnityCrashHandler64.exe")?.Length.ToString() ?? "0");
|
||||||
ServerLog.Debug("Aki.Core", Gfs(v2, "Uninstall.exe")?.Length.ToString() ?? "0");
|
ServerLog.Debug("SPT.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, "Register.bat")?.Length.ToString() ?? "0");
|
||||||
|
|
||||||
v0 = v4.Length - 1;
|
v0 = v4.Length - 1;
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ namespace Aki.Custom.Airdrops
|
|||||||
}
|
}
|
||||||
catch
|
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);
|
Destroy(this);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
@ -52,7 +52,7 @@ namespace Aki.Custom.Airdrops
|
|||||||
}
|
}
|
||||||
catch
|
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);
|
Destroy(this);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
@ -98,7 +98,7 @@ namespace Aki.Custom.Airdrops
|
|||||||
}
|
}
|
||||||
catch
|
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(airdropBox.gameObject);
|
||||||
Destroy(airdropPlane.gameObject);
|
Destroy(airdropPlane.gameObject);
|
||||||
Destroy(this);
|
Destroy(this);
|
||||||
|
@ -69,7 +69,7 @@ namespace Aki.Custom.Airdrops.Utils
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
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;
|
result = 25;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -104,7 +104,7 @@ namespace Aki.Custom.Airdrops.Utils
|
|||||||
|
|
||||||
if (flareAirdropPoints.Count == 0 && isFlare)
|
if (flareAirdropPoints.Count == 0 && isFlare)
|
||||||
{
|
{
|
||||||
Debug.LogError($"[AKI-AIRDROPS]: Airdrop called in by flare, Unable to find an airdropPoint within {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());
|
flareAirdropPoints.Add(allAirdropPoints.OrderBy(_ => Guid.NewGuid()).FirstOrDefault());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ namespace Aki.Custom.Airdrops.Utils
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.LogError($"[AKI-AIRDROPS]: unable to find template: {containerId}");
|
Debug.LogError($"[SPT-AIRDROPS]: unable to find template: {containerId}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net471</TargetFramework>
|
<TargetFramework>net471</TargetFramework>
|
||||||
<AssemblyName>aki-custom</AssemblyName>
|
<AssemblyName>spt-custom</AssemblyName>
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Company>Aki</Company>
|
<Company>SPT</Company>
|
||||||
<Copyright>Copyright @ Aki 2024</Copyright>
|
<Copyright>Copyright @ SPT 2024</Copyright>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -16,7 +16,7 @@ namespace Aki.Custom
|
|||||||
{
|
{
|
||||||
public void Awake()
|
public void Awake()
|
||||||
{
|
{
|
||||||
Logger.LogInfo("Loading: Aki.Custom");
|
Logger.LogInfo("Loading: SPT.Custom");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -56,6 +56,7 @@ namespace Aki.Custom
|
|||||||
new RagfairFeePatch().Enable();
|
new RagfairFeePatch().Enable();
|
||||||
new ScavQuestPatch().Enable();
|
new ScavQuestPatch().Enable();
|
||||||
new FixBrokenSpawnOnSandboxPatch().Enable();
|
new FixBrokenSpawnOnSandboxPatch().Enable();
|
||||||
|
new BTRControllerInitPatch().Enable();
|
||||||
new BTRPathLoadPatch().Enable();
|
new BTRPathLoadPatch().Enable();
|
||||||
new BTRActivateTraderDialogPatch().Enable();
|
new BTRActivateTraderDialogPatch().Enable();
|
||||||
new BTRInteractionPatch().Enable();
|
new BTRInteractionPatch().Enable();
|
||||||
@ -70,11 +71,13 @@ namespace Aki.Custom
|
|||||||
new BTREndRaidItemDeliveryPatch().Enable();
|
new BTREndRaidItemDeliveryPatch().Enable();
|
||||||
new BTRDestroyAtRaidEndPatch().Enable();
|
new BTRDestroyAtRaidEndPatch().Enable();
|
||||||
new BTRVehicleMovementSpeedPatch().Enable();
|
new BTRVehicleMovementSpeedPatch().Enable();
|
||||||
|
new BTRPathConfigMapPrefixPatch().Enable();
|
||||||
new ScavItemCheckmarkPatch().Enable();
|
new ScavItemCheckmarkPatch().Enable();
|
||||||
new ResetTraderServicesPatch().Enable();
|
new ResetTraderServicesPatch().Enable();
|
||||||
new CultistAmuletRemovalPatch().Enable();
|
new CultistAmuletRemovalPatch().Enable();
|
||||||
new HalloweenExtractPatch().Enable();
|
new HalloweenExtractPatch().Enable();
|
||||||
new ClampRagdollPatch().Enable();
|
new ClampRagdollPatch().Enable();
|
||||||
|
new DisablePvEPatch().Enable();
|
||||||
|
|
||||||
HookObject.AddOrGetComponent<MenuNotificationManager>();
|
HookObject.AddOrGetComponent<MenuNotificationManager>();
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,10 @@ using EFT.InventoryLogic;
|
|||||||
using EFT.UI;
|
using EFT.UI;
|
||||||
using EFT.Vehicle;
|
using EFT.Vehicle;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using System;
|
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Threading.Tasks;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Random = UnityEngine.Random;
|
using Random = UnityEngine.Random;
|
||||||
|
|
||||||
@ -27,6 +26,7 @@ namespace Aki.Custom.BTR
|
|||||||
private BTRView btrClientSide;
|
private BTRView btrClientSide;
|
||||||
private BotOwner btrBotShooter;
|
private BotOwner btrBotShooter;
|
||||||
private BTRDataPacket btrDataPacket = default;
|
private BTRDataPacket btrDataPacket = default;
|
||||||
|
private bool btrInitialized = false;
|
||||||
private bool btrBotShooterInitialized = false;
|
private bool btrBotShooterInitialized = false;
|
||||||
|
|
||||||
private float coverFireTime = 90f;
|
private float coverFireTime = 90f;
|
||||||
@ -48,17 +48,9 @@ namespace Aki.Custom.BTR
|
|||||||
private Player.FirearmController firearmController;
|
private Player.FirearmController firearmController;
|
||||||
private WeaponSoundPlayer weaponSoundPlayer;
|
private WeaponSoundPlayer weaponSoundPlayer;
|
||||||
|
|
||||||
private MethodInfo _updateTaxiPriceMethod;
|
|
||||||
|
|
||||||
private float originalDamageCoeff;
|
private float originalDamageCoeff;
|
||||||
|
|
||||||
BTRManager()
|
private async void Awake()
|
||||||
{
|
|
||||||
Type btrControllerType = typeof(BTRControllerClass);
|
|
||||||
_updateTaxiPriceMethod = AccessTools.GetDeclaredMethods(btrControllerType).Single(IsUpdateTaxiPriceMethod);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Awake()
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -76,11 +68,11 @@ namespace Aki.Custom.BTR
|
|||||||
|
|
||||||
btrController = gameWorld.BtrController;
|
btrController = gameWorld.BtrController;
|
||||||
|
|
||||||
InitBtr();
|
await InitBtr();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
ConsoleScreen.LogError("[AKI-BTR] Unable to spawn BTR. Check logs.");
|
ConsoleScreen.LogError("[SPT-BTR] Unable to spawn BTR. Check logs.");
|
||||||
Destroy(this);
|
Destroy(this);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
@ -133,14 +125,10 @@ namespace Aki.Custom.BTR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find `BTRControllerClass.method_9(PathDestination currentDestinationPoint, bool lastRoutePoint)`
|
|
||||||
private bool IsUpdateTaxiPriceMethod(MethodInfo method)
|
|
||||||
{
|
|
||||||
return (method.GetParameters().Length == 2 && method.GetParameters()[0].ParameterType == typeof(PathDestination));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Update()
|
private void Update()
|
||||||
{
|
{
|
||||||
|
if (!btrInitialized) return;
|
||||||
|
|
||||||
btrController.SyncBTRVehicleFromServer(UpdateDataPacket());
|
btrController.SyncBTRVehicleFromServer(UpdateDataPacket());
|
||||||
|
|
||||||
if (btrController.BotShooterBtr == null) return;
|
if (btrController.BotShooterBtr == null) return;
|
||||||
@ -169,9 +157,11 @@ namespace Aki.Custom.BTR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitBtr()
|
private async Task InitBtr()
|
||||||
{
|
{
|
||||||
// Initial setup
|
// Initial setup
|
||||||
|
await btrController.InitBtrController();
|
||||||
|
|
||||||
botEventHandler = Singleton<BotEventHandler>.Instance;
|
botEventHandler = Singleton<BotEventHandler>.Instance;
|
||||||
var botsController = Singleton<IBotGame>.Instance.BotsController;
|
var botsController = Singleton<IBotGame>.Instance.BotsController;
|
||||||
btrBotService = botsController.BotTradersServices.BTRServices;
|
btrBotService = botsController.BotTradersServices.BTRServices;
|
||||||
@ -187,6 +177,11 @@ namespace Aki.Custom.BTR
|
|||||||
ConfigureSettingsFromServer();
|
ConfigureSettingsFromServer();
|
||||||
|
|
||||||
var btrMapConfig = btrController.MapPathsConfiguration;
|
var btrMapConfig = btrController.MapPathsConfiguration;
|
||||||
|
if (btrMapConfig == null)
|
||||||
|
{
|
||||||
|
ConsoleScreen.LogError($"{nameof(btrController.MapPathsConfiguration)}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
btrServerSide.CurrentPathConfig = btrMapConfig.PathsConfiguration.pathsConfigurations.RandomElement();
|
btrServerSide.CurrentPathConfig = btrMapConfig.PathsConfiguration.pathsConfigurations.RandomElement();
|
||||||
btrServerSide.Initialization(btrMapConfig);
|
btrServerSide.Initialization(btrMapConfig);
|
||||||
btrController.method_14(); // creates and assigns the BTR a fake stash
|
btrController.method_14(); // creates and assigns the BTR a fake stash
|
||||||
@ -213,6 +208,8 @@ namespace Aki.Custom.BTR
|
|||||||
|
|
||||||
// Pull services data for the BTR from the server
|
// Pull services data for the BTR from the server
|
||||||
TraderServicesManager.Instance.GetTraderServicesDataFromServer(BTRUtil.BTRTraderId);
|
TraderServicesManager.Instance.GetTraderServicesDataFromServer(BTRUtil.BTRTraderId);
|
||||||
|
|
||||||
|
btrInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ConfigureSettingsFromServer()
|
private void ConfigureSettingsFromServer()
|
||||||
@ -249,7 +246,7 @@ namespace Aki.Custom.BTR
|
|||||||
TraderServicesManager.Instance.RemovePurchasedService(ETraderServiceType.PlayerTaxi, BTRUtil.BTRTraderId);
|
TraderServicesManager.Instance.RemovePurchasedService(ETraderServiceType.PlayerTaxi, BTRUtil.BTRTraderId);
|
||||||
|
|
||||||
// Update the prices for the taxi service
|
// Update the prices for the taxi service
|
||||||
_updateTaxiPriceMethod.Invoke(btrController, new object[] { destinationPoint, isFinal });
|
btrController.UpdateTaxiPrice(destinationPoint, isFinal);
|
||||||
|
|
||||||
// Update the UI
|
// Update the UI
|
||||||
TraderServicesManager.Instance.GetTraderServicesDataFromServer(BTRUtil.BTRTraderId);
|
TraderServicesManager.Instance.GetTraderServicesDataFromServer(BTRUtil.BTRTraderId);
|
||||||
@ -257,14 +254,9 @@ namespace Aki.Custom.BTR
|
|||||||
|
|
||||||
private bool IsBtrService(ETraderServiceType serviceType)
|
private bool IsBtrService(ETraderServiceType serviceType)
|
||||||
{
|
{
|
||||||
if (serviceType == ETraderServiceType.BtrItemsDelivery
|
return serviceType == ETraderServiceType.BtrItemsDelivery
|
||||||
|| serviceType == ETraderServiceType.PlayerTaxi
|
|| serviceType == ETraderServiceType.PlayerTaxi
|
||||||
|| serviceType == ETraderServiceType.BtrBotCover)
|
|| serviceType == ETraderServiceType.BtrBotCover;
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BtrTraderServicePurchased(ETraderServiceType serviceType, string subserviceId)
|
private void BtrTraderServicePurchased(ETraderServiceType serviceType, string subserviceId)
|
||||||
@ -338,7 +330,7 @@ namespace Aki.Custom.BTR
|
|||||||
}
|
}
|
||||||
catch
|
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;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -349,8 +341,8 @@ namespace Aki.Custom.BTR
|
|||||||
btrDataPacket.rotation = btrServerSide.transform.rotation;
|
btrDataPacket.rotation = btrServerSide.transform.rotation;
|
||||||
if (btrTurretServer != null && btrTurretServer.gunsBlockRoot != null)
|
if (btrTurretServer != null && btrTurretServer.gunsBlockRoot != null)
|
||||||
{
|
{
|
||||||
btrDataPacket.turretRotation = btrTurretServer.transform.rotation;
|
btrDataPacket.turretRotation = btrTurretServer.transform.localEulerAngles.y;
|
||||||
btrDataPacket.gunsBlockRotation = btrTurretServer.gunsBlockRoot.rotation;
|
btrDataPacket.gunsBlockRotation = btrTurretServer.gunsBlockRoot.localEulerAngles.x;
|
||||||
}
|
}
|
||||||
btrDataPacket.State = (byte)btrServerSide.BtrState;
|
btrDataPacket.State = (byte)btrServerSide.BtrState;
|
||||||
btrDataPacket.RouteState = (byte)btrServerSide.VehicleRouteState;
|
btrDataPacket.RouteState = (byte)btrServerSide.VehicleRouteState;
|
||||||
@ -390,12 +382,7 @@ namespace Aki.Custom.BTR
|
|||||||
|
|
||||||
private bool HasTarget()
|
private bool HasTarget()
|
||||||
{
|
{
|
||||||
if (currentTarget != null)
|
return currentTarget != null;
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetAim()
|
private void SetAim()
|
||||||
@ -428,12 +415,7 @@ namespace Aki.Custom.BTR
|
|||||||
|
|
||||||
private bool CanShoot()
|
private bool CanShoot()
|
||||||
{
|
{
|
||||||
if (currentTarget.IsVisible && btrBotShooter.BotBtrData.CanShoot())
|
return currentTarget.IsVisible && btrBotShooter.BotBtrData.CanShoot();
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartShooting()
|
private void StartShooting()
|
||||||
@ -469,9 +451,11 @@ namespace Aki.Custom.BTR
|
|||||||
{
|
{
|
||||||
targetHeadPos = currentTarget.Person.PlayerBones.Head.position;
|
targetHeadPos = currentTarget.Person.PlayerBones.Head.position;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 aimDirection = Vector3.Normalize(targetHeadPos - machineGunMuzzle.position);
|
Vector3 aimDirection = Vector3.Normalize(targetHeadPos - machineGunMuzzle.position);
|
||||||
ballisticCalculator.Shoot(btrMachineGunAmmo, machineGunMuzzle.position, aimDirection, btrBotShooter.ProfileId, btrMachineGunWeapon, 1f, 0);
|
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--;
|
burstCount--;
|
||||||
yield return new WaitForSecondsRealtime(0.092308f); // 650 RPM
|
yield return new WaitForSecondsRealtime(0.092308f); // 650 RPM
|
||||||
}
|
}
|
||||||
@ -504,13 +488,13 @@ namespace Aki.Custom.BTR
|
|||||||
|
|
||||||
if (btrClientSide != null)
|
if (btrClientSide != null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[AKI-BTR] BTRManager - Destroying btrClientSide");
|
Debug.LogWarning($"[SPT-BTR] {nameof(BTRManager)} - Destroying btrClientSide");
|
||||||
Destroy(btrClientSide.gameObject);
|
Destroy(btrClientSide.gameObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (btrServerSide != null)
|
if (btrServerSide != null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[AKI-BTR] BTRManager - Destroying btrServerSide");
|
Debug.LogWarning($"[SPT-BTR] {nameof(BTRManager)} - Destroying btrServerSide");
|
||||||
Destroy(btrServerSide.gameObject);
|
Destroy(btrServerSide.gameObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ namespace Aki.Custom.BTR
|
|||||||
{
|
{
|
||||||
public override bool IsStatic => false;
|
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()
|
bodyPart.ApplyInstantKill(new DamageInfo()
|
||||||
{
|
{
|
||||||
@ -31,7 +31,7 @@ namespace Aki.Custom.BTR
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RemovePenalty(GInterface94 player)
|
public override void RemovePenalty(GInterface106 player)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ using EFT.Vehicle;
|
|||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using BTRDialog = EFT.UI.TraderDialogScreen.GClass3132;
|
using BTRDialog = EFT.UI.TraderDialogScreen.GClass3153;
|
||||||
|
|
||||||
namespace Aki.Custom.BTR.Patches
|
namespace Aki.Custom.BTR.Patches
|
||||||
{
|
{
|
||||||
@ -28,12 +28,7 @@ namespace Aki.Custom.BTR.Patches
|
|||||||
{
|
{
|
||||||
FieldInfo btrField = type.GetField("btr");
|
FieldInfo btrField = type.GetField("btr");
|
||||||
|
|
||||||
if (btrField != null && btrField.FieldType == typeof(BTRSide))
|
return btrField != null && btrField.FieldType == typeof(BTRSide);
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[PatchPrefix]
|
[PatchPrefix]
|
||||||
|
@ -60,7 +60,7 @@ namespace Aki.Custom.BTR.Patches
|
|||||||
var valueTuple = (ValueTuple<ObservedPlayerView, bool>)_valueTuple0Field.GetValue(__instance);
|
var valueTuple = (ValueTuple<ObservedPlayerView, bool>)_valueTuple0Field.GetValue(__instance);
|
||||||
if (!valueTuple.Item2 && !InitTurretView(__instance, turretPlayer))
|
if (!valueTuple.Item2 && !InitTurretView(__instance, turretPlayer))
|
||||||
{
|
{
|
||||||
Logger.LogError("[AKI-BTR] BTRBotAttachPatch - BtrBot initialization failed");
|
Logger.LogError("[SPT-BTR] BTRBotAttachPatch - BtrBot initialization failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
34
project/Aki.Custom/BTR/Patches/BTRControllerInitPatch.cs
Normal file
34
project/Aki.Custom/BTR/Patches/BTRControllerInitPatch.cs
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,7 +11,7 @@ namespace Aki.Custom.BTR.Patches
|
|||||||
{
|
{
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
return AccessTools.Method(typeof(BaseLocalGame<GamePlayerOwner>), nameof(BaseLocalGame<GamePlayerOwner>.Stop));
|
return AccessTools.Method(typeof(BaseLocalGame<EftGamePlayerOwner>), nameof(BaseLocalGame<EftGamePlayerOwner>.Stop));
|
||||||
}
|
}
|
||||||
|
|
||||||
[PatchPrefix]
|
[PatchPrefix]
|
||||||
@ -26,7 +26,7 @@ namespace Aki.Custom.BTR.Patches
|
|||||||
var btrManager = gameWorld.GetComponent<BTRManager>();
|
var btrManager = gameWorld.GetComponent<BTRManager>();
|
||||||
if (btrManager != null)
|
if (btrManager != null)
|
||||||
{
|
{
|
||||||
Logger.LogWarning("[AKI-BTR] BTRDestroyAtRaidEndPatch - Raid Ended: Destroying BTRManager");
|
Logger.LogWarning("[SPT-BTR] BTRDestroyAtRaidEndPatch - Raid Ended: Destroying BTRManager");
|
||||||
Object.Destroy(btrManager);
|
Object.Destroy(btrManager);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,13 +32,13 @@ namespace Aki.Custom.BTR.Patches
|
|||||||
GameWorld gameWorld = Singleton<GameWorld>.Instance;
|
GameWorld gameWorld = Singleton<GameWorld>.Instance;
|
||||||
if (gameWorld == null)
|
if (gameWorld == null)
|
||||||
{
|
{
|
||||||
Logger.LogError("[AKI-BTR] BTREndRaidItemDeliveryPatch - GameWorld is null");
|
Logger.LogError("[SPT-BTR] BTREndRaidItemDeliveryPatch - GameWorld is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var player = gameWorld.MainPlayer;
|
var player = gameWorld.MainPlayer;
|
||||||
if (player == null)
|
if (player == null)
|
||||||
{
|
{
|
||||||
Logger.LogError("[AKI-BTR] BTREndRaidItemDeliveryPatch - Player is null");
|
Logger.LogError("[SPT-BTR] BTREndRaidItemDeliveryPatch - Player is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ namespace Aki.Custom.BTR.Patches
|
|||||||
|
|
||||||
if (!gameWorld.BtrController.HasNonEmptyTransferContainer(player.Profile.Id))
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ namespace Aki.Custom.BTR.Patches
|
|||||||
BTRView btrView = gameWorld.BtrController.BtrView;
|
BTRView btrView = gameWorld.BtrController.BtrView;
|
||||||
if (btrView == null)
|
if (btrView == null)
|
||||||
{
|
{
|
||||||
Logger.LogError($"[AKI-BTR] BTRExtractPassengersPatch - btrView is null");
|
Logger.LogError($"[SPT-BTR] BTRExtractPassengersPatch - btrView is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ namespace Aki.Custom.BTR.Patches
|
|||||||
BTRView btrView = gameWorld.BtrController.BtrView;
|
BTRView btrView = gameWorld.BtrController.BtrView;
|
||||||
if (btrView == null)
|
if (btrView == null)
|
||||||
{
|
{
|
||||||
Logger.LogError("[AKI-BTR] BTRInteractionPatch - btrView is null");
|
Logger.LogError("[SPT-BTR] BTRInteractionPatch - btrView is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,14 +19,14 @@ namespace Aki.Custom.BTR.Patches
|
|||||||
var gameWorld = Singleton<GameWorld>.Instance;
|
var gameWorld = Singleton<GameWorld>.Instance;
|
||||||
if (gameWorld == null)
|
if (gameWorld == null)
|
||||||
{
|
{
|
||||||
Logger.LogError("[AKI-BTR] BTRIsDoorsClosedPatch - GameWorld is null");
|
Logger.LogError("[SPT-BTR] BTRIsDoorsClosedPatch - GameWorld is null");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var serverSideBTR = gameWorld.BtrController.BtrVehicle;
|
var serverSideBTR = gameWorld.BtrController.BtrVehicle;
|
||||||
if (serverSideBTR == null)
|
if (serverSideBTR == null)
|
||||||
{
|
{
|
||||||
Logger.LogError("[AKI-BTR] BTRIsDoorsClosedPatch - serverSideBTR is null");
|
Logger.LogError("[SPT-BTR] BTRIsDoorsClosedPatch - serverSideBTR is null");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ namespace Aki.Custom.BTR.Patches
|
|||||||
}
|
}
|
||||||
catch (System.Exception)
|
catch (System.Exception)
|
||||||
{
|
{
|
||||||
ConsoleScreen.LogError("[AKI-BTR] Exception thrown, check logs.");
|
ConsoleScreen.LogError("[SPT-BTR] Exception thrown, check logs.");
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
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<GameWorld>.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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,16 @@ namespace Aki.Custom.BTR.Patches
|
|||||||
{
|
{
|
||||||
protected override MethodBase GetTargetMethod()
|
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]
|
[PatchPrefix]
|
||||||
@ -23,12 +32,15 @@ namespace Aki.Custom.BTR.Patches
|
|||||||
var botEventHandler = Singleton<BotEventHandler>.Instance;
|
var botEventHandler = Singleton<BotEventHandler>.Instance;
|
||||||
if (botEventHandler == null)
|
if (botEventHandler == null)
|
||||||
{
|
{
|
||||||
Logger.LogError($"[AKI-BTR] BTRReceiveDamageInfoPatch - BotEventHandler is null");
|
Logger.LogError($"[SPT-BTR] {nameof(BTRReceiveDamageInfoPatch)} - BotEventHandler is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var shotBy = (Player)damageInfo.Player.iPlayer;
|
var shotBy = (Player)damageInfo.Player.iPlayer;
|
||||||
|
if (shotBy != null)
|
||||||
|
{
|
||||||
botEventHandler.InterruptTraderServiceBtrSupportByBetrayer(shotBy);
|
botEventHandler.InterruptTraderServiceBtrSupportByBetrayer(shotBy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
66
project/Aki.Custom/BTR/Utils/BTRReflectionHelper.cs
Normal file
66
project/Aki.Custom/BTR/Utils/BTRReflectionHelper.cs
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
|
43
project/Aki.Custom/Models/DifficultyInfo.cs
Normal file
43
project/Aki.Custom/Models/DifficultyInfo.cs
Normal file
@ -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<string, object> 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<string, object> easy;
|
||||||
|
|
||||||
|
[JsonProperty("hard")]
|
||||||
|
public Dictionary<string, object> hard;
|
||||||
|
|
||||||
|
[JsonProperty("impossible")]
|
||||||
|
public Dictionary<string, object> impossible;
|
||||||
|
|
||||||
|
[JsonProperty("normal")]
|
||||||
|
public Dictionary<string, object> normal;
|
||||||
|
}
|
||||||
|
}
|
@ -13,7 +13,7 @@ namespace Aki.SinglePlayer.Patches.MainMenu
|
|||||||
{
|
{
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
return AccessTools.Method(typeof(TarkovApplication), nameof(TarkovApplication.method_27));
|
return AccessTools.Method(typeof(TarkovApplication), nameof(TarkovApplication.method_28));
|
||||||
}
|
}
|
||||||
|
|
||||||
[PatchPrefix]
|
[PatchPrefix]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using Aki.Common.Http;
|
using Aki.Custom.Utils;
|
||||||
using Aki.Reflection.Patching;
|
using Aki.Reflection.Patching;
|
||||||
using Aki.Reflection.Utils;
|
using Aki.Reflection.Utils;
|
||||||
using EFT;
|
using EFT;
|
||||||
@ -21,7 +21,7 @@ namespace Aki.Custom.Patches
|
|||||||
[PatchPrefix]
|
[PatchPrefix]
|
||||||
private static bool PatchPrefix(ref string __result, BotDifficulty botDifficulty, WildSpawnType role)
|
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);
|
var resultIsNullEmpty = string.IsNullOrWhiteSpace(__result);
|
||||||
if (resultIsNullEmpty)
|
if (resultIsNullEmpty)
|
||||||
{
|
{
|
||||||
|
@ -2,6 +2,7 @@ using Aki.Reflection.Patching;
|
|||||||
using Aki.Reflection.Utils;
|
using Aki.Reflection.Utils;
|
||||||
using Aki.Common.Http;
|
using Aki.Common.Http;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Aki.Custom.Utils;
|
||||||
|
|
||||||
namespace Aki.Custom.Patches
|
namespace Aki.Custom.Patches
|
||||||
{
|
{
|
||||||
@ -19,6 +20,11 @@ namespace Aki.Custom.Patches
|
|||||||
[PatchPrefix]
|
[PatchPrefix]
|
||||||
private static bool PatchPrefix(ref string __result)
|
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");
|
__result = RequestHandler.GetJson("/singleplayer/settings/bot/difficulty/core/core");
|
||||||
return string.IsNullOrWhiteSpace(__result);
|
return string.IsNullOrWhiteSpace(__result);
|
||||||
}
|
}
|
||||||
|
29
project/Aki.Custom/Patches/DisablePvEPatch.cs
Normal file
29
project/Aki.Custom/Patches/DisablePvEPatch.cs
Normal file
@ -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<HoverTooltipArea>().Where(o => o.name == "Locked").SingleOrDefault()?.SetMessageText("<color=#51c6db>SPT-AKI</color> is already PvE.");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,8 +12,8 @@ using Aki.Common.Utils;
|
|||||||
using Aki.Custom.Models;
|
using Aki.Custom.Models;
|
||||||
using Aki.Custom.Utils;
|
using Aki.Custom.Utils;
|
||||||
using Aki.Reflection.Patching;
|
using Aki.Reflection.Patching;
|
||||||
using Aki.Reflection.Utils;
|
|
||||||
using DependencyGraph = DependencyGraph<IEasyBundle>;
|
using DependencyGraph = DependencyGraph<IEasyBundle>;
|
||||||
|
using Aki.Reflection.Utils;
|
||||||
|
|
||||||
namespace Aki.Custom.Patches
|
namespace Aki.Custom.Patches
|
||||||
{
|
{
|
||||||
@ -23,7 +23,7 @@ namespace Aki.Custom.Patches
|
|||||||
|
|
||||||
static EasyAssetsPatch()
|
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()
|
public EasyAssetsPatch()
|
||||||
|
@ -13,7 +13,7 @@ namespace Aki.Custom.Patches
|
|||||||
{
|
{
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
return AccessTools.Method(typeof(BaseLocalGame<GamePlayerOwner>), nameof(BaseLocalGame<GamePlayerOwner>.Stop));
|
return AccessTools.Method(typeof(BaseLocalGame<EftGamePlayerOwner>), nameof(BaseLocalGame<EftGamePlayerOwner>.Stop));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look at BaseLocalGame<TPlayerOwner> and find a method named "Stop"
|
// Look at BaseLocalGame<TPlayerOwner> and find a method named "Stop"
|
||||||
@ -31,7 +31,7 @@ namespace Aki.Custom.Patches
|
|||||||
var player = Singleton<GameWorld>.Instance.MainPlayer;
|
var player = Singleton<GameWorld>.Instance.MainPlayer;
|
||||||
if (profileId == player?.Profile.Id)
|
if (profileId == player?.Profile.Id)
|
||||||
{
|
{
|
||||||
GClass3107.Instance.CloseAllScreensForced();
|
GClass3127.Instance.CloseAllScreensForced();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -12,7 +12,7 @@ namespace Aki.Custom.Patches
|
|||||||
{
|
{
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
var desiredType = typeof(BaseLocalGame<GamePlayerOwner>);
|
var desiredType = typeof(BaseLocalGame<EftGamePlayerOwner>);
|
||||||
var desiredMethod = desiredType.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public).SingleCustom(IsTargetMethod); // method_6
|
var desiredMethod = desiredType.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public).SingleCustom(IsTargetMethod); // method_6
|
||||||
|
|
||||||
Logger.LogDebug($"{this.GetType().Name} Type: {desiredType?.Name}");
|
Logger.LogDebug($"{this.GetType().Name} Type: {desiredType?.Name}");
|
||||||
|
@ -17,8 +17,8 @@ namespace Aki.Custom.Patches
|
|||||||
public RagfairFeePatch()
|
public RagfairFeePatch()
|
||||||
{
|
{
|
||||||
// Remember to update prefix parameter if below lines are broken
|
// Remember to update prefix parameter if below lines are broken
|
||||||
_ = nameof(GClass3069.IsAllSelectedItemSame);
|
_ = nameof(GClass3087.IsAllSelectedItemSame);
|
||||||
_ = nameof(GClass3069.AutoSelectSimilar);
|
_ = nameof(GClass3087.AutoSelectSimilar);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override MethodBase GetTargetMethod()
|
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
|
/// Calculate tax to charge player and send to server before the offer is sent
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="___item_0">Item sold</param>
|
/// <param name="___item_0">Item sold</param>
|
||||||
/// <param name="___gclass3069_0">OfferItemCount</param>
|
/// <param name="___gclass3087_0">OfferItemCount</param>
|
||||||
/// <param name="___double_0">RequirementsPrice</param>
|
/// <param name="___double_0">RequirementsPrice</param>
|
||||||
/// <param name="___bool_0">SellInOnePiece</param>
|
/// <param name="___bool_0">SellInOnePiece</param>
|
||||||
[PatchPrefix]
|
[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
|
RequestHandler.PutJson("/client/ragfair/offerfees", new
|
||||||
{
|
{
|
||||||
id = ___item_0.Id,
|
id = ___item_0.Id,
|
||||||
tpl = ___item_0.TemplateId,
|
tpl = ___item_0.TemplateId,
|
||||||
count = ___gclass3069_0.OfferItemCount,
|
count = ___gclass3087_0.OfferItemCount,
|
||||||
fee = Mathf.CeilToInt((float)GClass2089.CalculateTaxPrice(___item_0, ___gclass3069_0.OfferItemCount, ___double_0, ___bool_0))
|
fee = Mathf.CeilToInt((float)GClass2103.CalculateTaxPrice(___item_0, ___gclass3087_0.OfferItemCount, ___double_0, ___bool_0))
|
||||||
}.ToJson());
|
}.ToJson());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ namespace Aki.Custom.Patches
|
|||||||
{
|
{
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
return AccessTools.Method(typeof(BaseLocalGame<GamePlayerOwner>), nameof(BaseLocalGame<GamePlayerOwner>.Stop));
|
return AccessTools.Method(typeof(BaseLocalGame<EftGamePlayerOwner>), nameof(BaseLocalGame<EftGamePlayerOwner>.Stop));
|
||||||
}
|
}
|
||||||
|
|
||||||
[PatchPrefix]
|
[PatchPrefix]
|
||||||
|
@ -14,7 +14,7 @@ namespace Aki.Custom.Patches
|
|||||||
|
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
return AccessTools.Method(typeof(BaseLocalGame<GamePlayerOwner>), nameof(BaseLocalGame<GamePlayerOwner>.method_5));
|
return AccessTools.Method(typeof(BaseLocalGame<EftGamePlayerOwner>), nameof(BaseLocalGame<EftGamePlayerOwner>.method_5));
|
||||||
}
|
}
|
||||||
|
|
||||||
[PatchPostfix]
|
[PatchPostfix]
|
||||||
|
34
project/Aki.Custom/Utils/DifficultyManager.cs
Normal file
34
project/Aki.Custom/Utils/DifficultyManager.cs
Normal file
@ -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<string, DifficultyInfo> Difficulties { get; private set; }
|
||||||
|
|
||||||
|
static DifficultyManager()
|
||||||
|
{
|
||||||
|
Difficulties = new Dictionary<string, DifficultyInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Update()
|
||||||
|
{
|
||||||
|
// remove existing list
|
||||||
|
Difficulties.Clear();
|
||||||
|
|
||||||
|
// get new difficulties
|
||||||
|
var json = RequestHandler.GetJson("/singleplayer/settings/bot/difficulties");
|
||||||
|
Difficulties = Json.Deserialize<Dictionary<string, DifficultyInfo>>(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Get(BotDifficulty botDifficulty, WildSpawnType role)
|
||||||
|
{
|
||||||
|
var difficultyMatrix = Difficulties[role.ToString().ToLower()];
|
||||||
|
return Json.Serialize(difficultyMatrix[botDifficulty.ToString().ToLower()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net471</TargetFramework>
|
<TargetFramework>net471</TargetFramework>
|
||||||
<AssemblyName>aki-debugging</AssemblyName>
|
<AssemblyName>spt-debugging</AssemblyName>
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Company>Aki</Company>
|
<Company>SPT</Company>
|
||||||
<Copyright>Copyright @ Aki 2024</Copyright>
|
<Copyright>Copyright @ SPT 2024</Copyright>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -14,7 +14,7 @@ namespace Aki.Debugging
|
|||||||
|
|
||||||
public void Awake()
|
public void Awake()
|
||||||
{
|
{
|
||||||
Logger.LogInfo("Loading: Aki.Debugging");
|
Logger.LogInfo("Loading: SPT.Debugging");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -5,7 +5,7 @@ using EFT;
|
|||||||
using EFT.UI;
|
using EFT.UI;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using DialogControlClass = GClass1957;
|
using DialogControlClass = GClass1971;
|
||||||
|
|
||||||
namespace Aki.Debugging.Patches
|
namespace Aki.Debugging.Patches
|
||||||
{
|
{
|
||||||
|
@ -14,11 +14,11 @@ namespace Aki.Debugging.Patches
|
|||||||
|
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
return AccessTools.Method(typeof(BaseLocalGame<GamePlayerOwner>), nameof(BaseLocalGame<GamePlayerOwner>.Update));
|
return AccessTools.Method(typeof(BaseLocalGame<EftGamePlayerOwner>), nameof(BaseLocalGame<EftGamePlayerOwner>.Update));
|
||||||
}
|
}
|
||||||
|
|
||||||
[PatchPrefix]
|
[PatchPrefix]
|
||||||
private static void PatchPrefix(BaseLocalGame<GamePlayerOwner> __instance)
|
private static void PatchPrefix(BaseLocalGame<EftGamePlayerOwner> __instance)
|
||||||
{
|
{
|
||||||
if (!Input.GetKeyDown(KeyCode.LeftControl)) return;
|
if (!Input.GetKeyDown(KeyCode.LeftControl)) return;
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using ExitSettingsClass = GClass1225;
|
using ExitSettingsClass = GClass1234;
|
||||||
|
|
||||||
namespace Aki.Debugging.Patches
|
namespace Aki.Debugging.Patches
|
||||||
{
|
{
|
||||||
|
@ -17,11 +17,11 @@ namespace Aki.Debugging.Patches
|
|||||||
{
|
{
|
||||||
private readonly List<ISpawnPoint> playerSpawnPoints;
|
private readonly List<ISpawnPoint> playerSpawnPoints;
|
||||||
private readonly Random _rnd = new Random();
|
private readonly Random _rnd = new Random();
|
||||||
private readonly GStruct380 _spawnSettings = new GStruct380();
|
private readonly GStruct381 _spawnSettings = new GStruct381();
|
||||||
|
|
||||||
public SptSpawnHelper()
|
public SptSpawnHelper()
|
||||||
{
|
{
|
||||||
IEnumerable<ISpawnPoint> locationSpawnPoints = GClass2928.CreateFromScene();
|
IEnumerable<ISpawnPoint> locationSpawnPoints = GClass2946.CreateFromScene();
|
||||||
|
|
||||||
var playerSpawns = locationSpawnPoints.Where(x => x.Categories.HasFlag(ESpawnCategoryMask.Player)).ToList();
|
var playerSpawns = locationSpawnPoints.Where(x => x.Categories.HasFlag(ESpawnCategoryMask.Player)).ToList();
|
||||||
this.playerSpawnPoints = 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]
|
[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;
|
var firstBotRole = data.Profiles[0].Info.Settings.Role;
|
||||||
|
@ -38,7 +38,7 @@ namespace Aki.Debugging.Patches
|
|||||||
{
|
{
|
||||||
tarkovapp.HideoutControllerAccess.UnloadHideout();
|
tarkovapp.HideoutControllerAccess.UnloadHideout();
|
||||||
}
|
}
|
||||||
tarkovapp.method_48();
|
tarkovapp.method_49();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,13 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net471</TargetFramework>
|
<TargetFramework>net471</TargetFramework>
|
||||||
<AssemblyName>aki_PrePatch</AssemblyName>
|
<AssemblyName>spt-prepatch</AssemblyName>
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Company>Aki</Company>
|
<Company>SPT</Company>
|
||||||
<Copyright>Copyright @ Aki 2024</Copyright>
|
<Copyright>Copyright @ SPT 2024</Copyright>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -11,8 +11,8 @@ namespace Aki.PrePatch
|
|||||||
{
|
{
|
||||||
public static IEnumerable<string> TargetDLLs { get; } = new[] { "Assembly-CSharp.dll" };
|
public static IEnumerable<string> TargetDLLs { get; } = new[] { "Assembly-CSharp.dll" };
|
||||||
|
|
||||||
public static int sptUsecValue = 47;
|
public static int sptUsecValue = 100;
|
||||||
public static int sptBearValue = 48;
|
public static int sptBearValue = 101;
|
||||||
|
|
||||||
private static string _sptPluginFolder = "plugins/spt";
|
private static string _sptPluginFolder = "plugins/spt";
|
||||||
|
|
||||||
@ -86,14 +86,14 @@ namespace Aki.PrePatch
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate that the folder exists, and contains our plugins
|
// 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();
|
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);
|
logger.LogError(message);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,12 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net471</TargetFramework>
|
<TargetFramework>net471</TargetFramework>
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
|
<AssemblyName>spt-reflection</AssemblyName>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Company>Aki</Company>
|
<Company>SPT</Company>
|
||||||
<Copyright>Copyright @ Aki 2024</Copyright>
|
<Copyright>Copyright @ SPT 2024</Copyright>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net471</TargetFramework>
|
<TargetFramework>net471</TargetFramework>
|
||||||
<AssemblyName>aki-singleplayer</AssemblyName>
|
<AssemblyName>spt-singleplayer</AssemblyName>
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Company>Aki</Company>
|
<Company>SPT</Company>
|
||||||
<Copyright>Copyright @ Aki 2024</Copyright>
|
<Copyright>Copyright @ SPT 2024</Copyright>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -16,7 +16,7 @@ namespace Aki.SinglePlayer
|
|||||||
{
|
{
|
||||||
public void Awake()
|
public void Awake()
|
||||||
{
|
{
|
||||||
Logger.LogInfo("Loading: Aki.SinglePlayer");
|
Logger.LogInfo("Loading: SPT.SinglePlayer");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -32,7 +32,7 @@ namespace Aki.SinglePlayer.Patches.MainMenu
|
|||||||
// this.method_41();
|
// this.method_41();
|
||||||
//}
|
//}
|
||||||
|
|
||||||
return AccessTools.Method(typeof(MainMenuController), nameof(MainMenuController.method_72));
|
return AccessTools.Method(typeof(MainMenuController), nameof(MainMenuController.method_73));
|
||||||
}
|
}
|
||||||
|
|
||||||
[PatchPrefix]
|
[PatchPrefix]
|
||||||
|
@ -14,7 +14,7 @@ namespace Aki.SinglePlayer.Patches.Quests
|
|||||||
{
|
{
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
return AccessTools.Method(typeof(BaseLocalGame<GamePlayerOwner>), nameof(BaseLocalGame<GamePlayerOwner>.Stop));
|
return AccessTools.Method(typeof(BaseLocalGame<EftGamePlayerOwner>), nameof(BaseLocalGame<EftGamePlayerOwner>.Stop));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unused, but left here in case patch breaks and finding the intended method is difficult
|
// Unused, but left here in case patch breaks and finding the intended method is difficult
|
||||||
|
@ -32,7 +32,7 @@ namespace Aki.SinglePlayer.Patches.ScavMode
|
|||||||
_ = MatchmakerPlayerControllerClass.MAX_SCAV_COUNT; // UPDATE REFS TO THIS CLASS BELOW !!!
|
_ = MatchmakerPlayerControllerClass.MAX_SCAV_COUNT; // UPDATE REFS TO THIS CLASS BELOW !!!
|
||||||
|
|
||||||
// `MatchmakerInsuranceScreen` OnShowNextScreen
|
// `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");
|
_isLocalField = AccessTools.Field(typeof(MainMenuController), "bool_0");
|
||||||
_menuControllerField = typeof(TarkovApplication).GetFields(PatchConstants.PrivateFlags).FirstOrDefault(x => x.FieldType == typeof(MainMenuController));
|
_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()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
// `MatchMakerSelectionLocationScreen` OnShowNextScreen
|
// `MatchMakerSelectionLocationScreen` OnShowNextScreen
|
||||||
return AccessTools.Method(typeof(MainMenuController), nameof(MainMenuController.method_69));
|
return AccessTools.Method(typeof(MainMenuController), nameof(MainMenuController.method_71));
|
||||||
}
|
}
|
||||||
|
|
||||||
[PatchTranspiler]
|
[PatchTranspiler]
|
||||||
private static IEnumerable<CodeInstruction> PatchTranspiler(ILGenerator generator, IEnumerable<CodeInstruction> instructions)
|
private static IEnumerable<CodeInstruction> PatchTranspiler(ILGenerator generator, IEnumerable<CodeInstruction> 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<CodeInstruction>(instructions);
|
var codes = new List<CodeInstruction>(instructions);
|
||||||
|
var onReadyScreenMethodOperand = AccessTools.Method(typeof(MainMenuController), _onReadyScreenMethod.Name);
|
||||||
|
|
||||||
// The original method call that we want to replace
|
var callCodeIndex = codes.FindLastIndex(code => code.opcode == OpCodes.Call
|
||||||
var onReadyScreenMethodIndex = -1;
|
&& (MethodInfo)code.operand == onReadyScreenMethodOperand);
|
||||||
var onReadyScreenMethodCode = new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(MainMenuController), _onReadyScreenMethod.Name));
|
|
||||||
|
|
||||||
// We additionally need to replace an instruction that jumps to a label on certain conditions, since we change the jump target instruction
|
if (callCodeIndex == -1)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
throw new Exception($"{nameof(LoadOfflineRaidScreenPatch)} failed: Could not find {nameof(_onReadyScreenMethod)} reference code.");
|
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
|
// Overwrite the call instruction with the call to LoadOfflineRaidScreenForScav, preserving the label for the 0020 brfalse jump
|
||||||
var brFalseLabel = generator.DefineLabel();
|
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
|
// Remove the ldarg.0 instruction which we no longer need because LoadOfflineRaidScreenForScav is static
|
||||||
var callCode = new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(LoadOfflineRaidScreenPatch), nameof(LoadOfflineRaidScreenForScav))) { labels = { brFalseLabel } };
|
codes.RemoveAt(loadThisIndex);
|
||||||
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);
|
|
||||||
|
|
||||||
return codes.AsEnumerable();
|
return codes.AsEnumerable();
|
||||||
}
|
}
|
||||||
@ -123,12 +124,12 @@ namespace Aki.SinglePlayer.Patches.ScavMode
|
|||||||
.Single(field => field.FieldType == typeof(MatchmakerPlayerControllerClass))
|
.Single(field => field.FieldType == typeof(MatchmakerPlayerControllerClass))
|
||||||
?.GetValue(menuController) as 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;
|
gclass.OnShowNextScreen += LoadOfflineRaidNextScreen;
|
||||||
|
|
||||||
// `MatchmakerOfflineRaidScreen` OnShowReadyScreen
|
// `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);
|
gclass.ShowScreen(EScreenState.Queued);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ namespace Aki.SinglePlayer.Patches.ScavMode
|
|||||||
// TODO: REMAP/UPDATE GCLASS REF
|
// TODO: REMAP/UPDATE GCLASS REF
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
{
|
{
|
||||||
return AccessTools.Method(typeof(GClass1790), nameof(GClass1790.OnEnemyKill));
|
return AccessTools.Method(typeof(GClass1799), nameof(GClass1799.OnEnemyKill));
|
||||||
}
|
}
|
||||||
|
|
||||||
[PatchPrefix]
|
[PatchPrefix]
|
||||||
|
@ -19,7 +19,7 @@ namespace Aki.SinglePlayer.Utils.TraderServices
|
|||||||
gameWorld = Singleton<GameWorld>.Instance;
|
gameWorld = Singleton<GameWorld>.Instance;
|
||||||
if (gameWorld == null || TraderServicesManager.Instance == null)
|
if (gameWorld == null || TraderServicesManager.Instance == null)
|
||||||
{
|
{
|
||||||
logger.LogError("[AKI-LKS] GameWorld or TraderServices null");
|
logger.LogError("[SPT-LKS] GameWorld or TraderServices null");
|
||||||
Destroy(this);
|
Destroy(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -27,7 +27,7 @@ namespace Aki.SinglePlayer.Utils.TraderServices
|
|||||||
botsController = Singleton<IBotGame>.Instance.BotsController;
|
botsController = Singleton<IBotGame>.Instance.BotsController;
|
||||||
if (botsController == null)
|
if (botsController == null)
|
||||||
{
|
{
|
||||||
logger.LogError("[AKI-LKS] BotsController null");
|
logger.LogError("[SPT-LKS] BotsController null");
|
||||||
Destroy(this);
|
Destroy(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,9 @@ using System.Linq;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using static BackendConfigSettingsClass;
|
using static BackendConfigSettingsClass;
|
||||||
using TraderServiceClass = GClass1794;
|
using TraderServiceClass = GClass1805;
|
||||||
using QuestDictClass = GClass2133<string>;
|
using QuestDictClass = GClass2145<string>;
|
||||||
using StandingListClass = GClass2135<float>;
|
using StandingListClass = GClass2147<float>;
|
||||||
|
|
||||||
namespace Aki.SinglePlayer.Utils.TraderServices
|
namespace Aki.SinglePlayer.Utils.TraderServices
|
||||||
{
|
{
|
||||||
|
Binary file not shown.
@ -3,8 +3,6 @@ $bepinexFolder = "..\Build\BepInEx"
|
|||||||
$bepinexPatchFolder = "..\Build\BepInEx\patchers"
|
$bepinexPatchFolder = "..\Build\BepInEx\patchers"
|
||||||
$bepinexPluginFolder = "..\Build\BepInEx\plugins"
|
$bepinexPluginFolder = "..\Build\BepInEx\plugins"
|
||||||
$bepinexSptFolder = "..\Build\BepInEx\plugins\spt"
|
$bepinexSptFolder = "..\Build\BepInEx\plugins\spt"
|
||||||
$eftDataFolder = "..\Build\EscapeFromTarkov_Data"
|
|
||||||
$managedFolder = "..\Build\EscapeFromTarkov_Data\Managed"
|
|
||||||
$projReleaseFolder = ".\bin\Release\net471"
|
$projReleaseFolder = ".\bin\Release\net471"
|
||||||
$licenseFile = "..\..\LICENSE.md"
|
$licenseFile = "..\..\LICENSE.md"
|
||||||
|
|
||||||
@ -12,19 +10,19 @@ $licenseFile = "..\..\LICENSE.md"
|
|||||||
if (Test-Path "$buildFolder") { Remove-Item -Path "$buildFolder" -Recurse -Force }
|
if (Test-Path "$buildFolder") { Remove-Item -Path "$buildFolder" -Recurse -Force }
|
||||||
|
|
||||||
# Create build folder and subfolders if they don't exist
|
# 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) {
|
foreach ($folder in $foldersToCreate) {
|
||||||
if (-not (Test-Path "$folder")) { New-Item -Path "$folder" -ItemType Directory }
|
if (-not (Test-Path "$folder")) { New-Item -Path "$folder" -ItemType Directory }
|
||||||
}
|
}
|
||||||
|
|
||||||
# Move DLLs from project's bin-release folder to the build folder
|
# Move DLLs from project's bin-release folder to the build folder
|
||||||
Copy-Item "$projReleaseFolder\Aki.Common.dll" -Destination "$managedFolder"
|
Copy-Item "$projReleaseFolder\spt-common.dll" -Destination "$bepinexSptFolder"
|
||||||
Copy-Item "$projReleaseFolder\Aki.Reflection.dll" -Destination "$managedFolder"
|
Copy-Item "$projReleaseFolder\spt-reflection.dll" -Destination "$bepinexSptFolder"
|
||||||
Copy-Item "$projReleaseFolder\aki_PrePatch.dll" -Destination "$bepinexPatchFolder"
|
Copy-Item "$projReleaseFolder\spt-prepatch.dll" -Destination "$bepinexPatchFolder"
|
||||||
Copy-Item "$projReleaseFolder\aki-core.dll" -Destination "$bepinexSptFolder"
|
Copy-Item "$projReleaseFolder\spt-core.dll" -Destination "$bepinexSptFolder"
|
||||||
Copy-Item "$projReleaseFolder\aki-custom.dll" -Destination "$bepinexSptFolder"
|
Copy-Item "$projReleaseFolder\spt-custom.dll" -Destination "$bepinexSptFolder"
|
||||||
Copy-Item "$projReleaseFolder\aki-debugging.dll" -Destination "$bepinexSptFolder"
|
Copy-Item "$projReleaseFolder\spt-debugging.dll" -Destination "$bepinexSptFolder"
|
||||||
Copy-Item "$projReleaseFolder\aki-singleplayer.dll" -Destination "$bepinexSptFolder"
|
Copy-Item "$projReleaseFolder\spt-singleplayer.dll" -Destination "$bepinexSptFolder"
|
||||||
# If any new DLLs need to be copied, add here
|
# If any new DLLs need to be copied, add here
|
||||||
|
|
||||||
# Write the contents of the license file to a txt
|
# Write the contents of the license file to a txt
|
||||||
|
Loading…
x
Reference in New Issue
Block a user