AttachedRegistry refactors, and several adjacent ones

This commit is contained in:
TropheusJ 2025-02-12 08:08:19 -05:00
parent 888d175695
commit 41d725878e
36 changed files with 568 additions and 992 deletions

View file

@ -3,8 +3,8 @@ package com.simibubi.create;
import static com.simibubi.create.AllInteractionBehaviours.interactionBehaviour; import static com.simibubi.create.AllInteractionBehaviours.interactionBehaviour;
import static com.simibubi.create.AllMovementBehaviours.movementBehaviour; import static com.simibubi.create.AllMovementBehaviours.movementBehaviour;
import static com.simibubi.create.Create.REGISTRATE; import static com.simibubi.create.Create.REGISTRATE;
import static com.simibubi.create.api.contraption.storage.MountedStorageTypeRegistry.mountedFluidStorage; import static com.simibubi.create.api.contraption.storage.MountedStorageTypeRegistries.mountedFluidStorage;
import static com.simibubi.create.api.contraption.storage.MountedStorageTypeRegistry.mountedItemStorage; import static com.simibubi.create.api.contraption.storage.MountedStorageTypeRegistries.mountedItemStorage;
import static com.simibubi.create.content.redstone.displayLink.AllDisplayBehaviours.assignDataBehaviour; import static com.simibubi.create.content.redstone.displayLink.AllDisplayBehaviours.assignDataBehaviour;
import static com.simibubi.create.foundation.data.BlockStateGen.axisBlock; import static com.simibubi.create.foundation.data.BlockStateGen.axisBlock;
import static com.simibubi.create.foundation.data.BlockStateGen.simpleCubeAll; import static com.simibubi.create.foundation.data.BlockStateGen.simpleCubeAll;
@ -768,7 +768,7 @@ public class AllBlocks {
.loot((lt, block) -> lt.add(block, BlazeBurnerBlock.buildLootTable())) .loot((lt, block) -> lt.add(block, BlazeBurnerBlock.buildLootTable()))
.blockstate((c, p) -> p.simpleBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p))) .blockstate((c, p) -> p.simpleBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p)))
.onRegister(movementBehaviour(new BlazeBurnerMovementBehaviour())) .onRegister(movementBehaviour(new BlazeBurnerMovementBehaviour()))
.onRegister(block -> TrainConductorHandler.registerBlazeBurner()) .onRegister(TrainConductorHandler::registerBlazeBurner)
.item(BlazeBurnerBlockItem::withBlaze) .item(BlazeBurnerBlockItem::withBlaze)
.model(AssetLookup.customBlockItemModel("blaze_burner", "block_with_blaze")) .model(AssetLookup.customBlockItemModel("blaze_burner", "block_with_blaze"))
.build() .build()

View file

@ -1,94 +1,39 @@
package com.simibubi.create; package com.simibubi.create;
import java.util.ArrayList;
import java.util.List;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.simibubi.create.api.registry.AttachedRegistry;
import com.simibubi.create.content.contraptions.behaviour.DoorMovingInteraction; import com.simibubi.create.content.contraptions.behaviour.DoorMovingInteraction;
import com.simibubi.create.content.contraptions.behaviour.FenceGateMovingInteraction;
import com.simibubi.create.content.contraptions.behaviour.LeverMovingInteraction; import com.simibubi.create.content.contraptions.behaviour.LeverMovingInteraction;
import com.simibubi.create.content.contraptions.behaviour.MovingInteractionBehaviour; import com.simibubi.create.content.contraptions.behaviour.MovingInteractionBehaviour;
import com.simibubi.create.content.contraptions.behaviour.TrapdoorMovingInteraction; import com.simibubi.create.content.contraptions.behaviour.TrapdoorMovingInteraction;
import com.simibubi.create.foundation.utility.AttachedRegistry;
import com.tterrag.registrate.util.nullness.NonNullConsumer; import com.tterrag.registrate.util.nullness.NonNullConsumer;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.BlockTags; import net.minecraft.tags.BlockTags;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.registries.ForgeRegistries;
public class AllInteractionBehaviours { public class AllInteractionBehaviours {
private static final AttachedRegistry<Block, MovingInteractionBehaviour> BLOCK_BEHAVIOURS = new AttachedRegistry<>(ForgeRegistries.BLOCKS); public static final AttachedRegistry<Block, MovingInteractionBehaviour> REGISTRY = AttachedRegistry.create();
private static final List<BehaviourProvider> GLOBAL_BEHAVIOURS = new ArrayList<>();
public static void registerBehaviour(ResourceLocation block, MovingInteractionBehaviour provider) {
BLOCK_BEHAVIOURS.register(block, provider);
}
public static void registerBehaviour(Block block, MovingInteractionBehaviour provider) {
BLOCK_BEHAVIOURS.register(block, provider);
}
public static void registerBehaviourProvider(BehaviourProvider provider) {
GLOBAL_BEHAVIOURS.add(provider);
}
@Nullable @Nullable
public static MovingInteractionBehaviour getBehaviour(BlockState state) { public static MovingInteractionBehaviour getBehaviour(BlockState state) {
MovingInteractionBehaviour behaviour = BLOCK_BEHAVIOURS.get(state.getBlock()); return REGISTRY.get(state.getBlock());
if (behaviour != null) {
return behaviour;
}
for (BehaviourProvider provider : GLOBAL_BEHAVIOURS) {
behaviour = provider.getBehaviour(state);
if (behaviour != null) {
return behaviour;
}
}
return null;
} }
public static <B extends Block> NonNullConsumer<? super B> interactionBehaviour( /**
MovingInteractionBehaviour behaviour) { * Creates a consumer that will register a behavior to a block. Useful for Registrate.
return b -> registerBehaviour(b, behaviour); */
public static <B extends Block> NonNullConsumer<? super B> interactionBehaviour(MovingInteractionBehaviour behaviour) {
return b -> REGISTRY.register(b, behaviour);
} }
static void registerDefaults() { static void registerDefaults() {
registerBehaviour(Blocks.LEVER, new LeverMovingInteraction()); REGISTRY.register(Blocks.LEVER, new LeverMovingInteraction());
DoorMovingInteraction doorBehaviour = new DoorMovingInteraction(); REGISTRY.registerProvider(AttachedRegistry.Provider.forBlockTag(BlockTags.WOODEN_DOORS, new DoorMovingInteraction()));
registerBehaviourProvider(state -> { REGISTRY.registerProvider(AttachedRegistry.Provider.forBlockTag(BlockTags.WOODEN_TRAPDOORS, new TrapdoorMovingInteraction()));
if (state.is(BlockTags.WOODEN_DOORS)) { REGISTRY.registerProvider(AttachedRegistry.Provider.forBlockTag(BlockTags.FENCE_GATES, new TrapdoorMovingInteraction()));
return doorBehaviour;
}
return null;
});
TrapdoorMovingInteraction trapdoorBehaviour = new TrapdoorMovingInteraction();
registerBehaviourProvider(state -> {
if (state.is(BlockTags.WOODEN_TRAPDOORS)) {
return trapdoorBehaviour;
}
return null;
});
FenceGateMovingInteraction fenceGateBehavior = new FenceGateMovingInteraction();
registerBehaviourProvider(state -> {
if (state.is(BlockTags.FENCE_GATES)) {
return fenceGateBehavior;
}
return null;
});
}
public interface BehaviourProvider {
@Nullable
MovingInteractionBehaviour getBehaviour(BlockState state);
} }
} }

View file

@ -1,74 +1,41 @@
package com.simibubi.create; package com.simibubi.create;
import java.util.ArrayList; import org.jetbrains.annotations.Nullable;
import java.util.List;
import javax.annotation.Nullable;
import com.simibubi.create.api.registry.AttachedRegistry;
import com.simibubi.create.content.contraptions.behaviour.BellMovementBehaviour; import com.simibubi.create.content.contraptions.behaviour.BellMovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.CampfireMovementBehaviour; import com.simibubi.create.content.contraptions.behaviour.CampfireMovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.dispenser.DispenserMovementBehaviour; import com.simibubi.create.content.contraptions.behaviour.dispenser.DispenserMovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.dispenser.DropperMovementBehaviour; import com.simibubi.create.content.contraptions.behaviour.dispenser.DropperMovementBehaviour;
import com.simibubi.create.foundation.utility.AttachedRegistry;
import com.tterrag.registrate.util.nullness.NonNullConsumer; import com.tterrag.registrate.util.nullness.NonNullConsumer;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.registries.ForgeRegistries;
public class AllMovementBehaviours { public class AllMovementBehaviours {
private static final AttachedRegistry<Block, MovementBehaviour> BLOCK_BEHAVIOURS = new AttachedRegistry<>(ForgeRegistries.BLOCKS); public static final AttachedRegistry<Block, MovementBehaviour> REGISTRY = AttachedRegistry.create();
private static final List<BehaviourProvider> GLOBAL_BEHAVIOURS = new ArrayList<>();
public static void registerBehaviour(ResourceLocation block, MovementBehaviour behaviour) {
BLOCK_BEHAVIOURS.register(block, behaviour);
}
public static void registerBehaviour(Block block, MovementBehaviour behaviour) {
BLOCK_BEHAVIOURS.register(block, behaviour);
}
public static void registerBehaviourProvider(BehaviourProvider provider) {
GLOBAL_BEHAVIOURS.add(provider);
}
@Nullable @Nullable
public static MovementBehaviour getBehaviour(BlockState state) { public static MovementBehaviour getBehaviour(BlockState state) {
MovementBehaviour behaviour = BLOCK_BEHAVIOURS.get(state.getBlock()); return REGISTRY.get(state.getBlock());
if (behaviour != null) {
return behaviour;
}
for (BehaviourProvider provider : GLOBAL_BEHAVIOURS) {
behaviour = provider.getBehaviour(state);
if (behaviour != null) {
return behaviour;
}
}
return null;
} }
public static <B extends Block> NonNullConsumer<? super B> movementBehaviour( /**
MovementBehaviour behaviour) { * Creates a consumer that will register a behavior to a block. Useful for Registrate.
return b -> registerBehaviour(b, behaviour); */
public static <B extends Block> NonNullConsumer<? super B> movementBehaviour(MovementBehaviour behaviour) {
return b -> REGISTRY.register(b, behaviour);
} }
static void registerDefaults() { static void registerDefaults() {
registerBehaviour(Blocks.BELL, new BellMovementBehaviour()); REGISTRY.register(Blocks.BELL, new BellMovementBehaviour());
registerBehaviour(Blocks.CAMPFIRE, new CampfireMovementBehaviour()); REGISTRY.register(Blocks.CAMPFIRE, new CampfireMovementBehaviour());
registerBehaviour(Blocks.SOUL_CAMPFIRE, new CampfireMovementBehaviour()); REGISTRY.register(Blocks.SOUL_CAMPFIRE, new CampfireMovementBehaviour());
DispenserMovementBehaviour.gatherMovedDispenseItemBehaviours(); DispenserMovementBehaviour.gatherMovedDispenseItemBehaviours();
registerBehaviour(Blocks.DISPENSER, new DispenserMovementBehaviour()); REGISTRY.register(Blocks.DISPENSER, new DispenserMovementBehaviour());
registerBehaviour(Blocks.DROPPER, new DropperMovementBehaviour()); REGISTRY.register(Blocks.DROPPER, new DropperMovementBehaviour());
}
public interface BehaviourProvider {
@Nullable
MovementBehaviour getBehaviour(BlockState state);
} }
} }

View file

@ -33,7 +33,6 @@ import com.simibubi.create.foundation.data.CreateRegistrate;
import com.simibubi.create.foundation.item.ItemDescription; import com.simibubi.create.foundation.item.ItemDescription;
import com.simibubi.create.foundation.item.KineticStats; import com.simibubi.create.foundation.item.KineticStats;
import com.simibubi.create.foundation.item.TooltipModifier; import com.simibubi.create.foundation.item.TooltipModifier;
import com.simibubi.create.foundation.utility.AttachedRegistry;
import com.simibubi.create.foundation.utility.CreateNBTProcessors; import com.simibubi.create.foundation.utility.CreateNBTProcessors;
import com.simibubi.create.infrastructure.command.ServerLagger; import com.simibubi.create.infrastructure.command.ServerLagger;
import com.simibubi.create.infrastructure.config.AllConfigs; import com.simibubi.create.infrastructure.config.AllConfigs;
@ -48,6 +47,7 @@ import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.common.ForgeMod; import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
@ -140,8 +140,6 @@ public class Create {
// FIXME: some of these registrations are not thread-safe // FIXME: some of these registrations are not thread-safe
AllMovementBehaviours.registerDefaults(); AllMovementBehaviours.registerDefaults();
AllInteractionBehaviours.registerDefaults(); AllInteractionBehaviours.registerDefaults();
AllPortalTracks.registerDefaults();
AllDisplayBehaviours.registerDefaults();
ContraptionMovementSetting.registerDefaults(); ContraptionMovementSetting.registerDefaults();
BogeySizes.init(); BogeySizes.init();
AllBogeyStyles.init(); AllBogeyStyles.init();
@ -173,9 +171,10 @@ public class Create {
// These registrations use Create's registered objects directly so they must run after registration has finished. // These registrations use Create's registered objects directly so they must run after registration has finished.
BuiltinPotatoProjectileTypes.register(); BuiltinPotatoProjectileTypes.register();
BoilerHeaters.registerDefaults(); BoilerHeaters.registerDefaults();
AllPortalTracks.registerDefaults();
AllDisplayBehaviours.registerDefaults();
// -- // --
AttachedRegistry.unwrapAll();
AllAdvancements.register(); AllAdvancements.register();
AllTriggers.register(); AllTriggers.register();
}); });

