Last active
March 17, 2021 02:01
-
-
Save Commoble/cd22566fbf381c5fa060195cc9fbc30f to your computer and use it in GitHub Desktop.
Using Dispatch Codecs with Forge Registries
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// json for a StatePredicate that a data loader could load | |
// this will be parsed into a BlockPredicate instance that returns true | |
// if a blockstate's block is the Grass Block | |
{ | |
"type": "sandbox:block", | |
"block": "minecraft:grass_block" | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package commoble.sandbox; | |
import java.util.function.Supplier; | |
import com.mojang.serialization.Codec; | |
import commoble.sandbox.StatePredicateSerializer.StatePredicate; | |
import net.minecraft.block.Block; | |
import net.minecraft.block.BlockState; | |
import net.minecraft.util.registry.Registry; | |
import net.minecraftforge.fml.RegistryObject; | |
import net.minecraftforge.registries.DeferredRegister; | |
// some basic state predicates | |
public class StatePredicates | |
{ | |
@SuppressWarnings("unchecked") | |
public static final DeferredRegister<StatePredicateSerializer<?>> STATE_PREDICATE_SERIALIZERS = DeferredRegister.create(StatePredicateSerializer.class, "modid"); | |
public static final RegistryObject<StatePredicateSerializer<ConstantPredicate>> ALWAYS_TRUE = STATE_PREDICATE_SERIALIZERS.register("always_true", () -> new StatePredicateSerializer<>(StatePredicates.ConstantPredicate.ALWAYS_TRUE_CODEC)); | |
public static final RegistryObject<StatePredicateSerializer<ConstantPredicate>> ALWAYS_FALSE = STATE_PREDICATE_SERIALIZERS.register("always_false", () -> new StatePredicateSerializer<>(StatePredicates.ConstantPredicate.ALWAYS_FALSE_CODEC)); | |
public static final RegistryObject<StatePredicateSerializer<BlockPredicate>> BLOCK_SERIALIZER = STATE_PREDICATE_SERIALIZERS.register("block", () -> new StatePredicateSerializer<>(StatePredicates.BlockPredicate.CODEC)); | |
/** Predicates that always return either true or false **/ | |
public static class ConstantPredicate extends StatePredicate<ConstantPredicate> | |
{ | |
public static final Codec<ConstantPredicate> ALWAYS_FALSE_CODEC = Codec.unit(new ConstantPredicate(ALWAYS_FALSE, false)); | |
public static final Codec<ConstantPredicate> ALWAYS_TRUE_CODEC = Codec.unit(new ConstantPredicate(ALWAYS_TRUE, true)); | |
private final boolean value; | |
public ConstantPredicate(Supplier<StatePredicateSerializer<ConstantPredicate>> serializer, boolean value) | |
{ | |
super(serializer); | |
this.value = value; | |
} | |
@Override | |
public boolean test(BlockState state) | |
{ | |
return this.value; | |
} | |
} | |
/** Predicate that returns true if a state belongs to a given block instance **/ | |
public static class BlockPredicate extends StatePredicate<BlockPredicate> | |
{ | |
public static final Codec<BlockPredicate> CODEC = Registry.BLOCK.xmap(BlockPredicate::new, BlockPredicate::getBlock).fieldOf("block").codec(); | |
private final Block block; | |
public Block getBlock() { return this.block; } | |
public BlockPredicate(Block block) | |
{ | |
super(BLOCK_SERIALIZER); | |
this.block = block; | |
} | |
@Override | |
public boolean test(BlockState state) | |
{ | |
return state.isIn(this.block); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package commoble.sandbox; | |
import java.util.function.Predicate; | |
import java.util.function.Supplier; | |
import com.mojang.serialization.Codec; | |
import commoble.sandbox.StatePredicateSerializer.StatePredicate; | |
import net.minecraft.block.BlockState; | |
import net.minecraft.util.ResourceLocation; | |
import net.minecraftforge.event.RegistryEvent; | |
import net.minecraftforge.eventbus.api.SubscribeEvent; | |
import net.minecraftforge.fml.common.Mod.EventBusSubscriber; | |
import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; | |
import net.minecraftforge.registries.ForgeRegistryEntry; | |
import net.minecraftforge.registries.IForgeRegistry; | |
import net.minecraftforge.registries.RegistryBuilder; | |
/** Example of using dispatch codecs to make a registry of serializers for blockstate predicates **/ | |
@EventBusSubscriber(modid="sandbox", bus=Bus.MOD) | |
public class StatePredicateSerializer<LOGIC extends StatePredicate<LOGIC>> extends ForgeRegistryEntry<StatePredicateSerializer<LOGIC>> | |
{ | |
// forge hack to build generic-param-class registries | |
@SuppressWarnings("unchecked") | |
private static <T> Class<T> genericClass(Class<?> cls) { return (Class<T>)cls; } | |
// get a forge registry registered | |
@SubscribeEvent | |
static void onRegisterRegistries(RegistryEvent.NewRegistry event) | |
{ | |
Class<StatePredicateSerializer<?>> registryClass = genericClass(StatePredicateSerializer.class); | |
REGISTRY = new RegistryBuilder<StatePredicateSerializer<?>>() | |
.setName(new ResourceLocation("sandbox:statepredicate")) | |
.setType(registryClass) | |
.disableSaving() | |
// disable sync if you're not going to use the data loader on the client | |
.disableSync() | |
.create(); | |
} | |
// use DeferredRegister.create(StatePredicateSerializer.class, modid) to register stuff to this | |
public static IForgeRegistry<StatePredicateSerializer<?>> REGISTRY = null; | |
/** | |
* This is the registry dispatch codec; | |
* this will read jsons of the format: | |
{ | |
"type": "modid:serializer-name", | |
// extra fields definable by the sub-codecs | |
} | |
* this codec can be used to read jsons in data loaders, etc | |
* Fields in the subcodecs will get read from the same root jsonobject as the "type" field. | |
* If the subcodec isn't a map codec, the dispatcher will read the subcodec from a "value" field instead. | |
*/ | |
public static final Codec<StatePredicateSerializer<?>> CODEC = ResourceLocation.CODEC.xmap(id -> REGISTRY.getValue(id), StatePredicateSerializer::getRegistryName); | |
private final Codec<LOGIC> subCodec; | |
public Codec<LOGIC> getSubCodec() { return this.subCodec; } | |
/** | |
* | |
* @param subCodec The codec to use to read extra data for the StatePredicate instances | |
*/ | |
public StatePredicateSerializer(Codec<LOGIC> subCodec) | |
{ | |
this.subCodec = subCodec; | |
} | |
// the self-referential generic param here lets us have a reference to a properly generic'd serializer | |
public static abstract class StatePredicate<T extends StatePredicate<T>> implements Predicate<BlockState> | |
{ | |
public static final Codec<StatePredicate<?>> CODEC = StatePredicateSerializer.CODEC.dispatch(StatePredicate::getSerializer, StatePredicateSerializer::getSubCodec); | |
private final Supplier<StatePredicateSerializer<T>> serializerGetter; | |
public StatePredicateSerializer<T> getSerializer() { return this.serializerGetter.get(); } | |
/** | |
* @param serializerGetter Supplier for a state predicate serializer (since they're forge registry entries, you can use a RegistryObject here) | |
*/ | |
public StatePredicate(Supplier<StatePredicateSerializer<T>> serializerGetter) | |
{ | |
this.serializerGetter = serializerGetter; | |
} | |
/** | |
* @param state A blockstate to test | |
* @return true if the state passes the test | |
*/ | |
@Override | |
public abstract boolean test(BlockState state); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment