diff --git a/CustomInteractions.Prepatch/CustomInteractions.Prepatch.csproj b/CustomInteractions.Prepatch/CustomInteractions.Prepatch.csproj
index d93930c..c987699 100644
--- a/CustomInteractions.Prepatch/CustomInteractions.Prepatch.csproj
+++ b/CustomInteractions.Prepatch/CustomInteractions.Prepatch.csproj
@@ -5,6 +5,7 @@
IcyClawz.CustomInteractions.Prepatch
1.3.1
IcyClawz.CustomInteractions
+ latest
diff --git a/CustomInteractions.Prepatch/Prepatch.cs b/CustomInteractions.Prepatch/Prepatch.cs
index 385a8f6..6adcb1b 100644
--- a/CustomInteractions.Prepatch/Prepatch.cs
+++ b/CustomInteractions.Prepatch/Prepatch.cs
@@ -2,37 +2,24 @@ using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
-namespace IcyClawz.CustomInteractions
-{
- public static class Prepatch
- {
- public static IEnumerable TargetDLLs => new[] { "Assembly-CSharp.dll" };
+namespace IcyClawz.CustomInteractions;
- public static void Patch(ref AssemblyDefinition assembly)
- {
- var type = assembly.MainModule.GetType("GClass2816"); // DynamicInteraction
- if (type != null)
- {
- type.IsSealed = false;
- var field = type.Fields.SingleOrDefault(c => c.Name == "action_0");
- if (field != null)
- {
- field.IsFamily = true;
- field.IsInitOnly = false;
- }
- var ctor = type.Methods.SingleOrDefault(c => c.Name == ".ctor");
- if (ctor != null)
- {
- var param = ctor.Parameters.SingleOrDefault(c => c.Name == "callback");
- if (param != null)
- {
- param.IsOptional = true;
- param.HasDefault = true;
- param.Constant = null;
- }
- }
- }
- //assembly.Write("Assembly-CSharp-CustomInteractions.dll");
- }
+public static class Prepatch
+{
+ public static IEnumerable TargetDLLs => ["Assembly-CSharp.dll"];
+
+ public static void Patch(AssemblyDefinition assembly)
+ {
+ TypeDefinition type = assembly.MainModule.GetType("GClass2816"); // DynamicInteraction
+ type.IsSealed = false;
+ FieldDefinition field = type.Fields.SingleOrDefault(c => c.Name is "action_0");
+ field.IsFamily = true;
+ field.IsInitOnly = false;
+ MethodDefinition ctor = type.Methods.SingleOrDefault(c => c.Name is ".ctor");
+ ParameterDefinition param = ctor.Parameters.SingleOrDefault(c => c.Name is "callback");
+ param.IsOptional = true;
+ param.HasDefault = true;
+ param.Constant = null;
+ //assembly.Write("Assembly-CSharp-CustomInteractions.dll");
}
}
diff --git a/CustomInteractions/CustomInteractions.cs b/CustomInteractions/CustomInteractions.cs
index f2e26ca..d2a9463 100644
--- a/CustomInteractions/CustomInteractions.cs
+++ b/CustomInteractions/CustomInteractions.cs
@@ -11,196 +11,170 @@ using UnityEngine;
using DynamicInteraction = GClass2816;
using EmptyInteractions = GClass2817;
-namespace IcyClawz.CustomInteractions
+namespace IcyClawz.CustomInteractions;
+
+[EditorBrowsable(EditorBrowsableState.Never)]
+public interface ICustomInteractionsProvider { } // Do not implement this directly
+
+public interface IItemCustomInteractionsProvider : ICustomInteractionsProvider
{
- [EditorBrowsable(EditorBrowsableState.Never)]
- public interface ICustomInteractionsProvider { } // Do not implement this directly
+ IEnumerable GetCustomInteractions(ItemUiContext uiContext, EItemViewType viewType, Item item);
+}
- public interface IItemCustomInteractionsProvider : ICustomInteractionsProvider
+public static class CustomInteractionsManager
+{
+ internal static readonly LinkedList Providers = [];
+
+ public static void Register(ICustomInteractionsProvider provider)
{
- IEnumerable GetCustomInteractions(ItemUiContext uiContext, EItemViewType viewType, Item item);
+ if (!Providers.Contains(provider))
+ Providers.AddLast(provider);
+ }
+}
+
+public class CustomInteraction()
+{
+ internal readonly CustomInteractionImpl Impl = new();
+
+ public Func Caption { get => Impl.Caption; set => Impl.Caption = value; }
+ public Func Icon { get => Impl.Icon; set => Impl.Icon = value; }
+ public Action Action { get => Impl.Action; set => Impl.Action = value; }
+ public Func SubMenu { get => Impl.SubMenu; set => Impl.SubMenu = value; }
+ public Func Enabled { get => Impl.Enabled; set => Impl.Enabled = value; }
+ public Func Error { get => Impl.Error; set => Impl.Error = value; }
+}
+
+internal sealed class CustomInteractionImpl()
+ : DynamicInteraction(UnityEngine.Random.Range(0, int.MaxValue).ToString("x4"))
+{
+ public Func Caption { get; set; }
+ public new Func Icon { get; set; }
+ public Action Action { get => action_0; set => action_0 = value; }
+ public Func SubMenu { get; set; }
+ public Func Enabled { get; set; }
+ public Func Error { get; set; }
+
+ public bool IsInteractive() => Enabled?.Invoke() ?? true;
+}
+
+public abstract class CustomSubInteractions(ItemUiContext uiContext)
+{
+ internal readonly CustomSubInteractionsImpl Impl = new(uiContext);
+
+ public bool ExaminationRequired
+ {
+ get => Impl.ExaminationRequiredInternal;
+ set => Impl.ExaminationRequiredInternal = value;
}
- public static class CustomInteractionsManager
- {
- internal static readonly List Providers = new List();
+ public void Add(CustomInteraction interaction) => Impl.AddCustomInteraction(interaction);
+ public void AddRange(IEnumerable interactions) => interactions.ExecuteForEach(Impl.AddCustomInteraction);
+ public void Remove(CustomInteraction interaction) => Impl.RemoveCustomInteraction(interaction);
+ public void RemoveRange(IEnumerable interactions) => interactions.ExecuteForEach(Impl.RemoveCustomInteraction);
+ public void CallRedraw() => Impl.CallRedraw();
+ public void CallRedraw(string templateId) => Impl.CallRedraw(templateId);
+}
- public static void Register(ICustomInteractionsProvider provider)
- {
- if (!Providers.Contains(provider))
+internal sealed class CustomSubInteractionsImpl(ItemUiContext uiContext)
+ : EmptyInteractions(uiContext)
+{
+ public IEnumerable CustomInteractions => DynamicInteractions.OfType();
+
+ public bool ExaminationRequiredInternal { get; set; } = true;
+ public override bool ExaminationRequired => ExaminationRequiredInternal;
+ public override bool HasIcons => CustomInteractions.Any(interaction => interaction.Icon is not null);
+
+ public void CallRedraw() => itemUiContext_0.RedrawContextMenus(null);
+}
+
+internal static class AbstractInteractionsExtensions
+{
+ private static Dictionary GetDynamicInteractions(this GClass2817 instance) where T : Enum =>
+ typeof(GClass2817).GetField("dictionary_1", BindingFlags.NonPublic | BindingFlags.Instance)
+ .GetValue(instance) as Dictionary;
+
+ public static void AddCustomInteraction(this GClass2817 instance, CustomInteraction interaction) where T : Enum =>
+ instance.GetDynamicInteractions()[interaction.Impl.Key] = interaction.Impl;
+
+ public static void RemoveCustomInteraction(this GClass2817 instance, CustomInteraction interaction) where T : Enum =>
+ instance.GetDynamicInteractions().Remove(interaction.Impl.Key);
+}
+
+internal static class InteractionButtonsContainerExtensions
+{
+ private static readonly FieldInfo ButtonsContainerField =
+ typeof(InteractionButtonsContainer).GetField("_buttonsContainer", BindingFlags.NonPublic | BindingFlags.Instance);
+
+ private static RectTransform GetButtonsContainer(this InteractionButtonsContainer instance) =>
+ ButtonsContainerField.GetValue(instance) as RectTransform;
+
+ private static readonly FieldInfo ButtonTemplateField =
+ typeof(InteractionButtonsContainer).GetField("_buttonTemplate", BindingFlags.NonPublic | BindingFlags.Instance);
+
+ private static SimpleContextMenuButton GetButtonTemplate(this InteractionButtonsContainer instance) =>
+ ButtonTemplateField.GetValue(instance) as SimpleContextMenuButton;
+
+ private static readonly FieldInfo CurrentButtonField =
+ typeof(InteractionButtonsContainer).GetField("simpleContextMenuButton_0", BindingFlags.NonPublic | BindingFlags.Instance);
+
+ private static void SetCurrentButton(this InteractionButtonsContainer instance, SimpleContextMenuButton button) =>
+ CurrentButtonField.SetValue(instance, button);
+
+ private static readonly MethodInfo CreateButtonMethod =
+ typeof(InteractionButtonsContainer).GetMethod("method_1", BindingFlags.NonPublic | BindingFlags.Instance);
+
+ private static SimpleContextMenuButton CreateButton(this InteractionButtonsContainer instance,
+ string key, string caption, SimpleContextMenuButton template, RectTransform container,
+ [CanBeNull] Sprite sprite, [CanBeNull] Action onButtonClicked, [CanBeNull] Action onMouseHover,
+ bool subMenu = false, bool autoClose = true) =>
+ (SimpleContextMenuButton)CreateButtonMethod.Invoke(instance, [
+ key, caption, template, container, sprite, onButtonClicked, onMouseHover, subMenu, autoClose
+ ]);
+
+ private static readonly MethodInfo CloseSubMenuMethod =
+ typeof(InteractionButtonsContainer).GetMethod("method_4", BindingFlags.NonPublic | BindingFlags.Instance);
+
+ private static void CloseSubMenu(this InteractionButtonsContainer instance) =>
+ CloseSubMenuMethod.Invoke(instance, null);
+
+ private static readonly MethodInfo AddButtonMethod =
+ typeof(InteractionButtonsContainer).GetMethod("method_5", BindingFlags.NonPublic | BindingFlags.Instance);
+
+ private static void AddButton(this InteractionButtonsContainer instance, SimpleContextMenuButton button) =>
+ AddButtonMethod.Invoke(instance, [button]);
+
+ public static void AddCustomButton(this InteractionButtonsContainer instance, CustomInteractionImpl impl)
+ {
+ bool isInteractive = impl.IsInteractive();
+ SimpleContextMenuButton button = null;
+ button = instance.CreateButton(
+ impl.Key,
+ impl.Caption?.Invoke() ?? "",
+ instance.GetButtonTemplate(),
+ instance.GetButtonsContainer(),
+ impl.Icon?.Invoke(),
+ () =>
{
- Providers.Add(provider);
- }
- }
- }
-
- public class CustomInteraction
- {
- internal readonly CustomInteractionImpl Impl;
-
- public CustomInteraction()
- {
- Impl = new CustomInteractionImpl();
- }
-
- public Func Caption { get => Impl.Caption; set => Impl.Caption = value; }
- public Func Icon { get => Impl.Icon; set => Impl.Icon = value; }
- public Action Action { get => Impl.Action; set => Impl.Action = value; }
- public Func SubMenu { get => Impl.SubMenu; set => Impl.SubMenu = value; }
- public Func Enabled { get => Impl.Enabled; set => Impl.Enabled = value; }
- public Func Error { get => Impl.Error; set => Impl.Error = value; }
- }
-
- internal sealed class CustomInteractionImpl : DynamicInteraction
- {
- public CustomInteractionImpl()
- : base(UnityEngine.Random.Range(0, int.MaxValue).ToString("x4")) { }
-
- public Func Caption { get; set; }
- public new Func Icon { get; set; }
- public Action Action { get => action_0; set => action_0 = value; }
- public Func SubMenu { get; set; }
- public Func Enabled { get; set; }
- public Func Error { get; set; }
-
- public bool IsInteractive() =>
- Enabled?.Invoke() ?? true;
- }
-
- public abstract class CustomSubInteractions
- {
- internal readonly CustomSubInteractionsImpl Impl;
-
- public CustomSubInteractions(ItemUiContext uiContext)
- {
- Impl = new CustomSubInteractionsImpl(uiContext);
- }
-
- public bool ExaminationRequired { get => Impl._ExaminationRequired; set => Impl._ExaminationRequired = value; }
-
- public void Add(CustomInteraction customInteraction) =>
- Impl.AddCustomInteraction(customInteraction);
-
- public void Remove(CustomInteraction customInteraction) =>
- Impl.RemoveCustomInteraction(customInteraction);
-
- public void CallRedraw() =>
- Impl.CallRedraw();
-
- public void CallRedraw(string templateId) =>
- Impl.CallRedraw(templateId);
- }
-
- internal sealed class CustomSubInteractionsImpl : EmptyInteractions
- {
- public CustomSubInteractionsImpl(ItemUiContext uiContext)
- : base(uiContext) { }
-
- public IEnumerable CustomInteractions => DynamicInteractions.OfType();
-
- public bool _ExaminationRequired { get; set; } = true;
-
- public override bool ExaminationRequired => _ExaminationRequired;
-
- public override bool HasIcons => CustomInteractions.Any(customInteraction => customInteraction.Icon != null);
-
- public void CallRedraw() =>
- itemUiContext_0.RedrawContextMenus(null);
- }
-
- internal static class AbstractInteractionsExtensions
- {
- private static Dictionary GetDynamicInteractions(this GClass2817 instance) where T : Enum =>
- typeof(GClass2817).GetField("dictionary_1", BindingFlags.NonPublic | BindingFlags.Instance)
- .GetValue(instance) as Dictionary;
-
- public static void AddCustomInteraction(this GClass2817 instance, CustomInteraction customInteraction) where T : Enum =>
- instance.GetDynamicInteractions()[customInteraction.Impl.Key] = customInteraction.Impl;
-
- public static void RemoveCustomInteraction(this GClass2817 instance, CustomInteraction customInteraction) where T : Enum =>
- instance.GetDynamicInteractions().Remove(customInteraction.Impl.Key);
- }
-
- internal static class InteractionButtonsContainerExtensions
- {
- private static readonly FieldInfo ButtonsContainerField =
- typeof(InteractionButtonsContainer).GetField("_buttonsContainer", BindingFlags.NonPublic | BindingFlags.Instance);
-
- private static RectTransform GetButtonsContainer(this InteractionButtonsContainer instance) =>
- ButtonsContainerField.GetValue(instance) as RectTransform;
-
- private static readonly FieldInfo ButtonTemplateField =
- typeof(InteractionButtonsContainer).GetField("_buttonTemplate", BindingFlags.NonPublic | BindingFlags.Instance);
-
- private static SimpleContextMenuButton GetButtonTemplate(this InteractionButtonsContainer instance) =>
- ButtonTemplateField.GetValue(instance) as SimpleContextMenuButton;
-
- private static readonly FieldInfo CurrentButtonField =
- typeof(InteractionButtonsContainer).GetField("simpleContextMenuButton_0", BindingFlags.NonPublic | BindingFlags.Instance);
-
- private static void SetCurrentButton(this InteractionButtonsContainer instance, SimpleContextMenuButton button) =>
- CurrentButtonField.SetValue(instance, button);
-
- private static readonly MethodInfo CreateButtonMethod =
- typeof(InteractionButtonsContainer).GetMethod("method_1", BindingFlags.NonPublic | BindingFlags.Instance);
-
- private static SimpleContextMenuButton CreateButton(this InteractionButtonsContainer instance,
- string key, string caption, SimpleContextMenuButton template, RectTransform container,
- [CanBeNull] Sprite sprite, [CanBeNull] Action onButtonClicked, [CanBeNull] Action onMouseHover,
- bool subMenu = false, bool autoClose = true) =>
- (SimpleContextMenuButton)CreateButtonMethod.Invoke(instance, new object[] {
- key, caption, template, container, sprite, onButtonClicked, onMouseHover, subMenu, autoClose
- });
-
- private static readonly MethodInfo CloseSubMenuMethod =
- typeof(InteractionButtonsContainer).GetMethod("method_4", BindingFlags.NonPublic | BindingFlags.Instance);
-
- private static void CloseSubMenu(this InteractionButtonsContainer instance) =>
- CloseSubMenuMethod.Invoke(instance, null);
-
- private static readonly MethodInfo AddButtonMethod =
- typeof(InteractionButtonsContainer).GetMethod("method_5", BindingFlags.NonPublic | BindingFlags.Instance);
-
- private static void AddButton(this InteractionButtonsContainer instance, SimpleContextMenuButton button) =>
- AddButtonMethod.Invoke(instance, new object[] { button });
-
- public static void AddCustomButton(this InteractionButtonsContainer instance, CustomInteractionImpl customInteractionImpl)
- {
- bool isInteractive = customInteractionImpl.IsInteractive();
- SimpleContextMenuButton button = null;
- button = instance.CreateButton(
- customInteractionImpl.Key,
- customInteractionImpl.Caption?.Invoke() ?? string.Empty,
- instance.GetButtonTemplate(),
- instance.GetButtonsContainer(),
- customInteractionImpl.Icon?.Invoke(),
- () =>
+ if (isInteractive)
+ impl.Execute();
+ },
+ () =>
+ {
+ instance.SetCurrentButton(button);
+ instance.CloseSubMenu();
+ if (isInteractive)
{
- if (isInteractive)
- {
- customInteractionImpl.Execute();
- }
- },
- () =>
- {
- instance.SetCurrentButton(button);
- instance.CloseSubMenu();
- if (isInteractive)
- {
- var subMenu = customInteractionImpl.SubMenu?.Invoke();
- if (subMenu != null)
- {
- instance.SetSubInteractions(subMenu.Impl);
- }
- }
- },
- customInteractionImpl.SubMenu != null,
- false
- );
- button.SetButtonInteraction(
- (isInteractive, customInteractionImpl.Error?.Invoke() ?? string.Empty)
- );
- instance.AddButton(button);
- }
+ CustomSubInteractions subMenu = impl.SubMenu?.Invoke();
+ if (subMenu is not null)
+ instance.SetSubInteractions(subMenu.Impl);
+ }
+ },
+ impl.SubMenu is not null,
+ false
+ );
+ button.SetButtonInteraction(
+ (isInteractive, impl.Error?.Invoke() ?? "")
+ );
+ instance.AddButton(button);
}
}
\ No newline at end of file
diff --git a/CustomInteractions/CustomInteractions.csproj b/CustomInteractions/CustomInteractions.csproj
index 8e0c81d..85a6ed9 100644
--- a/CustomInteractions/CustomInteractions.csproj
+++ b/CustomInteractions/CustomInteractions.csproj
@@ -5,6 +5,7 @@
IcyClawz.CustomInteractions
1.3.1
IcyClawz.CustomInteractions
+ latest
diff --git a/CustomInteractions/Plugin.cs b/CustomInteractions/Plugin.cs
index 1a8d95f..7c01750 100644
--- a/CustomInteractions/Plugin.cs
+++ b/CustomInteractions/Plugin.cs
@@ -8,54 +8,50 @@ using DynamicInteraction = GClass2816;
using ItemContext = GClass2623;
using ItemInfoInteractions = GClass2817;
-namespace IcyClawz.CustomInteractions
+namespace IcyClawz.CustomInteractions;
+
+[BepInPlugin("com.IcyClawz.CustomInteractions", "IcyClawz.CustomInteractions", "1.3.1")]
+public class Plugin : BaseUnityPlugin
{
- [BepInPlugin("com.IcyClawz.CustomInteractions", "IcyClawz.CustomInteractions", "1.3.1")]
- public class Plugin : BaseUnityPlugin
+ private void Awake()
{
- private void Awake()
- {
- new ItemUiContextPatch().Enable();
- new InteractionButtonsContainerPatch().Enable();
- }
+ new ItemUiContextPatch().Enable();
+ new InteractionButtonsContainerPatch().Enable();
}
+}
- internal class ItemUiContextPatch : ModulePatch
+internal class ItemUiContextPatch : ModulePatch
+{
+ protected override MethodBase GetTargetMethod() =>
+ typeof(ItemUiContext).GetMethod("GetItemContextInteractions", BindingFlags.Public | BindingFlags.Instance);
+
+ [PatchPostfix]
+ private static void Postfix(ref ItemInfoInteractions __result, ref ItemUiContext __instance, ItemContext itemContext)
{
- protected override MethodBase GetTargetMethod() =>
- typeof(ItemUiContext).GetMethod("GetItemContextInteractions", BindingFlags.Public | BindingFlags.Instance);
-
- [PatchPostfix]
- private static void Postfix(ref ItemInfoInteractions __result, ItemUiContext __instance, ItemContext itemContext)
+ foreach (var provider in CustomInteractionsManager.Providers.OfType())
{
- foreach (var provider in CustomInteractionsManager.Providers.OfType())
- {
- var customInteractions = provider.GetCustomInteractions(__instance, itemContext.ViewType, itemContext.Item);
- if (customInteractions != null)
- {
- foreach (CustomInteraction customInteraction in customInteractions)
- {
- __result.AddCustomInteraction(customInteraction);
- }
- }
- }
- }
- }
-
- internal class InteractionButtonsContainerPatch : ModulePatch
- {
- protected override MethodBase GetTargetMethod() =>
- typeof(InteractionButtonsContainer).GetMethod("method_3", BindingFlags.NonPublic | BindingFlags.Instance);
-
- [PatchPrefix]
- private static bool Prefix(ref InteractionButtonsContainer __instance, DynamicInteraction interaction)
- {
- if (interaction is CustomInteractionImpl customInteractionImpl)
- {
- __instance.AddCustomButton(customInteractionImpl);
- return false;
- }
- return true;
+ var interactions = provider.GetCustomInteractions(__instance, itemContext.ViewType, itemContext.Item);
+ if (interactions is null)
+ continue;
+ foreach (CustomInteraction interaction in interactions)
+ __result.AddCustomInteraction(interaction);
}
}
}
+
+internal class InteractionButtonsContainerPatch : ModulePatch
+{
+ protected override MethodBase GetTargetMethod() =>
+ typeof(InteractionButtonsContainer).GetMethod("method_3", BindingFlags.NonPublic | BindingFlags.Instance);
+
+ [PatchPrefix]
+ private static bool Prefix(ref InteractionButtonsContainer __instance, DynamicInteraction interaction)
+ {
+ if (interaction is CustomInteractionImpl impl)
+ {
+ __instance.AddCustomButton(impl);
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/ItemAttributeFix/ItemAttributeFix.csproj b/ItemAttributeFix/ItemAttributeFix.csproj
index f97cc9a..0c3e0c8 100644
--- a/ItemAttributeFix/ItemAttributeFix.csproj
+++ b/ItemAttributeFix/ItemAttributeFix.csproj
@@ -5,6 +5,7 @@
IcyClawz.ItemAttributeFix
1.2.0
IcyClawz.ItemAttributeFix
+ latest
diff --git a/ItemAttributeFix/Plugin.cs b/ItemAttributeFix/Plugin.cs
index 361f00e..6648a14 100644
--- a/ItemAttributeFix/Plugin.cs
+++ b/ItemAttributeFix/Plugin.cs
@@ -3,33 +3,30 @@ using BepInEx;
using EFT.UI;
using System.Reflection;
-namespace IcyClawz.ItemAttributeFix
+namespace IcyClawz.ItemAttributeFix;
+
+[BepInPlugin("com.IcyClawz.ItemAttributeFix", "IcyClawz.ItemAttributeFix", "1.2.0")]
+public class Plugin : BaseUnityPlugin
{
- [BepInPlugin("com.IcyClawz.ItemAttributeFix", "IcyClawz.ItemAttributeFix", "1.2.0")]
- public class Plugin : BaseUnityPlugin
+ private void Awake() =>
+ new CompactCharacteristicPanelPatch().Enable();
+}
+
+internal class CompactCharacteristicPanelPatch : ModulePatch
+{
+ private static readonly FieldInfo ItemAttributeField =
+ typeof(CompactCharacteristicPanel).GetField("ItemAttribute", BindingFlags.NonPublic | BindingFlags.Instance);
+
+ private static readonly FieldInfo StringField =
+ typeof(CompactCharacteristicPanel).GetField("string_0", BindingFlags.NonPublic | BindingFlags.Instance);
+
+ protected override MethodBase GetTargetMethod() =>
+ typeof(CompactCharacteristicPanel).GetMethod("SetValues", BindingFlags.Public | BindingFlags.Instance);
+
+ [PatchPostfix]
+ private static void PatchPostfix(ref CompactCharacteristicPanel __instance)
{
- private void Awake()
- {
- new CompactCharacteristicPanelPatch().Enable();
- }
- }
-
- internal class CompactCharacteristicPanelPatch : ModulePatch
- {
- private static readonly FieldInfo ItemAttributeField =
- typeof(CompactCharacteristicPanel).GetField("ItemAttribute", BindingFlags.NonPublic | BindingFlags.Instance);
-
- private static readonly FieldInfo StringField =
- typeof(CompactCharacteristicPanel).GetField("string_0", BindingFlags.NonPublic | BindingFlags.Instance);
-
- protected override MethodBase GetTargetMethod() =>
- typeof(CompactCharacteristicPanel).GetMethod("SetValues", BindingFlags.Public | BindingFlags.Instance);
-
- [PatchPostfix]
- private static void PatchPostfix(ref CompactCharacteristicPanel __instance)
- {
- ItemAttributeClass attribute = ItemAttributeField.GetValue(__instance) as ItemAttributeClass;
+ if (ItemAttributeField.GetValue(__instance) is ItemAttributeClass attribute)
StringField.SetValue(__instance, attribute.FullStringValue());
- }
}
}
diff --git a/ItemContextMenuExt/ItemContextMenuExt.cs b/ItemContextMenuExt/ItemContextMenuExt.cs
index 5f9cd8f..54beadf 100644
--- a/ItemContextMenuExt/ItemContextMenuExt.cs
+++ b/ItemContextMenuExt/ItemContextMenuExt.cs
@@ -9,175 +9,158 @@ using System.Reflection;
using UnityEngine;
using ILightTemplate = GInterface246;
-using LightsState = GStruct155;
using ResourceCache = GClass1977;
-namespace IcyClawz.ItemContextMenuExt
+namespace IcyClawz.ItemContextMenuExt;
+
+internal static class PlayerExtensions
{
- internal static class PlayerExtensions
+ private static readonly FieldInfo InventoryControllerField =
+ typeof(Player).GetField("_inventoryController", BindingFlags.NonPublic | BindingFlags.Instance);
+
+ public static InventoryControllerClass GetInventoryController(this Player player) =>
+ InventoryControllerField.GetValue(player) as InventoryControllerClass;
+}
+
+internal static class LightComponentExtensions
+{
+ public static int GetModesCount(this LightComponent component) =>
+ ((ILightTemplate)component.Item.Template).ModesCount;
+}
+
+internal sealed class CustomInteractionsProvider : IItemCustomInteractionsProvider
+{
+ internal const string IconsPrefix = "Characteristics/Icons/";
+ internal static StaticIcons StaticIcons => EFTHardSettings.Instance.StaticIcons;
+
+ public IEnumerable GetCustomInteractions(ItemUiContext uiContext, EItemViewType viewType, Item item)
{
- private static readonly FieldInfo InventoryControllerField =
- typeof(Player).GetField("_inventoryController", BindingFlags.NonPublic | BindingFlags.Instance);
+ if (viewType is not EItemViewType.Inventory)
+ yield break;
- public static InventoryControllerClass GetInventoryController(this Player player) =>
- InventoryControllerField.GetValue(player) as InventoryControllerClass;
- }
-
- internal static class LightComponentExtensions
- {
- public static int GetModesCount(this LightComponent component) =>
- ((ILightTemplate)component.Item.Template).ModesCount;
- }
-
- internal sealed class CustomInteractionsProvider : IItemCustomInteractionsProvider
- {
- internal const string IconsPrefix = "Characteristics/Icons/";
- internal static StaticIcons StaticIcons => EFTHardSettings.Instance.StaticIcons;
-
- public IEnumerable GetCustomInteractions(ItemUiContext uiContext, EItemViewType viewType, Item item)
+ FireModeComponent fireModeComponent = item.GetItemComponent();
+ if (fireModeComponent is not null)
{
- if (viewType != EItemViewType.Inventory)
+ // Firing mode
+ yield return new()
{
- yield break;
- }
+ Caption = () => "Firing mode",
+ Icon = () => StaticIcons.GetAttributeIcon(EItemAttributeId.Weapon),
+ SubMenu = () => new FireModeSubMenu(uiContext, fireModeComponent),
+ Enabled = () => fireModeComponent.AvailableEFireModes.Length > 1,
+ Error = () => "This weapon is incapable of selective fire"
+ };
+ yield break;
+ }
+
+ LightComponent lightComponent = item.GetItemComponent();
+ if (lightComponent is not null)
+ {
+ // Turn on/off
+ yield return new()
{
- var component = item.GetItemComponent();
- if (component != null)
+ Caption = () => (lightComponent.IsActive ? "TurnOff" : "TurnOn").Localized(),
+ Icon = () => ResourceCache.Pop(IconsPrefix + (lightComponent.IsActive ? "TurnOff" : "TurnOn")),
+ Action = () =>
{
- // Firing mode
- yield return new CustomInteraction()
- {
- Caption = () => "Firing mode",
- Icon = () => StaticIcons.GetAttributeIcon(EItemAttributeId.Weapon),
- SubMenu = () => new FireModeSubMenu(uiContext, component),
- Enabled = () => component.AvailableEFireModes.Length > 1,
- Error = () => "This weapon is incapable of selective fire"
- };
- yield break;
+ Singleton.Instance.PlayUISound(EUISoundType.MenuContextMenu);
+ ComponentUtils.SetLightState(lightComponent, !lightComponent.IsActive, lightComponent.SelectedMode);
+ uiContext.RedrawContextMenus([item.TemplateId]);
}
- }
+ };
+ // Switch mode
+ yield return new()
{
- var component = item.GetItemComponent();
- if (component != null)
- {
- // Turn on/off
- yield return new CustomInteraction()
- {
- Caption = () => (component.IsActive ? "TurnOff" : "TurnOn").Localized(),
- Icon = () => ResourceCache.Pop(IconsPrefix + (component.IsActive ? "TurnOff" : "TurnOn")),
- Action = () =>
- {
- Singleton.Instance.PlayUISound(EUISoundType.MenuContextMenu);
- ComponentUtils.SetLightState(component, !component.IsActive, component.SelectedMode);
- uiContext.RedrawContextMenus(new[] { item.TemplateId });
- }
- };
- // Switch mode
- yield return new CustomInteraction()
- {
- Caption = () => "Switch mode",
- Icon = () => StaticIcons.GetAttributeIcon(EItemAttributeId.EncodeState),
- SubMenu = () => new LightModeSubMenu(uiContext, component),
- Enabled = () => component.GetModesCount() > 1,
- Error = () => "This device has no alternative modes"
- };
- yield break;
- }
- }
+ Caption = () => "Switch mode",
+ Icon = () => StaticIcons.GetAttributeIcon(EItemAttributeId.EncodeState),
+ SubMenu = () => new LightModeSubMenu(uiContext, lightComponent),
+ Enabled = () => lightComponent.GetModesCount() > 1,
+ Error = () => "This device has no alternative modes"
+ };
+ yield break;
}
}
+}
- internal class FireModeSubMenu : CustomSubInteractions
+internal class FireModeSubMenu : CustomSubInteractions
+{
+ public FireModeSubMenu(ItemUiContext uiContext, FireModeComponent component)
+ : base(uiContext)
{
- public FireModeSubMenu(ItemUiContext uiContext, FireModeComponent component)
- : base(uiContext)
+ AddRange(component.AvailableEFireModes.Select(fireMode => new CustomInteraction()
{
- foreach (var fireMode in component.AvailableEFireModes)
+ Caption = () => fireMode.ToString().Localized(),
+ Action = () =>
{
- Add(new CustomInteraction()
- {
- Caption = () => fireMode.ToString().Localized(),
- Action = () =>
- {
- Singleton.Instance.PlayUISound(EUISoundType.MenuContextMenu);
- ComponentUtils.SetFireMode(component, fireMode);
- },
- Enabled = () => fireMode != component.FireMode
- });
- }
- }
+ Singleton.Instance.PlayUISound(EUISoundType.MenuContextMenu);
+ ComponentUtils.SetFireMode(component, fireMode);
+ },
+ Enabled = () => fireMode != component.FireMode
+ }));
}
+}
- internal class LightModeSubMenu : CustomSubInteractions
+internal class LightModeSubMenu : CustomSubInteractions
+{
+ public LightModeSubMenu(ItemUiContext uiContext, LightComponent component)
+ : base(uiContext)
{
- public LightModeSubMenu(ItemUiContext uiContext, LightComponent component)
- : base(uiContext)
+ AddRange(Enumerable.Range(0, component.GetModesCount()).Select(lightMode => new CustomInteraction()
{
- foreach (var lightMode in Enumerable.Range(0, component.GetModesCount()))
+ Caption = () => $"Mode {lightMode + 1}",
+ Action = () =>
{
- Add(new CustomInteraction()
- {
- Caption = () => $"Mode {lightMode + 1}",
- Action = () =>
- {
- Singleton.Instance.PlayUISound(EUISoundType.MenuContextMenu);
- ComponentUtils.SetLightState(component, component.IsActive, lightMode);
- },
- Enabled = () => lightMode != component.SelectedMode
- });
- }
- }
+ Singleton.Instance.PlayUISound(EUISoundType.MenuContextMenu);
+ ComponentUtils.SetLightState(component, component.IsActive, lightMode);
+ },
+ Enabled = () => lightMode != component.SelectedMode
+ }));
}
+}
- internal static class ComponentUtils
+internal static class ComponentUtils
+{
+ public static void SetFireMode(FireModeComponent component, Weapon.EFireMode fireMode)
{
- public static void SetFireMode(FireModeComponent component, Weapon.EFireMode fireMode)
+ Player player = GamePlayerOwner.MyPlayer;
+
+ if (player is not null && player.HandsController is Player.FirearmController fc && component.Item == fc.Item)
{
- var player = GamePlayerOwner.MyPlayer;
- if (player != null && player.HandsController is Player.FirearmController fc && component.Item == fc.Item)
+ if (fc.Item.MalfState.State is not Weapon.EMalfunctionState.None)
{
- if (fc.Item.MalfState.State == Weapon.EMalfunctionState.None)
- {
- fc.ChangeFireMode(fireMode);
- }
- else
- {
- fc.FirearmsAnimator.MisfireSlideUnknown(false);
- player.GetInventoryController().ExamineMalfunction(fc.Item, false);
- }
+ fc.FirearmsAnimator.MisfireSlideUnknown(false);
+ player.GetInventoryController().ExamineMalfunction(fc.Item, false);
return;
}
- component.SetFireMode(fireMode);
+ fc.ChangeFireMode(fireMode);
+ return;
}
- public static void SetLightState(LightComponent component, bool isActive, int lightMode)
+ component.SetFireMode(fireMode);
+ }
+
+ public static void SetLightState(LightComponent component, bool isActive, int lightMode)
+ {
+ Player player = GamePlayerOwner.MyPlayer;
+
+ if (player is not null && player.HandsController is Player.FirearmController fc && component.Item.IsChildOf(fc.Item))
{
- var player = GamePlayerOwner.MyPlayer;
- if (player != null && player.HandsController is Player.FirearmController fc && component.Item.IsChildOf(fc.Item))
- {
- var state = new LightsState
- {
- Id = component.Item.Id,
- IsActive = isActive,
- LightMode = lightMode
- };
- fc.SetLightsState(new[] { state });
- return;
- }
+ fc.SetLightsState([new() { Id = component.Item.Id, IsActive = isActive, LightMode = lightMode }]);
+ return;
+ }
- component.IsActive = isActive;
- component.SelectedMode = lightMode;
+ component.IsActive = isActive;
+ component.SelectedMode = lightMode;
- if (player != null)
+ if (player is not null)
+ {
+ foreach (TacticalComboVisualController tcvc in player.GetComponentsInChildren())
{
- foreach (var tcvc in player.GetComponentsInChildren())
+ if (ReferenceEquals(tcvc.LightMod, component))
{
- if (ReferenceEquals(tcvc.LightMod, component))
- {
- tcvc.UpdateBeams();
- break;
- }
+ tcvc.UpdateBeams();
+ break;
}
}
}
diff --git a/ItemContextMenuExt/ItemContextMenuExt.csproj b/ItemContextMenuExt/ItemContextMenuExt.csproj
index c11309d..99eb56c 100644
--- a/ItemContextMenuExt/ItemContextMenuExt.csproj
+++ b/ItemContextMenuExt/ItemContextMenuExt.csproj
@@ -5,6 +5,7 @@
IcyClawz.ItemContextMenuExt
1.2.1
IcyClawz.ItemContextMenuExt
+ latest
diff --git a/ItemContextMenuExt/Plugin.cs b/ItemContextMenuExt/Plugin.cs
index 8aef43d..11bf788 100644
--- a/ItemContextMenuExt/Plugin.cs
+++ b/ItemContextMenuExt/Plugin.cs
@@ -1,14 +1,12 @@
using BepInEx;
using IcyClawz.CustomInteractions;
-namespace IcyClawz.ItemContextMenuExt
+namespace IcyClawz.ItemContextMenuExt;
+
+[BepInPlugin("com.IcyClawz.ItemContextMenuExt", "IcyClawz.ItemContextMenuExt", "1.2.1")]
+[BepInDependency("com.IcyClawz.CustomInteractions")]
+public class Plugin : BaseUnityPlugin
{
- [BepInPlugin("com.IcyClawz.ItemContextMenuExt", "IcyClawz.ItemContextMenuExt", "1.2.1")]
- public class Plugin : BaseUnityPlugin
- {
- private void Awake()
- {
- CustomInteractionsManager.Register(new CustomInteractionsProvider());
- }
- }
+ private void Awake() =>
+ CustomInteractionsManager.Register(new CustomInteractionsProvider());
}
diff --git a/ItemSellPrice/ItemSellPrice.cs b/ItemSellPrice/ItemSellPrice.cs
index 674497e..88630ae 100644
--- a/ItemSellPrice/ItemSellPrice.cs
+++ b/ItemSellPrice/ItemSellPrice.cs
@@ -10,203 +10,139 @@ using UnityEngine;
using CurrencyUtil = GClass2334;
-namespace IcyClawz.ItemSellPrice
+namespace IcyClawz.ItemSellPrice;
+
+internal static class TraderClassExtensions
{
- internal static class TraderClassExtensions
+ private static ISession _Session;
+ private static ISession Session => _Session ??= ClientAppUtils.GetMainApp().GetClientBackEndSession();
+
+ private static readonly FieldInfo SupplyDataField =
+ typeof(TraderClass).GetField("supplyData_0", BindingFlags.NonPublic | BindingFlags.Instance);
+
+ public static SupplyData GetSupplyData(this TraderClass trader) =>
+ SupplyDataField.GetValue(trader) as SupplyData;
+
+ public static void SetSupplyData(this TraderClass trader, SupplyData supplyData) =>
+ SupplyDataField.SetValue(trader, supplyData);
+
+ public static async void UpdateSupplyData(this TraderClass trader)
{
- private static ISession Session => ClientAppUtils.GetMainApp().GetClientBackEndSession();
-
- private static readonly FieldInfo SupplyDataField =
- typeof(TraderClass).GetField("supplyData_0", BindingFlags.NonPublic | BindingFlags.Instance);
-
- public static SupplyData GetSupplyData(this TraderClass trader) =>
- SupplyDataField.GetValue(trader) as SupplyData;
-
- public static void SetSupplyData(this TraderClass trader, SupplyData supplyData) =>
- SupplyDataField.SetValue(trader, supplyData);
-
- public static async void UpdateSupplyData(this TraderClass trader)
- {
- Result result = await Session.GetSupplyData(trader.Id);
- if (result.Failed)
- {
- Debug.LogError("Failed to download supply data");
- return;
- }
+ Result result = await Session.GetSupplyData(trader.Id);
+ if (result.Succeed)
trader.SetSupplyData(result.Value);
- }
+ else
+ Debug.LogError("Failed to download supply data");
}
+}
- internal static class ItemExtensions
+internal static class ItemExtensions
+{
+ private static readonly Dictionary DisplayNames = new()
{
- private static readonly Dictionary DisplayNames = new Dictionary()
+ ["ch"] = ["售价({0})", "无法出售给商人"],
+ ["cz"] = ["Prodejní cena ({0})", "Nemůže být prodán obchodníkům"],
+ ["en"] = ["Selling price ({0})", "Cannot be sold to traders"],
+ ["es"] = ["Precio de venta ({0})", "No puede ser vendido a los vendedores"],
+ ["es-mx"] = ["Precio de venta ({0})", "No puede ser vendido a comerciantes"],
+ ["fr"] = ["Prix de vente ({0})", "Ne peut pas être vendu aux marchands"],
+ ["ge"] = ["Verkaufspreis ({0})", "Kann nicht an Händler verkauft werden"],
+ ["hu"] = ["Eladási ár ({0})", "Kereskedőknek nem adható el"],
+ ["it"] = ["Prezzo di vendita ({0})", "Non vendibile ai mercanti"],
+ ["jp"] = ["販売価格({0})", "トレーダーには販売できません"],
+ ["kr"] = ["판매 가격 ({0})", "상인에게 판매 불가"],
+ ["pl"] = ["Cena sprzedaży ({0})", "Nie można sprzedawać handlarzom"],
+ ["po"] = ["Preço de venda ({0})", "Não pode ser vendido a comerciantes"],
+ ["ru"] = ["Цена продажи ({0})", "Невозможно продать торговцам"],
+ ["sk"] = ["Predajná cena ({0})", "Nedá sa predať obchodníkom"],
+ ["tu"] = ["Satış fiyatı ({0})", "Tüccarlara satılamaz"]
+ };
+
+ private static ISession _Session;
+ private static ISession Session => _Session ??= ClientAppUtils.GetMainApp().GetClientBackEndSession();
+
+ public static void AddTraderOfferAttribute(this Item item)
+ {
+ ItemAttributeClass attribute = new(EItemAttributeId.MoneySum)
{
- { "ch", new[] { "售价({0})", "无法出售给商人" } },
- { "cz", new[] { "Prodejní cena ({0})", "Nemůže být prodán obchodníkům" } },
- { "en", new[] { "Selling price ({0})", "Cannot be sold to traders" } },
- { "es", new[] { "Precio de venta ({0})", "No puede ser vendido a los vendedores" } },
- { "es-mx", new[] { "Precio de venta ({0})", "No puede ser vendido a comerciantes" } },
- { "fr", new[] { "Prix de vente ({0})", "Ne peut pas être vendu aux marchands" } },
- { "ge", new[] { "Verkaufspreis ({0})", "Kann nicht an Händler verkauft werden" } },
- { "hu", new[] { "Eladási ár ({0})", "Kereskedőknek nem adható el" } },
- { "it", new[] { "Prezzo di vendita ({0})", "Non vendibile ai mercanti" } },
- { "jp", new[] { "販売価格({0})", "トレーダーには販売できません" } },
- { "kr", new[] { "판매 가격 ({0})", "상인에게 판매 불가" } },
- { "pl", new[] { "Cena sprzedaży ({0})", "Nie można sprzedawać handlarzom" } },
- { "po", new[] { "Preço de venda ({0})", "Não pode ser vendido a comerciantes" } },
- { "ru", new[] { "Цена продажи ({0})", "Невозможно продать торговцам" } },
- { "sk", new[] { "Predajná cena ({0})", "Nedá sa predať obchodníkom" } },
- { "tu", new[] { "Satış fiyatı ({0})", "Tüccarlara satılamaz" } }
+ Name = EItemAttributeId.MoneySum.GetName(),
+ DisplayNameFunc = () =>
+ {
+ string language = Singleton.Instance?.Game?.Settings?.Language?.GetValue();
+ if (language is null || !DisplayNames.ContainsKey(language))
+ language = "en";
+ TraderOffer offer = GetBestTraderOffer(item);
+ return offer is not null
+ ? string.Format(DisplayNames[language][0], offer.Name)
+ : DisplayNames[language][1];
+ },
+ Base = () =>
+ {
+ TraderOffer offer = GetBestTraderOffer(item);
+ return offer is not null ? offer.Price : 0.01f;
+ },
+ StringValue = () =>
+ {
+ TraderOffer offer = GetBestTraderOffer(item);
+ return offer is not null
+ ? $"{offer.Currency} {offer.Price}" + (offer.Count > 1 ? $" ({offer.Count})" : "")
+ : "";
+ },
+ FullStringValue = () =>
+ {
+ IEnumerable offers = GetAllTraderOffers(item);
+ return offers is not null
+ ? string.Join(Environment.NewLine, offers.Select(offer => $"{offer.Name}: {offer.Currency} {offer.Price}"))
+ : "";
+ },
+ DisplayType = () => EItemAttributeDisplayType.Compact
};
-
- private static ISession Session => ClientAppUtils.GetMainApp().GetClientBackEndSession();
-
- public static void AddTraderOfferAttribute(this Item item)
- {
- ItemAttributeClass attribute = new ItemAttributeClass(EItemAttributeId.MoneySum)
- {
- Name = EItemAttributeId.MoneySum.GetName(),
- DisplayNameFunc = () =>
- {
- string language = Singleton.Instance?.Game?.Settings?.Language?.GetValue();
- if (language == null || !DisplayNames.ContainsKey(language))
- {
- language = "en";
- }
- if (GetBestTraderOffer(item) is TraderOffer offer)
- {
- return string.Format(DisplayNames[language][0], offer.Name);
- }
- else
- {
- return DisplayNames[language][1];
- }
- },
- Base = () =>
- {
- if (GetBestTraderOffer(item) is TraderOffer offer)
- {
- return offer.Price;
- }
- else
- {
- return 0.01f;
- }
- },
- StringValue = () =>
- {
- if (GetBestTraderOffer(item) is TraderOffer offer)
- {
- string value = $"{offer.Currency} {offer.Price}";
- if (offer.Count > 1)
- {
- value += $" ({offer.Count})";
- }
- return value;
- }
- else
- {
- return string.Empty;
- }
- },
- FullStringValue = () =>
- {
- if (GetAllTraderOffers(item) is List offers)
- {
- string[] lines = new string[offers.Count];
- for (int i = 0; i < offers.Count; i++)
- {
- TraderOffer offer = offers[i];
- lines[i] = $"{offer.Name}: {offer.Currency} {offer.Price}";
- }
- return string.Join(Environment.NewLine, lines);
- }
- else
- {
- return string.Empty;
- }
- },
- DisplayType = () => EItemAttributeDisplayType.Compact
- };
- List attributes = new List { attribute };
- attributes.AddRange(item.Attributes);
- item.Attributes = attributes;
- }
-
- private sealed class TraderOffer
- {
- public string Name;
- public int Price;
- public string Currency;
- public double Course;
- public int Count;
-
- public TraderOffer(string name, int price, string currency, double course, int count)
- {
- Name = name;
- Price = price;
- Currency = currency;
- Course = course;
- Count = count;
- }
- }
-
- private static TraderOffer GetTraderOffer(Item item, TraderClass trader)
- {
- var result = trader.GetUserItemPrice(item);
- if (result == null)
- {
- return null;
- }
- return new TraderOffer(
- trader.LocalizedName,
- result.Value.Amount,
- CurrencyUtil.GetCurrencyCharById(result.Value.CurrencyId),
- trader.GetSupplyData().CurrencyCourses[result.Value.CurrencyId],
- item.StackObjectsCount
- );
- }
-
- private static List GetAllTraderOffers(Item item)
- {
- if (!Session.Profile.Examined(item))
- {
- return null;
- }
- switch (item.Owner?.OwnerType)
- {
- case EOwnerType.RagFair:
- case EOwnerType.Trader:
- if (item.StackObjectsCount > 1 || item.UnlimitedCount)
- {
- item = item.CloneItem();
- item.StackObjectsCount = 1;
- item.UnlimitedCount = false;
- }
- break;
- }
- List offers = new List();
- foreach (TraderClass trader in Session.Traders)
- {
- if (GetTraderOffer(item, trader) is TraderOffer offer)
- {
- offers.Add(offer);
- }
- }
- offers.Sort((x, y) => (y.Price * y.Course).CompareTo(x.Price * x.Course));
- return offers;
- }
-
- private static TraderOffer GetBestTraderOffer(Item item)
- {
- if (GetAllTraderOffers(item) is List offers)
- {
- return offers.FirstOrDefault();
- }
- else
- {
- return null;
- }
- }
+ item.Attributes = [attribute, .. item.Attributes];
}
+
+ private sealed class TraderOffer(string name, int price, string currency, double course, int count)
+ {
+ public string Name = name;
+ public int Price = price;
+ public string Currency = currency;
+ public double Course = course;
+ public int Count = count;
+ }
+
+ private static TraderOffer GetTraderOffer(Item item, TraderClass trader)
+ {
+ var result = trader.GetUserItemPrice(item);
+ return result is null ? null : new(
+ trader.LocalizedName,
+ result.Value.Amount,
+ CurrencyUtil.GetCurrencyCharById(result.Value.CurrencyId),
+ trader.GetSupplyData().CurrencyCourses[result.Value.CurrencyId],
+ item.StackObjectsCount
+ );
+ }
+
+ private static IEnumerable GetAllTraderOffers(Item item)
+ {
+ if (!Session.Profile.Examined(item))
+ return null;
+ switch (item.Owner?.OwnerType)
+ {
+ case EOwnerType.RagFair:
+ case EOwnerType.Trader:
+ if (item.StackObjectsCount > 1 || item.UnlimitedCount)
+ {
+ item = item.CloneItem();
+ item.StackObjectsCount = 1;
+ item.UnlimitedCount = false;
+ }
+ break;
+ }
+ return Session.Traders
+ .Select(trader => GetTraderOffer(item, trader))
+ .Where(offer => offer is not null)
+ .OrderByDescending(offer => offer.Price * offer.Course);
+ }
+
+ private static TraderOffer GetBestTraderOffer(Item item) =>
+ GetAllTraderOffers(item)?.FirstOrDefault() ?? null;
}
\ No newline at end of file
diff --git a/ItemSellPrice/ItemSellPrice.csproj b/ItemSellPrice/ItemSellPrice.csproj
index 4d8fd8f..52060ab 100644
--- a/ItemSellPrice/ItemSellPrice.csproj
+++ b/ItemSellPrice/ItemSellPrice.csproj
@@ -5,6 +5,7 @@
IcyClawz.ItemSellPrice
1.2.1
IcyClawz.ItemSellPrice
+ latest
diff --git a/ItemSellPrice/Plugin.cs b/ItemSellPrice/Plugin.cs
index 157285c..e4d9461 100644
--- a/ItemSellPrice/Plugin.cs
+++ b/ItemSellPrice/Plugin.cs
@@ -3,78 +3,67 @@ using BepInEx;
using EFT.InventoryLogic;
using System.Reflection;
-namespace IcyClawz.ItemSellPrice
+namespace IcyClawz.ItemSellPrice;
+
+[BepInPlugin("com.IcyClawz.ItemSellPrice", "IcyClawz.ItemSellPrice", "1.2.1")]
+public class Plugin : BaseUnityPlugin
{
- [BepInPlugin("com.IcyClawz.ItemSellPrice", "IcyClawz.ItemSellPrice", "1.2.1")]
- public class Plugin : BaseUnityPlugin
+ private void Awake()
{
- private void Awake()
- {
- new TraderPatch().Enable();
- new ItemPatch().Enable();
- new AmmoPatch().Enable();
- new GrenadePatch().Enable();
- new SecureContainerPatch().Enable();
- }
- }
-
- internal class TraderPatch : ModulePatch
- {
- protected override MethodBase GetTargetMethod() =>
- typeof(TraderClass).GetConstructors()[0];
-
- [PatchPostfix]
- private static void PatchPostfix(ref TraderClass __instance)
- {
- __instance.UpdateSupplyData();
- }
- }
-
- internal class ItemPatch : ModulePatch
- {
- protected override MethodBase GetTargetMethod() =>
- typeof(Item).GetConstructors()[0];
-
- [PatchPostfix]
- private static void PatchPostfix(ref Item __instance)
- {
- __instance.AddTraderOfferAttribute();
- }
- }
-
- internal class AmmoPatch : ModulePatch
- {
- protected override MethodBase GetTargetMethod() =>
- typeof(BulletClass).GetConstructors()[0];
-
- [PatchPostfix]
- private static void PatchPostfix(ref BulletClass __instance)
- {
- __instance.AddTraderOfferAttribute();
- }
- }
-
- internal class GrenadePatch : ModulePatch
- {
- protected override MethodBase GetTargetMethod() =>
- typeof(GrenadeClass).GetConstructors()[0];
-
- [PatchPostfix]
- private static void PatchPostfix(ref GrenadeClass __instance)
- {
- __instance.AddTraderOfferAttribute();
- }
- }
-
- internal class SecureContainerPatch : ModulePatch
- {
- protected override MethodBase GetTargetMethod() =>
- typeof(ItemContainerClass).GetConstructors()[0];
-
- [PatchPostfix]
- private static void PatchPostfix(ref ItemContainerClass __instance)
- {
- __instance.AddTraderOfferAttribute();
- }
+ new TraderPatch().Enable();
+ new ItemPatch().Enable();
+ new AmmoPatch().Enable();
+ new GrenadePatch().Enable();
+ new SecureContainerPatch().Enable();
}
}
+
+internal class TraderPatch : ModulePatch
+{
+ protected override MethodBase GetTargetMethod() =>
+ typeof(TraderClass).GetConstructors()[0];
+
+ [PatchPostfix]
+ private static void PatchPostfix(ref TraderClass __instance) =>
+ __instance.UpdateSupplyData();
+}
+
+internal class ItemPatch : ModulePatch
+{
+ protected override MethodBase GetTargetMethod() =>
+ typeof(Item).GetConstructors()[0];
+
+ [PatchPostfix]
+ private static void PatchPostfix(ref Item __instance) =>
+ __instance.AddTraderOfferAttribute();
+}
+
+internal class AmmoPatch : ModulePatch
+{
+ protected override MethodBase GetTargetMethod() =>
+ typeof(BulletClass).GetConstructors()[0];
+
+ [PatchPostfix]
+ private static void PatchPostfix(ref BulletClass __instance) =>
+ __instance.AddTraderOfferAttribute();
+}
+
+internal class GrenadePatch : ModulePatch
+{
+ protected override MethodBase GetTargetMethod() =>
+ typeof(GrenadeClass).GetConstructors()[0];
+
+ [PatchPostfix]
+ private static void PatchPostfix(ref GrenadeClass __instance) =>
+ __instance.AddTraderOfferAttribute();
+}
+
+internal class SecureContainerPatch : ModulePatch
+{
+ protected override MethodBase GetTargetMethod() =>
+ typeof(ItemContainerClass).GetConstructors()[0];
+
+ [PatchPostfix]
+ private static void PatchPostfix(ref ItemContainerClass __instance) =>
+ __instance.AddTraderOfferAttribute();
+}
diff --git a/MagazineInspector/MagazineInspector.cs b/MagazineInspector/MagazineInspector.cs
index cb8c9d0..2816864 100644
--- a/MagazineInspector/MagazineInspector.cs
+++ b/MagazineInspector/MagazineInspector.cs
@@ -9,140 +9,85 @@ using UnityEngine;
using InGameStatus = GClass1716;
-namespace IcyClawz.MagazineInspector
+namespace IcyClawz.MagazineInspector;
+
+internal static class MagazineClassExtensions
{
- internal static class MagazineClassExtensions
+ private static readonly Dictionary DisplayNames = new()
{
- private static readonly Dictionary DisplayNames = new Dictionary()
+ ["ch"] = "上膛弹药",
+ ["cz"] = "Nabité střelivo",
+ ["en"] = "Loaded ammo",
+ ["es"] = "Munición cargada",
+ ["es-mx"] = "Munición cargada",
+ ["fr"] = "Munitions chargées",
+ ["ge"] = "Geladene Munition",
+ ["hu"] = "Töltött lőszer",
+ ["it"] = "Munizioni caricate",
+ ["jp"] = "装填弾薬",
+ ["kr"] = "장전 탄약",
+ ["pl"] = "Załadowana amunicja",
+ ["po"] = "Munição carregada",
+ ["ru"] = "Заряженные боеприпасы",
+ ["sk"] = "Nabitá munícia",
+ ["tu"] = "Yüklü mühimmat"
+ };
+
+ private static ISession _Session;
+ private static ISession Session => _Session ??= ClientAppUtils.GetMainApp().GetClientBackEndSession();
+
+ private static Profile ActiveProfile => InGameStatus.InRaid ? GamePlayerOwner.MyPlayer.Profile : Session.Profile;
+
+ public static void AddAmmoCountAttribute(this MagazineClass magazine)
+ {
+ ItemAttributeClass attribute = magazine.Attributes.Find(attr => attr.Id is EItemAttributeId.MaxCount);
+ if (attribute is null)
+ return;
+ attribute.DisplayNameFunc = () =>
{
- { "ch", "上膛弹药" },
- { "cz", "Nabité střelivo" },
- { "en", "Loaded ammo" },
- { "es", "Munición cargada" },
- { "es-mx", "Munición cargada" },
- { "fr", "Munitions chargées" },
- { "ge", "Geladene Munition" },
- { "hu", "Töltött lőszer" },
- { "it", "Munizioni caricate" },
- { "jp", "装填弾薬" },
- { "kr", "장전 탄약" },
- { "pl", "Załadowana amunicja" },
- { "po", "Munição carregada" },
- { "ru", "Заряженные боеприпасы" },
- { "sk", "Nabitá munícia" },
- { "tu", "Yüklü mühimmat" }
+ string language = Singleton.Instance?.Game?.Settings?.Language?.GetValue();
+ if (language is null || !DisplayNames.ContainsKey(language))
+ language = "en";
+ return DisplayNames[language];
};
-
- private static ISession Session => ClientAppUtils.GetMainApp().GetClientBackEndSession();
-
- private static Profile ActiveProfile => InGameStatus.InRaid ? GamePlayerOwner.MyPlayer.Profile : Session.Profile;
-
- public static void AddAmmoCountAttribute(this MagazineClass magazine)
+ attribute.Base = () =>
{
- ItemAttributeClass attribute = magazine.Attributes.Find(attr => attr.Id is EItemAttributeId.MaxCount);
- if (attribute == null)
- {
- return;
- }
- attribute.DisplayNameFunc = () =>
- {
- string language = Singleton.Instance?.Game?.Settings?.Language?.GetValue();
- if (language == null || !DisplayNames.ContainsKey(language))
+ int? ammoCount = GetAmmoCount(magazine, ActiveProfile, out _);
+ return ammoCount ?? 0f;
+ };
+ attribute.StringValue = () =>
+ {
+ int? ammoCount = GetAmmoCount(magazine, ActiveProfile, out _);
+ return $"{ammoCount?.ToString() ?? "?"}/{magazine.MaxCount}";
+ };
+ attribute.FullStringValue = () =>
+ {
+ int? ammoCount = GetAmmoCount(magazine, ActiveProfile, out bool magChecked);
+ return magChecked
+ ? string.Join(Environment.NewLine, magazine.Cartridges.Items.Reverse().Select(cartridge =>
{
- language = "en";
- }
- return DisplayNames[language];
- };
- attribute.Base = () =>
- {
- if (GetAmmoCount(magazine, ActiveProfile, out _) is int ammoCount)
- {
- return ammoCount;
- }
- else
- {
- return 0f;
- }
- };
- attribute.StringValue = () =>
- {
- string value;
- if (GetAmmoCount(magazine, ActiveProfile, out _) is int ammoCount)
- {
- value = ammoCount.ToString();
- }
- else
- {
- value = "?";
- }
- return $"{value}/{magazine.MaxCount}";
- };
- attribute.FullStringValue = () =>
- {
- Profile profile = ActiveProfile;
- int? ammoCount = GetAmmoCount(magazine, profile, out bool magChecked);
- if (magChecked)
- {
- List- cartridges = new List
- (magazine.Cartridges.Items);
- string[] lines = new string[cartridges.Count];
- int i = cartridges.Count - 1;
- foreach (Item cartridge in cartridges)
- {
- string count;
- if (ammoCount != null)
- {
- count = cartridge.StackObjectsCount.ToString();
- }
- else
- {
- count = "?";
- }
- string name;
- if (profile.Examined(cartridge))
- {
- name = cartridge.LocalizedName();
- }
- else
- {
- name = "Unknown item".Localized();
- }
- lines[i--] = $"{count} × {name}";
- }
- return string.Join(Environment.NewLine, lines);
- }
- else
- {
- return string.Empty;
- }
- };
+ string count = ammoCount is not null ? cartridge.StackObjectsCount.ToString() : "?";
+ string name = ActiveProfile.Examined(cartridge) ? cartridge.LocalizedName() : "Unknown item".Localized();
+ return $"{count} × {name}";
+ }))
+ : "";
+ };
+ }
+
+ private static int? GetAmmoCount(MagazineClass magazine, Profile profile, out bool magChecked)
+ {
+ if (!InGameStatus.InRaid || magazine.Count == 0)
+ {
+ magChecked = true;
+ return magazine.Count;
}
-
- private static int? GetAmmoCount(MagazineClass magazine, Profile profile, out bool magChecked)
- {
- if (!InGameStatus.InRaid || magazine.Count == 0)
- {
- magChecked = true;
- return magazine.Count;
- }
- magChecked = profile.CheckedMagazines.ContainsKey(magazine.Id);
- if (magChecked)
- {
- bool equipped = profile.Inventory.Equipment.GetAllSlots().Any(slot => ReferenceEquals(slot.ContainedItem, magazine));
- if (magazine.Count >= (equipped ? magazine.MaxCount - 1 : magazine.MaxCount))
- {
- return magazine.Count;
- }
- int skill = Mathf.Max(
- profile.MagDrillsMastering,
- profile.CheckedMagazineSkillLevel(magazine.Id),
- magazine.CheckOverride
- );
- if (skill > 1 || (skill == 1 && magazine.MaxCount <= 10))
- {
- return magazine.Count;
- }
- }
+ magChecked = profile.CheckedMagazines.ContainsKey(magazine.Id);
+ if (!magChecked)
return null;
- }
+ bool equipped = profile.Inventory.Equipment.GetAllSlots().Any(slot => ReferenceEquals(slot.ContainedItem, magazine));
+ if (magazine.Count >= (equipped ? magazine.MaxCount - 1 : magazine.MaxCount))
+ return magazine.Count;
+ int skill = Mathf.Max(profile.MagDrillsMastering, profile.CheckedMagazineSkillLevel(magazine.Id), magazine.CheckOverride);
+ return skill > 1 || (skill == 1 && magazine.MaxCount <= 10) ? magazine.Count : null;
}
}
\ No newline at end of file
diff --git a/MagazineInspector/MagazineInspector.csproj b/MagazineInspector/MagazineInspector.csproj
index 483f493..d64e652 100644
--- a/MagazineInspector/MagazineInspector.csproj
+++ b/MagazineInspector/MagazineInspector.csproj
@@ -5,6 +5,7 @@
IcyClawz.MagazineInspector
1.2.1
IcyClawz.MagazineInspector
+ latest
diff --git a/MagazineInspector/Plugin.cs b/MagazineInspector/Plugin.cs
index 09fa24f..60eba78 100644
--- a/MagazineInspector/Plugin.cs
+++ b/MagazineInspector/Plugin.cs
@@ -2,26 +2,21 @@ using Aki.Reflection.Patching;
using BepInEx;
using System.Reflection;
-namespace IcyClawz.MagazineInspector
-{
- [BepInPlugin("com.IcyClawz.MagazineInspector", "IcyClawz.MagazineInspector", "1.2.1")]
- public class Plugin : BaseUnityPlugin
- {
- private void Awake()
- {
- new MagazinePatch().Enable();
- }
- }
+namespace IcyClawz.MagazineInspector;
- internal class MagazinePatch : ModulePatch
- {
- protected override MethodBase GetTargetMethod() =>
- typeof(MagazineClass).GetConstructors()[0];
-
- [PatchPostfix]
- private static void PatchPostfix(ref MagazineClass __instance)
- {
- __instance.AddAmmoCountAttribute();
- }
- }
+[BepInPlugin("com.IcyClawz.MagazineInspector", "IcyClawz.MagazineInspector", "1.2.1")]
+public class Plugin : BaseUnityPlugin
+{
+ private void Awake() =>
+ new MagazinePatch().Enable();
+}
+
+internal class MagazinePatch : ModulePatch
+{
+ protected override MethodBase GetTargetMethod() =>
+ typeof(MagazineClass).GetConstructors()[0];
+
+ [PatchPostfix]
+ private static void PatchPostfix(ref MagazineClass __instance) =>
+ __instance.AddAmmoCountAttribute();
}
diff --git a/MunitionsExpert/ConfigurationManagerAttributes.cs b/MunitionsExpert/ConfigurationManagerAttributes.cs
new file mode 100644
index 0000000..6dc8950
--- /dev/null
+++ b/MunitionsExpert/ConfigurationManagerAttributes.cs
@@ -0,0 +1,112 @@
+#pragma warning disable 0169, 0414, 0649
+using BepInEx.Configuration;
+
+
+///
+/// Class that specifies how a setting should be displayed inside the ConfigurationManager settings window.
+///
+/// Usage:
+/// This class template has to be copied inside the plugin's project and referenced by its code directly.
+/// make a new instance, assign any fields that you want to override, and pass it as a tag for your setting.
+///
+/// If a field is null (default), it will be ignored and won't change how the setting is displayed.
+/// If a field is non-null (you assigned a value to it), it will override default behavior.
+///
+///
+///
+/// Here's an example of overriding order of settings and marking one of the settings as advanced:
+///
+/// // Override IsAdvanced and Order
+/// Config.Bind("X", "1", 1, new ConfigDescription("", null, new ConfigurationManagerAttributes { IsAdvanced = true, Order = 3 }));
+/// // Override only Order, IsAdvanced stays as the default value assigned by ConfigManager
+/// Config.Bind("X", "2", 2, new ConfigDescription("", null, new ConfigurationManagerAttributes { Order = 1 }));
+/// Config.Bind("X", "3", 3, new ConfigDescription("", null, new ConfigurationManagerAttributes { Order = 2 }));
+///
+///
+///
+///
+/// You can read more and see examples in the readme at https://github.com/BepInEx/BepInEx.ConfigurationManager
+/// You can optionally remove fields that you won't use from this class, it's the same as leaving them null.
+///
+internal sealed class ConfigurationManagerAttributes
+{
+ ///
+ /// Should the setting be shown as a percentage (only use with value range settings).
+ ///
+ public bool? ShowRangeAsPercent;
+
+ ///
+ /// Custom setting editor (OnGUI code that replaces the default editor provided by ConfigurationManager).
+ /// See below for a deeper explanation. Using a custom drawer will cause many of the other fields to do nothing.
+ ///
+ public System.Action CustomDrawer;
+
+ ///
+ /// Show this setting in the settings screen at all? If false, don't show.
+ ///
+ public bool? Browsable;
+
+ ///
+ /// Category the setting is under. Null to be directly under the plugin.
+ ///
+ public string Category;
+
+ ///
+ /// If set, a "Default" button will be shown next to the setting to allow resetting to default.
+ ///
+ public object DefaultValue;
+
+ ///
+ /// Force the "Reset" button to not be displayed, even if a valid DefaultValue is available.
+ ///
+ public bool? HideDefaultButton;
+
+ ///
+ /// Force the setting name to not be displayed. Should only be used with a to get more space.
+ /// Can be used together with to gain even more space.
+ ///
+ public bool? HideSettingName;
+
+ ///
+ /// Optional description shown when hovering over the setting.
+ /// Not recommended, provide the description when creating the setting instead.
+ ///
+ public string Description;
+
+ ///
+ /// Name of the setting.
+ ///
+ public string DispName;
+
+ ///
+ /// Order of the setting on the settings list relative to other settings in a category.
+ /// 0 by default, higher number is higher on the list.
+ ///
+ public int? Order;
+
+ ///
+ /// Only show the value, don't allow editing it.
+ ///
+ public bool? ReadOnly;
+
+ ///
+ /// If true, don't show the setting by default. User has to turn on showing advanced settings or search for it.
+ ///
+ public bool? IsAdvanced;
+
+ ///
+ /// Custom converter from setting type to string for the built-in editor textboxes.
+ ///
+ public System.Func