diff --git a/ASS.csproj b/ASS.csproj
index 5787288..19e1493 100644
--- a/ASS.csproj
+++ b/ASS.csproj
@@ -7,11 +7,12 @@
{967E5737-8917-4C2B-A0A4-B2B553498462}
Library
Properties
- armorMod.ASS
- armorMod.ASS
- v4.7.2
+ dvize.ASS
+ dvize.ASS
+ v4.8
512
true
+
true
@@ -86,13 +87,40 @@
False
F:\SPT-AKI\EscapeFromTarkov_Data\Managed\UnityEngine.CoreModule.dll
+
+ False
+ F:\SPT-AKI\EscapeFromTarkov_Data\Managed\UnityEngine.IMGUIModule.dll
+
+
+ False
+ F:\SPT-AKI\EscapeFromTarkov_Data\Managed\UnityEngine.TextRenderingModule.dll
+
+
+
+ True
+ True
+ Settings.settings
+
+
+
+
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
copy "$(TargetPath)" "F:\SPT-AKI\BepInEx\plugins\dvize.ASS.dll"
+
+
+
+
\ No newline at end of file
diff --git a/ArmorRegenComponent.cs b/ArmorRegenComponent.cs
new file mode 100644
index 0000000..d684a11
--- /dev/null
+++ b/ArmorRegenComponent.cs
@@ -0,0 +1,186 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using BepInEx.Logging;
+using Comfort.Common;
+using EFT;
+using EFT.InventoryLogic;
+using HarmonyLib;
+using UnityEngine;
+
+namespace ASS
+{
+ internal class ArmorRegenComponent : MonoBehaviour
+ {
+ private static float newRepairRate;
+ private static ArmorComponent armor;
+ private static float timeSinceLastHit = 0f;
+ private static Player player;
+ private static Slot slotContents;
+ private static bool isRegenerating = false;
+ private static InventoryControllerClass inventoryController;
+
+ private readonly Dictionary> equipmentSlotDictionary =
+ new Dictionary>
+ {
+ { EquipmentSlot.ArmorVest, new List- () },
+ { EquipmentSlot.TacticalVest, new List
- () },
+ { EquipmentSlot.Eyewear, new List
- () },
+ { EquipmentSlot.FaceCover, new List
- () },
+ { EquipmentSlot.Headwear, new List
- () },
+ };
+
+ protected static ManualLogSource Logger
+ {
+ get; private set;
+ }
+
+ private ArmorRegenComponent()
+ {
+ if (Logger == null)
+ {
+ Logger = BepInEx.Logging.Logger.CreateLogSource(nameof(ArmorRegenComponent));
+ }
+ }
+
+ internal static void Enable()
+ {
+ if (Singleton.Instantiated)
+ {
+ var gameWorld = Singleton.Instance;
+ gameWorld.GetOrAddComponent();
+
+ Logger.LogDebug("ASS: Attaching events");
+ }
+ }
+
+ private void Start()
+ {
+ player = Singleton.Instance.MainPlayer;
+
+ player.OnPlayerDeadOrUnspawn += Player_OnPlayerDeadOrUnspawn;
+ player.BeingHitAction += Player_BeingHitAction;
+ }
+
+
+ private void Update()
+ {
+ if (ASS.Plugin.ArmorServiceMode.Value)
+ {
+ timeSinceLastHit += Time.unscaledDeltaTime;
+ if (timeSinceLastHit >= Plugin.TimeDelayRepairInSec.Value)
+ {
+ if (!isRegenerating)
+ {
+ isRegenerating = true;
+ StartCoroutine(RepairArmor());
+ }
+ }
+ }
+ }
+
+
+ private IEnumerator RepairArmor()
+ {
+ //if the time since we were last hit exceeds TimeDelayRepairInSec.Value then repair all armor
+ while (isRegenerating && Plugin.ArmorServiceMode.Value)
+ {
+ //Logger.LogInfo($"Repairing Armor Block Reached Because TimeSinceLastHitReached: " + timeSinceLastHit);
+ //repair the armor divided by the time.unfixed rate
+ newRepairRate = Plugin.ArmorRepairRateOverTime.Value * Time.deltaTime;
+
+ foreach (EquipmentSlot slot in equipmentSlotDictionary.Keys.ToArray())
+ {
+ //Logger.LogInfo("ASS: Checking EquipmentSlot: " + slot);
+ Slot tempSlot = getEquipSlot(slot);
+
+ if (tempSlot == null || tempSlot.ContainedItem == null)
+ {
+ continue;
+ }
+
+ foreach (var item in tempSlot.ContainedItem.GetAllItems())
+ {
+ //get the armorcomponent of each item in items and check to see if all item componenets (even helmet side ears) are max durability
+ armor = item.GetItemComponent();
+
+ //check if it needs repair for the current item in loop of all items for the slot
+ if (
+ armor != null
+ && (armor.Repairable.Durability < armor.Repairable.MaxDurability)
+ )
+ {
+ //increase armor durability by newRepairRate until maximum then set as maximum durability
+ if (
+ armor.Repairable.Durability + newRepairRate
+ >= armor.Repairable.MaxDurability
+ )
+ {
+ armor.Repairable.Durability = armor.Repairable.MaxDurability;
+ //Logger.LogInfo("ASS: Setting MaxDurability for " + item.LocalizedName());
+ }
+ else
+ {
+ armor.Repairable.Durability += newRepairRate;
+ Logger.LogInfo("ASS: Repairing " + item.LocalizedName() + " : " + armor.Repairable.Durability + "/" + armor.Repairable.MaxDurability);
+ }
+ }
+ }
+ }
+
+ // Wait for the next frame before continuing
+ yield return null;
+ }
+
+ }
+
+ private void Player_BeingHitAction(DamageInfo arg1, EBodyPart arg2, float arg3)
+ {
+ timeSinceLastHit = 0f;
+ isRegenerating = false;
+ StopCoroutine(RepairArmor());
+ }
+
+ private void Player_OnPlayerDeadOrUnspawn(Player player)
+ {
+ Disable();
+ }
+
+ private void Disable()
+ {
+ if (player != null)
+ {
+ player.OnPlayerDeadOrUnspawn -= Player_OnPlayerDeadOrUnspawn;
+ player.BeingHitAction -= Player_BeingHitAction;
+ }
+ }
+
+ private Slot getEquipSlot(EquipmentSlot slot)
+ {
+ var player = Singleton.Instance.MainPlayer;
+
+ // Use AccessTools to get the protected field _inventoryController
+ inventoryController = (InventoryControllerClass)
+ AccessTools.Field(typeof(Player), "_inventoryController").GetValue(player);
+
+ if (inventoryController != null)
+ {
+ slotContents = inventoryController.Inventory.Equipment.GetSlot(slot);
+
+ if (slotContents.ContainedItem == null)
+ {
+ return null;
+ }
+
+ return slotContents;
+ }
+
+ return null;
+ }
+ }
+}
+
+
+
+
diff --git a/Plugin.cs b/Plugin.cs
index 16b6460..6b4f892 100644
--- a/Plugin.cs
+++ b/Plugin.cs
@@ -1,172 +1,75 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.Remoting.Messaging;
-using System.Threading.Tasks;
+using System.Diagnostics;
+using System.Reflection;
+using Aki.Reflection.Patching;
using BepInEx;
using BepInEx.Configuration;
-using Comfort.Common;
using EFT;
-using EFT.InventoryLogic;
-using HarmonyLib;
-using UnityEngine;
+using VersionChecker;
-namespace armorMod
+namespace ASS
{
- [BepInPlugin("com.armorMod.ASS", "armorMod.ASS", "1.0.0")]
-
- public class ASS : BaseUnityPlugin
+ [BepInPlugin("com.dvize.ASS", "dvize.ASS", "1.1.0")]
+ public class Plugin : BaseUnityPlugin
{
- private ConfigEntry ArmorServiceMode
- {
- get; set;
- }
- private static ConfigEntry TimeDelayRepairInSec
- {
- get; set;
- }
- private static ConfigEntry ArmorRepairRateOverTime
- {
- get; set;
- }
-
- private AbstractGame game;
- private bool runOnceAlready = false;
- private bool newGame = true;
- private float newRepairRate;
- private ArmorComponent armor;
- private static float timeSinceLastHit = 0f;
-
- private readonly Dictionary> equipmentSlotDictionary = new Dictionary>
- {
- { EquipmentSlot.ArmorVest, new List
- () },
- { EquipmentSlot.TacticalVest, new List
- () },
- { EquipmentSlot.Eyewear, new List
- () },
- { EquipmentSlot.FaceCover, new List
- () },
- { EquipmentSlot.Headwear, new List
- () }
- };
+ internal static ConfigEntry ArmorServiceMode { get; set; }
+ internal static ConfigEntry TimeDelayRepairInSec { get; set; }
+ internal static ConfigEntry ArmorRepairRateOverTime { get; set; }
internal void Awake()
{
- ArmorServiceMode = Config.Bind("Armor Repair Settings", "Enable/Disable Mod", true, "Enables the Armor Repairing Options Below");
- TimeDelayRepairInSec = Config.Bind("Armor Repair Settings", "Time Delay Repair in Sec", 60f, "How Long Before you were last hit that it repairs armor");
- ArmorRepairRateOverTime = Config.Bind("Armor Repair Settings", "Armor Repair Rate", 0.5f, "How much durability per second is repaired");
- }
- private void Update()
- {
- try
- {
- game = Singleton.Instance;
+ CheckEftVersion();
- if (game.InRaid && Camera.main.transform.position != null && newGame && ArmorServiceMode.Value)
- {
- var player = Singleton.Instance.MainPlayer;
- timeSinceLastHit += Time.deltaTime;
-
- if (!runOnceAlready && game.Status == GameStatus.Started)
- {
- Logger.LogDebug("ASS: Attaching events");
- player.BeingHitAction += Player_BeingHitAction;
- player.OnPlayerDeadOrUnspawn += Player_OnPlayerDeadOrUnspawn;
- runOnceAlready = true;
- }
-
- RepairArmor();
- }
- }
- catch { }
+ ArmorServiceMode = Config.Bind(
+ "Armor Repair Settings",
+ "Enable/Disable Mod",
+ true,
+ "Enables the Armor Repairing Options Below"
+ );
+ TimeDelayRepairInSec = Config.Bind(
+ "Armor Repair Settings",
+ "Time Delay Repair in Sec",
+ 60f,
+ "How Long Before you were last hit that it repairs armor"
+ );
+ ArmorRepairRateOverTime = Config.Bind(
+ "Armor Repair Settings",
+ "Armor Repair Rate",
+ 0.5f,
+ "How much durability per second is repaired"
+ );
}
- private void RepairArmor()
+ private void CheckEftVersion()
{
- //if the time since we were last hit exceeds TimeDelayRepairInSec.Value then repair all armor
- if (timeSinceLastHit >= TimeDelayRepairInSec.Value)
+ // Make sure the version of EFT being run is the correct version
+ int currentVersion = FileVersionInfo
+ .GetVersionInfo(BepInEx.Paths.ExecutablePath)
+ .FilePrivatePart;
+ int buildVersion = TarkovVersion.BuildVersion;
+ if (currentVersion != buildVersion)
{
- //Logger.LogInfo($"Repairing Armor Block Reached Because TimeSinceLastHitReached: " + timeSinceLastHit);
- //repair the armor divided by the time.unfixed rate
- newRepairRate = ArmorRepairRateOverTime.Value * Time.deltaTime;
-
- foreach (EquipmentSlot slot in equipmentSlotDictionary.Keys.ToArray())
- {
- Logger.LogInfo("ASS: Checking EquipmentSlot: " + slot);
- Slot tempSlot = getEquipSlot(slot);
-
- if (tempSlot == null || tempSlot.ContainedItem == null)
- {
- continue;
- }
-
- foreach (var item in tempSlot.ContainedItem.GetAllItems())
- {
- //get the armorcomponent of each item in items and check to see if all item componenets (even helmet side ears) are max durability
- armor = item.GetItemComponent();
-
- //check if it needs repair for the current item in loop of all items for the slot
- if (armor != null && (armor.Repairable.Durability < armor.Repairable.MaxDurability))
- {
- //increase armor durability by newRepairRate until maximum then set as maximum durability
- if (armor.Repairable.Durability + newRepairRate >= armor.Repairable.MaxDurability)
- {
- armor.Repairable.Durability = armor.Repairable.MaxDurability;
- //Logger.LogInfo("ASS: Setting MaxDurability for " + item.LocalizedName());
- }
- else
- {
- armor.Repairable.Durability += newRepairRate;
- //Logger.LogInfo("ASS: Repairing " + item.LocalizedName() + " : " + armor.Repairable.Durability + "/" + armor.Repairable.MaxDurability);
- }
- }
-
- }
-
- }
+ Logger.LogError(
+ $"ERROR: This version of {Info.Metadata.Name} v{Info.Metadata.Version} was built for Tarkov {buildVersion}, but you are running {currentVersion}. Please download the correct plugin version."
+ );
+ EFT.UI.ConsoleScreen.LogError(
+ $"ERROR: This version of {Info.Metadata.Name} v{Info.Metadata.Version} was built for Tarkov {buildVersion}, but you are running {currentVersion}. Please download the correct plugin version."
+ );
+ throw new Exception($"Invalid EFT Version ({currentVersion} != {buildVersion})");
}
}
-
- private void Player_BeingHitAction(DamageInfo dmgInfo, EBodyPart bodyPart, float hitEffectId) => timeSinceLastHit = 0f;
-
- private void Player_OnPlayerDeadOrUnspawn(Player player)
- {
- Logger.LogDebug("ASS: Undo all events");
- player.BeingHitAction -= Player_BeingHitAction;
- player.OnPlayerDeadOrUnspawn -= Player_OnPlayerDeadOrUnspawn;
- runOnceAlready = false;
- newGame = false;
-
- Task.Delay(TimeSpan.FromSeconds(15)).ContinueWith(_ =>
- {
- // Set newGame = true after the timer is finished so it doesn't execute the events right away
- newGame = true;
- });
- }
-
- private Slot slotContents;
- private InventoryControllerClass inventoryController;
- private Slot getEquipSlot(EquipmentSlot slot)
- {
- var player = Singleton.Instance.MainPlayer;
-
- // Use AccessTools to get the protected field _inventoryController
- inventoryController = (InventoryControllerClass)AccessTools.Field(typeof(Player), "_inventoryController").GetValue(player);
-
-
- if (inventoryController != null)
- {
- slotContents = inventoryController.Inventory.Equipment.GetSlot(slot);
-
- if (slotContents.ContainedItem == null)
- {
- return null;
- }
-
- return slotContents;
- }
-
- return null;
- }
-
-
}
-}
+ //re-initializes each new game
+ internal class NewGamePatch : ModulePatch
+ {
+ protected override MethodBase GetTargetMethod() =>
+ typeof(GameWorld).GetMethod(nameof(GameWorld.OnGameStarted));
+ [PatchPrefix]
+ public static void PatchPrefix()
+ {
+ ASS.ArmorRegenComponent.Enable();
+ }
+ }
+}
diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs
index 92e355a..2bd2859 100644
--- a/Properties/AssemblyInfo.cs
+++ b/Properties/AssemblyInfo.cs
@@ -1,15 +1,16 @@
-using System.Reflection;
+using System.Reflection;
using System.Runtime.InteropServices;
+using VersionChecker;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
-[assembly: AssemblyTitle("armorMod.ASS")]
+[assembly: AssemblyTitle("dvize.ASS")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("armorMod.ASS")]
-[assembly: AssemblyCopyright("Copyright © 2023")]
+[assembly: AssemblyProduct("dvize.ASS")]
+[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -31,5 +32,6 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyVersion("1.1.0.0")]
+[assembly: AssemblyFileVersion("1.1.0.0")]
+[assembly: TarkovVersion(23043)]
diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..c2c769d
--- /dev/null
+++ b/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace dvize.ASS.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.5.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/Properties/Settings.settings b/Properties/Settings.settings
new file mode 100644
index 0000000..049245f
--- /dev/null
+++ b/Properties/Settings.settings
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/VersionChecker/TarkovVersion.cs b/VersionChecker/TarkovVersion.cs
new file mode 100644
index 0000000..0249f88
--- /dev/null
+++ b/VersionChecker/TarkovVersion.cs
@@ -0,0 +1,146 @@
+using System;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using BepInEx.Configuration;
+using BepInEx.Logging;
+using BepInEx;
+using static EFT.ScenesPreset;
+using UnityEngine;
+
+namespace VersionChecker
+{
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
+ public class TarkovVersion : Attribute
+ {
+ private int version;
+
+ public TarkovVersion()
+ : this(0) { }
+
+ public TarkovVersion(int version)
+ {
+ this.version = version;
+ }
+
+ public static int BuildVersion
+ {
+ get
+ {
+ return Assembly
+ .GetExecutingAssembly()
+ .GetCustomAttributes(typeof(TarkovVersion), false)
+ ?.Cast()
+ ?.FirstOrDefault()
+ ?.version ?? 0;
+ }
+ }
+
+ // Make sure the version of EFT being run is the correct version, throw an exception and output log message if it isn't
+ ///
+ /// Check the currently running program's version against the plugin assembly TarkovVersion attribute, and
+ /// return false if they do not match.
+ /// Optionally add a fake setting to the F12 menu if Config is passed in
+ ///
+ /// The ManualLogSource to output an error to
+ /// The PluginInfo object for the plugin, used to get the plugin name and version
+ /// A BepinEx ConfigFile object, if provided, a custom message will be added to the F12 menu
+ ///
+ public static bool CheckEftVersion(
+ ManualLogSource Logger,
+ PluginInfo Info,
+ ConfigFile Config = null
+ )
+ {
+ int currentVersion = FileVersionInfo
+ .GetVersionInfo(BepInEx.Paths.ExecutablePath)
+ .FilePrivatePart;
+ int buildVersion = BuildVersion;
+ if (currentVersion != buildVersion)
+ {
+ string errorMessage =
+ $"ERROR: This version of {Info.Metadata.Name} v{Info.Metadata.Version} was built for Tarkov {buildVersion}, but you are running {currentVersion}. Please download the correct plugin version.";
+ Logger.LogError(errorMessage);
+
+ if (Config != null)
+ {
+ // This results in a bogus config entry in the BepInEx config file for the plugin, but it shouldn't hurt anything
+ // We leave the "section" parameter empty so there's no section header drawn
+ Config.Bind(
+ "",
+ "TarkovVersion",
+ "",
+ new ConfigDescription(
+ errorMessage,
+ null,
+ new ConfigurationManagerAttributes
+ {
+ CustomDrawer = ErrorLabelDrawer,
+ ReadOnly = true,
+ HideDefaultButton = true,
+ HideSettingName = true,
+ Category = null
+ }
+ )
+ );
+ }
+ return false;
+ }
+
+ return true;
+ }
+
+ static void ErrorLabelDrawer(ConfigEntryBase entry)
+ {
+ GUIStyle styleNormal = new GUIStyle(GUI.skin.label);
+ styleNormal.wordWrap = true;
+ styleNormal.stretchWidth = true;
+
+ GUIStyle styleError = new GUIStyle(GUI.skin.label);
+ styleError.stretchWidth = true;
+ styleError.alignment = TextAnchor.MiddleCenter;
+ styleError.normal.textColor = Color.red;
+ styleError.fontStyle = FontStyle.Bold;
+
+ // General notice that we're the wrong version
+ GUILayout.BeginVertical();
+ GUILayout.Label(
+ entry.Description.Description,
+ styleNormal,
+ new GUILayoutOption[] { GUILayout.ExpandWidth(true) }
+ );
+
+ // Centered red disabled text
+ GUILayout.Label(
+ "Plugin has been disabled!",
+ styleError,
+ new GUILayoutOption[] { GUILayout.ExpandWidth(true) }
+ );
+ GUILayout.EndVertical();
+ }
+
+#pragma warning disable 0169, 0414, 0649
+ internal sealed class ConfigurationManagerAttributes
+ {
+ public bool? ShowRangeAsPercent;
+ public System.Action CustomDrawer;
+ public CustomHotkeyDrawerFunc CustomHotkeyDrawer;
+ public delegate void CustomHotkeyDrawerFunc(
+ BepInEx.Configuration.ConfigEntryBase setting,
+ ref bool isCurrentlyAcceptingInput
+ );
+ public bool? Browsable;
+ public string Category;
+ public object DefaultValue;
+ public bool? HideDefaultButton;
+ public bool? HideSettingName;
+ public string Description;
+ public string DispName;
+ public int? Order;
+ public bool? ReadOnly;
+ public bool? IsAdvanced;
+ public System.Func