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("com.squareup:javapoet:1.13.0")
|
||||||
implementation("io.papermc.typewriter:typewriter:1.0.1")
|
implementation("io.papermc.typewriter:typewriter:1.0.1")
|
||||||
implementation("info.picocli:picocli:4.7.6")
|
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.jetbrains:annotations:26.0.2")
|
||||||
implementation("org.jspecify:jspecify:1.0.0")
|
implementation("org.jspecify:jspecify:1.0.0")
|
||||||
|
|
||||||
@ -185,6 +185,9 @@ abstract class GenerationArgumentProvider : CommandLineArgumentProvider {
|
|||||||
tasks.test {
|
tasks.test {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
}
|
}
|
||||||
|
tasks.compileTestJava {
|
||||||
|
options.compilerArgs.add("-parameters")
|
||||||
|
}
|
||||||
|
|
||||||
group = "io.papermc.paper"
|
group = "io.papermc.paper"
|
||||||
version = "1.0-SNAPSHOT"
|
version = "1.0-SNAPSHOT"
|
||||||
|
@ -2,6 +2,7 @@ package io.papermc.generator;
|
|||||||
|
|
||||||
import com.google.common.util.concurrent.MoreExecutors;
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
import com.mojang.logging.LogUtils;
|
import com.mojang.logging.LogUtils;
|
||||||
|
import io.papermc.generator.resources.DataFileLoader;
|
||||||
import io.papermc.generator.rewriter.registration.PaperPatternSourceSetRewriter;
|
import io.papermc.generator.rewriter.registration.PaperPatternSourceSetRewriter;
|
||||||
import io.papermc.generator.rewriter.registration.PatternSourceSetRewriter;
|
import io.papermc.generator.rewriter.registration.PatternSourceSetRewriter;
|
||||||
import io.papermc.generator.types.SourceGenerator;
|
import io.papermc.generator.types.SourceGenerator;
|
||||||
@ -107,8 +108,9 @@ public class Main implements Callable<Integer> {
|
|||||||
public Integer call() {
|
public Integer call() {
|
||||||
bootStrap(this.tagBootstrap).join();
|
bootStrap(this.tagBootstrap).join();
|
||||||
|
|
||||||
|
ROOT_DIR = this.rootDir;
|
||||||
|
DataFileLoader.init();
|
||||||
try {
|
try {
|
||||||
ROOT_DIR = this.rootDir;
|
|
||||||
if (this.isRewrite) {
|
if (this.isRewrite) {
|
||||||
rewrite(this.sourceSet, Rewriters.VALUES.get(this.side));
|
rewrite(this.sourceSet, Rewriters.VALUES.get(this.side));
|
||||||
} else {
|
} else {
|
||||||
|
@ -3,6 +3,7 @@ package io.papermc.generator;
|
|||||||
import com.squareup.javapoet.ClassName;
|
import com.squareup.javapoet.ClassName;
|
||||||
import io.papermc.generator.registry.RegistryBootstrapper;
|
import io.papermc.generator.registry.RegistryBootstrapper;
|
||||||
import io.papermc.generator.registry.RegistryEntries;
|
import io.papermc.generator.registry.RegistryEntries;
|
||||||
|
import io.papermc.generator.resources.DataFileLoader;
|
||||||
import io.papermc.generator.rewriter.registration.PatternSourceSetRewriter;
|
import io.papermc.generator.rewriter.registration.PatternSourceSetRewriter;
|
||||||
import io.papermc.generator.rewriter.types.Types;
|
import io.papermc.generator.rewriter.types.Types;
|
||||||
import io.papermc.generator.rewriter.types.registry.EnumRegistryRewriter;
|
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.StatisticRewriter;
|
||||||
import io.papermc.generator.rewriter.types.simple.trial.PoseRewriter;
|
import io.papermc.generator.rewriter.types.simple.trial.PoseRewriter;
|
||||||
import io.papermc.generator.rewriter.types.simple.trial.VillagerProfessionRewriter;
|
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.rewriter.types.registry.RegistriesArgumentProviderRewriter;
|
||||||
import io.papermc.generator.utils.Formatting;
|
import io.papermc.generator.utils.Formatting;
|
||||||
import io.papermc.typewriter.preset.EnumCloneRewriter;
|
import io.papermc.typewriter.preset.EnumCloneRewriter;
|
||||||
@ -189,7 +189,7 @@ public final class Rewriters {
|
|||||||
.register("MobGoalHelper#bukkitMap", Types.MOB_GOAL_HELPER, new SearchReplaceRewriter() {
|
.register("MobGoalHelper#bukkitMap", Types.MOB_GOAL_HELPER, new SearchReplaceRewriter() {
|
||||||
@Override
|
@Override
|
||||||
protected void insert(SearchMetadata metadata, StringBuilder builder) {
|
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(
|
builder.append(metadata.indent()).append("bukkitMap.put(%s.class, %s.class);".formatted(
|
||||||
entry.getKey().getCanonicalName(), this.importCollector.getShortName(Types.typed(entry.getValue()))
|
entry.getKey().getCanonicalName(), this.importCollector.getShortName(Types.typed(entry.getValue()))
|
||||||
));
|
));
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
package io.papermc.generator.registry;
|
package io.papermc.generator.registry;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.common.collect.Multimap;
|
||||||
import com.mojang.serialization.JsonOps;
|
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 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.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -19,13 +18,12 @@ import java.util.Objects;
|
|||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import io.papermc.generator.utils.SourceCodecs;
|
import net.minecraft.Util;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.core.component.DataComponents;
|
import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.core.particles.ParticleTypes;
|
import net.minecraft.core.particles.ParticleTypes;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.sounds.SoundEvents;
|
import net.minecraft.sounds.SoundEvents;
|
||||||
import net.minecraft.world.damagesource.DamageTypes;
|
import net.minecraft.world.damagesource.DamageTypes;
|
||||||
import net.minecraft.world.effect.MobEffects;
|
import net.minecraft.world.effect.MobEffects;
|
||||||
@ -63,11 +61,11 @@ import org.jspecify.annotations.NullMarked;
|
|||||||
@NullMarked
|
@NullMarked
|
||||||
public final class RegistryEntries {
|
public final class RegistryEntries {
|
||||||
|
|
||||||
private static <T> RegistryEntry.Builder<T> entry(ResourceKey<? extends Registry<T>> registryKey, Class<?> holderElementsClass) {
|
private static <T> RegistryIntern<T> entry(ResourceKey<? extends Registry<T>> registryKey, Class<?> holderElementsClass) {
|
||||||
return new RegistryEntry.Builder<>(registryKey, 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 {
|
static {
|
||||||
Map<ResourceKey<? extends Registry<?>>, RegistryKeyField<?>> registryKeyFields = new IdentityHashMap<>();
|
Map<ResourceKey<? extends Registry<?>>, RegistryKeyField<?>> registryKeyFields = new IdentityHashMap<>();
|
||||||
try {
|
try {
|
||||||
@ -89,7 +87,7 @@ public final class RegistryEntries {
|
|||||||
REGISTRY_KEY_FIELDS = Collections.unmodifiableMap(registryKeyFields);
|
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.GAME_EVENT, GameEvent.class),
|
||||||
entry(Registries.STRUCTURE_TYPE, StructureType.class),
|
entry(Registries.STRUCTURE_TYPE, StructureType.class),
|
||||||
entry(Registries.MOB_EFFECT, MobEffects.class),
|
entry(Registries.MOB_EFFECT, MobEffects.class),
|
||||||
@ -124,57 +122,49 @@ public final class RegistryEntries {
|
|||||||
entry(Registries.PARTICLE_TYPE, ParticleTypes.class),
|
entry(Registries.PARTICLE_TYPE, ParticleTypes.class),
|
||||||
entry(Registries.POTION, Potions.class),
|
entry(Registries.POTION, Potions.class),
|
||||||
entry(Registries.MEMORY_MODULE_TYPE, MemoryModuleType.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
|
@Deprecated
|
||||||
public static final List<RegistryEntry<?>> API_ONLY = new ArrayList<>();
|
public static final List<RegistryEntry<?>> API_ONLY = new ArrayList<>();
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static final List<ResourceKey<? extends Registry<?>>> API_ONLY_KEYS = List.of(
|
public static final List<ResourceKey<? extends Registry<?>>> API_ONLY_KEYS = List.of(
|
||||||
Registries.ENTITY_TYPE, Registries.PARTICLE_TYPE, Registries.POTION, Registries.MEMORY_MODULE_TYPE
|
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());
|
List<ResourceKey<? extends Registry<?>>> remainingRegistries = new ArrayList<>(EXPOSED_REGISTRIES.keySet());
|
||||||
for (RegistryEntry.Type type : RegistryEntry.Type.values()) {
|
DataFileLoader.REGISTRIES.forEach((type, file) -> {
|
||||||
try (Reader input = new BufferedReader(new InputStreamReader(RegistryEntries.class.getClassLoader().getResourceAsStream("data/registry/%s.json".formatted(type.getSerializedName()))))) {
|
Map<ResourceKey<? extends Registry<?>>, RegistryData> registries = file.get();
|
||||||
JsonObject registries = SourceCodecs.GSON.fromJson(input, JsonObject.class);
|
for (Map.Entry<ResourceKey<? extends Registry<?>>, RegistryData> registry : registries.entrySet()) {
|
||||||
for (String rawRegistryKey : registries.keySet()) {
|
ResourceKey<? extends Registry<?>> registryKey = registry.getKey();
|
||||||
ResourceKey<? extends Registry<?>> registryKey = ResourceKey.createRegistryKey(ResourceLocation.parse(rawRegistryKey));
|
RegistryEntry<?> entry = EXPOSED_REGISTRIES.get(registryKey).bind(registry.getValue());
|
||||||
RegistryData data = type.getDataCodec().parse(JsonOps.INSTANCE, registries.get(rawRegistryKey)).getOrThrow();
|
entry.validate(type);
|
||||||
RegistryEntry<?> entry = EXPOSED_REGISTRIES.get(registryKey)
|
if (remainingRegistries.remove(registryKey)) {
|
||||||
.type(type)
|
if (API_ONLY_KEYS.contains(registryKey)) {
|
||||||
.registryKeyField((RegistryKeyField) REGISTRY_KEY_FIELDS.get(registryKey))
|
API_ONLY.add(entry);
|
||||||
.data(data)
|
|
||||||
.build();
|
|
||||||
entry.validate();
|
|
||||||
if (remainingRegistries.remove(registryKey)) {
|
|
||||||
if (API_ONLY_KEYS.contains(registryKey)) {
|
|
||||||
API_ONLY.add(entry);
|
|
||||||
} else {
|
|
||||||
type.getEntries().add(entry);
|
|
||||||
}
|
|
||||||
} else {
|
} 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()) {
|
if (!remainingRegistries.isEmpty()) {
|
||||||
throw new IllegalStateException("Registry not found in data files: " + remainingRegistries);
|
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;
|
public static final Map<ResourceKey<? extends Registry<?>>, RegistryEntry<?>> BY_REGISTRY_KEY;
|
||||||
static {
|
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 -> {
|
forEach(entry -> {
|
||||||
byRegistryKey.put(entry.getRegistryKey(), 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);
|
BY_REGISTRY_KEY = Collections.unmodifiableMap(byRegistryKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,12 +175,12 @@ public final class RegistryEntries {
|
|||||||
|
|
||||||
// real registries
|
// real registries
|
||||||
public static void forEach(Consumer<RegistryEntry<?>> callback) {
|
public static void forEach(Consumer<RegistryEntry<?>> callback) {
|
||||||
forEach(callback, RegistryEntries.BUILT_IN, RegistryEntries.DATA_DRIVEN);
|
forEach(callback, REGISTRIES.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SafeVarargs
|
@SafeVarargs
|
||||||
public static void forEach(Consumer<RegistryEntry<?>> callback, List<RegistryEntry<?>>... datas) {
|
public static void forEach(Consumer<RegistryEntry<?>> callback, Collection<RegistryEntry<?>>... datas) {
|
||||||
for (List<RegistryEntry<?>> data : datas) {
|
for (Collection<RegistryEntry<?>> data : datas) {
|
||||||
for (RegistryEntry<?> entry : data) {
|
for (RegistryEntry<?> entry : data) {
|
||||||
callback.accept(entry);
|
callback.accept(entry);
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
package io.papermc.generator.registry;
|
package io.papermc.generator.registry;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
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.Main;
|
||||||
|
import io.papermc.generator.resources.RegistryData;
|
||||||
import io.papermc.generator.utils.ClassHelper;
|
import io.papermc.generator.utils.ClassHelper;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
@ -18,68 +16,23 @@ import net.minecraft.core.Registry;
|
|||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.util.StringRepresentable;
|
import net.minecraft.util.StringRepresentable;
|
||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|
||||||
import org.jspecify.annotations.NullMarked;
|
import org.jspecify.annotations.NullMarked;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
@NullMarked
|
@NullMarked
|
||||||
public final class RegistryEntry<T> implements RegistryIdentifiable<T> {
|
public 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final ResourceKey<? extends Registry<T>> registryKey;
|
private final ResourceKey<? extends Registry<T>> registryKey;
|
||||||
private final RegistryKeyField<T> registryKeyField;
|
private final RegistryKeyField<T> registryKeyField;
|
||||||
private final Class<T> elementClass;
|
|
||||||
private final Class<?> holderElementsClass;
|
private final Class<?> holderElementsClass;
|
||||||
private final Type type;
|
|
||||||
private final RegistryData data;
|
private final RegistryData data;
|
||||||
|
|
||||||
private @Nullable Map<ResourceKey<T>, String> fieldNames;
|
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.registryKey = registryKey;
|
||||||
this.registryKeyField = registryKeyField;
|
this.registryKeyField = registryKeyField;
|
||||||
this.elementClass = registryKeyField.elementClass();
|
|
||||||
this.holderElementsClass = holderElementsClass;
|
this.holderElementsClass = holderElementsClass;
|
||||||
this.type = type;
|
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +46,7 @@ public final class RegistryEntry<T> implements RegistryIdentifiable<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Class<T> elementClass() {
|
public Class<T> elementClass() {
|
||||||
return this.elementClass;
|
return this.registryKeyField.elementClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String registryKeyField() {
|
public String registryKeyField() {
|
||||||
@ -104,11 +57,13 @@ public final class RegistryEntry<T> implements RegistryIdentifiable<T> {
|
|||||||
return this.data;
|
return this.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validate() {
|
protected void validate(Type type) {
|
||||||
boolean isBuiltIn = this.type == Type.BUILT_IN;
|
Preconditions.checkState(type != Type.BUILT_IN || !this.data.impl().delayed(), "Built-in registry '%s' cannot be delayed!", this.registryKey.location());
|
||||||
Type realType = this.type == Type.BUILT_IN ? Type.DATA_DRIVEN : Type.BUILT_IN;
|
|
||||||
|
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
|
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.data.api().klass().simpleName();
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.elementClass.getSimpleName();
|
return this.elementClass().getSimpleName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean allowCustomKeys() {
|
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) {
|
private <TO> Map<ResourceKey<T>, TO> getFields(Map<ResourceKey<T>, TO> map, Function<Field, @Nullable TO> transform) {
|
||||||
Registry<T> registry = this.registry();
|
Registry<T> registry = this.registry();
|
||||||
|
Class<T> elementClass = this.elementClass();
|
||||||
try {
|
try {
|
||||||
for (Field field : this.holderElementsClass.getDeclaredFields()) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ClassHelper.isStaticConstant(field, Modifier.PUBLIC)) {
|
if (ClassHelper.isStaticConstant(field, Modifier.PUBLIC)) {
|
||||||
ResourceKey<T> key = null;
|
ResourceKey<T> key = null;
|
||||||
if (this.elementClass.isAssignableFrom(field.getType())) {
|
if (elementClass.isAssignableFrom(field.getType())) {
|
||||||
key = registry.getResourceKey(this.elementClass.cast(field.get(null))).orElseThrow();
|
key = registry.getResourceKey(elementClass.cast(field.get(null))).orElseThrow();
|
||||||
} else {
|
} else {
|
||||||
if (field.getGenericType() instanceof ParameterizedType complexType && complexType.getActualTypeArguments().length == 1 &&
|
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())) {
|
if (Holder.Reference.class.isAssignableFrom(field.getType())) {
|
||||||
key = ((Holder.Reference<T>) field.get(null)).key();
|
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 {
|
public enum Type implements StringRepresentable {
|
||||||
|
|
||||||
DATA_DRIVEN("data_driven", RegistryEntries.DATA_DRIVEN),
|
BUILT_IN("built_in"),
|
||||||
BUILT_IN("built_in", RegistryEntries.BUILT_IN, RegistryData.UNSAFE_CODEC.validate(data -> {
|
DATA_DRIVEN("data_driven");
|
||||||
return data.impl().delayed() ? DataResult.error(() -> "Built-in registry cannot be delayed!") : DataResult.success(data);
|
|
||||||
}));
|
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final List<RegistryEntry<?>> entries;
|
Type(String name) {
|
||||||
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) {
|
|
||||||
this.name = 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
|
@Override
|
||||||
|
@ -2,7 +2,9 @@ package io.papermc.generator.registry;
|
|||||||
|
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
||||||
|
|
||||||
|
@NullMarked
|
||||||
public interface RegistryIdentifiable<T> {
|
public interface RegistryIdentifiable<T> {
|
||||||
|
|
||||||
ResourceKey<? extends Registry<T>> getRegistryKey();
|
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.Codec;
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
@ -18,7 +18,7 @@ public record RegistryData(
|
|||||||
boolean allowInline
|
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),
|
Api.CODEC.fieldOf("api").forGetter(RegistryData::api),
|
||||||
Impl.CODEC.fieldOf("impl").forGetter(RegistryData::impl),
|
Impl.CODEC.fieldOf("impl").forGetter(RegistryData::impl),
|
||||||
Builder.CODEC.optionalFieldOf("builder").forGetter(RegistryData::builder),
|
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;
|
package io.papermc.generator.rewriter.types.registry;
|
||||||
|
|
||||||
import com.google.common.base.CaseFormat;
|
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.RegistryEntries;
|
||||||
import io.papermc.generator.registry.RegistryEntry;
|
import io.papermc.generator.registry.RegistryEntry;
|
||||||
import io.papermc.generator.rewriter.types.Types;
|
import io.papermc.generator.rewriter.types.Types;
|
||||||
@ -12,7 +12,7 @@ import net.minecraft.core.registries.Registries;
|
|||||||
|
|
||||||
public class PaperRegistriesRewriter extends SearchReplaceRewriter {
|
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(indent);
|
||||||
builder.append("start");
|
builder.append("start");
|
||||||
builder.append('(');
|
builder.append('(');
|
||||||
@ -54,7 +54,7 @@ public class PaperRegistriesRewriter extends SearchReplaceRewriter {
|
|||||||
builder.append(')');
|
builder.append(')');
|
||||||
}, () -> builder.append(".build()"));
|
}, () -> builder.append(".build()"));
|
||||||
}
|
}
|
||||||
if (canBeDelayed && data.impl().delayed()) {
|
if (data.impl().delayed()) {
|
||||||
builder.append(".delayed()");
|
builder.append(".delayed()");
|
||||||
}
|
}
|
||||||
builder.append(',');
|
builder.append(',');
|
||||||
@ -63,27 +63,22 @@ public class PaperRegistriesRewriter extends SearchReplaceRewriter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void insert(SearchMetadata metadata, StringBuilder builder) {
|
public void insert(SearchMetadata metadata, StringBuilder builder) {
|
||||||
builder.append(metadata.indent()).append("// built-in");
|
for (RegistryEntry.Type type : RegistryEntry.Type.values()) {
|
||||||
builder.append('\n');
|
builder.append(metadata.indent()).append("// ").append(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, type.getSerializedName()));
|
||||||
|
builder.append('\n');
|
||||||
|
|
||||||
for (RegistryEntry<?> entry : RegistryEntries.BUILT_IN) {
|
for (RegistryEntry<?> entry : RegistryEntries.byType(type)) {
|
||||||
appendEntry(metadata.indent(), builder, entry, false, false);
|
appendEntry(metadata.indent(), builder, entry, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.append('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
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(metadata.indent()).append("// api-only");
|
||||||
builder.append('\n');
|
builder.append('\n');
|
||||||
|
|
||||||
for (RegistryEntry<?> entry : RegistryEntries.API_ONLY) {
|
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...
|
builder.deleteCharAt(builder.length() - 2); // delete extra comma...
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package io.papermc.generator.rewriter.types.registry;
|
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.registry.RegistryEntries;
|
||||||
import io.papermc.generator.rewriter.types.Types;
|
import io.papermc.generator.rewriter.types.Types;
|
||||||
import io.papermc.typewriter.replace.SearchMetadata;
|
import io.papermc.typewriter.replace.SearchMetadata;
|
||||||
@ -16,17 +16,17 @@ public class RegistryEventsRewriter extends SearchReplaceRewriter {
|
|||||||
public void insert(SearchMetadata metadata, StringBuilder builder) {
|
public void insert(SearchMetadata metadata, StringBuilder builder) {
|
||||||
RegistryEntries.forEach(entry -> {
|
RegistryEntries.forEach(entry -> {
|
||||||
RegistryData data = entry.data();
|
RegistryData data = entry.data();
|
||||||
if (data.builder().isPresent()) {
|
data.builder().ifPresent(b -> {
|
||||||
builder.append(metadata.indent());
|
builder.append(metadata.indent());
|
||||||
builder.append("%s %s %s ".formatted(PUBLIC, STATIC, FINAL));
|
builder.append("%s %s %s ".formatted(PUBLIC, STATIC, FINAL));
|
||||||
builder.append(Types.REGISTRY_EVENT_PROVIDER.simpleName());
|
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(' ');
|
||||||
builder.append(entry.registryKeyField());
|
builder.append(entry.registryKeyField());
|
||||||
builder.append(" = ");
|
builder.append(" = ");
|
||||||
builder.append("create(").append(Types.REGISTRY_KEY.simpleName()).append('.').append(entry.registryKeyField()).append(");");
|
builder.append("create(").append(Types.REGISTRY_KEY.simpleName()).append('.').append(entry.registryKeyField()).append(");");
|
||||||
builder.append('\n');
|
builder.append('\n');
|
||||||
}
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package io.papermc.generator.rewriter.types.registry;
|
package io.papermc.generator.rewriter.types.registry;
|
||||||
|
|
||||||
import com.google.common.base.Suppliers;
|
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.RegistryEntries;
|
||||||
import io.papermc.generator.registry.RegistryEntry;
|
import io.papermc.generator.registry.RegistryEntry;
|
||||||
import io.papermc.generator.registry.RegistryIdentifiable;
|
import io.papermc.generator.registry.RegistryIdentifiable;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package io.papermc.generator.rewriter.types.simple;
|
package io.papermc.generator.rewriter.types.simple;
|
||||||
|
|
||||||
import io.papermc.generator.registry.RegistryEntries;
|
import io.papermc.generator.registry.RegistryEntries;
|
||||||
|
import io.papermc.generator.resources.DataFileLoader;
|
||||||
import io.papermc.generator.rewriter.types.Types;
|
import io.papermc.generator.rewriter.types.Types;
|
||||||
import io.papermc.generator.utils.Formatting;
|
import io.papermc.generator.utils.Formatting;
|
||||||
import io.papermc.generator.utils.ItemMetaData;
|
|
||||||
import io.papermc.generator.utils.predicate.ItemPredicate;
|
import io.papermc.generator.utils.predicate.ItemPredicate;
|
||||||
import io.papermc.typewriter.ClassNamed;
|
import io.papermc.typewriter.ClassNamed;
|
||||||
import io.papermc.typewriter.context.IndentUnit;
|
import io.papermc.typewriter.context.IndentUnit;
|
||||||
@ -25,8 +25,8 @@ public class CraftItemMetasRewriter extends SearchReplaceRewriter {
|
|||||||
protected void insert(SearchMetadata metadata, StringBuilder builder) {
|
protected void insert(SearchMetadata metadata, StringBuilder builder) {
|
||||||
IndentUnit indentUnit = this.indentUnit();
|
IndentUnit indentUnit = this.indentUnit();
|
||||||
ClassNamed itemType = RegistryEntries.byRegistryKey(Registries.ITEM).data().api().klass();
|
ClassNamed itemType = RegistryEntries.byRegistryKey(Registries.ITEM).data().api().klass();
|
||||||
for (Map.Entry<ClassNamed, List<ItemPredicate>> entry : ItemMetaData.PREDICATES.entrySet()) {
|
for (Map.Entry<ClassNamed, List<ItemPredicate>> entry : DataFileLoader.ItemMeta.PREDICATES.get().entrySet()) {
|
||||||
String field = ItemMetaData.BRIDGE.get(entry.getKey()).field();
|
String field = DataFileLoader.ItemMeta.BRIDGE.get().get(entry.getKey()).field();
|
||||||
Iterator<ItemPredicate> predicateIterator = entry.getValue().iterator();
|
Iterator<ItemPredicate> predicateIterator = entry.getValue().iterator();
|
||||||
|
|
||||||
builder.append(metadata.indent());
|
builder.append(metadata.indent());
|
||||||
|
@ -1,73 +1,27 @@
|
|||||||
package io.papermc.generator.rewriter.types.simple;
|
package io.papermc.generator.rewriter.types.simple;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import io.papermc.generator.resources.DataFileLoader;
|
||||||
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.rewriter.types.registry.EnumRegistryRewriter;
|
import io.papermc.generator.rewriter.types.registry.EnumRegistryRewriter;
|
||||||
import io.papermc.generator.utils.SourceCodecs;
|
import io.papermc.generator.resources.EntityTypeData;
|
||||||
import io.papermc.typewriter.ClassNamed;
|
|
||||||
import io.papermc.typewriter.preset.model.EnumValue;
|
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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.util.ExtraCodecs;
|
|
||||||
import net.minecraft.world.entity.EntityType;
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
|
||||||
import static io.papermc.generator.utils.Formatting.quoted;
|
import static io.papermc.generator.utils.Formatting.quoted;
|
||||||
|
|
||||||
public class EntityTypeRewriter extends EnumRegistryRewriter<EntityType<?>> {
|
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() {
|
public EntityTypeRewriter() {
|
||||||
super(Registries.ENTITY_TYPE, false);
|
super(Registries.ENTITY_TYPE, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected EnumValue.Builder rewriteEnumValue(Holder.Reference<EntityType<?>> reference) {
|
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();
|
String path = reference.key().location().getPath();
|
||||||
List<String> arguments = new ArrayList<>(4);
|
List<String> arguments = new ArrayList<>(4);
|
||||||
arguments.add(quoted(path));
|
arguments.add(quoted(path));
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package io.papermc.generator.rewriter.types.simple;
|
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.Types;
|
||||||
import io.papermc.generator.rewriter.types.registry.RegistryFieldRewriter;
|
import io.papermc.generator.rewriter.types.registry.RegistryFieldRewriter;
|
||||||
import io.papermc.generator.utils.ItemMetaData;
|
|
||||||
import io.papermc.generator.utils.predicate.ItemPredicate;
|
import io.papermc.generator.utils.predicate.ItemPredicate;
|
||||||
import io.papermc.typewriter.ClassNamed;
|
import io.papermc.typewriter.ClassNamed;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
@ -27,7 +27,7 @@ public class ItemTypeRewriter extends RegistryFieldRewriter<Item> {
|
|||||||
|
|
||||||
ClassNamed implMetaName = null;
|
ClassNamed implMetaName = null;
|
||||||
mainLoop:
|
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()) {
|
for (ItemPredicate predicate : entry.getValue()) {
|
||||||
if (predicate.test(reference)) {
|
if (predicate.test(reference)) {
|
||||||
implMetaName = entry.getKey();
|
implMetaName = entry.getKey();
|
||||||
@ -38,7 +38,7 @@ public class ItemTypeRewriter extends RegistryFieldRewriter<Item> {
|
|||||||
|
|
||||||
ClassNamed metaName = null;
|
ClassNamed metaName = null;
|
||||||
if (implMetaName != 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());
|
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;
|
package io.papermc.generator.tasks;
|
||||||
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.mojang.logging.LogUtils;
|
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.Main;
|
||||||
import io.papermc.generator.registry.RegistryEntries;
|
import io.papermc.generator.resources.DataFile;
|
||||||
import io.papermc.generator.rewriter.types.simple.EntityTypeRewriter;
|
import io.papermc.generator.resources.DataFileLoader;
|
||||||
import io.papermc.generator.types.goal.MobGoalNames;
|
import io.papermc.generator.resources.MutationResult;
|
||||||
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 org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import java.io.IOException;
|
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.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 {
|
public class PrepareInputFiles {
|
||||||
|
|
||||||
@ -59,140 +17,23 @@ public class PrepareInputFiles {
|
|||||||
|
|
||||||
private static final Logger LOGGER = LogUtils.getLogger();
|
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())) {
|
|
||||||
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 {
|
public static void main(String[] args) throws IOException {
|
||||||
Path resourceDir = Path.of(args[0]);
|
Path resourceDir = Path.of(args[0]);
|
||||||
for (DataFile<?> file : DATA_FILES) {
|
for (DataFile<?, ?, ?> file : DataFileLoader.DATA_FILES) {
|
||||||
Path filePath = Path.of("data", file.path());
|
if (!file.isMutable()) {
|
||||||
Path resourcePath = resourceDir.resolve(filePath);
|
continue;
|
||||||
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);
|
|
||||||
|
|
||||||
if (!result.added().isEmpty()) {
|
Path filePath = Path.of(file.path());
|
||||||
LOGGER.info("Added the following elements in {}:", filePath);
|
MutationResult<?, ?, ?> result = file.upgrade(resourceDir.resolve(filePath));
|
||||||
result.added().stream().map(Object::toString).forEach(LOGGER::info);
|
|
||||||
}
|
if (!result.added().isEmpty()) {
|
||||||
if (!result.removed().isEmpty()) {
|
LOGGER.info("Added the following elements in {}:", filePath);
|
||||||
LOGGER.warn("Removed the following keys in {}:", filePath);
|
result.added().stream().map(o -> "- " + o).forEach(LOGGER::info);
|
||||||
result.removed().stream().map(Object::toString).forEach(LOGGER::info);
|
}
|
||||||
}
|
if (!result.removed().isEmpty()) {
|
||||||
|
LOGGER.warn("Removed the following keys in {}:", filePath);
|
||||||
|
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.MethodSpec;
|
||||||
import com.squareup.javapoet.ParameterizedTypeName;
|
import com.squareup.javapoet.ParameterizedTypeName;
|
||||||
import com.squareup.javapoet.TypeName;
|
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.util.StringRepresentable;
|
||||||
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
||||||
import org.jspecify.annotations.NullMarked;
|
import org.jspecify.annotations.NullMarked;
|
||||||
@ -27,7 +27,7 @@ public class EnumPropertyWriter<T extends Enum<T> & StringRepresentable> extends
|
|||||||
@Override
|
@Override
|
||||||
protected TypeName processApiType() {
|
protected TypeName processApiType() {
|
||||||
Class<?> rawClass = this.property.getValueClass();
|
Class<?> rawClass = this.property.getValueClass();
|
||||||
return BlockStateData.ENUM_PROPERTY_TYPES.get(rawClass);
|
return DataFileLoader.BlockState.ENUM_PROPERTY_TYPES.get().get(rawClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -11,9 +11,9 @@ import io.papermc.generator.types.Types;
|
|||||||
import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator;
|
import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator;
|
||||||
import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase;
|
import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase;
|
||||||
import io.papermc.generator.types.craftblockdata.property.holder.appender.DataAppenders;
|
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.ClassHelper;
|
||||||
import io.papermc.generator.utils.CommonVariable;
|
import io.papermc.generator.utils.CommonVariable;
|
||||||
|
import io.papermc.generator.resources.DataFileLoader;
|
||||||
import io.papermc.generator.utils.NamingManager;
|
import io.papermc.generator.utils.NamingManager;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
@ -80,7 +80,7 @@ public class DataPropertyWriter extends DataPropertyWriterBase {
|
|||||||
this.type = DataHolderType.MAP;
|
this.type = DataHolderType.MAP;
|
||||||
this.internalIndexClass = ClassHelper.eraseType(complexType.getActualTypeArguments()[0]);
|
this.internalIndexClass = ClassHelper.eraseType(complexType.getActualTypeArguments()[0]);
|
||||||
if (this.internalIndexClass.isEnum()) {
|
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) {
|
if (indexClass == null) {
|
||||||
indexClass = TypeName.get(this.internalIndexClass);
|
indexClass = TypeName.get(this.internalIndexClass);
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import java.util.Comparator;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Stream;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.state.properties.Property;
|
import net.minecraft.world.level.block.state.properties.Property;
|
||||||
import org.jspecify.annotations.NullMarked;
|
import org.jspecify.annotations.NullMarked;
|
||||||
@ -18,18 +19,14 @@ import org.jspecify.annotations.NullMarked;
|
|||||||
@NullMarked
|
@NullMarked
|
||||||
public abstract class DataPropertyWriterBase implements DataPropertyMaker {
|
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 final Class<? extends Block> blockClass;
|
||||||
|
|
||||||
protected DataPropertyWriterBase(Collection<? extends Property<?>> properties, 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;
|
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) {
|
protected void createSyntheticCollection(CodeBlock.Builder code, boolean isArray, Map<Property<?>, Field> fields) {
|
||||||
if (isArray) {
|
if (isArray) {
|
||||||
code.add("{\n");
|
code.add("{\n");
|
||||||
@ -37,12 +34,12 @@ public abstract class DataPropertyWriterBase implements DataPropertyMaker {
|
|||||||
code.add("$T.of(\n", List.class);
|
code.add("$T.of(\n", List.class);
|
||||||
}
|
}
|
||||||
code.indent();
|
code.indent();
|
||||||
Iterator<? extends Property<?>> it = this.sortedIterator();
|
Iterator<? extends Property<?>> properties = this.properties.iterator();
|
||||||
while (it.hasNext()) {
|
while (properties.hasNext()) {
|
||||||
Property<?> property = it.next();
|
Property<?> property = properties.next();
|
||||||
Pair<Class<?>, String> fieldName = PropertyWriter.referenceField(this.blockClass, property, fields);
|
Pair<Class<?>, String> fieldName = PropertyWriter.referenceField(this.blockClass, property, fields);
|
||||||
code.add("$T.$L", fieldName.left(), fieldName.right());
|
code.add("$T.$L", fieldName.left(), fieldName.right());
|
||||||
if (it.hasNext()) {
|
if (properties.hasNext()) {
|
||||||
code.add(",");
|
code.add(",");
|
||||||
}
|
}
|
||||||
code.add("\n");
|
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) {
|
protected void createSyntheticMap(CodeBlock.Builder code, TypeName indexClass, Map<Property<?>, Field> fields) {
|
||||||
// assume indexClass is an enum with its values matching the property names
|
// assume indexClass is an enum with its values matching the property names
|
||||||
code.add("$T.of(\n", Map.class).indent();
|
code.add("$T.of(\n", Map.class).indent();
|
||||||
Iterator<? extends Property<?>> it = this.sortedIterator();
|
Iterator<? extends Property<?>> properties = this.properties.iterator();
|
||||||
while (it.hasNext()) {
|
while (properties.hasNext()) {
|
||||||
Property<?> property = it.next();
|
Property<?> property = properties.next();
|
||||||
String name = Formatting.formatKeyAsField(property.getName());
|
String name = Formatting.formatKeyAsField(property.getName());
|
||||||
Pair<Class<?>, String> fieldName = PropertyWriter.referenceField(this.blockClass, property, fields);
|
Pair<Class<?>, String> fieldName = PropertyWriter.referenceField(this.blockClass, property, fields);
|
||||||
code.add("$T.$L, $T.$L", indexClass, name, fieldName.left(), fieldName.right());
|
code.add("$T.$L, $T.$L", indexClass, name, fieldName.left(), fieldName.right());
|
||||||
if (it.hasNext()) {
|
if (properties.hasNext()) {
|
||||||
code.add(",");
|
code.add(",");
|
||||||
}
|
}
|
||||||
code.add("\n");
|
code.add("\n");
|
||||||
|
@ -10,7 +10,7 @@ import com.squareup.javapoet.TypeName;
|
|||||||
import com.squareup.javapoet.TypeSpec;
|
import com.squareup.javapoet.TypeSpec;
|
||||||
import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator;
|
import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator;
|
||||||
import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase;
|
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 io.papermc.generator.utils.NamingManager;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -54,7 +54,7 @@ public class VirtualDataPropertyWriter extends DataPropertyWriterBase {
|
|||||||
} else {
|
} else {
|
||||||
Class<?> valueClass = this.properties.iterator().next().getValueClass();
|
Class<?> valueClass = this.properties.iterator().next().getValueClass();
|
||||||
if (valueClass.isEnum()) {
|
if (valueClass.isEnum()) {
|
||||||
this.indexClass = BlockStateData.ENUM_PROPERTY_TYPES.get(valueClass);
|
this.indexClass = DataFileLoader.BlockState.ENUM_PROPERTY_TYPES.get().get(valueClass);
|
||||||
} else {
|
} else {
|
||||||
this.indexClass = TypeName.get(valueClass);
|
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.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
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.ClassName;
|
||||||
import com.squareup.javapoet.FieldSpec;
|
import com.squareup.javapoet.FieldSpec;
|
||||||
import com.squareup.javapoet.MethodSpec;
|
import com.squareup.javapoet.MethodSpec;
|
||||||
@ -12,23 +9,16 @@ import com.squareup.javapoet.ParameterSpec;
|
|||||||
import com.squareup.javapoet.ParameterizedTypeName;
|
import com.squareup.javapoet.ParameterizedTypeName;
|
||||||
import com.squareup.javapoet.TypeName;
|
import com.squareup.javapoet.TypeName;
|
||||||
import com.squareup.javapoet.TypeSpec;
|
import com.squareup.javapoet.TypeSpec;
|
||||||
|
import io.papermc.generator.resources.DataFileLoader;
|
||||||
import io.papermc.generator.types.Types;
|
import io.papermc.generator.types.Types;
|
||||||
import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator;
|
import io.papermc.generator.types.craftblockdata.CraftBlockDataGenerator;
|
||||||
import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase;
|
import io.papermc.generator.types.craftblockdata.property.converter.ConverterBase;
|
||||||
import io.papermc.generator.types.craftblockdata.property.holder.DataHolderType;
|
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.CommonVariable;
|
||||||
import io.papermc.generator.utils.NamingManager;
|
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.Collections;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
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 net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||||
import org.jspecify.annotations.NullMarked;
|
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()
|
private static final Map<String, String> INDEX_NAMES = ImmutableMap.<String, String>builder()
|
||||||
.put(Types.BLOCK_FACE.simpleName(), "Face")
|
.put(Types.BLOCK_FACE.simpleName(), "Face")
|
||||||
.buildOrThrow();
|
.buildOrThrow();
|
||||||
|
// todo find another way for extra method and clean up those hardcoded things ^
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataHolderType getType() {
|
public DataHolderType getType() {
|
||||||
@ -80,7 +56,7 @@ public class MapAppender implements DataAppender {
|
|||||||
builder.addMethod(methodBuilder.build());
|
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()) {
|
indexParameter.type instanceof ClassName className && !className.isBoxedPrimitive()) {
|
||||||
NamingManager.NameWrapper indexNaming = NamingManager.NameWrapper.wrap("get", INDEX_NAMES.getOrDefault(className.simpleName(), className.simpleName()));
|
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));
|
.returns(ParameterizedTypeName.get(Types.GOAL_KEY, type));
|
||||||
|
|
||||||
List<Class<Goal>> classes;
|
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);
|
classes = scanResult.getSubclasses(Goal.class.getName()).loadClasses(Goal.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,22 +1,14 @@
|
|||||||
package io.papermc.generator.types.goal;
|
package io.papermc.generator.types.goal;
|
||||||
|
|
||||||
import com.google.common.base.CaseFormat;
|
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 com.squareup.javapoet.ClassName;
|
||||||
|
import io.papermc.generator.resources.DataFileLoader;
|
||||||
import io.papermc.generator.types.Types;
|
import io.papermc.generator.types.Types;
|
||||||
import io.papermc.generator.utils.SourceCodecs;
|
|
||||||
import io.papermc.generator.utils.Formatting;
|
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.lang.reflect.Constructor;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.entity.Mob;
|
|
||||||
import net.minecraft.world.entity.ai.goal.Goal;
|
import net.minecraft.world.entity.ai.goal.Goal;
|
||||||
import net.minecraft.world.entity.monster.RangedAttackMob;
|
import net.minecraft.world.entity.monster.RangedAttackMob;
|
||||||
import org.apache.commons.lang3.math.NumberUtils;
|
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
|
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<>();
|
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<>();
|
private static final Map<String, String> deobfuscationMap = new HashMap<>();
|
||||||
|
|
||||||
static {
|
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) {
|
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) {
|
if (bukkitClass == null) {
|
||||||
throw new RuntimeException("Can't figure out applicable bukkit entity for nms entity " + nmsClass); // maybe just return Mob?
|
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.google.common.collect.Multimap;
|
||||||
import com.mojang.datafixers.util.Either;
|
import com.mojang.datafixers.util.Either;
|
||||||
import io.papermc.generator.Main;
|
import io.papermc.generator.Main;
|
||||||
|
import io.papermc.generator.resources.DataFileLoader;
|
||||||
import io.papermc.generator.types.craftblockdata.property.holder.VirtualField;
|
import io.papermc.generator.types.craftblockdata.property.holder.VirtualField;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
@ -148,7 +149,7 @@ public final class BlockStateMapping {
|
|||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}).orElseGet(() -> {
|
}).orElseGet(() -> {
|
||||||
Set<Property<?>> propertySet = new HashSet<>(entry.getValue());
|
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()) {
|
for (BlockPredicate predicate : predicateEntry.getValue()) {
|
||||||
if (predicate.test(specialBlock, propertySet)) {
|
if (predicate.test(specialBlock, propertySet)) {
|
||||||
return predicateEntry.getKey();
|
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;
|
package io.papermc.generator.utils;
|
||||||
|
|
||||||
import com.google.common.reflect.TypeToken;
|
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.Either;
|
||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
import com.mojang.serialization.DataResult;
|
import com.mojang.serialization.DataResult;
|
||||||
import com.mojang.serialization.DynamicOps;
|
import com.mojang.serialization.DynamicOps;
|
||||||
import com.squareup.javapoet.ClassName;
|
import com.squareup.javapoet.ClassName;
|
||||||
import io.papermc.generator.types.SimpleGenerator;
|
|
||||||
import io.papermc.typewriter.ClassNamed;
|
import io.papermc.typewriter.ClassNamed;
|
||||||
import javax.lang.model.SourceVersion;
|
import javax.lang.model.SourceVersion;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
@ -18,12 +14,13 @@ import net.minecraft.core.Registry;
|
|||||||
import net.minecraft.resources.RegistryFixedCodec;
|
import net.minecraft.resources.RegistryFixedCodec;
|
||||||
import net.minecraft.resources.RegistryOps;
|
import net.minecraft.resources.RegistryOps;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
||||||
|
|
||||||
|
@NullMarked
|
||||||
public final class SourceCodecs {
|
public final class SourceCodecs {
|
||||||
|
|
||||||
public static final Gson GSON = new GsonBuilder().setFormattingStyle(FormattingStyle.PRETTY.withIndent(SimpleGenerator.INDENT_UNIT)).create();
|
|
||||||
|
|
||||||
private SourceCodecs() {
|
private SourceCodecs() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,6 +71,8 @@ public final class SourceCodecs {
|
|||||||
io.papermc.generator.types.Types::typed, io.papermc.generator.rewriter.types.Types::typed
|
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) {
|
public static <E> Codec<Either<TagKey<E>, Holder<E>>> elementOrTagCodec(ResourceKey<? extends Registry<E>> registryKey) {
|
||||||
return Codec.either(RegistryAwareTagKeyCodec.hashedCodec(registryKey), RegistryFixedCodec.create(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.MapCodec;
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
import io.papermc.generator.utils.BlockStateMapping;
|
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.util.StringRepresentable;
|
||||||
import net.minecraft.world.level.block.state.properties.Property;
|
import net.minecraft.world.level.block.state.properties.Property;
|
||||||
import org.jspecify.annotations.NullMarked;
|
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<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>> 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();
|
Type type();
|
||||||
|
|
||||||
@ -79,7 +81,7 @@ public sealed interface BlockPropertyPredicate permits BlockPropertyPredicate.Is
|
|||||||
record IsFieldPredicate(String value) implements BlockPropertyPredicate {
|
record IsFieldPredicate(String value) implements BlockPropertyPredicate {
|
||||||
|
|
||||||
public static final MapCodec<IsFieldPredicate> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
|
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));
|
).apply(instance, IsFieldPredicate::new));
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,52 +1,16 @@
|
|||||||
package io.papermc.generator;
|
package io.papermc.generator;
|
||||||
|
|
||||||
import io.papermc.generator.utils.BlockStateData;
|
|
||||||
import java.lang.invoke.MethodHandles;
|
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.List;
|
||||||
import java.util.Map;
|
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.ChiseledBookShelfBlock;
|
||||||
import net.minecraft.world.level.block.MossyCarpetBlock;
|
import net.minecraft.world.level.block.MossyCarpetBlock;
|
||||||
import net.minecraft.world.level.block.PipeBlock;
|
import net.minecraft.world.level.block.PipeBlock;
|
||||||
import net.minecraft.world.level.block.WallBlock;
|
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;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
public class BlockStatePropertyTest extends BootstrapTest {
|
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
|
@Test
|
||||||
public void testReferences() throws NoSuchFieldException, IllegalAccessException {
|
public void testReferences() throws NoSuchFieldException, IllegalAccessException {
|
||||||
// if renamed should change DataPropertyWriter#FIELD_TO_BASE_NAME/FIELD_TO_BASE_NAME_SPECIFICS
|
// 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(WallBlock.class, "PROPERTY_BY_DIRECTION", Map.class);
|
||||||
lookup.findStaticVarHandle(MossyCarpetBlock.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;
|
package io.papermc.generator;
|
||||||
|
|
||||||
import net.minecraft.SharedConstants;
|
public abstract class BootstrapTest {
|
||||||
import net.minecraft.server.Bootstrap;
|
|
||||||
|
|
||||||
public class BootstrapTest {
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
SharedConstants.tryDetectVersion();
|
Main.bootStrap(true);
|
||||||
Bootstrap.bootStrap();
|
|
||||||
Bootstrap.validate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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