Initial Commit

This commit is contained in:
richard committed 2026-11-13 22:25:04 +01:00
1 parent 377b32db6e
commit 2d9a5eecba
14134 files changed
+1160982

No files matched your search

@@ -0,0 +1,167 @@
package net.minecraft.resources;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.ListBuilder;
import com.mojang.serialization.MapLike;
import com.mojang.serialization.RecordBuilder;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;
/**
* A {@link DynamicOps} that delegates all functionality to an internal delegate. Comments and parameters here are
* copied from {@link DynamicOps} in DataFixerUpper.
*/
public abstract class DelegatingOps<T> implements DynamicOps<T> {
protected final DynamicOps<T> delegate;
protected DelegatingOps(DynamicOps<T> pDelegate) {
this.delegate = pDelegate;
}
public T empty() {
return this.delegate.empty();
}
public <U> U convertTo(DynamicOps<U> pOutOps, T pInput) {
return this.delegate.convertTo(pOutOps, pInput);
}
public DataResult<Number> getNumberValue(T pInput) {
return this.delegate.getNumberValue(pInput);
}
public T createNumeric(Number pI) {
return this.delegate.createNumeric(pI);
}
public T createByte(byte pValue) {
return this.delegate.createByte(pValue);
}
public T createShort(short pValue) {
return this.delegate.createShort(pValue);
}
public T createInt(int pValue) {
return this.delegate.createInt(pValue);
}
public T createLong(long pValue) {
return this.delegate.createLong(pValue);
}
public T createFloat(float pValue) {
return this.delegate.createFloat(pValue);
}
public T createDouble(double pValue) {
return this.delegate.createDouble(pValue);
}
public DataResult<Boolean> getBooleanValue(T pInput) {
return this.delegate.getBooleanValue(pInput);
}
public T createBoolean(boolean pValue) {
return this.delegate.createBoolean(pValue);
}
public DataResult<String> getStringValue(T pInput) {
return this.delegate.getStringValue(pInput);
}
public T createString(String pValue) {
return this.delegate.createString(pValue);
}
public DataResult<T> mergeToList(T pList, T pValue) {
return this.delegate.mergeToList(pList, pValue);
}
public DataResult<T> mergeToList(T pList, List<T> pValues) {
return this.delegate.mergeToList(pList, pValues);
}
public DataResult<T> mergeToMap(T pMap, T pKey, T pValue) {
return this.delegate.mergeToMap(pMap, pKey, pValue);
}
public DataResult<T> mergeToMap(T pMap, MapLike<T> pValues) {
return this.delegate.mergeToMap(pMap, pValues);
}
public DataResult<Stream<Pair<T, T>>> getMapValues(T pInput) {
return this.delegate.getMapValues(pInput);
}
public DataResult<Consumer<BiConsumer<T, T>>> getMapEntries(T pInput) {
return this.delegate.getMapEntries(pInput);
}
public T createMap(Stream<Pair<T, T>> pMap) {
return this.delegate.createMap(pMap);
}
public DataResult<MapLike<T>> getMap(T pInput) {
return this.delegate.getMap(pInput);
}
public DataResult<Stream<T>> getStream(T pInput) {
return this.delegate.getStream(pInput);
}
public DataResult<Consumer<Consumer<T>>> getList(T pInput) {
return this.delegate.getList(pInput);
}
public T createList(Stream<T> pInput) {
return this.delegate.createList(pInput);
}
public DataResult<ByteBuffer> getByteBuffer(T pInput) {
return this.delegate.getByteBuffer(pInput);
}
public T createByteList(ByteBuffer pInput) {
return this.delegate.createByteList(pInput);
}
public DataResult<IntStream> getIntStream(T pInput) {
return this.delegate.getIntStream(pInput);
}
public T createIntList(IntStream pInput) {
return this.delegate.createIntList(pInput);
}
public DataResult<LongStream> getLongStream(T pInput) {
return this.delegate.getLongStream(pInput);
}
public T createLongList(LongStream pInput) {
return this.delegate.createLongList(pInput);
}
public T remove(T pInput, String pKey) {
return this.delegate.remove(pInput, pKey);
}
public boolean compressMaps() {
return this.delegate.compressMaps();
}
public ListBuilder<T> listBuilder() {
return new ListBuilder.Builder<>(this);
}
public RecordBuilder<T> mapBuilder() {
return new RecordBuilder.MapBuilder<>(this);
}
}
@@ -0,0 +1,41 @@
package net.minecraft.resources;
import java.util.List;
import java.util.Map;
import net.minecraft.server.packs.resources.Resource;
import net.minecraft.server.packs.resources.ResourceManager;
public class FileToIdConverter {
private final String prefix;
private final String extension;
public FileToIdConverter(String pPrefix, String pExtenstion) {
this.prefix = pPrefix;
this.extension = pExtenstion;
}
public static FileToIdConverter json(String pName) {
return new FileToIdConverter(pName, ".json");
}
public ResourceLocation idToFile(ResourceLocation pId) {
return pId.withPath(this.prefix + "/" + pId.getPath() + this.extension);
}
public ResourceLocation fileToId(ResourceLocation pFile) {
String s = pFile.getPath();
return pFile.withPath(s.substring(this.prefix.length() + 1, s.length() - this.extension.length()));
}
public Map<ResourceLocation, Resource> listMatchingResources(ResourceManager pResourceManager) {
return pResourceManager.listResources(this.prefix, (p_251986_) -> {
return p_251986_.getPath().endsWith(this.extension);
});
}
public Map<ResourceLocation, List<Resource>> listMatchingResourceStacks(ResourceManager pResourceManager) {
return pResourceManager.listResourceStacks(this.prefix, (p_248700_) -> {
return p_248700_.getPath().endsWith(this.extension);
});
}
}
@@ -0,0 +1,112 @@
package net.minecraft.resources;
import com.mojang.datafixers.util.Either;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.DynamicOps;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderGetter;
import net.minecraft.core.HolderOwner;
import net.minecraft.core.HolderSet;
import net.minecraft.core.Registry;
import net.minecraft.tags.TagKey;
import net.minecraft.util.ExtraCodecs;
public class HolderSetCodec<E> implements Codec<HolderSet<E>> {
private final ResourceKey<? extends Registry<E>> registryKey;
private final Codec<Holder<E>> elementCodec;
private final Codec<List<Holder<E>>> homogenousListCodec;
private final Codec<Either<TagKey<E>, List<Holder<E>>>> registryAwareCodec;
private final Codec<net.minecraftforge.registries.holdersets.ICustomHolderSet<E>> forgeDispatchCodec;
private final Codec<Either<net.minecraftforge.registries.holdersets.ICustomHolderSet<E>, Either<TagKey<E>, List<Holder<E>>>>> combinedCodec;
private static <E> Codec<List<Holder<E>>> homogenousList(Codec<Holder<E>> pHolderCodec, boolean pDisallowInline) {
Codec<List<Holder<E>>> codec = ExtraCodecs.validate(pHolderCodec.listOf(), ExtraCodecs.ensureHomogenous(Holder::kind));
return pDisallowInline ? codec : Codec.either(codec, pHolderCodec).xmap((p_206664_) -> {
return p_206664_.map((p_206694_) -> {
return p_206694_;
}, List::of);
}, (p_206684_) -> {
return p_206684_.size() == 1 ? Either.right(p_206684_.get(0)) : Either.left(p_206684_);
});
}
public static <E> Codec<HolderSet<E>> create(ResourceKey<? extends Registry<E>> pRegistryKey, Codec<Holder<E>> pHolderCodec, boolean pDisallowInline) {
return new HolderSetCodec<>(pRegistryKey, pHolderCodec, pDisallowInline);
}
private HolderSetCodec(ResourceKey<? extends Registry<E>> p_206660_, Codec<Holder<E>> p_206661_, boolean p_206662_) {
this.registryKey = p_206660_;
this.elementCodec = p_206661_;
this.homogenousListCodec = homogenousList(p_206661_, p_206662_);
this.registryAwareCodec = Codec.either(TagKey.hashedCodec(p_206660_), this.homogenousListCodec);
// FORGE: make registry-specific dispatch codec and make forge-or-vanilla either codec
this.forgeDispatchCodec = ExtraCodecs.lazyInitializedCodec(() -> net.minecraftforge.registries.ForgeRegistries.HOLDER_SET_TYPES.get().getCodec())
.dispatch(net.minecraftforge.registries.holdersets.ICustomHolderSet::type, type -> type.makeCodec(p_206660_, p_206661_, p_206662_));
this.combinedCodec = new ExtraCodecs.EitherCodec<>(this.forgeDispatchCodec, this.registryAwareCodec);
}
public <T> DataResult<Pair<HolderSet<E>, T>> decode(DynamicOps<T> p_206696_, T p_206697_) {
if (p_206696_ instanceof RegistryOps<T> registryops) {
Optional<HolderGetter<E>> optional = registryops.getter(this.registryKey);
if (optional.isPresent()) {
HolderGetter<E> holdergetter = optional.get();
// FORGE: use the wrapped codec to decode custom/tag/list instead of just tag/list
return this.combinedCodec.decode(p_206696_, p_206697_).map((p_206682_) -> {
return p_206682_.mapFirst((p_206679_) -> {
return p_206679_.map(java.util.function.Function.identity(), tagOrList -> tagOrList.map(holdergetter::getOrThrow, HolderSet::direct));
});
});
}
}
return this.decodeWithoutRegistry(p_206696_, p_206697_);
}
public <T> DataResult<T> encode(HolderSet<E> p_206674_, DynamicOps<T> p_206675_, T p_206676_) {
if (p_206675_ instanceof RegistryOps<T> registryops) {
Optional<HolderOwner<E>> optional = registryops.owner(this.registryKey);
if (optional.isPresent()) {
if (!p_206674_.canSerializeIn(optional.get())) {
return DataResult.error(() -> {
return "HolderSet " + p_206674_ + " is not valid in current registry set";
});
}
// FORGE: use the dispatch codec to encode custom holdersets, otherwise fall back to vanilla tag/list
if (p_206674_ instanceof net.minecraftforge.registries.holdersets.ICustomHolderSet<E> customHolderSet)
return this.forgeDispatchCodec.encode(customHolderSet, p_206675_, p_206676_);
return this.registryAwareCodec.encode(p_206674_.unwrap().mapRight(List::copyOf), p_206675_, p_206676_);
}
}
return this.encodeWithoutRegistry(p_206674_, p_206675_, p_206676_);
}
private <T> DataResult<Pair<HolderSet<E>, T>> decodeWithoutRegistry(DynamicOps<T> p_206671_, T p_206672_) {
return this.elementCodec.listOf().decode(p_206671_, p_206672_).flatMap((p_206666_) -> {
List<Holder.Direct<E>> list = new ArrayList<>();
for(Holder<E> holder : p_206666_.getFirst()) {
if (!(holder instanceof Holder.Direct)) {
return DataResult.error(() -> {
return "Can't decode element " + holder + " without registry";
});
}
Holder.Direct<E> direct = (Holder.Direct)holder;
list.add(direct);
}
return DataResult.success(new Pair<>(HolderSet.direct(list), p_206666_.getSecond()));
});
}
private <T> DataResult<T> encodeWithoutRegistry(HolderSet<E> p_206690_, DynamicOps<T> p_206691_, T p_206692_) {
return this.homogenousListCodec.encode(p_206690_.stream().toList(), p_206691_, p_206692_);
}
}
@@ -0,0 +1,166 @@
package net.minecraft.resources;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.mojang.datafixers.util.Pair;
import com.mojang.logging.LogUtils;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.Decoder;
import com.mojang.serialization.JsonOps;
import com.mojang.serialization.Lifecycle;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.WritableRegistry;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.ChatType;
import net.minecraft.server.packs.resources.Resource;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.world.damagesource.DamageType;
import net.minecraft.world.item.armortrim.TrimMaterial;
import net.minecraft.world.item.armortrim.TrimPattern;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.MultiNoiseBiomeSourceParameterList;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.levelgen.DensityFunction;
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorPreset;
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
import net.minecraft.world.level.levelgen.presets.WorldPreset;
import net.minecraft.world.level.levelgen.structure.Structure;
import net.minecraft.world.level.levelgen.structure.StructureSet;
import net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorType;
import net.minecraft.world.level.levelgen.synth.NormalNoise;
import org.slf4j.Logger;
public class RegistryDataLoader {
private static final Logger LOGGER = LogUtils.getLogger();
public static final List<RegistryDataLoader.RegistryData<?>> WORLDGEN_REGISTRIES = List.of(new RegistryDataLoader.RegistryData<>(Registries.DIMENSION_TYPE, DimensionType.DIRECT_CODEC), new RegistryDataLoader.RegistryData<>(Registries.BIOME, Biome.DIRECT_CODEC), new RegistryDataLoader.RegistryData<>(Registries.CHAT_TYPE, ChatType.CODEC), new RegistryDataLoader.RegistryData<>(Registries.CONFIGURED_CARVER, ConfiguredWorldCarver.DIRECT_CODEC), new RegistryDataLoader.RegistryData<>(Registries.CONFIGURED_FEATURE, ConfiguredFeature.DIRECT_CODEC), new RegistryDataLoader.RegistryData<>(Registries.PLACED_FEATURE, PlacedFeature.DIRECT_CODEC), new RegistryDataLoader.RegistryData<>(Registries.STRUCTURE, Structure.DIRECT_CODEC), new RegistryDataLoader.RegistryData<>(Registries.STRUCTURE_SET, StructureSet.DIRECT_CODEC), new RegistryDataLoader.RegistryData<>(Registries.PROCESSOR_LIST, StructureProcessorType.DIRECT_CODEC), new RegistryDataLoader.RegistryData<>(Registries.TEMPLATE_POOL, StructureTemplatePool.DIRECT_CODEC), new RegistryDataLoader.RegistryData<>(Registries.NOISE_SETTINGS, NoiseGeneratorSettings.DIRECT_CODEC), new RegistryDataLoader.RegistryData<>(Registries.NOISE, NormalNoise.NoiseParameters.DIRECT_CODEC), new RegistryDataLoader.RegistryData<>(Registries.DENSITY_FUNCTION, DensityFunction.DIRECT_CODEC), new RegistryDataLoader.RegistryData<>(Registries.WORLD_PRESET, WorldPreset.DIRECT_CODEC), new RegistryDataLoader.RegistryData<>(Registries.FLAT_LEVEL_GENERATOR_PRESET, FlatLevelGeneratorPreset.DIRECT_CODEC), new RegistryDataLoader.RegistryData<>(Registries.TRIM_PATTERN, TrimPattern.DIRECT_CODEC), new RegistryDataLoader.RegistryData<>(Registries.TRIM_MATERIAL, TrimMaterial.DIRECT_CODEC), new RegistryDataLoader.RegistryData<>(Registries.DAMAGE_TYPE, DamageType.CODEC), new RegistryDataLoader.RegistryData<>(Registries.MULTI_NOISE_BIOME_SOURCE_PARAMETER_LIST, MultiNoiseBiomeSourceParameterList.DIRECT_CODEC));
public static final List<RegistryDataLoader.RegistryData<?>> DIMENSION_REGISTRIES = List.of(new RegistryDataLoader.RegistryData<>(Registries.LEVEL_STEM, LevelStem.CODEC));
public static RegistryAccess.Frozen load(ResourceManager pResourceManager, RegistryAccess pRegistryAccess, List<RegistryDataLoader.RegistryData<?>> pRegistryData) {
Map<ResourceKey<?>, Exception> map = new HashMap<>();
List<Pair<WritableRegistry<?>, RegistryDataLoader.Loader>> list = pRegistryData.stream().map((p_250249_) -> {
return p_250249_.create(Lifecycle.stable(), map);
}).toList();
RegistryOps.RegistryInfoLookup registryops$registryinfolookup = createContext(pRegistryAccess, list);
list.forEach((p_255508_) -> {
p_255508_.getSecond().load(pResourceManager, registryops$registryinfolookup);
});
list.forEach((p_258223_) -> {
Registry<?> registry = p_258223_.getFirst();
try {
registry.freeze();
} catch (Exception exception) {
map.put(registry.key(), exception);
}
});
if (!map.isEmpty()) {
logErrors(map);
throw new IllegalStateException("Failed to load registries due to above errors");
} else {
return (new RegistryAccess.ImmutableRegistryAccess(list.stream().map(Pair::getFirst).toList())).freeze();
}
}
private static RegistryOps.RegistryInfoLookup createContext(RegistryAccess pRegistryAccess, List<Pair<WritableRegistry<?>, RegistryDataLoader.Loader>> pRegistryLoaders) {
final Map<ResourceKey<? extends Registry<?>>, RegistryOps.RegistryInfo<?>> map = new HashMap<>();
pRegistryAccess.registries().forEach((p_255505_) -> {
map.put(p_255505_.key(), createInfoForContextRegistry(p_255505_.value()));
});
pRegistryLoaders.forEach((p_258221_) -> {
map.put(p_258221_.getFirst().key(), createInfoForNewRegistry(p_258221_.getFirst()));
});
return new RegistryOps.RegistryInfoLookup() {
public <T> Optional<RegistryOps.RegistryInfo<T>> lookup(ResourceKey<? extends Registry<? extends T>> p_256014_) {
return Optional.ofNullable((RegistryOps.RegistryInfo<T>) map.get(p_256014_));
}
};
}
private static <T> RegistryOps.RegistryInfo<T> createInfoForNewRegistry(WritableRegistry<T> pRegistry) {
return new RegistryOps.RegistryInfo<>(pRegistry.asLookup(), pRegistry.createRegistrationLookup(), pRegistry.registryLifecycle());
}
private static <T> RegistryOps.RegistryInfo<T> createInfoForContextRegistry(Registry<T> pRegistry) {
return new RegistryOps.RegistryInfo<>(pRegistry.asLookup(), pRegistry.asTagAddingLookup(), pRegistry.registryLifecycle());
}
private static void logErrors(Map<ResourceKey<?>, Exception> pErrors) {
StringWriter stringwriter = new StringWriter();
PrintWriter printwriter = new PrintWriter(stringwriter);
Map<ResourceLocation, Map<ResourceLocation, Exception>> map = pErrors.entrySet().stream().collect(Collectors.groupingBy((p_249353_) -> {
return p_249353_.getKey().registry();
}, Collectors.toMap((p_251444_) -> {
return p_251444_.getKey().location();
}, Map.Entry::getValue)));
map.entrySet().stream().sorted(Entry.comparingByKey()).forEach((p_249838_) -> {
printwriter.printf("> Errors in registry %s:%n", p_249838_.getKey());
p_249838_.getValue().entrySet().stream().sorted(Entry.comparingByKey()).forEach((p_250688_) -> {
printwriter.printf(">> Errors in element %s:%n", p_250688_.getKey());
p_250688_.getValue().printStackTrace(printwriter);
});
});
printwriter.flush();
LOGGER.error("Registry loading errors:\n{}", (Object)stringwriter);
}
private static String registryDirPath(ResourceLocation p_252033_) {
return net.minecraftforge.common.ForgeHooks.prefixNamespace(p_252033_); // FORGE: add non-vanilla registry namespace to loader directory, same format as tag directory (see net.minecraft.tags.TagManager#getTagDir(ResourceKey))
}
static <E> void loadRegistryContents(RegistryOps.RegistryInfoLookup p_256369_, ResourceManager p_256349_, ResourceKey<? extends Registry<E>> p_255792_, WritableRegistry<E> p_256211_, Decoder<E> p_256232_, Map<ResourceKey<?>, Exception> p_255884_) {
String s = registryDirPath(p_255792_.location());
FileToIdConverter filetoidconverter = FileToIdConverter.json(s);
RegistryOps<JsonElement> registryops = RegistryOps.create(JsonOps.INSTANCE, p_256369_);
for(Map.Entry<ResourceLocation, Resource> entry : filetoidconverter.listMatchingResources(p_256349_).entrySet()) {
ResourceLocation resourcelocation = entry.getKey();
ResourceKey<E> resourcekey = ResourceKey.create(p_255792_, filetoidconverter.fileToId(resourcelocation));
Resource resource = entry.getValue();
try (Reader reader = resource.openAsReader()) {
JsonElement jsonelement = JsonParser.parseReader(reader);
if (!net.minecraftforge.common.crafting.conditions.ICondition.shouldRegisterEntry(jsonelement)) continue;
DataResult<E> dataresult = p_256232_.parse(registryops, jsonelement);
E e = dataresult.getOrThrow(false, (p_248715_) -> {
});
p_256211_.register(resourcekey, e, resource.isBuiltin() ? Lifecycle.stable() : dataresult.lifecycle());
} catch (Exception exception) {
p_255884_.put(resourcekey, new IllegalStateException(String.format(Locale.ROOT, "Failed to parse %s from pack %s", resourcelocation, resource.sourcePackId()), exception));
}
}
}
interface Loader {
void load(ResourceManager pResourceManager, RegistryOps.RegistryInfoLookup pRegistryInfoLookup);
}
public static record RegistryData<T>(ResourceKey<? extends Registry<T>> key, Codec<T> elementCodec) {
Pair<WritableRegistry<?>, RegistryDataLoader.Loader> create(Lifecycle pRegistryLifecycle, Map<ResourceKey<?>, Exception> p_251565_) {
WritableRegistry<T> writableregistry = new MappedRegistry<>(this.key, pRegistryLifecycle);
RegistryDataLoader.Loader registrydataloader$loader = (p_255511_, p_255512_) -> {
RegistryDataLoader.loadRegistryContents(p_255512_, p_255511_, this.key, writableregistry, this.elementCodec, p_251565_);
};
return Pair.of(writableregistry, registrydataloader$loader);
}
}
}
@@ -0,0 +1,104 @@
package net.minecraft.resources;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.Lifecycle;
import java.util.Optional;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderGetter;
import net.minecraft.core.HolderOwner;
import net.minecraft.core.Registry;
/**
* A codec that wraps a single element, or "file", within a registry. Possibly allows inline definitions, and always
* falls back to the element codec (and thus writing the registry element inline) if it fails to decode from the
* registry.
*/
public final class RegistryFileCodec<E> implements Codec<Holder<E>> {
private final ResourceKey<? extends Registry<E>> registryKey;
private final Codec<E> elementCodec;
private final boolean allowInline;
/**
* Creates a codec for a single registry element, which is held as an un-resolved {@code Supplier<E>}. Both inline
* definitions of the object, and references to an existing registry element id are allowed.
* @param pRegistryKey The registry which elements may belong to.
* @param pElementCodec The codec used to decode either inline definitions, or elements before entering them into the
* registry.
*/
public static <E> RegistryFileCodec<E> create(ResourceKey<? extends Registry<E>> pRegistryKey, Codec<E> pElementCodec) {
return create(pRegistryKey, pElementCodec, true);
}
public static <E> RegistryFileCodec<E> create(ResourceKey<? extends Registry<E>> pRegistryKey, Codec<E> pElementCodec, boolean pAllowInline) {
return new RegistryFileCodec<>(pRegistryKey, pElementCodec, pAllowInline);
}
private RegistryFileCodec(ResourceKey<? extends Registry<E>> pRegistryKey, Codec<E> pElementCodec, boolean pAllowInline) {
this.registryKey = pRegistryKey;
this.elementCodec = pElementCodec;
this.allowInline = pAllowInline;
}
public <T> DataResult<T> encode(Holder<E> pInput, DynamicOps<T> pOps, T pPrefix) {
if (pOps instanceof RegistryOps<?> registryops) {
Optional<HolderOwner<E>> optional = registryops.owner(this.registryKey);
if (optional.isPresent()) {
if (!pInput.canSerializeIn(optional.get())) {
return DataResult.error(() -> {
return "Element " + pInput + " is not valid in current registry set";
});
}
return pInput.unwrap().map((p_206714_) -> {
return ResourceLocation.CODEC.encode(p_206714_.location(), pOps, pPrefix);
}, (p_206710_) -> {
return this.elementCodec.encode(p_206710_, pOps, pPrefix);
});
}
}
return this.elementCodec.encode(pInput.value(), pOps, pPrefix);
}
public <T> DataResult<Pair<Holder<E>, T>> decode(DynamicOps<T> pOps, T pInput) {
if (pOps instanceof RegistryOps<?> registryops) {
Optional<HolderGetter<E>> optional = registryops.getter(this.registryKey);
if (optional.isEmpty()) {
return DataResult.error(() -> {
return "Registry does not exist: " + this.registryKey;
});
} else {
HolderGetter<E> holdergetter = optional.get();
DataResult<Pair<ResourceLocation, T>> dataresult = ResourceLocation.CODEC.decode(pOps, pInput);
if (dataresult.result().isEmpty()) {
return !this.allowInline ? DataResult.error(() -> {
return "Inline definitions not allowed here";
}) : this.elementCodec.decode(pOps, pInput).map((p_206720_) -> {
return p_206720_.mapFirst(Holder::direct);
});
} else {
Pair<ResourceLocation, T> pair = dataresult.result().get();
ResourceKey<E> resourcekey = ResourceKey.create(this.registryKey, pair.getFirst());
return holdergetter.get(resourcekey).map(DataResult::success).orElseGet(() -> {
return DataResult.error(() -> {
return "Failed to get element " + resourcekey;
});
}).map((p_255658_) -> {
return Pair.of((Holder<E>)p_255658_, pair.getSecond());
}).setLifecycle(Lifecycle.stable());
}
}
} else {
return this.elementCodec.decode(pOps, pInput).map((p_214212_) -> {
return p_214212_.mapFirst(Holder::direct);
});
}
}
public String toString() {
return "RegistryFileCodec[" + this.registryKey + " " + this.elementCodec + "]";
}
}
@@ -0,0 +1,75 @@
package net.minecraft.resources;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.Lifecycle;
import java.util.Optional;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderGetter;
import net.minecraft.core.HolderOwner;
import net.minecraft.core.Registry;
public final class RegistryFixedCodec<E> implements Codec<Holder<E>> {
private final ResourceKey<? extends Registry<E>> registryKey;
public static <E> RegistryFixedCodec<E> create(ResourceKey<? extends Registry<E>> p_206741_) {
return new RegistryFixedCodec<>(p_206741_);
}
private RegistryFixedCodec(ResourceKey<? extends Registry<E>> p_206723_) {
this.registryKey = p_206723_;
}
public <T> DataResult<T> encode(Holder<E> p_206729_, DynamicOps<T> p_206730_, T p_206731_) {
if (p_206730_ instanceof RegistryOps<?> registryops) {
Optional<HolderOwner<E>> optional = registryops.owner(this.registryKey);
if (optional.isPresent()) {
if (!p_206729_.canSerializeIn(optional.get())) {
return DataResult.error(() -> {
return "Element " + p_206729_ + " is not valid in current registry set";
});
}
return p_206729_.unwrap().map((p_206727_) -> {
return ResourceLocation.CODEC.encode(p_206727_.location(), p_206730_, p_206731_);
}, (p_274804_) -> {
return DataResult.error(() -> {
return "Elements from registry " + this.registryKey + " can't be serialized to a value";
});
});
}
}
return DataResult.error(() -> {
return "Can't access registry " + this.registryKey;
});
}
public <T> DataResult<Pair<Holder<E>, T>> decode(DynamicOps<T> p_206743_, T p_206744_) {
if (p_206743_ instanceof RegistryOps<?> registryops) {
Optional<HolderGetter<E>> optional = registryops.getter(this.registryKey);
if (optional.isPresent()) {
return ResourceLocation.CODEC.decode(p_206743_, p_206744_).flatMap((p_255515_) -> {
ResourceLocation resourcelocation = p_255515_.getFirst();
return optional.get().get(ResourceKey.create(this.registryKey, resourcelocation)).map(DataResult::success).orElseGet(() -> {
return DataResult.error(() -> {
return "Failed to get element " + resourcelocation;
});
}).map((p_256041_) -> {
return Pair.of((Holder<E>)p_256041_, (T)p_255515_.getSecond());
}).setLifecycle(Lifecycle.stable());
});
}
}
return DataResult.error(() -> {
return "Can't access registry " + this.registryKey;
});
}
public String toString() {
return "RegistryFixedCodec[" + this.registryKey + "]";
}
}
@@ -0,0 +1,118 @@
package net.minecraft.resources;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.Lifecycle;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderGetter;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.HolderOwner;
import net.minecraft.core.Registry;
import net.minecraft.util.ExtraCodecs;
public class RegistryOps<T> extends DelegatingOps<T> {
private final RegistryOps.RegistryInfoLookup lookupProvider;
private static RegistryOps.RegistryInfoLookup memoizeLookup(final RegistryOps.RegistryInfoLookup pLookupProvider) {
return new RegistryOps.RegistryInfoLookup() {
private final Map<ResourceKey<? extends Registry<?>>, Optional<? extends RegistryOps.RegistryInfo<?>>> lookups = new HashMap<>();
public <T> Optional<RegistryOps.RegistryInfo<T>> lookup(ResourceKey<? extends Registry<? extends T>> p_256043_) {
return (Optional<RegistryOps.RegistryInfo<T>>) this.lookups.computeIfAbsent(p_256043_, pLookupProvider::lookup);
}
};
}
public static <T> RegistryOps<T> create(DynamicOps<T> pDelegate, final HolderLookup.Provider pRegistries) {
return create(pDelegate, memoizeLookup(new RegistryOps.RegistryInfoLookup() {
public <E> Optional<RegistryOps.RegistryInfo<E>> lookup(ResourceKey<? extends Registry<? extends E>> p_256323_) {
return pRegistries.lookup(p_256323_).map((p_258224_) -> {
return new RegistryOps.RegistryInfo<>(p_258224_, p_258224_, p_258224_.registryLifecycle());
});
}
}));
}
public static <T> RegistryOps<T> create(DynamicOps<T> pDelegate, RegistryOps.RegistryInfoLookup pLookupProvider) {
return new RegistryOps<>(pDelegate, pLookupProvider);
}
private RegistryOps(DynamicOps<T> pDelegate, RegistryOps.RegistryInfoLookup pLookupProvider) {
super(pDelegate);
this.lookupProvider = pLookupProvider;
}
public <E> Optional<HolderOwner<E>> owner(ResourceKey<? extends Registry<? extends E>> pRegistryKey) {
return this.lookupProvider.lookup(pRegistryKey).map(RegistryOps.RegistryInfo::owner);
}
public <E> Optional<HolderGetter<E>> getter(ResourceKey<? extends Registry<? extends E>> pRegistryKey) {
return this.lookupProvider.lookup(pRegistryKey).map(RegistryOps.RegistryInfo::getter);
}
public static <E, O> RecordCodecBuilder<O, HolderGetter<E>> retrieveGetter(ResourceKey<? extends Registry<? extends E>> p_206833_) {
return ExtraCodecs.retrieveContext((p_274811_) -> {
if (p_274811_ instanceof RegistryOps<?> registryops) {
return registryops.lookupProvider.lookup(p_206833_).map((p_255527_) -> {
return DataResult.success(p_255527_.getter(), p_255527_.elementsLifecycle());
}).orElseGet(() -> {
return DataResult.error(() -> {
return "Unknown registry: " + p_206833_;
});
});
} else {
return DataResult.error(() -> {
return "Not a registry ops";
});
}
}).forGetter((p_255526_) -> {
return null;
});
}
public static <E> com.mojang.serialization.MapCodec<HolderLookup.RegistryLookup<E>> retrieveRegistryLookup(ResourceKey<? extends Registry<? extends E>> resourceKey) {
return ExtraCodecs.retrieveContext(ops -> {
if (!(ops instanceof RegistryOps<?> registryOps))
return DataResult.error(() -> "Not a registry ops");
return registryOps.lookupProvider.lookup(resourceKey).map(registryInfo -> {
if (!(registryInfo.owner() instanceof HolderLookup.RegistryLookup<E> registryLookup))
return DataResult.<HolderLookup.RegistryLookup<E>>error(() -> "Found holder getter but was not a registry lookup for " + resourceKey);
return DataResult.success(registryLookup, registryInfo.elementsLifecycle());
}).orElseGet(() -> DataResult.error(() -> "Unknown registry: " + resourceKey));
});
}
public static <E, O> RecordCodecBuilder<O, Holder.Reference<E>> retrieveElement(ResourceKey<E> pKey) {
ResourceKey<? extends Registry<E>> resourcekey = ResourceKey.createRegistryKey(pKey.registry());
return ExtraCodecs.retrieveContext((p_274808_) -> {
if (p_274808_ instanceof RegistryOps<?> registryops) {
return registryops.lookupProvider.lookup(resourcekey).flatMap((p_255518_) -> {
return p_255518_.getter().get(pKey);
}).map(DataResult::success).orElseGet(() -> {
return DataResult.error(() -> {
return "Can't find value: " + pKey;
});
});
} else {
return DataResult.error(() -> {
return "Not a registry ops";
});
}
}).forGetter((p_255524_) -> {
return null;
});
}
public static record RegistryInfo<T>(HolderOwner<T> owner, HolderGetter<T> getter, Lifecycle elementsLifecycle) {
}
public interface RegistryInfoLookup {
<T> Optional<RegistryOps.RegistryInfo<T>> lookup(ResourceKey<? extends Registry<? extends T>> pRegistryKey);
}
}
@@ -0,0 +1,102 @@
package net.minecraft.resources;
import com.google.common.collect.MapMaker;
import com.mojang.serialization.Codec;
import java.util.Optional;
import java.util.concurrent.ConcurrentMap;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
/**
* An immutable key for a resource, in terms of the name of its parent registry and its location in that registry.
* <p>
* {@link net.minecraft.core.Registry} uses this to return resource keys for registry objects via {@link
* net.minecraft.core.Registry#getResourceKey(Object)}. It also uses this class to store its name, with the parent
* registry name set to {@code minecraft:root}. When used in this way it is usually referred to as a "registry key".</p>
* <p>
* @param <T> The type of the resource represented by this {@code ResourceKey}, or the type of the registry if it is a
* registry key.
* @see net.minecraft.resources.ResourceLocation
*/
public class ResourceKey<T> implements Comparable<ResourceKey<?>> {
private static final ConcurrentMap<ResourceKey.InternKey, ResourceKey<?>> VALUES = (new MapMaker()).weakValues().makeMap();
/** The name of the parent registry of the resource. */
private final ResourceLocation registryName;
/** The location of the resource within the registry. */
private final ResourceLocation location;
public static <T> Codec<ResourceKey<T>> codec(ResourceKey<? extends Registry<T>> pRegistryKey) {
return ResourceLocation.CODEC.xmap((p_195979_) -> {
return create(pRegistryKey, p_195979_);
}, ResourceKey::location);
}
/**
* Constructs a new {@code ResourceKey} for a resource with the specified {@code location} within the registry
* specified by the given {@code registryKey}.
*
* @return the created resource key. The registry name is set to the location of the specified {@code registryKey}
* and with the specified {@code location} as the location of the resource.
*/
public static <T> ResourceKey<T> create(ResourceKey<? extends Registry<T>> pRegistryKey, ResourceLocation pLocation) {
return create(pRegistryKey.location, pLocation);
}
/**
* @return the created registry key. The registry name is set to {@code minecraft:root} and the location the
* specified {@code registryName}.
*/
public static <T> ResourceKey<Registry<T>> createRegistryKey(ResourceLocation pLocation) {
return create(BuiltInRegistries.ROOT_REGISTRY_NAME, pLocation);
}
private static <T> ResourceKey<T> create(ResourceLocation pRegistryName, ResourceLocation pLocation) {
return (ResourceKey<T>)VALUES.computeIfAbsent(new ResourceKey.InternKey(pRegistryName, pLocation), (p_258225_) -> {
return new ResourceKey(p_258225_.registry, p_258225_.location);
});
}
private ResourceKey(ResourceLocation pRegistryName, ResourceLocation pLocation) {
this.registryName = pRegistryName;
this.location = pLocation;
}
public String toString() {
return "ResourceKey[" + this.registryName + " / " + this.location + "]";
}
/**
* @return {@code true} if this resource key is a direct child of the specified {@code registryKey}.
*/
public boolean isFor(ResourceKey<? extends Registry<?>> pRegistryKey) {
return this.registryName.equals(pRegistryKey.location());
}
public <E> Optional<ResourceKey<E>> cast(ResourceKey<? extends Registry<E>> pRegistryKey) {
return this.isFor(pRegistryKey) ? Optional.of((ResourceKey<E>)this) : Optional.empty();
}
public ResourceLocation location() {
return this.location;
}
public ResourceLocation registry() {
return this.registryName;
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
return location.equals(((ResourceKey<?>) o).location) && registryName.equals(((ResourceKey<?>) o).registryName);
}
@Override
public int compareTo(ResourceKey<?> o) {
int ret = this.registry().compareTo(o.registry());
if (ret == 0) ret = this.location().compareTo(o.location());
return ret;
}
static record InternKey(ResourceLocation registry, ResourceLocation location) {
}
}
@@ -0,0 +1,309 @@
package net.minecraft.resources;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import java.lang.reflect.Type;
import java.util.function.UnaryOperator;
import javax.annotation.Nullable;
import net.minecraft.ResourceLocationException;
import net.minecraft.network.chat.Component;
import net.minecraft.util.GsonHelper;
import org.apache.commons.lang3.StringUtils;
/**
* An immutable location of a resource, in terms of a path and namespace.
* <p>
* This is used as an identifier for a resource, usually for those housed in a {@link net.minecraft.core.Registry}, such
* as blocks and items.
* <p>
* {@code minecraft} is always taken as the default namespace for a resource location when none is explicitly stated.
* When using this for registering objects, this namespace <strong>should</strong> only be used for resources added by
* Minecraft itself.
* <p>
* Generally, and by the implementation of {@link #toString()}, the string representation of this class is expressed in
* the form {@code namespace:path}. The colon is also used as the default separator for parsing strings as a {@code
* ResourceLocation}.
* @see net.minecraft.resources.ResourceKey
*/
public class ResourceLocation implements Comparable<ResourceLocation> {
public static final Codec<ResourceLocation> CODEC = Codec.STRING.comapFlatMap(ResourceLocation::read, ResourceLocation::toString).stable();
private static final SimpleCommandExceptionType ERROR_INVALID = new SimpleCommandExceptionType(Component.translatable("argument.id.invalid"));
public static final char NAMESPACE_SEPARATOR = ':';
public static final String DEFAULT_NAMESPACE = "minecraft";
public static final String REALMS_NAMESPACE = "realms";
private final String namespace;
private final String path;
protected ResourceLocation(String pNamespace, String pPath, @Nullable ResourceLocation.Dummy pDummy) {
this.namespace = pNamespace;
this.path = pPath;
}
public ResourceLocation(String pNamespace, String pPath) {
this(assertValidNamespace(pNamespace, pPath), assertValidPath(pNamespace, pPath), (ResourceLocation.Dummy)null);
}
private ResourceLocation(String[] pDecomposedLocation) {
this(pDecomposedLocation[0], pDecomposedLocation[1]);
}
public ResourceLocation(String pLocation) {
this(decompose(pLocation, ':'));
}
/**
* Constructs a {@code ResourceLocation} from the specified {@code location}, split into a namespace and path by the
* specified {@code separator} char.
* <p>
* If the {@code separator} char is not present in the {@code location}, the namespace defaults to {@code minecraft},
* taking the {@code location} as the path.
* @throws net.minecraft.ResourceLocationException if there is a non {@code [a-z0-9_.-]} character in the decomposed
* namespace or a non {@code [a-z0-9/._-]} character in the decomposed path.
* @see #tryParse(String)
* @see #isValidResourceLocation(String)
* @param pLocation the location string to parse as a {@code ResourceLocation}
* @param pSeparator the separator to separate the namespace and path by. This should not be any of these characters:
* {@code [a-z0-9/._-]}.
*/
public static ResourceLocation of(String pLocation, char pSeparator) {
return new ResourceLocation(decompose(pLocation, pSeparator));
}
/**
* Attempts to parse the specified {@code location} as a {@code ResourceLocation} by splitting it into a
* namespace and path by a colon.
* <p>
* If no colon is present in the {@code location}, the namespace defaults to {@code minecraft}, taking the {@code
* location} as the path.
* @return the parsed resource location; otherwise {@code null} if there is a non {@code [a-z0-9_.-]} character in
* the decomposed namespace or a non {@code [a-z0-9/._-]} character in the decomposed path
* @see #of(String, char)
* @param pLocation the location string to try to parse as a {@code ResourceLocation}
*/
@Nullable
public static ResourceLocation tryParse(String pLocation) {
try {
return new ResourceLocation(pLocation);
} catch (ResourceLocationException resourcelocationexception) {
return null;
}
}
@Nullable
public static ResourceLocation tryBuild(String pNamespace, String pPath) {
try {
return new ResourceLocation(pNamespace, pPath);
} catch (ResourceLocationException resourcelocationexception) {
return null;
}
}
protected static String[] decompose(String pLocation, char pSeparator) {
String[] astring = new String[]{"minecraft", pLocation};
int i = pLocation.indexOf(pSeparator);
if (i >= 0) {
astring[1] = pLocation.substring(i + 1);
if (i >= 1) {
astring[0] = pLocation.substring(0, i);
}
}
return astring;
}
public static DataResult<ResourceLocation> read(String p_135838_) {
try {
return DataResult.success(new ResourceLocation(p_135838_));
} catch (ResourceLocationException resourcelocationexception) {
return DataResult.error(() -> {
return "Not a valid resource location: " + p_135838_ + " " + resourcelocationexception.getMessage();
});
}
}
public String getPath() {
return this.path;
}
public String getNamespace() {
return this.namespace;
}
public ResourceLocation withPath(String pPath) {
return new ResourceLocation(this.namespace, assertValidPath(this.namespace, pPath), (ResourceLocation.Dummy)null);
}
public ResourceLocation withPath(UnaryOperator<String> pPathOperator) {
return this.withPath(pPathOperator.apply(this.path));
}
public ResourceLocation withPrefix(String pPathPrefix) {
return this.withPath(pPathPrefix + this.path);
}
public ResourceLocation withSuffix(String pPathSuffix) {
return this.withPath(this.path + pPathSuffix);
}
public String toString() {
return this.namespace + ":" + this.path;
}
public boolean equals(Object pOther) {
if (this == pOther) {
return true;
} else if (!(pOther instanceof ResourceLocation)) {
return false;
} else {
ResourceLocation resourcelocation = (ResourceLocation)pOther;
return this.namespace.equals(resourcelocation.namespace) && this.path.equals(resourcelocation.path);
}
}
public int hashCode() {
return 31 * this.namespace.hashCode() + this.path.hashCode();
}
public int compareTo(ResourceLocation pOther) {
int i = this.path.compareTo(pOther.path);
if (i == 0) {
i = this.namespace.compareTo(pOther.namespace);
}
return i;
}
// Normal compare sorts by path first, this compares namespace first.
public int compareNamespaced(ResourceLocation o) {
int ret = this.namespace.compareTo(o.namespace);
return ret != 0 ? ret : this.path.compareTo(o.path);
}
public String toDebugFileName() {
return this.toString().replace('/', '_').replace(':', '_');
}
public String toLanguageKey() {
return this.namespace + "." + this.path;
}
public String toShortLanguageKey() {
return this.namespace.equals("minecraft") ? this.path : this.toLanguageKey();
}
public String toLanguageKey(String pType) {
return pType + "." + this.toLanguageKey();
}
public String toLanguageKey(String pType, String p_270199_) {
return pType + "." + this.toLanguageKey() + "." + p_270199_;
}
public static ResourceLocation read(StringReader pReader) throws CommandSyntaxException {
int i = pReader.getCursor();
while(pReader.canRead() && isAllowedInResourceLocation(pReader.peek())) {
pReader.skip();
}
String s = pReader.getString().substring(i, pReader.getCursor());
try {
return new ResourceLocation(s);
} catch (ResourceLocationException resourcelocationexception) {
pReader.setCursor(i);
throw ERROR_INVALID.createWithContext(pReader);
}
}
public static boolean isAllowedInResourceLocation(char pCharacter) {
return pCharacter >= '0' && pCharacter <= '9' || pCharacter >= 'a' && pCharacter <= 'z' || pCharacter == '_' || pCharacter == ':' || pCharacter == '/' || pCharacter == '.' || pCharacter == '-';
}
/**
* @return {@code true} if the specified {@code path} is valid: consists only of {@code [a-z0-9/._-]} characters
*/
public static boolean isValidPath(String pPath) {
for(int i = 0; i < pPath.length(); ++i) {
if (!validPathChar(pPath.charAt(i))) {
return false;
}
}
return true;
}
/**
* @return {@code true} if the specified {@code namespace} is valid: consists only of {@code [a-z0-9_.-]} characters
*/
public static boolean isValidNamespace(String pNamespace) {
for(int i = 0; i < pNamespace.length(); ++i) {
if (!validNamespaceChar(pNamespace.charAt(i))) {
return false;
}
}
return true;
}
private static String assertValidNamespace(String pNamespae, String pPath) {
if (!isValidNamespace(pNamespae)) {
throw new ResourceLocationException("Non [a-z0-9_.-] character in namespace of location: " + pNamespae + ":" + pPath);
} else {
return pNamespae;
}
}
public static boolean validPathChar(char pPathChar) {
return pPathChar == '_' || pPathChar == '-' || pPathChar >= 'a' && pPathChar <= 'z' || pPathChar >= '0' && pPathChar <= '9' || pPathChar == '/' || pPathChar == '.';
}
public static boolean validNamespaceChar(char pNamespaceChar) {
return pNamespaceChar == '_' || pNamespaceChar == '-' || pNamespaceChar >= 'a' && pNamespaceChar <= 'z' || pNamespaceChar >= '0' && pNamespaceChar <= '9' || pNamespaceChar == '.';
}
/**
* Splits the specified {@code location} into a namespace and path by a colon, checking both are valid.
* <p>
* If no colon is present in the {@code location}, the namespace defaults to {@code minecraft}, taking the {@code
* location} as the path.</p>
* @return {@code true} if both the decomposed namespace and path are valid
* @see #isValidPath(String)
* @see #isValidNamespace(String)
*/
public static boolean isValidResourceLocation(String pLocation) {
String[] astring = decompose(pLocation, ':');
return isValidNamespace(StringUtils.isEmpty(astring[0]) ? "minecraft" : astring[0]) && isValidPath(astring[1]);
}
private static String assertValidPath(String pNamespace, String pPath) {
if (!isValidPath(pPath)) {
throw new ResourceLocationException("Non [a-z0-9/._-] character in path of location: " + pNamespace + ":" + pPath);
} else {
return pPath;
}
}
protected interface Dummy {
}
public static class Serializer implements JsonDeserializer<ResourceLocation>, JsonSerializer<ResourceLocation> {
public ResourceLocation deserialize(JsonElement pJson, Type pTypeOfT, JsonDeserializationContext pContext) throws JsonParseException {
return new ResourceLocation(GsonHelper.convertToString(pJson, "location"));
}
public JsonElement serialize(ResourceLocation pResourceLocation, Type pTypeOfT, JsonSerializationContext pContext) {
return new JsonPrimitive(pResourceLocation.toString());
}
}
}
@@ -0,0 +1,8 @@
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@FieldsAreNonnullByDefault
package net.minecraft.resources;
import javax.annotation.ParametersAreNonnullByDefault;
import net.minecraft.FieldsAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault;