From cd3f144b11760b18d16e2fe33b8543327aed3a93 Mon Sep 17 00:00:00 2001 From: MightyKnight <38622942+MightyKnight@users.noreply.github.com> Date: Sat, 13 Jul 2024 12:56:26 +0200 Subject: [PATCH] Fix #3: Crash on 1.20.6 due to Identifier.of For the update to 1.21 I needed to change new Identifier() to Identifier.of(), but this (obviously) caused a crash with lower versions. For some strange reason the tests in my dev environment didn't produce the crash however... --- gradle.properties | 2 +- shield-disruptor-mc120/build.gradle | 2 +- .../common/mixin/MixinHeldItemRenderer.java | 7 +- .../multiversion_mixin/ReflectionUtils.java | 102 ++++++++++++++ .../version/PehkuiVersionUtils.java | 124 ++++++++++++++++++ 5 files changed, 232 insertions(+), 5 deletions(-) create mode 100644 src/main/java/me/mightyknight/sd/multiversion_mixin/ReflectionUtils.java create mode 100644 src/main/java/me/mightyknight/sd/multiversion_mixin/version/PehkuiVersionUtils.java diff --git a/gradle.properties b/gradle.properties index 8dec7d3..9d5e922 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,7 +7,7 @@ common_yarn_mappings = 1.21+build.2 loader_version = 0.15.11 # Mod properties -mod_version = 1.8.0 +mod_version = 1.8.1 maven_group = me.mightyknight archives_base_name = shield-disruptor diff --git a/shield-disruptor-mc120/build.gradle b/shield-disruptor-mc120/build.gradle index f702e6b..4c8132a 100644 --- a/shield-disruptor-mc120/build.gradle +++ b/shield-disruptor-mc120/build.gradle @@ -10,7 +10,7 @@ dependencies { } // ModMenu seems to need it - modImplementation "net.fabricmc.fabric-api:fabric-api:0.97.8+1.20.6" + modImplementation "net.fabricmc.fabric-api:fabric-api:0.100.4+1.20.6" } // Minecraft 1.20.5 upwards uses Java 21 diff --git a/src/main/java/me/mightyknight/sd/common/mixin/MixinHeldItemRenderer.java b/src/main/java/me/mightyknight/sd/common/mixin/MixinHeldItemRenderer.java index dcb2606..b4c7ead 100644 --- a/src/main/java/me/mightyknight/sd/common/mixin/MixinHeldItemRenderer.java +++ b/src/main/java/me/mightyknight/sd/common/mixin/MixinHeldItemRenderer.java @@ -3,6 +3,7 @@ import com.github.crimsondawn45.fabricshieldlib.lib.object.FabricShield; import me.mightyknight.sd.common.SDConfig; import me.mightyknight.sd.common.ShieldDisruptor; +import me.mightyknight.sd.multiversion_mixin.ReflectionUtils; import me.mightyknight.sd.multiversion_mixin.VersionedMixin; import me.mightyknight.sd.versioned.Versioned; import net.fabricmc.loader.api.FabricLoader; @@ -63,14 +64,14 @@ private void hideShield(LivingEntity entity, ItemStack stack, ModelTransformatio } // Block items in the tag "c:tools/shields" (>1.20.5) - if(Versioned.REGISTRY.stackHasTag(stack, Identifier.of("c", "tools/shields"))) { + if(Versioned.REGISTRY.stackHasTag(stack, ReflectionUtils.constructIdentifier("c", "tools/shields"))) { callback.cancel(); return; } // Block items in the item tag "c:shields" // [LEGACY] This tag was changed to "c:tools/shields" in 1.20.5 - if(Versioned.REGISTRY.stackHasTag(stack, Identifier.of("c", "shields"))) { + if(Versioned.REGISTRY.stackHasTag(stack, ReflectionUtils.constructIdentifier("c", "shields"))) { callback.cancel(); return; } @@ -93,7 +94,7 @@ private void hideShield(LivingEntity entity, ItemStack stack, ModelTransformatio } // Check if item has the tag - Identifier tagId = Identifier.of( + Identifier tagId = ReflectionUtils.constructIdentifier( tagKey.split(":")[0].replaceFirst("#", ""), tagKey.split(":")[1]); diff --git a/src/main/java/me/mightyknight/sd/multiversion_mixin/ReflectionUtils.java b/src/main/java/me/mightyknight/sd/multiversion_mixin/ReflectionUtils.java new file mode 100644 index 0000000..ff24e1a --- /dev/null +++ b/src/main/java/me/mightyknight/sd/multiversion_mixin/ReflectionUtils.java @@ -0,0 +1,102 @@ +/* +MIT License + +Copyright (c) 2019 - 2024 Virtuoel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package me.mightyknight.sd.multiversion_mixin; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; +import me.mightyknight.sd.common.ShieldDisruptor; +import me.mightyknight.sd.multiversion_mixin.version.PehkuiVersionUtils; +import net.minecraft.util.Identifier; +import net.minecraft.util.InvalidIdentifierException; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; + +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.Version; + +// The reflection code adapted and modified from Pehkui, a big thank you to Virtuoel +public class ReflectionUtils { + + + public static final MethodHandle CONSTRUCT_ID_FROM_STRING, CONSTRUCT_ID_FROM_STRINGS; + final Version version = FabricLoader.getInstance().getModContainer("minecraft").get().getMetadata().getVersion(); + + static { + + final Int2ObjectMap h = new Int2ObjectArrayMap<>(); + + final MethodHandles.Lookup lookup = MethodHandles.lookup(); + String mapped = "unset"; + + try { + + final boolean is1206Minus = PehkuiVersionUtils.MINOR < 20 || (PehkuiVersionUtils.MINOR == 20 && PehkuiVersionUtils.PATCH <= 6);; + + // 1.20.6 was using "new Identifier(String)" + if (is1206Minus) { + h.put(9, lookup.unreflectConstructor(Identifier.class.getDeclaredConstructor(String.class))); + h.put(10, lookup.unreflectConstructor(Identifier.class.getDeclaredConstructor(String.class, String.class))); + } + + } catch (NoSuchMethodException | SecurityException | IllegalAccessException e) { + ShieldDisruptor.LOGGER.error("Current name lookup: {}", mapped); + ShieldDisruptor.LOGGER.catching(e); + } + + CONSTRUCT_ID_FROM_STRING = h.get(9); + CONSTRUCT_ID_FROM_STRINGS = h.get(10); + + } + + public static Identifier constructIdentifier(final String id) { + if (CONSTRUCT_ID_FROM_STRING != null) { + try { + return (Identifier) CONSTRUCT_ID_FROM_STRING.invoke(id); + } catch (final InvalidIdentifierException e) { + throw e; + } catch (final Throwable e) { + throw new RuntimeException(e); + } + } + + return Identifier.of(id); + } + + public static Identifier constructIdentifier(final String namespace, final String path) { + if (CONSTRUCT_ID_FROM_STRINGS != null) { + try { + return (Identifier) CONSTRUCT_ID_FROM_STRINGS.invoke(namespace, path); + } catch (final InvalidIdentifierException e) { + throw e; + } catch (final Throwable e) { + throw new RuntimeException(e); + } + } + + return Identifier.of(namespace, path); + } + + +} diff --git a/src/main/java/me/mightyknight/sd/multiversion_mixin/version/PehkuiVersionUtils.java b/src/main/java/me/mightyknight/sd/multiversion_mixin/version/PehkuiVersionUtils.java new file mode 100644 index 0000000..664691b --- /dev/null +++ b/src/main/java/me/mightyknight/sd/multiversion_mixin/version/PehkuiVersionUtils.java @@ -0,0 +1,124 @@ +/* +MIT License + +Copyright (c) 2019 - 2024 Virtuoel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package me.mightyknight.sd.multiversion_mixin.version; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; + +import org.jetbrains.annotations.Nullable; + +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.SemanticVersion; +import net.fabricmc.loader.api.Version; + +public class PehkuiVersionUtils +{ + private static final List> VERSION_PREDICATES = new ArrayList<>(); + + static + { + final int[][] ranges = + { + {1, 14, 4}, + {1, 15, 2}, + {1, 16, 5}, + {1, 17, 1}, + {1, 18, 2}, + {1, 19, 4}, + {1, 20, 6}, + {1, 21, 0}, + }; + + final String prefix = ".compat%s%s"; + + for (final int[] range : ranges) + { + final int major = range[0]; + final int minor = range[1]; + + final String predicatePrefix = String.format(prefix, major, minor); + final String predicateMinor = predicatePrefix + "."; + final String predicateMinorPlus = predicatePrefix + "plus."; + final String predicateMinorMinus = predicatePrefix + "minus."; + final String predicateMinorZero = predicatePrefix + "0."; + final String predicateMinorZeroMinus = predicatePrefix + "0minus."; + + VERSION_PREDICATES.add(n -> n.contains(predicateMinor) && PehkuiVersionUtils.MINOR != minor); + VERSION_PREDICATES.add(n -> n.contains(predicateMinorPlus) && PehkuiVersionUtils.MINOR < minor); + VERSION_PREDICATES.add(n -> n.contains(predicateMinorMinus) && PehkuiVersionUtils.MINOR > minor); + VERSION_PREDICATES.add(n -> n.contains(predicateMinorZero) && (PehkuiVersionUtils.MINOR != minor || PehkuiVersionUtils.PATCH != 0)); + VERSION_PREDICATES.add(n -> n.contains(predicateMinorZeroMinus) && (PehkuiVersionUtils.MINOR > minor || (PehkuiVersionUtils.MINOR == minor && PehkuiVersionUtils.PATCH > 0))); + + final int maxPatch = range[2]; + + for (int i = 1; i <= maxPatch; i++) + { + final int patch = i; + + final String predicatePatch = predicatePrefix + patch + "."; + final String predicatePatchPlus = predicatePrefix + patch + "plus."; + final String predicatePatchMinus = predicatePrefix + patch + "minus."; + + VERSION_PREDICATES.add(n -> n.contains(predicatePatch) && (PehkuiVersionUtils.MINOR != minor || PehkuiVersionUtils.PATCH != patch)); + VERSION_PREDICATES.add(n -> n.contains(predicatePatchPlus) && (PehkuiVersionUtils.MINOR < minor || (PehkuiVersionUtils.MINOR == minor && PehkuiVersionUtils.PATCH < patch))); + VERSION_PREDICATES.add(n -> n.contains(predicatePatchMinus) && (PehkuiVersionUtils.MINOR > minor || (PehkuiVersionUtils.MINOR == minor && PehkuiVersionUtils.PATCH > patch))); + } + } + } + + public static boolean shouldApplyCompatibilityMixin(String mixinClassName) + { + if (mixinClassName.contains(".compat")) + { + for (final Predicate predicate : VERSION_PREDICATES) + { + if (predicate.test(mixinClassName)) + { + return false; + } + } + } + + return true; + } + + @Nullable + public static final SemanticVersion MINECRAFT_VERSION = lookupMinecraftVersion(); + public static final int MAJOR = getVersionComponent(0); + public static final int MINOR = getVersionComponent(1); + public static final int PATCH = getVersionComponent(2); + + private static SemanticVersion lookupMinecraftVersion() + { + final Version version = FabricLoader.getInstance().getModContainer("minecraft").get().getMetadata().getVersion(); + + return (SemanticVersion) (version instanceof SemanticVersion ? version : null); + } + + private static int getVersionComponent(int pos) + { + return MINECRAFT_VERSION != null ? MINECRAFT_VERSION.getVersionComponent(pos) : -1; + } +}