From 84ba47f174fadc28680120dfc483b98ce40a7226 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 3 Mar 2023 21:43:32 -0500 Subject: [PATCH 1/3] Fix compatibility with Performant --- .../embeddedt/modernfix/core/config/ModernFixEarlyConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index c458a5c0..43baf26b 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -65,6 +65,7 @@ public class ModernFixEarlyConfig { disableIfModPresent("mixin.perf.thread_priorities", "smoothboot"); disableIfModPresent("mixin.perf.async_jei", "modernui"); disableIfModPresent("mixin.perf.compress_biome_container", "chocolate"); + disableIfModPresent("mixin.bugfix.mc218112", "performant"); } private void disableIfModPresent(String configName, String... ids) { From a54e7b831a57d49831ad783f920490867a430450 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 4 Mar 2023 09:10:12 -0500 Subject: [PATCH 2/3] Improve compatibility of ID desync fix, and add Roadrunner support --- .../embeddedt/modernfix/ModernFixClient.java | 35 +++++++++++++++++-- .../mc218112/SynchedEntityDataMixin.java | 34 ------------------ .../resources/META-INF/accesstransformer.cfg | 3 +- src/main/resources/modernfix.mixins.json | 1 - 4 files changed, 34 insertions(+), 39 deletions(-) delete mode 100644 src/main/java/org/embeddedt/modernfix/mixin/bugfix/mc218112/SynchedEntityDataMixin.java diff --git a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java index 7b97709a..f0bd2dfc 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java @@ -1,6 +1,7 @@ package org.embeddedt.modernfix; import com.mojang.datafixers.util.Pair; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.ConnectScreen; import net.minecraft.client.gui.screens.TitleScreen; @@ -105,7 +106,19 @@ public class ModernFixClient { * * This is to ensure we can perform ID fixup on already constructed managers. */ - public static Set allEntityDatas = Collections.newSetFromMap(new WeakHashMap<>()); + public static final Set allEntityDatas = Collections.newSetFromMap(new WeakHashMap<>()); + + private static final Field entriesArrayField; + static { + Field field; + try { + field = SynchedEntityData.class.getDeclaredField("entriesArray"); + field.setAccessible(true); + } catch(ReflectiveOperationException e) { + field = null; + } + entriesArrayField = field; + } /** * Extremely hacky method to detect and correct mismatched entity data parameter IDs on the client and server. @@ -140,12 +153,28 @@ public class ModernFixClient { if(fixNeeded) { dataEntries = new ArrayList<>(allEntityDatas); for(SynchedEntityData manager : dataEntries) { - Map> fixedMap = new HashMap<>(); + Int2ObjectOpenHashMap> fixedMap = new Int2ObjectOpenHashMap<>(); List> items = new ArrayList<>(manager.itemsById.values()); for(SynchedEntityData.DataItem item : items) { fixedMap.put(item.getAccessor().id, item); } - manager.itemsById = fixedMap; + manager.lock.writeLock().lock(); + try { + manager.itemsById.replaceAll((id, parameter) -> fixedMap.get((int)id)); + if(entriesArrayField != null) { + try { + SynchedEntityData.DataItem[] dataArray = new SynchedEntityData.DataItem[items.size()]; + for(int i = 0; i < dataArray.length; i++) { + dataArray[i] = fixedMap.get(i); + } + entriesArrayField.set(manager, dataArray); + } catch(ReflectiveOperationException e) { + ModernFix.LOGGER.error(e); + } + } + } finally { + manager.lock.writeLock().unlock(); + } } } allEntityDatas.clear(); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/bugfix/mc218112/SynchedEntityDataMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/mc218112/SynchedEntityDataMixin.java deleted file mode 100644 index 64b4f16b..00000000 --- a/src/main/java/org/embeddedt/modernfix/mixin/bugfix/mc218112/SynchedEntityDataMixin.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.embeddedt.modernfix.mixin.bugfix.mc218112; - -import net.minecraft.network.syncher.EntityDataAccessor; -import net.minecraft.network.syncher.SynchedEntityData; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; - -import java.util.Map; -import java.util.concurrent.locks.ReadWriteLock; - -@Mixin(SynchedEntityData.class) -public class SynchedEntityDataMixin { - @Shadow @Final private Map> itemsById; - - @Shadow @Final private ReadWriteLock lock; - - @Shadow private boolean isEmpty; - - @Inject(method = "createDataItem", at = @At(value = "INVOKE", target = "Ljava/util/Map;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) - private void putWithLock(EntityDataAccessor key, T value, CallbackInfo ci, SynchedEntityData.DataItem item) { - ci.cancel(); - try { - this.itemsById.put(key.getId(), item); - this.isEmpty = false; - } finally { - this.lock.writeLock().unlock(); - } - } -} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index a8145c22..7e921c8a 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -10,4 +10,5 @@ public net.minecraft.util.concurrent.ThreadTaskExecutor func_213160_bf()V # runA public net.minecraft.server.MinecraftServer field_211151_aa # nextTickTime public net.minecraft.client.Minecraft field_213277_ad # progressListener public-f net.minecraft.network.datasync.DataParameter field_187157_a # id -public-f net.minecraft.network.datasync.EntityDataManager field_187234_c # itemsById \ No newline at end of file +public-f net.minecraft.network.datasync.EntityDataManager field_187234_c # itemsById +public-f net.minecraft.network.datasync.EntityDataManager field_187235_d # lock \ No newline at end of file diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index b79452ef..d42fa2d3 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -53,7 +53,6 @@ "perf.fast_registry_validation.ForgeRegistryMixin", "perf.cache_strongholds.ChunkGeneratorMixin", "perf.cache_upgraded_structures.StructureManagerMixin", - "bugfix.mc218112.SynchedEntityDataMixin", "perf.cache_strongholds.ServerLevelMixin" ], "client": [ From 1c9935e2986906940956e057cdcc0bb56f0a1c36 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 4 Mar 2023 10:36:11 -0500 Subject: [PATCH 3/3] Use MethodHandles to select LWJGL 3.3 methods if needed --- .../modernfix/textures/StbStitcher.java | 113 +++++++++++++++++- 1 file changed, 111 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/textures/StbStitcher.java b/src/main/java/org/embeddedt/modernfix/textures/StbStitcher.java index cc386233..d2fbb230 100644 --- a/src/main/java/org/embeddedt/modernfix/textures/StbStitcher.java +++ b/src/main/java/org/embeddedt/modernfix/textures/StbStitcher.java @@ -11,12 +11,119 @@ import org.lwjgl.stb.STBRPNode; import org.lwjgl.stb.STBRPRect; import org.lwjgl.stb.STBRectPack; +import static java.lang.invoke.MethodHandles.*; +import static java.lang.invoke.MethodType.*; + +import java.lang.invoke.MethodHandle; +import java.sql.Ref; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; /* Source: https://github.com/GTNewHorizons/lwjgl3ify/blob/f21364cd3d178aef863458a2faa1f5718a4e350d/src/main/java/me/eigenraven/lwjgl3ify/textures/StbStitcher.java */ public class StbStitcher { + /* Most of this logic is to allow use of LWJGL versions where coordinates are short and versions where they are int */ + private static final MethodHandle MH_rect_shortSet, MH_rect_intSet, MH_rect_intX, MH_rect_intY, MH_rect_shortX, + MH_rect_shortY; + + static { + MethodHandle shortM = null, intM = null; + List exceptions = new ArrayList<>(); + try { + intM = publicLookup().findVirtual(STBRPRect.class, "set", methodType(STBRPRect.class, + int.class, /* id */ + int.class, + int.class, + int.class, + int.class, + boolean.class)); + } catch(ReflectiveOperationException e) { + exceptions.add(e); + } + try { + shortM = publicLookup().findVirtual(STBRPRect.class, "set", methodType(STBRPRect.class, + int.class, /* id */ + short.class, + short.class, + short.class, + short.class, + boolean.class)); + } catch(ReflectiveOperationException e) { + exceptions.add(e); + } + if(shortM == null && intM == null) { + IllegalStateException e = new IllegalStateException("An STBRPRect set method could not be located"); + exceptions.forEach(e::addSuppressed); + throw e; + } + MH_rect_shortSet = shortM; + MH_rect_intSet = intM; + /* Now look for X methods */ + exceptions.clear(); + try { + intM = publicLookup().findVirtual(STBRPRect.class, "x", methodType(int.class)); + } catch(ReflectiveOperationException e) { + exceptions.add(e); + } + try { + shortM = publicLookup().findVirtual(STBRPRect.class, "x", methodType(short.class)); + } catch(ReflectiveOperationException e) { + exceptions.add(e); + } + if(shortM == null && intM == null) { + IllegalStateException e = new IllegalStateException("An STBRPRect x() method could not be located"); + exceptions.forEach(e::addSuppressed); + throw e; + } + MH_rect_shortX = shortM; + MH_rect_intX = intM; + /* Assume that Y is the same */ + try { + if(MH_rect_shortX != null) { + MH_rect_shortY = publicLookup().findVirtual(STBRPRect.class, "y", methodType(short.class)); + MH_rect_intY = null; + } else { /* it must be int */ + MH_rect_intY = publicLookup().findVirtual(STBRPRect.class, "y", methodType(int.class)); + MH_rect_shortY = null; + } + } catch(ReflectiveOperationException e) { + throw new IllegalStateException("An STBRPRect y() method could not be located", e); + } + } + + private static STBRPRect setWrapper(STBRPRect rect, int id, int width, int height, int x, int y, boolean was_packed) { + try { + if(MH_rect_shortSet != null) + return (STBRPRect)MH_rect_shortSet.invokeExact(rect, id, (short)width, (short)height, (short)0, (short)0, false); + else + return (STBRPRect)MH_rect_intSet.invokeExact(rect, id, width, height, 0, 0, false); + } catch(Throwable e) { + throw new AssertionError(e); + } + } + + private static int getX(STBRPRect rect) { + try { + if(MH_rect_shortX != null) + return (short)MH_rect_shortX.invokeExact(rect); + else + return (int)MH_rect_intX.invokeExact(rect); + } catch(Throwable e) { + throw new AssertionError(e); + } + } + + private static int getY(STBRPRect rect) { + try { + if(MH_rect_shortX != null) + return (short)MH_rect_shortY.invokeExact(rect); + else + return (int)MH_rect_intY.invokeExact(rect); + } catch(Throwable e) { + throw new AssertionError(e); + } + } + public static Pair, List> packRects(Stitcher.Holder[] holders) { int holderSize = holders.length; @@ -36,7 +143,9 @@ public class StbStitcher { int height = holder.height; // The ID here is just the array index, for easy lookup later - rectBuf.get(j).set(j, (short)width, (short)height, (short)0, (short)0, false); + STBRPRect rect = rectBuf.get(j); + + setWrapper(rect, j, width, height, 0, 0, false); sqSize += (width * height); } @@ -63,7 +172,7 @@ public class StbStitcher { } // Initialize the sprite now with the position and size that we've calculated so far - infoList.add(new LoadableSpriteInfo(holder.spriteInfo, width, height, rect.x(), rect.y())); + infoList.add(new LoadableSpriteInfo(holder.spriteInfo, width, height, getX(rect), getY(rect))); //holder.spriteInfo.initSprite(size, size, rect.x(), rect.y(), false); }