diff --git a/paper-generator/build.gradle.kts b/paper-generator/build.gradle.kts index f23d61eaa3..e2d47ccc15 100644 --- a/paper-generator/build.gradle.kts +++ b/paper-generator/build.gradle.kts @@ -30,7 +30,7 @@ dependencies { val generatedApiPath = file("generatedApi") val generatedServerPath = file("generatedServer") -tasks.register("generate") { +val generate by tasks.registering(JavaExec::class) { dependsOn(tasks.check) mainClass.set("io.papermc.generator.Main") classpath(sourceSets.main.map { it.runtimeClasspath }) @@ -40,6 +40,13 @@ tasks.register("generate") { project(":paper-server").sourceSets["main"].java.srcDirs.first().toString()) } +generate.configure { + delete(generatedApiPath, generatedServerPath) + // the module depends on paper-api but generate into the project which cause conflict + // ideally this module would only depend on vanilla source in the long + // run +} + tasks.register("scanOldGeneratedSourceCode") { mainClass.set("io.papermc.generator.rewriter.OldGeneratedCodeTest") classpath(sourceSets.test.map { it.runtimeClasspath }) diff --git a/paper-generator/src/main/java/io/papermc/generator/Main.java b/paper-generator/src/main/java/io/papermc/generator/Main.java index 0048a11158..5727c31164 100644 --- a/paper-generator/src/main/java/io/papermc/generator/Main.java +++ b/paper-generator/src/main/java/io/papermc/generator/Main.java @@ -5,7 +5,7 @@ import com.mojang.logging.LogUtils; import io.papermc.generator.rewriter.registration.PaperPatternSourceSetRewriter; import io.papermc.generator.rewriter.registration.PatternSourceSetRewriter; import io.papermc.generator.types.SourceGenerator; -import io.papermc.generator.utils.experimental.TagCollector; +import io.papermc.generator.utils.experimental.ExperimentalCollector; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -66,7 +66,7 @@ public final class Main { MoreExecutors.directExecutor() ).join(); reloadableServerResources.updateStaticRegistryTags(); - EXPERIMENTAL_TAGS = TagCollector.grabExperimental(resourceManager); + EXPERIMENTAL_TAGS = ExperimentalCollector.collectTags(resourceManager); } private Main() { diff --git a/paper-generator/src/main/java/io/papermc/generator/Rewriters.java b/paper-generator/src/main/java/io/papermc/generator/Rewriters.java index 617cca8bf1..6c326d1495 100644 --- a/paper-generator/src/main/java/io/papermc/generator/Rewriters.java +++ b/paper-generator/src/main/java/io/papermc/generator/Rewriters.java @@ -75,7 +75,7 @@ import org.jspecify.annotations.NullMarked; import static io.papermc.generator.rewriter.registration.PaperPatternSourceSetRewriter.composite; import static io.papermc.generator.rewriter.registration.RewriterHolder.holder; -import static io.papermc.typewriter.utils.Formatting.quoted; +import static io.papermc.typewriter.util.Formatting.quoted; @NullMarked public final class Rewriters { diff --git a/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java b/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java index 2e51e0ce1b..7668d56faa 100644 --- a/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java +++ b/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java @@ -6,6 +6,7 @@ import io.papermc.paper.registry.data.GameEventRegistryEntry; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.lang.reflect.Type; +import java.util.Arrays; import java.util.Collections; import java.util.IdentityHashMap; import java.util.List; @@ -13,6 +14,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Consumer; +import java.util.stream.Collectors; import net.minecraft.core.Registry; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.core.registries.Registries; @@ -38,6 +40,7 @@ import net.minecraft.world.item.equipment.trim.TrimPatterns; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BannerPatterns; +import net.minecraft.world.level.levelgen.structure.BuiltinStructures; import net.minecraft.world.level.material.Fluids; import net.minecraft.world.level.saveddata.maps.MapDecorationTypes; import org.bukkit.Art; @@ -70,36 +73,29 @@ import org.bukkit.map.MapCursor; import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionType; import org.jspecify.annotations.NullMarked; -import org.jspecify.annotations.Nullable; @NullMarked public final class RegistryEntries { - private static RegistryEntry entry(ResourceKey> registryKey, @Nullable Class registryConstantClass, Class apiClass, String implClass) { - return new RegistryEntry<>(registryKey, (RegistryKeyField) REGISTRY_KEY_FIELDS.get(registryKey), registryConstantClass, apiClass, implClass); + private static RegistryEntry entry(ResourceKey> registryKey, Class holderElementsClass, Class apiClass, String implClass) { + return new RegistryEntry<>(registryKey, (RegistryKeyField) REGISTRY_KEY_FIELDS.get(registryKey), holderElementsClass, apiClass, implClass); } // CraftBukkit entry where implementation start by "Craft" - private static RegistryEntry entry(ResourceKey> registryKey, @Nullable Class registryConstantClass, Class apiClass) { - return entry(registryKey, registryConstantClass, "Craft", apiClass); + private static RegistryEntry entry(ResourceKey> registryKey, Class holderElementsClass, Class apiClass) { + return entry(registryKey, holderElementsClass, "Craft", apiClass); } - private static RegistryEntry entry(ResourceKey> registryKey, @Nullable Class registryConstantClass, String implPrefix, Class apiClass) { - String name = io.papermc.typewriter.utils.ClassHelper.retrieveFullNestedName(apiClass); + private static RegistryEntry entry(ResourceKey> registryKey, Class holderElementsClass, String implPrefix, Class apiClass) { + String name = io.papermc.typewriter.util.ClassHelper.retrieveFullNestedName(apiClass); RegistryKeyField registryKeyField = (RegistryKeyField) REGISTRY_KEY_FIELDS.get(registryKey); String[] classes = name.split("\\."); if (classes.length == 0) { - return new RegistryEntry<>(registryKey, registryKeyField, registryConstantClass, apiClass, implPrefix.concat(apiClass.getSimpleName())); + return new RegistryEntry<>(registryKey, registryKeyField, holderElementsClass, apiClass, implPrefix.concat(apiClass.getSimpleName())); } - StringBuilder implName = new StringBuilder(name.length() + implPrefix.length() * classes.length); - implName.append(implPrefix.concat(classes[0])); - for (int i = 1; i < classes.length; i++) { - implName.append('.'); - implName.append(implPrefix.concat(classes[i])); - } - - return new RegistryEntry<>(registryKey, registryKeyField, registryConstantClass, apiClass,implName.toString()); + String implName = Arrays.stream(classes).map(implPrefix::concat).collect(Collectors.joining(".")); + return new RegistryEntry<>(registryKey, registryKeyField, holderElementsClass, apiClass, implName); } private static final Map>, RegistryKeyField> REGISTRY_KEY_FIELDS; @@ -148,7 +144,7 @@ public final class RegistryEntries { public static final List> DATA_DRIVEN = List.of( entry(Registries.BIOME, Biomes.class, Biome.class).delayed(), - entry(Registries.STRUCTURE, null, Structure.class).delayed(), + entry(Registries.STRUCTURE, BuiltinStructures.class, Structure.class).delayed(), entry(Registries.TRIM_MATERIAL, TrimMaterials.class, TrimMaterial.class).delayed(), entry(Registries.TRIM_PATTERN, TrimPatterns.class, TrimPattern.class).delayed(), entry(Registries.DAMAGE_TYPE, DamageTypes.class, DamageType.class).delayed(), diff --git a/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntry.java b/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntry.java index dd5bc803bb..10192c80ff 100644 --- a/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntry.java +++ b/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntry.java @@ -22,8 +22,8 @@ public final class RegistryEntry { private final ResourceKey> registryKey; private final RegistryKeyField registryKeyField; - private final Class registryElementClass; - private final @Nullable Class registryConstantClass; + private final Class elementClass; + private final Class holderElementsClass; private final Class apiClass; // TODO remove Keyed private final String implClass; @@ -37,11 +37,11 @@ public final class RegistryEntry { private @Nullable Map, String> fieldNames; - public RegistryEntry(ResourceKey> registryKey, RegistryKeyField registryKeyField, @Nullable Class registryConstantClass, Class apiClass, String implClass) { + public RegistryEntry(ResourceKey> registryKey, RegistryKeyField registryKeyField, Class holderElementsClass, Class apiClass, String implClass) { this.registryKey = registryKey; this.registryKeyField = registryKeyField; - this.registryElementClass = registryKeyField.elementClass(); - this.registryConstantClass = registryConstantClass; + this.elementClass = registryKeyField.elementClass(); + this.holderElementsClass = holderElementsClass; this.apiClass = apiClass; this.implClass = implClass; } @@ -112,7 +112,7 @@ public final class RegistryEntry { return this.apiClass.getSimpleName(); } - return this.registryElementClass.getSimpleName(); + return this.elementClass.getSimpleName(); } public boolean allowCustomKeys() { @@ -122,18 +122,18 @@ public final class RegistryEntry { private Map, TO> getFields(Map, TO> map, Function transform) { Registry registry = this.registry(); try { - for (Field field : this.registryConstantClass.getDeclaredFields()) { - if (!ResourceKey.class.isAssignableFrom(field.getType()) && !Holder.Reference.class.isAssignableFrom(field.getType()) && !this.registryElementClass.isAssignableFrom(field.getType())) { + for (Field field : this.holderElementsClass.getDeclaredFields()) { + if (!ResourceKey.class.isAssignableFrom(field.getType()) && !Holder.Reference.class.isAssignableFrom(field.getType()) && !this.elementClass.isAssignableFrom(field.getType())) { continue; } if (ClassHelper.isStaticConstant(field, Modifier.PUBLIC)) { ResourceKey key = null; - if (this.registryElementClass.isAssignableFrom(field.getType())) { - key = registry.getResourceKey(this.registryElementClass.cast(field.get(null))).orElseThrow(); + if (this.elementClass.isAssignableFrom(field.getType())) { + key = registry.getResourceKey(this.elementClass.cast(field.get(null))).orElseThrow(); } else { if (field.getGenericType() instanceof ParameterizedType complexType && complexType.getActualTypeArguments().length == 1 && - complexType.getActualTypeArguments()[0] == this.registryElementClass) { + complexType.getActualTypeArguments()[0] == this.elementClass) { if (Holder.Reference.class.isAssignableFrom(field.getType())) { key = ((Holder.Reference) field.get(null)).key(); @@ -164,10 +164,6 @@ public final class RegistryEntry { } public Map, TO> getFields(Function transform) { - if (this.registryConstantClass == null) { - return Collections.emptyMap(); - } - return Collections.unmodifiableMap(this.getFields(new IdentityHashMap<>(), transform)); } diff --git a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/EnumRegistryRewriter.java b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/EnumRegistryRewriter.java index 262105e9ab..5d1aa89fb4 100644 --- a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/EnumRegistryRewriter.java +++ b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/EnumRegistryRewriter.java @@ -4,12 +4,11 @@ import com.google.common.base.Suppliers; import io.papermc.generator.Main; import io.papermc.generator.rewriter.utils.Annotations; import io.papermc.generator.utils.Formatting; -import io.papermc.generator.utils.RegistryUtils; -import io.papermc.generator.utils.experimental.FlagHolders; +import io.papermc.generator.utils.experimental.ExperimentalCollector; import io.papermc.generator.utils.experimental.SingleFlagHolder; import io.papermc.typewriter.preset.EnumRewriter; import io.papermc.typewriter.preset.model.EnumValue; -import java.util.Set; +import java.util.Map; import java.util.function.Supplier; import net.minecraft.core.Holder; import net.minecraft.core.Registry; @@ -19,13 +18,13 @@ import net.minecraft.world.flag.FeatureFlags; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; -import static io.papermc.typewriter.utils.Formatting.quoted; +import static io.papermc.typewriter.util.Formatting.quoted; @NullMarked public class EnumRegistryRewriter extends EnumRewriter> { private final Registry registry; - private final Supplier>> experimentalKeys; + private final Supplier, SingleFlagHolder>> experimentalKeys; private final boolean isFilteredRegistry; private final boolean hasKeyArgument; @@ -35,7 +34,7 @@ public class EnumRegistryRewriter extends EnumRewriter> { protected EnumRegistryRewriter(ResourceKey> registryKey, boolean hasKeyArgument) { this.registry = Main.REGISTRY_ACCESS.lookupOrThrow(registryKey); - this.experimentalKeys = Suppliers.memoize(() -> RegistryUtils.collectExperimentalDataDrivenKeys(this.registry)); + this.experimentalKeys = Suppliers.memoize(() -> ExperimentalCollector.collectDataDrivenElementIds(this.registry)); this.isFilteredRegistry = FeatureElement.FILTERED_REGISTRIES.contains(registryKey); this.hasKeyArgument = hasKeyArgument; } @@ -74,9 +73,7 @@ public class EnumRegistryRewriter extends EnumRewriter> { } } else { // data-driven registry - if (this.experimentalKeys.get().contains(reference.key())) { - return FlagHolders.NEXT_UPDATE; - } + return this.experimentalKeys.get().get(reference.key()); } return null; } diff --git a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/FeatureFlagRewriter.java b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/FeatureFlagRewriter.java index 2a32034b35..154309a832 100644 --- a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/FeatureFlagRewriter.java +++ b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/FeatureFlagRewriter.java @@ -16,7 +16,7 @@ import org.jspecify.annotations.NullMarked; import org.slf4j.Logger; import static io.papermc.generator.rewriter.utils.Annotations.annotation; -import static io.papermc.typewriter.utils.Formatting.quoted; +import static io.papermc.typewriter.util.Formatting.quoted; @NullMarked public class FeatureFlagRewriter extends SearchReplaceRewriter { diff --git a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/PaperFeatureFlagMapping.java b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/PaperFeatureFlagMapping.java index 0e59392ab0..06287f65a0 100644 --- a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/PaperFeatureFlagMapping.java +++ b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/PaperFeatureFlagMapping.java @@ -14,7 +14,7 @@ public class PaperFeatureFlagMapping extends SearchReplaceRewriter { @Override protected void insert(SearchMetadata metadata, StringBuilder builder) { - Iterator flagIterator = FeatureFlags.REGISTRY.toNames(FeatureFlags.REGISTRY.allFlags()).stream().sorted(Formatting.alphabeticKeyOrder(name -> name.getPath())).iterator(); + Iterator flagIterator = FeatureFlags.REGISTRY.toNames(FeatureFlags.REGISTRY.allFlags()).stream().sorted(Formatting.alphabeticKeyOrder(ResourceLocation::getPath)).iterator(); while (flagIterator.hasNext()) { ResourceLocation name = flagIterator.next(); diff --git a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/RegistryFieldRewriter.java b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/RegistryFieldRewriter.java index 4f5342b94d..d289ff12ee 100644 --- a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/RegistryFieldRewriter.java +++ b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/RegistryFieldRewriter.java @@ -6,15 +6,14 @@ import com.mojang.logging.LogUtils; import io.papermc.generator.Main; import io.papermc.generator.rewriter.utils.Annotations; import io.papermc.generator.utils.Formatting; -import io.papermc.generator.utils.RegistryUtils; -import io.papermc.generator.utils.experimental.FlagHolders; +import io.papermc.generator.utils.experimental.ExperimentalCollector; import io.papermc.generator.utils.experimental.SingleFlagHolder; import io.papermc.typewriter.ClassNamed; import io.papermc.typewriter.SourceFile; import io.papermc.typewriter.replace.SearchMetadata; import io.papermc.typewriter.replace.SearchReplaceRewriter; import java.util.Iterator; -import java.util.Set; +import java.util.Map; import java.util.function.Supplier; import net.minecraft.core.Holder; import net.minecraft.core.Registry; @@ -26,7 +25,7 @@ import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; -import static io.papermc.typewriter.utils.Formatting.quoted; +import static io.papermc.typewriter.util.Formatting.quoted; import static javax.lang.model.element.Modifier.FINAL; import static javax.lang.model.element.Modifier.PUBLIC; import static javax.lang.model.element.Modifier.STATIC; @@ -37,7 +36,7 @@ public class RegistryFieldRewriter extends SearchReplaceRewriter { private static final Logger LOGGER = LogUtils.getLogger(); private final Registry registry; - private final Supplier>> experimentalKeys; + private final Supplier, SingleFlagHolder>> experimentalKeys; private final boolean isFilteredRegistry; private final @Nullable String fetchMethod; @@ -45,7 +44,7 @@ public class RegistryFieldRewriter extends SearchReplaceRewriter { public RegistryFieldRewriter(ResourceKey> registryKey, @Nullable String fetchMethod) { this.registry = Main.REGISTRY_ACCESS.lookupOrThrow(registryKey); - this.experimentalKeys = Suppliers.memoize(() -> RegistryUtils.collectExperimentalDataDrivenKeys(this.registry)); + this.experimentalKeys = Suppliers.memoize(() -> ExperimentalCollector.collectDataDrivenElementIds(this.registry)); this.isFilteredRegistry = FeatureElement.FILTERED_REGISTRIES.contains(registryKey); this.fetchMethod = fetchMethod; } @@ -127,9 +126,7 @@ public class RegistryFieldRewriter extends SearchReplaceRewriter { } } else { // data-driven registry - if (this.experimentalKeys.get().contains(reference.key())) { - return FlagHolders.NEXT_UPDATE; - } + return this.experimentalKeys.get().get(reference.key()); } return null; } diff --git a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/RegistryTagRewriter.java b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/RegistryTagRewriter.java index 8c7aec9d7a..3ee0f0ae6a 100644 --- a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/RegistryTagRewriter.java +++ b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/RegistryTagRewriter.java @@ -18,7 +18,7 @@ import org.bukkit.Tag; import org.jspecify.annotations.NullMarked; import org.slf4j.Logger; -import static io.papermc.typewriter.utils.Formatting.quoted; +import static io.papermc.typewriter.util.Formatting.quoted; import static javax.lang.model.element.Modifier.FINAL; import static javax.lang.model.element.Modifier.PUBLIC; import static javax.lang.model.element.Modifier.STATIC; diff --git a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/TagRewriter.java b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/TagRewriter.java index 26f87f12b5..3efecd6da4 100644 --- a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/TagRewriter.java +++ b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/registry/TagRewriter.java @@ -21,7 +21,7 @@ import org.bukkit.NamespacedKey; import org.bukkit.entity.EntityType; import org.jspecify.annotations.NullMarked; -import static io.papermc.typewriter.utils.Formatting.quoted; +import static io.papermc.typewriter.util.Formatting.quoted; @NullMarked public class TagRewriter extends SearchReplaceRewriter { diff --git a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/BlockTypeRewriter.java b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/BlockTypeRewriter.java index 6a82e91a3c..9a496c75e1 100644 --- a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/BlockTypeRewriter.java +++ b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/BlockTypeRewriter.java @@ -2,7 +2,7 @@ package io.papermc.generator.rewriter.types.simple; import io.papermc.generator.rewriter.types.registry.RegistryFieldRewriter; import io.papermc.generator.utils.BlockStateMapping; -import io.papermc.typewriter.utils.ClassHelper; +import io.papermc.typewriter.util.ClassHelper; import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; import net.minecraft.world.level.block.Block; diff --git a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/EntityTypeRewriter.java b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/EntityTypeRewriter.java index 29da10c020..9450c3c23e 100644 --- a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/EntityTypeRewriter.java +++ b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/EntityTypeRewriter.java @@ -20,7 +20,7 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.Mob; -import static io.papermc.typewriter.utils.Formatting.quoted; +import static io.papermc.typewriter.util.Formatting.quoted; public class EntityTypeRewriter extends EnumRegistryRewriter> { @@ -146,11 +146,11 @@ public class EntityTypeRewriter extends EnumRegistryRewriter> { @Override protected EnumValue.Builder rewriteEnumValue(Holder.Reference> reference) { String path = reference.key().location().getPath(); - List arguments = Util.make(new ArrayList<>(), args -> { - args.add(quoted(path)); - args.add(toBukkitClass(reference).concat(".class")); - args.add(Integer.toString(LEGACY_ID.getOrDefault(reference.value(), -1))); - }); + List arguments = new ArrayList<>(4); + arguments.add(quoted(path)); + arguments.add(toBukkitClass(reference).concat(".class")); + arguments.add(Integer.toString(LEGACY_ID.getOrDefault(reference.value(), -1))); + if (!reference.value().canSummon()) { arguments.add(Boolean.FALSE.toString()); } diff --git a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/ItemTypeRewriter.java b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/ItemTypeRewriter.java index 9f3ef39a88..232cf52237 100644 --- a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/ItemTypeRewriter.java +++ b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/ItemTypeRewriter.java @@ -1,7 +1,7 @@ package io.papermc.generator.rewriter.types.simple; import io.papermc.generator.rewriter.types.registry.RegistryFieldRewriter; -import io.papermc.typewriter.utils.ClassHelper; +import io.papermc.typewriter.util.ClassHelper; import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; import net.minecraft.world.item.Item; diff --git a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/MemoryKeyRewriter.java b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/MemoryKeyRewriter.java index 45de3e79fb..f7db7df5b4 100644 --- a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/MemoryKeyRewriter.java +++ b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/MemoryKeyRewriter.java @@ -25,7 +25,7 @@ import org.bukkit.Location; import org.bukkit.NamespacedKey; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -import static io.papermc.typewriter.utils.Formatting.quoted; +import static io.papermc.typewriter.util.Formatting.quoted; public class MemoryKeyRewriter extends RegistryFieldRewriter> { diff --git a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/StatisticRewriter.java b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/StatisticRewriter.java index cdea9a9023..7cbed5e803 100644 --- a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/StatisticRewriter.java +++ b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/StatisticRewriter.java @@ -22,7 +22,7 @@ import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; import org.bukkit.Statistic; -import static io.papermc.typewriter.utils.Formatting.quoted; +import static io.papermc.typewriter.util.Formatting.quoted; @Deprecated(forRemoval = true) public class StatisticRewriter { @@ -59,7 +59,8 @@ public class StatisticRewriter { .put("INTERACT_WITH_FURNACE", "FURNACE_INTERACTION") .put("INTERACT_WITH_CRAFTING_TABLE", "CRAFTING_TABLE_INTERACTION") .put("OPEN_CHEST", "CHEST_OPENED") - .put("OPEN_SHULKER_BOX", "SHULKER_BOX_OPENED").build(); + .put("OPEN_SHULKER_BOX", "SHULKER_BOX_OPENED") + .build(); public static class Custom extends EnumRegistryRewriter { diff --git a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/VillagerProfessionRewriter.java b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/VillagerProfessionRewriter.java index d0361aa46e..6f0fa7c09b 100644 --- a/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/VillagerProfessionRewriter.java +++ b/paper-generator/src/main/java/io/papermc/generator/rewriter/types/simple/VillagerProfessionRewriter.java @@ -3,13 +3,11 @@ package io.papermc.generator.rewriter.types.simple; import io.papermc.generator.rewriter.types.registry.RegistryFieldRewriter; import io.papermc.generator.utils.Formatting; import io.papermc.typewriter.parser.Lexer; -import io.papermc.typewriter.parser.exception.ParserException; import io.papermc.typewriter.parser.token.CharSequenceBlockToken; import io.papermc.typewriter.parser.token.CharSequenceToken; -import io.papermc.typewriter.parser.token.Token; import io.papermc.typewriter.parser.token.TokenType; +import io.papermc.typewriter.parser.SequenceTokens; import io.papermc.typewriter.replace.SearchMetadata; -import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; import java.util.List; @@ -20,7 +18,6 @@ import net.minecraft.core.registries.Registries; import net.minecraft.world.entity.npc.VillagerProfession; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.jetbrains.annotations.ApiStatus; -import org.jspecify.annotations.Nullable; @ApiStatus.Experimental public class VillagerProfessionRewriter extends RegistryFieldRewriter { @@ -37,108 +34,82 @@ public class VillagerProfessionRewriter extends RegistryFieldRewriter> javadocsPerConstant; + private static class ConstantInfo { + private @MonotonicNonNull String constantName; + private @MonotonicNonNull List javadocs; + + public void constantName(String name) { + this.constantName = name; + } + + public void javadocs(List javadocs) { + this.javadocs = javadocs; + } + + public String constantName() { + return this.constantName; + } + + public List javadocs() { + return this.javadocs; + } + + public boolean isEmpty() { + return this.constantName == null || this.javadocs == null; + } + } + private Map> parseConstantJavadocs(String content) { Map> map = new HashMap<>(); Lexer lex = new Lexer(content.toCharArray()); - String constantName = null; - List javadocs = null; - boolean firstId = true; - while (lex.canRead()) { - Token token = lex.readToken(); - if (token.type() == TokenType.EOI) { - break; - } - - if (token.type() == TokenType.SECO) { - if (constantName != null && javadocs != null) { - map.put(constantName, new ArrayList<>(javadocs)); - } - firstId = true; - constantName = null; - javadocs = null; - continue; - } - - if (FORMAT_TOKENS.contains(token.type())) { - continue; - } - - if (token.type() == TokenType.LPAREN && constantName != null) { - if (!this.skipClosure(lex)) { - return map; - } - continue; - } - - if (token.type() == TokenType.JAVADOC) { - javadocs = ((CharSequenceBlockToken) token).value(); - } else if (token.type() == TokenType.PUBLIC || token.type() == TokenType.STATIC || token.type() == TokenType.FINAL) { - // should check duplicate per statement - continue; // ignore - } else if (token.type() == TokenType.IDENTIFIER && constantName == null) { - if (firstId) { - Token nextToken = this.skipTypeName(lex); - if (nextToken != null && nextToken.type() == TokenType.IDENTIFIER) { - token = nextToken; - } - firstId = false; - } - - constantName = ((CharSequenceToken) token).value(); - } - } + SequenceTokens.wrap(lex, FORMAT_TOKENS) + .group(action -> { + ConstantInfo info = new ConstantInfo(); + action + .map(TokenType.JAVADOC, token -> { + info.javadocs(((CharSequenceBlockToken) token).value()); + }, SequenceTokens.TokenTask::asOptional) + .skipQualifiedName(Set.of(TokenType.JAVADOC)) + .map(TokenType.IDENTIFIER, token -> { + info.constantName(((CharSequenceToken) token).value()); + }) + .skip(TokenType.IDENTIFIER) + .skipClosure(TokenType.LPAREN, TokenType.RPAREN, true) + .map(TokenType.SECO, $ -> { + if (!info.isEmpty()) { + map.put(info.constantName(), info.javadocs()); + } + }); + }, SequenceTokens.TokenTask::asRepeatable) + .execute(); + /* + for enums: + SequenceTokens.wrap(lex, FORMAT_TOKENS) + .group(action -> { + ConstantInfo info = new ConstantInfo(); + action + .map(TokenType.JAVADOC, token -> { + info.javadocs(((CharSequenceBlockToken) token).value()); + }, SequenceTokens.TokenTask::asOptional) + .map(TokenType.IDENTIFIER, token -> { + info.constantName(((CharSequenceToken) token).value()); + }) + .skipClosure(TokenType.LPAREN, TokenType.RPAREN, true) + .skipClosure(TokenType.LSCOPE, TokenType.RSCOPE, true) + .mapMulti(Set.of(TokenType.CO, TokenType.SECO), $ -> { + // this part will probably fail for the last entry for enum without end (,;) + if (!info.isEmpty()) { + map.put(info.constantName(), info.javadocs()); + } + }); + }, SequenceTokens.TokenTask::asRepeatable) + .execute(); + */ return map; } - private boolean skipClosure(Lexer lex) { - int parenDepth = 1; - while (lex.canRead()) { - Token nestedToken = lex.readToken(); - if (nestedToken.type() == TokenType.EOI) { - return false; - } - - if (nestedToken.type() == TokenType.LPAREN) { - parenDepth++; - } else if (nestedToken.type() == TokenType.RPAREN) { - parenDepth--; - } - - if (parenDepth == 0) { - break; - } - - if (parenDepth < 0) { - throw new ParserException("Unbalanced parenthesis", nestedToken); - } - } - - return true; - } - - private @Nullable Token skipTypeName(Lexer lex) { - boolean expectDot = true; - while (lex.canRead()) { - Token token = lex.readToken(); - if (token.type() == TokenType.EOI) { - break; - } - - if (FORMAT_TOKENS.contains(token.type()) || token.type() == TokenType.JAVADOC) { - continue; // ignore intrusive comments inside the name - } - - if (token.type() == (expectDot ? TokenType.DOT : TokenType.IDENTIFIER)) { - expectDot = !expectDot; - } else { - return token; - } - } - return null; - } - @Override protected void insert(SearchMetadata metadata, StringBuilder builder) { this.javadocsPerConstant = parseConstantJavadocs(metadata.replacedContent()); diff --git a/paper-generator/src/main/java/io/papermc/generator/rewriter/utils/Annotations.java b/paper-generator/src/main/java/io/papermc/generator/rewriter/utils/Annotations.java index 5295264994..013f7f643e 100644 --- a/paper-generator/src/main/java/io/papermc/generator/rewriter/utils/Annotations.java +++ b/paper-generator/src/main/java/io/papermc/generator/rewriter/utils/Annotations.java @@ -2,7 +2,7 @@ package io.papermc.generator.rewriter.utils; import io.papermc.generator.utils.experimental.SingleFlagHolder; import io.papermc.typewriter.context.ImportCollector; -import io.papermc.typewriter.utils.ClassHelper; +import io.papermc.typewriter.util.ClassHelper; import java.lang.annotation.Annotation; import org.bukkit.MinecraftExperimental; import org.jetbrains.annotations.ApiStatus; diff --git a/paper-generator/src/main/java/io/papermc/generator/types/StructuredGenerator.java b/paper-generator/src/main/java/io/papermc/generator/types/OverriddenClassGenerator.java similarity index 88% rename from paper-generator/src/main/java/io/papermc/generator/types/StructuredGenerator.java rename to paper-generator/src/main/java/io/papermc/generator/types/OverriddenClassGenerator.java index 144b19b7a3..2a66cf16d2 100644 --- a/paper-generator/src/main/java/io/papermc/generator/types/StructuredGenerator.java +++ b/paper-generator/src/main/java/io/papermc/generator/types/OverriddenClassGenerator.java @@ -10,14 +10,14 @@ import org.slf4j.Logger; import static javax.lang.model.element.Modifier.PUBLIC; @NullMarked -public abstract class StructuredGenerator extends SimpleGenerator { +public abstract class OverriddenClassGenerator extends SimpleGenerator { private static final Logger LOGGER = LogUtils.getLogger(); protected final Class baseClass; protected boolean printWarningOnMissingOverride; - protected StructuredGenerator(Class baseClass, String className, String packageName) { + protected OverriddenClassGenerator(Class baseClass, String className, String packageName) { super(className, packageName); this.baseClass = baseClass; } diff --git a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/CraftBlockDataGenerator.java b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/CraftBlockDataGenerator.java index c2f25ac9ce..5e55153cc2 100644 --- a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/CraftBlockDataGenerator.java +++ b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/CraftBlockDataGenerator.java @@ -8,7 +8,7 @@ import com.squareup.javapoet.FieldSpec; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.TypeSpec; -import io.papermc.generator.types.StructuredGenerator; +import io.papermc.generator.types.OverriddenClassGenerator; import io.papermc.generator.types.Types; import io.papermc.generator.types.craftblockdata.property.PropertyMaker; import io.papermc.generator.types.craftblockdata.property.PropertyWriter; @@ -46,7 +46,7 @@ import static javax.lang.model.element.Modifier.PUBLIC; import static javax.lang.model.element.Modifier.STATIC; @NullMarked -public class CraftBlockDataGenerator extends StructuredGenerator { +public class CraftBlockDataGenerator extends OverriddenClassGenerator { private final Class blockClass; private final BlockStateMapping.BlockData blockData; @@ -66,7 +66,7 @@ public class CraftBlockDataGenerator extends StructuredGene .put(BlockStateProperties.EYE, keywordGet("has")) .put(BlockStateProperties.BERRIES, keywordGet("has")) // spigot method rename // data holder keywords is only needed for the first property they hold - .put(ChiseledBookShelfBlock.SLOT_OCCUPIED_PROPERTIES.get(0), keywordGet("is")) + .put(ChiseledBookShelfBlock.SLOT_OCCUPIED_PROPERTIES.getFirst(), keywordGet("is")) .build(); private static final Map, BiConsumer> SETTER_PRECONDITIONS = Map.of( diff --git a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/IntegerPropertyWriter.java b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/IntegerPropertyWriter.java index dc6b937c73..5d5fb8c8be 100644 --- a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/IntegerPropertyWriter.java +++ b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/IntegerPropertyWriter.java @@ -3,7 +3,7 @@ package io.papermc.generator.types.craftblockdata.property; import com.squareup.javapoet.FieldSpec; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.TypeSpec; -import io.papermc.generator.types.StructuredGenerator; +import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator; import io.papermc.generator.types.craftblockdata.property.converter.Converters; import io.papermc.generator.utils.NamingManager; import net.minecraft.world.level.block.state.properties.BlockStateProperties; @@ -18,7 +18,7 @@ public class IntegerPropertyWriter extends PropertyWriter { } @Override - public void addExtras(TypeSpec.Builder builder, FieldSpec field, StructuredGenerator generator, NamingManager naming) { + public void addExtras(TypeSpec.Builder builder, FieldSpec field, CraftBlockDataGenerator generator, NamingManager naming) { if (Converters.has(this.property)) { return; } diff --git a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/PropertyWriter.java b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/PropertyWriter.java index cbda1466f4..60c93f27a9 100644 --- a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/PropertyWriter.java +++ b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/PropertyWriter.java @@ -1,15 +1,12 @@ package io.papermc.generator.types.craftblockdata.property; import com.google.common.base.Suppliers; -import com.google.common.collect.ImmutableMap; import com.google.common.primitives.Primitives; import com.squareup.javapoet.FieldSpec; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; -import io.papermc.generator.types.StructuredGenerator; -import io.papermc.generator.types.craftblockdata.property.appender.AppenderBase; -import io.papermc.generator.types.craftblockdata.property.appender.EnumValuesAppender; -import io.papermc.generator.types.craftblockdata.property.appender.PropertyAppender; +import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator; +import io.papermc.generator.types.craftblockdata.property.appender.PropertyAppenders; import io.papermc.generator.utils.BlockStateMapping; import io.papermc.generator.utils.NamingManager; import it.unimi.dsi.fastutil.Pair; @@ -20,9 +17,6 @@ import java.util.function.Supplier; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.Property; -import org.bukkit.Axis; -import org.bukkit.block.BlockFace; -import org.bukkit.block.data.Rail; import org.jspecify.annotations.NullMarked; @NullMarked @@ -64,30 +58,9 @@ public class PropertyWriter> implements PropertyMaker { return "this.get(%s)"; } - private static final Map, AppenderBase> APPENDERS; - private static final ImmutableMap.Builder, AppenderBase> builder = ImmutableMap.builder(); - - static { - register(new EnumValuesAppender<>(BlockStateProperties.AXIS, Axis.class, "getAxes")); - register(new EnumValuesAppender<>(BlockStateProperties.HORIZONTAL_AXIS, Axis.class, "getAxes")); - register(new EnumValuesAppender<>(BlockStateProperties.FACING, BlockFace.class, "getFaces")); - register(new EnumValuesAppender<>(BlockStateProperties.HORIZONTAL_FACING, BlockFace.class, "getFaces")); - register(new EnumValuesAppender<>(BlockStateProperties.FACING_HOPPER, BlockFace.class, "getFaces")); - register(new EnumValuesAppender<>(BlockStateProperties.RAIL_SHAPE, Rail.Shape.class, "getShapes")); - register(new EnumValuesAppender<>(BlockStateProperties.RAIL_SHAPE_STRAIGHT, Rail.Shape.class, "getShapes")); - register(new EnumValuesAppender<>(BlockStateProperties.VERTICAL_DIRECTION, BlockFace.class, "getVerticalDirections")); - APPENDERS = builder.build(); - } - - private static void register(PropertyAppender, ?> converter) { - builder.put(converter.getProperty(), converter); - } - @Override - public void addExtras(TypeSpec.Builder builder, FieldSpec field, StructuredGenerator generator, NamingManager naming) { - if (APPENDERS.containsKey(this.property)) { - APPENDERS.get(this.property).addExtras(builder, field, generator, naming); - } + public void addExtras(TypeSpec.Builder builder, FieldSpec field, CraftBlockDataGenerator generator, NamingManager naming) { + PropertyAppenders.ifPresent(this.property, appender -> appender.addExtras(builder, field, generator, naming)); } public static Pair, String> referenceField(Class from, Property property, Map, Field> fields) { diff --git a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/appender/AppenderBase.java b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/appender/AppenderBase.java index 0c16b104af..b1e149e75b 100644 --- a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/appender/AppenderBase.java +++ b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/appender/AppenderBase.java @@ -2,12 +2,12 @@ package io.papermc.generator.types.craftblockdata.property.appender; import com.squareup.javapoet.FieldSpec; import com.squareup.javapoet.TypeSpec; -import io.papermc.generator.types.StructuredGenerator; +import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator; import io.papermc.generator.utils.NamingManager; import org.jspecify.annotations.NullMarked; @NullMarked public interface AppenderBase { - void addExtras(TypeSpec.Builder builder, FieldSpec field, StructuredGenerator generator, NamingManager naming); + void addExtras(TypeSpec.Builder builder, FieldSpec field, CraftBlockDataGenerator generator, NamingManager naming); } diff --git a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/appender/EnumValuesAppender.java b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/appender/EnumValuesAppender.java index 9dd5532732..0898c37475 100644 --- a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/appender/EnumValuesAppender.java +++ b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/appender/EnumValuesAppender.java @@ -4,7 +4,7 @@ import com.squareup.javapoet.FieldSpec; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeSpec; -import io.papermc.generator.types.StructuredGenerator; +import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator; import io.papermc.generator.utils.NamingManager; import java.util.Set; import net.minecraft.util.StringRepresentable; @@ -35,7 +35,7 @@ public class EnumValuesAppender & StringRepresentable, A exten } @Override - public void addExtras(TypeSpec.Builder builder, FieldSpec field, StructuredGenerator generator, NamingManager naming) { + public void addExtras(TypeSpec.Builder builder, FieldSpec field, CraftBlockDataGenerator generator, NamingManager naming) { MethodSpec.Builder methodBuilder = generator.createMethod(this.methodName); methodBuilder.addStatement("return this.getValues($N, $T.class)", field, this.apiType); methodBuilder.returns(ParameterizedTypeName.get(Set.class, this.apiType)); diff --git a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/appender/PropertyAppenders.java b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/appender/PropertyAppenders.java new file mode 100644 index 0000000000..9ddfe158c6 --- /dev/null +++ b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/appender/PropertyAppenders.java @@ -0,0 +1,33 @@ +package io.papermc.generator.types.craftblockdata.property.appender; + +import java.util.Map; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.Property; +import org.bukkit.Axis; +import org.bukkit.block.BlockFace; +import org.bukkit.block.data.Rail; +import org.jspecify.annotations.NullMarked; + +@NullMarked +public final class PropertyAppenders { + + private static final Map, AppenderBase> APPENDERS = Stream.of( + new EnumValuesAppender<>(BlockStateProperties.AXIS, Axis.class, "getAxes"), + new EnumValuesAppender<>(BlockStateProperties.HORIZONTAL_AXIS, Axis.class, "getAxes"), + new EnumValuesAppender<>(BlockStateProperties.FACING, BlockFace.class, "getFaces"), + new EnumValuesAppender<>(BlockStateProperties.HORIZONTAL_FACING, BlockFace.class, "getFaces"), + new EnumValuesAppender<>(BlockStateProperties.FACING_HOPPER, BlockFace.class, "getFaces"), + new EnumValuesAppender<>(BlockStateProperties.RAIL_SHAPE, Rail.Shape.class, "getShapes"), + new EnumValuesAppender<>(BlockStateProperties.RAIL_SHAPE_STRAIGHT, Rail.Shape.class, "getShapes"), + new EnumValuesAppender<>(BlockStateProperties.VERTICAL_DIRECTION, BlockFace.class, "getVerticalDirections") + ).collect(Collectors.toUnmodifiableMap(PropertyAppender::getProperty, key -> key)); + + public static void ifPresent(Property property, Consumer callback) { + if (APPENDERS.containsKey(property)) { + callback.accept(APPENDERS.get(property)); + } + } +} diff --git a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/converter/Converter.java b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/converter/Converter.java index 17dbd6e8e8..f4c3205c84 100644 --- a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/converter/Converter.java +++ b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/converter/Converter.java @@ -8,5 +8,6 @@ public interface Converter, A> extends ConverterBase { Property getProperty(); + @Override Class getApiType(); } diff --git a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/converter/Converters.java b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/converter/Converters.java index 6c4575c719..ee2f8d3d5f 100644 --- a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/converter/Converters.java +++ b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/converter/Converters.java @@ -1,22 +1,19 @@ package io.papermc.generator.types.craftblockdata.property.converter; -import com.google.common.collect.ImmutableMap; import io.papermc.generator.types.craftblockdata.property.PropertyMaker; import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; import net.minecraft.world.level.block.state.properties.Property; import org.jspecify.annotations.NullMarked; @NullMarked public final class Converters { - private static final Map, ConverterBase> CONVERTERS; - private static final ImmutableMap.Builder, ConverterBase> builder = ImmutableMap.builder(); - - static { - register(new RotationConverter()); - register(new NoteConverter()); - CONVERTERS = builder.build(); - } + private static final Map, ConverterBase> CONVERTERS = Stream.of( + new RotationConverter(), + new NoteConverter() + ).collect(Collectors.toUnmodifiableMap(Converter::getProperty, key -> key)); public static ConverterBase getOrDefault(Property property, PropertyMaker maker) { return CONVERTERS.getOrDefault(property, maker); @@ -25,8 +22,4 @@ public final class Converters { public static boolean has(Property property) { return CONVERTERS.containsKey(property); } - - private static void register(Converter, ?> converter) { - builder.put(converter.getProperty(), converter); - } } diff --git a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/DataPropertyWriter.java b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/DataPropertyWriter.java index a01a5e84cc..965b26e7e6 100644 --- a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/DataPropertyWriter.java +++ b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/DataPropertyWriter.java @@ -1,7 +1,5 @@ package io.papermc.generator.types.craftblockdata.property.holder; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Maps; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.FieldSpec; @@ -9,13 +7,10 @@ import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; -import io.papermc.generator.types.StructuredGenerator; import io.papermc.generator.types.Types; +import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator; import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase; -import io.papermc.generator.types.craftblockdata.property.holder.appender.ArrayAppender; -import io.papermc.generator.types.craftblockdata.property.holder.appender.DataAppender; -import io.papermc.generator.types.craftblockdata.property.holder.appender.ListAppender; -import io.papermc.generator.types.craftblockdata.property.holder.appender.MapAppender; +import io.papermc.generator.types.craftblockdata.property.holder.appender.DataAppenders; import io.papermc.generator.utils.BlockStateMapping; import io.papermc.generator.utils.ClassHelper; import io.papermc.generator.utils.CommonVariable; @@ -160,24 +155,8 @@ public class DataPropertyWriter extends DataPropertyWriterBase { return name; } - private static final Map APPENDERS; - private static final ImmutableMap.Builder builder = ImmutableMap.builder(); - - static { - register(new ArrayAppender()); - register(new ListAppender()); - register(new MapAppender()); - APPENDERS = Maps.immutableEnumMap(builder.build()); - } - - private static void register(DataAppender converter) { - builder.put(converter.getType(), converter); - } - @Override - public void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase childConverter, StructuredGenerator generator, NamingManager naming) { - if (APPENDERS.containsKey(this.type)) { - APPENDERS.get(this.type).addExtras(builder, field, indexParameter, childConverter, generator, naming); - } + public void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase childConverter, CraftBlockDataGenerator generator, NamingManager naming) { + DataAppenders.ifPresent(this.type, appender -> appender.addExtras(builder, field, indexParameter, childConverter, generator, naming)); } } diff --git a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/VirtualDataPropertyWriter.java b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/VirtualDataPropertyWriter.java index 5a863b4218..df7ef4cfda 100644 --- a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/VirtualDataPropertyWriter.java +++ b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/VirtualDataPropertyWriter.java @@ -7,7 +7,7 @@ import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; -import io.papermc.generator.types.StructuredGenerator; +import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator; import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase; import io.papermc.generator.utils.BlockStateMapping; import io.papermc.generator.utils.NamingManager; @@ -93,7 +93,7 @@ public class VirtualDataPropertyWriter extends DataPropertyWriterBase { } @Override - public void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase converter, StructuredGenerator generator, NamingManager naming) { + public void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase converter, CraftBlockDataGenerator generator, NamingManager naming) { } } diff --git a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/appender/ArrayAppender.java b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/appender/ArrayAppender.java index c8ebf5cea5..88853a234f 100644 --- a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/appender/ArrayAppender.java +++ b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/appender/ArrayAppender.java @@ -6,7 +6,7 @@ import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeSpec; -import io.papermc.generator.types.StructuredGenerator; +import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator; import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase; import io.papermc.generator.types.craftblockdata.property.holder.DataHolderType; import io.papermc.generator.utils.CommonVariable; @@ -23,7 +23,7 @@ public class ArrayAppender implements DataAppender { } @Override - public void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase childConverter, StructuredGenerator generator, NamingManager naming) { + public void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase childConverter, CraftBlockDataGenerator generator, NamingManager naming) { if (childConverter.getApiType() == Boolean.TYPE) { String collectVarName = naming.getVariableNameWrapper().post("s").concat(); MethodSpec.Builder methodBuilder = generator.createMethod(naming.getMethodNameWrapper().post("s").concat()); diff --git a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/appender/DataAppender.java b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/appender/DataAppender.java index 34f308acf4..3d42772f69 100644 --- a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/appender/DataAppender.java +++ b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/appender/DataAppender.java @@ -3,7 +3,7 @@ package io.papermc.generator.types.craftblockdata.property.holder.appender; import com.squareup.javapoet.FieldSpec; import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.TypeSpec; -import io.papermc.generator.types.StructuredGenerator; +import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator; import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase; import io.papermc.generator.types.craftblockdata.property.holder.DataHolderType; import io.papermc.generator.utils.NamingManager; @@ -14,5 +14,5 @@ public interface DataAppender { DataHolderType getType(); - void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase converter, StructuredGenerator generator, NamingManager naming); + void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase converter, CraftBlockDataGenerator generator, NamingManager naming); } diff --git a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/appender/DataAppenders.java b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/appender/DataAppenders.java new file mode 100644 index 0000000000..fb484ff56b --- /dev/null +++ b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/appender/DataAppenders.java @@ -0,0 +1,24 @@ +package io.papermc.generator.types.craftblockdata.property.holder.appender; + +import io.papermc.generator.types.craftblockdata.property.holder.DataHolderType; +import java.util.Map; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.jspecify.annotations.NullMarked; + +@NullMarked +public final class DataAppenders { + + private static final Map APPENDERS = Stream.of( + new ArrayAppender(), + new ListAppender(), + new MapAppender() + ).collect(Collectors.toUnmodifiableMap(DataAppender::getType, key -> key)); + + public static void ifPresent(DataHolderType type, Consumer callback) { + if (APPENDERS.containsKey(type)) { + callback.accept(APPENDERS.get(type)); + } + } +} diff --git a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/appender/ListAppender.java b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/appender/ListAppender.java index 9bf0b406b1..67c4d72bac 100644 --- a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/appender/ListAppender.java +++ b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/appender/ListAppender.java @@ -6,7 +6,7 @@ import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeSpec; -import io.papermc.generator.types.StructuredGenerator; +import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator; import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase; import io.papermc.generator.types.craftblockdata.property.holder.DataHolderType; import io.papermc.generator.utils.CommonVariable; @@ -28,7 +28,7 @@ public class ListAppender implements DataAppender { } @Override - public void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase childConverter, StructuredGenerator generator, NamingManager naming) { + public void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase childConverter, CraftBlockDataGenerator generator, NamingManager naming) { NamingManager.NameWrapper methodName = NamingManager.NameWrapper.wrap("get", METHOD_BASE_RENAMES.getOrDefault(naming.getMethodBaseName(), naming.getMethodBaseName())); if (childConverter.getApiType() == Boolean.TYPE) { diff --git a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/appender/MapAppender.java b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/appender/MapAppender.java index 63b013b90d..f7ebd43ffd 100644 --- a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/appender/MapAppender.java +++ b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/appender/MapAppender.java @@ -7,7 +7,7 @@ import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeSpec; -import io.papermc.generator.types.StructuredGenerator; +import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator; import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase; import io.papermc.generator.types.craftblockdata.property.holder.DataHolderType; import io.papermc.generator.utils.CommonVariable; @@ -27,7 +27,7 @@ public class MapAppender implements DataAppender { } @Override - public void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase childConverter, StructuredGenerator generator, NamingManager naming) { + public void addExtras(TypeSpec.Builder builder, FieldSpec field, ParameterSpec indexParameter, ConverterBase childConverter, CraftBlockDataGenerator generator, NamingManager naming) { if (childConverter.getApiType() == Boolean.TYPE) { String collectVarName = naming.getVariableNameWrapper().post("s").concat(); MethodSpec.Builder methodBuilder = generator.createMethod(naming.getMethodNameWrapper().post("s").concat()); diff --git a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/converter/DataConverters.java b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/converter/DataConverters.java index c96efd597b..cfe7e37d4e 100644 --- a/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/converter/DataConverters.java +++ b/paper-generator/src/main/java/io/papermc/generator/types/craftblockdata/property/holder/converter/DataConverters.java @@ -1,32 +1,25 @@ package io.papermc.generator.types.craftblockdata.property.holder.converter; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Maps; import io.papermc.generator.types.craftblockdata.property.holder.DataHolderType; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.jspecify.annotations.NullMarked; @NullMarked public final class DataConverters { - private static final ImmutableMap CONVERTERS; - private static final ImmutableMap.Builder builder = ImmutableMap.builder(); - - static { - register(new ArrayConverter()); - register(new ListConverter()); - register(new MapConverter()); - CONVERTERS = Maps.immutableEnumMap(builder.build()); - } + private static final Map CONVERTERS = Stream.of( + new ArrayConverter(), + new ListConverter(), + new MapConverter() + ).collect(Collectors.toUnmodifiableMap(DataConverter::getType, key -> key)); public static DataConverter getOrThrow(DataHolderType type) { DataConverter converter = CONVERTERS.get(type); if (converter == null) { - throw new IllegalStateException("Cannot handle " + type); + throw new IllegalStateException("Cannot handle data holder type: " + type); } return converter; } - - private static void register(DataConverter converter) { - builder.put(converter.getType(), converter); - } } diff --git a/paper-generator/src/main/java/io/papermc/generator/types/goal/MobGoalGenerator.java b/paper-generator/src/main/java/io/papermc/generator/types/goal/MobGoalGenerator.java index 9db9e2cbdb..faf71d7b4f 100644 --- a/paper-generator/src/main/java/io/papermc/generator/types/goal/MobGoalGenerator.java +++ b/paper-generator/src/main/java/io/papermc/generator/types/goal/MobGoalGenerator.java @@ -15,9 +15,10 @@ import io.papermc.generator.types.SimpleGenerator; import io.papermc.generator.utils.Annotations; import io.papermc.generator.utils.Formatting; import io.papermc.generator.utils.Javadocs; -import io.papermc.typewriter.utils.ClassHelper; +import io.papermc.typewriter.util.ClassHelper; import java.util.Comparator; import java.util.List; +import java.util.stream.Stream; import net.minecraft.world.entity.ai.goal.Goal; import net.minecraft.world.entity.ai.goal.GoalSelector; import net.minecraft.world.entity.ai.goal.WrappedGoal; @@ -64,17 +65,16 @@ public class MobGoalGenerator extends SimpleGenerator { classes = scanResult.getSubclasses(Goal.class.getName()).loadClasses(Goal.class); } - List> vanillaGoals = classes.stream() + Stream> vanillaGoals = classes.stream() .filter(clazz -> !java.lang.reflect.Modifier.isAbstract(clazz.getModifiers())) .filter(clazz -> !clazz.isAnonymousClass() || ClassHelper.getTopLevelClass(clazz) != GoalSelector.class) .filter(clazz -> !WrappedGoal.class.equals(clazz)) // TODO - properly fix .map(MobGoalNames::getKey) .sorted(Comparator., String>comparing(o -> o.getEntityClass().getSimpleName()) .thenComparing(vanillaGoalKey -> vanillaGoalKey.getNamespacedKey().getKey()) - ) - .toList(); + ); - for (GoalKey goalKey : vanillaGoals) { + vanillaGoals.forEach(goalKey -> { String keyPath = goalKey.getNamespacedKey().getKey(); String fieldName = Formatting.formatKeyAsField(keyPath); @@ -82,7 +82,7 @@ public class MobGoalGenerator extends SimpleGenerator { FieldSpec.Builder fieldBuilder = FieldSpec.builder(typedKey, fieldName, PUBLIC, STATIC, FINAL) .initializer("$N($S, $T.class)", createMethod.build(), keyPath, goalKey.getEntityClass()); typeBuilder.addField(fieldBuilder.build()); - } + }); return typeBuilder.addMethod(createMethod.build()).build(); } diff --git a/paper-generator/src/main/java/io/papermc/generator/types/registry/GeneratedKeyType.java b/paper-generator/src/main/java/io/papermc/generator/types/registry/GeneratedKeyType.java index ffd94a3e4a..c56411ae56 100644 --- a/paper-generator/src/main/java/io/papermc/generator/types/registry/GeneratedKeyType.java +++ b/paper-generator/src/main/java/io/papermc/generator/types/registry/GeneratedKeyType.java @@ -13,12 +13,11 @@ import io.papermc.generator.types.SimpleGenerator; import io.papermc.generator.utils.Annotations; import io.papermc.generator.utils.Formatting; import io.papermc.generator.utils.Javadocs; -import io.papermc.generator.utils.RegistryUtils; -import io.papermc.generator.utils.experimental.FlagHolders; +import io.papermc.generator.utils.experimental.ExperimentalCollector; import io.papermc.generator.utils.experimental.SingleFlagHolder; import io.papermc.paper.registry.RegistryKey; import io.papermc.paper.registry.TypedKey; -import java.util.Set; +import java.util.Map; import java.util.function.Supplier; import javax.lang.model.SourceVersion; import net.kyori.adventure.key.Key; @@ -43,14 +42,14 @@ public class GeneratedKeyType extends SimpleGenerator { private final RegistryEntry entry; private final Registry registry; - private final Supplier>> experimentalKeys; + private final Supplier, SingleFlagHolder>> experimentalKeys; private final boolean isFilteredRegistry; public GeneratedKeyType(String packageName, RegistryEntry entry) { super(entry.keyClassName().concat("Keys"), packageName); this.entry = entry; this.registry = entry.registry(); - this.experimentalKeys = Suppliers.memoize(() -> RegistryUtils.collectExperimentalDataDrivenKeys(this.registry)); + this.experimentalKeys = Suppliers.memoize(() -> ExperimentalCollector.collectDataDrivenElementIds(this.registry)); this.isFilteredRegistry = FeatureElement.FILTERED_REGISTRIES.contains(entry.registryKey()); } @@ -124,7 +123,7 @@ public class GeneratedKeyType extends SimpleGenerator { return builder.addStaticImport(Key.class, "key"); } - public @Nullable SingleFlagHolder getRequiredFeature(Holder.Reference reference) { + protected @Nullable SingleFlagHolder getRequiredFeature(Holder.Reference reference) { if (this.isFilteredRegistry) { // built-in registry FeatureElement element = (FeatureElement) reference.value(); @@ -133,9 +132,7 @@ public class GeneratedKeyType extends SimpleGenerator { } } else { // data-driven registry - if (this.experimentalKeys.get().contains(reference.key())) { - return FlagHolders.NEXT_UPDATE; - } + return this.experimentalKeys.get().get(reference.key()); } return null; } diff --git a/paper-generator/src/main/java/io/papermc/generator/utils/Annotations.java b/paper-generator/src/main/java/io/papermc/generator/utils/Annotations.java index e7488cc4e9..47322695e4 100644 --- a/paper-generator/src/main/java/io/papermc/generator/utils/Annotations.java +++ b/paper-generator/src/main/java/io/papermc/generator/utils/Annotations.java @@ -8,7 +8,6 @@ import net.minecraft.SharedConstants; import org.bukkit.MinecraftExperimental; import org.jetbrains.annotations.ApiStatus; import org.jspecify.annotations.NullMarked; -import org.jspecify.annotations.Nullable; @NullMarked public final class Annotations { @@ -23,24 +22,6 @@ public final class Annotations { ); } - public static AnnotationSpec deprecatedVersioned(@Nullable String version, boolean forRemoval) { - AnnotationSpec.Builder annotationSpec = AnnotationSpec.builder(Deprecated.class); - if (forRemoval) { - annotationSpec.addMember("forRemoval", "$L", true); - } - if (version != null) { - annotationSpec.addMember("since", "$S", version); - } - - return annotationSpec.build(); - } - - public static AnnotationSpec scheduledRemoval(String version) { - return AnnotationSpec.builder(ApiStatus.ScheduledForRemoval.class) - .addMember("inVersion", "$S", version) - .build(); - } - public static AnnotationSpec suppressWarnings(String... values) { AnnotationSpec.Builder builder = AnnotationSpec.builder(SuppressWarnings.class); for (String value : values) { @@ -53,12 +34,11 @@ public final class Annotations { public static final AnnotationSpec EXPERIMENTAL_API_ANNOTATION = AnnotationSpec.builder(ApiStatus.Experimental.class).build(); public static final AnnotationSpec NULL_MARKED = AnnotationSpec.builder(NullMarked.class).build(); public static final AnnotationSpec OVERRIDE = AnnotationSpec.builder(Override.class).build(); - private static final AnnotationSpec SUPPRESS_WARNINGS = suppressWarnings("unused", "SpellCheckingInspection"); public static final AnnotationSpec GENERATED_FROM = AnnotationSpec.builder(GeneratedFrom.class) .addMember("value", "$S", SharedConstants.getCurrentVersion().getName()) .build(); public static final Iterable CLASS_HEADER = List.of( - SUPPRESS_WARNINGS, + suppressWarnings("unused", "SpellCheckingInspection"), NULL_MARKED, GENERATED_FROM ); diff --git a/paper-generator/src/main/java/io/papermc/generator/utils/ClassHelper.java b/paper-generator/src/main/java/io/papermc/generator/utils/ClassHelper.java index a34b1825c6..51e3df843e 100644 --- a/paper-generator/src/main/java/io/papermc/generator/utils/ClassHelper.java +++ b/paper-generator/src/main/java/io/papermc/generator/utils/ClassHelper.java @@ -59,7 +59,7 @@ public final class ClassHelper { return (field.getModifiers() & flags) == flags; } - public static Class classOr(String className, Class defaultClass) { + public static @Nullable Class classOr(String className, @Nullable Class defaultClass) { try { return (Class) Class.forName(className); } catch (ClassNotFoundException ignored) { diff --git a/paper-generator/src/main/java/io/papermc/generator/utils/Formatting.java b/paper-generator/src/main/java/io/papermc/generator/utils/Formatting.java index be38ef0d79..8452f0c405 100644 --- a/paper-generator/src/main/java/io/papermc/generator/utils/Formatting.java +++ b/paper-generator/src/main/java/io/papermc/generator/utils/Formatting.java @@ -4,7 +4,6 @@ import java.util.Optional; import org.apache.commons.lang3.math.NumberUtils; import java.util.Comparator; import java.util.Locale; -import java.util.Optional; import java.util.OptionalInt; import java.util.function.Function; import java.util.regex.Pattern; @@ -12,7 +11,6 @@ import java.util.stream.IntStream; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; -import org.apache.commons.lang3.math.NumberUtils; import org.jspecify.annotations.NullMarked; @NullMarked @@ -75,7 +73,7 @@ public final class Formatting { return newName; } - public static Comparator ALPHABETIC_KEY_ORDER = alphabeticKeyOrder(path -> path); + public static final Comparator ALPHABETIC_KEY_ORDER = alphabeticKeyOrder(path -> path); public static Comparator alphabeticKeyOrder(Function mapper) { return (o1, o2) -> { diff --git a/paper-generator/src/main/java/io/papermc/generator/utils/RegistryUtils.java b/paper-generator/src/main/java/io/papermc/generator/utils/RegistryUtils.java deleted file mode 100644 index 80f4fa37e3..0000000000 --- a/paper-generator/src/main/java/io/papermc/generator/utils/RegistryUtils.java +++ /dev/null @@ -1,46 +0,0 @@ -package io.papermc.generator.utils; - -import com.google.common.collect.Sets; -import io.papermc.generator.utils.experimental.CollectingContext; -import java.util.Collections; -import java.util.IdentityHashMap; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import net.minecraft.core.Registry; -import net.minecraft.core.RegistrySetBuilder; -import net.minecraft.data.registries.VanillaRegistries; -import net.minecraft.data.registries.WinterDropRegistries; -import net.minecraft.resources.ResourceKey; -import org.jspecify.annotations.NullMarked; -import org.jspecify.annotations.Nullable; - -@NullMarked -public class RegistryUtils { - - private static final Map>, RegistrySetBuilder.RegistryBootstrap> VANILLA_REGISTRY_ENTRIES = VanillaRegistries.BUILDER.entries.stream() - .collect(Collectors.toMap(RegistrySetBuilder.RegistryStub::key, RegistrySetBuilder.RegistryStub::bootstrap)); - - private static final Map>, RegistrySetBuilder.RegistryBootstrap> EXPERIMENTAL_REGISTRY_ENTRIES = WinterDropRegistries.BUILDER.entries.stream() - .collect(Collectors.toMap(RegistrySetBuilder.RegistryStub::key, RegistrySetBuilder.RegistryStub::bootstrap)); // Update for Experimental API - - @SuppressWarnings("unchecked") - public static Set> collectExperimentalDataDrivenKeys(Registry registry) { - RegistrySetBuilder.@Nullable RegistryBootstrap experimentalBootstrap = (RegistrySetBuilder.RegistryBootstrap) EXPERIMENTAL_REGISTRY_ENTRIES.get(registry.key()); - if (experimentalBootstrap == null) { - return Collections.emptySet(); - } - Set> experimental = Collections.newSetFromMap(new IdentityHashMap<>()); - CollectingContext experimentalCollector = new CollectingContext<>(experimental, registry); - experimentalBootstrap.run(experimentalCollector); - - RegistrySetBuilder.@Nullable RegistryBootstrap vanillaBootstrap = (RegistrySetBuilder.RegistryBootstrap) VANILLA_REGISTRY_ENTRIES.get(registry.key()); - if (vanillaBootstrap != null) { - Set> vanilla = Collections.newSetFromMap(new IdentityHashMap<>()); - CollectingContext vanillaCollector = new CollectingContext<>(vanilla, registry); - vanillaBootstrap.run(vanillaCollector); - return Sets.difference(experimental, vanilla); - } - return experimental; - } -} diff --git a/paper-generator/src/main/java/io/papermc/generator/utils/experimental/ExperimentalCollector.java b/paper-generator/src/main/java/io/papermc/generator/utils/experimental/ExperimentalCollector.java new file mode 100644 index 0000000000..b8ad105e8c --- /dev/null +++ b/paper-generator/src/main/java/io/papermc/generator/utils/experimental/ExperimentalCollector.java @@ -0,0 +1,134 @@ +package io.papermc.generator.utils.experimental; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.mojang.logging.LogUtils; +import io.papermc.generator.Main; +import io.papermc.generator.utils.Formatting; +import java.util.Collection; +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.stream.Collectors; +import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.RegistrySetBuilder; +import net.minecraft.core.registries.Registries; +import net.minecraft.data.registries.TradeRebalanceRegistries; +import net.minecraft.data.registries.VanillaRegistries; +import net.minecraft.data.registries.WinterDropRegistries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.packs.PackResources; +import net.minecraft.server.packs.PackType; +import net.minecraft.server.packs.repository.BuiltInPackSource; +import net.minecraft.server.packs.resources.MultiPackResourceManager; +import net.minecraft.tags.TagKey; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +import org.slf4j.Logger; + +@NullMarked +public final class ExperimentalCollector { + + private static final Logger LOGGER = LogUtils.getLogger(); + + private static final Map>, RegistrySetBuilder.RegistryBootstrap> VANILLA_REGISTRY_ENTRIES = VanillaRegistries.BUILDER.entries.stream() + .collect(Collectors.toMap(RegistrySetBuilder.RegistryStub::key, RegistrySetBuilder.RegistryStub::bootstrap)); + + private static final Map EXPERIMENTAL_REGISTRY_FLAGS = Map.of( + // Update for Experimental API + WinterDropRegistries.BUILDER, FlagHolders.WINTER_DROP, + TradeRebalanceRegistries.BUILDER, FlagHolders.TRADE_REBALANCE + ); + + private static final Multimap>, Map.Entry>> EXPERIMENTAL_REGISTRY_ENTRIES; + static { + EXPERIMENTAL_REGISTRY_ENTRIES = HashMultimap.create(); + for (Map.Entry entry : EXPERIMENTAL_REGISTRY_FLAGS.entrySet()) { + for (RegistrySetBuilder.RegistryStub stub : entry.getKey().entries) { + EXPERIMENTAL_REGISTRY_ENTRIES.put(stub.key(), Map.entry(entry.getValue(), stub.bootstrap())); + } + } + } + + @SuppressWarnings("unchecked") + public static Map, SingleFlagHolder> collectDataDrivenElementIds(Registry registry) { + Collection>> experimentalEntries = EXPERIMENTAL_REGISTRY_ENTRIES.get(registry.key()); + if (experimentalEntries.isEmpty()) { + return Collections.emptyMap(); + } + + Map, SingleFlagHolder> result = new IdentityHashMap<>(); + for (Map.Entry> experimentalEntry : experimentalEntries) { + RegistrySetBuilder.RegistryBootstrap experimentalBootstrap = (RegistrySetBuilder.RegistryBootstrap) experimentalEntry.getValue(); + Set> experimental = Collections.newSetFromMap(new IdentityHashMap<>()); + CollectingContext experimentalCollector = new CollectingContext<>(experimental, registry); + experimentalBootstrap.run(experimentalCollector); + result.putAll(experimental.stream().collect(Collectors.toMap(key -> key, key -> experimentalEntry.getKey()))); + } + + RegistrySetBuilder.@Nullable RegistryBootstrap vanillaBootstrap = (RegistrySetBuilder.RegistryBootstrap) VANILLA_REGISTRY_ENTRIES.get(registry.key()); + if (vanillaBootstrap != null) { + Set> vanilla = Collections.newSetFromMap(new IdentityHashMap<>()); + CollectingContext vanillaCollector = new CollectingContext<>(vanilla, registry); + vanillaBootstrap.run(vanillaCollector); + result.keySet().removeAll(vanilla); + } + return result; + } + + // collect all the tags by grabbing the json from the data-packs + // another (probably) way is to hook into the data generator like the typed keys generator + public static Map, String> collectTags(MultiPackResourceManager resourceManager) { + Map, String> result = new IdentityHashMap<>(); + + // collect all vanilla tags + Multimap>, String> vanillaTags = HashMultimap.create(); + PackResources vanillaPack = resourceManager.listPacks() + .filter(packResources -> packResources.packId().equals(BuiltInPackSource.VANILLA_ID)) + .findFirst() + .orElseThrow(); + collectTagsFromPack(vanillaPack, (entry, path) -> vanillaTags.put(entry.key(), path)); + + // then distinct with other data-pack tags to know for sure newly created tags and so experimental one + resourceManager.listPacks().forEach(pack -> { + String packId = pack.packId(); + if (packId.equals(BuiltInPackSource.VANILLA_ID)) return; + + collectTagsFromPack(pack, (entry, path) -> { + if (vanillaTags.get(entry.key()).contains(path)) { + return; + } + + result.put(entry.value().listTagIds() + .filter(tagKey -> tagKey.location().getPath().equals(path)) + .findFirst() + .orElseThrow(), packId); + }); + }); + return Collections.unmodifiableMap(result); + } + + private static void collectTagsFromPack(PackResources pack, BiConsumer, String> output) { + Set namespaces = pack.getNamespaces(PackType.SERVER_DATA); + + for (String namespace : namespaces) { + Main.REGISTRY_ACCESS.registries().forEach(entry -> { + // this is probably expensive but can't find another way around and data-pack loader has similar logic + // the issue is that registry key can have parent/key but tag key can also have parent/key so parsing become a mess + // without having at least one of the two values + String tagDir = Registries.tagsDirPath(entry.key()); + pack.listResources(PackType.SERVER_DATA, namespace, tagDir, (id, supplier) -> { + Formatting.formatTagKey(tagDir, id.getPath()).ifPresentOrElse(path -> output.accept(entry, path), () -> { + LOGGER.warn("Unable to parse the path: {}/{}/{}.json in the data-pack {} into a tag key", namespace, tagDir, id.getPath(), pack.packId()); + }); + }); + }); + } + } + + private ExperimentalCollector() { + } +} diff --git a/paper-generator/src/main/java/io/papermc/generator/utils/experimental/FlagHolders.java b/paper-generator/src/main/java/io/papermc/generator/utils/experimental/FlagHolders.java index b890ea8093..2a736de1e0 100644 --- a/paper-generator/src/main/java/io/papermc/generator/utils/experimental/FlagHolders.java +++ b/paper-generator/src/main/java/io/papermc/generator/utils/experimental/FlagHolders.java @@ -8,18 +8,17 @@ import net.minecraft.world.flag.FeatureFlag; import net.minecraft.world.flag.FeatureFlags; import org.bukkit.MinecraftExperimental; import org.jspecify.annotations.NullMarked; -import org.jspecify.annotations.Nullable; @NullMarked public class FlagHolders { - public static final @Nullable SingleFlagHolder NEXT_UPDATE = SingleFlagHolder.fromValue(FeatureFlags.WINTER_DROP)/*SingleFlagHolder.fromValue(FeatureFlags.UPDATE_1_22)*/; + public static final SingleFlagHolder WINTER_DROP = SingleFlagHolder.fromValue(FeatureFlags.WINTER_DROP); public static final SingleFlagHolder TRADE_REBALANCE = SingleFlagHolder.fromValue(FeatureFlags.TRADE_REBALANCE); public static final SingleFlagHolder REDSTONE_EXPERIMENTS = SingleFlagHolder.fromValue(FeatureFlags.REDSTONE_EXPERIMENTS); public static final SingleFlagHolder MINECART_IMPROVEMENTS = SingleFlagHolder.fromValue(FeatureFlags.MINECART_IMPROVEMENTS); static final Map ANNOTATION_EQUIVALENT = Util.make(new HashMap(), map -> { - map.put(NEXT_UPDATE, MinecraftExperimental.Requires.WINTER_DROP); //map.put(NEXT_UPDATE, MinecraftExperimental.Requires.UPDATE_1_22); + map.put(WINTER_DROP, MinecraftExperimental.Requires.WINTER_DROP); map.put(TRADE_REBALANCE, MinecraftExperimental.Requires.TRADE_REBALANCE); map.put(REDSTONE_EXPERIMENTS, MinecraftExperimental.Requires.REDSTONE_EXPERIMENTS); map.put(MINECART_IMPROVEMENTS, MinecraftExperimental.Requires.MINECART_IMPROVEMENTS); diff --git a/paper-generator/src/main/java/io/papermc/generator/utils/experimental/SingleFlagHolder.java b/paper-generator/src/main/java/io/papermc/generator/utils/experimental/SingleFlagHolder.java index e8e267225b..d97a4a5926 100644 --- a/paper-generator/src/main/java/io/papermc/generator/utils/experimental/SingleFlagHolder.java +++ b/paper-generator/src/main/java/io/papermc/generator/utils/experimental/SingleFlagHolder.java @@ -42,7 +42,7 @@ public record SingleFlagHolder(FeatureFlag flag) implements FlagHolder { // todo public MinecraftExperimental.Requires asAnnotationMember() { MinecraftExperimental.Requires annotationMember = FlagHolders.ANNOTATION_EQUIVALENT.get(this.flag); if (annotationMember == null) { - throw new UnsupportedOperationException("Don't know that feature flag : " + FEATURE_FLAG_NAME.get(this.flag)); + throw new UnsupportedOperationException("Don't know that feature flag: " + FEATURE_FLAG_NAME.get(this.flag)); } return annotationMember; } diff --git a/paper-generator/src/main/java/io/papermc/generator/utils/experimental/TagCollector.java b/paper-generator/src/main/java/io/papermc/generator/utils/experimental/TagCollector.java deleted file mode 100644 index 3d2e2f0110..0000000000 --- a/paper-generator/src/main/java/io/papermc/generator/utils/experimental/TagCollector.java +++ /dev/null @@ -1,82 +0,0 @@ -package io.papermc.generator.utils.experimental; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import com.mojang.logging.LogUtils; -import io.papermc.generator.Main; -import io.papermc.generator.utils.Formatting; -import java.util.Collections; -import java.util.IdentityHashMap; -import java.util.Map; -import java.util.Set; -import java.util.function.BiConsumer; -import net.minecraft.core.Registry; -import net.minecraft.core.RegistryAccess; -import net.minecraft.core.registries.Registries; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.packs.PackResources; -import net.minecraft.server.packs.PackType; -import net.minecraft.server.packs.repository.BuiltInPackSource; -import net.minecraft.server.packs.resources.MultiPackResourceManager; -import net.minecraft.tags.TagKey; -import org.jspecify.annotations.NullMarked; -import org.slf4j.Logger; - -// collect all the tags by grabbing the json from the data-packs -// another (probably) way is to hook into the data generator like the typed keys generator -@NullMarked -public final class TagCollector { - - private static final Logger LOGGER = LogUtils.getLogger(); - - public static Map, String> grabExperimental(MultiPackResourceManager resourceManager) { - Map, String> result = new IdentityHashMap<>(); - - // collect all vanilla tags - Multimap>, String> vanillaTags = HashMultimap.create(); - PackResources vanillaPack = resourceManager.listPacks() - .filter(packResources -> packResources.packId().equals(BuiltInPackSource.VANILLA_ID)) - .findFirst() - .orElseThrow(); - collectFromPack(vanillaPack, (entry, path) -> vanillaTags.put(entry.key(), path)); - - // then distinct with other data-pack tags to know for sure newly created tags and so experimental one - resourceManager.listPacks().forEach(pack -> { - String packId = pack.packId(); - if (packId.equals(BuiltInPackSource.VANILLA_ID)) return; - - collectFromPack(pack, (entry, path) -> { - if (vanillaTags.get(entry.key()).contains(path)) { - return; - } - - result.put(entry.value().listTagIds() - .filter(tagKey -> tagKey.location().getPath().equals(path)) - .findFirst() - .orElseThrow(), packId); - }); - }); - return Collections.unmodifiableMap(result); - } - - private static void collectFromPack(PackResources pack, BiConsumer, String> output) { - Set namespaces = pack.getNamespaces(PackType.SERVER_DATA); - - for (String namespace : namespaces) { - Main.REGISTRY_ACCESS.registries().forEach(entry -> { - // this is probably expensive but can't find another way around and data-pack loader has similar logic - // the issue is that registry key can have parent/key (and custom folder too) but tag key can also have parent/key so parsing become a mess - // without having at least one of the two values - String tagDir = Registries.tagsDirPath(entry.key()); - pack.listResources(PackType.SERVER_DATA, namespace, tagDir, (id, supplier) -> { - Formatting.formatTagKey(tagDir, id.getPath()).ifPresentOrElse(path -> output.accept(entry, path), () -> { - LOGGER.warn("Unable to parse the path: {}/{}/{}.json in the data-pack {} into a tag key", namespace, tagDir, id.getPath(), pack.packId()); - }); - }); - }); - } - } - - private TagCollector() { - } -} diff --git a/paper-generator/src/test/java/io/papermc/generator/BlockStatePropertyTest.java b/paper-generator/src/test/java/io/papermc/generator/BlockStatePropertyTest.java index ee4d64893d..39d2bb95f7 100644 --- a/paper-generator/src/test/java/io/papermc/generator/BlockStatePropertyTest.java +++ b/paper-generator/src/test/java/io/papermc/generator/BlockStatePropertyTest.java @@ -1,23 +1,26 @@ package io.papermc.generator; import io.papermc.generator.utils.BlockStateMapping; +import java.lang.invoke.MethodHandles; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Collections; import java.util.HashSet; import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; import java.util.Set; import net.minecraft.SharedConstants; import net.minecraft.server.Bootstrap; import net.minecraft.world.level.block.ChiseledBookShelfBlock; +import net.minecraft.world.level.block.MossyCarpetBlock; import net.minecraft.world.level.block.PipeBlock; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.EnumProperty; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.fail; - public class BlockStatePropertyTest { private static Set>> ENUM_PROPERTY_VALUES; @@ -49,24 +52,24 @@ public class BlockStatePropertyTest { } } - { - // reference test - // if renamed should change DataPropertyWriter#FIELD_TO_BASE_NAME - var a = ChiseledBookShelfBlock.SLOT_OCCUPIED_PROPERTIES; - var b = PipeBlock.PROPERTY_BY_DIRECTION; + @Test + public void testReferences() throws NoSuchFieldException, IllegalAccessException { + // if renamed should change DataPropertyWriter#FIELD_TO_BASE_NAME/FIELD_TO_BASE_NAME_SPECIFICS + MethodHandles.Lookup lookup = MethodHandles.lookup(); + lookup.findStaticVarHandle(ChiseledBookShelfBlock.class, "SLOT_OCCUPIED_PROPERTIES", List.class); + lookup.findStaticVarHandle(PipeBlock.class, "PROPERTY_BY_DIRECTION", Map.class); + MethodHandles.privateLookupIn(MossyCarpetBlock.class, lookup).findStaticVarHandle(MossyCarpetBlock.class, "PROPERTY_BY_DIRECTION", Map.class); } @Test public void testBridge() { - Set missingApisEquivalent = new HashSet<>(); + Set missingApiEquivalents = new HashSet<>(); for (Class> value : ENUM_PROPERTY_VALUES) { if (!BlockStateMapping.ENUM_BRIDGE.containsKey(value)) { - missingApisEquivalent.add(value.getCanonicalName()); + missingApiEquivalents.add(value.getCanonicalName()); } } - if (!missingApisEquivalent.isEmpty()) { - fail("Missing some api equivalent in the blockstate mapping enum bridge (BlockStateMapping#ENUM_BRIDGE) : " + String.join(", ", missingApisEquivalent)); - } + Assertions.assertTrue(missingApiEquivalents.isEmpty(), () -> "Missing some api equivalent in the block state mapping enum bridge (BlockStateMapping#ENUM_BRIDGE) : " + String.join(", ", missingApiEquivalents)); } } diff --git a/paper-generator/src/test/java/io/papermc/generator/MobGoalConverterTest.java b/paper-generator/src/test/java/io/papermc/generator/MobGoalConverterTest.java index 487bc9ec62..56052d6b58 100644 --- a/paper-generator/src/test/java/io/papermc/generator/MobGoalConverterTest.java +++ b/paper-generator/src/test/java/io/papermc/generator/MobGoalConverterTest.java @@ -10,14 +10,14 @@ import net.minecraft.world.entity.Mob; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; public class MobGoalConverterTest { @Test public void testBukkitMap() { final List> classes; - try (ScanResult scanResult = new ClassGraph().enableAllInfo().whitelistPackages(Entity.class.getPackageName()).scan()) { + try (ScanResult scanResult = new ClassGraph().enableClassInfo().whitelistPackages(Entity.class.getPackageName()).scan()) { classes = scanResult.getSubclasses(Mob.class.getName()).loadClasses(Mob.class); } @@ -30,8 +30,6 @@ public class MobGoalConverterTest { } } - if (!missingClasses.isEmpty()) { - fail("Missing some entity classes in the bukkit map: " + String.join(", ", missingClasses)); - } + assertTrue(missingClasses.isEmpty(), () -> "Missing some entity classes in the bukkit map: " + String.join(", ", missingClasses)); } } diff --git a/patches/server/0350-Implement-Mob-Goal-API.patch b/patches/server/0350-Implement-Mob-Goal-API.patch index c805728a75..faed913389 100644 --- a/patches/server/0350-Implement-Mob-Goal-API.patch +++ b/patches/server/0350-Implement-Mob-Goal-API.patch @@ -648,7 +648,7 @@ index a8d6d7054110b5d95830296699f004418dae10db..acc25b08ed3b9f978229fa017d23f9fa LOOK, JUMP, diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 6b042419af11730b0159c030ea1881dcfbb37dcd..8339da59b7a73411f45b77f6eb93e8ad65a1ef48 100644 +index 89a37c31c0376d66251fee36df4a78dac05c2031..b91dc9532380788f7b6b7a50a53625e1cb3889d2 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -2956,5 +2956,11 @@ public final class CraftServer implements Server { @@ -663,46 +663,3 @@ index 6b042419af11730b0159c030ea1881dcfbb37dcd..8339da59b7a73411f45b77f6eb93e8ad + } // Paper end } -diff --git a/src/test/java/io/papermc/paper/entity/ai/MobGoalConverterTest.java b/src/test/java/io/papermc/paper/entity/ai/MobGoalConverterTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b020f795846d98f5464b390008be8815e892f9e8 ---- /dev/null -+++ b/src/test/java/io/papermc/paper/entity/ai/MobGoalConverterTest.java -@@ -0,0 +1,37 @@ -+package io.papermc.paper.entity.ai; -+ -+import com.destroystokyo.paper.entity.ai.MobGoalHelper; -+import io.github.classgraph.ClassGraph; -+import io.github.classgraph.ScanResult; -+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() { -+ 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) { -+ Class bukkitClass = MobGoalHelper.toBukkitClass(nmsClass); -+ if (bukkitClass == null) { -+ missingClasses.add(nmsClass.getCanonicalName()); -+ } -+ } -+ -+ if (!missingClasses.isEmpty()) { -+ fail("Missing some entity classes in the bukkit map (MobGoalHelper): " + String.join(", ", missingClasses)); -+ } -+ } -+}