Depend on EFTApi and refactor code

This commit is contained in:
kmyuhkyuk 2024-04-08 10:45:58 +08:00
parent d75de1aa04
commit f7caaaadaf
13 changed files with 255 additions and 747 deletions

View File

@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.1.32407.343 VisualStudioVersion = 17.1.32407.343
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SkinHide", "SkinHide\SkinHide.csproj", "{E5DD6484-115E-4104-AADF-E5610EE4F397}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HideDress", "HideDress\HideDress.csproj", "{E5DD6484-115E-4104-AADF-E5610EE4F397}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution

View File

@ -7,8 +7,8 @@
<ProjectGuid>{E5DD6484-115E-4104-AADF-E5610EE4F397}</ProjectGuid> <ProjectGuid>{E5DD6484-115E-4104-AADF-E5610EE4F397}</ProjectGuid>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SkinHide</RootNamespace> <RootNamespace>HideDress</RootNamespace>
<AssemblyName>SkinHide</AssemblyName> <AssemblyName>HideDress</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion> <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic> <Deterministic>true</Deterministic>
@ -55,6 +55,12 @@
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>R:\Battlestate Games\Client.0.12.12.15.17349\EscapeFromTarkov_Data\Managed\Comfort.dll</HintPath> <HintPath>R:\Battlestate Games\Client.0.12.12.15.17349\EscapeFromTarkov_Data\Managed\Comfort.dll</HintPath>
</Reference> </Reference>
<Reference Include="EFTApi">
<HintPath>..\..\EFTApi\Build\bin\Current\EFTApi.dll</HintPath>
</Reference>
<Reference Include="EFTReflection">
<HintPath>..\..\EFTApi\Build\bin\Current\EFTReflection.dll</HintPath>
</Reference>
<Reference Include="Sirenix.Serialization, Version=3.0.4.0, Culture=neutral, PublicKeyToken=null" /> <Reference Include="Sirenix.Serialization, Version=3.0.4.0, Culture=neutral, PublicKeyToken=null" />
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
@ -78,11 +84,12 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Patches\PlayerPatch.cs" /> <Compile Include="Models\ReflectionModel.cs" />
<Compile Include="Patches\PlayerModelViewPatch.cs" /> <Compile Include="Models\SettingsModel.cs" />
<Compile Include="SkinHidePlugin.cs" /> <Compile Include="Models\HideDressModel.cs" />
<Compile Include="HideDressPlugin.cs" />
<Compile Include="Patches\PlayerModelViewShow.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Utils\RefHelp.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="kmyuhkyuk.pfx" /> <None Include="kmyuhkyuk.pfx" />

View File