View file

@ -3,7 +3,7 @@ package com.simibubi.create.api.contraption.storage;
import com.simibubi.create.Create; import com.simibubi.create.Create;
import com.simibubi.create.api.contraption.storage.fluid.MountedFluidStorageType; import com.simibubi.create.api.contraption.storage.fluid.MountedFluidStorageType;
import com.simibubi.create.api.contraption.storage.item.MountedItemStorageType; import com.simibubi.create.api.contraption.storage.item.MountedItemStorageType;
import com.simibubi.create.api.lookup.BlockLookup; import com.simibubi.create.api.registry.AttachedRegistry;
import com.simibubi.create.impl.contraption.storage.MountedStorageTypeRegistryImpl; import com.simibubi.create.impl.contraption.storage.MountedStorageTypeRegistryImpl;
import com.tterrag.registrate.builders.BlockBuilder; import com.tterrag.registrate.builders.BlockBuilder;
import com.tterrag.registrate.util.entry.RegistryEntry; import com.tterrag.registrate.util.entry.RegistryEntry;
@ -12,9 +12,10 @@ import com.tterrag.registrate.util.nullness.NonNullUnaryOperator;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraftforge.registries.IForgeRegistry; import net.minecraftforge.registries.IForgeRegistry;
public class MountedStorageTypeRegistry { public class MountedStorageTypeRegistries {
public static final ResourceKey<Registry<MountedItemStorageType<?>>> ITEMS = ResourceKey.createRegistryKey( public static final ResourceKey<Registry<MountedItemStorageType<?>>> ITEMS = ResourceKey.createRegistryKey(
Create.asResource("mounted_item_storage_type") Create.asResource("mounted_item_storage_type")
); );
@ -22,16 +23,8 @@ public class MountedStorageTypeRegistry {
Create.asResource("mounted_fluid_storage_type") Create.asResource("mounted_fluid_storage_type")
); );
/** public static final AttachedRegistry<Block, MountedItemStorageType<?>> ITEM_STORAGES = MountedStorageTypeRegistryImpl.ITEM_STORAGES;
* Lookup used for finding the item storage type associated with a block. public static final AttachedRegistry<Block, MountedFluidStorageType<?>> FLUID_STORAGES = MountedStorageTypeRegistryImpl.FLUID_STORAGES;
* @see BlockLookup
*/
public static final BlockLookup<MountedItemStorageType<?>> ITEM_LOOKUP = MountedStorageTypeRegistryImpl.ITEM_LOOKUP;
/**
* Lookup used for finding the fluid storage type associated with a block.
* @see BlockLookup
*/
public static final BlockLookup<MountedFluidStorageType<?>> FLUID_LOOKUP = MountedStorageTypeRegistryImpl.FLUID_LOOKUP;
/** /**
* @throws NullPointerException if called before registry registration * @throws NullPointerException if called before registry registration
@ -52,7 +45,7 @@ public class MountedStorageTypeRegistry {
* that will register the given MountedItemStorageType to a block when ready. * that will register the given MountedItemStorageType to a block when ready.
*/ */
public static <B extends Block, P> NonNullUnaryOperator<BlockBuilder<B, P>> mountedItemStorage(RegistryEntry<? extends MountedItemStorageType<?>> type) { public static <B extends Block, P> NonNullUnaryOperator<BlockBuilder<B, P>> mountedItemStorage(RegistryEntry<? extends MountedItemStorageType<?>> type) {
return builder -> builder.onRegisterAfter(ITEMS, block -> ITEM_LOOKUP.register(block, type.get())); return builder -> builder.onRegisterAfter(ITEMS, block -> ITEM_STORAGES.register(block, type.get()));
} }
/** /**
@ -60,6 +53,6 @@ public class MountedStorageTypeRegistry {
* that will register the given MountedFluidStorageType to a block when ready. * that will register the given MountedFluidStorageType to a block when ready.
*/ */
public static <B extends Block, P> NonNullUnaryOperator<BlockBuilder<B, P>> mountedFluidStorage(RegistryEntry<? extends MountedFluidStorageType<?>> type) { public static <B extends Block, P> NonNullUnaryOperator<BlockBuilder<B, P>> mountedFluidStorage(RegistryEntry<? extends MountedFluidStorageType<?>> type) {
return builder -> builder.onRegisterAfter(ITEMS, block -> FLUID_LOOKUP.register(block, type.get())); return builder -> builder.onRegisterAfter(ITEMS, block -> FLUID_STORAGES.register(block, type.get()));
} }
} }

View file

