diff --git a/.gitignore b/.gitignore index 71fa37fc83..a2adff58b6 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,7 @@ out/ # other stuff run/ +logs/ Paper-Server Paper-API diff --git a/paper-api-generator/build.gradle.kts b/paper-api-generator/build.gradle.kts index 0147a21349..c3deae7adb 100644 --- a/paper-api-generator/build.gradle.kts +++ b/paper-api-generator/build.gradle.kts @@ -16,6 +16,8 @@ dependencies { implementation(project(":paper-api")) implementation("io.github.classgraph:classgraph:4.8.47") implementation("org.jetbrains:annotations:24.0.1") + testImplementation("org.junit.jupiter:junit-jupiter:5.10.2") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") } tasks.register("generate") { @@ -24,5 +26,9 @@ tasks.register("generate") { args(projectDir.toPath().resolve("generated").toString()) } +tasks.test { + useJUnitPlatform() +} + group = "io.papermc.paper" version = "1.0-SNAPSHOT" diff --git a/paper-api-generator/generated/com/destroystokyo/paper/entity/ai/VanillaGoal.java b/paper-api-generator/generated/com/destroystokyo/paper/entity/ai/VanillaGoal.java index c7f171b77d..7ff40b6c33 100644 --- a/paper-api-generator/generated/com/destroystokyo/paper/entity/ai/VanillaGoal.java +++ b/paper-api-generator/generated/com/destroystokyo/paper/entity/ai/VanillaGoal.java @@ -1122,7 +1122,8 @@ public interface VanillaGoal extends Goal { ) GoalKey UNIVERSAL_ANGER_RESET = create("universal_anger_reset", Mob.class); - private static @NotNull GoalKey create(final @NotNull String key, final @NotNull Class clazz) { - return GoalKey.of(clazz, NamespacedKey.minecraft(key)); + private static @NotNull GoalKey create(final @NotNull String key, + final @NotNull Class type) { + return GoalKey.of(type, NamespacedKey.minecraft(key)); } } diff --git a/paper-api-generator/generated/io/papermc/paper/registry/keys/GameEventKeys.java b/paper-api-generator/generated/io/papermc/paper/registry/keys/GameEventKeys.java index 97ee8b7e15..26ce70c2ab 100644 --- a/paper-api-generator/generated/io/papermc/paper/registry/keys/GameEventKeys.java +++ b/paper-api-generator/generated/io/papermc/paper/registry/keys/GameEventKeys.java @@ -124,6 +124,13 @@ public final class GameEventKeys { */ public static final TypedKey ELYTRA_GLIDE = create(key("elytra_glide")); + /** + * {@code minecraft:entity_action} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey ENTITY_ACTION = create(key("entity_action")); + /** * {@code minecraft:entity_damage} * @@ -166,13 +173,6 @@ public final class GameEventKeys { */ public static final TypedKey ENTITY_PLACE = create(key("entity_place")); - /** - * {@code minecraft:entity_action} - * - * @apiNote This field is version-dependant and may be removed in future Minecraft versions - */ - public static final TypedKey ENTITY_ACTION = create(key("entity_action")); - /** * {@code minecraft:equip} * @@ -285,62 +285,6 @@ public final class GameEventKeys { */ public static final TypedKey PROJECTILE_SHOOT = create(key("projectile_shoot")); - /** - * {@code minecraft:sculk_sensor_tendrils_clicking} - * - * @apiNote This field is version-dependant and may be removed in future Minecraft versions - */ - public static final TypedKey SCULK_SENSOR_TENDRILS_CLICKING = create(key("sculk_sensor_tendrils_clicking")); - - /** - * {@code minecraft:shear} - * - * @apiNote This field is version-dependant and may be removed in future Minecraft versions - */ - public static final TypedKey SHEAR = create(key("shear")); - - /** - * {@code minecraft:shriek} - * - * @apiNote This field is version-dependant and may be removed in future Minecraft versions - */ - public static final TypedKey SHRIEK = create(key("shriek")); - - /** - * {@code minecraft:splash} - * - * @apiNote This field is version-dependant and may be removed in future Minecraft versions - */ - public static final TypedKey SPLASH = create(key("splash")); - - /** - * {@code minecraft:step} - * - * @apiNote This field is version-dependant and may be removed in future Minecraft versions - */ - public static final TypedKey STEP = create(key("step")); - - /** - * {@code minecraft:swim} - * - * @apiNote This field is version-dependant and may be removed in future Minecraft versions - */ - public static final TypedKey SWIM = create(key("swim")); - - /** - * {@code minecraft:teleport} - * - * @apiNote This field is version-dependant and may be removed in future Minecraft versions - */ - public static final TypedKey TELEPORT = create(key("teleport")); - - /** - * {@code minecraft:unequip} - * - * @apiNote This field is version-dependant and may be removed in future Minecraft versions - */ - public static final TypedKey UNEQUIP = create(key("unequip")); - /** * {@code minecraft:resonate_1} * @@ -446,6 +390,62 @@ public final class GameEventKeys { */ public static final TypedKey RESONATE_15 = create(key("resonate_15")); + /** + * {@code minecraft:sculk_sensor_tendrils_clicking} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SCULK_SENSOR_TENDRILS_CLICKING = create(key("sculk_sensor_tendrils_clicking")); + + /** + * {@code minecraft:shear} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SHEAR = create(key("shear")); + + /** + * {@code minecraft:shriek} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SHRIEK = create(key("shriek")); + + /** + * {@code minecraft:splash} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SPLASH = create(key("splash")); + + /** + * {@code minecraft:step} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey STEP = create(key("step")); + + /** + * {@code minecraft:swim} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SWIM = create(key("swim")); + + /** + * {@code minecraft:teleport} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey TELEPORT = create(key("teleport")); + + /** + * {@code minecraft:unequip} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey UNEQUIP = create(key("unequip")); + private GameEventKeys() { } diff --git a/paper-api-generator/src/main/java/io/papermc/generator/Main.java b/paper-api-generator/src/main/java/io/papermc/generator/Main.java index e02f55871f..fa2b05e94c 100644 --- a/paper-api-generator/src/main/java/io/papermc/generator/Main.java +++ b/paper-api-generator/src/main/java/io/papermc/generator/Main.java @@ -1,20 +1,14 @@ package io.papermc.generator; import com.mojang.logging.LogUtils; -import io.papermc.generator.types.GeneratedKeyType; import io.papermc.generator.types.SourceGenerator; -import io.papermc.paper.registry.RegistryKey; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.List; import net.minecraft.SharedConstants; import net.minecraft.core.LayeredRegistryAccess; -import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; -import net.minecraft.core.registries.Registries; import net.minecraft.resources.RegistryDataLoader; -import net.minecraft.resources.ResourceKey; import net.minecraft.server.Bootstrap; import net.minecraft.server.RegistryLayer; import net.minecraft.server.WorldLoader; @@ -24,12 +18,6 @@ import net.minecraft.server.packs.repository.PackRepository; import net.minecraft.server.packs.repository.ServerPacksSource; import net.minecraft.server.packs.resources.MultiPackResourceManager; import org.apache.commons.io.file.PathUtils; -import org.bukkit.GameEvent; -import org.bukkit.block.Biome; -import org.bukkit.generator.structure.Structure; -import org.bukkit.generator.structure.StructureType; -import org.bukkit.inventory.meta.trim.TrimMaterial; -import org.bukkit.inventory.meta.trim.TrimPattern; import org.slf4j.Logger; public final class Main { @@ -40,6 +28,8 @@ public final class Main { static { SharedConstants.tryDetectVersion(); Bootstrap.bootStrap(); + Bootstrap.validate(); + final PackRepository resourceRepository = ServerPacksSource.createVanillaTrustedRepository(); resourceRepository.reload(); final MultiPackResourceManager resourceManager = new MultiPackResourceManager(PackType.SERVER_DATA, resourceRepository.getAvailablePacks().stream().map(Pack::open).toList()); diff --git a/paper-api-generator/src/main/java/io/papermc/generator/types/GeneratedKeyType.java b/paper-api-generator/src/main/java/io/papermc/generator/types/GeneratedKeyType.java index b5ad821c1c..ba27aa640d 100644 --- a/paper-api-generator/src/main/java/io/papermc/generator/types/GeneratedKeyType.java +++ b/paper-api-generator/src/main/java/io/papermc/generator/types/GeneratedKeyType.java @@ -10,6 +10,7 @@ import com.squareup.javapoet.TypeSpec; import io.papermc.generator.Main; import io.papermc.generator.utils.Annotations; import io.papermc.generator.utils.CollectingContext; +import io.papermc.generator.utils.Formatting; import io.papermc.generator.utils.Javadocs; import io.papermc.paper.registry.RegistryKey; import io.papermc.paper.registry.TypedKey; @@ -19,14 +20,15 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.stream.Collectors; import net.kyori.adventure.key.Key; +import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.RegistrySetBuilder; import net.minecraft.data.registries.UpdateOneTwentyOneRegistries; import net.minecraft.resources.ResourceKey; +import org.bukkit.MinecraftExperimental; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.DefaultQualifier; @@ -115,30 +117,31 @@ public class GeneratedKeyType extends SimpleGenerator { final TypeName typedKey = ParameterizedTypeName.get(TypedKey.class, this.apiType); final TypeSpec.Builder typeBuilder = this.keyHolderType(); - typeBuilder.addAnnotation(EXPERIMENTAL_API_ANNOTATION); // TODO experimental API final MethodSpec.Builder createMethod = this.createMethod(typedKey); final Registry registry = Main.REGISTRY_ACCESS.registryOrThrow(this.registryKey); final List> experimental = this.collectExperimentalKeys(registry); boolean allExperimental = true; - for (final T value : registry) { - final ResourceKey key = registry.getResourceKey(value).orElseThrow(); + for (final Holder.Reference reference : registry.holders().sorted(Formatting.alphabeticKeyOrder(reference -> reference.key().location().getPath())).toList()) { + final ResourceKey key = reference.key(); final String keyPath = key.location().getPath(); - final String fieldName = keyPath.toUpperCase(Locale.ENGLISH).replaceAll("[.-/]", "_"); // replace invalid field name chars + final String fieldName = Formatting.formatKeyAsField(keyPath); final FieldSpec.Builder fieldBuilder = FieldSpec.builder(typedKey, fieldName, PUBLIC, STATIC, FINAL) .initializer("$N(key($S))", createMethod.build(), keyPath) .addJavadoc(Javadocs.getVersionDependentField("{@code $L}"), key.location().toString()); if (experimental.contains(key)) { - fieldBuilder.addAnnotations(experimentalAnnotations("MinecraftExperimental.Requires.UPDATE_1_21")); + fieldBuilder.addAnnotations(experimentalAnnotations(MinecraftExperimental.Requires.UPDATE_1_21)); } else { allExperimental = false; } typeBuilder.addField(fieldBuilder.build()); } if (allExperimental) { - typeBuilder.addAnnotations(experimentalAnnotations("MinecraftExperimental.Requires.UPDATE_1_21")); - createMethod.addAnnotations(experimentalAnnotations("MinecraftExperimental.Requires.UPDATE_1_21")); + typeBuilder.addAnnotations(experimentalAnnotations(MinecraftExperimental.Requires.UPDATE_1_21)); + createMethod.addAnnotations(experimentalAnnotations(MinecraftExperimental.Requires.UPDATE_1_21)); + } else { + typeBuilder.addAnnotation(EXPERIMENTAL_API_ANNOTATION); // TODO experimental API } return typeBuilder.addMethod(createMethod.build()).build(); } diff --git a/paper-api-generator/src/main/java/io/papermc/generator/types/SimpleGenerator.java b/paper-api-generator/src/main/java/io/papermc/generator/types/SimpleGenerator.java index 76edecd9ff..b4c1095c84 100644 --- a/paper-api-generator/src/main/java/io/papermc/generator/types/SimpleGenerator.java +++ b/paper-api-generator/src/main/java/io/papermc/generator/types/SimpleGenerator.java @@ -5,7 +5,6 @@ import com.squareup.javapoet.TypeSpec; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.nio.file.Files; import java.nio.file.Path; public abstract class SimpleGenerator implements SourceGenerator { @@ -24,14 +23,13 @@ public abstract class SimpleGenerator implements SourceGenerator { @Override public void writeToFile(Path parent) throws IOException { - Path packagePath = parent.resolve(this.packageName.replace('.', '/')); - Files.createDirectories(packagePath); - JavaFile.Builder builder = JavaFile.builder(this.packageName, this.getTypeSpec()) - .indent(" "); - this.file(builder); + JavaFile.Builder builder = JavaFile.builder(this.packageName, this.getTypeSpec()); + this.file(builder) + .indent(" ") + .skipJavaLangImports(true); - Files.writeString(packagePath.resolve(this.className + ".java"), this.file(builder).build().toString(), StandardCharsets.UTF_8); + builder.build().writeTo(parent, StandardCharsets.UTF_8); } } diff --git a/paper-api-generator/src/main/java/io/papermc/generator/types/goal/MobGoalGenerator.java b/paper-api-generator/src/main/java/io/papermc/generator/types/goal/MobGoalGenerator.java index 649490b5b0..7f94034424 100644 --- a/paper-api-generator/src/main/java/io/papermc/generator/types/goal/MobGoalGenerator.java +++ b/paper-api-generator/src/main/java/io/papermc/generator/types/goal/MobGoalGenerator.java @@ -2,7 +2,6 @@ package io.papermc.generator.types.goal; import com.destroystokyo.paper.entity.RangedEntity; import com.destroystokyo.paper.entity.ai.GoalKey; -import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.FieldSpec; import com.squareup.javapoet.JavaFile; @@ -19,12 +18,7 @@ import io.papermc.generator.utils.Annotations; import io.papermc.generator.utils.Formatting; import io.papermc.generator.utils.Javadocs; import java.util.Comparator; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.util.function.Supplier; -import java.util.stream.Collectors; import javax.lang.model.element.Modifier; import net.minecraft.world.entity.ai.goal.Goal; import net.minecraft.world.entity.ai.goal.WrappedGoal; @@ -65,9 +59,13 @@ import org.bukkit.entity.Vindicator; import org.bukkit.entity.WanderingTrader; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.framework.qual.DefaultQualifier; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; +import static javax.lang.model.element.Modifier.FINAL; +import static javax.lang.model.element.Modifier.PRIVATE; +import static javax.lang.model.element.Modifier.PUBLIC; +import static javax.lang.model.element.Modifier.STATIC; + @DefaultQualifier(NonNull.class) public class MobGoalGenerator extends SimpleGenerator { @@ -168,57 +166,53 @@ public class MobGoalGenerator extends SimpleGenerator { @Override protected TypeSpec getTypeSpec() { - TypeName clazzType = TypeName.get(Class.class) - .annotated(Annotations.NOT_NULL); - TypeName keyType = TypeName.get(String.class) - .annotated(Annotations.NOT_NULL); - - MethodSpec.Builder createMethod = MethodSpec.methodBuilder("create") - .addModifiers(Modifier.PRIVATE, Modifier.STATIC) - .addParameter(ParameterSpec.builder(keyType, "key", Modifier.FINAL) - .build() - ) - .addParameter(ParameterSpec.builder(clazzType, "clazz", Modifier.FINAL) - .build() - ) - .addCode("return $T.of(clazz, $T.minecraft(key));", GoalKey.class, NamespacedKey.class) - .returns(ParameterizedTypeName.get(GoalKey.class).annotated(Annotations.NOT_NULL)); - - TypeVariableName type = TypeVariableName.get("T", Mob.class); TypeSpec.Builder typeBuilder = TypeSpec.interfaceBuilder(this.className) .addSuperinterface(ParameterizedTypeName.get(ClassName.get(com.destroystokyo.paper.entity.ai.Goal.class), type)) - .addModifiers(Modifier.PUBLIC) + .addModifiers(PUBLIC) .addTypeVariable(type) .addAnnotations(Annotations.CLASS_HEADER) .addJavadoc(CLASS_HEADER); + TypeName mobType = ParameterizedTypeName.get(ClassName.get(Class.class), type) + .annotated(Annotations.NOT_NULL); + TypeName keyType = TypeName.get(String.class) + .annotated(Annotations.NOT_NULL); - List> classes; + ParameterSpec keyParam = ParameterSpec.builder(keyType, "key", FINAL).build(); + ParameterSpec typeParam = ParameterSpec.builder(mobType, "type", FINAL).build(); + MethodSpec.Builder createMethod = MethodSpec.methodBuilder("create") + .addModifiers(PRIVATE, STATIC) + .addParameter(keyParam) + .addParameter(typeParam) + .addCode("return $T.of($N, $T.minecraft($N));", GoalKey.class, typeParam, NamespacedKey.class, keyParam) + .addTypeVariable(type) + .returns(ParameterizedTypeName.get(ClassName.get(GoalKey.class), type).annotated(Annotations.NOT_NULL)); + + List> classes; try (ScanResult scanResult = new ClassGraph().enableAllInfo().whitelistPackages("net.minecraft").scan()) { - classes = scanResult.getSubclasses(net.minecraft.world.entity.ai.goal.Goal.class.getName()).loadClasses(); + classes = scanResult.getSubclasses(Goal.class.getName()).loadClasses(Goal.class); } - List vanillaNames = classes.stream() + List> vanillaNames = classes.stream() .filter(clazz -> !java.lang.reflect.Modifier.isAbstract(clazz.getModifiers())) .filter(clazz -> !WrappedGoal.class.equals(clazz)) // TODO - properly fix - .map(goalClass -> new VanillaGoalKey(goalClass, MobGoalNames.getKey(goalClass.getName(), (Class) goalClass))) - .filter((key) -> !MobGoalNames.isIgnored(key.key().getNamespacedKey().getKey())) - .sorted(Comparator.comparing(o -> o.key().getEntityClass().getSimpleName()) - .thenComparing(vanillaGoalKey -> vanillaGoalKey.key.getNamespacedKey().getKey()) + .map(goalClass -> MobGoalNames.getKey(goalClass.getName(), goalClass)) + .filter((key) -> !MobGoalNames.isIgnored(key.getNamespacedKey().getKey())) + .sorted(Comparator., String>comparing(o -> o.getEntityClass().getSimpleName()) + .thenComparing(vanillaGoalKey -> vanillaGoalKey.getNamespacedKey().getKey()) ) .toList(); - for (final VanillaGoalKey vanillaGoalKey : vanillaNames) { - GoalKey value = vanillaGoalKey.key(); - TypeName typedKey = ParameterizedTypeName.get(GoalKey.class, value.getEntityClass()); - NamespacedKey key = value.getNamespacedKey(); + for (final GoalKey goalKey : vanillaNames) { + TypeName typedKey = ParameterizedTypeName.get(GoalKey.class, goalKey.getEntityClass()); + NamespacedKey key = goalKey.getNamespacedKey(); String keyPath = key.getKey(); - String fieldName = Formatting.formatKeyAsField(key); - FieldSpec.Builder fieldBuilder = FieldSpec.builder(typedKey, fieldName, Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) - .initializer("$N($S, $T.class)", createMethod.build(), keyPath, value.getEntityClass()); + String fieldName = Formatting.formatKeyAsField(keyPath); + FieldSpec.Builder fieldBuilder = FieldSpec.builder(typedKey, fieldName, PUBLIC, STATIC, FINAL) + .initializer("$N($S, $T.class)", createMethod.build(), keyPath, goalKey.getEntityClass()); typeBuilder.addField(fieldBuilder.build()); } @@ -227,8 +221,8 @@ public class MobGoalGenerator extends SimpleGenerator { NamespacedKey key = NamespacedKey.minecraft(value.entryName); String keyPath = key.getKey(); - String fieldName = Formatting.formatKeyAsField(key); - FieldSpec.Builder fieldBuilder = FieldSpec.builder(typedKey, fieldName, Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) + String fieldName = Formatting.formatKeyAsField(keyPath); + FieldSpec.Builder fieldBuilder = FieldSpec.builder(typedKey, fieldName, PUBLIC, STATIC, FINAL) .addAnnotation(Annotations.deprecatedVersioned(value.removedVersion, value.removalVersion != null)) .initializer("$N($S, $T.class)", createMethod.build(), keyPath, value.entity); @@ -251,9 +245,6 @@ public class MobGoalGenerator extends SimpleGenerator { .skipJavaLangImports(true); } - record VanillaGoalKey(Class clazz, GoalKey key) { - } - record DeprecatedEntry(Class entity, String entryName, @Nullable String removalVersion, @Nullable String removedVersion) { diff --git a/paper-api-generator/src/main/java/io/papermc/generator/types/goal/MobGoalNames.java b/paper-api-generator/src/main/java/io/papermc/generator/types/goal/MobGoalNames.java index 37506e3f84..2ad5e0ac06 100644 --- a/paper-api-generator/src/main/java/io/papermc/generator/types/goal/MobGoalNames.java +++ b/paper-api-generator/src/main/java/io/papermc/generator/types/goal/MobGoalNames.java @@ -126,7 +126,7 @@ import java.util.Set; public class MobGoalNames { private static final Map, Class> entityClassCache = new HashMap<>(); - private static final Map, Class> bukkitMap = new HashMap<>(); + public static final Map, Class> bukkitMap = new HashMap<>(); static { @@ -233,6 +233,8 @@ public class MobGoalNames { bukkitMap.put(net.minecraft.world.entity.animal.allay.Allay.class, org.bukkit.entity.Allay.class); bukkitMap.put(net.minecraft.world.entity.animal.sniffer.Sniffer.class, org.bukkit.entity.Sniffer.class); bukkitMap.put(net.minecraft.world.entity.monster.breeze.Breeze.class, org.bukkit.entity.Breeze.class); + bukkitMap.put(net.minecraft.world.entity.animal.armadillo.Armadillo.class, org.bukkit.entity.Armadillo.class); + bukkitMap.put(net.minecraft.world.entity.monster.Bogged.class, org.bukkit.entity.Bogged.class); // } diff --git a/paper-api-generator/src/main/java/io/papermc/generator/utils/Annotations.java b/paper-api-generator/src/main/java/io/papermc/generator/utils/Annotations.java index 5c82a94e7a..a00a682330 100644 --- a/paper-api-generator/src/main/java/io/papermc/generator/utils/Annotations.java +++ b/paper-api-generator/src/main/java/io/papermc/generator/utils/Annotations.java @@ -12,11 +12,11 @@ import org.jetbrains.annotations.Nullable; public final class Annotations { - public static List experimentalAnnotations(final String version) { + public static List experimentalAnnotations(final MinecraftExperimental.Requires requiredFeatureFlag) { return List.of( AnnotationSpec.builder(ApiStatus.Experimental.class).build(), AnnotationSpec.builder(MinecraftExperimental.class) - .addMember("value", "$L", version) + .addMember("value", "$T.$L", MinecraftExperimental.Requires.class, requiredFeatureFlag.name()) .build() ); } diff --git a/paper-api-generator/src/main/java/io/papermc/generator/utils/Formatting.java b/paper-api-generator/src/main/java/io/papermc/generator/utils/Formatting.java index f4b07411a4..a6c88a8a14 100644 --- a/paper-api-generator/src/main/java/io/papermc/generator/utils/Formatting.java +++ b/paper-api-generator/src/main/java/io/papermc/generator/utils/Formatting.java @@ -1,13 +1,47 @@ package io.papermc.generator.utils; -import net.kyori.adventure.key.Key; - +import org.apache.commons.lang3.math.NumberUtils; +import java.util.Comparator; import java.util.Locale; +import java.util.OptionalInt; +import java.util.function.Function; +import java.util.regex.Pattern; public final class Formatting { - public static String formatKeyAsField(Key key) { - return key.value().toUpperCase(Locale.ENGLISH).replaceAll("[.-/]", "_"); // replace invalid field name chars + private static final Pattern ILLEGAL_FIELD_CHARACTERS = Pattern.compile("[.-/]"); + + public static String formatKeyAsField(String path) { + return ILLEGAL_FIELD_CHARACTERS.matcher(path.toUpperCase(Locale.ENGLISH)).replaceAll("_"); + } + + public static Comparator ALPHABETIC_KEY_ORDER = alphabeticKeyOrder(path -> path); + + public static Comparator alphabeticKeyOrder(Function mapper) { + return (o1, o2) -> { + String path1 = mapper.apply(o1); + String path2 = mapper.apply(o2); + + OptionalInt trailingInt1 = tryParseTrailingInt(path1); + OptionalInt trailingInt2 = tryParseTrailingInt(path2); + + if (trailingInt1.isPresent() && trailingInt2.isPresent()) { + return Integer.compare(trailingInt1.getAsInt(), trailingInt2.getAsInt()); + } + + return path1.compareTo(path2); + }; + } + + private static OptionalInt tryParseTrailingInt(String path) { + int delimiterIndex = path.lastIndexOf('_'); + if (delimiterIndex != -1) { + String score = path.substring(delimiterIndex + 1); + if (NumberUtils.isDigits(score)) { + return OptionalInt.of(Integer.parseInt(score)); + } + } + return OptionalInt.empty(); } private Formatting() { diff --git a/paper-api-generator/src/test/java/io/papermc/generator/MobGoalConverterTest.java b/paper-api-generator/src/test/java/io/papermc/generator/MobGoalConverterTest.java new file mode 100644 index 0000000000..9bc9f6b400 --- /dev/null +++ b/paper-api-generator/src/test/java/io/papermc/generator/MobGoalConverterTest.java @@ -0,0 +1,37 @@ +package io.papermc.generator; + +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ScanResult; +import io.papermc.generator.types.goal.MobGoalNames; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.Mob; +import org.junit.jupiter.api.Test; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.fail; + +public class MobGoalConverterTest { + + @Test + public void testBukkitMap() { + final List> classes; + try (ScanResult scanResult = new ClassGraph().enableAllInfo().whitelistPackages(Entity.class.getPackageName()).scan()) { + classes = scanResult.getSubclasses(Mob.class.getName()).loadClasses(Mob.class); + } + + assertFalse(classes.isEmpty(), "There are supposed to be more than 0 mob classes!"); + + List missingClasses = new ArrayList<>(); + for (Class nmsClass : classes) { + if (!MobGoalNames.bukkitMap.containsKey(nmsClass)) { + missingClasses.add(nmsClass.getCanonicalName()); + } + } + + if (!missingClasses.isEmpty()) { + fail("Missing some entity classes in the bukkit map: " + String.join(", ", missingClasses)); + } + } +} diff --git a/patches/api/0004-Code-Generation.patch b/patches/api/0004-Code-Generation.patch index 2e1f5eb6a3..edbc6ff3ef 100644 --- a/patches/api/0004-Code-Generation.patch +++ b/patches/api/0004-Code-Generation.patch @@ -246,13 +246,14 @@ index 0000000000000000000000000000000000000000..3c3fd73f7742bb8602e2f9164dd4c120 +record TypedKeyImpl(@NotNull Key key, @NotNull RegistryKey registryKey) implements TypedKey { +} diff --git a/src/main/java/org/bukkit/MinecraftExperimental.java b/src/main/java/org/bukkit/MinecraftExperimental.java -index b6f4810e387c22c4a70609ea1d605130245689a5..74d5c5e516715e7876b81bfa997d80edbe48476d 100644 +index b6f4810e387c22c4a70609ea1d605130245689a5..03824ae54e1bdb8b14f79b3c5e0294ae725e43f8 100644 --- a/src/main/java/org/bukkit/MinecraftExperimental.java +++ b/src/main/java/org/bukkit/MinecraftExperimental.java -@@ -49,4 +49,6 @@ public @interface MinecraftExperimental { +@@ -47,6 +47,6 @@ public @interface MinecraftExperimental { + @ApiStatus.Internal + public enum Requires { - UPDATE_1_21 +- UPDATE_1_21 ++ UPDATE_1_21, BUNDLE, TRADE_REBALANCE // Paper } -+ -+ String desc() default ""; // Paper } diff --git a/patches/api/0442-add-missing-Experimental-annotations.patch b/patches/api/0442-add-missing-Experimental-annotations.patch index 9c46d14fa0..89d99d97d4 100644 --- a/patches/api/0442-add-missing-Experimental-annotations.patch +++ b/patches/api/0442-add-missing-Experimental-annotations.patch @@ -27,7 +27,7 @@ index 6b68c92ec894451d99ded3e3df5965cb31d68ed2..fd5e433f930963c102c9c977523a0036 public static final FeatureFlag UPDATE_121 = Bukkit.getUnsafe().getFeatureFlag(NamespacedKey.minecraft("update_1_21")); } diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java -index 8283eccf2578bae50a4c6fd86318e0d5f7cf09df..6ebc5da2b47b005b836927621f3b929d2442a832 100644 +index 8283eccf2578bae50a4c6fd86318e0d5f7cf09df..c892610f2127f7415c287fa007ddda0aa99af28d 100644 --- a/src/main/java/org/bukkit/Material.java +++ b/src/main/java/org/bukkit/Material.java @@ -146,54 +146,67 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla @@ -240,15 +240,16 @@ index 8283eccf2578bae50a4c6fd86318e0d5f7cf09df..6ebc5da2b47b005b836927621f3b929d WAXED_OXIDIZED_COPPER_TRAPDOOR(21450, TrapDoor.class), /** * BlockData: {@link Gate} -@@ -2531,6 +2569,7 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla +@@ -2531,6 +2569,8 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla EGG(21603, 16), COMPASS(24139), RECOVERY_COMPASS(12710), ++ @MinecraftExperimental(Requires.BUNDLE) // Paper - add missing annotation + @org.jetbrains.annotations.ApiStatus.Experimental // Paper - add missing annotation BUNDLE(16835, 1), FISHING_ROD(4167, 1, 64), CLOCK(14980), -@@ -2637,6 +2676,7 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla +@@ -2637,6 +2677,7 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla * BlockData: {@link Crafter} */ @MinecraftExperimental(Requires.UPDATE_1_21) @@ -256,7 +257,7 @@ index 8283eccf2578bae50a4c6fd86318e0d5f7cf09df..6ebc5da2b47b005b836927621f3b929d CRAFTER(25243, Crafter.class), FILLED_MAP(23504), SHEARS(27971, 1, 238), -@@ -2677,8 +2717,10 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla +@@ -2677,8 +2718,10 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla BEE_SPAWN_EGG(22924), BLAZE_SPAWN_EGG(4759), @MinecraftExperimental(Requires.UPDATE_1_21) @@ -267,7 +268,7 @@ index 8283eccf2578bae50a4c6fd86318e0d5f7cf09df..6ebc5da2b47b005b836927621f3b929d BREEZE_SPAWN_EGG(7580), CAT_SPAWN_EGG(29583), CAMEL_SPAWN_EGG(14760), -@@ -2755,10 +2797,12 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla +@@ -2755,10 +2798,12 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla EXPERIENCE_BOTTLE(12858), FIRE_CHARGE(4842), @MinecraftExperimental(Requires.UPDATE_1_21) @@ -280,7 +281,7 @@ index 8283eccf2578bae50a4c6fd86318e0d5f7cf09df..6ebc5da2b47b005b836927621f3b929d MACE(4771, 1, 250), ITEM_FRAME(27318), GLOW_ITEM_FRAME(26473), -@@ -3157,8 +3201,10 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla +@@ -3157,8 +3202,10 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla RAISER_ARMOR_TRIM_SMITHING_TEMPLATE(29116), HOST_ARMOR_TRIM_SMITHING_TEMPLATE(12165), @MinecraftExperimental(Requires.UPDATE_1_21) @@ -291,7 +292,7 @@ index 8283eccf2578bae50a4c6fd86318e0d5f7cf09df..6ebc5da2b47b005b836927621f3b929d BOLT_ARMOR_TRIM_SMITHING_TEMPLATE(9698), ANGLER_POTTERY_SHERD(9952), ARCHER_POTTERY_SHERD(21629), -@@ -3169,9 +3215,11 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla +@@ -3169,9 +3216,11 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla DANGER_POTTERY_SHERD(30506), EXPLORER_POTTERY_SHERD(5124), @MinecraftExperimental(Requires.UPDATE_1_21) @@ -303,7 +304,7 @@ index 8283eccf2578bae50a4c6fd86318e0d5f7cf09df..6ebc5da2b47b005b836927621f3b929d GUSTER_POTTERY_SHERD(28193), HEART_POTTERY_SHERD(17607), HEARTBREAK_POTTERY_SHERD(21108), -@@ -3181,6 +3229,7 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla +@@ -3181,6 +3230,7 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla PLENTY_POTTERY_SHERD(28236), PRIZE_POTTERY_SHERD(4341), @MinecraftExperimental(Requires.UPDATE_1_21) @@ -311,7 +312,7 @@ index 8283eccf2578bae50a4c6fd86318e0d5f7cf09df..6ebc5da2b47b005b836927621f3b929d SCRAPE_POTTERY_SHERD(30034), SHEAF_POTTERY_SHERD(23652), SHELTER_POTTERY_SHERD(28390), -@@ -3190,99 +3239,121 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla +@@ -3190,99 +3240,121 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla * BlockData: {@link Waterlogged} */ @MinecraftExperimental(Requires.UPDATE_1_21) @@ -485,7 +486,7 @@ index b0ccd263cabe911d43cc13261011b64cacaeb7bb..82d75010cc86bbbbb9c094c2bac5e570 /** * Uses {@link BlockData} as DataType diff --git a/src/main/java/org/bukkit/Sound.java b/src/main/java/org/bukkit/Sound.java -index 375172e05a78611deb3003f780867516cb6cd1a4..b31a8ff47e28440b5e91ddd2fe3f07fd7219d4df 100644 +index 375172e05a78611deb3003f780867516cb6cd1a4..7c39a281a38b412a989dbdf3d12e826ee6eda714 100644 --- a/src/main/java/org/bukkit/Sound.java +++ b/src/main/java/org/bukkit/Sound.java @@ -221,40 +221,56 @@ public enum Sound implements Keyed, net.kyori.adventure.sound.Sound.Type { // Pa @@ -796,7 +797,22 @@ index 375172e05a78611deb3003f780867516cb6cd1a4..b31a8ff47e28440b5e91ddd2fe3f07fd EVENT_MOB_EFFECT_TRIAL_OMEN("event.mob_effect.trial_omen"), EVENT_RAID_HORN("event.raid.horn"), INTENTIONALLY_EMPTY("intentionally_empty"), -@@ -1624,13 +1709,17 @@ public enum Sound implements Keyed, net.kyori.adventure.sound.Sound.Type { // Pa +@@ -1591,8 +1676,14 @@ public enum Sound implements Keyed, net.kyori.adventure.sound.Sound.Type { // Pa + ITEM_BUCKET_FILL_LAVA("item.bucket.fill_lava"), + ITEM_BUCKET_FILL_POWDER_SNOW("item.bucket.fill_powder_snow"), + ITEM_BUCKET_FILL_TADPOLE("item.bucket.fill_tadpole"), ++ @MinecraftExperimental(Requires.BUNDLE) // Paper - add missing annotation ++ @org.jetbrains.annotations.ApiStatus.Experimental // Paper - add missing annotation + ITEM_BUNDLE_DROP_CONTENTS("item.bundle.drop_contents"), ++ @MinecraftExperimental(Requires.BUNDLE) // Paper - add missing annotation ++ @org.jetbrains.annotations.ApiStatus.Experimental // Paper - add missing annotation + ITEM_BUNDLE_INSERT("item.bundle.insert"), ++ @MinecraftExperimental(Requires.BUNDLE) // Paper - add missing annotation ++ @org.jetbrains.annotations.ApiStatus.Experimental // Paper - add missing annotation + ITEM_BUNDLE_REMOVE_ONE("item.bundle.remove_one"), + ITEM_CHORUS_FRUIT_TELEPORT("item.chorus_fruit.teleport"), + ITEM_CROP_PLANT("item.crop.plant"), +@@ -1624,13 +1715,17 @@ public enum Sound implements Keyed, net.kyori.adventure.sound.Sound.Type { // Pa ITEM_INK_SAC_USE("item.ink_sac.use"), ITEM_LODESTONE_COMPASS_LOCK("item.lodestone_compass.lock"), @MinecraftExperimental(Requires.UPDATE_1_21) @@ -814,7 +830,7 @@ index 375172e05a78611deb3003f780867516cb6cd1a4..b31a8ff47e28440b5e91ddd2fe3f07fd ITEM_OMINOUS_BOTTLE_DISPOSE("item.ominous_bottle.dispose"), ITEM_SHIELD_BLOCK("item.shield.block"), ITEM_SHIELD_BREAK("item.shield.break"), -@@ -1647,12 +1736,16 @@ public enum Sound implements Keyed, net.kyori.adventure.sound.Sound.Type { // Pa +@@ -1647,12 +1742,16 @@ public enum Sound implements Keyed, net.kyori.adventure.sound.Sound.Type { // Pa ITEM_TRIDENT_THROW("item.trident.throw"), ITEM_TRIDENT_THUNDER("item.trident.thunder"), @MinecraftExperimental(Requires.UPDATE_1_21) diff --git a/patches/server/0363-Implement-Mob-Goal-API.patch b/patches/server/0363-Implement-Mob-Goal-API.patch index 33bb7d6d59..50b5ac2812 100644 --- a/patches/server/0363-Implement-Mob-Goal-API.patch +++ b/patches/server/0363-Implement-Mob-Goal-API.patch @@ -18,10 +18,10 @@ index b1b7d9b72c9f79fe2cfcde47be35a7e73b35d6ff..81b42b378f2d44ce1ffba5ee3f50aad3 testImplementation("org.mockito:mockito-core:5.11.0") diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java new file mode 100644 -index 0000000000000000000000000000000000000000..74778e5089814dd3a28e91738e82dfd7b8eb8d4c +index 0000000000000000000000000000000000000000..55e85267c7cbd8be5d2da212e33c43fb353f2e12 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java -@@ -0,0 +1,376 @@ +@@ -0,0 +1,378 @@ +package com.destroystokyo.paper.entity.ai; + +import com.destroystokyo.paper.entity.RangedEntity; @@ -270,6 +270,8 @@ index 0000000000000000000000000000000000000000..74778e5089814dd3a28e91738e82dfd7 + bukkitMap.put(net.minecraft.world.entity.animal.allay.Allay.class, org.bukkit.entity.Allay.class); + bukkitMap.put(net.minecraft.world.entity.animal.sniffer.Sniffer.class, org.bukkit.entity.Sniffer.class); + bukkitMap.put(Breeze.class, org.bukkit.entity.Breeze.class); ++ bukkitMap.put(net.minecraft.world.entity.animal.armadillo.Armadillo.class, org.bukkit.entity.Armadillo.class); ++ bukkitMap.put(net.minecraft.world.entity.monster.Bogged.class, org.bukkit.entity.Bogged.class); + } + + public static String getUsableName(Class clazz) { diff --git a/patches/server/0574-Missing-Entity-API.patch b/patches/server/0574-Missing-Entity-API.patch index 1e466fb30d..0f3d205a48 100644 --- a/patches/server/0574-Missing-Entity-API.patch +++ b/patches/server/0574-Missing-Entity-API.patch @@ -44,7 +44,7 @@ Co-authored-by: FireInstall Co-authored-by: maxcom1 <46265094+maxcom1@users.noreply.github.com> diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java -index 74778e5089814dd3a28e91738e82dfd7b8eb8d4c..86933746b211a8fa7006b6854c42234a78a37843 100644 +index 55e85267c7cbd8be5d2da212e33c43fb353f2e12..c72d6bccf7d72d08d388c65936a89c92261c7860 100644 --- a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java +++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java @@ -165,7 +165,7 @@ public class MobGoalHelper {