@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=patches/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -0,0 +1,107 @@
using System.Collections.Generic;
using System.Linq;
using BepInEx;
using EFT;
using EFT.Visual;
using HideDress.Models;
using static EFTApi.EFTHelpers;
namespace HideDress
{
[BepInPlugin("com.kmyuhkyuk.HideDress", "kmyuhkyuk-HideDress", "1.2.7")]
[BepInDependency("com.kmyuhkyuk.EFTApi", "1.2.0")]
public partial class HideDressPlugin : BaseUnityPlugin
{
private void Awake()
{
SettingsModel.Create(Config);
}
private void Start()
{
ReflectionModel.Instance.PlayerModelViewShow.Add(this, nameof(PlayerModelViewShow));
}
private void Update()
{
var player = _PlayerHelper.Player;
var world = _GameWorldHelper.GameWorld;
var settingsModel = SettingsModel.Instance;
var hideDressModel = HideDressModel.Instance;
if (settingsModel.KeyPlayerHideDressShortcut.Value.IsDown())
{
settingsModel.KeyPlayerHideDress.Value = !settingsModel.KeyPlayerHideDress.Value;
}
if (settingsModel.KeyOtherPlayerHideDressShortcut.Value.IsDown())
{
settingsModel.KeyOtherPlayerHideDress.Value = !settingsModel.KeyOtherPlayerHideDress.Value;
}
if (hideDressModel.PlayerModelViewBody != null)
{
EnabledPartDress(hideDressModel.PlayerModelViewBody, settingsModel.KeyPlayerHideDressPart.Value, !settingsModel.KeyPlayerHideDress.Value);
}
if (player != null)
{
EnabledPartDress(player.PlayerBody, settingsModel.KeyPlayerHideDressPart.Value, !settingsModel.KeyPlayerHideDress.Value);
}
if (world != null)
{
foreach (var otherPlayer in _GameWorldHelper.AllOtherPlayer)
{
EnabledPartDress(otherPlayer.PlayerBody, settingsModel.KeyOtherPlayerHideDressPart.Value, !settingsModel.KeyOtherPlayerHideDress.Value);
}
}
}
private static void EnabledPartDress(PlayerBody playerBody, HideDressModel.DressPart part, bool enabled)
{
var reflectionModel = ReflectionModel.Instance;
var slotViews = reflectionModel.RefSlotViews.GetValue(playerBody);
var slotList = reflectionModel.RefSlotList.GetValue(slotViews);
var dressList = new List<Dress>();
foreach (var slot in slotList)
{
var dresses = reflectionModel.RefDresses.GetValue(slot);
if (dresses == null)
continue;
foreach (var dress in dresses)
{
dressList.Add(dress);
}
}
EnabledDress(dressList.Where(x => x.GetType() == typeof(Dress)), part == HideDressModel.DressPart.SkinDress || enabled);
EnabledSkinDress(dressList.Where(x => x is SkinDress || x is ArmBandView), part == HideDressModel.DressPart.Dress || enabled);
}
private static void EnabledDress(IEnumerable<Dress> dressEnumerable, bool enabled)
{
foreach (var dress in dressEnumerable)
{
foreach (var renderer in ReflectionModel.Instance.RefRenderers.GetValue(dress))
{
renderer.enabled = enabled;
}
}
}
private static void EnabledSkinDress(IEnumerable<Dress> skinDressEnumerable, bool enabled)
{
foreach (var skinDress in skinDressEnumerable)
{
skinDress.gameObject.SetActive(enabled);
}
}
}
}

View File

@ -0,0 +1,25 @@
using System;
using EFT;
namespace HideDress.Models
{
internal class HideDressModel
{
private static readonly Lazy<HideDressModel> Lazy = new Lazy<HideDressModel>(() => new HideDressModel());
public static HideDressModel Instance => Lazy.Value;
public PlayerBody PlayerModelViewBody;
public enum DressPart
{
Both,
Dress,
SkinDress
}
private HideDressModel()
{
}
}
}

View File

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using EFT;
using EFT.UI;
using EFT.Visual;
using EFTReflection;
using UnityEngine;
namespace HideDress.Models
{
internal class ReflectionModel
{
private static readonly Lazy<ReflectionModel> Lazy = new Lazy<ReflectionModel>(() => new ReflectionModel());
public static ReflectionModel Instance => Lazy.Value;
public readonly RefHelper.FieldRef<PlayerBody, object> RefSlotViews;
public readonly RefHelper.FieldRef<object, IEnumerable<object>> RefSlotList;
public readonly RefHelper.FieldRef<object, Dress[]> RefDresses;
public readonly RefHelper.FieldRef<Dress, Renderer[]> RefRenderers;
public readonly RefHelper.HookRef PlayerModelViewShow;
private ReflectionModel()
{
RefSlotViews = RefHelper.FieldRef<PlayerBody, object>.Create("SlotViews");
RefSlotList = RefHelper.FieldRef<object, IEnumerable<object>>.Create(RefSlotViews.FieldType, "list_0");
RefDresses =
RefHelper.FieldRef<object, Dress[]>.Create(RefSlotList.FieldType.GetGenericArguments()[0], "Dresses");
RefRenderers = RefHelper.FieldRef<Dress, Renderer[]>.Create("Renderers");
PlayerModelViewShow = RefHelper.HookRef.Create(typeof(PlayerModelView), x => x.Name == "Show" && x.GetParameters()[0].ParameterType == typeof(PlayerVisualRepresentation));
}
}
}

View File

@ -0,0 +1,50 @@
using System.Diagnostics.CodeAnalysis;
using BepInEx.Configuration;
namespace HideDress.Models
{
internal class SettingsModel
{
public static SettingsModel Instance { get; private set; }
public readonly ConfigEntry<bool> KeyPlayerHideDress;
public readonly ConfigEntry<bool> KeyOtherPlayerHideDress;
public readonly ConfigEntry<HideDressModel.DressPart> KeyPlayerHideDressPart;
public readonly ConfigEntry<HideDressModel.DressPart> KeyOtherPlayerHideDressPart;
public readonly ConfigEntry<KeyboardShortcut> KeyPlayerHideDressShortcut;
public readonly ConfigEntry<KeyboardShortcut> KeyOtherPlayerHideDressShortcut;
[SuppressMessage("ReSharper", "RedundantTypeArgumentsOfMethod")]
private SettingsModel(ConfigFile configFile)
{
const string hideDressSettings = "Hide Dress Settings";
const string hideDressPartSettings = "Hide Dress Part Settings";
const string shortcutSettings = "Keyboard Shortcut Settings";
KeyPlayerHideDress = configFile.Bind<bool>(hideDressSettings, "Hide Player Dress", false);
KeyOtherPlayerHideDress = configFile.Bind<bool>(hideDressSettings, "Hide Other Player Dress", false);
KeyPlayerHideDressPart =
configFile.Bind<HideDressModel.DressPart>(hideDressPartSettings, "Player", HideDressModel.DressPart.Both);
KeyOtherPlayerHideDressPart =
configFile.Bind<HideDressModel.DressPart>(hideDressPartSettings, "Other Player", HideDressModel.DressPart.Both);
KeyPlayerHideDressShortcut =
configFile.Bind<KeyboardShortcut>(shortcutSettings, "Hide Player Dress",
KeyboardShortcut.Empty);
KeyOtherPlayerHideDressShortcut =
configFile.Bind<KeyboardShortcut>(shortcutSettings, "Hide Other Player Dress", KeyboardShortcut.Empty);
}
// ReSharper disable once UnusedMethodReturnValue.Global
public static SettingsModel Create(ConfigFile configFile)
{
if (Instance != null)
return Instance;
return Instance = new SettingsModel(configFile);
}
}
}

View File

@ -0,0 +1,16 @@
using System.Threading.Tasks;
using EFT.UI;
using HideDress.Models;
namespace HideDress
{
public partial class HideDressPlugin
{
private static async void PlayerModelViewShow(Task __result, PlayerModelView __instance)
{
await __result;
HideDressModel.Instance.PlayerModelViewBody = __instance.PlayerBody;
}
}
}

View File

@ -1,15 +1,14 @@
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下 // 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改 // 控制。更改这些特性值可修改
// 与程序集关联的信息。 // 与程序集关联的信息。
[assembly: AssemblyTitle("kmyuhkyuk-SkinHide")] [assembly: AssemblyTitle("kmyuhkyuk-HideDress")]
[assembly: AssemblyDescription("")] [assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("https://hub.sp-tarkov.com/files/file/583-skin-hide")] [assembly: AssemblyCompany("https://hub.sp-tarkov.com/files/file/583-skin-hide")]
[assembly: AssemblyProduct("SkinHide")] [assembly: AssemblyProduct("HideDress")]
[assembly: AssemblyCopyright("Copyright © 2022")] [assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
@ -33,4 +32,4 @@ using System.Runtime.InteropServices;
//通过使用 "*",如下所示: //通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.2.7.0")] [assembly: AssemblyVersion("1.2.7.0")]
[assembly: AssemblyFileVersion("1.2.7.0")] [assembly: AssemblyFileVersion("1.2.7.0")]

View File

@ -1,24 +0,0 @@
using Aki.Reflection.Patching;
using Aki.Reflection.Utils;
using System.Reflection;
using System.Threading.Tasks;
using EFT.UI;
namespace SkinHide.Patches
{
public class PlayerModelViewPatch : ModulePatch
{
protected override MethodBase GetTargetMethod()
{
return typeof(PlayerModelView).GetMethod("method_0", PatchConstants.PrivateFlags);
}
[PatchPostfix]
private static async void PatchPostfix(Task __result, PlayerModelView __instance)
{
await __result;
SkinHidePlugin.PlayerModelView = __instance.PlayerBody;
}
}
}

View File

@ -1,75 +0,0 @@
using Aki.Reflection.Patching;
using Aki.Reflection.Utils;
using System;
using System.Reflection;
using System.Threading.Tasks;
using EFT;
namespace SkinHide.Patches
{
public class PlayerInitPatch : ModulePatch
{
private static readonly bool Is231Up = SkinHidePlugin.GameVersion > new Version("0.12.12.17349");
protected override MethodBase GetTargetMethod()
{
return typeof(Player).GetMethod("Init", PatchConstants.PrivateFlags);
}
[PatchPostfix]
private async static void PatchPostfix(Task __result, Player __instance)
{
await __result;
bool isYouPlayer;
if (Is231Up)
{
isYouPlayer = __instance.IsYourPlayer;
}
else
{
isYouPlayer = __instance.Id == 1;
}
if (isYouPlayer)
{
SkinHidePlugin.Player = __instance.PlayerBody;
}
else
{
SkinHidePlugin.BotList.Add(__instance.PlayerBody);
}
}
}
public class PlayerEndPatch : ModulePatch
{
private static readonly bool Is231Up = SkinHidePlugin.GameVersion > new Version("0.12.12.17349");
protected override MethodBase GetTargetMethod()
{
return typeof(Player).GetMethod("OnGameSessionEnd", BindingFlags.Public | BindingFlags.Instance);
}
[PatchPostfix]
private static void PatchPostfix(Player __instance)
{
bool isYouPlayer;
if (Is231Up)
{
isYouPlayer = __instance.IsYourPlayer;
}
else
{
isYouPlayer = __instance.Id == 1;
}
if (isYouPlayer)
{
SkinHidePlugin.BotList.Clear();
}
}
}
}

View File

@ -1,206 +0,0 @@
using BepInEx;
using BepInEx.Configuration;
using System;
using System.Linq;
using System.Diagnostics;
using System.Collections.Generic;
using UnityEngine;
using EFT;
using EFT.Visual;
using SkinHide.Patches;
using SkinHide.Utils;
using EFT.InventoryLogic;
namespace SkinHide
{
[BepInPlugin("com.kmyuhkyuk.SkinHide", "kmyuhkyuk-SkinHide", "1.2.7")]
public class SkinHidePlugin : BaseUnityPlugin
{
internal static PlayerBody Player;
internal static PlayerBody PlayerModelView;
internal static List<PlayerBody> BotList = new List<PlayerBody>();
private readonly SettingsData SettingsDatas = new SettingsData();
private readonly ReflectionData ReflectionDatas = new ReflectionData();
private bool PMVHideCache;
private bool PlayerHideCache;
private bool BotHideCache;
internal static Version GameVersion { get; private set; }
public enum Part
{
All,
Dress,
SkinDress
}
private void Start()
{
Logger.LogInfo("Loaded: kmyuhkyuk-SkinHide");
FileVersionInfo exeInfo = Process.GetCurrentProcess().MainModule.FileVersionInfo;
GameVersion = new Version(exeInfo.FileMajorPart, exeInfo.ProductMinorPart, exeInfo.ProductBuildPart, exeInfo.FilePrivatePart);
const string skinHideSettings = "Skin Hide Settings";
const string skinHidePartSettings = "隐藏部分设置 Skin Hide Part Settings";
const string kbsSettings = "快捷键设置 Keyboard Shortcut Settings";
SettingsDatas.KeyPlayerSkinHide = Config.Bind<bool>(skinHideSettings, "玩家服装隐藏 Player Skin Hide", false);
SettingsDatas.KeyBotSkinHide = Config.Bind<bool>(skinHideSettings, "Bot服装隐藏 Bot Skin Hide", false);
SettingsDatas.KeyPlayerSkinHidePart = Config.Bind<Part>(skinHidePartSettings, "Player", Part.All);
SettingsDatas.KeyBotSkinHidePart = Config.Bind<Part>(skinHidePartSettings, "Bot", Part.All);
SettingsDatas.KBSPlayerSkinHide = Config.Bind<KeyboardShortcut>(kbsSettings, "玩家服装隐藏快捷键 Player Skin Hide", KeyboardShortcut.Empty);
SettingsDatas.KBSBotSkinHide = Config.Bind<KeyboardShortcut>(kbsSettings, "Bot服装隐藏快捷键 Bot Skin Hide", KeyboardShortcut.Empty);
new PlayerModelViewPatch().Enable();
new PlayerInitPatch().Enable();
new PlayerEndPatch().Enable();
ReflectionDatas.RefSlotViews = RefHelp.FieldRef<PlayerBody, object>.Create("SlotViews");
ReflectionDatas.RefSlotList = RefHelp.FieldRef<object, IEnumerable<object>>.Create(ReflectionDatas.RefSlotViews.FieldType, "list_0");
ReflectionDatas.RefDresses = RefHelp.FieldRef<object, Dress[]>.Create(ReflectionDatas.RefSlotList.FieldType.GetGenericArguments()[0], "Dresses");
ReflectionDatas.RefRenderers = RefHelp.FieldRef<Dress, Renderer[]>.Create("Renderers");
}
void Update()
{
if (SettingsDatas.KBSPlayerSkinHide.Value.IsDown())
{
SettingsDatas.KeyPlayerSkinHide.Value = !SettingsDatas.KeyPlayerSkinHide.Value;
}
if (SettingsDatas.KBSBotSkinHide.Value.IsDown())
{
SettingsDatas.KeyBotSkinHide.Value = !SettingsDatas.KeyBotSkinHide.Value;
}
//PlayerModelView Skin Hide
if (PlayerModelView != null)
{
if (SettingsDatas.KeyPlayerSkinHide.Value)
{
Hide(PlayerModelView, SettingsDatas.KeyPlayerSkinHidePart.Value, true);
PMVHideCache = true;
}
else if (!SettingsDatas.KeyPlayerSkinHide.Value && PMVHideCache)
{
Hide(PlayerModelView, Part.All, false);
PMVHideCache = false;
}
}
//Player Skin Hide
if (Player != null)
{
if (SettingsDatas.KeyPlayerSkinHide.Value)
{
Hide(Player, SettingsDatas.KeyPlayerSkinHidePart.Value, true);
PlayerHideCache = true;
}
else if (!SettingsDatas.KeyPlayerSkinHide.Value && PlayerHideCache)
{
Hide(Player, Part.All, false);
PlayerHideCache = false;
}
}
//Bot Skin Hide
if (BotList.Count > 0)
{
if (SettingsDatas.KeyBotSkinHide.Value)
{
foreach (PlayerBody bot in BotList)
{
Hide(bot, SettingsDatas.KeyBotSkinHidePart.Value, true);
}
BotHideCache = true;
}
else if (!SettingsDatas.KeyBotSkinHide.Value && BotHideCache)
{
foreach (PlayerBody bot in BotList)
{
Hide(bot, Part.All, false);
}
BotHideCache = false;
}
}
}
void Hide(PlayerBody playerbody, Part part, bool hide)
{
object slotViews = ReflectionDatas.RefSlotViews.GetValue(playerbody);
IEnumerable<object> slotList = ReflectionDatas.RefSlotList.GetValue(slotViews);
IEnumerable<Dress> dresses = slotList.SelectMany(x => ReflectionDatas.RefDresses.GetValue(x)).Where(x => x != null);
IEnumerable<Dress> dress = dresses.Where(x => x.GetType() == typeof(Dress));
IEnumerable<Renderer> renDress = dress.SelectMany(x => ReflectionDatas.RefRenderers.GetValue(x));
IEnumerable<GameObject> skinDress = dresses.Where(x => x.GetType() == typeof(SkinDress) || x.GetType() == typeof(ArmBandView)).Select(x => x.gameObject);
switch (part)
{
case Part.All:
foreach (GameObject gameobject in skinDress)
{
gameobject.SetActive(!hide);
}
foreach (MeshRenderer renderer in renDress)
{
renderer.enabled = !hide;
}
break;
case Part.Dress:
foreach (MeshRenderer renderer in renDress)
{
renderer.enabled = !hide;
}
break;
case Part.SkinDress:
foreach (GameObject gameobject in skinDress)
{
gameobject.SetActive(!hide);
}
break;
}
}
public class SettingsData
{
public ConfigEntry<bool> KeyPlayerSkinHide;
public ConfigEntry<bool> KeyBotSkinHide;
public ConfigEntry<Part> KeyPlayerSkinHidePart;
public ConfigEntry<Part> KeyBotSkinHidePart;
public ConfigEntry<KeyboardShortcut> KBSPlayerSkinHide;
public ConfigEntry<KeyboardShortcut> KBSBotSkinHide;
}
public class ReflectionData
{
public RefHelp.FieldRef<PlayerBody, object> RefSlotViews;
public RefHelp.FieldRef<object, IEnumerable<object>> RefSlotList;
public RefHelp.FieldRef<object, Dress[]> RefDresses;
public RefHelp.FieldRef<Dress, Renderer[]> RefRenderers;
}
}
}

View File

@ -1,431 +0,0 @@
using Aki.Reflection.Utils;
using HarmonyLib;
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
namespace SkinHide.Utils
{
public class RefHelp
{
public static DelegateType ObjectMethodDelegate<DelegateType>(MethodInfo method, bool virtualCall = true) where DelegateType : Delegate
{
if (method == null)
{
throw new ArgumentNullException(nameof(method));
}
var delegateType = typeof(DelegateType);
var declaringType = method.DeclaringType;
var delegateMethod = delegateType.GetMethod("Invoke");
var delegateParameters = delegateMethod.GetParameters();
var delegateParameterTypes = delegateParameters.Select(x => x.ParameterType).ToArray();
Type returnType;
bool needBox;
if (delegateMethod.ReturnType == typeof(object) && method.ReturnType.IsValueType)
{
returnType = typeof(object);
needBox = true;
}
else
{
returnType = method.ReturnType;
needBox = false;
}
var dmd = new DynamicMethod("OpenInstanceDelegate_" + method.Name, returnType, delegateParameterTypes);
var ilGen = dmd.GetILGenerator();
Type[] parameterTypes;
int num;
if (!method.IsStatic)
{
var parameters = method.GetParameters();
var numParameters = parameters.Length;
parameterTypes = new Type[numParameters + 1];
parameterTypes[0] = typeof(object);
for (int i = 0; i < numParameters; i++)
{
parameterTypes[i + 1] = parameters[i].ParameterType;
}
if (declaringType != null && declaringType.IsValueType)
{
ilGen.Emit(OpCodes.Ldarga_S, 0);
}
else
{
ilGen.Emit(OpCodes.Ldarg_0);
}
ilGen.Emit(OpCodes.Castclass, declaringType);
num = 1;
}
else
{
parameterTypes = method.GetParameters().Select(x => x.ParameterType).ToArray();
num = 0;
}
for (int i = num; i < parameterTypes.Length; i++)
{
ilGen.Emit(OpCodes.Ldarg, i);
Type parameterType = parameterTypes[i];
bool isValueType = parameterType.IsValueType;
if (!isValueType)
{
ilGen.Emit(OpCodes.Castclass, parameterType);
}
//DelegateparameterTypes i == parameterTypes i
else if (delegateParameterTypes[i] == typeof(object) && isValueType)
{
ilGen.Emit(OpCodes.Unbox_Any, parameterType);
}
}
if (method.IsStatic || !virtualCall)
{
ilGen.Emit(OpCodes.Call, method);
}
else
{
ilGen.Emit(OpCodes.Callvirt, method);
}
if (needBox)
{
ilGen.Emit(OpCodes.Box, method.ReturnType);
}
ilGen.Emit(OpCodes.Ret);
return (DelegateType)dmd.CreateDelegate(delegateType);
}
public class PropertyRef<T, F> where T : class
{
private Func<T, F> RefGetValue;
private Action<T, F> RefSetValue;
private PropertyInfo PropertyInfo;
private MethodInfo GetMethodInfo;
private MethodInfo SetMethodInfo;
private Type TType;
private T Instance;
public Type InType
{
get
{
return TType;
}
}
public Type PropertyType
{
get
{
return PropertyInfo.PropertyType;
}
}
public PropertyRef(PropertyInfo propertyinfo, object instance)
{
if (propertyinfo == null)
{
throw new Exception("PropertyInfo is null");
}
Init(propertyinfo, instance);
}
public PropertyRef(Type type, string propertyname, bool declaredonly, object instance)
{
BindingFlags flags = declaredonly ? AccessTools.allDeclared : AccessTools.all;
PropertyInfo propertyInfo = type.GetProperty(propertyname, flags);
if (propertyInfo == null)
{
throw new Exception(propertyname + " is null");
}
Init(propertyInfo, instance);
}
public PropertyRef(Type type, string[] propertynames, bool declaredonly, object instance)
{
BindingFlags flags = declaredonly ? AccessTools.allDeclared : AccessTools.all;
PropertyInfo propertyInfo = propertyInfo = propertynames.Select(x => type.GetProperty(x, flags)).FirstOrDefault(x => x != null);
if (propertyInfo == null)
{
throw new Exception(propertynames.First() + " is null");
}
Init(propertyInfo, instance);
}
private void Init(PropertyInfo propertyinfo, object instance)
{
PropertyInfo = propertyinfo;
TType = PropertyInfo.DeclaringType;
Instance = (T)instance;
if (PropertyInfo.CanRead)
{
GetMethodInfo = PropertyInfo.GetGetMethod(true);
RefGetValue = ObjectMethodDelegate<Func<T, F>>(GetMethodInfo);
}
if (PropertyInfo.CanWrite)
{
SetMethodInfo = PropertyInfo.GetSetMethod(true);
RefSetValue = ObjectMethodDelegate<Action<T, F>>(SetMethodInfo);
}
}
public static PropertyRef<T, F> Create(PropertyInfo propertyinfo, object instance)
{
return new PropertyRef<T, F>(propertyinfo, instance);
}
public static PropertyRef<T, F> Create(string propertyname, bool declaredonly = false, object instance = null)
{
return new PropertyRef<T, F>(typeof(T), propertyname, declaredonly, instance);
}
public static PropertyRef<T, F> Create(string[] propertynames, bool declaredonly = false, object instance = null)
{
return new PropertyRef<T, F>(typeof(T), propertynames, declaredonly, instance);
}
public static PropertyRef<T, F> Create(Type type, string propertyname, bool declaredonly = false, object instance = null)
{
return new PropertyRef<T, F>(type, propertyname, declaredonly, instance);
}
public static PropertyRef<T, F> Create(Type type, string[] propertynames, bool declaredonly = false, object instance = null)
{
return new PropertyRef<T, F>(type, propertynames, declaredonly, instance);
}
public F GetValue(T instance)
{
if (RefGetValue == null)
{
throw new ArgumentNullException(nameof(RefGetValue));
}
if (instance != null && TType.IsAssignableFrom(instance.GetType()))
{
return RefGetValue(instance);
}
else if (Instance != null && instance == null)
{
return RefGetValue(Instance);
}
else
{
return default;
}
}
public void SetValue(T instance, F value)
{
if (RefSetValue == null)
{
throw new ArgumentNullException(nameof(RefSetValue));
}
if (instance != null && TType.IsAssignableFrom(instance.GetType()))
{
RefSetValue(instance, value);
}
else if (Instance != null && instance == null)
{
RefSetValue(Instance, value);
}
}
}
public class FieldRef<T, F> where T : class
{
private AccessTools.FieldRef<T, F> HarmonyFieldRef;
private FieldInfo FieldInfo;
private Type TType;
private T Instance;
public Type InType
{
get
{
return TType;
}
}
public Type FieldType
{
get
{
return FieldInfo.FieldType;
}
}
public FieldRef(FieldInfo fieldinfo, object instance)
{
if (fieldinfo == null)
{
throw new Exception("FieldInfo is null");
}
Init(fieldinfo, instance);
}
public FieldRef(Type type, string fieldname, bool declaredonly, object instance)
{
BindingFlags flags = declaredonly ? AccessTools.allDeclared : AccessTools.all;
FieldInfo fieldInfo = type.GetField(fieldname, flags);
if (fieldInfo == null)
{
throw new Exception(fieldname + " is null");
}
Init(fieldInfo, instance);
}
public FieldRef(Type type, string[] fieldnames, bool declaredonly, object instance)
{
BindingFlags flags = declaredonly ? AccessTools.allDeclared : AccessTools.all;
FieldInfo fieldInfo = fieldnames.Select(x => type.GetField(x, flags)).FirstOrDefault(x => x != null);
if (fieldInfo == null)
{
throw new Exception(fieldnames.First() + " is null");
}
Init(fieldInfo, instance);
}
public static FieldRef<T, F> Create(FieldInfo fieldinfo, object instance = null)
{
return new FieldRef<T, F>(fieldinfo, instance);
}
public static FieldRef<T, F> Create(string fieldname, bool declaredonly = false, object instance = null)
{
return new FieldRef<T, F>(typeof(T), fieldname, declaredonly, instance);
}
public static FieldRef<T, F> Create(string[] fieldnames, bool declaredonly = false, object instance = null)
{
return new FieldRef<T, F>(typeof(T), fieldnames, declaredonly, instance);
}
public static FieldRef<T, F> Create(Type type, string fieldname, bool declaredonly = false, object instance = null)
{
return new FieldRef<T, F>(type, fieldname, declaredonly, instance);
}
public static FieldRef<T, F> Create(Type type, string[] fieldnames, bool declaredonly = false, object instance = null)
{
return new FieldRef<T, F>(type, fieldnames, declaredonly, instance);
}
private void Init(FieldInfo fieldinfo, object instance = null)
{
FieldInfo = fieldinfo;
TType = FieldInfo.DeclaringType;
Instance = (T)instance;
HarmonyFieldRef = AccessTools.FieldRefAccess<T, F>(FieldInfo);
}
public F GetValue(T instance)
{
if (HarmonyFieldRef == null)
{
throw new ArgumentNullException(nameof(HarmonyFieldRef));
}
if (instance != null && TType.IsAssignableFrom(instance.GetType()))
{
return HarmonyFieldRef(instance);
}
else if (Instance != null && instance == null)
{
return HarmonyFieldRef(Instance);
}
else
{
return default;
}
}
public void SetValue(T instance, F value)
{
if (HarmonyFieldRef == null)
{
throw new ArgumentNullException(nameof(HarmonyFieldRef));
}
if (instance != null && TType.IsAssignableFrom(instance.GetType()))
{
HarmonyFieldRef(instance) = value;
}
else if (Instance != null && instance == null)
{
HarmonyFieldRef(Instance) = value;
}
}
}
public static Type GetEftType(Func<Type, bool> func)
{
return PatchConstants.EftTypes.Single(func);
}
public static MethodInfo GetEftMethod(Type type, BindingFlags flags, Func<MethodInfo, bool> func)
{
return type.GetMethods(flags).Single(func);
}
public static MethodInfo GetEftMethod(Func<Type, bool> func, BindingFlags flags, Func<MethodInfo, bool> func2)
{
return GetEftMethod(GetEftType(func), flags, func2);
}
}
}