Skip to content

Commit

Permalink
Simplify runtime enum injection
Browse files Browse the repository at this point in the history
  • Loading branch information
MartijnMuijsers committed Feb 18, 2024
1 parent 34ddfa0 commit b6d7227
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 122 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,21 @@ This patch has an analogous patch in `fiddle-api` with the same name.
License: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
Fiddle - https://fiddlemc.org

diff --git a/src/main/java/org/fiddlemc/fiddle/bytebuddy/package-info.java b/src/main/java/org/fiddlemc/fiddle/bytebuddy/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..d59a43ab5087f87d434c2a8d63ea48ea31344ea2
--- /dev/null
+++ b/src/main/java/org/fiddlemc/fiddle/bytebuddy/package-info.java
@@ -0,0 +1,9 @@
+@ParametersAreNonnullByDefault
+@MethodsReturnNonnullByDefault
+@FieldsAreNonnullByDefault
+package org.fiddlemc.fiddle.bytebuddy;
+
+import net.minecraft.FieldsAreNonnullByDefault;
+import net.minecraft.MethodsReturnNonnullByDefault;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/src/main/java/org/fiddlemc/fiddle/configuration/package-info.java b/src/main/java/org/fiddlemc/fiddle/configuration/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..4b5406690afdcaaf33bba4f8055a6b99693e01ff
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ License: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
Fiddle - https://fiddlemc.org

diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
index 34e60855b01cc7722132a8b5bef6795bb2c34c99..5396d2571dbc900e0c96fa36e513537bdb0f2bbd 100644
index 6fd08200c4292c2cd90ed1f21a2cb2a2653ca259..38045bc523547abc903487c56c760333153eeed0 100644
--- a/src/main/java/net/minecraft/server/Main.java
+++ b/src/main/java/net/minecraft/server/Main.java
@@ -152,6 +152,34 @@ public class Main {
Expand Down Expand Up @@ -46,3 +46,108 @@ index 34e60855b01cc7722132a8b5bef6795bb2c34c99..5396d2571dbc900e0c96fa36e513537b
dedicatedserversettings.forceSave();
// Paper start - load config files early for access below if needed
org.bukkit.configuration.file.YamlConfiguration bukkitConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionset.valueOf("bukkit-settings"));
diff --git a/src/main/java/org/fiddlemc/fiddle/bytebuddy/ByteBuddyWithoutValueOf.java b/src/main/java/org/fiddlemc/fiddle/bytebuddy/ByteBuddyWithoutValueOf.java
new file mode 100644
index 0000000000000000000000000000000000000000..6b59bd353030a0b72ee50b0cbb22f943ad3ed0ee
--- /dev/null
+++ b/src/main/java/org/fiddlemc/fiddle/bytebuddy/ByteBuddyWithoutValueOf.java
@@ -0,0 +1,99 @@
+// Fiddle - modifiable Bukkit enums - inject runtime versions - common utilities
+
+package org.fiddlemc.fiddle.bytebuddy;
+
+import net.bytebuddy.ByteBuddy;
+import net.bytebuddy.build.HashCodeAndEqualsPlugin;
+import net.bytebuddy.description.modifier.*;
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.dynamic.DynamicType;
+import net.bytebuddy.dynamic.TargetType;
+import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
+import net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder;
+import net.bytebuddy.implementation.MethodDelegation;
+import net.bytebuddy.implementation.SuperMethodCall;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * An extension to {@link ByteBuddy} that permits an alternative to the {@link ByteBuddy#makeEnumeration} method:
+ * {@link #makeEnumerationWithoutValueOf}.
+ */
+@HashCodeAndEqualsPlugin.Enhance
+public class ByteBuddyWithoutValueOf extends ByteBuddy {
+
+ public ByteBuddyWithoutValueOf() {
+ super();
+ }
+
+ /**
+ * A modified version of {@link ByteBuddy#makeEnumeration},
+ * that does not add an implementation of an enum's static {@code valueOf(String)} method.
+ */
+ public DynamicType.Builder<? extends Enum<?>> makeEnumerationWithoutValueOf(Collection<? extends String> values) {
+ // Copied from ByteBuddy#makeEnumeration, except for marked lines
+ if (values.isEmpty()) {
+ throw new IllegalArgumentException("Require at least one enumeration constant");
+ }
+ TypeDescription.Generic enumType = TypeDescription.Generic.Builder.parameterizedType(Enum.class, TargetType.class).build();
+ return new SubclassDynamicTypeBuilder<Enum<?>>(instrumentedTypeFactory.subclass(namingStrategy.subclass(enumType),
+ ModifierContributor.Resolver.of(Visibility.PUBLIC, TypeManifestation.FINAL, EnumerationState.ENUMERATION).resolve(),
+ enumType),
+ classFileVersion,
+ auxiliaryTypeNamingStrategy,
+ annotationValueFilterFactory,
+ annotationRetention,
+ implementationContextFactory,
+ methodGraphCompiler,
+ typeValidation,
+ visibilityBridgeStrategy,
+ classWriterStrategy,
+ ignoredMethods,
+ ConstructorStrategy.Default.NO_CONSTRUCTORS)
+ .defineConstructor(Visibility.PRIVATE).withParameters(String.class, int.class)
+ .intercept(SuperMethodCall.INSTANCE)
+ .defineMethod(EnumerationImplementationWithoutValueOf.ENUM_VALUES_METHOD_NAME, // Modified from ByteBuddy#makeEnumeration
+ TargetType[].class,
+ Visibility.PUBLIC, Ownership.STATIC)
+ .intercept(new EnumerationImplementationWithoutValueOf(new ArrayList<>(values))); // Modified from ByteBuddy#makeEnumeration
+ }
+
+ /**
+ * A convenience function that calls {@link #makeEnumerationWithoutValueOf(Collection)}
+ * and also immediately applies the given target as implementation for {@code valueOf}.
+ */
+ public DynamicType.Builder<? extends Enum<?>> makeEnumerationWithoutValueOf(Collection<? extends String> values, Class<?> delegationTarget) {
+ return this.makeEnumerationWithoutValueOf(values)
+ .defineMethod(EnumerationImplementationWithoutValueOf.ENUM_VALUE_OF_METHOD_NAME, TargetType.class, Visibility.PUBLIC, Ownership.STATIC)
+ .withParameters(String.class)
+ .intercept(MethodDelegation.to(delegationTarget));
+ }
+
+ /**
+ * An extension to {@link ByteBuddy.EnumerationImplementation},
+ * for use in {@link #makeEnumerationWithoutValueOf}.
+ */
+ @HashCodeAndEqualsPlugin.Enhance
+ private static class EnumerationImplementationWithoutValueOf extends EnumerationImplementation {
+
+ /**
+ * This simply exposes {@link ByteBuddy.EnumerationImplementation#ENUM_VALUE_OF_METHOD_NAME}
+ * as public.
+ */
+ public static final String ENUM_VALUE_OF_METHOD_NAME = ByteBuddy.EnumerationImplementation.ENUM_VALUE_OF_METHOD_NAME;
+
+ /**
+ * This simply exposes {@link ByteBuddy.EnumerationImplementation#ENUM_VALUES_METHOD_NAME}
+ * for use inside the {@link ByteBuddyWithoutValueOf} class.
+ */
+ private static final String ENUM_VALUES_METHOD_NAME = ByteBuddy.EnumerationImplementation.ENUM_VALUES_METHOD_NAME;
+
+ private EnumerationImplementationWithoutValueOf(List<String> values) {
+ super(values);
+ }
+
+ }
+
+}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ License: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
Fiddle - https://fiddlemc.org

diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
index 38045bc523547abc903487c56c760333153eeed0..7b932fcee235acf2e7ee56003b90c84e7136c146 100644
index 38045bc523547abc903487c56c760333153eeed0..b041da597f1cb13775d889a1ba94264908925224 100644
--- a/src/main/java/net/minecraft/server/Main.java
+++ b/src/main/java/net/minecraft/server/Main.java
@@ -180,6 +180,79 @@ public class Main {
@@ -180,6 +180,65 @@ public class Main {
var injectRuntimeClassVersionHelper = new InjectRuntimeClassVersionHelper();
// Fiddle end - modifiable Bukkit enums - inject runtime versions - common utilities

Expand All @@ -36,23 +36,11 @@ index 38045bc523547abc903487c56c760333153eeed0..7b932fcee235acf2e7ee56003b90c84e
+ fiddleEnumNames.stream().map(it.unimi.dsi.fastutil.Pair::left),
+ vanillaEnumNames.stream().filter(org.fiddlemc.fiddle.material.MaterialLegacyNameChecker::isMaterialNameLegacy)
+ ).toList();
+ var materialClassBuilder = new net.bytebuddy.ByteBuddy()
+ .subclass(net.bytebuddy.description.type.TypeDescription.Generic.Builder
+ .parameterizedType(Enum.class, net.bytebuddy.dynamic.TargetType.class).build(),
+ net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING)
+ //.modifiers(net.bytebuddy.description.modifier.Visibility.PUBLIC, net.bytebuddy.description.modifier.TypeManifestation.FINAL, net.bytebuddy.description.modifier.EnumerationState.ENUMERATION)
+ //.makeEnumeration(enumNames)
+ var materialClassBuilder = new org.fiddlemc.fiddle.bytebuddy.ByteBuddyWithoutValueOf()
+ // Back valueOf(String) by matchMaterial(String)
+ .makeEnumerationWithoutValueOf(enumNames, org.fiddlemc.fiddle.bukkit.material.MatchMaterialTarget.class)
+ .name("org.bukkit.Material");
+ for (var enumName : enumNames) {
+ materialClassBuilder = materialClassBuilder.defineField(enumName, net.bytebuddy.dynamic.TargetType.class, java.lang.reflect.Modifier.PUBLIC | java.lang.reflect.Modifier.STATIC);
+ }
+ materialClassBuilder
+ // Add the static $VALUES field (which is the way that Java stores an array of enum values)
+ .defineField("$VALUES", net.bytebuddy.description.type.TypeDescription.Generic.Builder.of(net.bytebuddy.dynamic.TargetType.class).asArray().build(), java.lang.reflect.Modifier.PUBLIC | java.lang.reflect.Modifier.STATIC)
+ // Add a static initializer that initializes the static fields
+ .invokable(net.bytebuddy.description.method.MethodDescription::isTypeInitializer).intercept(net.bytebuddy.implementation.MethodDelegation.to(org.fiddlemc.fiddle.bukkit.material.MaterialStaticInitializerTarget.class))
+ // Implement the enum values() as backed by the $VALUES field
+ .defineMethod("values", net.bytebuddy.description.type.TypeDescription.Generic.Builder.of(net.bytebuddy.dynamic.TargetType.class).asArray().build(), net.bytebuddy.description.modifier.Visibility.PUBLIC, net.bytebuddy.description.modifier.Ownership.STATIC).intercept(net.bytebuddy.implementation.MethodDelegation.to(org.fiddlemc.fiddle.bukkit.material.ValuesTarget.class))
+ // Inherit the default implementations in AbstractMaterial
+ .implement(org.fiddlemc.fiddle.material.AbstractMaterial.class)
+ // Implement the getCraftingRemainingItem() method which returns the casted return value of getAbstractCraftingRemainingItem()
Expand All @@ -62,8 +50,6 @@ index 38045bc523547abc903487c56c760333153eeed0..7b932fcee235acf2e7ee56003b90c84e
+ .defineMethod("getMaterial", net.bytebuddy.dynamic.TargetType.class, net.bytebuddy.description.modifier.Visibility.PUBLIC, net.bytebuddy.description.modifier.Ownership.STATIC).withParameters(String.class, Boolean.TYPE).intercept(net.bytebuddy.implementation.MethodDelegation.to(org.fiddlemc.fiddle.bukkit.material.GetMaterialTarget.class))
+ .defineMethod("matchMaterial", net.bytebuddy.dynamic.TargetType.class, net.bytebuddy.description.modifier.Visibility.PUBLIC, net.bytebuddy.description.modifier.Ownership.STATIC).withParameters(String.class).intercept(net.bytebuddy.implementation.MethodDelegation.to(org.fiddlemc.fiddle.bukkit.material.MatchMaterialTarget.class))
+ .defineMethod("matchMaterial", net.bytebuddy.dynamic.TargetType.class, net.bytebuddy.description.modifier.Visibility.PUBLIC, net.bytebuddy.description.modifier.Ownership.STATIC).withParameters(String.class, Boolean.TYPE).intercept(net.bytebuddy.implementation.MethodDelegation.to(org.fiddlemc.fiddle.bukkit.material.MatchMaterialTarget.class))
+ // Also implement the enum valueOf(String) as backed by matchMaterial(String)
+ .defineMethod("valueOf", net.bytebuddy.dynamic.TargetType.class, net.bytebuddy.description.modifier.Visibility.PUBLIC, net.bytebuddy.description.modifier.Ownership.STATIC).withParameters(String.class).intercept(net.bytebuddy.implementation.MethodDelegation.to(org.fiddlemc.fiddle.bukkit.material.MatchMaterialTarget.class))
+ // Implement the data field, which will initially be null, and initialized to its actual non-null value as soon as possible (which is, due to its reliance on CraftMagicNumbers#computeData and thereby Bukkit#createBlockData, as soon as the return value of Bukkit#getServer is no longer null)
+ .defineField("data", net.bytebuddy.description.type.TypeDescription.Generic.Builder.parameterizedType(Class.class, new java.lang.reflect.WildcardType() {
+
Expand Down Expand Up @@ -178,83 +164,6 @@ index 0000000000000000000000000000000000000000..cabeebf1337a087c0d3c49150e391355
+ }
+
+}
diff --git a/src/main/java/org/fiddlemc/fiddle/bukkit/material/MaterialStaticInitializerTarget.java b/src/main/java/org/fiddlemc/fiddle/bukkit/material/MaterialStaticInitializerTarget.java
new file mode 100644
index 0000000000000000000000000000000000000000..562ad9d53cd21cf24668180cc64ff0ed606c2ffd
--- /dev/null
+++ b/src/main/java/org/fiddlemc/fiddle/bukkit/material/MaterialStaticInitializerTarget.java
@@ -0,0 +1,36 @@
+// Fiddle - modifiable Bukkit enums - inject runtime versions - Material
+
+package org.fiddlemc.fiddle.bukkit.material;
+
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+
+/**
+ * Provides the static initializer block for the {@link org.bukkit.Material} class,
+ * that initializes all static fields, including the enum values.
+ */
+public class MaterialStaticInitializerTarget {
+
+ public static void init() throws Exception {
+ var materialClass = org.bukkit.Material.class;
+ var constructor = materialClass.getDeclaredConstructor(String.class, Integer.TYPE);
+ constructor.trySetAccessible();
+ // Initialize the enum fields
+ var enumFields = Arrays.stream(materialClass.getDeclaredFields())
+ .filter(field -> Modifier.isStatic(field.getModifiers()) && field.getType() == materialClass)
+ .toList();
+ var valuesArray = new org.bukkit.Material[enumFields.size()];
+ for (int i = 0; i < enumFields.size(); i++) {
+ var field = enumFields.get(i);
+ field.trySetAccessible();
+ var instance = constructor.newInstance(field.getName(), i);
+ valuesArray[i] = instance;
+ field.set(null, instance);
+ }
+ // Initialize $VALUES
+ var valuesField = materialClass.getDeclaredField("$VALUES");
+ valuesField.trySetAccessible();
+ valuesField.set(null, valuesArray);
+ }
+
+}
diff --git a/src/main/java/org/fiddlemc/fiddle/bukkit/material/ValuesTarget.java b/src/main/java/org/fiddlemc/fiddle/bukkit/material/ValuesTarget.java
new file mode 100644
index 0000000000000000000000000000000000000000..0af39aa02a913ec3c81d63d7ffc0f6404d5724be
--- /dev/null
+++ b/src/main/java/org/fiddlemc/fiddle/bukkit/material/ValuesTarget.java
@@ -0,0 +1,29 @@
+// Fiddle - modifiable Bukkit enums - inject runtime versions - Material
+
+package org.fiddlemc.fiddle.bukkit.material;
+
+import net.bytebuddy.implementation.bind.annotation.RuntimeType;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * A delegation target for the {@link org.bukkit.Material#values()} method.
+ */
+public class ValuesTarget {
+
+ private static Object backingArray;
+
+ @RuntimeType
+ public static @NotNull Object values() {
+ if (backingArray == null) {
+ try {
+ var backingArrayField = org.bukkit.Material.class.getDeclaredField("$VALUES");
+ backingArrayField.trySetAccessible();
+ backingArray = backingArrayField.get(null);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return ((org.bukkit.Material[]) backingArray).clone();
+ }
+
+}
diff --git a/src/main/java/org/fiddlemc/fiddle/bukkit/material/package-info.java b/src/main/java/org/fiddlemc/fiddle/bukkit/material/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..5b6c9f858d0530fe175a006717e5545dc7b36c13
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ License: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
Fiddle - https://fiddlemc.org

diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
index 7b932fcee235acf2e7ee56003b90c84e7136c146..28c28156f130360953418baa5d2327aa34f62bb6 100644
index b041da597f1cb13775d889a1ba94264908925224..4364c96c511ba2ea9bc66e6e3360730bc423bb0b 100644
--- a/src/main/java/net/minecraft/server/Main.java
+++ b/src/main/java/net/minecraft/server/Main.java
@@ -251,6 +251,11 @@ public class Main {
@@ -237,6 +237,11 @@ public class Main {
}).build())
.make()
.load(ClassLoader.getSystemClassLoader(), net.bytebuddy.dynamic.loading.ClassLoadingStrategy.Default.INJECTION);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ License: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
Fiddle - https://fiddlemc.org

diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
index 28c28156f130360953418baa5d2327aa34f62bb6..67bbd4d0d895c400110bc743c40afab8f3b2f243 100644
index 4364c96c511ba2ea9bc66e6e3360730bc423bb0b..b605fdd91a3f6ee204ab7e710effff2e6a798c63 100644
--- a/src/main/java/net/minecraft/server/Main.java
+++ b/src/main/java/net/minecraft/server/Main.java
@@ -435,6 +435,8 @@ public class Main {
@@ -421,6 +421,8 @@ public class Main {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ License: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
Fiddle - https://fiddlemc.org

diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
index 67bbd4d0d895c400110bc743c40afab8f3b2f243..6f1e10bb4bf6ea99a7287a99a350830caa181a10 100644
index b605fdd91a3f6ee204ab7e710effff2e6a798c63..57a1cae73e8fa9e01c4852037596e5bae9ea206d 100644
--- a/src/main/java/net/minecraft/server/Main.java
+++ b/src/main/java/net/minecraft/server/Main.java
@@ -145,6 +145,8 @@ public class Main {
Expand All @@ -19,7 +19,7 @@ index 67bbd4d0d895c400110bc743c40afab8f3b2f243..6f1e10bb4bf6ea99a7287a99a350830c
io.papermc.paper.plugin.PluginInitializerManager.load(optionset); // Paper
Bootstrap.bootStrap();
Bootstrap.validate();
@@ -436,6 +438,15 @@ public class Main {
@@ -422,6 +424,15 @@ public class Main {
}

org.fiddlemc.fiddle.pack.read.StartupPackLoadPhase.endStartupLoadPhase(); // Fiddle - read packs - startup load phase - end after initial read
Expand Down

0 comments on commit b6d7227

Please sign in to comment.