Skip to content

Commit

Permalink
Fix #3: Crash on 1.20.6 due to Identifier.of
Browse files Browse the repository at this point in the history
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...
  • Loading branch information
MightyKnight committed Jul 13, 2024
1 parent b56b0d9 commit cd3f144
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 5 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion shield-disruptor-mc120/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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]);

Expand Down
Original file line number Diff line number Diff line change
@@ -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<MethodHandle> 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);
}


}
Original file line number Diff line number Diff line change
@@ -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<Predicate<String>> 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<String> 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;
}
}

0 comments on commit cd3f144

Please sign in to comment.