diff --git a/ChestPreview/ChestPreview/PreviewTargetProvider.cs b/ChestPreview/ChestPreview/PreviewTargetProvider.cs index b800330..acd9dd0 100644 --- a/ChestPreview/ChestPreview/PreviewTargetProvider.cs +++ b/ChestPreview/ChestPreview/PreviewTargetProvider.cs @@ -242,7 +242,7 @@ internal partial class PreviewTargetProvider(ICoreClientAPI api, Config config) if (player == null || playerEntity == null) return false; - return inventory.CanPlayerAccess(player, playerEntity.Pos); + return inventory.CanPlayerAccess(player, playerEntity.GetPos()); } private bool IsContainerAllowed(Block block) diff --git a/ChestPreview/ChestPreview/Rendering/CardRenderer.cs b/ChestPreview/ChestPreview/Rendering/CardRenderer.cs index 0ec04e8..3f557a7 100644 --- a/ChestPreview/ChestPreview/Rendering/CardRenderer.cs +++ b/ChestPreview/ChestPreview/Rendering/CardRenderer.cs @@ -1,6 +1,7 @@ using Cairo; using ChestPreview.Configs; using ChestPreview.Models; +using ChestPreview.Utils; using System; using System.Collections.Generic; using System.Globalization; @@ -50,7 +51,7 @@ internal class CardRenderer(ICoreClientAPI api, Config config) : IDisposable IPlayer? player = api.World.Player; EntityPlayer? playerEntity = player?.Entity; - if (player == null || playerEntity == null || !inventory.CanPlayerAccess(player, playerEntity.Pos)) + if (player == null || playerEntity == null || !inventory.CanPlayerAccess(player, playerEntity.GetPos())) return false; string targetKey = CreateTargetKey(target.BlockEntity.Pos); diff --git a/ChestPreview/ChestPreview/Utils/CompatibilityUtil.cs b/ChestPreview/ChestPreview/Utils/CompatibilityUtil.cs new file mode 100644 index 0000000..f08fbbe --- /dev/null +++ b/ChestPreview/ChestPreview/Utils/CompatibilityUtil.cs @@ -0,0 +1,55 @@ +using System; +using Vintagestory.API.Common.Entities; + +namespace ChestPreview.Utils; + +/// +/// When the mod is built for 1.21, and then you run it with 1.22, this happens when referring to Entity.Pos, +/// which was changed from a field to a property (and that being the reason this happens): +/// +/// System.MissingFieldException: Field not found: 'Vintagestory.API.Common.Entities.Entity.Pos'. +/// at MonoMod.Core.Interop.CoreCLR.V60.InvokeCompileMethod(IntPtr functionPtr, IntPtr thisPtr, IntPtr corJitInfo, CORINFO_METHOD_INFO* methodInfo, UInt32 flags, Byte** nativeEntry, UInt32* nativeSizeOfCode) +/// at MonoMod.Core.Platforms.Runtimes.Core60Runtime.JitHookDelegateHolder.CompileMethodHook(IntPtr jit, IntPtr corJitInfo, CORINFO_METHOD_INFO* methodInfo, UInt32 flags, Byte** nativeEntry, UInt32* nativeSizeOfCode) +/// at ChestPreview.PreviewTargetProvider.CanAccessContainer(BlockEntity blockEntity) in E:\Code\VintageStory\ChestPreview\ChestPreview\ChestPreview\PreviewTargetProvider.cs:line 237 +/// +/// the PreviewTargetProvider.cs: around line 237 looks like this: +/// +/// private bool CanAccessContainer(BlockEntity blockEntity) +/// { +/// if (blockEntity is not IBlockEntityContainer container || container.Inventory is not InventoryBase inventory) +/// return false; +/// +/// IPlayer? player = api.World.Player; +/// EntityPlayer? playerEntity = player?.Entity; +/// if (player == null || playerEntity == null) +/// return false; +/// +/// return inventory.CanPlayerAccess(player, playerEntity.Pos); +/// } +/// +/// it happens because of the last line where we refer to "playerEntity.Pos" - this field doesn't exist now, because it's a property. +/// +/// This class uses reflection to refer to either the property, or the field, whichever actually exists. +/// +internal static class CompatibilityUtil +{ +#if !VERSION22 + private static Func? _getPos; + + private static Func GetPosFunc => _getPos ??= BuildGetPos(); + + private static Func BuildGetPos() + { + var prop = typeof(Entity).GetProperty("Pos"); + if (prop != null) + return (Func)Delegate.CreateDelegate(typeof(Func), prop.GetGetMethod()!); + + var field = typeof(Entity).GetField("Pos")!; + return entity => (EntityPos)field.GetValue(entity)!; + } + + public static EntityPos GetPos(this Entity entity) => GetPosFunc(entity); +#else + public static EntityPos GetPos(this Entity entity) => entity.Pos; +#endif +} \ No newline at end of file