@ -3,7 +3,7 @@ package com.simibubi.create.api.contraption.storage.fluid;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.simibubi.create.api.contraption.storage.MountedStorageTypeRegistry; import com.simibubi.create.api.contraption.storage.MountedStorageTypeRegistries;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.ExtraCodecs; import net.minecraft.util.ExtraCodecs;
@ -13,7 +13,7 @@ import net.minecraft.world.level.block.state.BlockState;
public abstract class MountedFluidStorageType<T extends MountedFluidStorage> { public abstract class MountedFluidStorageType<T extends MountedFluidStorage> {
public static final Codec<MountedFluidStorageType<?>> CODEC = ExtraCodecs.lazyInitializedCodec( public static final Codec<MountedFluidStorageType<?>> CODEC = ExtraCodecs.lazyInitializedCodec(
() -> MountedStorageTypeRegistry.getFluidsRegistry().getCodec() () -> MountedStorageTypeRegistries.getFluidsRegistry().getCodec()
); );
public final Codec<? extends T> codec; public final Codec<? extends T> codec;

View file

@ -1,7 +1,8 @@
package com.simibubi.create.api.contraption.storage.fluid.registrate; package com.simibubi.create.api.contraption.storage.fluid.registrate;
import com.simibubi.create.api.contraption.storage.MountedStorageTypeRegistry; import com.simibubi.create.api.contraption.storage.MountedStorageTypeRegistries;
import com.simibubi.create.api.contraption.storage.fluid.MountedFluidStorageType; import com.simibubi.create.api.contraption.storage.fluid.MountedFluidStorageType;
import com.simibubi.create.api.registry.AttachedRegistry;
import com.tterrag.registrate.AbstractRegistrate; import com.tterrag.registrate.AbstractRegistrate;
import com.tterrag.registrate.builders.AbstractBuilder; import com.tterrag.registrate.builders.AbstractBuilder;
import com.tterrag.registrate.builders.BuilderCallback; import com.tterrag.registrate.builders.BuilderCallback;
@ -14,17 +15,17 @@ public class MountedFluidStorageTypeBuilder<T extends MountedFluidStorageType<?>
private final T type; private final T type;
public MountedFluidStorageTypeBuilder(AbstractRegistrate<?> owner, P parent, String name, BuilderCallback callback, T type) { public MountedFluidStorageTypeBuilder(AbstractRegistrate<?> owner, P parent, String name, BuilderCallback callback, T type) {
super(owner, parent, name, callback, MountedStorageTypeRegistry.FLUIDS); super(owner, parent, name, callback, MountedStorageTypeRegistries.FLUIDS);
this.type = type; this.type = type;
} }
public MountedFluidStorageTypeBuilder<T, P> registerTo(Block block) { public MountedFluidStorageTypeBuilder<T, P> registerTo(Block block) {
MountedStorageTypeRegistry.FLUID_LOOKUP.register(block, this.type); MountedStorageTypeRegistries.FLUID_STORAGES.register(block, this.type);
return this; return this;
} }
public MountedFluidStorageTypeBuilder<T, P> registerTo(TagKey<Block> tag) { public MountedFluidStorageTypeBuilder<T, P> registerTo(TagKey<Block> tag) {
MountedStorageTypeRegistry.FLUID_LOOKUP.registerTag(tag, this.type); MountedStorageTypeRegistries.FLUID_STORAGES.registerProvider(AttachedRegistry.Provider.forBlockTag(tag, this.type));
return this; return this;
} }

View file

@ -3,7 +3,7 @@ package com.simibubi.create.api.contraption.storage.item;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.simibubi.create.api.contraption.storage.MountedStorageTypeRegistry; import com.simibubi.create.api.contraption.storage.MountedStorageTypeRegistries;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.util.ExtraCodecs; import net.minecraft.util.ExtraCodecs;
@ -13,7 +13,7 @@ import net.minecraft.world.level.block.state.BlockState;
public abstract class MountedItemStorageType<T extends MountedItemStorage> { public abstract class MountedItemStorageType<T extends MountedItemStorage> {
public static final Codec<MountedItemStorageType<?>> CODEC = ExtraCodecs.lazyInitializedCodec( public static final Codec<MountedItemStorageType<?>> CODEC = ExtraCodecs.lazyInitializedCodec(
() -> MountedStorageTypeRegistry.getItemsRegistry().getCodec() () -> MountedStorageTypeRegistries.getItemsRegistry().getCodec()
); );
public final Codec<? extends T> codec; public final Codec<? extends T> codec;

View file

@ -1,7 +1,8 @@
package com.simibubi.create.api.contraption.storage.item.registrate; package com.simibubi.create.api.contraption.storage.item.registrate;
import com.simibubi.create.api.contraption.storage.MountedStorageTypeRegistry; import com.simibubi.create.api.contraption.storage.MountedStorageTypeRegistries;
import com.simibubi.create.api.contraption.storage.item.MountedItemStorageType; import com.simibubi.create.api.contraption.storage.item.MountedItemStorageType;
import com.simibubi.create.api.registry.AttachedRegistry;
import com.tterrag.registrate.AbstractRegistrate; import com.tterrag.registrate.AbstractRegistrate;
import com.tterrag.registrate.builders.AbstractBuilder; import com.tterrag.registrate.builders.AbstractBuilder;
import com.tterrag.registrate.builders.BuilderCallback; import com.tterrag.registrate.builders.BuilderCallback;
@ -14,17 +15,17 @@ public class MountedItemStorageTypeBuilder<T extends MountedItemStorageType<?>,
private final T type; private final T type;
public MountedItemStorageTypeBuilder(AbstractRegistrate<?> owner, P parent, String name, BuilderCallback callback, T type) { public MountedItemStorageTypeBuilder(AbstractRegistrate<?> owner, P parent, String name, BuilderCallback callback, T type) {
super(owner, parent, name, callback, MountedStorageTypeRegistry.ITEMS); super(owner, parent, name, callback, MountedStorageTypeRegistries.ITEMS);
this.type = type; this.type = type;
} }
public MountedItemStorageTypeBuilder<T, P> registerTo(Block block) { public MountedItemStorageTypeBuilder<T, P> registerTo(Block block) {
MountedStorageTypeRegistry.ITEM_LOOKUP.register(block, this.type); MountedStorageTypeRegistries.ITEM_STORAGES.register(block, this.type);
return this; return this;
} }
public MountedItemStorageTypeBuilder<T, P> registerTo(TagKey<Block> tag) { public MountedItemStorageTypeBuilder<T, P> registerTo(TagKey<Block> tag) {
MountedStorageTypeRegistry.ITEM_LOOKUP.registerTag(tag, this.type); MountedStorageTypeRegistries.ITEM_STORAGES.registerProvider(AttachedRegistry.Provider.forBlockTag(tag, this.type));
return this; return this;
} }

View file

@ -1,52 +1,49 @@
package com.simibubi.create.api.contraption.train; package com.simibubi.create.api.contraption.train;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllInteractionBehaviours;
import com.simibubi.create.content.processing.burner.BlazeBurnerBlock;
import com.simibubi.create.content.processing.burner.BlockBasedTrainConductorInteractionBehaviour;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.ApiStatus;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.jetbrains.annotations.ApiStatus;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllInteractionBehaviours;
import com.simibubi.create.content.processing.burner.BlazeBurnerBlock;
import com.simibubi.create.content.processing.burner.BlockBasedTrainConductorInteractionBehaviour;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
/** /**
* All required methods to make your block a train conductor similar to the blaze burner * All required methods to make your block a train conductor similar to the blaze burner
*/ */
@FunctionalInterface
public interface TrainConductorHandler { public interface TrainConductorHandler {
@ApiStatus.Internal @ApiStatus.Internal
List<TrainConductorHandler> CONDUCTOR_HANDLERS = new ArrayList<>(); List<TrainConductorHandler> CONDUCTOR_HANDLERS = new ArrayList<>();
boolean isValidConductor(BlockState state); boolean isValidConductor(BlockState state);
private static void registerHandler(TrainConductorHandler handler) { private static void registerHandler(TrainConductorHandler handler) {
CONDUCTOR_HANDLERS.add(handler); CONDUCTOR_HANDLERS.add(handler);
} }
static void registerConductor(ResourceLocation blockRl, Predicate<BlockState> isValidConductor, UpdateScheduleCallback updateScheduleCallback) { static void registerConductor(Block block, Predicate<BlockState> isValidConductor, UpdateScheduleCallback updateScheduleCallback) {
AllInteractionBehaviours.registerBehaviour(blockRl, new BlockBasedTrainConductorInteractionBehaviour(isValidConductor, updateScheduleCallback)); BlockBasedTrainConductorInteractionBehaviour behavior = new BlockBasedTrainConductorInteractionBehaviour(isValidConductor, updateScheduleCallback);
AllInteractionBehaviours.REGISTRY.register(block, behavior);
registerHandler(isValidConductor::test); registerHandler(isValidConductor::test);
} }
@ApiStatus.Internal @ApiStatus.Internal
static void registerBlazeBurner() { static void registerBlazeBurner(Block block) {
registerConductor(AllBlocks.BLAZE_BURNER.getId(), blockState -> AllBlocks.BLAZE_BURNER.has(blockState) registerConductor(block, blockState -> AllBlocks.BLAZE_BURNER.has(blockState)
&& blockState.getValue(BlazeBurnerBlock.HEAT_LEVEL) != BlazeBurnerBlock.HeatLevel.NONE, UpdateScheduleCallback.EMPTY); && blockState.getValue(BlazeBurnerBlock.HEAT_LEVEL) != BlazeBurnerBlock.HeatLevel.NONE, UpdateScheduleCallback.EMPTY);
} }
@FunctionalInterface
interface UpdateScheduleCallback { interface UpdateScheduleCallback {
UpdateScheduleCallback EMPTY = (hasSchedule, blockState, blockStateSetter) -> {}; UpdateScheduleCallback EMPTY = (hasSchedule, blockState, blockStateSetter) -> {};
void update(boolean hasSchedule, BlockState currentBlockState, Consumer<BlockState> blockStateSetter); void update(boolean hasSchedule, BlockState currentBlockState, Consumer<BlockState> blockStateSetter);

View file

@ -1,49 +0,0 @@
package com.simibubi.create.api.contraption.transformable;
import com.simibubi.create.content.contraptions.StructureTransform;
import com.simibubi.create.impl.contraption.transformable.ContraptionTransformableRegistryImpl;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
/**
* Registry for registering new contraption transformations
* to properly place blocks when disassembled after being part of a contraption
*/
public class ContraptionTransformableRegistry {
/**
* Register a new transform for a provided block
*
* @param block The block you want to register a new {@link TransformableBlock} for
* @param transformableBlock The transform that should be applied whenever this block is being placed from
* contraption disassembly
*/
public static void registerForBlock(Block block, TransformableBlock transformableBlock) {
ContraptionTransformableRegistryImpl.registerForBlock(block, transformableBlock);
}
/**
* Register a new transform for a provided block entity type
*
* @param blockEntityType The blockEntityType you want to register a new {@link TransformableBlockEntity} for
* @param transformableBlockEntity The transform that should be applied whenever this block entity type is
* being placed from contraption disassembly
*/
public static void registerForBlockEntity(BlockEntityType<?> blockEntityType, TransformableBlockEntity transformableBlockEntity) {
ContraptionTransformableRegistryImpl.registerForBlockEntity(blockEntityType, transformableBlockEntity);
}
// --- Interfaces that provide the context that would be accessible if you implemented the ITransformable* interfaces ---
@FunctionalInterface
public interface TransformableBlock {
BlockState transform(Block block, BlockState state, StructureTransform transform);
}
@FunctionalInterface
public interface TransformableBlockEntity {
void transform(BlockEntity blockEntity, StructureTransform transform);
}
}

View file

@ -0,0 +1,28 @@
package com.simibubi.create.api.contraption.transformable;
import com.simibubi.create.api.registry.AttachedRegistry;
import com.simibubi.create.content.contraptions.StructureTransform;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
/**
* Registry for custom transformations to apply to blocks after they've been moved by a contraption.
* These interfaces are alternatives to the {@link ITransformableBlock} and {@link ITransformableBlockEntity} interfaces.
*/
public class MovedBlockTransformerRegistries {
public static final AttachedRegistry<Block, BlockTransformer> BLOCK_TRANSFORMERS = AttachedRegistry.create();
public static final AttachedRegistry<BlockEntityType<?>, BlockEntityTransformer> BLOCK_ENTITY_TRANSFORMERS = AttachedRegistry.create();
@FunctionalInterface
public interface BlockTransformer {
BlockState transform(Block block, BlockState state, StructureTransform transform);
}
@FunctionalInterface
public interface BlockEntityTransformer {
void transform(BlockEntity be, StructureTransform transform);
}
}

View file

@ -1,66 +0,0 @@
package com.simibubi.create.api.lookup;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.impl.lookup.BlockLookupImpl;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
/**
* Lookup for objects provided by blocks. Values can either be registered directly
* or found lazily through providers. Providers are only queried once per block.
* If they return a value, that value is cached. If they don't, that block is recorded
* as not having a corresponding value.
* <p>
* Provided values are reset on resource reloads and will be re-queried and re-cached the
* next time a block is queried.
* <p>
* All providers are expected to be registered synchronously during game init.
* Adding new ones late is not supported.
*/
@ApiStatus.NonExtendable
public interface BlockLookup<T> {
@Nullable
T find(Block block);
/**
* Shortcut to avoid calling getBlock() on a BlockState.
*/
@Nullable
T find(BlockState state);
/**
* Register a value to one block.
*/
void register(Block block, T value);
/**
* Register a value to all entries of a tag.
*/
void registerTag(TagKey<Block> tag, T value);
/**
* Register a new provider that will be queried.
* Providers are queried in reverse-registration order.
*/
void registerProvider(Provider<T> provider);
static <T> BlockLookup<T> create() {
return new BlockLookupImpl<>();
}
static <T> BlockLookup<T> create(Provider<T> initialProvider) {
BlockLookup<T> lookup = new BlockLookupImpl<>();
lookup.registerProvider(initialProvider);
return lookup;
}
@FunctionalInterface
interface Provider<T> {
@Nullable
T get(Block block);
}
}

View file

@ -0,0 +1,92 @@
package com.simibubi.create.api.registry;
import java.util.function.Function;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.impl.registry.AttachedRegistryImpl;
import com.simibubi.create.impl.registry.TagProviderImpl;
import net.minecraft.core.Holder;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
/**
* A mapping of registered objects to something else.
* This class is thread-safe, and may be safely used during parallel mod init.
*/
public interface AttachedRegistry<K, V> {
/**
* Register an association between a key and a value.
* @throws IllegalArgumentException if the object already has an associated value
*/
void register(K object, V value);
/**
* Add a new provider to this registry. For information on providers, see {@link Provider}.
* @throws IllegalArgumentException if the provider has already been registered to this registry
*/
void registerProvider(Provider<K, V> provider);
/**
* Invalidate the cached values provided by the given provider, so they get re-computed on the next query.
* @throws IllegalArgumentException if the provider is not registered to this registry
*/
void invalidateProvider(Provider<K, V> provider);
/**
* Query the value associated with the given object. May be null if no association is present.
*/
@Nullable
V get(K object);
static <K, V> AttachedRegistry<K, V> create() {
return new AttachedRegistryImpl<>();
}
/**
* A provider can provide values to the registry in a lazy fashion. When a key does not have an
* associated value, all providers will be queried in reverse-registration order.
* <p>
* The values returned by providers are cached so that repeated queries always return the same value.
* To invalidate the cache of a provider, call {@link AttachedRegistry#invalidateProvider(Provider)}.
*/
@FunctionalInterface
interface Provider<K, V> {
@Nullable
V get(K object);
/**
* Called by the AttachedRegistry this provider is registered to after it's registered.
* This is useful for behavior that should only happen if a provider is actually registered,
* such as registering event listeners.
*/
default void onRegister(AttachedRegistry<K, V> registry) {
}
/**
* Create a provider that will return the same value for all entries in a tag.
* The Provider will invalidate itself when tags are reloaded.
*/
static <K, V> Provider<K, V> forTag(TagKey<K> tag, Function<K, Holder<K>> holderGetter, V value) {
return new TagProviderImpl<>(tag, holderGetter, value);
}
/**
* Shortcut for {@link #forTag} when the registry's type is Block.
*/
@SuppressWarnings("deprecation")
static <V> Provider<Block, V> forBlockTag(TagKey<Block> tag, V value) {
return new TagProviderImpl<>(tag, Block::builtInRegistryHolder, value);
}
/**
* Shortcut for {@link #forTag} when the registry's type is Item.
*/
@SuppressWarnings("deprecation")
static <V> Provider<Item, V> forItemTag(TagKey<Item> tag, V value) {
return new TagProviderImpl<>(tag, Item::builtInRegistryHolder, value);
}
}
}

View file

@ -0,0 +1,27 @@
package com.simibubi.create.api.schematic.nbt;
import com.simibubi.create.api.registry.AttachedRegistry;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
/**
* Registry for safe NBT writers, used for filtering unsafe BlockEntity data out of schematics.
* <p>
* This is used to exclude specific tags that would result in exploits, ex. signs that execute commands when clicked.
* <p>
* This is provided as an alternative to {@link IPartialSafeNBT}.
*/
public class SafeNbtWriterRegistry {
public static final AttachedRegistry<BlockEntityType<?>, SafeNbtWriter> REGISTRY = AttachedRegistry.create();
@FunctionalInterface
public interface SafeNbtWriter {
/**
* Write filtered, safe NBT to the given tag. This is always called on the logical server.
* @param tag the NBT tag to write to
*/
void writeSafe(BlockEntity be, CompoundTag tag);
}
}

View file

@ -1,37 +0,0 @@
package com.simibubi.create.api.schematic.nbt;
import com.simibubi.create.impl.schematic.nbt.SchematicSafeNBTRegistryImpl;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
/**
* Registry for modifying the data of BlockEntities when being placed with the schematic system.
* </br>
* Mostly used to exclude specific tags that would result in exploits from being written.
*/
public class SchematicSafeNBTRegistry {
/**
* Register a new partial safe nbt provider for a specific blockEntityType
*
* @param blockEntityType The block entity type you would like to register this for
* @param safeNBT The custom PartialSafeNBT provider you would like to register for this blockEntityType,
* your {@link ContextProvidingPartialSafeNBT#writeSafe(BlockEntity, CompoundTag)} method will be
* called on the passed {@link ContextProvidingPartialSafeNBT}
* when the block entities data is being prepared for placement.
*/
public static void register(BlockEntityType<? extends BlockEntity> blockEntityType, ContextProvidingPartialSafeNBT safeNBT) {
SchematicSafeNBTRegistryImpl.register(blockEntityType, safeNBT);
}
// --- Interface that provides the context that would be available if you were to implement IPartialSafeNBT instead ---
@FunctionalInterface
public interface ContextProvidingPartialSafeNBT {
/**
* This will always be called from the logical server
*/
void writeSafe(BlockEntity blockEntity, CompoundTag tag);
}
}

View file

@ -0,0 +1,45 @@
package com.simibubi.create.api.schematic.requirement;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.api.registry.AttachedRegistry;
import com.simibubi.create.content.schematics.requirement.ItemRequirement;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
/**
* Registries for custom schematic requirements for blocks, block entities, and entities. These requirements determine
* the items that are needed for placement into the world through schematics.
* <p>
* This is provided as an alternative to the following interfaces:
* <ul>
* <li>{@link ISpecialBlockItemRequirement}</li>
* <li>{@link ISpecialBlockEntityItemRequirement}</li>
* <li>{@link ISpecialEntityItemRequirement}</li>
* </ul>
*/
public class SchematicRequirementRegistries {
public static final AttachedRegistry<Block, BlockRequirement> BLOCKS = AttachedRegistry.create();
public static final AttachedRegistry<BlockEntityType<?>, BlockEntityRequirement> BLOCK_ENTITIES = AttachedRegistry.create();
public static final AttachedRegistry<EntityType<?>, EntityRequirement> ENTITIES = AttachedRegistry.create();
@FunctionalInterface
public interface BlockRequirement {
ItemRequirement getRequiredItems(Block block, BlockState state, @Nullable BlockEntity blockEntity);
}
@FunctionalInterface
public interface BlockEntityRequirement {
ItemRequirement getRequiredItems(BlockEntity blockEntity, BlockState state);
}
@FunctionalInterface
public interface EntityRequirement {
ItemRequirement getRequiredItems(Entity entity);
}
}

View file

@ -1,115 +0,0 @@
package com.simibubi.create.api.schematic.requirement;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.content.schematics.requirement.ItemRequirement;
import com.simibubi.create.impl.schematic.requirement.SchematicRequirementsRegistryImpl;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
/**
* Registry for schematic requirements for blocks, block entities, and entities.
*/
public class SchematicRequirementsRegistry {
/**
* Register a new special requirement for a specified block
*
* @param block The block you want to register a {@link BlockRequirement} for
* @param requirement The requirement you would like to add to this block,
* the {@link BlockRequirement#getRequiredItems(Block, BlockState, BlockEntity)}
* method will be called on the {@link BlockRequirement} you have provided,
* and you will be able to insert requirements based off the context that is given
*/
public static void registerForBlock(Block block, BlockRequirement requirement) {
SchematicRequirementsRegistryImpl.registerForBlock(block, requirement);
}
/**
* Register a new special requirement for a specified block
*
* @param block The id of the block you want to register a {@link BlockRequirement} for
* @param requirement The requirement you would like to add to this block,
* the {@link BlockRequirement#getRequiredItems(Block, BlockState, BlockEntity)}
* method will be called on the {@link BlockRequirement} you have provided,
* and you will be able to insert requirements based off the context that is given
*/
public static void registerForBlock(ResourceLocation block, BlockRequirement requirement) {
SchematicRequirementsRegistryImpl.registerForBlock(block, requirement);
}
/**
* Register a new special requirement for a specified block entity type
*
* @param blockEntityType The blockEntityType you want to register a {@link BlockEntityRequirement} for
* @param requirement The requirement you would like to add to this block entity type,
* the {@link BlockEntityRequirement#getRequiredItems(BlockEntity, BlockState)}
* method will be called on the {@link BlockEntityRequirement} you have provided,
* and you will be able to insert requirements based off the context that is given
*/
public static void registerForBlockEntity(BlockEntityType<BlockEntity> blockEntityType, BlockEntityRequirement requirement) {
SchematicRequirementsRegistryImpl.registerForBlockEntity(blockEntityType, requirement);
}
/**
* Register a new special requirement for a specified block entity type
*
* @param blockEntityType The id of the blockEntityType you want to register a {@link BlockEntityRequirement} for
* @param requirement The requirement you would like to add to this block entity type,
* the {@link BlockEntityRequirement#getRequiredItems(BlockEntity, BlockState)}
* method will be called on the {@link BlockEntityRequirement} you have provided,
* and you will be able to insert requirements based off the context that is given
*/
public static void registerForBlockEntity(ResourceLocation blockEntityType, BlockEntityRequirement requirement) {
SchematicRequirementsRegistryImpl.registerForBlockEntity(blockEntityType, requirement);
}
/**
* Register a new special requirement for a specified entity type
*
* @param entityType The entityType you want to register a {@link EntityRequirement} for
* @param requirement The requirement you would like to add to this entity type,
* the {@link EntityRequirement#getRequiredItems(Entity)}
* method will be called on the {@link EntityRequirement} you have provided,
* and you will be able to insert requirements based off the context that is given
*/
public static void registerForEntity(EntityType<Entity> entityType, EntityRequirement requirement) {
SchematicRequirementsRegistryImpl.registerForEntity(entityType, requirement);
}
/**
* Register a new special requirement for a specified entity type
*
* @param entityType The id of the entityType you want to register a {@link EntityRequirement} for
* @param requirement The requirement you would like to add to this entity type,
* the {@link EntityRequirement#getRequiredItems(Entity)}
* method will be called on the {@link EntityRequirement} you have provided,
* and you will be able to insert requirements based off the context that is given
*/
public static void registerForEntity(ResourceLocation entityType, EntityRequirement requirement) {
SchematicRequirementsRegistryImpl.registerForEntity(entityType, requirement);
}
// --- Interfaces that provide the context that would be accessible if you implemented the ISpecial* interfaces ---
@FunctionalInterface
public interface BlockRequirement {
ItemRequirement getRequiredItems(Block block, BlockState state, @Nullable BlockEntity blockEntity);
}
@FunctionalInterface
public interface BlockEntityRequirement {
ItemRequirement getRequiredItems(BlockEntity blockEntity, BlockState state);
}
@FunctionalInterface
public interface EntityRequirement {
ItemRequirement getRequiredItems(Entity entity);
}
}

View file

@ -1,39 +1,30 @@
package com.simibubi.create.content.contraptions; package com.simibubi.create.content.contraptions;
import com.simibubi.create.foundation.utility.AttachedRegistry; import java.util.Collection;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import com.simibubi.create.api.registry.AttachedRegistry;
import com.simibubi.create.infrastructure.config.AllConfigs; import com.simibubi.create.infrastructure.config.AllConfigs;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
import net.minecraftforge.common.extensions.IForgeBlock;
import net.minecraftforge.registries.ForgeRegistries;
import javax.annotation.Nullable; import net.minecraftforge.common.extensions.IForgeBlock;
import java.util.Collection;
import java.util.function.Supplier;
public enum ContraptionMovementSetting { public enum ContraptionMovementSetting {
MOVABLE, NO_PICKUP, UNMOVABLE; MOVABLE, NO_PICKUP, UNMOVABLE;
private static final AttachedRegistry<Block, Supplier<ContraptionMovementSetting>> SETTING_SUPPLIERS = new AttachedRegistry<>(ForgeRegistries.BLOCKS); public static final AttachedRegistry<Block, Supplier<ContraptionMovementSetting>> REGISTRY = AttachedRegistry.create();
public static void register(ResourceLocation block, Supplier<ContraptionMovementSetting> settingSupplier) {
SETTING_SUPPLIERS.register(block, settingSupplier);
}
public static void register(Block block, Supplier<ContraptionMovementSetting> settingSupplier) {
SETTING_SUPPLIERS.register(block, settingSupplier);
}
@Nullable @Nullable
public static ContraptionMovementSetting get(Block block) { public static ContraptionMovementSetting get(Block block) {
if (block instanceof IMovementSettingProvider provider) if (block instanceof IMovementSettingProvider provider)
return provider.getContraptionMovementSetting(); return provider.getContraptionMovementSetting();
Supplier<ContraptionMovementSetting> supplier = SETTING_SUPPLIERS.get(block); Supplier<ContraptionMovementSetting> supplier = REGISTRY.get(block);
if (supplier == null) return supplier == null ? null : supplier.get();
return null;
return supplier.get();
} }
public static boolean allAre(Collection<StructureTemplate.StructureBlockInfo> blocks, ContraptionMovementSetting are) { public static boolean allAre(Collection<StructureTemplate.StructureBlockInfo> blocks, ContraptionMovementSetting are) {
@ -45,12 +36,12 @@ public enum ContraptionMovementSetting {
} }
public static void registerDefaults() { public static void registerDefaults() {
register(Blocks.SPAWNER, () -> AllConfigs.server().kinetics.spawnerMovement.get()); REGISTRY.register(Blocks.SPAWNER, () -> AllConfigs.server().kinetics.spawnerMovement.get());
register(Blocks.BUDDING_AMETHYST, () -> AllConfigs.server().kinetics.amethystMovement.get()); REGISTRY.register(Blocks.BUDDING_AMETHYST, () -> AllConfigs.server().kinetics.amethystMovement.get());
register(Blocks.OBSIDIAN, () -> AllConfigs.server().kinetics.obsidianMovement.get()); REGISTRY.register(Blocks.OBSIDIAN, () -> AllConfigs.server().kinetics.obsidianMovement.get());
register(Blocks.CRYING_OBSIDIAN, () -> AllConfigs.server().kinetics.obsidianMovement.get()); REGISTRY.register(Blocks.CRYING_OBSIDIAN, () -> AllConfigs.server().kinetics.obsidianMovement.get());
register(Blocks.RESPAWN_ANCHOR, () -> AllConfigs.server().kinetics.obsidianMovement.get()); REGISTRY.register(Blocks.RESPAWN_ANCHOR, () -> AllConfigs.server().kinetics.obsidianMovement.get());
register(Blocks.REINFORCED_DEEPSLATE, () -> AllConfigs.server().kinetics.reinforcedDeepslateMovement.get()); REGISTRY.register(Blocks.REINFORCED_DEEPSLATE, () -> AllConfigs.server().kinetics.reinforcedDeepslateMovement.get());
} }
public interface IMovementSettingProvider extends IForgeBlock { public interface IMovementSettingProvider extends IForgeBlock {

View file

@ -17,7 +17,7 @@ import com.google.common.collect.Sets.SetView;
import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.util.Pair;
import com.simibubi.create.AllPackets; import com.simibubi.create.AllPackets;
import com.simibubi.create.Create; import com.simibubi.create.Create;
import com.simibubi.create.api.contraption.storage.MountedStorageTypeRegistry; import com.simibubi.create.api.contraption.storage.MountedStorageTypeRegistries;
import com.simibubi.create.api.contraption.storage.SyncedMountedStorage; import com.simibubi.create.api.contraption.storage.SyncedMountedStorage;
import com.simibubi.create.api.contraption.storage.fluid.MountedFluidStorage; import com.simibubi.create.api.contraption.storage.fluid.MountedFluidStorage;
import com.simibubi.create.api.contraption.storage.fluid.MountedFluidStorageType; import com.simibubi.create.api.contraption.storage.fluid.MountedFluidStorageType;
@ -144,7 +144,7 @@ public class MountedStorageManager {
} }
public void addBlock(Level level, BlockState state, BlockPos globalPos, BlockPos localPos, @Nullable BlockEntity be) { public void addBlock(Level level, BlockState state, BlockPos globalPos, BlockPos localPos, @Nullable BlockEntity be) {
MountedItemStorageType<?> itemType = MountedStorageTypeRegistry.ITEM_LOOKUP.find(state); MountedItemStorageType<?> itemType = MountedStorageTypeRegistries.ITEM_STORAGES.get(state.getBlock());
if (itemType != null) { if (itemType != null) {
MountedItemStorage storage = itemType.mount(level, state, globalPos, be); MountedItemStorage storage = itemType.mount(level, state, globalPos, be);
if (storage != null) { if (storage != null) {
@ -152,7 +152,7 @@ public class MountedStorageManager {
} }
} }
MountedFluidStorageType<?> fluidType = MountedStorageTypeRegistry.FLUID_LOOKUP.find(state); MountedFluidStorageType<?> fluidType = MountedStorageTypeRegistries.FLUID_STORAGES.get(state.getBlock());
if (fluidType != null) { if (fluidType != null) {
MountedFluidStorage storage = fluidType.mount(level, state, globalPos, be); MountedFluidStorage storage = fluidType.mount(level, state, globalPos, be);
if (storage != null) { if (storage != null) {
@ -167,7 +167,7 @@ public class MountedStorageManager {
MountedItemStorage itemStorage = this.getAllItemStorages().get(localPos); MountedItemStorage itemStorage = this.getAllItemStorages().get(localPos);
if (itemStorage != null) { if (itemStorage != null) {
MountedItemStorageType<?> expectedType = MountedStorageTypeRegistry.ITEM_LOOKUP.find(state); MountedItemStorageType<?> expectedType = MountedStorageTypeRegistries.ITEM_STORAGES.get(state.getBlock());
if (itemStorage.type == expectedType) { if (itemStorage.type == expectedType) {
itemStorage.unmount(level, state, globalPos, be); itemStorage.unmount(level, state, globalPos, be);
} }
@ -175,7 +175,7 @@ public class MountedStorageManager {
MountedFluidStorage fluidStorage = this.getFluids().storages.get(localPos); MountedFluidStorage fluidStorage = this.getFluids().storages.get(localPos);
if (fluidStorage != null) { if (fluidStorage != null) {
MountedFluidStorageType<?> expectedType = MountedStorageTypeRegistry.FLUID_LOOKUP.find(state); MountedFluidStorageType<?> expectedType = MountedStorageTypeRegistries.FLUID_STORAGES.get(state.getBlock());
if (fluidStorage.type == expectedType) { if (fluidStorage.type == expectedType) {
fluidStorage.unmount(level, state, globalPos, be); fluidStorage.unmount(level, state, globalPos, be);
} }

View file

@ -4,10 +4,11 @@ import static net.minecraft.world.level.block.state.properties.BlockStatePropert
import static net.minecraft.world.level.block.state.properties.BlockStateProperties.FACING; import static net.minecraft.world.level.block.state.properties.BlockStateProperties.FACING;
import static net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING; import static net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING;
import com.simibubi.create.api.contraption.transformable.ContraptionTransformableRegistry;
import com.simibubi.create.api.contraption.transformable.ITransformableBlock; import com.simibubi.create.api.contraption.transformable.ITransformableBlock;
import com.simibubi.create.api.contraption.transformable.ITransformableBlockEntity; import com.simibubi.create.api.contraption.transformable.ITransformableBlockEntity;
import com.simibubi.create.impl.contraption.transformable.ContraptionTransformableRegistryImpl; import com.simibubi.create.api.contraption.transformable.MovedBlockTransformerRegistries;
import com.simibubi.create.api.contraption.transformable.MovedBlockTransformerRegistries.BlockEntityTransformer;
import com.simibubi.create.api.contraption.transformable.MovedBlockTransformerRegistries.BlockTransformer;
import net.createmod.catnip.math.VecHelper; import net.createmod.catnip.math.VecHelper;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -133,9 +134,9 @@ public class StructureTransform {
} }
public void apply(BlockEntity be) { public void apply(BlockEntity be) {
ContraptionTransformableRegistry.TransformableBlockEntity transformableBlockEntity = ContraptionTransformableRegistryImpl.get(be.getType()); BlockEntityTransformer transformer = MovedBlockTransformerRegistries.BLOCK_ENTITY_TRANSFORMERS.get(be.getType());
if (transformableBlockEntity != null) { if (transformer != null) {
transformableBlockEntity.transform(be, this); transformer.transform(be, this);
} else if (be instanceof ITransformableBlockEntity itbe) { } else if (be instanceof ITransformableBlockEntity itbe) {
itbe.transform(this); itbe.transform(this);
} }
@ -148,9 +149,9 @@ public class StructureTransform {
*/ */
public BlockState apply(BlockState state) { public BlockState apply(BlockState state) {
Block block = state.getBlock(); Block block = state.getBlock();
ContraptionTransformableRegistry.TransformableBlock transformableBlock = ContraptionTransformableRegistryImpl.get(block); BlockTransformer transformer = MovedBlockTransformerRegistries.BLOCK_TRANSFORMERS.get(block);
if (transformableBlock != null) { if (transformer != null) {
return transformableBlock.transform(block, state, this); return transformer.transform(block, state, this);
} else if (block instanceof ITransformableBlock transformable) { } else if (block instanceof ITransformableBlock transformable) {
return transformable.transform(state, this); return transformable.transform(state, this);
} }

View file

@ -1,66 +1,39 @@
package com.simibubi.create.content.fluids.tank; package com.simibubi.create.content.fluids.tank;
import java.util.ArrayList;
import java.util.List;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTags.AllBlockTags; import com.simibubi.create.AllTags.AllBlockTags;
import com.simibubi.create.api.registry.AttachedRegistry;
import com.simibubi.create.content.processing.burner.BlazeBurnerBlock; import com.simibubi.create.content.processing.burner.BlazeBurnerBlock;
import com.simibubi.create.content.processing.burner.BlazeBurnerBlock.HeatLevel; import com.simibubi.create.content.processing.burner.BlazeBurnerBlock.HeatLevel;
import com.simibubi.create.foundation.utility.AttachedRegistry;
import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.BlockHelper;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.registries.ForgeRegistries;
public class BoilerHeaters { public class BoilerHeaters {
private static final AttachedRegistry<Block, Heater> BLOCK_HEATERS = new AttachedRegistry<>(ForgeRegistries.BLOCKS); public static final int PASSIVE_HEAT = 0;
private static final List<HeaterProvider> GLOBAL_HEATERS = new ArrayList<>(); public static final int NO_HEAT = -1;
public static void registerHeater(ResourceLocation block, Heater heater) { public static final AttachedRegistry<Block, Heater> REGISTRY = AttachedRegistry.create();
BLOCK_HEATERS.register(block, heater);
}
public static void registerHeater(Block block, Heater heater) { public static final Heater PASSIVE_HEATER = (level, pos, state) -> BlockHelper.isNotUnheated(state) ? PASSIVE_HEAT : NO_HEAT;
BLOCK_HEATERS.register(block, heater);
}
public static void registerHeaterProvider(HeaterProvider provider) {
GLOBAL_HEATERS.add(provider);
}
/** /**
* A return value of {@code -1} represents no heat. * Gets the heat at the given location. If a heater is present, queries it for heat. If not, returns {@link #NO_HEAT}.
* A return value of {@code 0} represents passive heat. * @see Heater#getActiveHeat(Level, BlockPos, BlockState)
* All other positive values are used as the amount of active heat.
*/ */
public static float getActiveHeat(Level level, BlockPos pos, BlockState state) { public static float getActiveHeat(Level level, BlockPos pos, BlockState state) {
Heater heater = BLOCK_HEATERS.get(state.getBlock()); Heater heater = REGISTRY.get(state.getBlock());
if (heater != null) { return heater != null ? heater.getActiveHeat(level, pos, state) : NO_HEAT;
return heater.getActiveHeat(level, pos, state);
}
for (HeaterProvider provider : GLOBAL_HEATERS) {
heater = provider.getHeater(level, pos, state);
if (heater != null) {
return heater.getActiveHeat(level, pos, state);
}
}
return -1;
} }
public static void registerDefaults() { public static void registerDefaults() {
registerHeater(AllBlocks.BLAZE_BURNER.get(), (level, pos, state) -> { REGISTRY.register(AllBlocks.BLAZE_BURNER.get(), (level, pos, state) -> {
HeatLevel value = state.getValue(BlazeBurnerBlock.HEAT_LEVEL); HeatLevel value = state.getValue(BlazeBurnerBlock.HEAT_LEVEL);
if (value == HeatLevel.NONE) { if (value == HeatLevel.NONE) {
return -1; return NO_HEAT;
} }
if (value == HeatLevel.SEETHING) { if (value == HeatLevel.SEETHING) {
return 2; return 2;
@ -68,28 +41,19 @@ public class BoilerHeaters {
if (value.isAtLeast(HeatLevel.FADING)) { if (value.isAtLeast(HeatLevel.FADING)) {
return 1; return 1;
} }
return 0; return PASSIVE_HEAT;
}); });
registerHeaterProvider((level, pos, state) -> { REGISTRY.registerProvider(AttachedRegistry.Provider.forBlockTag(AllBlockTags.PASSIVE_BOILER_HEATERS.tag, PASSIVE_HEATER));
if (AllBlockTags.PASSIVE_BOILER_HEATERS.matches(state) && BlockHelper.isNotUnheated(state)) {
return (level1, pos1, state1) -> 0;
}
return null;
});
} }
@FunctionalInterface
public interface Heater { public interface Heater {
/** /**
* A return value of {@code -1} represents no heat. * @return the amount of heat to provide.
* A return value of {@code 0} represents passive heat. * @see #NO_HEAT
* All other positive values are used as the amount of active heat. * @see #PASSIVE_HEAT
*/ */
float getActiveHeat(Level level, BlockPos pos, BlockState state); float getActiveHeat(Level level, BlockPos pos, BlockState state);
} }
public interface HeaterProvider {
@Nullable
Heater getHeater(Level level, BlockPos pos, BlockState state);
}
} }

View file

@ -9,6 +9,7 @@ import java.util.Map;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.simibubi.create.Create; import com.simibubi.create.Create;
import com.simibubi.create.api.registry.AttachedRegistry;
import com.simibubi.create.compat.Mods; import com.simibubi.create.compat.Mods;
import com.simibubi.create.content.redstone.displayLink.source.ComputerDisplaySource; import com.simibubi.create.content.redstone.displayLink.source.ComputerDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.DeathCounterDisplaySource; import com.simibubi.create.content.redstone.displayLink.source.DeathCounterDisplaySource;
@ -19,7 +20,6 @@ import com.simibubi.create.content.redstone.displayLink.source.ScoreboardDisplay
import com.simibubi.create.content.redstone.displayLink.target.DisplayTarget; import com.simibubi.create.content.redstone.displayLink.target.DisplayTarget;
import com.simibubi.create.content.redstone.displayLink.target.LecternDisplayTarget; import com.simibubi.create.content.redstone.displayLink.target.LecternDisplayTarget;
import com.simibubi.create.content.redstone.displayLink.target.SignDisplayTarget; import com.simibubi.create.content.redstone.displayLink.target.SignDisplayTarget;
import com.simibubi.create.foundation.utility.AttachedRegistry;
import com.tterrag.registrate.util.nullness.NonNullConsumer; import com.tterrag.registrate.util.nullness.NonNullConsumer;
import net.createmod.catnip.platform.CatnipServices; import net.createmod.catnip.platform.CatnipServices;
@ -32,16 +32,17 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.ForgeRegistries;
public class AllDisplayBehaviours { public class AllDisplayBehaviours {
public static final Map<ResourceLocation, DisplayBehaviour> GATHERER_BEHAVIOURS = new HashMap<>(); public static final Map<ResourceLocation, DisplayBehaviour> GATHERER_BEHAVIOURS = new HashMap<>();
private static final AttachedRegistry<Block, List<DisplaySource>> SOURCES_BY_BLOCK = new AttachedRegistry<>(ForgeRegistries.BLOCKS); private static final AttachedRegistry<Block, List<DisplaySource>> SOURCES_BY_BLOCK = AttachedRegistry.create();
private static final AttachedRegistry<BlockEntityType<?>, List<DisplaySource>> SOURCES_BY_BLOCK_ENTITY = new AttachedRegistry<>(ForgeRegistries.BLOCK_ENTITY_TYPES); private static final AttachedRegistry<BlockEntityType<?>, List<DisplaySource>> SOURCES_BY_BLOCK_ENTITY = AttachedRegistry.create();
private static final AttachedRegistry<Block, DisplayTarget> TARGETS_BY_BLOCK = new AttachedRegistry<>(ForgeRegistries.BLOCKS); private static final AttachedRegistry<Block, DisplayTarget> TARGETS_BY_BLOCK = AttachedRegistry.create();
private static final AttachedRegistry<BlockEntityType<?>, DisplayTarget> TARGETS_BY_BLOCK_ENTITY = new AttachedRegistry<>(ForgeRegistries.BLOCK_ENTITY_TYPES); private static final AttachedRegistry<BlockEntityType<?>, DisplayTarget> TARGETS_BY_BLOCK_ENTITY = AttachedRegistry.create();
public static DisplayBehaviour register(ResourceLocation id, DisplayBehaviour behaviour) { public static DisplayBehaviour register(ResourceLocation id, DisplayBehaviour behaviour) {
behaviour.id = id; behaviour.id = id;
@ -49,34 +50,6 @@ public class AllDisplayBehaviours {
return behaviour; return behaviour;
} }
public static void assignBlock(DisplayBehaviour behaviour, ResourceLocation block) {
if (behaviour instanceof DisplaySource source) {
List<DisplaySource> sources = SOURCES_BY_BLOCK.get(block);
if (sources == null) {
sources = new ArrayList<>();
SOURCES_BY_BLOCK.register(block, sources);
}
sources.add(source);
}
if (behaviour instanceof DisplayTarget target) {
TARGETS_BY_BLOCK.register(block, target);
}
}
public static void assignBlockEntity(DisplayBehaviour behaviour, ResourceLocation beType) {
if (behaviour instanceof DisplaySource source) {
List<DisplaySource> sources = SOURCES_BY_BLOCK_ENTITY.get(beType);
if (sources == null) {
sources = new ArrayList<>();
SOURCES_BY_BLOCK_ENTITY.register(beType, sources);
}
sources.add(source);
}
if (behaviour instanceof DisplayTarget target) {
TARGETS_BY_BLOCK_ENTITY.register(beType, target);
}
}
public static void assignBlock(DisplayBehaviour behaviour, Block block) { public static void assignBlock(DisplayBehaviour behaviour, Block block) {
if (behaviour instanceof DisplaySource source) { if (behaviour instanceof DisplaySource source) {
List<DisplaySource> sources = SOURCES_BY_BLOCK.get(block); List<DisplaySource> sources = SOURCES_BY_BLOCK.get(block);
@ -105,6 +78,15 @@ public class AllDisplayBehaviours {
} }
} }
public static void tryAssignBlockEntity(DisplayBehaviour behaviour, ResourceLocation id) {
if (ForgeRegistries.BLOCK_ENTITY_TYPES.containsKey(id)) {
BlockEntityType<?> type = ForgeRegistries.BLOCK_ENTITY_TYPES.getValue(id);
assignBlockEntity(behaviour, type);
} else {
Create.LOGGER.warn("Block entity for display behavior wasn't found: {}. Outdated compat?", id);
}
}
public static <B extends Block> NonNullConsumer<? super B> assignDataBehaviour(DisplayBehaviour behaviour, public static <B extends Block> NonNullConsumer<? super B> assignDataBehaviour(DisplayBehaviour behaviour,
String... suffix) { String... suffix) {
return b -> { return b -> {
@ -113,7 +95,7 @@ public class AllDisplayBehaviours {
if (suffix.length > 0) if (suffix.length > 0)
idSuffix += "_" + suffix[0]; idSuffix += "_" + suffix[0];
assignBlock(register(new ResourceLocation(registryName.getNamespace(), registryName.getPath() + idSuffix), assignBlock(register(new ResourceLocation(registryName.getNamespace(), registryName.getPath() + idSuffix),
behaviour), registryName); behaviour), b);
}; };
} }
@ -127,7 +109,7 @@ public class AllDisplayBehaviours {
assignBlockEntity( assignBlockEntity(
register(new ResourceLocation(registryName.getNamespace(), registryName.getPath() + idSuffix), register(new ResourceLocation(registryName.getNamespace(), registryName.getPath() + idSuffix),
behaviour), behaviour),
registryName); b);
}; };
} }
@ -237,10 +219,10 @@ public class AllDisplayBehaviours {
Mods.COMPUTERCRAFT.executeIfInstalled(() -> () -> { Mods.COMPUTERCRAFT.executeIfInstalled(() -> () -> {
DisplayBehaviour computerDisplaySource = register(Create.asResource("computer_display_source"), new ComputerDisplaySource()); DisplayBehaviour computerDisplaySource = register(Create.asResource("computer_display_source"), new ComputerDisplaySource());
assignBlockEntity(computerDisplaySource, Mods.COMPUTERCRAFT.rl("wired_modem_full")); tryAssignBlockEntity(computerDisplaySource, Mods.COMPUTERCRAFT.rl("wired_modem_full"));
assignBlockEntity(computerDisplaySource, Mods.COMPUTERCRAFT.rl("computer_normal")); tryAssignBlockEntity(computerDisplaySource, Mods.COMPUTERCRAFT.rl("computer_normal"));
assignBlockEntity(computerDisplaySource, Mods.COMPUTERCRAFT.rl("computer_advanced")); tryAssignBlockEntity(computerDisplaySource, Mods.COMPUTERCRAFT.rl("computer_advanced"));
assignBlockEntity(computerDisplaySource, Mods.COMPUTERCRAFT.rl("computer_command")); tryAssignBlockEntity(computerDisplaySource, Mods.COMPUTERCRAFT.rl("computer_command"));
}); });
} }
} }

View file

@ -6,15 +6,15 @@ import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.api.schematic.requirement.ISpecialBlockEntityItemRequirement; import com.simibubi.create.api.schematic.requirement.ISpecialBlockEntityItemRequirement;
import com.simibubi.create.api.schematic.requirement.ISpecialBlockItemRequirement; import com.simibubi.create.api.schematic.requirement.ISpecialBlockItemRequirement;
import com.simibubi.create.api.schematic.requirement.ISpecialEntityItemRequirement; import com.simibubi.create.api.schematic.requirement.ISpecialEntityItemRequirement;
import com.simibubi.create.api.schematic.requirement.SchematicRequirementsRegistry; import com.simibubi.create.api.schematic.requirement.SchematicRequirementRegistries;
import com.simibubi.create.compat.framedblocks.FramedBlocksInSchematics; import com.simibubi.create.compat.framedblocks.FramedBlocksInSchematics;
import com.simibubi.create.foundation.data.recipe.Mods; import com.simibubi.create.foundation.data.recipe.Mods;
import com.simibubi.create.impl.schematic.requirement.SchematicRequirementsRegistryImpl;
import net.createmod.catnip.nbt.NBTProcessors; import net.createmod.catnip.nbt.NBTProcessors;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.decoration.ArmorStand;
@ -35,9 +35,8 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.SlabType; import net.minecraft.world.level.block.state.properties.SlabType;
import net.minecraftforge.registries.ForgeRegistries;
import org.jetbrains.annotations.Nullable; import net.minecraftforge.registries.ForgeRegistries;
public class ItemRequirement { public class ItemRequirement {
public static final ItemRequirement NONE = new ItemRequirement(Collections.emptyList()); public static final ItemRequirement NONE = new ItemRequirement(Collections.emptyList());
@ -71,9 +70,9 @@ public class ItemRequirement {
Block block = state.getBlock(); Block block = state.getBlock();
ItemRequirement requirement; ItemRequirement requirement;
SchematicRequirementsRegistry.BlockRequirement blockItemRequirement = SchematicRequirementsRegistryImpl.getRequirementForBlock(block); SchematicRequirementRegistries.BlockRequirement blockRequirement = SchematicRequirementRegistries.BLOCKS.get(block);
if (blockItemRequirement != null) { if (blockRequirement != null) {
requirement = blockItemRequirement.getRequiredItems(block, state, be); requirement = blockRequirement.getRequiredItems(block, state, be);
} else if (block instanceof ISpecialBlockItemRequirement specialBlock) { } else if (block instanceof ISpecialBlockItemRequirement specialBlock) {
requirement = specialBlock.getRequiredItems(state, be); requirement = specialBlock.getRequiredItems(state, be);
} else { } else {
@ -81,9 +80,9 @@ public class ItemRequirement {
} }
if (be != null) { if (be != null) {
SchematicRequirementsRegistry.BlockEntityRequirement blockEntityItemRequirement = SchematicRequirementsRegistryImpl.getRequirementForBlockEntityType(be.getType()); SchematicRequirementRegistries.BlockEntityRequirement beRequirement = SchematicRequirementRegistries.BLOCK_ENTITIES.get(be.getType());
if (blockEntityItemRequirement != null) { if (beRequirement != null) {
requirement = requirement.union(blockEntityItemRequirement.getRequiredItems(be, state)); requirement = requirement.union(beRequirement.getRequiredItems(be, state));
} else if (be instanceof ISpecialBlockEntityItemRequirement specialBE) { } else if (be instanceof ISpecialBlockEntityItemRequirement specialBE) {
requirement = requirement.union(specialBE.getRequiredItems(state)); requirement = requirement.union(specialBE.getRequiredItems(state));
} else if (com.simibubi.create.compat.Mods.FRAMEDBLOCKS.contains(block)) { } else if (com.simibubi.create.compat.Mods.FRAMEDBLOCKS.contains(block)) {
@ -134,9 +133,9 @@ public class ItemRequirement {
} }
public static ItemRequirement of(Entity entity) { public static ItemRequirement of(Entity entity) {
SchematicRequirementsRegistry.EntityRequirement entityItemRequirement = SchematicRequirementsRegistryImpl.getRequirementForEntityType(entity.getType()); SchematicRequirementRegistries.EntityRequirement requirement = SchematicRequirementRegistries.ENTITIES.get(entity.getType());
if (entityItemRequirement != null) { if (requirement != null) {
return entityItemRequirement.getRequiredItems(entity); return requirement.getRequiredItems(entity);
} else if (entity instanceof ISpecialEntityItemRequirement specialEntity) { } else if (entity instanceof ISpecialEntityItemRequirement specialEntity) {
return specialEntity.getRequiredItems(); return specialEntity.getRequiredItems();
} }

View file

@ -5,13 +5,13 @@ import java.util.function.Function;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
import com.simibubi.create.Create; import com.simibubi.create.Create;
import com.simibubi.create.api.registry.AttachedRegistry;
import com.simibubi.create.compat.Mods; import com.simibubi.create.compat.Mods;
import com.simibubi.create.compat.betterend.BetterEndPortalCompat; import com.simibubi.create.compat.betterend.BetterEndPortalCompat;
import com.simibubi.create.content.contraptions.glue.SuperGlueEntity; import com.simibubi.create.content.contraptions.glue.SuperGlueEntity;
import com.simibubi.create.foundation.utility.AttachedRegistry;
import net.createmod.catnip.math.BlockFace;
import net.createmod.catnip.data.Pair; import net.createmod.catnip.data.Pair;
import net.createmod.catnip.math.BlockFace;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
@ -26,6 +26,7 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.portal.PortalInfo; import net.minecraft.world.level.portal.PortalInfo;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
import net.minecraftforge.common.util.ITeleporter; import net.minecraftforge.common.util.ITeleporter;
import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.ForgeRegistries;
@ -48,27 +49,22 @@ public class AllPortalTracks {
/** /**
* Registry mapping portal blocks to their respective {@link PortalTrackProvider}s. * Registry mapping portal blocks to their respective {@link PortalTrackProvider}s.
*/ */
private static final AttachedRegistry<Block, PortalTrackProvider> PORTAL_BEHAVIOURS = public static final AttachedRegistry<Block, PortalTrackProvider> REGISTRY = AttachedRegistry.create();
new AttachedRegistry<>(ForgeRegistries.BLOCKS);
/** /**
* Registers a portal track integration for a given block identified by its {@link ResourceLocation}. * Registers a portal track integration for a given block identified by its {@link ResourceLocation}, if it exists.
* If it does not, a warning will be logged.
* *
* @param block The resource location of the portal block. * @param id The resource location of the portal block.
* @param provider The portal track provider for the block. * @param provider The portal track provider for the block.
*/ */
public static void registerIntegration(ResourceLocation block, PortalTrackProvider provider) { public static void tryRegisterIntegration(ResourceLocation id, PortalTrackProvider provider) {
PORTAL_BEHAVIOURS.register(block, provider); if (ForgeRegistries.BLOCKS.containsKey(id)) {
} Block block = ForgeRegistries.BLOCKS.getValue(id);
REGISTRY.register(block, provider);
/** } else {
* Registers a portal track integration for a given {@link Block}. Create.LOGGER.warn("Portal for integration wasn't found: {}. Compat outdated?", id);
* }
* @param block The portal block.
* @param provider The portal track provider for the block.
*/
public static void registerIntegration(Block block, PortalTrackProvider provider) {
PORTAL_BEHAVIOURS.register(block, provider);
} }
/** /**
@ -78,7 +74,7 @@ public class AllPortalTracks {
* @return {@code true} if the block state represents a supported portal; {@code false} otherwise. * @return {@code true} if the block state represents a supported portal; {@code false} otherwise.
*/ */
public static boolean isSupportedPortal(BlockState state) { public static boolean isSupportedPortal(BlockState state) {
return PORTAL_BEHAVIOURS.get(state.getBlock()) != null; return REGISTRY.get(state.getBlock()) != null;
} }
/** /**
@ -92,7 +88,7 @@ public class AllPortalTracks {
public static Pair<ServerLevel, BlockFace> getOtherSide(ServerLevel level, BlockFace inboundTrack) { public static Pair<ServerLevel, BlockFace> getOtherSide(ServerLevel level, BlockFace inboundTrack) {
BlockPos portalPos = inboundTrack.getConnectedPos(); BlockPos portalPos = inboundTrack.getConnectedPos();
BlockState portalState = level.getBlockState(portalPos); BlockState portalState = level.getBlockState(portalPos);
PortalTrackProvider provider = PORTAL_BEHAVIOURS.get(portalState.getBlock()); PortalTrackProvider provider = REGISTRY.get(portalState.getBlock());
return provider == null ? null : provider.apply(Pair.of(level, inboundTrack)); return provider == null ? null : provider.apply(Pair.of(level, inboundTrack));
} }
@ -103,11 +99,15 @@ public class AllPortalTracks {
* This includes the Nether and the Aether (if loaded). * This includes the Nether and the Aether (if loaded).
*/ */
public static void registerDefaults() { public static void registerDefaults() {
registerIntegration(Blocks.NETHER_PORTAL, AllPortalTracks::nether); REGISTRY.register(Blocks.NETHER_PORTAL, AllPortalTracks::nether);
if (Mods.AETHER.isLoaded())
registerIntegration(Mods.AETHER.rl("aether_portal"), AllPortalTracks::aether); if (Mods.AETHER.isLoaded()) {
if (Mods.BETTEREND.isLoaded()) tryRegisterIntegration(Mods.AETHER.rl("aether_portal"), AllPortalTracks::aether);
registerIntegration(Mods.BETTEREND.rl("end_portal_block"), AllPortalTracks::betterend); }
if (Mods.BETTEREND.isLoaded()) {
tryRegisterIntegration(Mods.BETTEREND.rl("end_portal_block"), AllPortalTracks::betterend);
}
} }
/** /**

View file

@ -47,6 +47,7 @@ import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour.Properties; import net.minecraft.world.level.block.state.BlockBehaviour.Properties;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions; import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions;
@ -106,10 +107,13 @@ public class CreateRegistrate extends AbstractRegistrate<CreateRegistrate> {
Builder<R, T, ?, ?> builder, NonNullSupplier<? extends T> creator, Builder<R, T, ?, ?> builder, NonNullSupplier<? extends T> creator,
NonNullFunction<RegistryObject<T>, ? extends RegistryEntry<T>> entryFactory) { NonNullFunction<RegistryObject<T>, ? extends RegistryEntry<T>> entryFactory) {
RegistryEntry<T> entry = super.accept(name, type, builder, creator, entryFactory); RegistryEntry<T> entry = super.accept(name, type, builder, creator, entryFactory);
if (type.equals(Registries.ITEM)) { if (type.equals(Registries.ITEM) && currentTooltipModifierFactory != null) {
if (currentTooltipModifierFactory != null) { // grab the factory here for the lambda, it can change between now and registration
TooltipModifier.REGISTRY.registerDeferred(entry.getId(), currentTooltipModifierFactory); Function<Item, TooltipModifier> factory = currentTooltipModifierFactory;
} this.addRegisterCallback(name, Registries.ITEM, item -> {
TooltipModifier modifier = factory.apply(item);
TooltipModifier.REGISTRY.register(item, modifier);
});
} }
if (currentTab != null) { if (currentTab != null) {
TAB_LOOKUP.put(entry, currentTab); TAB_LOOKUP.put(entry, currentTab);

View file

@ -2,14 +2,15 @@ package com.simibubi.create.foundation.item;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.simibubi.create.foundation.utility.AttachedRegistry; import com.simibubi.create.api.registry.AttachedRegistry;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraftforge.event.entity.player.ItemTooltipEvent;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.event.entity.player.ItemTooltipEvent;
@FunctionalInterface
public interface TooltipModifier { public interface TooltipModifier {
AttachedRegistry<Item, TooltipModifier> REGISTRY = new AttachedRegistry<>(ForgeRegistries.ITEMS); AttachedRegistry<Item, TooltipModifier> REGISTRY = AttachedRegistry.create();
TooltipModifier EMPTY = new TooltipModifier() { TooltipModifier EMPTY = new TooltipModifier() {
@Override @Override

View file

@ -1,146 +0,0 @@
package com.simibubi.create.foundation.utility;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.Create;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.registries.IForgeRegistry;
public class AttachedRegistry<K, V> {
private static final List<AttachedRegistry<?, ?>> ALL = new ArrayList<>();
protected final IForgeRegistry<K> objectRegistry;
protected final Map<ResourceLocation, V> idMap = new HashMap<>();
protected final Map<K, V> objectMap = new IdentityHashMap<>();
protected final Map<ResourceLocation, Function<K, V>> deferredRegistrations = new HashMap<>();
protected boolean unwrapped = false;
public AttachedRegistry(IForgeRegistry<K> objectRegistry) {
this.objectRegistry = objectRegistry;
ALL.add(this);
}
public void register(ResourceLocation id, V value) {
if (!unwrapped) {
idMap.put(id, value);
} else {
K object = objectRegistry.getValue(id);
if (object != null) {
objectMap.put(object, value);
} else {
Create.LOGGER.warn("Could not get object for id '" + id + "' in AttachedRegistry after unwrapping!");
}
}
}
public void register(K object, V value) {
if (unwrapped) {
objectMap.put(object, value);
} else {
ResourceLocation id = objectRegistry.getKey(object);
if (id != null) {
idMap.put(id, value);
} else {
Create.LOGGER.warn("Could not get id of object '" + object + "' in AttachedRegistry before unwrapping!");
}
}
}
public void registerDeferred(ResourceLocation id, Function<K, V> func) {
if (!unwrapped) {
deferredRegistrations.put(id, func);
} else {
K object = objectRegistry.getValue(id);
if (object != null) {
objectMap.put(object, func.apply(object));
} else {
Create.LOGGER.warn("Could not get object for id '" + id + "' in AttachedRegistry after unwrapping!");
}
}
}
public void registerDeferred(K object, Function<K, V> func) {
if (unwrapped) {
objectMap.put(object, func.apply(object));
} else {
ResourceLocation id = objectRegistry.getKey(object);
if (id != null) {
deferredRegistrations.put(id, func);
} else {
Create.LOGGER.warn("Could not get id of object '" + object + "' in AttachedRegistry before unwrapping!");
}
}
}
@Nullable
public V get(ResourceLocation id) {
if (!unwrapped) {
return idMap.get(id);
} else {
K object = objectRegistry.getValue(id);
if (object != null) {
return objectMap.get(object);
} else {
Create.LOGGER.warn("Could not get object for id '" + id + "' in AttachedRegistry after unwrapping!");
return null;
}
}
}
@Nullable
public V get(K object) {
if (unwrapped) {
return objectMap.get(object);
} else {
ResourceLocation id = objectRegistry.getKey(object);
if (id != null) {
return idMap.get(id);
} else {
Create.LOGGER.warn("Could not get id of object '" + object + "' in AttachedRegistry before unwrapping!");
return null;
}
}
}
public boolean isUnwrapped() {
return unwrapped;
}
protected void unwrap() {
deferredRegistrations.forEach((id, func) -> {
K object = objectRegistry.getValue(id);
if (object != null) {
objectMap.put(object, func.apply(object));
} else {
Create.LOGGER.warn("Could not get object for id '" + id + "' in AttachedRegistry during unwrapping!");
}
});
idMap.forEach((id, value) -> {
K object = objectRegistry.getValue(id);
if (object != null) {
objectMap.put(object, value);
} else {
Create.LOGGER.warn("Could not get object for id '" + id + "' in AttachedRegistry during unwrapping!");
}
});
deferredRegistrations.clear();
idMap.clear();
unwrapped = true;
}
public static void unwrapAll() {
for (AttachedRegistry<?, ?> registry : ALL) {
registry.unwrap();
}
}
}

View file

@ -8,7 +8,8 @@ import javax.annotation.Nullable;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTags.AllBlockTags; import com.simibubi.create.AllTags.AllBlockTags;
import com.simibubi.create.api.schematic.nbt.IPartialSafeNBT; import com.simibubi.create.api.schematic.nbt.IPartialSafeNBT;
import com.simibubi.create.api.schematic.nbt.SchematicSafeNBTRegistry; import com.simibubi.create.api.schematic.nbt.SafeNbtWriterRegistry;
import com.simibubi.create.api.schematic.nbt.SafeNbtWriterRegistry.SafeNbtWriter;
import com.simibubi.create.compat.Mods; import com.simibubi.create.compat.Mods;
import com.simibubi.create.compat.framedblocks.FramedBlocksInSchematics; import com.simibubi.create.compat.framedblocks.FramedBlocksInSchematics;
import com.simibubi.create.content.kinetics.base.KineticBlockEntity; import com.simibubi.create.content.kinetics.base.KineticBlockEntity;
@ -16,7 +17,6 @@ import com.simibubi.create.content.processing.burner.BlazeBurnerBlock;
import com.simibubi.create.content.processing.burner.BlazeBurnerBlock.HeatLevel; import com.simibubi.create.content.processing.burner.BlazeBurnerBlock.HeatLevel;
import com.simibubi.create.foundation.blockEntity.IMergeableBE; import com.simibubi.create.foundation.blockEntity.IMergeableBE;
import com.simibubi.create.foundation.blockEntity.IMultiBlockEntityContainer; import com.simibubi.create.foundation.blockEntity.IMultiBlockEntityContainer;
import com.simibubi.create.impl.schematic.nbt.SchematicSafeNBTRegistryImpl;
import net.createmod.catnip.nbt.NBTProcessors; import net.createmod.catnip.nbt.NBTProcessors;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -57,6 +57,7 @@ import net.minecraft.world.level.block.state.properties.SlabType;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.FluidState;
import net.minecraftforge.common.IPlantable; import net.minecraftforge.common.IPlantable;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.level.BlockEvent; import net.minecraftforge.event.level.BlockEvent;
@ -279,18 +280,19 @@ public class BlockHelper {
if (blockEntity == null) if (blockEntity == null)
return null; return null;
SchematicSafeNBTRegistry.ContextProvidingPartialSafeNBT safeNBT = SchematicSafeNBTRegistryImpl.getPartialSafeNBT(blockEntity.getType()); SafeNbtWriter writer = SafeNbtWriterRegistry.REGISTRY.get(blockEntity.getType());
if (AllBlockTags.SAFE_NBT.matches(blockState)) { if (AllBlockTags.SAFE_NBT.matches(blockState)) {
data = blockEntity.saveWithFullMetadata(); data = blockEntity.saveWithFullMetadata();
} else if (safeNBT != null) { } else if (writer != null) {
data = new CompoundTag(); data = new CompoundTag();
safeNBT.writeSafe(blockEntity, data); writer.writeSafe(blockEntity, data);
} else if (blockEntity instanceof IPartialSafeNBT safeNbtBE) { } else if (blockEntity instanceof IPartialSafeNBT safeNbtBE) {
data = new CompoundTag(); data = new CompoundTag();
safeNbtBE.writeSafe(data); safeNbtBE.writeSafe(data);
} else if (Mods.FRAMEDBLOCKS.contains(blockState.getBlock())) { } else if (Mods.FRAMEDBLOCKS.contains(blockState.getBlock())) {
data = FramedBlocksInSchematics.prepareBlockEntityData(blockState, blockEntity); data = FramedBlocksInSchematics.prepareBlockEntityData(blockState, blockEntity);
} }
return NBTProcessors.process(blockState, blockEntity, data, true); return NBTProcessors.process(blockState, blockEntity, data, true);
} }

View file

@ -3,15 +3,20 @@ package com.simibubi.create.impl.contraption.storage;
import java.util.Objects; import java.util.Objects;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.AllMountedStorageTypes; import com.simibubi.create.AllMountedStorageTypes;
import com.simibubi.create.AllTags; import com.simibubi.create.AllTags;
import com.simibubi.create.api.contraption.storage.MountedStorageTypeRegistry; import com.simibubi.create.api.contraption.storage.MountedStorageTypeRegistries;
import com.simibubi.create.api.contraption.storage.fluid.MountedFluidStorageType; import com.simibubi.create.api.contraption.storage.fluid.MountedFluidStorageType;
import com.simibubi.create.api.contraption.storage.item.MountedItemStorageType; import com.simibubi.create.api.contraption.storage.item.MountedItemStorageType;
import com.simibubi.create.api.lookup.BlockLookup; import com.simibubi.create.api.registry.AttachedRegistry;
import net.minecraft.Util;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.TagsUpdatedEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.registries.IForgeRegistry; import net.minecraftforge.registries.IForgeRegistry;
@ -21,8 +26,12 @@ import net.minecraftforge.registries.RegistryBuilder;
@ApiStatus.Internal @ApiStatus.Internal
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) @Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
public class MountedStorageTypeRegistryImpl { public class MountedStorageTypeRegistryImpl {
public static final BlockLookup<MountedItemStorageType<?>> ITEM_LOOKUP = BlockLookup.create(MountedStorageTypeRegistryImpl::itemFallback); public static final AttachedRegistry<Block, MountedItemStorageType<?>> ITEM_STORAGES = Util.make(() -> {
public static final BlockLookup<MountedFluidStorageType<?>> FLUID_LOOKUP = BlockLookup.create(); AttachedRegistry<Block, MountedItemStorageType<?>> registry = AttachedRegistry.create();
registry.registerProvider(ItemFallbackProvider.INSTANCE);
return registry;
});
public static final AttachedRegistry<Block, MountedFluidStorageType<?>> FLUID_STORAGES = AttachedRegistry.create();
private static IForgeRegistry<MountedItemStorageType<?>> itemsRegistry; private static IForgeRegistry<MountedItemStorageType<?>> itemsRegistry;
private static IForgeRegistry<MountedFluidStorageType<?>> fluidsRegistry; private static IForgeRegistry<MountedFluidStorageType<?>> fluidsRegistry;
@ -39,19 +48,34 @@ public class MountedStorageTypeRegistryImpl {
public static void registerRegistries(NewRegistryEvent event) { public static void registerRegistries(NewRegistryEvent event) {
event.create( event.create(
new RegistryBuilder<MountedItemStorageType<?>>() new RegistryBuilder<MountedItemStorageType<?>>()
.setName(MountedStorageTypeRegistry.ITEMS.location()), .setName(MountedStorageTypeRegistries.ITEMS.location()),
registry -> itemsRegistry = registry registry -> itemsRegistry = registry
); );
event.create( event.create(
new RegistryBuilder<MountedFluidStorageType<?>>() new RegistryBuilder<MountedFluidStorageType<?>>()
.setName(MountedStorageTypeRegistry.FLUIDS.location()), .setName(MountedStorageTypeRegistries.FLUIDS.location()),
registry -> fluidsRegistry = registry registry -> fluidsRegistry = registry
); );
} }
private static MountedItemStorageType<?> itemFallback(Block block) { private enum ItemFallbackProvider implements AttachedRegistry.Provider<Block, MountedItemStorageType<?>> {
return AllTags.AllBlockTags.FALLBACK_MOUNTED_STORAGE_BLACKLIST.matches(block) INSTANCE;
? null
: AllMountedStorageTypes.FALLBACK.get(); @Override
@Nullable
public MountedItemStorageType<?> get(Block block) {
return AllTags.AllBlockTags.FALLBACK_MOUNTED_STORAGE_BLACKLIST.matches(block)
? null
: AllMountedStorageTypes.FALLBACK.get();
}
@Override
public void onRegister(AttachedRegistry<Block, MountedItemStorageType<?>> registry) {
MinecraftForge.EVENT_BUS.addListener((TagsUpdatedEvent event) -> {
if (event.shouldUpdateStaticData()) {
registry.invalidateProvider(this);
}
});
}
} }
} }

View file

@ -1,33 +0,0 @@
package com.simibubi.create.impl.contraption.transformable;
import org.jetbrains.annotations.ApiStatus;
import com.simibubi.create.api.contraption.transformable.ContraptionTransformableRegistry.TransformableBlock;
import com.simibubi.create.api.contraption.transformable.ContraptionTransformableRegistry.TransformableBlockEntity;
import com.simibubi.create.foundation.utility.AttachedRegistry;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraftforge.registries.ForgeRegistries;
@ApiStatus.Internal
public class ContraptionTransformableRegistryImpl {
private static final AttachedRegistry<Block, TransformableBlock> TRANSFORMABLE_BLOCKS = new AttachedRegistry<>(ForgeRegistries.BLOCKS);
private static final AttachedRegistry<BlockEntityType<?>, TransformableBlockEntity> TRANSFORMABLE_BLOCK_ENTITIES = new AttachedRegistry<>(ForgeRegistries.BLOCK_ENTITY_TYPES);
public static void registerForBlock(Block block, TransformableBlock transformableBlock) {
TRANSFORMABLE_BLOCKS.register(block, transformableBlock);
}
public static void registerForBlockEntity(BlockEntityType<?> blockEntityType, TransformableBlockEntity transformableBlockEntity) {
TRANSFORMABLE_BLOCK_ENTITIES.register(blockEntityType, transformableBlockEntity);
}
public static TransformableBlock get(Block block) {
return TRANSFORMABLE_BLOCKS.get(block);
}
public static TransformableBlockEntity get(BlockEntityType<?> blockEntityType) {
return TRANSFORMABLE_BLOCK_ENTITIES.get(blockEntityType);
}
}

View file

@ -1,103 +0,0 @@
package com.simibubi.create.impl.lookup;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.simibubi.create.api.lookup.BlockLookup;
import net.minecraftforge.event.TagsUpdatedEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
@ApiStatus.Internal
@Mod.EventBusSubscriber
public class BlockLookupImpl<T> implements BlockLookup<T> {
private static final List<BlockLookupImpl<?>> allLookups = new ArrayList<>();
private final Map<Block, T> map;
private final Map<Block, T> providedValues;
private final Set<Block> providedNull;
private final List<Provider<T>> providers;
public BlockLookupImpl() {
this.map = new IdentityHashMap<>();
this.providedValues = new IdentityHashMap<>();
this.providedNull = new HashSet<>();
this.providers = new ArrayList<>();
allLookups.add(this);
}
@Nullable
@Override
public T find(BlockState state) {
return this.find(state.getBlock());
}
@Nullable
@Override
public T find(Block block) {
T registered = this.map.get(block);
if (registered != null)
return registered;
if (this.providedNull.contains(block))
return null;
return this.providedValues.computeIfAbsent(block, $ -> {
for (Provider<T> provider : this.providers) {
T value = provider.get(block);
if (value != null) {
return value;
}
}
this.providedNull.add(block);
return null;
});
}
@Override
public void register(Block block, T value) {
this.map.put(block, value);
}
@Override
public void registerTag(TagKey<Block> tag, T value) {
this.registerProvider(new TagProvider<>(tag, value));
}
@Override
public void registerProvider(Provider<T> provider) {
this.providers.add(0, provider);
}
@SubscribeEvent
public static void onTagsReloaded(TagsUpdatedEvent event) {
if (event.getUpdateCause() == TagsUpdatedEvent.UpdateCause.SERVER_DATA_LOAD) {
for (BlockLookupImpl<?> lookup : allLookups) {
lookup.providedValues.clear();
lookup.providedNull.clear();
}
}
}
private record TagProvider<T>(TagKey<Block> tag, T value) implements Provider<T> {
@Override
@Nullable
@SuppressWarnings("deprecation")
public T get(Block block) {
return block.builtInRegistryHolder().is(this.tag) ? this.value : null;
}
}
}

View file

@ -0,0 +1,103 @@
package com.simibubi.create.impl.registry;
import java.util.ArrayList;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.api.registry.AttachedRegistry;
// methods are synchronized since registrations can happen during parallel mod loading
public class AttachedRegistryImpl<K, V> implements AttachedRegistry<K, V> {
private static final Object nullMarker = new Object();
// all of these have identity semantics
private final Map<K, V> registrations = new IdentityHashMap<>();
private final List<Provider<K, V>> providers = new ArrayList<>();
private final Map<Provider<K, V>, Set<K>> providedKeys = new IdentityHashMap<>();
private final Map<K, V> providedValues = new IdentityHashMap<>();
@Override
public synchronized void register(K object, V value) {
Objects.requireNonNull(object, "object");
Objects.requireNonNull(value, "value");
V existing = this.registrations.get(object);
if (existing != null) {
String message = String.format("Tried to register duplicate values for object %s: old=%s, new=%s", object, existing, value);
throw new IllegalArgumentException(message);
}
this.registrations.put(object, value);
}
@Override
public synchronized void registerProvider(Provider<K, V> provider) {
Objects.requireNonNull(provider);
if (this.providers.contains(provider)) {
throw new IllegalArgumentException("Tried to register provider twice: " + provider);
}
// add to start of list so it's queried first
this.providers.add(0, provider);
provider.onRegister(this);
}
@Override
public synchronized void invalidateProvider(Provider<K, V> provider) {
Objects.requireNonNull(provider);
if (!this.providers.contains(provider)) {
throw new IllegalArgumentException("Cannot invalidate non-registered provider: " + provider);
}
// discard all the values the provider has provided
Set<K> keys = providedKeys.remove(provider);
if (keys != null) {
keys.forEach(providedValues::remove);
}
// when a provider is invalidated, we need to clear all cached values that evaluated to null, so they can be re-queried
this.providedValues.values().removeIf(value -> value == nullMarker);
}
@Override
@Nullable
public synchronized V get(K object) {
if (this.registrations.containsKey(object)) {
return this.registrations.get(object);
} else if (this.providedValues.containsKey(object)) {
V provided = this.providedValues.get(object);
return provided == nullMarker ? null : provided;
}
// no value known, check providers
// descendingSet: go in reverse-registration order
for (Provider<K, V> provider : this.providers) {
V value = provider.get(object);
if (value != null) {
this.providedValues.put(object, value);
// track which provider provided the value for invalidation
this.providedKeys.computeIfAbsent(provider, $ -> identityHashSet()).add(object);
return value;
}
}
// no provider returned non-null
this.providedValues.put(object, nullMarker());
return null;
}
@SuppressWarnings("unchecked")
private static <T> T nullMarker() {
return (T) nullMarker;
}
private static <T> Set<T> identityHashSet() {
return Collections.newSetFromMap(new IdentityHashMap<>());
}
}

View file

@ -0,0 +1,41 @@
package com.simibubi.create.impl.registry;
import java.util.function.Function;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.api.registry.AttachedRegistry;
import net.minecraft.core.Holder;
import net.minecraft.tags.TagKey;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.TagsUpdatedEvent;
public class TagProviderImpl<K, V> implements AttachedRegistry.Provider<K, V> {
private final TagKey<K> tag;
private final Function<K, Holder<K>> holderGetter;
private final V value;
public TagProviderImpl(TagKey<K> tag, Function<K, Holder<K>> holderGetter, V value) {
this.tag = tag;
this.holderGetter = holderGetter;
this.value = value;
}
@Override
@Nullable
public V get(K object) {
Holder<K> holder = this.holderGetter.apply(object);
return holder.is(this.tag) ? this.value : null;
}
@Override
public void onRegister(AttachedRegistry<K, V> registry) {
MinecraftForge.EVENT_BUS.addListener((TagsUpdatedEvent event) -> {
if (event.shouldUpdateStaticData()) {
registry.invalidateProvider(this);
}
});
}
}

View file

@ -1,23 +0,0 @@
package com.simibubi.create.impl.schematic.nbt;
import org.jetbrains.annotations.ApiStatus;
import com.simibubi.create.api.schematic.nbt.SchematicSafeNBTRegistry;
import com.simibubi.create.foundation.utility.AttachedRegistry;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraftforge.registries.ForgeRegistries;
@ApiStatus.Internal
public class SchematicSafeNBTRegistryImpl {
private static final AttachedRegistry<BlockEntityType<?>, SchematicSafeNBTRegistry.ContextProvidingPartialSafeNBT> BLOCK_ENTITY_PARTIAL_SAFE_NBT = new AttachedRegistry<>(ForgeRegistries.BLOCK_ENTITY_TYPES);
public static void register(BlockEntityType<? extends BlockEntity> blockEntityType, SchematicSafeNBTRegistry.ContextProvidingPartialSafeNBT safeNBT) {
BLOCK_ENTITY_PARTIAL_SAFE_NBT.register(blockEntityType, safeNBT);
}
public static SchematicSafeNBTRegistry.ContextProvidingPartialSafeNBT getPartialSafeNBT(BlockEntityType<? extends BlockEntity> blockEntityType) {
return BLOCK_ENTITY_PARTIAL_SAFE_NBT.get(blockEntityType);
}
}

View file

@ -1,59 +0,0 @@
package com.simibubi.create.impl.schematic.requirement;
import org.jetbrains.annotations.ApiStatus;
import com.simibubi.create.api.schematic.requirement.SchematicRequirementsRegistry;
import com.simibubi.create.foundation.utility.AttachedRegistry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraftforge.registries.ForgeRegistries;
@ApiStatus.Internal
public class SchematicRequirementsRegistryImpl {
private static final AttachedRegistry<Block, SchematicRequirementsRegistry.BlockRequirement> BLOCK_REQUIREMENTS = new AttachedRegistry<>(ForgeRegistries.BLOCKS);
private static final AttachedRegistry<BlockEntityType<?>, SchematicRequirementsRegistry.BlockEntityRequirement> BLOCK_ENTITY_REQUIREMENTS = new AttachedRegistry<>(ForgeRegistries.BLOCK_ENTITY_TYPES);
private static final AttachedRegistry<EntityType<?>, SchematicRequirementsRegistry.EntityRequirement> ENTITY_REQUIREMENTS = new AttachedRegistry<>(ForgeRegistries.ENTITY_TYPES);
public static void registerForBlock(Block block, SchematicRequirementsRegistry.BlockRequirement requirement) {
BLOCK_REQUIREMENTS.register(block, requirement);
}
public static void registerForBlock(ResourceLocation block, SchematicRequirementsRegistry.BlockRequirement requirement) {
BLOCK_REQUIREMENTS.register(block, requirement);
}
public static void registerForBlockEntity(BlockEntityType<BlockEntity> blockEntityType, SchematicRequirementsRegistry.BlockEntityRequirement requirement) {
BLOCK_ENTITY_REQUIREMENTS.register(blockEntityType, requirement);
}
public static void registerForBlockEntity(ResourceLocation blockEntityType, SchematicRequirementsRegistry.BlockEntityRequirement requirement) {
BLOCK_ENTITY_REQUIREMENTS.register(blockEntityType, requirement);
}
public static void registerForEntity(EntityType<Entity> entityType, SchematicRequirementsRegistry.EntityRequirement requirement) {
ENTITY_REQUIREMENTS.register(entityType, requirement);
}
// ---
public static void registerForEntity(ResourceLocation entityType, SchematicRequirementsRegistry.EntityRequirement requirement) {
ENTITY_REQUIREMENTS.register(entityType, requirement);
}
public static SchematicRequirementsRegistry.BlockRequirement getRequirementForBlock(Block block) {
return BLOCK_REQUIREMENTS.get(block);
}
public static SchematicRequirementsRegistry.BlockEntityRequirement getRequirementForBlockEntityType(BlockEntityType<? extends BlockEntity> blockEntityType) {
return BLOCK_ENTITY_REQUIREMENTS.get(blockEntityType);
}
public static SchematicRequirementsRegistry.EntityRequirement getRequirementForEntityType(EntityType<? extends Entity> entityType) {
return ENTITY_REQUIREMENTS.get(entityType);
}
}