mirror of
https://github.com/PaperMC/Paper.git
synced 2025-05-19 05:30:23 -07:00
generalize data file handling
This commit is contained in:
parent
5fa30c43da
commit
c6e3d1b0b5
@ -16,7 +16,7 @@ dependencies {
|
||||
implementation("com.squareup:javapoet:1.13.0")
|
||||
implementation("io.papermc.typewriter:typewriter:1.0.1")
|
||||
implementation("info.picocli:picocli:4.7.6")
|
||||
implementation("io.github.classgraph:classgraph:4.8.47")
|
||||
implementation("io.github.classgraph:classgraph:4.8.179")
|
||||
implementation("org.jetbrains:annotations:26.0.2")
|
||||
implementation("org.jspecify:jspecify:1.0.0")
|
||||
|
||||
@ -185,6 +185,9 @@ abstract class GenerationArgumentProvider : CommandLineArgumentProvider {
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
tasks.compileTestJava {
|
||||
options.compilerArgs.add("-parameters")
|
||||
}
|
||||
|
||||
group = "io.papermc.paper"
|
||||
version = "1.0-SNAPSHOT"
|
||||
|
@ -2,6 +2,7 @@ package io.papermc.generator;
|
||||
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import io.papermc.generator.resources.DataFileLoader;
|
||||
import io.papermc.generator.rewriter.registration.PaperPatternSourceSetRewriter;
|
||||
import io.papermc.generator.rewriter.registration.PatternSourceSetRewriter;
|
||||
import io.papermc.generator.types.SourceGenerator;
|
||||
@ -107,8 +108,9 @@ public class Main implements Callable<Integer> {
|
||||
public Integer call() {
|
||||
bootStrap(this.tagBootstrap).join();
|
||||
|
||||
try {
|
||||
ROOT_DIR = this.rootDir;
|
||||
DataFileLoader.init();
|
||||
try {
|
||||
if (this.isRewrite) {
|
||||
rewrite(this.sourceSet, Rewriters.VALUES.get(this.side));
|
||||
} else {
|
||||
|
@ -3,6 +3,7 @@ package io.papermc.generator;
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import io.papermc.generator.registry.RegistryBootstrapper;
|
||||
import io.papermc.generator.registry.RegistryEntries;
|
||||
import io.papermc.generator.resources.DataFileLoader;
|
||||
import io.papermc.generator.rewriter.registration.PatternSourceSetRewriter;
|
||||
import io.papermc.generator.rewriter.types.Types;
|
||||
import io.papermc.generator.rewriter.types.registry.EnumRegistryRewriter;
|
||||
@ -25,7 +26,6 @@ import io.papermc.generator.rewriter.types.simple.MemoryKeyRewriter;
|
||||
import io.papermc.generator.rewriter.types.simple.StatisticRewriter;
|
||||
import io.papermc.generator.rewriter.types.simple.trial.PoseRewriter;
|
||||
import io.papermc.generator.rewriter.types.simple.trial.VillagerProfessionRewriter;
|
||||
import io.papermc.generator.types.goal.MobGoalNames;
|
||||
import io.papermc.generator.rewriter.types.registry.RegistriesArgumentProviderRewriter;
|
||||
import io.papermc.generator.utils.Formatting;
|
||||
import io.papermc.typewriter.preset.EnumCloneRewriter;
|
||||
@ -189,7 +189,7 @@ public final class Rewriters {
|
||||
.register("MobGoalHelper#bukkitMap", Types.MOB_GOAL_HELPER, new SearchReplaceRewriter() {
|
||||
@Override
|
||||
protected void insert(SearchMetadata metadata, StringBuilder builder) {
|
||||
for (Map.Entry<Class<? extends Mob>, ClassName> entry : MobGoalNames.ENTITY_CLASS_NAMES.entrySet()) {
|
||||
for (Map.Entry<Class<? extends Mob>, ClassName> entry : DataFileLoader.ENTITY_CLASS_NAMES.get().entrySet()) {
|
||||
builder.append(metadata.indent()).append("bukkitMap.put(%s.class, %s.class);".formatted(
|
||||
entry.getKey().getCanonicalName(), this.importCollector.getShortName(Types.typed(entry.getValue()))
|
||||
));
|
||||
|
@ -1,16 +1,15 @@
|
||||
package io.papermc.generator.registry;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.MultimapBuilder;
|
||||
import io.papermc.generator.resources.DataFileLoader;
|
||||
import io.papermc.generator.resources.RegistryData;
|
||||
import io.papermc.generator.utils.ClassHelper;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
@ -19,13 +18,12 @@ import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import io.papermc.generator.utils.SourceCodecs;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.world.damagesource.DamageTypes;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
@ -63,11 +61,11 @@ import org.jspecify.annotations.NullMarked;
|
||||
@NullMarked
|
||||
public final class RegistryEntries {
|
||||
|
||||
private static <T> RegistryEntry.Builder<T> entry(ResourceKey<? extends Registry<T>> registryKey, Class<?> holderElementsClass) {
|
||||
return new RegistryEntry.Builder<>(registryKey, holderElementsClass);
|
||||
private static <T> RegistryIntern<T> entry(ResourceKey<? extends Registry<T>> registryKey, Class<?> holderElementsClass) {
|
||||
return new RegistryIntern<>(registryKey, holderElementsClass);
|
||||
}
|
||||
|
||||
private static final Map<ResourceKey<? extends Registry<?>>, RegistryKeyField<?>> REGISTRY_KEY_FIELDS;
|
||||
public static final Map<ResourceKey<? extends Registry<?>>, RegistryKeyField<?>> REGISTRY_KEY_FIELDS;
|
||||
static {
|
||||
Map<ResourceKey<? extends Registry<?>>, RegistryKeyField<?>> registryKeyFields = new IdentityHashMap<>();
|
||||
try {
|
||||
@ -89,7 +87,7 @@ public final class RegistryEntries {
|
||||
REGISTRY_KEY_FIELDS = Collections.unmodifiableMap(registryKeyFields);
|
||||
}
|
||||
|
||||
private static final Map<ResourceKey<? extends Registry<?>>, RegistryEntry.Builder<?>> EXPOSED_REGISTRIES = Stream.of(
|
||||
private static final Map<ResourceKey<? extends Registry<?>>, RegistryIntern<?>> EXPOSED_REGISTRIES = Stream.of(
|
||||
entry(Registries.GAME_EVENT, GameEvent.class),
|
||||
entry(Registries.STRUCTURE_TYPE, StructureType.class),
|
||||
entry(Registries.MOB_EFFECT, MobEffects.class),
|
||||
@ -124,10 +122,8 @@ public final class RegistryEntries {
|
||||
entry(Registries.PARTICLE_TYPE, ParticleTypes.class),
|
||||
entry(Registries.POTION, Potions.class),
|
||||
entry(Registries.MEMORY_MODULE_TYPE, MemoryModuleType.class)
|
||||
).collect(Collectors.toMap(RegistryEntry.Builder::getRegistryKey, entry -> entry));
|
||||
).collect(Collectors.toMap(RegistryIntern::getRegistryKey, entry -> entry));
|
||||
|
||||
public static final List<RegistryEntry<?>> BUILT_IN = new ArrayList<>();
|
||||
public static final List<RegistryEntry<?>> DATA_DRIVEN = new ArrayList<>();
|
||||
@Deprecated
|
||||
public static final List<RegistryEntry<?>> API_ONLY = new ArrayList<>();
|
||||
|
||||
@ -136,45 +132,39 @@ public final class RegistryEntries {
|
||||
Registries.ENTITY_TYPE, Registries.PARTICLE_TYPE, Registries.POTION, Registries.MEMORY_MODULE_TYPE
|
||||
);
|
||||
|
||||
static {
|
||||
public static final Multimap<RegistryEntry.Type, RegistryEntry<?>> REGISTRIES = Util.make(MultimapBuilder.enumKeys(RegistryEntry.Type.class).arrayListValues().build(), map -> {
|
||||
List<ResourceKey<? extends Registry<?>>> remainingRegistries = new ArrayList<>(EXPOSED_REGISTRIES.keySet());
|
||||
for (RegistryEntry.Type type : RegistryEntry.Type.values()) {
|
||||
try (Reader input = new BufferedReader(new InputStreamReader(RegistryEntries.class.getClassLoader().getResourceAsStream("data/registry/%s.json".formatted(type.getSerializedName()))))) {
|
||||
JsonObject registries = SourceCodecs.GSON.fromJson(input, JsonObject.class);
|
||||
for (String rawRegistryKey : registries.keySet()) {
|
||||
ResourceKey<? extends Registry<?>> registryKey = ResourceKey.createRegistryKey(ResourceLocation.parse(rawRegistryKey));
|
||||
RegistryData data = type.getDataCodec().parse(JsonOps.INSTANCE, registries.get(rawRegistryKey)).getOrThrow();
|
||||
RegistryEntry<?> entry = EXPOSED_REGISTRIES.get(registryKey)
|
||||
.type(type)
|
||||
.registryKeyField((RegistryKeyField) REGISTRY_KEY_FIELDS.get(registryKey))
|
||||
.data(data)
|
||||
.build();
|
||||
entry.validate();
|
||||
DataFileLoader.REGISTRIES.forEach((type, file) -> {
|
||||
Map<ResourceKey<? extends Registry<?>>, RegistryData> registries = file.get();
|
||||
for (Map.Entry<ResourceKey<? extends Registry<?>>, RegistryData> registry : registries.entrySet()) {
|
||||
ResourceKey<? extends Registry<?>> registryKey = registry.getKey();
|
||||
RegistryEntry<?> entry = EXPOSED_REGISTRIES.get(registryKey).bind(registry.getValue());
|
||||
entry.validate(type);
|
||||
if (remainingRegistries.remove(registryKey)) {
|
||||
if (API_ONLY_KEYS.contains(registryKey)) {
|
||||
API_ONLY.add(entry);
|
||||
} else {
|
||||
type.getEntries().add(entry);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("Duplicate registry found in data files: " + registryKey);
|
||||
map.put(type, entry);
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!remainingRegistries.isEmpty()) {
|
||||
throw new IllegalStateException("Registry not found in data files: " + remainingRegistries);
|
||||
}
|
||||
});
|
||||
|
||||
public static Collection<RegistryEntry<?>> byType(RegistryEntry.Type type) {
|
||||
return REGISTRIES.get(type);
|
||||
}
|
||||
|
||||
public static final Map<ResourceKey<? extends Registry<?>>, RegistryEntry<?>> BY_REGISTRY_KEY;
|
||||
static {
|
||||
Map<ResourceKey<? extends Registry<?>>, RegistryEntry<?>> byRegistryKey = new IdentityHashMap<>(BUILT_IN.size() + DATA_DRIVEN.size() + API_ONLY.size());
|
||||
Map<ResourceKey<? extends Registry<?>>, RegistryEntry<?>> byRegistryKey = new IdentityHashMap<>(REGISTRIES.size() + API_ONLY.size());
|
||||
forEach(entry -> {
|
||||
byRegistryKey.put(entry.getRegistryKey(), entry);
|
||||
}, RegistryEntries.BUILT_IN, RegistryEntries.DATA_DRIVEN, RegistryEntries.API_ONLY);
|
||||
}, REGISTRIES.values(), API_ONLY);
|
||||
BY_REGISTRY_KEY = Collections.unmodifiableMap(byRegistryKey);
|
||||
}
|
||||
|
||||
@ -185,12 +175,12 @@ public final class RegistryEntries {
|
||||
|
||||
// real registries
|
||||
public static void forEach(Consumer<RegistryEntry<?>> callback) {
|
||||
forEach(callback, RegistryEntries.BUILT_IN, RegistryEntries.DATA_DRIVEN);
|
||||
forEach(callback, REGISTRIES.values());
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static void forEach(Consumer<RegistryEntry<?>> callback, List<RegistryEntry<?>>... datas) {
|
||||
for (List<RegistryEntry<?>> data : datas) {
|
||||
public static void forEach(Consumer<RegistryEntry<?>> callback, Collection<RegistryEntry<?>>... datas) {
|
||||
for (Collection<RegistryEntry<?>> data : datas) {
|
||||
for (RegistryEntry<?> entry : data) {
|
||||
callback.accept(entry);
|
||||
}
|
||||
|
@ -1,16 +1,14 @@
|
||||
package io.papermc.generator.registry;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.DataResult;
|
||||
import io.papermc.generator.Main;
|
||||
import io.papermc.generator.resources.RegistryData;
|
||||
import io.papermc.generator.utils.ClassHelper;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.util.Collections;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import net.minecraft.core.Holder;
|
||||
@ -18,68 +16,23 @@ import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.util.StringRepresentable;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@NullMarked
|
||||
public final class RegistryEntry<T> implements RegistryIdentifiable<T> {
|
||||
|
||||
public static class Builder<T> implements RegistryIdentifiable<T> {
|
||||
|
||||
private final ResourceKey<? extends Registry<T>> registryKey;
|
||||
private final Class<?> holderElementsClass;
|
||||
|
||||
private @MonotonicNonNull RegistryKeyField<T> registryKeyField;
|
||||
private @MonotonicNonNull Type type;
|
||||
private @MonotonicNonNull RegistryData data;
|
||||
|
||||
protected Builder(ResourceKey<? extends Registry<T>> registryKey, Class<?> holderElementsClass) {
|
||||
this.registryKey = registryKey;
|
||||
this.holderElementsClass = holderElementsClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceKey<? extends Registry<T>> getRegistryKey() {
|
||||
return registryKey;
|
||||
}
|
||||
|
||||
public Builder<T> registryKeyField(RegistryKeyField<T> registryKeyField) {
|
||||
this.registryKeyField = registryKeyField;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<T> type(Type type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<T> data(RegistryData data) {
|
||||
this.data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RegistryEntry<T> build() {
|
||||
Preconditions.checkState(this.type != null && this.data != null && this.registryKeyField != null, "Type, data and registry key field cannot be nulls");
|
||||
return new RegistryEntry<>(this.registryKey, this.registryKeyField, this.holderElementsClass, this.type, this.data);
|
||||
}
|
||||
}
|
||||
public class RegistryEntry<T> implements RegistryIdentifiable<T> {
|
||||
|
||||
private final ResourceKey<? extends Registry<T>> registryKey;
|
||||
private final RegistryKeyField<T> registryKeyField;
|
||||
private final Class<T> elementClass;
|
||||
private final Class<?> holderElementsClass;
|
||||
private final Type type;
|
||||
private final RegistryData data;
|
||||
|
||||
private @Nullable Map<ResourceKey<T>, String> fieldNames;
|
||||
|
||||
private RegistryEntry(ResourceKey<? extends Registry<T>> registryKey, RegistryKeyField<T> registryKeyField, Class<?> holderElementsClass, Type type, RegistryData data) {
|
||||
protected RegistryEntry(ResourceKey<? extends Registry<T>> registryKey, RegistryKeyField<T> registryKeyField, Class<?> holderElementsClass, RegistryData data) {
|
||||
this.registryKey = registryKey;
|
||||
this.registryKeyField = registryKeyField;
|
||||
this.elementClass = registryKeyField.elementClass();
|
||||
this.holderElementsClass = holderElementsClass;
|
||||
this.type = type;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@ -93,7 +46,7 @@ public final class RegistryEntry<T> implements RegistryIdentifiable<T> {
|
||||
}
|
||||
|
||||
public Class<T> elementClass() {
|
||||
return this.elementClass;
|
||||
return this.registryKeyField.elementClass();
|
||||
}
|
||||
|
||||
public String registryKeyField() {
|
||||
@ -104,11 +57,13 @@ public final class RegistryEntry<T> implements RegistryIdentifiable<T> {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
public void validate() {
|
||||
boolean isBuiltIn = this.type == Type.BUILT_IN;
|
||||
Type realType = this.type == Type.BUILT_IN ? Type.DATA_DRIVEN : Type.BUILT_IN;
|
||||
protected void validate(Type type) {
|
||||
Preconditions.checkState(type != Type.BUILT_IN || !this.data.impl().delayed(), "Built-in registry '%s' cannot be delayed!", this.registryKey.location());
|
||||
|
||||
boolean isBuiltIn = type == Type.BUILT_IN;
|
||||
Type realType = type == Type.BUILT_IN ? Type.DATA_DRIVEN : Type.BUILT_IN;
|
||||
Preconditions.checkState(isBuiltIn == BuiltInRegistries.REGISTRY.containsKey(this.registryKey.location()), // type is checked at runtime and not guessed in case api/impl change is needed
|
||||
"Mismatch type, registry %s is %s but was in registry/%s.json".formatted(this.registryKey.location(), realType.getSerializedName(), this.type.getSerializedName())
|
||||
"Mismatch type, registry '%s' is %s but was in registry/%s.json".formatted(this.registryKey.location(), realType.getSerializedName(), type.getSerializedName())
|
||||
);
|
||||
}
|
||||
|
||||
@ -117,28 +72,29 @@ public final class RegistryEntry<T> implements RegistryIdentifiable<T> {
|
||||
return this.data.api().klass().simpleName();
|
||||
}
|
||||
|
||||
return this.elementClass.getSimpleName();
|
||||
return this.elementClass().getSimpleName();
|
||||
}
|
||||
|
||||
public boolean allowCustomKeys() {
|
||||
return this.data.builder().isPresent() || RegistryEntries.DATA_DRIVEN.contains(this);
|
||||
return this.data.builder().isPresent() || RegistryEntries.byType(Type.DATA_DRIVEN).contains(this);
|
||||
}
|
||||
|
||||
private <TO> Map<ResourceKey<T>, TO> getFields(Map<ResourceKey<T>, TO> map, Function<Field, @Nullable TO> transform) {
|
||||
Registry<T> registry = this.registry();
|
||||
Class<T> elementClass = this.elementClass();
|
||||
try {
|
||||
for (Field field : this.holderElementsClass.getDeclaredFields()) {
|
||||
if (!ResourceKey.class.isAssignableFrom(field.getType()) && !Holder.Reference.class.isAssignableFrom(field.getType()) && !this.elementClass.isAssignableFrom(field.getType())) {
|
||||
if (!ResourceKey.class.isAssignableFrom(field.getType()) && !Holder.Reference.class.isAssignableFrom(field.getType()) && !elementClass.isAssignableFrom(field.getType())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ClassHelper.isStaticConstant(field, Modifier.PUBLIC)) {
|
||||
ResourceKey<T> key = null;
|
||||
if (this.elementClass.isAssignableFrom(field.getType())) {
|
||||
key = registry.getResourceKey(this.elementClass.cast(field.get(null))).orElseThrow();
|
||||
if (elementClass.isAssignableFrom(field.getType())) {
|
||||
key = registry.getResourceKey(elementClass.cast(field.get(null))).orElseThrow();
|
||||
} else {
|
||||
if (field.getGenericType() instanceof ParameterizedType complexType && complexType.getActualTypeArguments().length == 1 &&
|
||||
complexType.getActualTypeArguments()[0] == this.elementClass) {
|
||||
complexType.getActualTypeArguments()[0] == elementClass) {
|
||||
|
||||
if (Holder.Reference.class.isAssignableFrom(field.getType())) {
|
||||
key = ((Holder.Reference<T>) field.get(null)).key();
|
||||
@ -183,31 +139,12 @@ public final class RegistryEntry<T> implements RegistryIdentifiable<T> {
|
||||
|
||||
public enum Type implements StringRepresentable {
|
||||
|
||||
DATA_DRIVEN("data_driven", RegistryEntries.DATA_DRIVEN),
|
||||
BUILT_IN("built_in", RegistryEntries.BUILT_IN, RegistryData.UNSAFE_CODEC.validate(data -> {
|
||||
return data.impl().delayed() ? DataResult.error(() -> "Built-in registry cannot be delayed!") : DataResult.success(data);
|
||||
}));
|
||||
BUILT_IN("built_in"),
|
||||
DATA_DRIVEN("data_driven");
|
||||
|
||||
private final String name;
|
||||
private final List<RegistryEntry<?>> entries;
|
||||
private final Codec<RegistryData> dataCodec;
|
||||
|
||||
Type(String name, List<RegistryEntry<?>> entries) {
|
||||
this(name, entries, RegistryData.UNSAFE_CODEC);
|
||||
}
|
||||
|
||||
Type(String name, List<RegistryEntry<?>> entries, Codec<RegistryData> dataCodec) {
|
||||
Type(String name) {
|
||||
this.name = name;
|
||||
this.entries = entries;
|
||||
this.dataCodec = dataCodec;
|
||||
}
|
||||
|
||||
public List<RegistryEntry<?>> getEntries() {
|
||||
return this.entries;
|
||||
}
|
||||
|
||||
public Codec<RegistryData> getDataCodec() {
|
||||
return this.dataCodec;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2,7 +2,9 @@ package io.papermc.generator.registry;
|
||||
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@NullMarked
|
||||
public interface RegistryIdentifiable<T> {
|
||||
|
||||
ResourceKey<? extends Registry<T>> getRegistryKey();
|
||||
|
@ -0,0 +1,22 @@
|
||||
package io.papermc.generator.registry;
|
||||
|
||||
import io.papermc.generator.resources.RegistryData;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@NullMarked
|
||||
public record RegistryIntern<T>(ResourceKey<? extends Registry<T>> registryKey, RegistryKeyField<T> registryKeyField, Class<?> holderElementsClass) implements RegistryIdentifiable<T> {
|
||||
public RegistryIntern(ResourceKey<? extends Registry<T>> registryKey, Class<?> holderElementsClass) {
|
||||
this(registryKey, (RegistryKeyField<T>) RegistryEntries.REGISTRY_KEY_FIELDS.get(registryKey), holderElementsClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceKey<? extends Registry<T>> getRegistryKey() {
|
||||
return this.registryKey;
|
||||
}
|
||||
|
||||
public RegistryEntry<?> bind(RegistryData data) {
|
||||
return new RegistryEntry<>(this.registryKey, this.registryKeyField, this.holderElementsClass, data);
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
package io.papermc.generator.resources;
|
||||
|
||||
import com.google.gson.FormattingStyle;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.DynamicOps;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import io.papermc.generator.Main;
|
||||
import io.papermc.generator.types.SimpleGenerator;
|
||||
import net.minecraft.resources.RegistryOps;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.jetbrains.annotations.VisibleForTesting;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
@NullMarked
|
||||
public abstract class DataFile<V, A, R> {
|
||||
|
||||
public static final Gson GSON = new GsonBuilder().setFormattingStyle(FormattingStyle.PRETTY.withIndent(SimpleGenerator.INDENT_UNIT)).create();
|
||||
|
||||
private final String path;
|
||||
private final Codec<V> codec;
|
||||
private final Transmuter<V, A, R> transmuter;
|
||||
private final boolean requireRegistry;
|
||||
private @MonotonicNonNull V cached;
|
||||
|
||||
protected DataFile(String path, Codec<V> codec, Transmuter<V, A, R> transmuter, boolean requireRegistry) {
|
||||
this.path = path;
|
||||
this.codec = codec;
|
||||
this.transmuter = transmuter;
|
||||
this.requireRegistry = requireRegistry;
|
||||
}
|
||||
|
||||
protected DataFile(String path, Codec<V> codec, Transmuter<V, A, R> transmuter) {
|
||||
this(path, codec, transmuter, false);
|
||||
}
|
||||
|
||||
public static class Map<K, V> extends DataFile<java.util.Map<K, V>, java.util.Map.Entry<K, V>, K> {
|
||||
public Map(String path, Codec<java.util.Map<K, V>> codec, Transmuter<java.util.Map<K, V>, java.util.Map.Entry<K, V>, K> transmuter, boolean requireRegistry) {
|
||||
super(path, codec, transmuter, requireRegistry);
|
||||
}
|
||||
|
||||
public Map(String path, Codec<java.util.Map<K, V>> codec, Transmuter<java.util.Map<K, V>, java.util.Map.Entry<K, V>, K> transmuter) {
|
||||
super(path, codec, transmuter);
|
||||
}
|
||||
}
|
||||
|
||||
public static class List<E> extends DataFile<java.util.List<E>, E, E> {
|
||||
public List(String path, Codec<java.util.List<E>> codec, Transmuter<java.util.List<E>, E, E> transmuter, boolean requireRegistry) {
|
||||
super(path, codec, transmuter, requireRegistry);
|
||||
}
|
||||
|
||||
public List(String path, Codec<java.util.List<E>> codec, Transmuter<java.util.List<E>, E, E> transmuter) {
|
||||
super(path, codec, transmuter);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMutable() {
|
||||
return this.transmuter instanceof Transmuter.Mutable<V, A, R>;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public Transmuter<V, A, R> transmuter() {
|
||||
return this.transmuter;
|
||||
}
|
||||
|
||||
public V get() {
|
||||
if (this.cached == null) {
|
||||
this.cached = this.readUnchecked();
|
||||
}
|
||||
return this.cached;
|
||||
}
|
||||
|
||||
public V readUnchecked() {
|
||||
try {
|
||||
return this.read();
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public V read() throws IOException {
|
||||
try (Reader input = new BufferedReader(new InputStreamReader(DataFile.class.getClassLoader().getResourceAsStream(this.path)))) {
|
||||
JsonElement predicates = GSON.fromJson(input, JsonElement.class);
|
||||
return this.codec.parse(this.readOps(), predicates).getOrThrow();
|
||||
}
|
||||
}
|
||||
|
||||
public MutationResult<V, A, R> upgrade(Path destination) throws IOException {
|
||||
V value = this.read();
|
||||
MutationResult<V, A, R> result = this.transmuter.transmute(value);
|
||||
if (this.transmuter instanceof Transmuter.Mutable<V, A, R> mutableTransmuter) {
|
||||
value = mutableTransmuter.applyChanges(result);
|
||||
} else {
|
||||
value = result.value(); // sorted values
|
||||
}
|
||||
|
||||
Files.writeString(destination, this.toJsonString(value), StandardCharsets.UTF_8);
|
||||
return result;
|
||||
}
|
||||
|
||||
public String toJsonString(V object) {
|
||||
JsonElement element = this.codec.encodeStart(this.writeOps(), object).getOrThrow();
|
||||
return GSON.toJson(element) + "\n";
|
||||
}
|
||||
|
||||
public String path() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
private DynamicOps<JsonElement> readOps() {
|
||||
DynamicOps<JsonElement> ops = JsonOps.INSTANCE;
|
||||
if (this.requireRegistry) {
|
||||
ops = RegistryOps.create(ops, Main.REGISTRY_ACCESS);
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
private DynamicOps<JsonElement> writeOps() {
|
||||
return JsonOps.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DataFile[path=" + this.path + ']';
|
||||
}
|
||||
}
|
@ -0,0 +1,218 @@
|
||||
package io.papermc.generator.resources;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import io.github.classgraph.ClassGraph;
|
||||
import io.github.classgraph.ScanResult;
|
||||
import io.papermc.generator.registry.RegistryEntries;
|
||||
import io.papermc.generator.registry.RegistryEntry;
|
||||
import io.papermc.generator.utils.ClassHelper;
|
||||
import io.papermc.generator.utils.Formatting;
|
||||
import io.papermc.generator.utils.SourceCodecs;
|
||||
import io.papermc.generator.utils.predicate.BlockPredicate;
|
||||
import io.papermc.generator.utils.predicate.ItemPredicate;
|
||||
import io.papermc.typewriter.ClassNamed;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.util.ExtraCodecs;
|
||||
import net.minecraft.util.StringRepresentable;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.vehicle.AbstractBoat;
|
||||
import net.minecraft.world.entity.vehicle.AbstractMinecart;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@NullMarked
|
||||
public class DataFileLoader {
|
||||
|
||||
private static <K, V> Transmuter<Map<K, V>, Map.Entry<K, V>, K> sortedMap(Comparator<K> comparator) {
|
||||
return transmuteMap(MutationResult::constant, comparator);
|
||||
}
|
||||
|
||||
private static <K, V> Transmuter<Map<K, V>, Map.Entry<K, V>, K> transmuteMap(Supplier<Set<K>> typesProvider, Function<K, V> onMissing, Comparator<K> comparator) {
|
||||
return transmuteMap(map -> {
|
||||
Set<K> types = typesProvider.get();
|
||||
Set<K> registeredTypes = map.keySet();
|
||||
|
||||
Set<Map.Entry<K, V>> added = new HashSet<>();
|
||||
Sets.difference(types, registeredTypes).forEach(missingType -> added.add(Map.entry(missingType, onMissing.apply(missingType))));
|
||||
Set<K> removed = new HashSet<>(Sets.difference(registeredTypes, types));
|
||||
return new MutationResult<>(map, added, removed);
|
||||
}, comparator);
|
||||
}
|
||||
|
||||
private static <K, V> Transmuter<Map<K, V>, Map.Entry<K, V>, K> transmuteMap(Function<Map<K, V>, io.papermc.generator.resources.MutationResult<Map<K, V>, Map.Entry<K, V>, K>> mutation, Comparator<K> comparator) {
|
||||
return new Transmuter.Mutable<>() {
|
||||
|
||||
@Override
|
||||
public MutationResult<Map<K, V>, Map.Entry<K, V>, K> transmute(Map<K, V> value) {
|
||||
Map<K, V> map = new TreeMap<>(comparator);
|
||||
map.putAll(value);
|
||||
return mutation.apply(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<K, V> applyChanges(MutationResult<Map<K, V>, Map.Entry<K, V>, K> result) {
|
||||
result.added().forEach(entry -> result.value().put(entry.getKey(), entry.getValue()));
|
||||
result.removed().forEach(result.value()::remove);
|
||||
return result.value();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static class BlockState {
|
||||
|
||||
private static final Codec<Map<Class<? extends Enum<? extends StringRepresentable>>, ClassName>> ENUM_PROPERTY_TYPES_CODEC = Codec.unboundedMap(
|
||||
SourceCodecs.classCodec(new TypeToken<Enum<? extends StringRepresentable>>() {}), SourceCodecs.CLASS_NAME
|
||||
);
|
||||
public static final DataFile.Map<Class<? extends Enum<? extends StringRepresentable>>, ClassName> ENUM_PROPERTY_TYPES = new DataFile.Map<>(
|
||||
"data/block_state/enum_property_types.json", ENUM_PROPERTY_TYPES_CODEC,
|
||||
transmuteMap(() -> {
|
||||
try {
|
||||
Set<Class<? extends Enum<? extends StringRepresentable>>> enumPropertyTypes = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||
for (Field field : BlockStateProperties.class.getDeclaredFields()) {
|
||||
if (ClassHelper.isStaticConstant(field, Modifier.PUBLIC)) {
|
||||
if (!EnumProperty.class.isAssignableFrom(field.getType())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
enumPropertyTypes.add(((EnumProperty<?>) field.get(null)).getValueClass());
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableSet(enumPropertyTypes);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
},
|
||||
missingType -> ClassName.get("org.bukkit.block.data.type", missingType.getSimpleName()),
|
||||
Comparator.comparing(Class::getCanonicalName))
|
||||
);
|
||||
|
||||
// add classes that extends MultipleFacing and RedstoneWire
|
||||
// no real rule here some has some don't mossy carpet and wall could have it
|
||||
private static final Codec<List<ClassNamed>> EXTRA_ALLOWED_METHOD_CODEC = SourceCodecs.CLASS_NAMED.listOf();
|
||||
public static final DataFile.List<ClassNamed> EXTRA_ALLOWED_METHOD = new DataFile.List<>(
|
||||
"data/block_state/extra_allowed_method.json", EXTRA_ALLOWED_METHOD_CODEC, MutationResult::constant
|
||||
);
|
||||
|
||||
private static final Codec<Map<ClassNamed, List<BlockPredicate>>> PREDICATES_CODEC = Codec.unboundedMap(
|
||||
SourceCodecs.CLASS_NAMED, ExtraCodecs.nonEmptyList(BlockPredicate.CODEC.listOf())
|
||||
);
|
||||
public static final DataFile.Map<ClassNamed, List<BlockPredicate>> PREDICATES = new DataFile.Map<>(
|
||||
"data/block_state/predicates.json", PREDICATES_CODEC, MutationResult::constant, true
|
||||
);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static class ItemMeta {
|
||||
public record BridgeData(ClassNamed api, String field) {
|
||||
|
||||
public static final Codec<BridgeData> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
SourceCodecs.CLASS_NAMED.fieldOf("api").forGetter(BridgeData::api),
|
||||
SourceCodecs.IDENTIFIER.fieldOf("field").forGetter(BridgeData::field)
|
||||
).apply(instance, BridgeData::new));
|
||||
}
|
||||
|
||||
private static final Codec<Map<ClassNamed, BridgeData>> BRIDGE_CODEC = Codec.unboundedMap(SourceCodecs.CLASS_NAMED, BridgeData.CODEC);
|
||||
public static final DataFile.Map<ClassNamed, BridgeData> BRIDGE = new DataFile.Map<>(
|
||||
"data/item_meta/bridge.json", BRIDGE_CODEC, sortedMap(Comparator.comparing(ClassNamed::canonicalName))
|
||||
);
|
||||
|
||||
private static final Codec<Map<ClassNamed, List<ItemPredicate>>> PREDICATES_CODEC = Codec.unboundedMap(SourceCodecs.CLASS_NAMED, ExtraCodecs.nonEmptyList(ItemPredicate.CODEC.listOf()));
|
||||
public static final DataFile.Map<ClassNamed, List<ItemPredicate>> PREDICATES = new DataFile.Map<>(
|
||||
"data/item_meta/predicates.json", PREDICATES_CODEC, MutationResult::constant, true
|
||||
);
|
||||
}
|
||||
|
||||
private static final Codec<Map<ResourceKey<? extends Registry<?>>, RegistryData>> REGISTRIES_CODEC = Codec.unboundedMap(
|
||||
SourceCodecs.REGISTRY_KEY, RegistryData.CODEC
|
||||
);
|
||||
public static final Map<RegistryEntry.Type, DataFile.Map<ResourceKey<? extends Registry<?>>, RegistryData>> REGISTRIES = Collections.unmodifiableMap(Util.makeEnumMap(RegistryEntry.Type.class, type -> {
|
||||
return new DataFile.Map<>("data/registry/%s.json".formatted(type.getSerializedName()), REGISTRIES_CODEC, MutationResult::constant);
|
||||
}));
|
||||
|
||||
private static final Map<ResourceKey<EntityType<?>>, Class<?>> ENTITY_TYPE_GENERICS = RegistryEntries.byRegistryKey(Registries.ENTITY_TYPE).getFields(field -> {
|
||||
if (field.getGenericType() instanceof ParameterizedType complexType && complexType.getActualTypeArguments().length == 1) {
|
||||
return (Class<?>) complexType.getActualTypeArguments()[0];
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
private static final Codec<Map<ResourceKey<EntityType<?>>, EntityTypeData>> ENTITY_TYPES_CODEC = Codec.unboundedMap(ResourceKey.codec(Registries.ENTITY_TYPE), EntityTypeData.CODEC);
|
||||
public static final DataFile.Map<ResourceKey<EntityType<?>>, EntityTypeData> ENTITY_TYPES = new DataFile.Map<>(
|
||||
"data/entity_types.json", ENTITY_TYPES_CODEC,
|
||||
transmuteMap(() -> BuiltInRegistries.ENTITY_TYPE.listElementIds().collect(Collectors.toSet()),
|
||||
missingType -> {
|
||||
Class<?> genericType = ENTITY_TYPE_GENERICS.get(missingType);
|
||||
|
||||
String packageName = "org.bukkit.entity";
|
||||
if (AbstractBoat.class.isAssignableFrom(genericType)) {
|
||||
packageName += ".boat";
|
||||
} else if (AbstractMinecart.class.isAssignableFrom(genericType)) {
|
||||
packageName += ".minecart";
|
||||
}
|
||||
|
||||
return new EntityTypeData(ClassNamed.of(packageName, genericType.getSimpleName()));
|
||||
},
|
||||
Formatting.alphabeticKeyOrder(key -> key.location().getPath()))
|
||||
);
|
||||
|
||||
private static final Codec<Map<Class<? extends Mob>, ClassName>> ENTITY_CLASS_NAMES_CODEC = Codec.unboundedMap(
|
||||
SourceCodecs.classCodec(Mob.class), SourceCodecs.CLASS_NAME
|
||||
);
|
||||
public static final DataFile.Map<Class<? extends Mob>, ClassName> ENTITY_CLASS_NAMES = new DataFile.Map<>(
|
||||
"data/entity_class_names.json", ENTITY_CLASS_NAMES_CODEC,
|
||||
transmuteMap(() -> {
|
||||
try (ScanResult scanResult = new ClassGraph().enableClassInfo().acceptPackages(Entity.class.getPackageName()).scan()) {
|
||||
Set<Class<? extends Mob>> classes = new HashSet<>(scanResult.getSubclasses(Mob.class.getName()).loadClasses(Mob.class));
|
||||
if (classes.isEmpty()) {
|
||||
throw new IllegalStateException("There are supposed to be more than 0 mob classes!");
|
||||
}
|
||||
|
||||
classes.add(Mob.class);
|
||||
return Collections.unmodifiableSet(classes);
|
||||
}
|
||||
},
|
||||
missingType -> ClassName.get("org.bukkit.entity", missingType.getSimpleName()),
|
||||
Comparator.comparing(Class::getCanonicalName))
|
||||
);
|
||||
|
||||
public static final @MonotonicNonNull List<DataFile<?, ?, ?>> DATA_FILES = Collections.unmodifiableList(Util.make(new ArrayList<>(), list -> {
|
||||
list.add(BlockState.ENUM_PROPERTY_TYPES);
|
||||
list.add(BlockState.EXTRA_ALLOWED_METHOD);
|
||||
list.add(BlockState.PREDICATES);
|
||||
list.add(ItemMeta.BRIDGE);
|
||||
list.add(ItemMeta.PREDICATES);
|
||||
list.addAll(REGISTRIES.values());
|
||||
list.add(ENTITY_CLASS_NAMES);
|
||||
list.add(ENTITY_TYPES);
|
||||
}));
|
||||
|
||||
public static void init() {
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package io.papermc.generator.resources;
|
||||
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import io.papermc.generator.utils.SourceCodecs;
|
||||
import io.papermc.typewriter.ClassNamed;
|
||||
import net.minecraft.util.ExtraCodecs;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@NullMarked
|
||||
public record EntityTypeData(ClassNamed api, int legacyId) {
|
||||
|
||||
private static final int NO_LEGACY_ID = -1;
|
||||
|
||||
public EntityTypeData(ClassNamed api) {
|
||||
this(api, NO_LEGACY_ID);
|
||||
}
|
||||
|
||||
public static final Codec<EntityTypeData> DIRECT_CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
SourceCodecs.CLASS_NAMED.fieldOf("api").forGetter(EntityTypeData::api),
|
||||
ExtraCodecs.intRange(-1, Integer.MAX_VALUE).optionalFieldOf("legacy_id", NO_LEGACY_ID).deprecated(13).forGetter(EntityTypeData::legacyId)
|
||||
).apply(instance, EntityTypeData::new));
|
||||
|
||||
private static final Codec<EntityTypeData> CLASS_ONLY_CODEC = SourceCodecs.CLASS_NAMED.xmap(EntityTypeData::new, EntityTypeData::api);
|
||||
|
||||
public static final Codec<EntityTypeData> CODEC = Codec.either(CLASS_ONLY_CODEC, DIRECT_CODEC).xmap(Either::unwrap, data -> {
|
||||
if (data.legacyId() != NO_LEGACY_ID) {
|
||||
return Either.right(data);
|
||||
}
|
||||
return Either.left(data);
|
||||
});
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package io.papermc.generator.resources;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
@NullMarked
|
||||
public record MutationResult<V, A, R>(V value, Set<A> added, Set<R> removed) {
|
||||
|
||||
public static <V, A, R> MutationResult<V, A, R> constant(V value) {
|
||||
return new MutationResult<>(value, Collections.emptySet(), Collections.emptySet());
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package io.papermc.generator.registry;
|
||||
package io.papermc.generator.resources;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
@ -18,7 +18,7 @@ public record RegistryData(
|
||||
boolean allowInline
|
||||
) {
|
||||
|
||||
public static final Codec<RegistryData> UNSAFE_CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
public static final Codec<RegistryData> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
Api.CODEC.fieldOf("api").forGetter(RegistryData::api),
|
||||
Impl.CODEC.fieldOf("impl").forGetter(RegistryData::impl),
|
||||
Builder.CODEC.optionalFieldOf("builder").forGetter(RegistryData::builder),
|
@ -0,0 +1,14 @@
|
||||
package io.papermc.generator.resources;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@NullMarked
|
||||
public interface Transmuter<V, A, R> {
|
||||
|
||||
MutationResult<V, A, R> transmute(V value);
|
||||
|
||||
interface Mutable<V, A, R> extends Transmuter<V, A, R> {
|
||||
|
||||
V applyChanges(MutationResult<V, A, R> result);
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package io.papermc.generator.rewriter.types.registry;
|
||||
|
||||
import com.google.common.base.CaseFormat;
|
||||
import io.papermc.generator.registry.RegistryData;
|
||||
import io.papermc.generator.resources.RegistryData;
|
||||
import io.papermc.generator.registry.RegistryEntries;
|
||||
import io.papermc.generator.registry.RegistryEntry;
|
||||
import io.papermc.generator.rewriter.types.Types;
|
||||
@ -12,7 +12,7 @@ import net.minecraft.core.registries.Registries;
|
||||
|
||||
public class PaperRegistriesRewriter extends SearchReplaceRewriter {
|
||||
|
||||
private void appendEntry(String indent, StringBuilder builder, RegistryEntry<?> entry, boolean canBeDelayed, boolean apiOnly) {
|
||||
private void appendEntry(String indent, StringBuilder builder, RegistryEntry<?> entry, boolean apiOnly) {
|
||||
builder.append(indent);
|
||||
builder.append("start");
|
||||
builder.append('(');
|
||||
@ -54,7 +54,7 @@ public class PaperRegistriesRewriter extends SearchReplaceRewriter {
|
||||
builder.append(')');
|
||||
}, () -> builder.append(".build()"));
|
||||
}
|
||||
if (canBeDelayed && data.impl().delayed()) {
|
||||
if (data.impl().delayed()) {
|
||||
builder.append(".delayed()");
|
||||
}
|
||||
builder.append(',');
|
||||
@ -63,27 +63,22 @@ public class PaperRegistriesRewriter extends SearchReplaceRewriter {
|
||||
|
||||
@Override
|
||||
public void insert(SearchMetadata metadata, StringBuilder builder) {
|
||||
builder.append(metadata.indent()).append("// built-in");
|
||||
for (RegistryEntry.Type type : RegistryEntry.Type.values()) {
|
||||
builder.append(metadata.indent()).append("// ").append(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, type.getSerializedName()));
|
||||
builder.append('\n');
|
||||
|
||||
for (RegistryEntry<?> entry : RegistryEntries.BUILT_IN) {
|
||||
appendEntry(metadata.indent(), builder, entry, false, false);
|
||||
for (RegistryEntry<?> entry : RegistryEntries.byType(type)) {
|
||||
appendEntry(metadata.indent(), builder, entry, false);
|
||||
}
|
||||
|
||||
builder.append('\n');
|
||||
builder.append(metadata.indent()).append("// data-driven");
|
||||
builder.append('\n');
|
||||
|
||||
for (RegistryEntry<?> entry : RegistryEntries.DATA_DRIVEN) {
|
||||
appendEntry(metadata.indent(), builder, entry, true, false);
|
||||
}
|
||||
|
||||
builder.append('\n');
|
||||
builder.append(metadata.indent()).append("// api-only");
|
||||
builder.append('\n');
|
||||
|
||||
for (RegistryEntry<?> entry : RegistryEntries.API_ONLY) {
|
||||
appendEntry(metadata.indent(), builder, entry, false, true);
|
||||
appendEntry(metadata.indent(), builder, entry, true);
|
||||
}
|
||||
|
||||
builder.deleteCharAt(builder.length() - 2); // delete extra comma...
|
||||
|
@ -1,6 +1,6 @@
|
||||
package io.papermc.generator.rewriter.types.registry;
|
||||
|
||||
import io.papermc.generator.registry.RegistryData;
|
||||
import io.papermc.generator.resources.RegistryData;
|
||||
import io.papermc.generator.registry.RegistryEntries;
|
||||
import io.papermc.generator.rewriter.types.Types;
|
||||
import io.papermc.typewriter.replace.SearchMetadata;
|
||||
@ -16,17 +16,17 @@ public class RegistryEventsRewriter extends SearchReplaceRewriter {
|
||||
public void insert(SearchMetadata metadata, StringBuilder builder) {
|
||||
RegistryEntries.forEach(entry -> {
|
||||
RegistryData data = entry.data();
|
||||
if (data.builder().isPresent()) {
|
||||
data.builder().ifPresent(b -> {
|
||||
builder.append(metadata.indent());
|
||||
builder.append("%s %s %s ".formatted(PUBLIC, STATIC, FINAL));
|
||||
builder.append(Types.REGISTRY_EVENT_PROVIDER.simpleName());
|
||||
builder.append("<").append(this.importCollector.getShortName(data.api().klass())).append(", ").append(this.importCollector.getShortName(data.builder().get().api())).append('>');
|
||||
builder.append("<").append(this.importCollector.getShortName(data.api().klass())).append(", ").append(this.importCollector.getShortName(b.api())).append('>');
|
||||
builder.append(' ');
|
||||
builder.append(entry.registryKeyField());
|
||||
builder.append(" = ");
|
||||
builder.append("create(").append(Types.REGISTRY_KEY.simpleName()).append('.').append(entry.registryKeyField()).append(");");
|
||||
builder.append('\n');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package io.papermc.generator.rewriter.types.registry;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import io.papermc.generator.registry.RegistryData;
|
||||
import io.papermc.generator.resources.RegistryData;
|
||||
import io.papermc.generator.registry.RegistryEntries;
|
||||
import io.papermc.generator.registry.RegistryEntry;
|
||||
import io.papermc.generator.registry.RegistryIdentifiable;
|
||||
|
@ -1,9 +1,9 @@
|
||||
package io.papermc.generator.rewriter.types.simple;
|
||||
|
||||
import io.papermc.generator.registry.RegistryEntries;
|
||||
import io.papermc.generator.resources.DataFileLoader;
|
||||
import io.papermc.generator.rewriter.types.Types;
|
||||
import io.papermc.generator.utils.Formatting;
|
||||
import io.papermc.generator.utils.ItemMetaData;
|
||||
import io.papermc.generator.utils.predicate.ItemPredicate;
|
||||
import io.papermc.typewriter.ClassNamed;
|
||||
import io.papermc.typewriter.context.IndentUnit;
|
||||
@ -25,8 +25,8 @@ public class CraftItemMetasRewriter extends SearchReplaceRewriter {
|
||||
protected void insert(SearchMetadata metadata, StringBuilder builder) {
|
||||
IndentUnit indentUnit = this.indentUnit();
|
||||
ClassNamed itemType = RegistryEntries.byRegistryKey(Registries.ITEM).data().api().klass();
|
||||
for (Map.Entry<ClassNamed, List<ItemPredicate>> entry : ItemMetaData.PREDICATES.entrySet()) {
|
||||
String field = ItemMetaData.BRIDGE.get(entry.getKey()).field();
|
||||
for (Map.Entry<ClassNamed, List<ItemPredicate>> entry : DataFileLoader.ItemMeta.PREDICATES.get().entrySet()) {
|
||||
String field = DataFileLoader.ItemMeta.BRIDGE.get().get(entry.getKey()).field();
|
||||
Iterator<ItemPredicate> predicateIterator = entry.getValue().iterator();
|
||||
|
||||
builder.append(metadata.indent());
|
||||
|
@ -1,73 +1,27 @@
|
||||
package io.papermc.generator.rewriter.types.simple;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import io.papermc.generator.resources.DataFileLoader;
|
||||
import io.papermc.generator.rewriter.types.registry.EnumRegistryRewriter;
|
||||
import io.papermc.generator.utils.SourceCodecs;
|
||||
import io.papermc.typewriter.ClassNamed;
|
||||
import io.papermc.generator.resources.EntityTypeData;
|
||||
import io.papermc.typewriter.preset.model.EnumValue;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.util.ExtraCodecs;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
|
||||
import static io.papermc.generator.utils.Formatting.quoted;
|
||||
|
||||
public class EntityTypeRewriter extends EnumRegistryRewriter<EntityType<?>> {
|
||||
|
||||
public record Data(ClassNamed api, int legacyId) {
|
||||
|
||||
private static final int NO_LEGACY_ID = -1;
|
||||
|
||||
public Data(ClassNamed api) {
|
||||
this(api, NO_LEGACY_ID);
|
||||
}
|
||||
|
||||
public static final Codec<Data> DIRECT_CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
SourceCodecs.CLASS_NAMED.fieldOf("api").forGetter(Data::api),
|
||||
ExtraCodecs.intRange(-1, Integer.MAX_VALUE).optionalFieldOf("legacy_id", NO_LEGACY_ID).deprecated(13).forGetter(Data::legacyId)
|
||||
).apply(instance, Data::new));
|
||||
|
||||
private static final Codec<Data> CLASS_ONLY_CODEC = SourceCodecs.CLASS_NAMED.xmap(Data::new, Data::api);
|
||||
|
||||
public static final Codec<Data> CODEC = Codec.either(CLASS_ONLY_CODEC, DIRECT_CODEC).xmap(Either::unwrap, data -> {
|
||||
if (data.legacyId() != NO_LEGACY_ID) {
|
||||
return Either.right(data);
|
||||
}
|
||||
return Either.left(data);
|
||||
});
|
||||
}
|
||||
|
||||
private static final Map<ResourceKey<EntityType<?>>, Data> DATA;
|
||||
public static final Codec<Map<ResourceKey<EntityType<?>>, Data>> DATA_CODEC = Codec.unboundedMap(ResourceKey.codec(Registries.ENTITY_TYPE), Data.CODEC);
|
||||
static {
|
||||
try (Reader input = new BufferedReader(new InputStreamReader(EntityTypeRewriter.class.getClassLoader().getResourceAsStream("data/entity_types.json")))) {
|
||||
JsonObject registries = SourceCodecs.GSON.fromJson(input, JsonObject.class);
|
||||
DATA = DATA_CODEC.parse(JsonOps.INSTANCE, registries).getOrThrow();
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public EntityTypeRewriter() {
|
||||
super(Registries.ENTITY_TYPE, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EnumValue.Builder rewriteEnumValue(Holder.Reference<EntityType<?>> reference) {
|
||||
Data data = Objects.requireNonNull(DATA.get(reference.key()), () -> "Missing entity type data for " + reference);
|
||||
EntityTypeData data = Objects.requireNonNull(DataFileLoader.ENTITY_TYPES.get().get(reference.key()), () -> "Missing entity type data for " + reference);
|
||||
String path = reference.key().location().getPath();
|
||||
List<String> arguments = new ArrayList<>(4);
|
||||
arguments.add(quoted(path));
|
||||
|
@ -1,8 +1,8 @@
|
||||
package io.papermc.generator.rewriter.types.simple;
|
||||
|
||||
import io.papermc.generator.resources.DataFileLoader;
|
||||
import io.papermc.generator.rewriter.types.Types;
|
||||
import io.papermc.generator.rewriter.types.registry.RegistryFieldRewriter;
|
||||
import io.papermc.generator.utils.ItemMetaData;
|
||||
import io.papermc.generator.utils.predicate.ItemPredicate;
|
||||
import io.papermc.typewriter.ClassNamed;
|
||||
import net.minecraft.core.Holder;
|
||||
@ -27,7 +27,7 @@ public class ItemTypeRewriter extends RegistryFieldRewriter<Item> {
|
||||
|
||||
ClassNamed implMetaName = null;
|
||||
mainLoop:
|
||||
for (Map.Entry<ClassNamed, List<ItemPredicate>> entry : ItemMetaData.PREDICATES.entrySet()) {
|
||||
for (Map.Entry<ClassNamed, List<ItemPredicate>> entry : DataFileLoader.ItemMeta.PREDICATES.get().entrySet()) {
|
||||
for (ItemPredicate predicate : entry.getValue()) {
|
||||
if (predicate.test(reference)) {
|
||||
implMetaName = entry.getKey();
|
||||
@ -38,7 +38,7 @@ public class ItemTypeRewriter extends RegistryFieldRewriter<Item> {
|
||||
|
||||
ClassNamed metaName = null;
|
||||
if (implMetaName != null) {
|
||||
metaName = ItemMetaData.BRIDGE.get(implMetaName).api();
|
||||
metaName = DataFileLoader.ItemMeta.BRIDGE.get().get(implMetaName).api();
|
||||
}
|
||||
return "%s<%s>".formatted(Types.ITEM_TYPE_TYPED.dottedNestedName(), metaName != null ? this.importCollector.getShortName(metaName) : Types.ITEM_META.simpleName());
|
||||
}
|
||||
|
@ -1,55 +1,13 @@
|
||||
package io.papermc.generator.tasks;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import io.github.classgraph.ClassGraph;
|
||||
import io.github.classgraph.ScanResult;
|
||||
import io.papermc.generator.Main;
|
||||
import io.papermc.generator.registry.RegistryEntries;
|
||||
import io.papermc.generator.rewriter.types.simple.EntityTypeRewriter;
|
||||
import io.papermc.generator.types.goal.MobGoalNames;
|
||||
import io.papermc.generator.utils.BlockStateData;
|
||||
import io.papermc.generator.utils.ClassHelper;
|
||||
import io.papermc.generator.utils.Formatting;
|
||||
import io.papermc.generator.utils.ItemMetaData;
|
||||
import io.papermc.generator.utils.SourceCodecs;
|
||||
import io.papermc.typewriter.ClassNamed;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.util.StringRepresentable;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.vehicle.AbstractBoat;
|
||||
import net.minecraft.world.entity.vehicle.AbstractMinecart;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
||||
import io.papermc.generator.resources.DataFile;
|
||||
import io.papermc.generator.resources.DataFileLoader;
|
||||
import io.papermc.generator.resources.MutationResult;
|
||||
import org.slf4j.Logger;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class PrepareInputFiles {
|
||||
|
||||
@ -59,140 +17,23 @@ public class PrepareInputFiles {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
private interface MutationResult<A> {
|
||||
A value();
|
||||
|
||||
Set<?> added();
|
||||
|
||||
Set<?> removed();
|
||||
}
|
||||
|
||||
private record SimpleMutationResult<A>(A value, Set<?> added, Set<?> removed) implements MutationResult<A> {
|
||||
|
||||
public static <A> MutationResult<A> noMutation(A value) {
|
||||
return new SimpleMutationResult<>(value, Collections.emptySet(), Collections.emptySet());
|
||||
}
|
||||
}
|
||||
|
||||
private record MapMutationResult<K, V>(Map<K, V> value, Set<Map.Entry<K, V>> added, Set<K> removed) implements MutationResult<Map<K, V>> {
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface Transmuter<A> {
|
||||
|
||||
MutationResult<A> transmute(A value);
|
||||
}
|
||||
|
||||
private record DataFile<A>(String path, Codec<A> codec, Transmuter<A> transmuter) {
|
||||
|
||||
public MutationResult<A> transmuteRaw(Object value) {
|
||||
return this.transmuter.transmute((A) value);
|
||||
}
|
||||
}
|
||||
|
||||
private static <K, V> Transmuter<Map<K, V>> transmuteMap(Comparator<? super K> comparator) {
|
||||
return transmuteMap(SimpleMutationResult::noMutation, comparator);
|
||||
}
|
||||
|
||||
private static <K, V> Transmuter<Map<K, V>> transmuteDeltaMap(Supplier<Set<K>> typesProvider, Function<K, V> onMissing, Comparator<? super K> comparator) {
|
||||
return transmuteMap(map -> {
|
||||
Set<K> types = typesProvider.get();
|
||||
Set<K> registeredTypes = map.keySet();
|
||||
|
||||
Set<Map.Entry<K, V>> added = new HashSet<>();
|
||||
Sets.difference(types, registeredTypes).forEach(missingType -> added.add(Map.entry(missingType, onMissing.apply(missingType))));
|
||||
Set<K> removed = new HashSet<>(Sets.difference(registeredTypes, types));
|
||||
|
||||
added.forEach(entry -> map.put(entry.getKey(), entry.getValue()));
|
||||
removed.forEach(map::remove);
|
||||
return new MapMutationResult<>(map, added, removed);
|
||||
}, comparator);
|
||||
}
|
||||
|
||||
private static <K, V> Transmuter<Map<K, V>> transmuteMap(Function<Map<K, V>, MutationResult<Map<K, V>>> mutation, Comparator<? super K> comparator) {
|
||||
return value -> {
|
||||
TreeMap<K, V> map = new TreeMap<>(comparator);
|
||||
map.putAll(value);
|
||||
return mutation.apply(map);
|
||||
};
|
||||
}
|
||||
|
||||
private static final Map<ResourceKey<EntityType<?>>, Class<?>> ENTITY_TYPE_GENERICS = RegistryEntries.byRegistryKey(Registries.ENTITY_TYPE).getFields(field -> {
|
||||
if (field.getGenericType() instanceof ParameterizedType complexType && complexType.getActualTypeArguments().length == 1) {
|
||||
return (Class<?>) complexType.getActualTypeArguments()[0];
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
private static final List<DataFile<?>> DATA_FILES = List.of(
|
||||
new DataFile<>("block_state/enum_property_types.json", BlockStateData.ENUM_PROPERTY_TYPES_CODEC, transmuteDeltaMap(() -> {
|
||||
try {
|
||||
Set<Class<? extends Enum<? extends StringRepresentable>>> enumPropertyTypes = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||
for (Field field : BlockStateProperties.class.getDeclaredFields()) {
|
||||
if (ClassHelper.isStaticConstant(field, Modifier.PUBLIC)) {
|
||||
if (!EnumProperty.class.isAssignableFrom(field.getType())) {
|
||||
public static void main(String[] args) throws IOException {
|
||||
Path resourceDir = Path.of(args[0]);
|
||||
for (DataFile<?, ?, ?> file : DataFileLoader.DATA_FILES) {
|
||||
if (!file.isMutable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
enumPropertyTypes.add(((EnumProperty<?>) field.get(null)).getValueClass());
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableSet(enumPropertyTypes);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
},
|
||||
missingType -> ClassName.get("org.bukkit.block.data.type", missingType.getSimpleName()),
|
||||
Comparator.comparing(Class::getCanonicalName))
|
||||
),
|
||||
new DataFile<>("entity_types.json", EntityTypeRewriter.DATA_CODEC, transmuteDeltaMap(() -> BuiltInRegistries.ENTITY_TYPE.listElementIds().collect(Collectors.toSet()),
|
||||
missingType -> {
|
||||
Holder.Reference<EntityType<?>> reference = Main.REGISTRY_ACCESS.get(missingType).orElseThrow();
|
||||
Class<?> genericType = ENTITY_TYPE_GENERICS.get(missingType);
|
||||
|
||||
String packageName = "org.bukkit.entity";
|
||||
if (AbstractBoat.class.isAssignableFrom(genericType)) {
|
||||
packageName += ".boat";
|
||||
} else if (AbstractMinecart.class.isAssignableFrom(genericType)) {
|
||||
packageName += ".minecart";
|
||||
}
|
||||
|
||||
return new EntityTypeRewriter.Data(ClassNamed.of(packageName, genericType.getSimpleName()));
|
||||
},
|
||||
Formatting.alphabeticKeyOrder(key -> key.location().getPath()))
|
||||
),
|
||||
new DataFile<>("entity_class_names.json", MobGoalNames.ENTITY_CLASS_NAMES_CODEC, transmuteDeltaMap(() -> {
|
||||
try (ScanResult scanResult = new ClassGraph().enableClassInfo().whitelistPackages(Entity.class.getPackageName()).scan()) {
|
||||
Set<Class<? extends Mob>> classes = new HashSet<>(scanResult.getSubclasses(Mob.class.getName()).loadClasses(Mob.class));
|
||||
classes.add(Mob.class);
|
||||
return Collections.unmodifiableSet(classes);
|
||||
}
|
||||
},
|
||||
missingType -> ClassName.get("org.bukkit.entity", missingType.getSimpleName()),
|
||||
Comparator.comparing(Class::getCanonicalName))
|
||||
),
|
||||
new DataFile<>("item_meta/bridge.json", ItemMetaData.BRIDGE_CODEC, transmuteMap(Comparator.comparing(ClassNamed::canonicalName)))
|
||||
);
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
Path resourceDir = Path.of(args[0]);
|
||||
for (DataFile<?> file : DATA_FILES) {
|
||||
Path filePath = Path.of("data", file.path());
|
||||
Path resourcePath = resourceDir.resolve(filePath);
|
||||
try (Reader input = Files.newBufferedReader(resourcePath, StandardCharsets.UTF_8)) {
|
||||
JsonElement element = SourceCodecs.GSON.fromJson(input, JsonElement.class);
|
||||
MutationResult<?> result = file.transmuteRaw(file.codec().parse(JsonOps.INSTANCE, element).getOrThrow());
|
||||
element = ((Codec<Object>) file.codec()).encodeStart(JsonOps.INSTANCE, result.value()).getOrThrow();
|
||||
Files.writeString(resourcePath, SourceCodecs.GSON.toJson(element) + "\n", StandardCharsets.UTF_8);
|
||||
Path filePath = Path.of(file.path());
|
||||
MutationResult<?, ?, ?> result = file.upgrade(resourceDir.resolve(filePath));
|
||||
|
||||
if (!result.added().isEmpty()) {
|
||||
LOGGER.info("Added the following elements in {}:", filePath);
|
||||
result.added().stream().map(Object::toString).forEach(LOGGER::info);
|
||||
result.added().stream().map(o -> "- " + o).forEach(LOGGER::info);
|
||||
}
|
||||
if (!result.removed().isEmpty()) {
|
||||
LOGGER.warn("Removed the following keys in {}:", filePath);
|
||||
result.removed().stream().map(Object::toString).forEach(LOGGER::info);
|
||||
}
|
||||
result.removed().stream().map(o -> "- " + o).forEach(LOGGER::warn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import com.squareup.javapoet.FieldSpec;
|
||||
import com.squareup.javapoet.MethodSpec;
|
||||
import com.squareup.javapoet.ParameterizedTypeName;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import io.papermc.generator.utils.BlockStateData;
|
||||
import io.papermc.generator.resources.DataFileLoader;
|
||||
import net.minecraft.util.StringRepresentable;
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
@ -27,7 +27,7 @@ public class EnumPropertyWriter<T extends Enum<T> & StringRepresentable> extends
|
||||
@Override
|
||||
protected TypeName processApiType() {
|
||||
Class<?> rawClass = this.property.getValueClass();
|
||||
return BlockStateData.ENUM_PROPERTY_TYPES.get(rawClass);
|
||||
return DataFileLoader.BlockState.ENUM_PROPERTY_TYPES.get().get(rawClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -11,9 +11,9 @@ 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.DataAppenders;
|
||||
import io.papermc.generator.utils.BlockStateData;
|
||||
import io.papermc.generator.utils.ClassHelper;
|
||||
import io.papermc.generator.utils.CommonVariable;
|
||||
import io.papermc.generator.resources.DataFileLoader;
|
||||
import io.papermc.generator.utils.NamingManager;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
@ -80,7 +80,7 @@ public class DataPropertyWriter extends DataPropertyWriterBase {
|
||||
this.type = DataHolderType.MAP;
|
||||
this.internalIndexClass = ClassHelper.eraseType(complexType.getActualTypeArguments()[0]);
|
||||
if (this.internalIndexClass.isEnum()) {
|
||||
TypeName indexClass = BlockStateData.ENUM_PROPERTY_TYPES.get(this.internalIndexClass);
|
||||
TypeName indexClass = DataFileLoader.BlockState.ENUM_PROPERTY_TYPES.get().get(this.internalIndexClass);
|
||||
if (indexClass == null) {
|
||||
indexClass = TypeName.get(this.internalIndexClass);
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
@ -18,18 +19,14 @@ import org.jspecify.annotations.NullMarked;
|
||||
@NullMarked
|
||||
public abstract class DataPropertyWriterBase implements DataPropertyMaker {
|
||||
|
||||
protected final Collection<? extends Property<?>> properties;
|
||||
protected final Stream<? extends Property<?>> properties;
|
||||
protected final Class<? extends Block> blockClass;
|
||||
|
||||
protected DataPropertyWriterBase(Collection<? extends Property<?>> properties, Class<? extends Block> blockClass) {
|
||||
this.properties = properties;
|
||||
this.properties = properties.stream().sorted(Comparator.comparing(Property::getName));
|
||||
this.blockClass = blockClass;
|
||||
}
|
||||
|
||||
private Iterator<? extends Property<?>> sortedIterator() {
|
||||
return this.properties.stream().sorted(Comparator.comparing(Property::getName)).iterator();
|
||||
}
|
||||
|
||||
protected void createSyntheticCollection(CodeBlock.Builder code, boolean isArray, Map<Property<?>, Field> fields) {
|
||||
if (isArray) {
|
||||
code.add("{\n");
|
||||
@ -37,12 +34,12 @@ public abstract class DataPropertyWriterBase implements DataPropertyMaker {
|
||||
code.add("$T.of(\n", List.class);
|
||||
}
|
||||
code.indent();
|
||||
Iterator<? extends Property<?>> it = this.sortedIterator();
|
||||
while (it.hasNext()) {
|
||||
Property<?> property = it.next();
|
||||
Iterator<? extends Property<?>> properties = this.properties.iterator();
|
||||
while (properties.hasNext()) {
|
||||
Property<?> property = properties.next();
|
||||
Pair<Class<?>, String> fieldName = PropertyWriter.referenceField(this.blockClass, property, fields);
|
||||
code.add("$T.$L", fieldName.left(), fieldName.right());
|
||||
if (it.hasNext()) {
|
||||
if (properties.hasNext()) {
|
||||
code.add(",");
|
||||
}
|
||||
code.add("\n");
|
||||
@ -53,13 +50,13 @@ public abstract class DataPropertyWriterBase implements DataPropertyMaker {
|
||||
protected void createSyntheticMap(CodeBlock.Builder code, TypeName indexClass, Map<Property<?>, Field> fields) {
|
||||
// assume indexClass is an enum with its values matching the property names
|
||||
code.add("$T.of(\n", Map.class).indent();
|
||||
Iterator<? extends Property<?>> it = this.sortedIterator();
|
||||
while (it.hasNext()) {
|
||||
Property<?> property = it.next();
|
||||
Iterator<? extends Property<?>> properties = this.properties.iterator();
|
||||
while (properties.hasNext()) {
|
||||
Property<?> property = properties.next();
|
||||
String name = Formatting.formatKeyAsField(property.getName());
|
||||
Pair<Class<?>, String> fieldName = PropertyWriter.referenceField(this.blockClass, property, fields);
|
||||
code.add("$T.$L, $T.$L", indexClass, name, fieldName.left(), fieldName.right());
|
||||
if (it.hasNext()) {
|
||||
if (properties.hasNext()) {
|
||||
code.add(",");
|
||||
}
|
||||
code.add("\n");
|
||||
|
@ -10,7 +10,7 @@ import com.squareup.javapoet.TypeName;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator;
|
||||
import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase;
|
||||
import io.papermc.generator.utils.BlockStateData;
|
||||
import io.papermc.generator.resources.DataFileLoader;
|
||||
import io.papermc.generator.utils.NamingManager;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collection;
|
||||
@ -54,7 +54,7 @@ public class VirtualDataPropertyWriter extends DataPropertyWriterBase {
|
||||
} else {
|
||||
Class<?> valueClass = this.properties.iterator().next().getValueClass();
|
||||
if (valueClass.isEnum()) {
|
||||
this.indexClass = BlockStateData.ENUM_PROPERTY_TYPES.get(valueClass);
|
||||
this.indexClass = DataFileLoader.BlockState.ENUM_PROPERTY_TYPES.get().get(valueClass);
|
||||
} else {
|
||||
this.indexClass = TypeName.get(valueClass);
|
||||
}
|
||||
|
@ -2,9 +2,6 @@ package io.papermc.generator.types.craftblockdata.property.holder.appender;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.FieldSpec;
|
||||
import com.squareup.javapoet.MethodSpec;
|
||||
@ -12,23 +9,16 @@ import com.squareup.javapoet.ParameterSpec;
|
||||
import com.squareup.javapoet.ParameterizedTypeName;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
import io.papermc.generator.resources.DataFileLoader;
|
||||
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.DataHolderType;
|
||||
import io.papermc.generator.utils.BlockStateMapping;
|
||||
import io.papermc.generator.utils.CommonVariable;
|
||||
import io.papermc.generator.utils.NamingManager;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import io.papermc.generator.utils.SourceCodecs;
|
||||
import io.papermc.typewriter.ClassNamed;
|
||||
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@ -38,21 +28,7 @@ public class MapAppender implements DataAppender {
|
||||
private static final Map<String, String> INDEX_NAMES = ImmutableMap.<String, String>builder()
|
||||
.put(Types.BLOCK_FACE.simpleName(), "Face")
|
||||
.buildOrThrow();
|
||||
|
||||
// no real rule here some has some don't mossy carpet and wall could have it
|
||||
// todo find another way and clean up those hardcoced things ^
|
||||
public static final List<ClassNamed> SUPPORT_ALLOWED_METHOD;
|
||||
public static final Codec<List<ClassNamed>> SUPPORT_ALLOWED_METHOD_CODEC = SourceCodecs.CLASS_NAMED.listOf(1, Integer.MAX_VALUE);
|
||||
|
||||
static {
|
||||
// add classes that extends MultipleFacing and RedstoneWire
|
||||
try (Reader input = new BufferedReader(new InputStreamReader(BlockStateMapping.class.getClassLoader().getResourceAsStream("data/block_state/extra_allowed_method.json")))) {
|
||||
JsonArray classes = SourceCodecs.GSON.fromJson(input, JsonArray.class);
|
||||
SUPPORT_ALLOWED_METHOD = SUPPORT_ALLOWED_METHOD_CODEC.parse(JsonOps.INSTANCE, classes).getOrThrow();
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
// todo find another way for extra method and clean up those hardcoded things ^
|
||||
|
||||
@Override
|
||||
public DataHolderType getType() {
|
||||
@ -80,7 +56,7 @@ public class MapAppender implements DataAppender {
|
||||
builder.addMethod(methodBuilder.build());
|
||||
}
|
||||
|
||||
if (SUPPORT_ALLOWED_METHOD.contains(generator.getBaseClass()) &&
|
||||
if (DataFileLoader.BlockState.EXTRA_ALLOWED_METHOD.get().contains(generator.getBaseClass()) &&
|
||||
indexParameter.type instanceof ClassName className && !className.isBoxedPrimitive()) {
|
||||
NamingManager.NameWrapper indexNaming = NamingManager.NameWrapper.wrap("get", INDEX_NAMES.getOrDefault(className.simpleName(), className.simpleName()));
|
||||
|
||||
|
@ -61,7 +61,7 @@ public class MobGoalGenerator extends SimpleGenerator {
|
||||
.returns(ParameterizedTypeName.get(Types.GOAL_KEY, type));
|
||||
|
||||
List<Class<Goal>> classes;
|
||||
try (ScanResult scanResult = new ClassGraph().enableAllInfo().whitelistPackages("net.minecraft").scan()) {
|
||||
try (ScanResult scanResult = new ClassGraph().enableAllInfo().acceptPackages("net.minecraft").scan()) {
|
||||
classes = scanResult.getSubclasses(Goal.class.getName()).loadClasses(Goal.class);
|
||||
}
|
||||
|
||||
|
@ -1,22 +1,14 @@
|
||||
package io.papermc.generator.types.goal;
|
||||
|
||||
import com.google.common.base.CaseFormat;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import io.papermc.generator.resources.DataFileLoader;
|
||||
import io.papermc.generator.types.Types;
|
||||
import io.papermc.generator.utils.SourceCodecs;
|
||||
import io.papermc.generator.utils.Formatting;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.ai.goal.Goal;
|
||||
import net.minecraft.world.entity.monster.RangedAttackMob;
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
@ -26,20 +18,6 @@ import org.jspecify.annotations.NullMarked;
|
||||
public final class MobGoalNames { // todo sync with MobGoalHelper ideally this should not be duplicated
|
||||
|
||||
private static final Map<Class<? extends Goal>, ClassName> entityClassCache = new HashMap<>();
|
||||
public static final Map<Class<? extends Mob>, ClassName> ENTITY_CLASS_NAMES;
|
||||
public static final Codec<Map<Class<? extends Mob>, ClassName>> ENTITY_CLASS_NAMES_CODEC = Codec.unboundedMap(
|
||||
SourceCodecs.classCodec(Mob.class), SourceCodecs.CLASS_NAME
|
||||
);
|
||||
|
||||
static {
|
||||
try (Reader input = new BufferedReader(new InputStreamReader(MobGoalNames.class.getClassLoader().getResourceAsStream("data/entity_class_names.json")))) {
|
||||
JsonObject names = SourceCodecs.GSON.fromJson(input, JsonObject.class);
|
||||
ENTITY_CLASS_NAMES = ENTITY_CLASS_NAMES_CODEC.parse(JsonOps.INSTANCE, names).getOrThrow();
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<String, String> deobfuscationMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
@ -102,7 +80,7 @@ public final class MobGoalNames { // todo sync with MobGoalHelper ideally this s
|
||||
}
|
||||
|
||||
private static ClassName toBukkitClass(Class<? extends net.minecraft.world.entity.Mob> nmsClass) {
|
||||
ClassName bukkitClass = ENTITY_CLASS_NAMES.get(nmsClass);
|
||||
ClassName bukkitClass = DataFileLoader.ENTITY_CLASS_NAMES.get().get(nmsClass);
|
||||
if (bukkitClass == null) {
|
||||
throw new RuntimeException("Can't figure out applicable bukkit entity for nms entity " + nmsClass); // maybe just return Mob?
|
||||
}
|
||||
|
@ -1,52 +0,0 @@
|
||||
package io.papermc.generator.utils;
|
||||
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import io.papermc.generator.Main;
|
||||
import io.papermc.generator.utils.predicate.BlockPredicate;
|
||||
import io.papermc.typewriter.ClassNamed;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import net.minecraft.resources.RegistryOps;
|
||||
import net.minecraft.util.StringRepresentable;
|
||||
|
||||
public final class BlockStateData {
|
||||
|
||||
public static final Map<ClassNamed, List<BlockPredicate>> PREDICATES;
|
||||
public static final Codec<Map<ClassNamed, List<BlockPredicate>>> PREDICATES_CODEC = Codec.unboundedMap(
|
||||
SourceCodecs.CLASS_NAMED, BlockPredicate.CODEC.listOf()
|
||||
);
|
||||
|
||||
static {
|
||||
try (Reader input = new BufferedReader(new InputStreamReader(BlockStateMapping.class.getClassLoader().getResourceAsStream("data/block_state/predicates.json")))) {
|
||||
JsonObject predicates = SourceCodecs.GSON.fromJson(input, JsonObject.class);
|
||||
PREDICATES = PREDICATES_CODEC.parse(RegistryOps.create(JsonOps.INSTANCE, Main.REGISTRY_ACCESS), predicates).getOrThrow();
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static final Map<Class<? extends Enum<? extends StringRepresentable>>, ClassName> ENUM_PROPERTY_TYPES;
|
||||
public static final Codec<Map<Class<? extends Enum<? extends StringRepresentable>>, ClassName>> ENUM_PROPERTY_TYPES_CODEC = Codec.unboundedMap(
|
||||
SourceCodecs.classCodec(new TypeToken<Enum<? extends StringRepresentable>>() {}), SourceCodecs.CLASS_NAME
|
||||
);
|
||||
|
||||
static {
|
||||
try (Reader input = new BufferedReader(new InputStreamReader(BlockStateMapping.class.getClassLoader().getResourceAsStream("data/block_state/enum_property_types.json")))) {
|
||||
JsonObject properties = SourceCodecs.GSON.fromJson(input, JsonObject.class);
|
||||
ENUM_PROPERTY_TYPES = ENUM_PROPERTY_TYPES_CODEC.parse(JsonOps.INSTANCE, properties).getOrThrow();
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private BlockStateData() {
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import io.papermc.generator.Main;
|
||||
import io.papermc.generator.resources.DataFileLoader;
|
||||
import io.papermc.generator.types.craftblockdata.property.holder.VirtualField;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
@ -148,7 +149,7 @@ public final class BlockStateMapping {
|
||||
return Optional.empty();
|
||||
}).orElseGet(() -> {
|
||||
Set<Property<?>> propertySet = new HashSet<>(entry.getValue());
|
||||
for (Map.Entry<ClassNamed, List<BlockPredicate>> predicateEntry : BlockStateData.PREDICATES.entrySet()) {
|
||||
for (Map.Entry<ClassNamed, List<BlockPredicate>> predicateEntry : DataFileLoader.BlockState.PREDICATES.get().entrySet()) {
|
||||
for (BlockPredicate predicate : predicateEntry.getValue()) {
|
||||
if (predicate.test(specialBlock, propertySet)) {
|
||||
return predicateEntry.getKey();
|
||||
|
@ -1,53 +0,0 @@
|
||||
package io.papermc.generator.utils;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import io.papermc.generator.Main;
|
||||
import io.papermc.generator.utils.predicate.ItemPredicate;
|
||||
import io.papermc.typewriter.ClassNamed;
|
||||
import net.minecraft.resources.RegistryOps;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Deprecated
|
||||
public final class ItemMetaData {
|
||||
|
||||
public record BridgeData(ClassNamed api, String field) {
|
||||
|
||||
public static final Codec<BridgeData> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
SourceCodecs.CLASS_NAMED.fieldOf("api").forGetter(BridgeData::api),
|
||||
SourceCodecs.IDENTIFIER.fieldOf("field").forGetter(BridgeData::field)
|
||||
).apply(instance, BridgeData::new));
|
||||
}
|
||||
|
||||
public static final Map<ClassNamed, BridgeData> BRIDGE;
|
||||
public static final Codec<Map<ClassNamed, BridgeData>> BRIDGE_CODEC = Codec.unboundedMap(SourceCodecs.CLASS_NAMED, BridgeData.CODEC);
|
||||
static {
|
||||
try (Reader input = new BufferedReader(new InputStreamReader(ItemMetaData.class.getClassLoader().getResourceAsStream("data/item_meta/bridge.json")))) {
|
||||
JsonObject metas = SourceCodecs.GSON.fromJson(input, JsonObject.class);
|
||||
BRIDGE = BRIDGE_CODEC.parse(JsonOps.INSTANCE, metas).getOrThrow();
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static final Map<ClassNamed, List<ItemPredicate>> PREDICATES;
|
||||
public static final Codec<Map<ClassNamed, List<ItemPredicate>>> PREDICATES_CODEC = Codec.unboundedMap(SourceCodecs.CLASS_NAMED, ItemPredicate.CODEC.listOf(1, Integer.MAX_VALUE));
|
||||
static {
|
||||
try (Reader input = new BufferedReader(new InputStreamReader(ItemMetaData.class.getClassLoader().getResourceAsStream("data/item_meta/predicates.json")))) {
|
||||
JsonObject predicates = SourceCodecs.GSON.fromJson(input, JsonObject.class);
|
||||
PREDICATES = PREDICATES_CODEC.parse(RegistryOps.create(JsonOps.INSTANCE, Main.REGISTRY_ACCESS), predicates).getOrThrow();
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private ItemMetaData() {
|
||||
}
|
||||
}
|
@ -1,16 +1,12 @@
|
||||
package io.papermc.generator.utils;
|
||||
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.gson.FormattingStyle;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.DataResult;
|
||||
import com.mojang.serialization.DynamicOps;
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import io.papermc.generator.types.SimpleGenerator;
|
||||
import io.papermc.typewriter.ClassNamed;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import net.minecraft.core.Holder;
|
||||
@ -18,12 +14,13 @@ import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.RegistryFixedCodec;
|
||||
import net.minecraft.resources.RegistryOps;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@NullMarked
|
||||
public final class SourceCodecs {
|
||||
|
||||
public static final Gson GSON = new GsonBuilder().setFormattingStyle(FormattingStyle.PRETTY.withIndent(SimpleGenerator.INDENT_UNIT)).create();
|
||||
|
||||
private SourceCodecs() {
|
||||
}
|
||||
|
||||
@ -74,6 +71,8 @@ public final class SourceCodecs {
|
||||
io.papermc.generator.types.Types::typed, io.papermc.generator.rewriter.types.Types::typed
|
||||
);
|
||||
|
||||
public static final Codec<ResourceKey<? extends Registry<?>>> REGISTRY_KEY = ResourceLocation.CODEC.xmap(ResourceKey::createRegistryKey, ResourceKey::location);
|
||||
|
||||
public static <E> Codec<Either<TagKey<E>, Holder<E>>> elementOrTagCodec(ResourceKey<? extends Registry<E>> registryKey) {
|
||||
return Codec.either(RegistryAwareTagKeyCodec.hashedCodec(registryKey), RegistryFixedCodec.create(registryKey));
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import io.papermc.generator.utils.BlockStateMapping;
|
||||
import io.papermc.generator.utils.SourceCodecs;
|
||||
import net.minecraft.util.ExtraCodecs;
|
||||
import net.minecraft.util.StringRepresentable;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
@ -20,7 +22,7 @@ public sealed interface BlockPropertyPredicate permits BlockPropertyPredicate.Is
|
||||
Codec<BlockPropertyPredicate> CODEC = Codec.either(BlockPropertyPredicate.IsNamePredicate.COMPACT_CODEC, DIRECT_CODEC).xmap(Either::unwrap, Either::right);
|
||||
|
||||
Codec<Set<BlockPropertyPredicate>> SET_CODEC = CODEC.listOf().xmap(Set::copyOf, List::copyOf);
|
||||
Codec<Set<BlockPropertyPredicate>> NON_EMPTY_SET_CODEC = CODEC.listOf(1, Integer.MAX_VALUE).xmap(Set::copyOf, List::copyOf);
|
||||
Codec<Set<BlockPropertyPredicate>> NON_EMPTY_SET_CODEC = ExtraCodecs.nonEmptyList(CODEC.listOf()).xmap(Set::copyOf, List::copyOf);
|
||||
|
||||
Type type();
|
||||
|
||||
@ -79,7 +81,7 @@ public sealed interface BlockPropertyPredicate permits BlockPropertyPredicate.Is
|
||||
record IsFieldPredicate(String value) implements BlockPropertyPredicate {
|
||||
|
||||
public static final MapCodec<IsFieldPredicate> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||
Codec.STRING.fieldOf("value").forGetter(IsFieldPredicate::value)
|
||||
SourceCodecs.IDENTIFIER.fieldOf("value").forGetter(IsFieldPredicate::value)
|
||||
).apply(instance, IsFieldPredicate::new));
|
||||
|
||||
@Override
|
||||
|
@ -1,52 +1,16 @@
|
||||
package io.papermc.generator;
|
||||
|
||||
import io.papermc.generator.utils.BlockStateData;
|
||||
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 java.util.stream.Collectors;
|
||||
import io.papermc.generator.utils.ClassHelper;
|
||||
import net.minecraft.util.StringRepresentable;
|
||||
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.WallBlock;
|
||||
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;
|
||||
|
||||
public class BlockStatePropertyTest extends BootstrapTest {
|
||||
|
||||
private static Set<Class<? extends Enum<? extends StringRepresentable>>> ENUM_PROPERTY_TYPES;
|
||||
|
||||
@BeforeAll
|
||||
public static void getAllProperties() {
|
||||
// get all properties
|
||||
Set<Class<? extends Enum<? extends StringRepresentable>>> enumPropertyTypes = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||
try {
|
||||
for (Field field : BlockStateProperties.class.getDeclaredFields()) {
|
||||
if (ClassHelper.isStaticConstant(field, Modifier.PUBLIC)) {
|
||||
if (!EnumProperty.class.isAssignableFrom(field.getType())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
enumPropertyTypes.add(((EnumProperty<?>) field.get(null)).getValueClass());
|
||||
}
|
||||
}
|
||||
ENUM_PROPERTY_TYPES = Collections.unmodifiableSet(enumPropertyTypes);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReferences() throws NoSuchFieldException, IllegalAccessException {
|
||||
// if renamed should change DataPropertyWriter#FIELD_TO_BASE_NAME/FIELD_TO_BASE_NAME_SPECIFICS
|
||||
@ -56,16 +20,4 @@ public class BlockStatePropertyTest extends BootstrapTest {
|
||||
lookup.findStaticVarHandle(WallBlock.class, "PROPERTY_BY_DIRECTION", Map.class);
|
||||
lookup.findStaticVarHandle(MossyCarpetBlock.class, "PROPERTY_BY_DIRECTION", Map.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBridge() {
|
||||
Set<Class<? extends Enum<? extends StringRepresentable>>> missingApiEquivalents = new HashSet<>();
|
||||
for (Class<? extends Enum<? extends StringRepresentable>> type : ENUM_PROPERTY_TYPES) {
|
||||
if (!BlockStateData.ENUM_PROPERTY_TYPES.containsKey(type)) {
|
||||
missingApiEquivalents.add(type);
|
||||
}
|
||||
}
|
||||
|
||||
Assertions.assertTrue(missingApiEquivalents.isEmpty(), () -> "Missing some api equivalent in the block state data enum types (in block_state/enum_property_types.json) : " + missingApiEquivalents.stream().map(Class::getCanonicalName).collect(Collectors.joining(", ")));
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,8 @@
|
||||
package io.papermc.generator;
|
||||
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
|
||||
public class BootstrapTest {
|
||||
public abstract class BootstrapTest {
|
||||
|
||||
static {
|
||||
SharedConstants.tryDetectVersion();
|
||||
Bootstrap.bootStrap();
|
||||
Bootstrap.validate();
|
||||
Main.bootStrap(true);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
package io.papermc.generator;
|
||||
|
||||
import io.papermc.generator.resources.DataFile;
|
||||
import io.papermc.generator.resources.DataFileLoader;
|
||||
import io.papermc.generator.resources.MutationResult;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class DataFileTest extends BootstrapTest {
|
||||
|
||||
public static List<DataFile<?, ?, ?>> files() {
|
||||
return DataFileLoader.DATA_FILES;
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("files")
|
||||
public <V, A, R> void testFile(DataFile<V, A, R> file) {
|
||||
MutationResult<V, A, R> result = file.transmuter().transmute(file.readUnchecked());
|
||||
assertTrue(result.added().isEmpty(), () -> "Missing some data in " + file.path() + ":\n" + String.join("\n", result.added().stream().map(Object::toString).collect(Collectors.toSet())));
|
||||
assertTrue(result.removed().isEmpty(), () -> "Extra data found in " + file.path() + ":\n" + String.join("\n", result.removed().stream().map(Object::toString).collect(Collectors.toSet())));
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package io.papermc.generator;
|
||||
|
||||
import io.github.classgraph.ClassGraph;
|
||||
import io.github.classgraph.ScanResult;
|
||||
import io.papermc.generator.types.goal.MobGoalNames;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
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.assertTrue;
|
||||
|
||||
public class MobGoalConverterTest extends BootstrapTest {
|
||||
|
||||
@Test
|
||||
public void testBukkitMap() {
|
||||
final List<Class<Mob>> classes;
|
||||
try (ScanResult scanResult = new ClassGraph().enableClassInfo().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<String> missingClasses = new ArrayList<>();
|
||||
for (Class<Mob> nmsClass : classes) {
|
||||
if (!MobGoalNames.ENTITY_CLASS_NAMES.containsKey(nmsClass)) {
|
||||
missingClasses.add(nmsClass.getCanonicalName());
|
||||
}
|
||||
}
|
||||
|
||||
assertTrue(missingClasses.isEmpty(), () -> "Missing some entity classes in the bukkit map: " + String.join(", ", missingClasses));
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user