Merge branch 'mc1.20.1/feature-dev' into mc1.21.1/dev

This commit is contained in:
IThundxr 2025-02-21 18:31:28 -05:00
commit 13148135b5
Failed to generate hash of commit
180 changed files with 5385 additions and 4794 deletions

View file

@ -140,6 +140,7 @@ _Now using Flywheel 1.0_
- Added `#create:sugar_cane_variants` to allow the mechanical saw to work with custom sugarcane variants (#7263) - Added `#create:sugar_cane_variants` to allow the mechanical saw to work with custom sugarcane variants (#7263)
- New API for custom storage block behaviour on contraptions. - New API for custom storage block behaviour on contraptions.
For simple cases, create provides the `#create:simple_mounted_storage` and `#create:chest_mounted_storage` block tags. For simple cases, create provides the `#create:simple_mounted_storage` and `#create:chest_mounted_storage` block tags.
- Added `#create:non_breakable` to mark blocks that cannot be broken by block-breaking kinetics
- Removed LangMerger and related classes - Removed LangMerger and related classes
- Implemented an api to allow mods to register schematic requirements, partial safe nbt and contraption transforms - Implemented an api to allow mods to register schematic requirements, partial safe nbt and contraption transforms
without implementing interfaces (#4702) without implementing interfaces (#4702)

View file

@ -0,0 +1,3 @@
// 1.20.1 2025-02-20T18:50:30.47100651 Create's Contraption Type Tags
700982b6682ea583e7f08e44198af1b3219531d5 data/create/tags/create/contraption_type/opens_controls.json
08384ffb27c43caadbd36c2d390ed9af1c357084 data/create/tags/create/contraption_type/requires_vehicle_for_render.json

View file

@ -0,0 +1,3 @@
{
"values": []
}

View file

@ -0,0 +1,5 @@
{
"values": [
"create:carriage"
]
}

View file

@ -0,0 +1,5 @@
{
"values": [
"create:mounted"
]
}

View file

@ -1,7 +1,6 @@
package com.simibubi.create; package com.simibubi.create;
import static com.simibubi.create.Create.REGISTRATE; import static com.simibubi.create.Create.REGISTRATE;
import static com.simibubi.create.content.redstone.displayLink.AllDisplayBehaviours.assignDataBehaviourBE;
import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsBlockEntity; import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsBlockEntity;
import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsRenderer; import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsRenderer;
@ -203,8 +202,6 @@ import com.simibubi.create.content.redstone.diodes.PulseRepeaterBlockEntity;
import com.simibubi.create.content.redstone.diodes.PulseTimerBlockEntity; import com.simibubi.create.content.redstone.diodes.PulseTimerBlockEntity;
import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlockEntity; import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlockEntity;
import com.simibubi.create.content.redstone.displayLink.LinkBulbRenderer; import com.simibubi.create.content.redstone.displayLink.LinkBulbRenderer;
import com.simibubi.create.content.redstone.displayLink.source.NixieTubeDisplaySource;
import com.simibubi.create.content.redstone.displayLink.target.NixieTubeDisplayTarget;
import com.simibubi.create.content.redstone.link.RedstoneLinkBlockEntity; import com.simibubi.create.content.redstone.link.RedstoneLinkBlockEntity;
import com.simibubi.create.content.redstone.link.controller.LecternControllerBlockEntity; import com.simibubi.create.content.redstone.link.controller.LecternControllerBlockEntity;
import com.simibubi.create.content.redstone.link.controller.LecternControllerRenderer; import com.simibubi.create.content.redstone.link.controller.LecternControllerRenderer;
@ -821,11 +818,11 @@ public class AllBlockEntityTypes {
public static final BlockEntityEntry<NixieTubeBlockEntity> NIXIE_TUBE = REGISTRATE public static final BlockEntityEntry<NixieTubeBlockEntity> NIXIE_TUBE = REGISTRATE
.blockEntity("nixie_tube", NixieTubeBlockEntity::new) .blockEntity("nixie_tube", NixieTubeBlockEntity::new)
.displaySource(AllDisplaySources.NIXIE_TUBE)
.displayTarget(AllDisplayTargets.NIXIE_TUBE)
.validBlocks(AllBlocks.ORANGE_NIXIE_TUBE) .validBlocks(AllBlocks.ORANGE_NIXIE_TUBE)
.validBlocks(AllBlocks.NIXIE_TUBES.toArray()) .validBlocks(AllBlocks.NIXIE_TUBES.toArray())
.renderer(() -> NixieTubeRenderer::new) .renderer(() -> NixieTubeRenderer::new)
.onRegister(assignDataBehaviourBE(new NixieTubeDisplayTarget()))
.onRegister(assignDataBehaviourBE(new NixieTubeDisplaySource()))
.register(); .register();
public static final BlockEntityEntry<DisplayLinkBlockEntity> DISPLAY_LINK = REGISTRATE public static final BlockEntityEntry<DisplayLinkBlockEntity> DISPLAY_LINK = REGISTRATE

View file

@ -1,11 +1,12 @@
package com.simibubi.create; package com.simibubi.create;
import static com.simibubi.create.AllInteractionBehaviours.interactionBehaviour;
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.behaviour.display.DisplaySource.displaySource;
import static com.simibubi.create.api.contraption.storage.MountedStorageTypeRegistry.mountedItemStorage; import static com.simibubi.create.api.behaviour.display.DisplayTarget.displayTarget;
import static com.simibubi.create.content.redstone.displayLink.AllDisplayBehaviours.assignDataBehaviour; import static com.simibubi.create.api.behaviour.interaction.MovingInteractionBehaviour.interactionBehaviour;
import static com.simibubi.create.api.behaviour.movement.MovementBehaviour.movementBehaviour;
import static com.simibubi.create.api.contraption.storage.fluid.MountedFluidStorageType.mountedFluidStorage;
import static com.simibubi.create.api.contraption.storage.item.MountedItemStorageType.mountedItemStorage;
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;
import static com.simibubi.create.foundation.data.CreateRegistrate.connectedTextures; import static com.simibubi.create.foundation.data.CreateRegistrate.connectedTextures;
@ -17,6 +18,7 @@ import static com.simibubi.create.foundation.data.TagGen.tagBlockAndItem;
import com.simibubi.create.AllTags.AllBlockTags; import com.simibubi.create.AllTags.AllBlockTags;
import com.simibubi.create.AllTags.AllItemTags; import com.simibubi.create.AllTags.AllItemTags;
import com.simibubi.create.api.behaviour.interaction.ConductorBlockInteractionBehavior;
import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsBlock; import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsBlock;
import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovement; import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovement;
import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovingInteraction; import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovingInteraction;
@ -226,26 +228,6 @@ import com.simibubi.create.content.redstone.diodes.ToggleLatchBlock;
import com.simibubi.create.content.redstone.diodes.ToggleLatchGenerator; import com.simibubi.create.content.redstone.diodes.ToggleLatchGenerator;
import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlock; import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlock;
import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlockItem; import com.simibubi.create.content.redstone.displayLink.DisplayLinkBlockItem;
import com.simibubi.create.content.redstone.displayLink.source.AccumulatedItemCountDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.BoilerDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.CurrentFloorDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.EntityNameDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.FactoryGaugeDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.FillLevelDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.FluidAmountDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.FluidListDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.ItemCountDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.ItemListDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.ItemNameDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.ItemThroughputDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.KineticSpeedDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.KineticStressDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.ObservedTrainNameSource;
import com.simibubi.create.content.redstone.displayLink.source.StationSummaryDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.StopWatchDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.TimeOfDayDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.TrainStatusDisplaySource;
import com.simibubi.create.content.redstone.displayLink.target.DisplayBoardTarget;
import com.simibubi.create.content.redstone.link.RedstoneLinkBlock; import com.simibubi.create.content.redstone.link.RedstoneLinkBlock;
import com.simibubi.create.content.redstone.link.RedstoneLinkGenerator; import com.simibubi.create.content.redstone.link.RedstoneLinkGenerator;
import com.simibubi.create.content.redstone.link.controller.LecternControllerBlock; import com.simibubi.create.content.redstone.link.controller.LecternControllerBlock;
@ -290,7 +272,6 @@ import com.simibubi.create.foundation.item.UncontainableBlockItem;
import com.simibubi.create.foundation.mixin.accessor.BlockLootSubProviderAccessor; import com.simibubi.create.foundation.mixin.accessor.BlockLootSubProviderAccessor;
import com.simibubi.create.foundation.utility.ColorHandlers; import com.simibubi.create.foundation.utility.ColorHandlers;
import com.simibubi.create.foundation.utility.DyeHelper; import com.simibubi.create.foundation.utility.DyeHelper;
import com.simibubi.create.impl.contraption.train.TrainConductorHandlerImpl;
import com.tterrag.registrate.providers.RegistrateRecipeProvider; import com.tterrag.registrate.providers.RegistrateRecipeProvider;
import com.tterrag.registrate.util.DataIngredient; import com.tterrag.registrate.util.DataIngredient;
import com.tterrag.registrate.util.entry.BlockEntry; import com.tterrag.registrate.util.entry.BlockEntry;
@ -552,7 +533,7 @@ public class AllBlocks {
.transform(axeOrPickaxe()) .transform(axeOrPickaxe())
.blockstate(new BeltGenerator()::generate) .blockstate(new BeltGenerator()::generate)
.transform(BlockStressDefaults.setImpact(0)) .transform(BlockStressDefaults.setImpact(0))
.onRegister(assignDataBehaviour(new ItemNameDisplaySource(), "combine_item_names")) .transform(displaySource(AllDisplaySources.ITEM_NAMES))
.onRegister(CreateRegistrate.blockModel(() -> BeltModel::new)) .onRegister(CreateRegistrate.blockModel(() -> BeltModel::new))
.clientExtension(() -> () -> new BeltBlock.RenderProperties()) .clientExtension(() -> () -> new BeltBlock.RenderProperties())
.register(); .register();
@ -674,8 +655,8 @@ public class AllBlocks {
.properties(p -> p.mapColor(MapColor.TERRACOTTA_YELLOW)) .properties(p -> p.mapColor(MapColor.TERRACOTTA_YELLOW))
.transform(axeOrPickaxe()) .transform(axeOrPickaxe())
.transform(BuilderTransformers.cuckooClock()) .transform(BuilderTransformers.cuckooClock())
.onRegister(assignDataBehaviour(new TimeOfDayDisplaySource(), "time_of_day")) .transform(displaySource(AllDisplaySources.TIME_OF_DAY))
.onRegister(assignDataBehaviour(new StopWatchDisplaySource(), "stop_watch")) .transform(displaySource(AllDisplaySources.STOPWATCH))
.register(); .register();
public static final BlockEntry<CuckooClockBlock> MYSTERIOUS_CUCKOO_CLOCK = public static final BlockEntry<CuckooClockBlock> MYSTERIOUS_CUCKOO_CLOCK =
@ -771,7 +752,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 -> TrainConductorHandlerImpl.registerBlazeBurner()) .onRegister(interactionBehaviour(new ConductorBlockInteractionBehavior.BlazeBurner()))
.item(BlazeBurnerBlockItem::withBlaze) .item(BlazeBurnerBlockItem::withBlaze)
.model(AssetLookup.customBlockItemModel("blaze_burner", "block_with_blaze")) .model(AssetLookup.customBlockItemModel("blaze_burner", "block_with_blaze"))
.build() .build()
@ -802,7 +783,7 @@ public class AllBlocks {
.properties(p -> p.mapColor(MapColor.COLOR_GRAY)) .properties(p -> p.mapColor(MapColor.COLOR_GRAY))
.transform(axeOrPickaxe()) .transform(axeOrPickaxe())
.blockstate((c, p) -> p.simpleBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p))) .blockstate((c, p) -> p.simpleBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p)))
.onRegister(assignDataBehaviour(new ItemNameDisplaySource(), "combine_item_names")) .transform(displaySource(AllDisplaySources.ITEM_NAMES))
.onRegister(interactionBehaviour(new MountedDepotInteractionBehaviour())) .onRegister(interactionBehaviour(new MountedDepotInteractionBehaviour()))
.transform(mountedItemStorage(AllMountedStorageTypes.DEPOT)) .transform(mountedItemStorage(AllMountedStorageTypes.DEPOT))
.item() .item()
@ -817,7 +798,7 @@ public class AllBlocks {
.transform(axeOrPickaxe()) .transform(axeOrPickaxe())
.blockstate((c, p) -> p.horizontalBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p), 180)) .blockstate((c, p) -> p.horizontalBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p), 180))
.transform(BlockStressDefaults.setImpact(2.0)) .transform(BlockStressDefaults.setImpact(2.0))
.onRegister(assignDataBehaviour(new ItemNameDisplaySource(), "combine_item_names")) .transform(displaySource(AllDisplaySources.ITEM_NAMES))
.item(EjectorItem::new) .item(EjectorItem::new)
.transform(customItemModel()) .transform(customItemModel())
.register(); .register();
@ -858,7 +839,7 @@ public class AllBlocks {
.transform(axeOrPickaxe()) .transform(axeOrPickaxe())
.transform(BlockStressDefaults.setNoImpact()) .transform(BlockStressDefaults.setNoImpact())
.blockstate(new GaugeGenerator()::generate) .blockstate(new GaugeGenerator()::generate)
.onRegister(assignDataBehaviour(new KineticSpeedDisplaySource(), "kinetic_speed")) .transform(displaySource(AllDisplaySources.KINETIC_SPEED))
.item() .item()
.transform(ModelGen.customItemModel("gauge", "_", "item")) .transform(ModelGen.customItemModel("gauge", "_", "item"))
.register(); .register();
@ -869,7 +850,7 @@ public class AllBlocks {
.transform(axeOrPickaxe()) .transform(axeOrPickaxe())
.transform(BlockStressDefaults.setNoImpact()) .transform(BlockStressDefaults.setNoImpact())
.blockstate(new GaugeGenerator()::generate) .blockstate(new GaugeGenerator()::generate)
.onRegister(assignDataBehaviour(new KineticStressDisplaySource(), "kinetic_stress")) .transform(displaySource(AllDisplaySources.KINETIC_STRESS))
.item() .item()
.transform(ModelGen.customItemModel("gauge", "_", "item")) .transform(ModelGen.customItemModel("gauge", "_", "item"))
.register(); .register();
@ -1004,7 +985,7 @@ public class AllBlocks {
.transform(pickaxeOnly()) .transform(pickaxeOnly())
.blockstate(new FluidTankGenerator()::generate) .blockstate(new FluidTankGenerator()::generate)
.onRegister(CreateRegistrate.blockModel(() -> FluidTankModel::standard)) .onRegister(CreateRegistrate.blockModel(() -> FluidTankModel::standard))
.onRegister(assignDataBehaviour(new BoilerDisplaySource(), "boiler_status")) .transform(displaySource(AllDisplaySources.BOILER))
.transform(mountedFluidStorage(AllMountedStorageTypes.FLUID_TANK)) .transform(mountedFluidStorage(AllMountedStorageTypes.FLUID_TANK))
.onRegister(movementBehaviour(new FluidTankMovementBehavior())) .onRegister(movementBehaviour(new FluidTankMovementBehavior()))
.addLayer(() -> RenderType::cutoutMipped) .addLayer(() -> RenderType::cutoutMipped)
@ -1433,7 +1414,7 @@ public class AllBlocks {
: calling ? AssetLookup.partialBaseModel(c, p, "dim") : AssetLookup.partialBaseModel(c, p); : calling ? AssetLookup.partialBaseModel(c, p, "dim") : AssetLookup.partialBaseModel(c, p);
})) }))
.loot((p, b) -> p.dropOther(b, REDSTONE_CONTACT.get())) .loot((p, b) -> p.dropOther(b, REDSTONE_CONTACT.get()))
.onRegister(assignDataBehaviour(new CurrentFloorDisplaySource(), "current_floor")) .transform(displaySource(AllDisplaySources.CURRENT_FLOOR))
.item() .item()
.transform(customItemModel("_", "block")) .transform(customItemModel("_", "block"))
.register(); .register();
@ -1668,8 +1649,8 @@ public class AllBlocks {
.sound(SoundType.NETHERITE_BLOCK)) .sound(SoundType.NETHERITE_BLOCK))
.transform(pickaxeOnly()) .transform(pickaxeOnly())
.blockstate((c, p) -> p.simpleBlock(c.get(), AssetLookup.partialBaseModel(c, p))) .blockstate((c, p) -> p.simpleBlock(c.get(), AssetLookup.partialBaseModel(c, p)))
.onRegister(assignDataBehaviour(new StationSummaryDisplaySource(), "station_summary")) .transform(displaySource(AllDisplaySources.STATION_SUMMARY))
.onRegister(assignDataBehaviour(new TrainStatusDisplaySource(), "train_status")) .transform(displaySource(AllDisplaySources.TRAIN_STATUS))
.lang("Train Station") .lang("Train Station")
.item(TrackTargetingBlockItem.ofType(EdgePointType.STATION)) .item(TrackTargetingBlockItem.ofType(EdgePointType.STATION))
.transform(customItemModel()) .transform(customItemModel())
@ -1699,7 +1680,7 @@ public class AllBlocks {
.sound(SoundType.NETHERITE_BLOCK)) .sound(SoundType.NETHERITE_BLOCK))
.blockstate((c, p) -> BlockStateGen.simpleBlock(c, p, AssetLookup.forPowered(c, p))) .blockstate((c, p) -> BlockStateGen.simpleBlock(c, p, AssetLookup.forPowered(c, p)))
.transform(pickaxeOnly()) .transform(pickaxeOnly())
.onRegister(assignDataBehaviour(new ObservedTrainNameSource(), "observed_train_name")) .transform(displaySource(AllDisplaySources.OBSERVED_TRAIN_NAME))
.lang("Train Observer") .lang("Train Observer")
.item(TrackTargetingBlockItem.ofType(EdgePointType.OBSERVER)) .item(TrackTargetingBlockItem.ofType(EdgePointType.OBSERVER))
.transform(customItemModel("_", "block")) .transform(customItemModel("_", "block"))
@ -1793,16 +1774,16 @@ public class AllBlocks {
REGISTRATE.block("andesite_tunnel", BeltTunnelBlock::new) REGISTRATE.block("andesite_tunnel", BeltTunnelBlock::new)
.properties(p -> p.mapColor(MapColor.STONE)) .properties(p -> p.mapColor(MapColor.STONE))
.transform(BuilderTransformers.beltTunnel("andesite", ResourceLocation.withDefaultNamespace("block/polished_andesite"))) .transform(BuilderTransformers.beltTunnel("andesite", ResourceLocation.withDefaultNamespace("block/polished_andesite")))
.onRegister(assignDataBehaviour(new AccumulatedItemCountDisplaySource(), "accumulate_items")) .transform(displaySource(AllDisplaySources.ACCUMULATE_ITEMS))
.onRegister(assignDataBehaviour(new ItemThroughputDisplaySource(), "item_throughput")) .transform(displaySource(AllDisplaySources.ITEM_THROUGHPUT))
.register(); .register();
public static final BlockEntry<BrassTunnelBlock> BRASS_TUNNEL = public static final BlockEntry<BrassTunnelBlock> BRASS_TUNNEL =
REGISTRATE.block("brass_tunnel", BrassTunnelBlock::new) REGISTRATE.block("brass_tunnel", BrassTunnelBlock::new)
.properties(p -> p.mapColor(MapColor.TERRACOTTA_YELLOW)) .properties(p -> p.mapColor(MapColor.TERRACOTTA_YELLOW))
.transform(BuilderTransformers.beltTunnel("brass", Create.asResource("block/brass_block"))) .transform(BuilderTransformers.beltTunnel("brass", Create.asResource("block/brass_block")))
.onRegister(assignDataBehaviour(new AccumulatedItemCountDisplaySource(), "accumulate_items")) .transform(displaySource(AllDisplaySources.ACCUMULATE_ITEMS))
.onRegister(assignDataBehaviour(new ItemThroughputDisplaySource(), "item_throughput")) .transform(displaySource(AllDisplaySources.ITEM_THROUGHPUT))
.onRegister(connectedTextures(BrassTunnelCTBehaviour::new)) .onRegister(connectedTextures(BrassTunnelCTBehaviour::new))
.register(); .register();
@ -1814,10 +1795,10 @@ public class AllBlocks {
.properties(p -> p.isRedstoneConductor(($1, $2, $3) -> false)) .properties(p -> p.isRedstoneConductor(($1, $2, $3) -> false))
.transform(axeOrPickaxe()) .transform(axeOrPickaxe())
.blockstate(new SmartObserverGenerator()::generate) .blockstate(new SmartObserverGenerator()::generate)
.onRegister(assignDataBehaviour(new ItemCountDisplaySource(), "count_items")) .transform(displaySource(AllDisplaySources.COUNT_ITEMS))
.onRegister(assignDataBehaviour(new ItemListDisplaySource(), "list_items")) .transform(displaySource(AllDisplaySources.LIST_ITEMS))
.onRegister(assignDataBehaviour(new FluidAmountDisplaySource(), "count_fluids")) .transform(displaySource(AllDisplaySources.COUNT_FLUIDS))
.onRegister(assignDataBehaviour(new FluidListDisplaySource(), "list_fluids")) .transform(displaySource(AllDisplaySources.LIST_FLUIDS))
.lang("Smart Observer") .lang("Smart Observer")
.item() .item()
.transform(customItemModel("_", "block")) .transform(customItemModel("_", "block"))
@ -1831,7 +1812,7 @@ public class AllBlocks {
.properties(p -> p.isRedstoneConductor(($1, $2, $3) -> false)) .properties(p -> p.isRedstoneConductor(($1, $2, $3) -> false))
.transform(axeOrPickaxe()) .transform(axeOrPickaxe())
.blockstate(new ThresholdSwitchGenerator()::generate) .blockstate(new ThresholdSwitchGenerator()::generate)
.onRegister(assignDataBehaviour(new FillLevelDisplaySource(), "fill_level")) .transform(displaySource(AllDisplaySources.FILL_LEVEL))
.lang("Threshold Switch") .lang("Threshold Switch")
.item() .item()
.transform(customItemModel("threshold_switch", "block_wall")) .transform(customItemModel("threshold_switch", "block_wall"))
@ -1981,7 +1962,7 @@ public class AllBlocks {
.transform(pickaxeOnly()) .transform(pickaxeOnly())
.blockstate((c, p) -> p.horizontalFaceBlock(c.get(), AssetLookup.partialBaseModel(c, p))) .blockstate((c, p) -> p.horizontalFaceBlock(c.get(), AssetLookup.partialBaseModel(c, p)))
.onRegister(CreateRegistrate.blockModel(() -> FactoryPanelModel::new)) .onRegister(CreateRegistrate.blockModel(() -> FactoryPanelModel::new))
.onRegister(assignDataBehaviour(new FactoryGaugeDisplaySource(), "gauge_status")) .transform(displaySource(AllDisplaySources.GAUGE_STATUS))
.item(FactoryPanelBlockItem::new) .item(FactoryPanelBlockItem::new)
.model(AssetLookup::customItemModel) .model(AssetLookup::customItemModel)
.build() .build()
@ -2058,7 +2039,7 @@ public class AllBlocks {
.transform(pickaxeOnly()) .transform(pickaxeOnly())
.transform(BlockStressDefaults.setImpact(0)) .transform(BlockStressDefaults.setImpact(0))
.blockstate((c, p) -> p.horizontalBlock(c.get(), AssetLookup.partialBaseModel(c, p))) .blockstate((c, p) -> p.horizontalBlock(c.get(), AssetLookup.partialBaseModel(c, p)))
.onRegister(assignDataBehaviour(new DisplayBoardTarget())) .transform(displayTarget(AllDisplayTargets.DISPLAY_BOARD))
.lang("Display Board") .lang("Display Board")
.item() .item()
.transform(customItemModel()) .transform(customItemModel())
@ -2410,7 +2391,7 @@ public class AllBlocks {
.transform(axeOnly()) .transform(axeOnly())
.onRegister(movementBehaviour(movementBehaviour)) .onRegister(movementBehaviour(movementBehaviour))
.onRegister(interactionBehaviour(interactionBehaviour)) .onRegister(interactionBehaviour(interactionBehaviour))
.onRegister(assignDataBehaviour(new EntityNameDisplaySource(), "entity_name")) .transform(displaySource(AllDisplaySources.ENTITY_NAME))
.blockstate((c, p) -> { .blockstate((c, p) -> {
p.simpleBlock(c.get(), p.models() p.simpleBlock(c.get(), p.models()
.withExistingParent(colourName + "_seat", p.modLoc("block/seat")) .withExistingParent(colourName + "_seat", p.modLoc("block/seat"))

View file

@ -0,0 +1,17 @@
package com.simibubi.create;
import com.simibubi.create.api.contraption.ContraptionMovementSetting;
import com.simibubi.create.infrastructure.config.AllConfigs;
import net.minecraft.world.level.block.Blocks;
public class AllContraptionMovementSettings {
public static void registerDefaults() {
ContraptionMovementSetting.REGISTRY.register(Blocks.SPAWNER, () -> AllConfigs.server().kinetics.spawnerMovement.get());
ContraptionMovementSetting.REGISTRY.register(Blocks.BUDDING_AMETHYST, () -> AllConfigs.server().kinetics.amethystMovement.get());
ContraptionMovementSetting.REGISTRY.register(Blocks.OBSIDIAN, () -> AllConfigs.server().kinetics.obsidianMovement.get());
ContraptionMovementSetting.REGISTRY.register(Blocks.CRYING_OBSIDIAN, () -> AllConfigs.server().kinetics.obsidianMovement.get());
ContraptionMovementSetting.REGISTRY.register(Blocks.RESPAWN_ANCHOR, () -> AllConfigs.server().kinetics.obsidianMovement.get());
ContraptionMovementSetting.REGISTRY.register(Blocks.REINFORCED_DEEPSLATE, () -> AllConfigs.server().kinetics.reinforcedDeepslateMovement.get());
}
}

View file

@ -0,0 +1,51 @@
package com.simibubi.create;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
import com.simibubi.create.api.contraption.ContraptionType;
import com.simibubi.create.api.registry.CreateRegistries;
import com.simibubi.create.content.contraptions.Contraption;
import com.simibubi.create.content.contraptions.bearing.BearingContraption;
import com.simibubi.create.content.contraptions.bearing.ClockworkContraption;
import com.simibubi.create.content.contraptions.bearing.StabilizedContraption;
import com.simibubi.create.content.contraptions.elevator.ElevatorContraption;
import com.simibubi.create.content.contraptions.gantry.GantryContraption;
import com.simibubi.create.content.contraptions.mounted.MountedContraption;
import com.simibubi.create.content.contraptions.piston.PistonContraption;
import com.simibubi.create.content.contraptions.pulley.PulleyContraption;
import com.simibubi.create.content.trains.entity.CarriageContraption;
import net.minecraft.core.Holder;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.registries.DeferredRegister;
public class AllContraptionTypes {
private static final DeferredRegister<ContraptionType> REGISTER = DeferredRegister.create(CreateRegistries.CONTRAPTION_TYPE, Create.ID);
public static final Map<String, ContraptionType> BY_LEGACY_NAME = new HashMap<>();
public static final Holder<ContraptionType> PISTON = register("piston", PistonContraption::new);
public static final Holder<ContraptionType> BEARING = register("bearing", BearingContraption::new);
public static final Holder<ContraptionType> PULLEY = register("pulley", PulleyContraption::new);
public static final Holder<ContraptionType> CLOCKWORK = register("clockwork", ClockworkContraption::new);
public static final Holder<ContraptionType> MOUNTED = register("mounted", MountedContraption::new);
public static final Holder<ContraptionType> STABILIZED = register("stabilized", StabilizedContraption::new);
public static final Holder<ContraptionType> GANTRY = register("gantry", GantryContraption::new);
public static final Holder<ContraptionType> CARRIAGE = register("carriage", CarriageContraption::new);
public static final Holder<ContraptionType> ELEVATOR = register("elevator", ElevatorContraption::new);
private static Holder<ContraptionType> register(String name, Supplier<? extends Contraption> factory) {
return REGISTER.register(name, () -> {
ContraptionType type = new ContraptionType(factory);
BY_LEGACY_NAME.put(name, type);
return type;
});
}
public static void register(IEventBus modEventBus) {
REGISTER.register(modEventBus);
}
}

View file

@ -0,0 +1,154 @@
package com.simibubi.create;
import static com.simibubi.create.Create.REGISTRATE;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import com.simibubi.create.api.behaviour.display.DisplaySource;
import com.simibubi.create.compat.Mods;
import com.simibubi.create.content.redstone.displayLink.source.AccumulatedItemCountDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.BoilerDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.ComputerDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.CurrentFloorDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.DeathCounterDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.EnchantPowerDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.EntityNameDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.FactoryGaugeDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.FillLevelDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.FluidAmountDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.FluidListDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.ItemCountDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.ItemListDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.ItemNameDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.ItemThroughputDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.KineticSpeedDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.KineticStressDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.NixieTubeDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.ObservedTrainNameSource;
import com.simibubi.create.content.redstone.displayLink.source.RedstonePowerDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.ScoreboardDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.StationSummaryDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.StopWatchDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.TimeOfDayDisplaySource;
import com.simibubi.create.content.redstone.displayLink.source.TrainStatusDisplaySource;
import com.tterrag.registrate.util.entry.RegistryEntry;
import net.minecraft.Util;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntityType;
public class AllDisplaySources {
public static final RegistryEntry<DisplaySource, DeathCounterDisplaySource> DEATH_COUNT = REGISTRATE.displaySource("death_count", DeathCounterDisplaySource::new)
.associate(Blocks.RESPAWN_ANCHOR)
.register();
public static final RegistryEntry<DisplaySource, ScoreboardDisplaySource> SCOREBOARD = REGISTRATE.displaySource("scoreboard", ScoreboardDisplaySource::new)
.associate(BlockEntityType.COMMAND_BLOCK)
.register();
public static final RegistryEntry<DisplaySource, EnchantPowerDisplaySource> ENCHANT_POWER = REGISTRATE.displaySource("enchant_power", EnchantPowerDisplaySource::new)
.associate(BlockEntityType.ENCHANTING_TABLE)
.register();
public static final RegistryEntry<DisplaySource, RedstonePowerDisplaySource> REDSTONE_POWER = REGISTRATE.displaySource("redstone_power", RedstonePowerDisplaySource::new)
.associate(Blocks.TARGET)
.register();
public static final RegistryEntry<DisplaySource, NixieTubeDisplaySource> NIXIE_TUBE = simple("nixie_tube", NixieTubeDisplaySource::new);
public static final RegistryEntry<DisplaySource, ItemNameDisplaySource> ITEM_NAMES = simple("item_names", ItemNameDisplaySource::new);
public static final RegistryEntry<DisplaySource, BoilerDisplaySource> BOILER = simple("boiler", BoilerDisplaySource::new);
public static final RegistryEntry<DisplaySource, CurrentFloorDisplaySource> CURRENT_FLOOR = simple("current_floor", CurrentFloorDisplaySource::new);
public static final RegistryEntry<DisplaySource, FillLevelDisplaySource> FILL_LEVEL = simple("fill_level", FillLevelDisplaySource::new);
public static final RegistryEntry<DisplaySource, FactoryGaugeDisplaySource> GAUGE_STATUS = simple("gauge_status", FactoryGaugeDisplaySource::new);
public static final RegistryEntry<DisplaySource, EntityNameDisplaySource> ENTITY_NAME = simple("entity_name", EntityNameDisplaySource::new);
public static final RegistryEntry<DisplaySource, TimeOfDayDisplaySource> TIME_OF_DAY = simple("time_of_day", TimeOfDayDisplaySource::new);
public static final RegistryEntry<DisplaySource, StopWatchDisplaySource> STOPWATCH = simple("stopwatch", StopWatchDisplaySource::new);
public static final RegistryEntry<DisplaySource, KineticSpeedDisplaySource> KINETIC_SPEED = simple("kinetic_speed", KineticSpeedDisplaySource::new);
public static final RegistryEntry<DisplaySource, KineticStressDisplaySource> KINETIC_STRESS = simple("kinetic_stress", KineticStressDisplaySource::new);
public static final RegistryEntry<DisplaySource, StationSummaryDisplaySource> STATION_SUMMARY = simple("station_summary", StationSummaryDisplaySource::new);
public static final RegistryEntry<DisplaySource, TrainStatusDisplaySource> TRAIN_STATUS = simple("train_status", TrainStatusDisplaySource::new);
public static final RegistryEntry<DisplaySource, ObservedTrainNameSource> OBSERVED_TRAIN_NAME = simple("observed_train_name", ObservedTrainNameSource::new);
public static final RegistryEntry<DisplaySource, AccumulatedItemCountDisplaySource> ACCUMULATE_ITEMS = simple("accumulate_items", AccumulatedItemCountDisplaySource::new);
public static final RegistryEntry<DisplaySource, ItemThroughputDisplaySource> ITEM_THROUGHPUT = simple("item_throughput", ItemThroughputDisplaySource::new);
public static final RegistryEntry<DisplaySource, ItemCountDisplaySource> COUNT_ITEMS = simple("count_items", ItemCountDisplaySource::new);
public static final RegistryEntry<DisplaySource, ItemListDisplaySource> LIST_ITEMS = simple("list_items", ItemListDisplaySource::new);
public static final RegistryEntry<DisplaySource, FluidAmountDisplaySource> COUNT_FLUIDS = simple("count_fluids", FluidAmountDisplaySource::new);
public static final RegistryEntry<DisplaySource, FluidListDisplaySource> LIST_FLUIDS = simple("list_fluids", FluidListDisplaySource::new);
public static final RegistryEntry<DisplaySource, ComputerDisplaySource> COMPUTER = REGISTRATE.displaySource("computer", ComputerDisplaySource::new)
.onRegisterAfter(Registries.BLOCK_ENTITY_TYPE, source -> {
List<String> types = List.of("wired_modem_full", "computer_normal", "computer_advanced", "computer_command");
for (String name : types) {
ResourceLocation id = Mods.COMPUTERCRAFT.rl(name);
if (BuiltInRegistries.BLOCK_ENTITY_TYPE.containsKey(id)) {
BlockEntityType<?> type = BuiltInRegistries.BLOCK_ENTITY_TYPE.get(id);
DisplaySource.BY_BLOCK_ENTITY.add(type, source);
} else {
Create.LOGGER.warn("Could not find block entity type {}. Outdated compat?", id);
}
}
})
.register();
public static final Map<String, RegistryEntry<DisplaySource, ? extends DisplaySource>> LEGACY_NAMES = Util.make(() -> {
Map<String, RegistryEntry<DisplaySource, ? extends DisplaySource>> map = new HashMap<>();
map.put("death_count_display_source", DEATH_COUNT);
map.put("scoreboard_display_source", SCOREBOARD);
map.put("enchant_power_display_source", ENCHANT_POWER);
map.put("redstone_power_display_source", REDSTONE_POWER);
map.put("nixie_tube_source", NIXIE_TUBE);
map.put("belt_source_combine_item_names", ITEM_NAMES);
map.put("cuckoo_clock_source_time_of_day", TIME_OF_DAY);
map.put("cuckoo_clock_source_stop_watch", STOPWATCH);
map.put("speedometer_source_kinetic_speed", KINETIC_SPEED);
map.put("stressometer_source_kinetic_stress", KINETIC_STRESS);
map.put("fluid_tank_source_boiler_status", BOILER);
map.put("elevator_contact_source_current_floor", CURRENT_FLOOR);
map.put("track_station_source_station_summary", STATION_SUMMARY);
map.put("track_station_source_train_status", TRAIN_STATUS);
map.put("track_observer_source_observed_train_name", OBSERVED_TRAIN_NAME);
map.put("andesite_tunnel_source_accumulate_items", ACCUMULATE_ITEMS);
map.put("andesite_tunnel_source_item_throughput", ITEM_THROUGHPUT);
map.put("brass_tunnel_source_accumulate_items", ACCUMULATE_ITEMS);
map.put("brass_tunnel_source_item_throughput", ITEM_THROUGHPUT);
map.put("content_observer_source_count_items", COUNT_ITEMS);
map.put("content_observer_source_list_items", LIST_ITEMS);
map.put("content_observer_source_count_fluids", COUNT_FLUIDS);
map.put("content_observer_source_list_fluids", LIST_FLUIDS);
map.put("stockpile_switch_source_fill_level", FILL_LEVEL);
map.put("factory_gauge_source_gauge_status", GAUGE_STATUS);
for (DyeColor color : DyeColor.values()) {
String name = color.getSerializedName() + "_seat_source_entity_name";
map.put(name, ENTITY_NAME);
}
map.put("depot_source_combine_item_names", ITEM_NAMES);
map.put("weighted_ejector_source_combine_item_names", ITEM_NAMES);
map.put("computer_display_source", COMPUTER);
return map;
});
private static <T extends DisplaySource> RegistryEntry<DisplaySource, T> simple(String name, Supplier<T> supplier) {
return REGISTRATE.displaySource(name, supplier).register();
}
public static void register() {
}
}

View file

@ -0,0 +1,41 @@
package com.simibubi.create;
import static com.simibubi.create.Create.REGISTRATE;
import java.util.Map;
import java.util.function.Supplier;
import com.simibubi.create.api.behaviour.display.DisplayTarget;
import com.simibubi.create.content.redstone.displayLink.target.DisplayBoardTarget;
import com.simibubi.create.content.redstone.displayLink.target.LecternDisplayTarget;
import com.simibubi.create.content.redstone.displayLink.target.NixieTubeDisplayTarget;
import com.simibubi.create.content.redstone.displayLink.target.SignDisplayTarget;
import com.tterrag.registrate.util.entry.RegistryEntry;
import net.minecraft.world.level.block.entity.BlockEntityType;
public class AllDisplayTargets {
public static final RegistryEntry<DisplayTarget, SignDisplayTarget> SIGN = REGISTRATE.displayTarget("sign", SignDisplayTarget::new)
.associate(BlockEntityType.SIGN)
.register();
public static final RegistryEntry<DisplayTarget, LecternDisplayTarget> LECTERN = REGISTRATE.displayTarget("lectern", LecternDisplayTarget::new)
.associate(BlockEntityType.LECTERN)
.register();
public static final RegistryEntry<DisplayTarget, DisplayBoardTarget> DISPLAY_BOARD = simple("display_board", DisplayBoardTarget::new);
public static final RegistryEntry<DisplayTarget, NixieTubeDisplayTarget> NIXIE_TUBE = simple("nixie_tube", NixieTubeDisplayTarget::new);
public static final Map<String, RegistryEntry<DisplayTarget, ? extends DisplayTarget>> LEGACY_NAMES = Map.of(
"sign_display_target", SIGN,
"lectern_display_target", LECTERN,
"display_board_target", DISPLAY_BOARD,
"nixie_tube_target", NIXIE_TUBE
);
private static <T extends DisplayTarget> RegistryEntry<DisplayTarget, T> simple(String name, Supplier<T> supplier) {
return REGISTRATE.displayTarget(name, supplier).register();
}
public static void register() {
}
}

View file

@ -1,94 +1,20 @@
package com.simibubi.create; package com.simibubi.create;
import java.util.ArrayList; import com.simibubi.create.api.behaviour.interaction.MovingInteractionBehaviour;
import java.util.List; import com.simibubi.create.api.registry.SimpleRegistry;
import org.jetbrains.annotations.Nullable;
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.TrapdoorMovingInteraction; import com.simibubi.create.content.contraptions.behaviour.TrapdoorMovingInteraction;
import com.simibubi.create.foundation.utility.AttachedRegistry;
import com.tterrag.registrate.util.nullness.NonNullConsumer;
import net.minecraft.core.registries.BuiltInRegistries;
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.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
public class AllInteractionBehaviours { public class AllInteractionBehaviours {
private static final AttachedRegistry<Block, MovingInteractionBehaviour> BLOCK_BEHAVIOURS = new AttachedRegistry<>(BuiltInRegistries.BLOCK);
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
public static MovingInteractionBehaviour getBehaviour(BlockState state) {
MovingInteractionBehaviour behaviour = BLOCK_BEHAVIOURS.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) {
return b -> registerBehaviour(b, behaviour);
}
static void registerDefaults() { static void registerDefaults() {
registerBehaviour(Blocks.LEVER, new LeverMovingInteraction()); MovingInteractionBehaviour.REGISTRY.register(Blocks.LEVER, new LeverMovingInteraction());
DoorMovingInteraction doorBehaviour = new DoorMovingInteraction(); MovingInteractionBehaviour.REGISTRY.registerProvider(SimpleRegistry.Provider.forBlockTag(BlockTags.WOODEN_DOORS, new DoorMovingInteraction()));
registerBehaviourProvider(state -> { MovingInteractionBehaviour.REGISTRY.registerProvider(SimpleRegistry.Provider.forBlockTag(BlockTags.WOODEN_TRAPDOORS, new TrapdoorMovingInteraction()));
if (state.is(BlockTags.MOB_INTERACTABLE_DOORS)) { MovingInteractionBehaviour.REGISTRY.registerProvider(SimpleRegistry.Provider.forBlockTag(BlockTags.FENCE_GATES, new TrapdoorMovingInteraction()));
return doorBehaviour;
}
return null;
});
TrapdoorMovingInteraction trapdoorBehaviour = new TrapdoorMovingInteraction();
registerBehaviourProvider(state -> {
if (state.is(BlockTags.TRAPDOORS) && !state.is(Blocks.IRON_TRAPDOOR)) {
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

@ -34,14 +34,14 @@ public class AllMountedStorageTypes {
// these are for external blocks, register associations here // these are for external blocks, register associations here
public static final RegistryEntry<MountedItemStorageType<?>, SimpleMountedStorageType.Impl> SIMPLE = REGISTRATE.mountedItemStorage("simple", SimpleMountedStorageType.Impl::new) public static final RegistryEntry<MountedItemStorageType<?>, SimpleMountedStorageType.Impl> SIMPLE = REGISTRATE.mountedItemStorage("simple", SimpleMountedStorageType.Impl::new)
.registerTo(AllTags.AllBlockTags.SIMPLE_MOUNTED_STORAGE.tag) .associateBlockTag(AllTags.AllBlockTags.SIMPLE_MOUNTED_STORAGE.tag)
.register(); .register();
public static final RegistryEntry<MountedItemStorageType<?>, ChestMountedStorageType> CHEST = REGISTRATE.mountedItemStorage("chest", ChestMountedStorageType::new) public static final RegistryEntry<MountedItemStorageType<?>, ChestMountedStorageType> CHEST = REGISTRATE.mountedItemStorage("chest", ChestMountedStorageType::new)
.registerTo(AllTags.AllBlockTags.CHEST_MOUNTED_STORAGE.tag) .associateBlockTag(AllTags.AllBlockTags.CHEST_MOUNTED_STORAGE.tag)
.register(); .register();
public static final RegistryEntry<MountedItemStorageType<?>, DispenserMountedStorageType> DISPENSER = REGISTRATE.mountedItemStorage("dispenser", DispenserMountedStorageType::new) public static final RegistryEntry<MountedItemStorageType<?>, DispenserMountedStorageType> DISPENSER = REGISTRATE.mountedItemStorage("dispenser", DispenserMountedStorageType::new)
.registerTo(Blocks.DISPENSER) .associate(Blocks.DISPENSER)
.registerTo(Blocks.DROPPER) .associate(Blocks.DROPPER)
.register(); .register();
private static <T extends MountedItemStorageType<?>> RegistryEntry<MountedItemStorageType<?>, T> simpleItem(String name, Supplier<T> supplier) { private static <T extends MountedItemStorageType<?>> RegistryEntry<MountedItemStorageType<?>, T> simpleItem(String name, Supplier<T> supplier) {

View file

@ -1,75 +1,21 @@
package com.simibubi.create; package com.simibubi.create;
import java.util.ArrayList; import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import java.util.List;
import javax.annotation.Nullable;
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.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 net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
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;
public class AllMovementBehaviours { public class AllMovementBehaviours {
private static final AttachedRegistry<Block, MovementBehaviour> BLOCK_BEHAVIOURS = new AttachedRegistry<>(BuiltInRegistries.BLOCK);
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
public static MovementBehaviour getBehaviour(BlockState state) {
MovementBehaviour behaviour = BLOCK_BEHAVIOURS.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) {
return b -> registerBehaviour(b, behaviour);
}
static void registerDefaults() { static void registerDefaults() {
registerBehaviour(Blocks.BELL, new BellMovementBehaviour()); MovementBehaviour.REGISTRY.register(Blocks.BELL, new BellMovementBehaviour());
registerBehaviour(Blocks.CAMPFIRE, new CampfireMovementBehaviour()); MovementBehaviour.REGISTRY.register(Blocks.CAMPFIRE, new CampfireMovementBehaviour());
registerBehaviour(Blocks.SOUL_CAMPFIRE, new CampfireMovementBehaviour()); MovementBehaviour.REGISTRY.register(Blocks.SOUL_CAMPFIRE, new CampfireMovementBehaviour());
DispenserMovementBehaviour.gatherMovedDispenseItemBehaviours(); DispenserMovementBehaviour.gatherMovedDispenseItemBehaviours();
registerBehaviour(Blocks.DISPENSER, new DispenserMovementBehaviour()); MovementBehaviour.REGISTRY.register(Blocks.DISPENSER, new DispenserMovementBehaviour());
registerBehaviour(Blocks.DROPPER, new DropperMovementBehaviour()); MovementBehaviour.REGISTRY.register(Blocks.DROPPER, new DropperMovementBehaviour());
}
public interface BehaviourProvider {
@Nullable
MovementBehaviour getBehaviour(BlockState state);
} }
} }

View file

@ -0,0 +1,23 @@
package com.simibubi.create;
import com.simibubi.create.api.effect.OpenPipeEffectHandler;
import com.simibubi.create.api.registry.SimpleRegistry;
import com.simibubi.create.impl.effect.LavaEffectHandler;
import com.simibubi.create.impl.effect.MilkEffectHandler;
import com.simibubi.create.impl.effect.PotionEffectHandler;
import com.simibubi.create.impl.effect.TeaEffectHandler;
import com.simibubi.create.impl.effect.WaterEffectHandler;
import net.minecraft.tags.FluidTags;
import net.neoforged.neoforge.common.Tags;
public class AllOpenPipeEffectHandlers {
public static void registerDefaults() {
OpenPipeEffectHandler.REGISTRY.registerProvider(SimpleRegistry.Provider.forFluidTag(FluidTags.WATER, new WaterEffectHandler()));
OpenPipeEffectHandler.REGISTRY.registerProvider(SimpleRegistry.Provider.forFluidTag(FluidTags.LAVA, new LavaEffectHandler()));
OpenPipeEffectHandler.REGISTRY.registerProvider(SimpleRegistry.Provider.forFluidTag(Tags.Fluids.MILK, new MilkEffectHandler()));
OpenPipeEffectHandler.REGISTRY.register(AllFluids.POTION.getSource(), new PotionEffectHandler());
OpenPipeEffectHandler.REGISTRY.register(AllFluids.TEA.getSource(), new TeaEffectHandler());
}
}

View file

@ -1,54 +0,0 @@
package com.simibubi.create;
import com.simibubi.create.api.contraption.storage.fluid.MountedFluidStorageType;
import com.simibubi.create.api.contraption.storage.item.MountedItemStorageType;
import com.simibubi.create.content.kinetics.fan.processing.FanProcessingType;
import com.simibubi.create.content.kinetics.mechanicalArm.ArmInteractionPointType;
import com.simibubi.create.content.logistics.item.filter.attribute.ItemAttributeType;
import com.simibubi.create.content.logistics.packagePort.PackagePortTargetType;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.registries.NewRegistryEvent;
import net.neoforged.neoforge.registries.RegistryBuilder;
@EventBusSubscriber(bus = EventBusSubscriber.Bus.MOD)
public class AllRegistries {
public static final Registry<ArmInteractionPointType> ARM_INTERACTION_POINT_TYPE = create(Keys.ARM_INTERACTION_POINT_TYPE);
public static final Registry<FanProcessingType> FAN_PROCESSING_TYPE = create(Keys.FAN_PROCESSING_TYPE);
public static final Registry<ItemAttributeType> ITEM_ATTRIBUTE_TYPE = create(AllRegistries.Keys.ITEM_ATTRIBUTE_TYPE);
public static final Registry<PackagePortTargetType> PACKAGE_PORT_TARGET = create(Keys.PACKAGE_PORT_TARGET);
public static final Registry<MountedItemStorageType<?>> MOUNTED_ITEM_STORAGE_TYPE = create(Keys.MOUNTED_ITEM_STORAGE_TYPE);
public static final Registry<MountedFluidStorageType<?>> MOUNTED_FLUID_STORAGE_TYPE = create(Keys.MOUNTED_FLUID_STORAGE_TYPE);
private static <T> Registry<T> create(ResourceKey<Registry<T>> key) {
return new RegistryBuilder<>(key).sync(true).create();
}
// Make these non-plural
public static final class Keys {
public static final ResourceKey<Registry<ArmInteractionPointType>> ARM_INTERACTION_POINT_TYPE = key("arm_interaction_point_type");
public static final ResourceKey<Registry<FanProcessingType>> FAN_PROCESSING_TYPE = key("fan_processing_type");
public static final ResourceKey<Registry<ItemAttributeType>> ITEM_ATTRIBUTE_TYPE = key("item_attribute_type");
public static final ResourceKey<Registry<PackagePortTargetType>> PACKAGE_PORT_TARGET = key("package_port_target");
public static final ResourceKey<Registry<MountedItemStorageType<?>>> MOUNTED_ITEM_STORAGE_TYPE = key("mounted_item_storage_type");
public static final ResourceKey<Registry<MountedFluidStorageType<?>>> MOUNTED_FLUID_STORAGE_TYPE = key("mounted_fluid_storage_type");
private static <T> ResourceKey<Registry<T>> key(String name) {
return ResourceKey.createRegistryKey(Create.asResource(name));
}
}
@SubscribeEvent
public static void registerRegistries(NewRegistryEvent event) {
event.register(AllRegistries.ARM_INTERACTION_POINT_TYPE);
event.register(AllRegistries.FAN_PROCESSING_TYPE);
event.register(AllRegistries.ITEM_ATTRIBUTE_TYPE);
event.register(AllRegistries.PACKAGE_PORT_TARGET);
event.register(AllRegistries.MOUNTED_ITEM_STORAGE_TYPE);
event.register(AllRegistries.MOUNTED_FLUID_STORAGE_TYPE);
}
}

View file

@ -6,6 +6,9 @@ import static com.simibubi.create.AllTags.NameSpace.MOD;
import static com.simibubi.create.AllTags.NameSpace.QUARK; import static com.simibubi.create.AllTags.NameSpace.QUARK;
import static com.simibubi.create.AllTags.NameSpace.TIC; import static com.simibubi.create.AllTags.NameSpace.TIC;
import com.simibubi.create.api.contraption.ContraptionType;
import com.simibubi.create.api.registry.CreateRegistries;
import net.createmod.catnip.lang.Lang; import net.createmod.catnip.lang.Lang;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
@ -56,9 +59,7 @@ public class AllTags {
TIC("tconstruct"), TIC("tconstruct"),
QUARK("quark"), QUARK("quark"),
GS("galosphere"), GS("galosphere"),
CURIOS("curios") CURIOS("curios");
;
public final String id; public final String id;
public final boolean optionalDefault; public final boolean optionalDefault;
@ -89,6 +90,7 @@ public class AllTags {
GIRDABLE_TRACKS, GIRDABLE_TRACKS,
MOVABLE_EMPTY_COLLIDER, MOVABLE_EMPTY_COLLIDER,
NON_MOVABLE, NON_MOVABLE,
NON_BREAKABLE,
ORE_OVERRIDE_STONE, ORE_OVERRIDE_STONE,
PASSIVE_BOILER_HEATERS, PASSIVE_BOILER_HEATERS,
SAFE_NBT, SAFE_NBT,
@ -159,7 +161,8 @@ public class AllTags {
return state.is(tag); return state.is(tag);
} }
private static void init() {} private static void init() {
}
} }
@ -190,17 +193,15 @@ public class AllTags {
VALVE_HANDLES, VALVE_HANDLES,
PLATES(COMMON), PLATES(COMMON),
OBSIDIAN_DUST(COMMON,"dusts/obsidian"), OBSIDIAN_DUST(COMMON, "dusts/obsidian"),
WRENCH(COMMON, "tools/wrench"), WRENCH(COMMON, "tools/wrench"),
ALLURITE(MOD,"stone_types/galosphere/allurite"), ALLURITE(MOD, "stone_types/galosphere/allurite"),
AMETHYST(MOD,"stone_types/galosphere/amethyst"), AMETHYST(MOD, "stone_types/galosphere/amethyst"),
LUMIERE(MOD, "stone_types/galosphere/lumiere"), LUMIERE(MOD, "stone_types/galosphere/lumiere"),
UA_CORAL(MOD, "upgrade_aquatic/coral"), UA_CORAL(MOD, "upgrade_aquatic/coral"),
CURIOS_HEAD(CURIOS, "head") CURIOS_HEAD(CURIOS, "head");
;
public final TagKey<Item> tag; public final TagKey<Item> tag;
public final boolean alwaysDatagen; public final boolean alwaysDatagen;
@ -241,7 +242,8 @@ public class AllTags {
return stack.is(tag); return stack.is(tag);
} }
private static void init() {} private static void init() {
}
} }
@ -294,7 +296,8 @@ public class AllTags {
return state.is(tag); return state.is(tag);
} }
private static void init() {} private static void init() {
}
} }
@ -342,7 +345,8 @@ public class AllTags {
return matches(entity.getType()); return matches(entity.getType());
} }
private static void init() {} private static void init() {
}
} }
@ -386,7 +390,29 @@ public class AllTags {
return BuiltInRegistries.RECIPE_SERIALIZER.getHolder(key).orElseThrow().is(tag); return BuiltInRegistries.RECIPE_SERIALIZER.getHolder(key).orElseThrow().is(tag);
} }
private static void init() {} private static void init() {
}
}
public enum AllContraptionTypeTags {
OPENS_CONTROLS,
REQUIRES_VEHICLE_FOR_RENDER;
public final TagKey<ContraptionType> tag;
public final boolean alwaysDatagen;
AllContraptionTypeTags() {
ResourceLocation tagId = Create.asResource(Lang.asId(this.name()));
this.tag = TagKey.create(CreateRegistries.CONTRAPTION_TYPE, tagId);
this.alwaysDatagen = true;
}
public boolean matches(ContraptionType type) {
return type.is(this.tag);
}
private static void init() {
}
} }
public static void init() { public static void init() {
@ -395,5 +421,6 @@ public class AllTags {
AllFluidTags.init(); AllFluidTags.init();
AllEntityTags.init(); AllEntityTags.init();
AllRecipeSerializerTags.init(); AllRecipeSerializerTags.init();
AllContraptionTypeTags.init();
} }
} }

View file

@ -2,27 +2,31 @@ package com.simibubi.create;
import java.util.Random; import java.util.Random;
import com.simibubi.create.content.equipment.armor.AllArmorMaterials;
import com.simibubi.create.content.logistics.packagePort.AllPackagePortTargetTypes;
import com.simibubi.create.foundation.recipe.AllIngredients;
import net.minecraft.core.registries.BuiltInRegistries;
import net.neoforged.neoforge.registries.RegisterEvent;
import org.slf4j.Logger; import org.slf4j.Logger;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.mojang.logging.LogUtils; import com.mojang.logging.LogUtils;
import com.simibubi.create.api.behaviour.BlockSpoutingBehaviour; import com.simibubi.create.api.behaviour.spouting.BlockSpoutingBehaviour;
import com.simibubi.create.compat.Mods; import com.simibubi.create.compat.Mods;
import com.simibubi.create.compat.computercraft.ComputerCraftProxy; import com.simibubi.create.compat.computercraft.ComputerCraftProxy;
import com.simibubi.create.compat.curios.Curios; import com.simibubi.create.compat.curios.Curios;
import com.simibubi.create.content.contraptions.ContraptionMovementSetting;
import com.simibubi.create.content.decoration.palettes.AllPaletteBlocks; import com.simibubi.create.content.decoration.palettes.AllPaletteBlocks;
import com.simibubi.create.content.equipment.armor.AllArmorMaterials;
import com.simibubi.create.content.equipment.potatoCannon.BuiltinPotatoProjectileTypes; import com.simibubi.create.content.equipment.potatoCannon.BuiltinPotatoProjectileTypes;
import com.simibubi.create.content.fluids.tank.BoilerHeaters; import com.simibubi.create.content.fluids.tank.BoilerHeaters;
import com.simibubi.create.content.kinetics.TorquePropagator; import com.simibubi.create.content.kinetics.TorquePropagator;
import com.simibubi.create.content.kinetics.fan.processing.AllFanProcessingTypes; import com.simibubi.create.content.kinetics.fan.processing.AllFanProcessingTypes;
import com.simibubi.create.content.kinetics.mechanicalArm.AllArmInteractionPointTypes; import com.simibubi.create.content.kinetics.mechanicalArm.AllArmInteractionPointTypes;
import com.simibubi.create.content.logistics.item.filter.attribute.AllItemAttributeTypes; import com.simibubi.create.content.logistics.item.filter.attribute.AllItemAttributeTypes;
import com.simibubi.create.content.logistics.packagePort.AllPackagePortTargetTypes;
import com.simibubi.create.content.logistics.packagerLink.GlobalLogisticsManager; import com.simibubi.create.content.logistics.packagerLink.GlobalLogisticsManager;
import com.simibubi.create.content.redstone.displayLink.AllDisplayBehaviours;
import com.simibubi.create.content.redstone.link.RedstoneLinkNetworkHandler; import com.simibubi.create.content.redstone.link.RedstoneLinkNetworkHandler;
import com.simibubi.create.content.schematics.ServerSchematicLoader; import com.simibubi.create.content.schematics.ServerSchematicLoader;
import com.simibubi.create.content.trains.GlobalRailwayManager; import com.simibubi.create.content.trains.GlobalRailwayManager;
@ -34,8 +38,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.recipe.AllIngredients;
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;
@ -45,13 +47,13 @@ import com.simibubi.create.infrastructure.worldgen.AllPlacementModifiers;
import net.createmod.catnip.lang.FontHelper; import net.createmod.catnip.lang.FontHelper;
import net.createmod.catnip.lang.LangBuilder; import net.createmod.catnip.lang.LangBuilder;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation; 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.neoforged.bus.api.EventPriority; import net.neoforged.bus.api.EventPriority;
import net.neoforged.bus.api.IEventBus; import net.neoforged.bus.api.IEventBus;
import net.neoforged.fml.ModContainer; import net.neoforged.fml.ModContainer;
@ -59,7 +61,6 @@ import net.neoforged.fml.ModLoadingContext;
import net.neoforged.fml.common.Mod; import net.neoforged.fml.common.Mod;
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
import net.neoforged.neoforge.common.NeoForgeMod; import net.neoforged.neoforge.common.NeoForgeMod;
import net.neoforged.neoforge.registries.RegisterEvent;
@Mod(Create.ID) @Mod(Create.ID)
public class Create { public class Create {
@ -111,6 +112,8 @@ public class Create {
AllTags.init(); AllTags.init();
AllCreativeModeTabs.register(modEventBus); AllCreativeModeTabs.register(modEventBus);
AllArmorMaterials.register(modEventBus); AllArmorMaterials.register(modEventBus);
AllDisplaySources.register();
AllDisplayTargets.register();
AllBlocks.register(); AllBlocks.register();
AllItems.register(); AllItems.register();
AllFluids.register(); AllFluids.register();
@ -136,15 +139,10 @@ public class Create {
AllArmInteractionPointTypes.register(modEventBus); AllArmInteractionPointTypes.register(modEventBus);
AllFanProcessingTypes.register(modEventBus); AllFanProcessingTypes.register(modEventBus);
AllItemAttributeTypes.register(modEventBus); AllItemAttributeTypes.register(modEventBus);
AllContraptionTypes.register(modEventBus);
AllPackagePortTargetTypes.register(modEventBus); AllPackagePortTargetTypes.register(modEventBus);
BlockSpoutingBehaviour.registerDefaults();
// FIXME: some of these registrations are not thread-safe // FIXME: some of these registrations are not thread-safe
AllMovementBehaviours.registerDefaults();
AllInteractionBehaviours.registerDefaults();
AllPortalTracks.registerDefaults();
AllDisplayBehaviours.registerDefaults();
ContraptionMovementSetting.registerDefaults();
BogeySizes.init(); BogeySizes.init();
AllBogeyStyles.init(); AllBogeyStyles.init();
// ---- // ----
@ -173,9 +171,13 @@ 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();
BlockSpoutingBehaviour.registerDefaults();
AllMovementBehaviours.registerDefaults();
AllInteractionBehaviours.registerDefaults();
AllContraptionMovementSettings.registerDefaults();
AllOpenPipeEffectHandlers.registerDefaults();
// -- // --
AttachedRegistry.unwrapAll();
}); });
} }

View file

@ -1,46 +0,0 @@
package com.simibubi.create.api.behaviour;
import com.simibubi.create.Create;
import com.simibubi.create.compat.tconstruct.SpoutCasting;
import com.simibubi.create.content.fluids.spout.SpoutBlockEntity;
import com.simibubi.create.impl.behaviour.BlockSpoutingBehaviourImpl;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.Level;
import net.neoforged.neoforge.fluids.FluidStack;
public abstract class BlockSpoutingBehaviour {
/**
* Register a new custom spout interaction
*
* @param resourceLocation The interaction id
* @param spoutingBehaviour An instance of your behaviour class
*/
public static void addCustomSpoutInteraction(ResourceLocation resourceLocation, BlockSpoutingBehaviour spoutingBehaviour) {
BlockSpoutingBehaviourImpl.addCustomSpoutInteraction(resourceLocation, spoutingBehaviour);
}
public static void registerDefaults() {
addCustomSpoutInteraction(Create.asResource("ticon_casting"), new SpoutCasting());
}
/**
* While idle, Spouts will call this every tick with simulate == true <br>
* When fillBlock returns &gt; 0, the Spout will start its animation cycle <br>
* <br>
* During this animation cycle, fillBlock is called once again with simulate == false but only on the relevant SpoutingBehaviour <br>
* When fillBlock returns &gt; 0 once again, the Spout will drain its content by the returned amount of units <br>
* Perform any other side effects in this method <br>
* This method is called server-side only (except in ponder) <br>
*
* @param level The current level
* @param pos The position of the affected block
* @param spout The spout block entity that is calling this
* @param availableFluid A copy of the fluidStack that is available, modifying this will do nothing, return the amount to be subtracted instead
* @param simulate Whether the spout is testing or actually performing this behaviour
* @return The amount filled into the block, 0 to idle/cancel
*/
public abstract int fillBlock(Level level, BlockPos pos, SpoutBlockEntity spout, FluidStack availableFluid, boolean simulate);
}

View file

@ -0,0 +1,172 @@
package com.simibubi.create.api.behaviour.display;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ImmutableList;
import com.simibubi.create.AllDisplaySources;
import com.simibubi.create.Create;
import com.simibubi.create.api.registry.CreateBuiltInRegistries;
import com.simibubi.create.api.registry.CreateRegistries;
import com.simibubi.create.api.registry.SimpleRegistry;
import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext;
import com.simibubi.create.content.redstone.displayLink.target.DisplayBoardTarget;
import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats;
import com.simibubi.create.content.trains.display.FlapDisplayBlockEntity;
import com.simibubi.create.content.trains.display.FlapDisplayLayout;
import com.simibubi.create.foundation.gui.ModularGuiLineBuilder;
import com.tterrag.registrate.builders.BlockBuilder;
import com.tterrag.registrate.util.entry.RegistryEntry;
import com.tterrag.registrate.util.nullness.NonNullUnaryOperator;
import net.createmod.catnip.nbt.NBTProcessors;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.LevelAccessor;
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;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.api.distmarker.OnlyIn;
public abstract class DisplaySource {
public static final SimpleRegistry.Multi<Block, DisplaySource> BY_BLOCK = SimpleRegistry.Multi.create();
public static final SimpleRegistry.Multi<BlockEntityType<?>, DisplaySource> BY_BLOCK_ENTITY = SimpleRegistry.Multi.create();
public static final List<MutableComponent> EMPTY = ImmutableList.of(Component.empty());
public static final MutableComponent EMPTY_LINE = Component.empty();
public static final MutableComponent WHITESPACE = CommonComponents.space();
public abstract List<MutableComponent> provideText(DisplayLinkContext context, DisplayTargetStats stats);
public void transferData(DisplayLinkContext context, DisplayTarget activeTarget, int line) {
DisplayTargetStats stats = activeTarget.provideStats(context);
if (activeTarget instanceof DisplayBoardTarget fddt) {
List<List<MutableComponent>> flapDisplayText = provideFlapDisplayText(context, stats);
fddt.acceptFlapText(line, flapDisplayText, context);
}
List<MutableComponent> text = provideText(context, stats);
if (text.isEmpty())
text = EMPTY;
if (activeTarget.requiresComponentSanitization())
for (MutableComponent component : text)
if (NBTProcessors.textComponentHasClickEvent(component))
return; // Naughty
activeTarget.acceptText(line, text, context);
}
public void onSignalReset(DisplayLinkContext context) {
}
public void populateData(DisplayLinkContext context) {
}
public int getPassiveRefreshTicks() {
return 100;
}
public boolean shouldPassiveReset() {
return true;
}
protected final ResourceLocation getId() {
return CreateBuiltInRegistries.DISPLAY_SOURCE.getKey(this);
}
protected String getTranslationKey() {
return this.getId().getPath();
}
public Component getName() {
return Component.translatable(this.getId().getNamespace() + ".display_source." + getTranslationKey());
}
public void loadFlapDisplayLayout(DisplayLinkContext context, FlapDisplayBlockEntity flapDisplay, FlapDisplayLayout layout, int lineIndex) {
loadFlapDisplayLayout(context, flapDisplay, layout);
}
public void loadFlapDisplayLayout(DisplayLinkContext context, FlapDisplayBlockEntity flapDisplay,
FlapDisplayLayout layout) {
if (!layout.isLayout("Default"))
layout.loadDefault(flapDisplay.getMaxCharCount());
}
public List<List<MutableComponent>> provideFlapDisplayText(DisplayLinkContext context, DisplayTargetStats stats) {
return provideText(context, stats).stream()
.map(Arrays::asList)
.toList();
}
@OnlyIn(Dist.CLIENT)
public void initConfigurationWidgets(DisplayLinkContext context, ModularGuiLineBuilder builder,
boolean isFirstLine) {
}
/**
* Utility for use with Registrate builders. Creates a builder transformer
* that will register the given DisplaySource to a block when ready.
*/
public static <B extends Block, P> NonNullUnaryOperator<BlockBuilder<B, P>> displaySource(RegistryEntry<DisplaySource, ? extends DisplaySource> source) {
return builder -> builder.onRegisterAfter(CreateRegistries.DISPLAY_SOURCE, block -> BY_BLOCK.add(block, source.get()));
}
/**
* Get the DisplaySource with the given ID, accounting for legacy names.
*/
@Nullable
public static DisplaySource get(@Nullable ResourceLocation id) {
if (id == null)
return null;
if (id.getNamespace().equals(Create.ID) && AllDisplaySources.LEGACY_NAMES.containsKey(id.getPath())) {
return AllDisplaySources.LEGACY_NAMES.get(id.getPath()).get();
}
return CreateBuiltInRegistries.DISPLAY_SOURCE.get(id);
}
/**
* Get all DisplaySources applicable to the block at the given location, checking both the Block and BlockEntity.
* Returns an empty list if none are present, not null.
*/
public static List<DisplaySource> getAll(LevelAccessor level, BlockPos pos) {
BlockState state = level.getBlockState(pos);
List<DisplaySource> byBlock = BY_BLOCK.get(state);
BlockEntity be = level.getBlockEntity(pos);
if (be == null)
return byBlock;
List<DisplaySource> byBe = BY_BLOCK_ENTITY.get(be.getType());
if (byBlock.isEmpty()) {
if (byBe.isEmpty()) {
// none
return List.of();
} else {
// only BlockEntity
return byBe;
}
} else if (byBe.isEmpty()) {
// only Block
return byBlock;
} else {
// both present, combine
List<DisplaySource> combined = new ArrayList<>(byBlock);
combined.addAll(byBe);
return combined;
}
}
}

View file

@ -0,0 +1,137 @@
package com.simibubi.create.api.behaviour.display;
import java.util.List;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllDisplayTargets;
import com.simibubi.create.Create;
import com.simibubi.create.api.registry.CreateBuiltInRegistries;
import com.simibubi.create.api.registry.CreateRegistries;
import com.simibubi.create.api.registry.SimpleRegistry;
import com.simibubi.create.content.redstone.displayLink.DisplayLinkContext;
import com.simibubi.create.content.redstone.displayLink.target.DisplayTargetStats;
import com.simibubi.create.foundation.utility.CreateLang;
import com.tterrag.registrate.builders.BlockBuilder;
import com.tterrag.registrate.util.entry.RegistryEntry;
import com.tterrag.registrate.util.nullness.NonNullUnaryOperator;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.LevelAccessor;
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.entity.SignBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.shapes.VoxelShape;
public abstract class DisplayTarget {
public static final SimpleRegistry<Block, DisplayTarget> BY_BLOCK = SimpleRegistry.create();
public static final SimpleRegistry<BlockEntityType<?>, DisplayTarget> BY_BLOCK_ENTITY = SimpleRegistry.create();
public abstract void acceptText(int line, List<MutableComponent> text, DisplayLinkContext context);
public abstract DisplayTargetStats provideStats(DisplayLinkContext context);
public AABB getMultiblockBounds(LevelAccessor level, BlockPos pos) {
VoxelShape shape = level.getBlockState(pos)
.getShape(level, pos);
if (shape.isEmpty())
return new AABB(pos);
return shape.bounds()
.move(pos);
}
public Component getLineOptionText(int line) {
return CreateLang.translateDirect("display_target.line", line + 1);
}
public static void reserve(int line, BlockEntity target, DisplayLinkContext context) {
if (line == 0)
return;
CompoundTag tag = target.getPersistentData();
CompoundTag compound = tag.getCompound("DisplayLink");
compound.putLong("Line" + line, context.blockEntity()
.getBlockPos()
.asLong());
tag.put("DisplayLink", compound);
}
public boolean isReserved(int line, BlockEntity target, DisplayLinkContext context) {
CompoundTag tag = target.getPersistentData();
CompoundTag compound = tag.getCompound("DisplayLink");
if (!compound.contains("Line" + line))
return false;
long l = compound.getLong("Line" + line);
BlockPos reserved = BlockPos.of(l);
if (!reserved.equals(context.blockEntity()
.getBlockPos()) && AllBlocks.DISPLAY_LINK.has(target.getLevel()
.getBlockState(reserved)))
return true;
compound.remove("Line" + line);
if (compound.isEmpty())
tag.remove("DisplayLink");
return false;
}
public boolean requiresComponentSanitization() {
return false;
}
/**
* Utility for use with Registrate builders. Creates a builder transformer
* that will register the given DisplayTarget to a block when ready.
*/
public static <B extends Block, P> NonNullUnaryOperator<BlockBuilder<B, P>> displayTarget(RegistryEntry<DisplayTarget, ? extends DisplayTarget> target) {
return builder -> builder.onRegisterAfter(CreateRegistries.DISPLAY_TARGET, block -> BY_BLOCK.register(block, target.get()));
}
/**
* Get the DisplayTarget with the given ID, accounting for legacy names.
*/
@Nullable
public static DisplayTarget get(@Nullable ResourceLocation id) {
if (id == null)
return null;
if (id.getNamespace().equals(Create.ID) && AllDisplayTargets.LEGACY_NAMES.containsKey(id.getPath())) {
return AllDisplayTargets.LEGACY_NAMES.get(id.getPath()).get();
}
return CreateBuiltInRegistries.DISPLAY_TARGET.get(id);
}
/**
* Get the DisplayTarget applicable to the given location, or null if there isn't one.
*/
@Nullable
public static DisplayTarget get(LevelAccessor level, BlockPos pos) {
BlockState state = level.getBlockState(pos);
DisplayTarget byBlock = BY_BLOCK.get(state);
// block takes priority if present, it's more granular
if (byBlock != null)
return byBlock;
BlockEntity be = level.getBlockEntity(pos);
if (be == null)
return null;
DisplayTarget byBe = BY_BLOCK_ENTITY.get(be.getType());
if (byBe != null)
return byBe;
// special case: modded signs are common
return be instanceof SignBlockEntity ? AllDisplayTargets.SIGN.get() : null;
}
}

View file

@ -1,11 +1,12 @@
package com.simibubi.create.content.processing.burner; package com.simibubi.create.api.behaviour.interaction;
import java.util.function.Consumer;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.api.contraption.train.TrainConductorHandler;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.Contraption; import com.simibubi.create.content.contraptions.Contraption;
import com.simibubi.create.content.contraptions.behaviour.MovingInteractionBehaviour; import com.simibubi.create.content.processing.burner.BlazeBurnerBlock;
import com.simibubi.create.content.trains.entity.CarriageContraption; import com.simibubi.create.content.trains.entity.CarriageContraption;
import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; import com.simibubi.create.content.trains.entity.CarriageContraptionEntity;
import com.simibubi.create.content.trains.entity.Train; import com.simibubi.create.content.trains.entity.Train;
@ -25,20 +26,25 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
import java.util.function.Predicate; /**
* Partial interaction behavior implementation that allows blocks to act as conductors on trains, like Blaze Burners.
*/
public abstract class ConductorBlockInteractionBehavior extends MovingInteractionBehaviour {
/**
* Check if the given state is capable of being a conductor.
*/
public abstract boolean isValidConductor(BlockState state);
public class BlockBasedTrainConductorInteractionBehaviour extends MovingInteractionBehaviour { /**
* Called when the conductor's schedule has changed.
private final Predicate<BlockState> isValidConductor; * @param hasSchedule true if the schedule was set, false if it was removed
private final TrainConductorHandler.UpdateScheduleCallback callback; * @param blockStateSetter a consumer that will change the BlockState of this conductor on the contraption
*/
public BlockBasedTrainConductorInteractionBehaviour(Predicate<BlockState> isValidConductor, TrainConductorHandler.UpdateScheduleCallback callback) { protected void onScheduleUpdate(boolean hasSchedule, BlockState currentBlockState, Consumer<BlockState> blockStateSetter) {
this.isValidConductor = isValidConductor;
this.callback = callback;
} }
@Override @Override
public boolean handlePlayerInteraction(Player player, InteractionHand activeHand, BlockPos localPos, public final boolean handlePlayerInteraction(Player player, InteractionHand activeHand, BlockPos localPos,
AbstractContraptionEntity contraptionEntity) { AbstractContraptionEntity contraptionEntity) {
ItemStack itemInHand = player.getItemInHand(activeHand); ItemStack itemInHand = player.getItemInHand(activeHand);
@ -52,7 +58,7 @@ public class BlockBasedTrainConductorInteractionBehaviour extends MovingInteract
StructureBlockInfo info = carriageContraption.getBlocks() StructureBlockInfo info = carriageContraption.getBlocks()
.get(localPos); .get(localPos);
if (info == null || !isValidConductor.test(info.state())) if (info == null || !this.isValidConductor(info.state()))
return false; return false;
Direction assemblyDirection = carriageContraption.getAssemblyDirection(); Direction assemblyDirection = carriageContraption.getAssemblyDirection();
@ -85,7 +91,7 @@ public class BlockBasedTrainConductorInteractionBehaviour extends MovingInteract
train.runtime.isAutoSchedule ? "schedule.auto_removed_from_train" : "schedule.removed_from_train"), train.runtime.isAutoSchedule ? "schedule.auto_removed_from_train" : "schedule.removed_from_train"),
true); true);
player.setItemInHand(activeHand, train.runtime.returnSchedule(player.registryAccess())); player.setItemInHand(activeHand, train.runtime.returnSchedule(player.registryAccess()));
callback.update(false, info.state(), newBlockState -> setBlockState(localPos, contraptionEntity, newBlockState)); this.onScheduleUpdate(false, info.state(), newBlockState -> setBlockState(localPos, contraptionEntity, newBlockState));
return true; return true;
} }
@ -101,7 +107,7 @@ public class BlockBasedTrainConductorInteractionBehaviour extends MovingInteract
player.displayClientMessage(CreateLang.translateDirect("schedule.no_stops"), true); player.displayClientMessage(CreateLang.translateDirect("schedule.no_stops"), true);
return true; return true;
} }
callback.update(true, info.state(), newBlockState -> setBlockState(localPos, contraptionEntity, newBlockState)); this.onScheduleUpdate(true, info.state(), newBlockState -> setBlockState(localPos, contraptionEntity, newBlockState));
train.runtime.setSchedule(schedule, false); train.runtime.setSchedule(schedule, false);
AllAdvancements.CONDUCTOR.awardTo(player); AllAdvancements.CONDUCTOR.awardTo(player);
AllSoundEvents.CONFIRM.playOnServer(player.level(), player.blockPosition(), 1, 1); AllSoundEvents.CONFIRM.playOnServer(player.level(), player.blockPosition(), 1, 1);
@ -123,4 +129,14 @@ public class BlockBasedTrainConductorInteractionBehaviour extends MovingInteract
setContraptionBlockData(contraption, localPos, new StructureTemplate.StructureBlockInfo(info.pos(), newState, info.nbt())); setContraptionBlockData(contraption, localPos, new StructureTemplate.StructureBlockInfo(info.pos(), newState, info.nbt()));
} }
} }
/**
* Implementation used for Blaze Burners. May be reused by addons if applicable.
*/
public static class BlazeBurner extends ConductorBlockInteractionBehavior {
@Override
public boolean isValidConductor(BlockState state) {
return state.getValue(BlazeBurnerBlock.HEAT_LEVEL) != BlazeBurnerBlock.HeatLevel.NONE;
}
}
} }

View file

@ -1,19 +1,35 @@
package com.simibubi.create.content.contraptions.behaviour; package com.simibubi.create.api.behaviour.interaction;
import org.apache.commons.lang3.tuple.MutablePair; import org.apache.commons.lang3.tuple.MutablePair;
import com.simibubi.create.api.registry.SimpleRegistry;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.tterrag.registrate.util.nullness.NonNullConsumer;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
/**
* MovingInteractionBehaviors define behavior of blocks on contraptions
* when interacted with by players or collided with by entities.
*/
public abstract class MovingInteractionBehaviour { public abstract class MovingInteractionBehaviour {
public static final SimpleRegistry<Block, MovingInteractionBehaviour> REGISTRY = SimpleRegistry.create();
/**
* Creates a consumer that will register a behavior to a block. Useful for Registrate.
*/
public static <B extends Block> NonNullConsumer<? super B> interactionBehaviour(MovingInteractionBehaviour behaviour) {
return b -> REGISTRY.register(b, behaviour);
}
protected void setContraptionActorData(AbstractContraptionEntity contraptionEntity, int index, protected void setContraptionActorData(AbstractContraptionEntity contraptionEntity, int index,
StructureBlockInfo info, MovementContext ctx) { StructureBlockInfo info, MovementContext ctx) {
contraptionEntity.getContraption().getActors().remove(index); contraptionEntity.getContraption().getActors().remove(index);
contraptionEntity.getContraption().getActors().add(index, MutablePair.of(info, ctx)); contraptionEntity.getContraption().getActors().add(index, MutablePair.of(info, ctx));
if (contraptionEntity.level().isClientSide) if (contraptionEntity.level().isClientSide)

View file

@ -1,11 +1,14 @@
package com.simibubi.create.content.contraptions.behaviour; package com.simibubi.create.api.behaviour.movement;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.simibubi.create.api.registry.SimpleRegistry;
import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.simibubi.create.content.contraptions.render.ActorVisual; import com.simibubi.create.content.contraptions.render.ActorVisual;
import com.simibubi.create.content.contraptions.render.ContraptionMatrices; import com.simibubi.create.content.contraptions.render.ContraptionMatrices;
import com.simibubi.create.foundation.virtualWorld.VirtualRenderWorld; import com.simibubi.create.foundation.virtualWorld.VirtualRenderWorld;
import com.simibubi.create.infrastructure.config.AllConfigs; import com.simibubi.create.infrastructure.config.AllConfigs;
import com.tterrag.registrate.util.nullness.NonNullConsumer;
import dev.engine_room.flywheel.api.visualization.VisualizationContext; import dev.engine_room.flywheel.api.visualization.VisualizationContext;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
@ -14,11 +17,24 @@ import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.neoforged.api.distmarker.Dist; import net.neoforged.api.distmarker.Dist;
import net.neoforged.api.distmarker.OnlyIn; import net.neoforged.api.distmarker.OnlyIn;
import net.neoforged.neoforge.items.ItemHandlerHelper; import net.neoforged.neoforge.items.ItemHandlerHelper;
/**
* MovementBehaviors, also known as Actors, provide behavior to blocks mounted on contraptions.
* Blocks may be associated with a behavior through {@link #REGISTRY}.
*/
public interface MovementBehaviour { public interface MovementBehaviour {
SimpleRegistry<Block, MovementBehaviour> REGISTRY = SimpleRegistry.create();
/**
* Creates a consumer that will register a behavior to a block. Useful for Registrate.
*/
static <B extends Block> NonNullConsumer<? super B> movementBehaviour(MovementBehaviour behaviour) {
return b -> REGISTRY.register(b, behaviour);
}
default boolean isActive(MovementContext context) { default boolean isActive(MovementContext context) {
return !context.disabled; return !context.disabled;

View file

@ -0,0 +1,103 @@
package com.simibubi.create.api.behaviour.spouting;
import java.util.List;
import java.util.function.Predicate;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.Create;
import com.simibubi.create.api.registry.SimpleRegistry;
import com.simibubi.create.compat.Mods;
import com.simibubi.create.compat.tconstruct.SpoutCasting;
import com.simibubi.create.content.fluids.spout.SpoutBlockEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.FarmBlock;
import net.minecraft.world.level.block.LayeredCauldronBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import net.neoforged.neoforge.fluids.FluidStack;
/**
* Interface for custom block-filling behavior for spouts.
* <p>
* Behaviors are queried by block first, through {@link #BY_BLOCK}. If no behavior was provided,
* they are then queried by block entity type, through {@link #BY_BLOCK_ENTITY}.
* @see StateChangingBehavior
* @see CauldronSpoutingBehavior
*/
@FunctionalInterface
public interface BlockSpoutingBehaviour {
SimpleRegistry<Block, BlockSpoutingBehaviour> BY_BLOCK = SimpleRegistry.create();
SimpleRegistry<BlockEntityType<?>, BlockSpoutingBehaviour> BY_BLOCK_ENTITY = SimpleRegistry.create();
/**
* Get the behavior that should be used for the block at the given location.
* Queries both the block and the block entity if needed.
*/
@Nullable
static BlockSpoutingBehaviour get(Level level, BlockPos pos) {
BlockState state = level.getBlockState(pos);
BlockSpoutingBehaviour byBlock = BY_BLOCK.get(state.getBlock());
if (byBlock != null)
return byBlock;
BlockEntity be = level.getBlockEntity(pos);
if (be == null)
return null;
return BY_BLOCK_ENTITY.get(be.getType());
}
static void registerDefaults() {
Predicate<Fluid> isWater = fluid -> fluid.isSame(Fluids.WATER);
BlockSpoutingBehaviour toMud = StateChangingBehavior.setTo(250, isWater, Blocks.MUD);
for (Block dirt : List.of(Blocks.DIRT, Blocks.COARSE_DIRT, Blocks.ROOTED_DIRT)) {
BY_BLOCK.register(dirt, toMud);
}
BY_BLOCK.register(Blocks.FARMLAND, StateChangingBehavior.incrementingState(100, isWater, FarmBlock.MOISTURE));
BY_BLOCK.register(Blocks.WATER_CAULDRON, StateChangingBehavior.incrementingState(250, isWater, LayeredCauldronBlock.LEVEL));
BY_BLOCK.register(Blocks.CAULDRON, CauldronSpoutingBehavior.INSTANCE);
if (!Mods.TCONSTRUCT.isLoaded())
return;
for (String name : List.of("table", "basin")) {
ResourceLocation id = Mods.TCONSTRUCT.rl(name);
if (BuiltInRegistries.BLOCK_ENTITY_TYPE.containsKey(id)) {
BlockEntityType<?> table = BuiltInRegistries.BLOCK_ENTITY_TYPE.get(id);
BY_BLOCK_ENTITY.register(table, SpoutCasting.INSTANCE);
} else {
Create.LOGGER.warn("Block entity {} wasn't found. Outdated compat?", id);
}
}
}
/**
* While idle, spouts will query the behavior provided by the block below it.
* If one is present, this method will be called every tick with simulate == true.
* <p>
* When a value greater than 0 is returned, the spout will begin processing. It will call this method again
* with simulate == false, which is when any filling behavior should actually occur.
* <p>
* This method is only called on the server side, except for in Ponder.
* @param level The current level
* @param pos The position of the affected block
* @param spout The spout block entity that is calling this
* @param availableFluid A copy of the fluidStack that is available, modifying this will do nothing, return the amount to be subtracted instead
* @param simulate Whether the spout is testing or actually performing this behaviour
* @return The amount filled into the block, 0 to idle/cancel
*/
int fillBlock(Level level, BlockPos pos, SpoutBlockEntity spout, FluidStack availableFluid, boolean simulate);
}

View file

@ -0,0 +1,56 @@
package com.simibubi.create.api.behaviour.spouting;
import com.simibubi.create.api.registry.SimpleRegistry;
import com.simibubi.create.content.fluids.spout.SpoutBlockEntity;
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import net.neoforged.neoforge.fluids.FluidStack;
/**
* {@link BlockSpoutingBehaviour} for empty cauldrons. Mods can register their fluids
* to {@link #CAULDRON_INFO} to allow spouts to fill empty cauldrons with their fluids.
*/
public enum CauldronSpoutingBehavior implements BlockSpoutingBehaviour {
INSTANCE;
public static final SimpleRegistry<Fluid, CauldronInfo> CAULDRON_INFO = Util.make(() -> {
SimpleRegistry<Fluid, CauldronInfo> registry = SimpleRegistry.create();
registry.register(Fluids.WATER, new CauldronInfo(250, Blocks.WATER_CAULDRON));
registry.register(Fluids.LAVA, new CauldronInfo(1000, Blocks.LAVA_CAULDRON));
return registry;
});
@Override
public int fillBlock(Level level, BlockPos pos, SpoutBlockEntity spout, FluidStack availableFluid, boolean simulate) {
CauldronInfo info = CAULDRON_INFO.get(availableFluid.getFluid());
if (info == null)
return 0;
if (availableFluid.getAmount() < info.amount)
return 0;
if (!simulate) {
level.setBlockAndUpdate(pos, info.cauldron);
}
return info.amount;
}
/**
* @param amount the amount of fluid that must be inserted into an empty cauldron
* @param cauldron the BlockState to set after filling an empty cauldron with the given amount of fluid
*/
public record CauldronInfo(int amount, BlockState cauldron) {
public CauldronInfo(int amount, Block block) {
this(amount, block.defaultBlockState());
}
}
}

View file

@ -0,0 +1,71 @@
package com.simibubi.create.api.behaviour.spouting;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import com.simibubi.create.content.fluids.spout.SpoutBlockEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.level.material.Fluid;
import net.neoforged.neoforge.fluids.FluidStack;
/**
* An implementation of {@link BlockSpoutingBehaviour} that allows for easily modifying a BlockState through spouting.
* @param amount the amount of fluid consumed when filling
* @param fluidTest a predicate for fluids that can be used to fill the target block
* @param canFill a predicate that must match the target BlockState to fill it
* @param fillFunction a function that converts the current state into the filled one
*/
public record StateChangingBehavior(int amount, Predicate<Fluid> fluidTest, Predicate<BlockState> canFill,
UnaryOperator<BlockState> fillFunction) implements BlockSpoutingBehaviour {
@Override
public int fillBlock(Level level, BlockPos pos, SpoutBlockEntity spout, FluidStack availableFluid, boolean simulate) {
if (availableFluid.getAmount() < this.amount || !this.fluidTest.test(availableFluid.getFluid()))
return 0;
BlockState state = level.getBlockState(pos);
if (!this.canFill.test(state))
return 0;
if (!simulate) {
BlockState newState = this.fillFunction.apply(state);
level.setBlockAndUpdate(pos, newState);
}
return this.amount;
}
/**
* Shortcut for {@link #setTo(int, Predicate, BlockState)} that uses the Block's default state.
*/
public static BlockSpoutingBehaviour setTo(int amount, Predicate<Fluid> fluidTest, Block block) {
return setTo(amount, fluidTest, block.defaultBlockState());
}
/**
* Create a {@link BlockSpoutingBehaviour} that will simply convert the target block to the given state.
* @param newState the state that will be set after filling
*/
public static BlockSpoutingBehaviour setTo(int amount, Predicate<Fluid> fluidTest, BlockState newState) {
return new StateChangingBehavior(amount, fluidTest, state -> true, state -> newState);
}
/**
* Create a {@link BlockSpoutingBehaviour} that will increment the given {@link IntegerProperty} until it reaches
* its maximum value, consuming {@code amount} each time fluid is filled.
* @param property the property that will be incremented by one on each fill
*/
public static BlockSpoutingBehaviour incrementingState(int amount, Predicate<Fluid> fluidTest, IntegerProperty property) {
int max = property.getPossibleValues().stream().max(Integer::compareTo).orElseThrow();
Predicate<BlockState> canFill = state -> state.getValue(property) < max;
UnaryOperator<BlockState> fillFunction = state -> state.setValue(property, state.getValue(property) + 1);
return new StateChangingBehavior(amount, fluidTest, canFill, fillFunction);
}
}

View file

@ -0,0 +1,51 @@
package com.simibubi.create.api.boiler;
import com.simibubi.create.api.registry.SimpleRegistry;
import com.simibubi.create.content.fluids.tank.BoilerHeaters;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
/**
* A BoilerHeater provides heat to boilers.
* Boilers will query blocks for heaters through the registry, usually with {@link #findHeat(Level, BlockPos, BlockState) findHeat}.
* Heaters can provide a heat level by returning any positive integer from their {@link #getHeat(Level, BlockPos, BlockState) getHeat} method.
* Returning any negative number counts as no heat - {@link #NO_HEAT} is provided for convenience.
* <p>
* Returning {@link #PASSIVE_HEAT} is special - passive heat can be used to provide a small amount of heat, highly limiting
* in its abilities. This is usually used for free sources of heat, such as fire or magma blocks.
*/
@FunctionalInterface
public interface BoilerHeater {
int PASSIVE_HEAT = 0;
int NO_HEAT = -1;
/**
* The heater used by common passively-heating blocks. Automatically provides
* heat for any block in the {@code create:passive_boiler_heaters} block tag.
*/
BoilerHeater PASSIVE = BoilerHeaters::passive;
/**
* The heater used by Blaze Burners. Addons can register this to their own blocks if they use the same functionality.
*/
BoilerHeater BLAZE_BURNER = BoilerHeaters::blazeBurner;
SimpleRegistry<Block, BoilerHeater> REGISTRY = SimpleRegistry.create();
/**
* Gets the heat at the given location. If a heater is present, queries it for heat. If not, returns {@link #NO_HEAT}.
*/
static float findHeat(Level level, BlockPos pos, BlockState state) {
BoilerHeater heater = REGISTRY.get(state);
return heater != null ? heater.getHeat(level, pos, state) : NO_HEAT;
}
/**
* @return the amount of heat to provide.
* @see #NO_HEAT
* @see #PASSIVE_HEAT
*/
float getHeat(Level level, BlockPos pos, BlockState state);
}

View file

@ -0,0 +1,147 @@
package com.simibubi.create.api.contraption;
import com.simibubi.create.impl.contraption.BlockMovementChecksImpl;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
/**
* Provides several interfaces that can define the behavior of blocks when mounting onto contraptions:
* <ul>
* <li>{@link MovementNecessaryCheck}</li>
* <li>{@link MovementAllowedCheck}</li>
* <li>{@link BrittleCheck}</li>
* <li>{@link AttachedCheck}</li>
* <li>{@link NotSupportiveCheck}</li>
* </ul>
* See each one for details.
* <p>
* For each interface, checks can be registered and queried.
* Registration is thread-safe and can be done in parallel mod init.
* Each query will iterate all registered checks of that type in reverse-registration order. If a check returns
* a non-{@link CheckResult#PASS PASS} result, that is the result of the query. If no check catches a query, then
* a best-effort fallback is used.
*/
public class BlockMovementChecks {
public static void registerMovementNecessaryCheck(MovementNecessaryCheck check) {
BlockMovementChecksImpl.registerMovementNecessaryCheck(check);
}
public static void registerMovementAllowedCheck(MovementAllowedCheck check) {
BlockMovementChecksImpl.registerMovementAllowedCheck(check);
}
public static void registerBrittleCheck(BrittleCheck check) {
BlockMovementChecksImpl.registerBrittleCheck(check);
}
public static void registerAttachedCheck(AttachedCheck check) {
BlockMovementChecksImpl.registerAttachedCheck(check);
}
public static void registerNotSupportiveCheck(NotSupportiveCheck check) {
BlockMovementChecksImpl.registerNotSupportiveCheck(check);
}
// queries
public static boolean isMovementNecessary(BlockState state, Level world, BlockPos pos) {
return BlockMovementChecksImpl.isMovementNecessary(state, world, pos);
}
public static boolean isMovementAllowed(BlockState state, Level world, BlockPos pos) {
return BlockMovementChecksImpl.isMovementAllowed(state, world, pos);
}
public static boolean isBrittle(BlockState state) {
return BlockMovementChecksImpl.isBrittle(state);
}
public static boolean isBlockAttachedTowards(BlockState state, Level world, BlockPos pos, Direction direction) {
return BlockMovementChecksImpl.isBlockAttachedTowards(state, world, pos, direction);
}
public static boolean isNotSupportive(BlockState state, Direction facing) {
return BlockMovementChecksImpl.isNotSupportive(state, facing);
}
@FunctionalInterface
public interface MovementNecessaryCheck {
/**
* Determine if it's necessary to move the given block. Contraptions
* will generally ignore blocks that are unnecessary to move.
*/
CheckResult isMovementNecessary(BlockState state, Level world, BlockPos pos);
}
@FunctionalInterface
public interface MovementAllowedCheck {
/**
* Determine if the given block is movable. Immobile blocks will generally prevent a contraption from assembling.
* @see ContraptionMovementSetting
*/
CheckResult isMovementAllowed(BlockState state, Level world, BlockPos pos);
}
@FunctionalInterface
public interface BrittleCheck {
/**
* Brittle blocks are blocks that require another block for support, like torches or ladders.
* They're collected first to avoid them breaking when their support block is removed.
*/
CheckResult isBrittle(BlockState state);
}
@FunctionalInterface
public interface AttachedCheck {
/**
* Determine if the given block is attached to the block in the given direction.
* Attached blocks will be moved together. Examples:
* <ul>
* <li>Ladders are attached to their support block</li>
* <li>Pressure plates are attached to the floor</li>
* <li>Fluid tanks are attached to others in their multiblock</li>
* <li>Bed halves are attached to each other</li>
* </ul>
*/
CheckResult isBlockAttachedTowards(BlockState state, Level world, BlockPos pos, Direction direction);
}
@FunctionalInterface
public interface NotSupportiveCheck {
/**
* Check if the given block is non-supportive in the given direction.
* Non-supportive blocks stop block collection propagation.
* Examples:
* <ul>
* <li>Drills are not supportive for the block in front of them</li>
* <li>Carpets are not supportive for the block above them</li>
* <li>Non-extended stickers are not supportive of the block in front of them</li>
* </ul>
*/
CheckResult isNotSupportive(BlockState state, Direction direction);
}
public enum CheckResult {
SUCCESS, FAIL, PASS;
public boolean toBoolean() {
if (this == PASS) {
throw new IllegalStateException("PASS does not have a boolean value");
}
return this == SUCCESS;
}
public static CheckResult of(boolean b) {
return b ? SUCCESS : FAIL;
}
public static CheckResult of(Boolean b) {
return b == null ? PASS : (b ? SUCCESS : FAIL);
}
}
}

View file

@ -0,0 +1,78 @@
package com.simibubi.create.api.contraption;
import java.util.Collection;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import com.simibubi.create.api.registry.SimpleRegistry;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
import net.neoforged.neoforge.common.extensions.IBlockExtension;
/**
* Defines whether a block is movable by contraptions.
* This is used as a fallback check for {@link BlockMovementChecks#isMovementAllowed(BlockState, Level, BlockPos)}.
* The registry uses suppliers, so the setting of a block can change. This is useful for config options.
*/
public enum ContraptionMovementSetting {
/**
* Block is fully movable with no restrictions.
*/
MOVABLE,
/**
* Block can be mounted and moved, but if it's on a minecart contraption, the contraption cannot be picked up.
*/
NO_PICKUP,
/**
* Block cannot ever be moved by a contraption.
*/
UNMOVABLE;
public static final SimpleRegistry<Block, Supplier<ContraptionMovementSetting>> REGISTRY = SimpleRegistry.create();
/**
* Shortcut that gets the block of the given state.
*/
@Nullable
public static ContraptionMovementSetting get(BlockState state) {
return get(state.getBlock());
}
/**
* Get the current movement setting of the given block.
*/
@Nullable
public static ContraptionMovementSetting get(Block block) {
if (block instanceof MovementSettingProvider provider)
return provider.getContraptionMovementSetting();
Supplier<ContraptionMovementSetting> supplier = REGISTRY.get(block);
return supplier == null ? null : supplier.get();
}
/**
* Check if any of the blocks in the collection match the given setting.
*/
public static boolean anyAre(Collection<StructureTemplate.StructureBlockInfo> blocks, ContraptionMovementSetting setting) {
return blocks.stream().anyMatch(b -> get(b.state().getBlock()) == setting);
}
/**
* Check if any of the blocks in the collection forbid pickup.
*/
public static boolean isNoPickup(Collection<StructureTemplate.StructureBlockInfo> blocks) {
return anyAre(blocks, ContraptionMovementSetting.NO_PICKUP);
}
/**
* Interface that may optionally be implemented on a Block implementation which will be queried instead of the registry.
*/
public interface MovementSettingProvider extends IBlockExtension {
ContraptionMovementSetting getContraptionMovementSetting();
}
}

View file

@ -0,0 +1,43 @@
package com.simibubi.create.api.contraption;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import com.simibubi.create.AllContraptionTypes;
import com.simibubi.create.api.registry.CreateBuiltInRegistries;
import com.simibubi.create.content.contraptions.Contraption;
import net.minecraft.core.Holder;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
public final class ContraptionType {
public final Supplier<? extends Contraption> factory;
public final Holder.Reference<ContraptionType> holder;
public ContraptionType(Supplier<? extends Contraption> factory) {
this.factory = factory;
this.holder = CreateBuiltInRegistries.CONTRAPTION_TYPE.createIntrusiveHolder(this);
}
public boolean is(TagKey<ContraptionType> tag) {
return this.holder.is(tag);
}
/**
* Lookup the ContraptionType with the given ID, and create a new Contraption from it if present.
* If it doesn't exist, returns null.
*/
@Nullable
public static Contraption fromType(String typeId) {
ContraptionType legacy = AllContraptionTypes.BY_LEGACY_NAME.get(typeId);
if (legacy != null) {
return legacy.factory.get();
}
ResourceLocation id = ResourceLocation.tryParse(typeId);
ContraptionType type = CreateBuiltInRegistries.CONTRAPTION_TYPE.get(id);
return type == null ? null : type.factory.get();
}
}

View file

@ -1,41 +0,0 @@
package com.simibubi.create.api.contraption.storage;
import com.simibubi.create.AllRegistries.Keys;
import com.simibubi.create.api.contraption.storage.fluid.MountedFluidStorageType;
import com.simibubi.create.api.contraption.storage.item.MountedItemStorageType;
import com.simibubi.create.api.lookup.BlockLookup;
import com.simibubi.create.impl.contraption.storage.MountedStorageTypeRegistryImpl;
import com.tterrag.registrate.builders.BlockBuilder;
import com.tterrag.registrate.util.entry.RegistryEntry;
import com.tterrag.registrate.util.nullness.NonNullUnaryOperator;
import net.minecraft.world.level.block.Block;
public class MountedStorageTypeRegistry {
/**
* Lookup used for finding the item storage type associated with a block.
* @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;
/**
* Utility for use with Registrate builders. Creates a builder transformer
* 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) {
return builder -> builder.onRegisterAfter(Keys.MOUNTED_ITEM_STORAGE_TYPE, block -> ITEM_LOOKUP.register(block, type.get()));
}
/**
* Utility for use with Registrate builders. Creates a builder transformer
* 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) {
return builder -> builder.onRegisterAfter(Keys.MOUNTED_FLUID_STORAGE_TYPE, block -> FLUID_LOOKUP.register(block, type.get()));
}
}

View file

@ -4,17 +4,22 @@ import org.jetbrains.annotations.Nullable;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec; import com.mojang.serialization.MapCodec;
import com.simibubi.create.AllRegistries; import com.simibubi.create.api.registry.CreateBuiltInRegistries;
import com.simibubi.create.api.registry.CreateRegistries;
import com.simibubi.create.api.registry.SimpleRegistry;
import com.tterrag.registrate.builders.BlockBuilder;
import com.tterrag.registrate.util.entry.RegistryEntry;
import com.tterrag.registrate.util.nullness.NonNullUnaryOperator;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
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.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; 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 = Codec.lazyInitialized( public static final Codec<MountedFluidStorageType<?>> CODEC = CreateBuiltInRegistries.MOUNTED_FLUID_STORAGE_TYPE.byNameCodec();
AllRegistries.MOUNTED_FLUID_STORAGE_TYPE::byNameCodec public static final SimpleRegistry<Block, MountedFluidStorageType<?>> REGISTRY = SimpleRegistry.create();
);
public final MapCodec<? extends T> codec; public final MapCodec<? extends T> codec;
@ -24,4 +29,12 @@ public abstract class MountedFluidStorageType<T extends MountedFluidStorage> {
@Nullable @Nullable
public abstract T mount(Level level, BlockState state, BlockPos pos, @Nullable BlockEntity be); public abstract T mount(Level level, BlockState state, BlockPos pos, @Nullable BlockEntity be);
/**
* Utility for use with Registrate builders. Creates a builder transformer
* that will register the given MountedFluidStorageType to a block when ready.
*/
public static <B extends Block, P> NonNullUnaryOperator<BlockBuilder<B, P>> mountedFluidStorage(RegistryEntry<MountedFluidStorageType<?>, ? extends MountedFluidStorageType<?>> type) {
return builder -> builder.onRegisterAfter(CreateRegistries.MOUNTED_FLUID_STORAGE_TYPE, block -> REGISTRY.register(block, type.get()));
}
} }

View file

@ -1,37 +0,0 @@
package com.simibubi.create.api.contraption.storage.fluid.registrate;
import com.simibubi.create.AllRegistries;
import com.simibubi.create.api.contraption.storage.MountedStorageTypeRegistry;
import com.simibubi.create.api.contraption.storage.fluid.MountedFluidStorageType;
import com.tterrag.registrate.AbstractRegistrate;
import com.tterrag.registrate.builders.AbstractBuilder;
import com.tterrag.registrate.builders.BuilderCallback;
import com.tterrag.registrate.util.nullness.NonnullType;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.block.Block;
public class MountedFluidStorageTypeBuilder<T extends MountedFluidStorageType<?>, P> extends AbstractBuilder<MountedFluidStorageType<?>, T, P, MountedFluidStorageTypeBuilder<T, P>> {
private final T type;
public MountedFluidStorageTypeBuilder(AbstractRegistrate<?> owner, P parent, String name, BuilderCallback callback, T type) {
super(owner, parent, name, callback, AllRegistries.Keys.MOUNTED_FLUID_STORAGE_TYPE);
this.type = type;
}
public MountedFluidStorageTypeBuilder<T, P> registerTo(Block block) {
MountedStorageTypeRegistry.FLUID_LOOKUP.register(block, this.type);
return this;
}
public MountedFluidStorageTypeBuilder<T, P> registerTo(TagKey<Block> tag) {
MountedStorageTypeRegistry.FLUID_LOOKUP.registerTag(tag, this.type);
return this;
}
@Override
@NonnullType
protected T createEntry() {
return this.type;
}
}

View file

@ -8,10 +8,10 @@ import java.util.function.Predicate;
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.behaviour.movement.MovementBehaviour;
import com.simibubi.create.api.contraption.storage.item.menu.MountedStorageMenus; import com.simibubi.create.api.contraption.storage.item.menu.MountedStorageMenus;
import com.simibubi.create.content.contraptions.Contraption; import com.simibubi.create.content.contraptions.Contraption;
import com.simibubi.create.content.contraptions.MountedStorageManager; import com.simibubi.create.content.contraptions.MountedStorageManager;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.simibubi.create.foundation.utility.CreateLang; import com.simibubi.create.foundation.utility.CreateLang;

View file

@ -4,17 +4,28 @@ import org.jetbrains.annotations.Nullable;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec; import com.mojang.serialization.MapCodec;
import com.simibubi.create.AllRegistries; import com.simibubi.create.api.registry.CreateBuiltInRegistries;
import com.simibubi.create.api.registry.CreateRegistries;
import com.simibubi.create.api.registry.SimpleRegistry;
import com.simibubi.create.impl.contraption.storage.MountedItemStorageFallbackProvider;
import com.tterrag.registrate.builders.BlockBuilder;
import com.tterrag.registrate.util.entry.RegistryEntry;
import com.tterrag.registrate.util.nullness.NonNullUnaryOperator;
import net.minecraft.Util;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
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.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; 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 = Codec.lazyInitialized( public static final Codec<MountedItemStorageType<?>> CODEC = CreateBuiltInRegistries.MOUNTED_ITEM_STORAGE_TYPE.byNameCodec();
AllRegistries.MOUNTED_ITEM_STORAGE_TYPE::byNameCodec public static final SimpleRegistry<Block, MountedItemStorageType<?>> REGISTRY = Util.make(() -> {
); SimpleRegistry<Block, MountedItemStorageType<?>> registry = SimpleRegistry.create();
registry.registerProvider(MountedItemStorageFallbackProvider.INSTANCE);
return registry;
});
public final MapCodec<? extends T> codec; public final MapCodec<? extends T> codec;
@ -24,4 +35,12 @@ public abstract class MountedItemStorageType<T extends MountedItemStorage> {
@Nullable @Nullable
public abstract T mount(Level level, BlockState state, BlockPos pos, @Nullable BlockEntity be); public abstract T mount(Level level, BlockState state, BlockPos pos, @Nullable BlockEntity be);
/**
* Utility for use with Registrate builders. Creates a builder transformer
* that will register the given MountedItemStorageType to a block when ready.
*/
public static <B extends Block, P> NonNullUnaryOperator<BlockBuilder<B, P>> mountedItemStorage(RegistryEntry<MountedItemStorageType<?>, ? extends MountedItemStorageType<?>> type) {
return builder -> builder.onRegisterAfter(CreateRegistries.MOUNTED_ITEM_STORAGE_TYPE, block -> REGISTRY.register(block, type.get()));
}
} }

View file

@ -1,37 +0,0 @@
package com.simibubi.create.api.contraption.storage.item.registrate;
import com.simibubi.create.AllRegistries;
import com.simibubi.create.api.contraption.storage.MountedStorageTypeRegistry;
import com.simibubi.create.api.contraption.storage.item.MountedItemStorageType;
import com.tterrag.registrate.AbstractRegistrate;
import com.tterrag.registrate.builders.AbstractBuilder;
import com.tterrag.registrate.builders.BuilderCallback;
import com.tterrag.registrate.util.nullness.NonnullType;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.block.Block;
public class MountedItemStorageTypeBuilder<T extends MountedItemStorageType<?>, P> extends AbstractBuilder<MountedItemStorageType<?>, T, P, MountedItemStorageTypeBuilder<T, P>> {
private final T type;
public MountedItemStorageTypeBuilder(AbstractRegistrate<?> owner, P parent, String name, BuilderCallback callback, T type) {
super(owner, parent, name, callback, AllRegistries.Keys.MOUNTED_ITEM_STORAGE_TYPE);
this.type = type;
}
public MountedItemStorageTypeBuilder<T, P> registerTo(Block block) {
MountedStorageTypeRegistry.ITEM_LOOKUP.register(block, this.type);
return this;
}
public MountedItemStorageTypeBuilder<T, P> registerTo(TagKey<Block> tag) {
MountedStorageTypeRegistry.ITEM_LOOKUP.registerTag(tag, this.type);
return this;
}
@Override
@NonnullType
protected T createEntry() {
return this.type;
}
}

View file

@ -0,0 +1,71 @@
package com.simibubi.create.api.contraption.train;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.api.registry.SimpleRegistry;
import com.simibubi.create.content.trains.track.AllPortalTracks;
import net.createmod.catnip.math.BlockFace;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Portal;
import net.minecraft.world.level.block.state.BlockState;
/**
* A provider for portal track connections.
* Takes a track inbound through a portal and finds the exit location for the outbound track.
*/
@FunctionalInterface
public interface PortalTrackProvider {
SimpleRegistry<Block, PortalTrackProvider> REGISTRY = SimpleRegistry.create();
/**
* Find the exit location for a track going through a portal.
* @param level the level of the inbound track
* @param face the face of the inbound track
*/
Exit findExit(ServerLevel level, BlockFace face);
/**
* Checks if a given {@link BlockState} represents a supported portal block.
* @param state The block state to check.
* @return {@code true} if the block state represents a supported portal; {@code false} otherwise.
*/
static boolean isSupportedPortal(BlockState state) {
return REGISTRY.get(state) != null;
}
/**
* Retrieves the corresponding outbound track on the other side of a portal.
* @param level The current {@link ServerLevel}.
* @param inboundTrack The inbound track {@link BlockFace}.
* @return the found outbound track, or null if one wasn't found.
*/
@Nullable
static Exit getOtherSide(ServerLevel level, BlockFace inboundTrack) {
BlockPos portalPos = inboundTrack.getConnectedPos();
BlockState portalState = level.getBlockState(portalPos);
PortalTrackProvider provider = REGISTRY.get(portalState);
return provider == null ? null : provider.findExit(level, inboundTrack);
}
/**
* Find an exit location by using an {@link Portal} instance.
* @param level The level of the inbound track
* @param face The face of the inbound track
* @param firstDimension The first dimension (typically the Overworld)
* @param secondDimension The second dimension (e.g., Nether, Aether)
* @param portal The portal
* @return A found exit, or null if one wasn't found
*/
static Exit fromPortal(ServerLevel level, BlockFace face, ResourceKey<Level> firstDimension,
ResourceKey<Level> secondDimension, Portal portal) {
return AllPortalTracks.fromPortal(level, face, firstDimension, secondDimension, portal);
}
record Exit(ServerLevel level, BlockFace face) {
}
}

View file

@ -1,34 +0,0 @@
package com.simibubi.create.api.contraption.train;
import java.util.function.Consumer;
import java.util.function.Predicate;
import com.simibubi.create.AllInteractionBehaviours;
import com.simibubi.create.content.processing.burner.BlockBasedTrainConductorInteractionBehaviour;
import com.simibubi.create.impl.contraption.train.TrainConductorHandlerImpl;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.state.BlockState;
/**
* All required methods to make your block a train conductor similar to the blaze burner
*/
public interface TrainConductorHandler {
boolean isValidConductor(BlockState state);
private static void registerHandler(TrainConductorHandler handler) {
TrainConductorHandlerImpl.CONDUCTOR_HANDLERS.add(handler);
}
static void registerConductor(ResourceLocation blockRl, Predicate<BlockState> isValidConductor, UpdateScheduleCallback updateScheduleCallback) {
AllInteractionBehaviours.registerBehaviour(blockRl, new BlockBasedTrainConductorInteractionBehaviour(isValidConductor, updateScheduleCallback));
registerHandler(isValidConductor::test);
}
interface UpdateScheduleCallback {
UpdateScheduleCallback EMPTY = (hasSchedule, blockState, blockStateSetter) -> {};
void update(boolean hasSchedule, BlockState currentBlockState, Consumer<BlockState> blockStateSetter);
}
}

View file

@ -1,34 +0,0 @@
package com.simibubi.create.api.contraption.transformable;
import com.simibubi.create.impl.contraption.transformable.ContraptionTransformableRegistryImpl;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntityType;
/**
* 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);
}
}

View file

@ -0,0 +1,28 @@
package com.simibubi.create.api.contraption.transformable;
import com.simibubi.create.api.registry.SimpleRegistry;
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 TransformableBlock} and {@link TransformableBlockEntity} interfaces.
*/
public class MovedBlockTransformerRegistries {
public static final SimpleRegistry<Block, BlockTransformer> BLOCK_TRANSFORMERS = SimpleRegistry.create();
public static final SimpleRegistry<BlockEntityType<?>, BlockEntityTransformer> BLOCK_ENTITY_TRANSFORMERS = SimpleRegistry.create();
@FunctionalInterface
public interface BlockTransformer {
BlockState transform(BlockState state, StructureTransform transform);
}
@FunctionalInterface
public interface BlockEntityTransformer {
void transform(BlockEntity be, StructureTransform transform);
}
}

View file

@ -0,0 +1,28 @@
package com.simibubi.create.api.effect;
import com.simibubi.create.api.registry.SimpleRegistry;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.phys.AABB;
import net.neoforged.neoforge.fluids.FluidStack;
/**
* Interface for custom behavior for fluids spilling out of open pipes. Examples:
* <ul>
* <li>Potions: applying potion effects</li>
* <li>Milk: clearing effects</li>
* <li>Water: extinguishing fire</li>
* </ul>
*/
@FunctionalInterface
public interface OpenPipeEffectHandler {
SimpleRegistry<Fluid, OpenPipeEffectHandler> REGISTRY = SimpleRegistry.create();
/**
* @param area the area to apply effects in
* @param fluid the fluid in the pipe. Do not modify, it will do nothing
*/
void apply(Level level, AABB area, FluidStack fluid);
}

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,95 @@
package com.simibubi.create.api.registry;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import org.jetbrains.annotations.ApiStatus;
import com.mojang.serialization.Lifecycle;
import com.simibubi.create.api.behaviour.display.DisplaySource;
import com.simibubi.create.api.behaviour.display.DisplayTarget;
import com.simibubi.create.api.contraption.ContraptionType;
import com.simibubi.create.api.contraption.storage.fluid.MountedFluidStorageType;
import com.simibubi.create.api.contraption.storage.item.MountedItemStorageType;
import com.simibubi.create.content.kinetics.fan.processing.FanProcessingType;
import com.simibubi.create.content.kinetics.mechanicalArm.ArmInteractionPointType;
import com.simibubi.create.content.logistics.item.filter.attribute.ItemAttributeType;
import com.simibubi.create.content.logistics.packagePort.PackagePortTargetType;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.RegistrationInfo;
import net.minecraft.core.Registry;
import net.minecraft.core.WritableRegistry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceKey;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.fml.common.EventBusSubscriber.Bus;
import net.neoforged.neoforge.registries.NewRegistryEvent;
/**
* Static registries added by Create.
*
* @see CreateRegistries
*/
@EventBusSubscriber(bus = Bus.MOD)
public class CreateBuiltInRegistries {
private static final WritableRegistry<WritableRegistry<?>> ROOT_REGISTRY = getRootRegistry();
public static final Set<Registry<?>> REGISTRIES = new HashSet<>();
public static final Registry<ArmInteractionPointType> ARM_INTERACTION_POINT_TYPE = simple(CreateRegistries.ARM_INTERACTION_POINT_TYPE);
public static final Registry<FanProcessingType> FAN_PROCESSING_TYPE = simple(CreateRegistries.FAN_PROCESSING_TYPE);
public static final Registry<ItemAttributeType> ITEM_ATTRIBUTE_TYPE = simple(CreateRegistries.ITEM_ATTRIBUTE_TYPE);
public static final Registry<DisplaySource> DISPLAY_SOURCE = simple(CreateRegistries.DISPLAY_SOURCE);
public static final Registry<DisplayTarget> DISPLAY_TARGET = simple(CreateRegistries.DISPLAY_TARGET);
public static final Registry<MountedItemStorageType<?>> MOUNTED_ITEM_STORAGE_TYPE = simple(CreateRegistries.MOUNTED_ITEM_STORAGE_TYPE);
public static final Registry<MountedFluidStorageType<?>> MOUNTED_FLUID_STORAGE_TYPE = simple(CreateRegistries.MOUNTED_FLUID_STORAGE_TYPE);
public static final Registry<ContraptionType> CONTRAPTION_TYPE = withIntrusiveHolders(CreateRegistries.CONTRAPTION_TYPE);
public static final Registry<PackagePortTargetType> PACKAGE_PORT_TARGET_TYPE = simple(CreateRegistries.PACKAGE_PORT_TARGET_TYPE);
private static <T> Registry<T> simple(ResourceKey<Registry<T>> key) {
return register(key, new MappedRegistry<>(key, Lifecycle.stable(), false));
}
private static <T> Registry<T> withIntrusiveHolders(ResourceKey<Registry<T>> key) {
return register(key, new MappedRegistry<>(key, Lifecycle.stable(), true));
}
@SuppressWarnings("unchecked")
private static <T> Registry<T> register(ResourceKey<Registry<T>> key, WritableRegistry<T> registry) {
ROOT_REGISTRY.register(
(ResourceKey<WritableRegistry<?>>) (Object) key, registry, new RegistrationInfo(Optional.empty(), Lifecycle.stable())
);
REGISTRIES.add(registry);
return registry;
}
@SuppressWarnings("unchecked")
private static WritableRegistry<WritableRegistry<?>> getRootRegistry() {
// an accessor can't be used here because BuiltInRegistries is loaded too early during datagen.
try {
Field field = BuiltInRegistries.class.getDeclaredField("WRITABLE_REGISTRY");
field.setAccessible(true);
return (WritableRegistry<WritableRegistry<?>>) field.get(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException("Create: Failed to get root registry", e);
}
}
// TODO Remove
@ApiStatus.Internal
public static void init() {
// make sure the class is loaded.
// this method is called at the tail of BuiltInRegistries, injected by a coremod. See it for details.
}
@SubscribeEvent
public static void onNewRegistryEvent(NewRegistryEvent event) {
for (Registry<?> registry : REGISTRIES)
event.register(registry);
}
}

View file

@ -0,0 +1,35 @@
package com.simibubi.create.api.registry;
import com.simibubi.create.Create;
import com.simibubi.create.api.behaviour.display.DisplaySource;
import com.simibubi.create.api.behaviour.display.DisplayTarget;
import com.simibubi.create.api.contraption.ContraptionType;
import com.simibubi.create.api.contraption.storage.fluid.MountedFluidStorageType;
import com.simibubi.create.api.contraption.storage.item.MountedItemStorageType;
import com.simibubi.create.content.kinetics.fan.processing.FanProcessingType;
import com.simibubi.create.content.kinetics.mechanicalArm.ArmInteractionPointType;
import com.simibubi.create.content.logistics.item.filter.attribute.ItemAttributeType;
import com.simibubi.create.content.logistics.packagePort.PackagePortTargetType;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
/**
* Keys for registries added by Create.
* @see CreateBuiltInRegistries
*/
public class CreateRegistries {
public static final ResourceKey<Registry<ArmInteractionPointType>> ARM_INTERACTION_POINT_TYPE = key("arm_interaction_point_type");
public static final ResourceKey<Registry<FanProcessingType>> FAN_PROCESSING_TYPE = key("fan_processing_type");
public static final ResourceKey<Registry<ItemAttributeType>> ITEM_ATTRIBUTE_TYPE = key("item_attribute_type");
public static final ResourceKey<Registry<DisplaySource>> DISPLAY_SOURCE = key("display_source");
public static final ResourceKey<Registry<DisplayTarget>> DISPLAY_TARGET = key("display_target");
public static final ResourceKey<Registry<MountedItemStorageType<?>>> MOUNTED_ITEM_STORAGE_TYPE = key("mounted_item_storage_type");
public static final ResourceKey<Registry<MountedFluidStorageType<?>>> MOUNTED_FLUID_STORAGE_TYPE = key("mounted_fluid_storage_type");
public static final ResourceKey<Registry<ContraptionType>> CONTRAPTION_TYPE = key("contraption_type");
public static final ResourceKey<Registry<PackagePortTargetType>> PACKAGE_PORT_TARGET_TYPE = key("package_port_target_type");
private static <T> ResourceKey<Registry<T>> key(String name) {
return ResourceKey.createRegistryKey(Create.asResource(name));
}
}

View file

@ -0,0 +1,167 @@
package com.simibubi.create.api.registry;
import java.util.List;
import java.util.function.Function;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.impl.registry.SimpleRegistryImpl;
import com.simibubi.create.impl.registry.TagProviderImpl;
import net.minecraft.core.Holder;
import net.minecraft.tags.TagKey;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.StateHolder;
import net.minecraft.world.level.material.Fluid;
/**
* A simple registry mapping between objects with identity semantics.
* Provides simple registration functionality, as well as lazy providers.
* This class is thread-safe, and may be safely used during parallel mod init.
*/
@ApiStatus.NonExtendable
public interface SimpleRegistry<K, V> {
/**
* Register an association between a key and a value.
* Direct registrations here always take priority over providers.
* @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 all providers, so they get re-computed on the next query.
* This should be called by providers when something changes that would affect their results, such as
* a resource reload in the case of providers based on tags.
*/
void invalidate();
/**
* Query the value associated with the given object. May be null if no association is present.
*/
@Nullable
V get(K object);
/**
* Shortcut for {@link #get(Object)} that accepts a StateHolder, such as BlockState or FluidState.
*/
@Nullable
V get(StateHolder<K, ?> state);
static <K, V> SimpleRegistry<K, V> create() {
return SimpleRegistryImpl.single();
}
/**
* 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 (newest first).
* <p>
* The values returned by providers are cached so that repeated queries always return the same value.
* To invalidate the cache of a registry, call {@link SimpleRegistry#invalidate()}.
*/
@FunctionalInterface
interface Provider<K, V> {
@Nullable
V get(K object);
/**
* Called by the SimpleRegistry 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(Runnable invalidate) {
}
// factory methods for common Providers
/**
* 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 BlockEntityType.
*/
static <V> Provider<BlockEntityType<?>, V> forBlockEntityTag(TagKey<BlockEntityType<?>> tag, V value) {
return new TagProviderImpl<>(tag, TagProviderImpl::getBeHolder, 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);
}
/**
* Shortcut for {@link #forTag} when the registry's type is EntityType.
*/
@SuppressWarnings("deprecation")
static <V> Provider<EntityType<?>, V> forEntityTag(TagKey<EntityType<?>> tag, V value) {
return new TagProviderImpl<>(tag, EntityType::builtInRegistryHolder, value);
}
/**
* Shortcut for {@link #forTag} when the registry's type is Fluid.
*/
@SuppressWarnings("deprecation")
static <V> Provider<Fluid, V> forFluidTag(TagKey<Fluid> tag, V value) {
return new TagProviderImpl<>(tag, Fluid::builtInRegistryHolder, value);
}
}
/**
* An extension of SimpleRegistry that handles multiple registrations per object.
* {@link #register(Object, Object)} Will set a whole list of registrations - use {@link #add(Object, Object)} to add one.
* Here, all Providers are always queried, and all of their results are returned. Their provided values are also
* provided on top of explicit registrations - they do not take priority.
*/
interface Multi<K, V> extends SimpleRegistry<K, List<V>> {
void add(K object, V value);
/**
* Shortcut that wraps a single-value provider into one that provides a List.
*/
void addProvider(Provider<K, V> provider);
/**
* Never returns null, will return an empty list if no registrations are present
*/
@Override
@NotNull
List<V> get(K object);
/**
* Never returns null, will return an empty list if no registrations are present
*/
@Override
@NotNull
List<V> get(StateHolder<K, ?> state);
static <K, V> Multi<K, V> create() {
return SimpleRegistryImpl.multi();
}
}
}

View file

@ -0,0 +1,161 @@
package com.simibubi.create.api.registry.registrate;
import java.util.function.BiConsumer;
import java.util.function.Function;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.api.registry.SimpleRegistry;
import com.simibubi.create.api.registry.SimpleRegistry.Provider;
import com.simibubi.create.impl.registry.TagProviderImpl;
import com.tterrag.registrate.AbstractRegistrate;
import com.tterrag.registrate.builders.AbstractBuilder;
import com.tterrag.registrate.builders.BuilderCallback;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.tags.TagKey;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.material.Fluid;
public class SimpleBuilder<R, T extends R, P> extends AbstractBuilder<R, T, P, SimpleBuilder<R, T, P>> {
private final T value;
private SimpleRegistryAccess<Block, R> byBlock;
private SimpleRegistryAccess<BlockEntityType<?>, R> byBlockEntity;
private SimpleRegistryAccess<EntityType<?>, R> byEntity;
private SimpleRegistryAccess<Fluid, R> byFluid;
public SimpleBuilder(AbstractRegistrate<?> owner, P parent, String name, BuilderCallback callback, ResourceKey<Registry<R>> registryKey, T value) {
super(owner, parent, name, callback, registryKey);
this.value = value;
}
@Override
protected T createEntry() {
return this.value;
}
// for setup
@SuppressWarnings("deprecation")
public SimpleBuilder<R, T, P> byBlock(SimpleRegistry<Block, R> registry) {
this.byBlock = SimpleRegistryAccess.of(registry, Block::builtInRegistryHolder);
return this;
}
@SuppressWarnings("deprecation")
public SimpleBuilder<R, T, P> byBlock(SimpleRegistry.Multi<Block, R> registry) {
this.byBlock = SimpleRegistryAccess.of(registry, Block::builtInRegistryHolder);
return this;
}
public SimpleBuilder<R, T, P> byBlockEntity(SimpleRegistry<BlockEntityType<?>, R> registry) {
this.byBlockEntity = SimpleRegistryAccess.of(registry, TagProviderImpl::getBeHolder);
return this;
}
public SimpleBuilder<R, T, P> byBlockEntity(SimpleRegistry.Multi<BlockEntityType<?>, R> registry) {
this.byBlockEntity = SimpleRegistryAccess.of(registry, TagProviderImpl::getBeHolder);
return this;
}
@SuppressWarnings("deprecation")
public SimpleBuilder<R, T, P> byEntity(SimpleRegistry<EntityType<?>, R> registry) {
this.byEntity = SimpleRegistryAccess.of(registry, EntityType::builtInRegistryHolder);
return this;
}
@SuppressWarnings("deprecation")
public SimpleBuilder<R, T, P> byEntity(SimpleRegistry.Multi<EntityType<?>, R> registry) {
this.byEntity = SimpleRegistryAccess.of(registry, EntityType::builtInRegistryHolder);
return this;
}
@SuppressWarnings("deprecation")
public SimpleBuilder<R, T, P> byFluid(SimpleRegistry<Fluid, R> registry) {
this.byFluid = SimpleRegistryAccess.of(registry, Fluid::builtInRegistryHolder);
return this;
}
@SuppressWarnings("deprecation")
public SimpleBuilder<R, T, P> byFluid(SimpleRegistry.Multi<Fluid, R> registry) {
this.byFluid = SimpleRegistryAccess.of(registry, Fluid::builtInRegistryHolder);
return this;
}
// association methods
public SimpleBuilder<R, T, P> associate(Block block) {
assertPresent(this.byBlock, "Block");
this.byBlock.adder.accept(block, this.value);
return this;
}
public SimpleBuilder<R, T, P> associateBlockTag(TagKey<Block> tag) {
assertPresent(this.byBlock, "Block");
this.byBlock.tagAdder.accept(tag, this.value);
return this;
}
public SimpleBuilder<R, T, P> associate(BlockEntityType<?> type) {
assertPresent(this.byBlockEntity, "BlockEntityType");
this.byBlockEntity.adder.accept(type, this.value);
return this;
}
public SimpleBuilder<R, T, P> associateBeTag(TagKey<BlockEntityType<?>> tag) {
assertPresent(this.byBlockEntity, "BlockEntityType");
this.byBlockEntity.tagAdder.accept(tag, this.value);
return this;
}
public SimpleBuilder<R, T, P> associate(EntityType<?> type) {
assertPresent(this.byEntity, "EntityType");
this.byEntity.adder.accept(type, this.value);
return this;
}
public SimpleBuilder<R, T, P> associateEntityTag(TagKey<EntityType<?>> tag) {
assertPresent(this.byEntity, "EntityType");
this.byEntity.tagAdder.accept(tag, this.value);
return this;
}
public SimpleBuilder<R, T, P> associate(Fluid fluid) {
assertPresent(this.byFluid, "Fluid");
this.byFluid.adder.accept(fluid, this.value);
return this;
}
public SimpleBuilder<R, T, P> associateFluidTag(TagKey<Fluid> tag) {
assertPresent(this.byFluid, "Fluid");
this.byFluid.tagAdder.accept(tag, this.value);
return this;
}
private static void assertPresent(@Nullable Object object, String type) {
if (object == null) {
throw new IllegalStateException("This type does not support " + type + " associations");
}
}
protected record SimpleRegistryAccess<K, V>(BiConsumer<K, V> adder, BiConsumer<TagKey<K>, V> tagAdder) {
public static <K, V> SimpleRegistryAccess<K, V> of(SimpleRegistry<K, V> registry, Function<K, Holder<K>> holderGetter) {
return new SimpleRegistryAccess<>(
registry::register,
(tag, value) -> registry.registerProvider(Provider.forTag(tag, holderGetter, value))
);
}
public static <K, V> SimpleRegistryAccess<K, V> of(SimpleRegistry.Multi<K, V> registry, Function<K, Holder<K>> holderGetter) {
return new SimpleRegistryAccess<>(
registry::add,
(tag, value) -> registry.addProvider(Provider.forTag(tag, holderGetter, value))
);
}
}
}

View file

@ -0,0 +1,28 @@
package com.simibubi.create.api.schematic.nbt;
import com.simibubi.create.api.registry.SimpleRegistry;
import net.minecraft.core.HolderLookup;
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 PartialSafeNBT}.
*/
public class SafeNbtWriterRegistry {
public static final SimpleRegistry<BlockEntityType<?>, SafeNbtWriter> REGISTRY = SimpleRegistry.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, HolderLookup.Provider registries);
}
}

View file

@ -1,38 +0,0 @@
package com.simibubi.create.api.schematic.nbt;
import com.simibubi.create.impl.schematic.nbt.SchematicSafeNBTRegistryImpl;
import net.minecraft.core.HolderLookup;
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, HolderLookup.Provider)} 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, HolderLookup.Provider registries);
}
}

View file

@ -0,0 +1,45 @@
package com.simibubi.create.api.schematic.requirement;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.api.registry.SimpleRegistry;
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 SpecialBlockItemRequirement}</li>
* <li>{@link SpecialBlockEntityItemRequirement}</li>
* <li>{@link SpecialEntityItemRequirement}</li>
* </ul>
*/
public class SchematicRequirementRegistries {
public static final SimpleRegistry<Block, BlockRequirement> BLOCKS = SimpleRegistry.create();
public static final SimpleRegistry<BlockEntityType<?>, BlockEntityRequirement> BLOCK_ENTITIES = SimpleRegistry.create();
public static final SimpleRegistry<EntityType<?>, EntityRequirement> ENTITIES = SimpleRegistry.create();
@FunctionalInterface
public interface BlockRequirement {
ItemRequirement getRequiredItems(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,117 +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 ContextProvidingBlockRequirement} for
* @param requirement The requirement you would like to add to this block,
* the {@link ContextProvidingBlockRequirement#getRequiredItems(BlockState, BlockEntity)}
* method will be called on the {@link ContextProvidingBlockRequirement} you have provided,
* and you will be able to insert requirements based off the context that is given
*/
public static void registerForBlock(Block block, ContextProvidingBlockRequirement 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 ContextProvidingBlockRequirement} for
* @param requirement The requirement you would like to add to this block,
* the {@link ContextProvidingBlockRequirement#getRequiredItems(BlockState, BlockEntity)}
* method will be called on the {@link ContextProvidingBlockRequirement} you have provided,
* and you will be able to insert requirements based off the context that is given
*/
public static void registerForBlock(ResourceLocation block, ContextProvidingBlockRequirement 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 ContextProvidingBlockEntityRequirement} for
* @param requirement The requirement you would like to add to this block entity type,
* the {@link ContextProvidingBlockEntityRequirement#getRequiredItems(BlockEntity)}
* method will be called on the
* {@link ContextProvidingBlockEntityRequirement} 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, ContextProvidingBlockEntityRequirement 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 ContextProvidingBlockEntityRequirement} for
* @param requirement The requirement you would like to add to this block entity type,
* the {@link ContextProvidingBlockEntityRequirement#getRequiredItems(BlockEntity)}
* method will be called on the
* {@link ContextProvidingBlockEntityRequirement} you have provided,
* and you will be able to insert requirements based off the context that is given
*/
public static void registerForBlockEntity(ResourceLocation blockEntityType, ContextProvidingBlockEntityRequirement 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 ContextProvidingEntityRequirement} for
* @param requirement The requirement you would like to add to this entity type,
* the {@link ContextProvidingEntityRequirement#getRequiredItems(Entity)}
* method will be called on the {@link ContextProvidingEntityRequirement} 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, ContextProvidingEntityRequirement 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 ContextProvidingEntityRequirement} for
* @param requirement The requirement you would like to add to this entity type,
* the {@link ContextProvidingEntityRequirement#getRequiredItems(Entity)}
* method will be called on the {@link ContextProvidingEntityRequirement} you have provided,
* and you will be able to insert requirements based off the context that is given
*/
public static void registerForEntity(ResourceLocation entityType, ContextProvidingEntityRequirement requirement) {
SchematicRequirementsRegistryImpl.registerForEntity(entityType, requirement);
}
// --- Interfaces that provide the context that would be accessible if you implemented the ISpecial* interfaces ---
@FunctionalInterface
public interface ContextProvidingBlockRequirement {
ItemRequirement getRequiredItems(BlockState state, @Nullable BlockEntity blockEntity);
}
@FunctionalInterface
public interface ContextProvidingBlockEntityRequirement {
ItemRequirement getRequiredItems(BlockEntity blockEntity);
}
@FunctionalInterface
public interface ContextProvidingEntityRequirement {
ItemRequirement getRequiredItems(Entity entity);
}
}

View file

@ -1,32 +1,25 @@
package com.simibubi.create.compat.tconstruct; package com.simibubi.create.compat.tconstruct;
import com.simibubi.create.api.behaviour.BlockSpoutingBehaviour; import com.simibubi.create.api.behaviour.spouting.BlockSpoutingBehaviour;
import com.simibubi.create.compat.Mods;
import com.simibubi.create.content.fluids.spout.SpoutBlockEntity; import com.simibubi.create.content.fluids.spout.SpoutBlockEntity;
import com.simibubi.create.foundation.fluid.FluidHelper; import com.simibubi.create.foundation.fluid.FluidHelper;
import com.simibubi.create.infrastructure.config.AllConfigs; import com.simibubi.create.infrastructure.config.AllConfigs;
import net.createmod.catnip.registry.RegisteredObjectsHelper;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.neoforged.neoforge.capabilities.Capabilities; import net.neoforged.neoforge.capabilities.Capabilities;
import net.neoforged.neoforge.fluids.FluidStack; import net.neoforged.neoforge.fluids.FluidStack;
import net.neoforged.neoforge.fluids.capability.IFluidHandler; import net.neoforged.neoforge.fluids.capability.IFluidHandler;
import net.neoforged.neoforge.fluids.capability.IFluidHandler.FluidAction; import net.neoforged.neoforge.fluids.capability.IFluidHandler.FluidAction;
public class SpoutCasting extends BlockSpoutingBehaviour { public enum SpoutCasting implements BlockSpoutingBehaviour {
INSTANCE;
private static final boolean TICON_PRESENT = Mods.TCONSTRUCT.isLoaded();
ResourceLocation TABLE = ResourceLocation.fromNamespaceAndPath("tconstruct", "table");
ResourceLocation BASIN = ResourceLocation.fromNamespaceAndPath("tconstruct", "basin");
@Override @Override
public int fillBlock(Level level, BlockPos pos, SpoutBlockEntity spout, FluidStack availableFluid, public int fillBlock(Level level, BlockPos pos, SpoutBlockEntity spout, FluidStack availableFluid, boolean simulate) {
boolean simulate) {
if (!enabled()) if (!enabled())
return 0; return 0;
@ -40,9 +33,6 @@ public class SpoutCasting extends BlockSpoutingBehaviour {
if (handler.getTanks() != 1) if (handler.getTanks() != 1)
return 0; return 0;
ResourceLocation registryName = RegisteredObjectsHelper.getKeyOrThrow(blockEntity.getType());
if (!registryName.equals(TABLE) && !registryName.equals(BASIN))
return 0;
if (!handler.isFluidValid(0, availableFluid)) if (!handler.isFluidValid(0, availableFluid))
return 0; return 0;
@ -61,9 +51,6 @@ public class SpoutCasting extends BlockSpoutingBehaviour {
} }
private boolean enabled() { private boolean enabled() {
if (!TICON_PRESENT)
return false;
return AllConfigs.server().recipes.allowCastingBySpout.get(); return AllConfigs.server().recipes.allowCastingBySpout.get();
} }
} }

View file

@ -16,13 +16,12 @@ import org.jetbrains.annotations.NotNull;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.AllMovementBehaviours;
import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import com.simibubi.create.content.contraptions.actors.psi.PortableStorageInterfaceMovement; import com.simibubi.create.content.contraptions.actors.psi.PortableStorageInterfaceMovement;
import com.simibubi.create.content.contraptions.actors.seat.SeatBlock; import com.simibubi.create.content.contraptions.actors.seat.SeatBlock;
import com.simibubi.create.content.contraptions.actors.seat.SeatEntity; import com.simibubi.create.content.contraptions.actors.seat.SeatEntity;
import com.simibubi.create.content.contraptions.actors.trainControls.ControlsStopControllingPacket; import com.simibubi.create.content.contraptions.actors.trainControls.ControlsStopControllingPacket;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.simibubi.create.content.contraptions.data.ContraptionSyncLimiting; import com.simibubi.create.content.contraptions.data.ContraptionSyncLimiting;
import com.simibubi.create.content.contraptions.elevator.ElevatorContraption; import com.simibubi.create.content.contraptions.elevator.ElevatorContraption;
@ -444,7 +443,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
for (MutablePair<StructureBlockInfo, MovementContext> pair : contraption.getActors()) { for (MutablePair<StructureBlockInfo, MovementContext> pair : contraption.getActors()) {
MovementContext context = pair.right; MovementContext context = pair.right;
StructureBlockInfo blockInfo = pair.left; StructureBlockInfo blockInfo = pair.left;
MovementBehaviour actor = AllMovementBehaviours.getBehaviour(blockInfo.state()); MovementBehaviour actor = MovementBehaviour.REGISTRY.get(blockInfo.state());
if (actor == null) if (actor == null)
continue; continue;
@ -507,7 +506,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
for (MutablePair<StructureBlockInfo, MovementContext> pair : contraption.getActors()) { for (MutablePair<StructureBlockInfo, MovementContext> pair : contraption.getActors()) {
MovementContext context = pair.right; MovementContext context = pair.right;
StructureBlockInfo blockInfo = pair.left; StructureBlockInfo blockInfo = pair.left;
MovementBehaviour actor = AllMovementBehaviours.getBehaviour(blockInfo.state()); MovementBehaviour actor = MovementBehaviour.REGISTRY.get(blockInfo.state());
if (actor instanceof PortableStorageInterfaceMovement && isActorActive(context, actor)) if (actor instanceof PortableStorageInterfaceMovement && isActorActive(context, actor))
if (context.position != null) if (context.position != null)
actor.visitNewPosition(context, BlockPos.containing(context.position)); actor.visitNewPosition(context, BlockPos.containing(context.position));

View file

@ -29,8 +29,11 @@ import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlockEntityTypes;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllInteractionBehaviours; import com.simibubi.create.AllTags.AllContraptionTypeTags;
import com.simibubi.create.AllMovementBehaviours; import com.simibubi.create.api.behaviour.interaction.MovingInteractionBehaviour;
import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import com.simibubi.create.api.contraption.BlockMovementChecks;
import com.simibubi.create.api.contraption.ContraptionType;
import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovement; import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovement;
import com.simibubi.create.content.contraptions.actors.harvester.HarvesterMovementBehaviour; import com.simibubi.create.content.contraptions.actors.harvester.HarvesterMovementBehaviour;
import com.simibubi.create.content.contraptions.actors.seat.SeatBlock; import com.simibubi.create.content.contraptions.actors.seat.SeatBlock;
@ -40,9 +43,7 @@ import com.simibubi.create.content.contraptions.bearing.MechanicalBearingBlock;
import com.simibubi.create.content.contraptions.bearing.StabilizedContraption; import com.simibubi.create.content.contraptions.bearing.StabilizedContraption;
import com.simibubi.create.content.contraptions.bearing.WindmillBearingBlock; import com.simibubi.create.content.contraptions.bearing.WindmillBearingBlock;
import com.simibubi.create.content.contraptions.bearing.WindmillBearingBlockEntity; import com.simibubi.create.content.contraptions.bearing.WindmillBearingBlockEntity;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.simibubi.create.content.contraptions.behaviour.MovingInteractionBehaviour;
import com.simibubi.create.content.contraptions.chassis.AbstractChassisBlock; import com.simibubi.create.content.contraptions.chassis.AbstractChassisBlock;
import com.simibubi.create.content.contraptions.chassis.ChassisBlockEntity; import com.simibubi.create.content.contraptions.chassis.ChassisBlockEntity;
import com.simibubi.create.content.contraptions.chassis.StickerBlock; import com.simibubi.create.content.contraptions.chassis.StickerBlock;
@ -92,6 +93,7 @@ import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.NbtUtils;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.network.protocol.game.DebugPackets; import net.minecraft.network.protocol.game.DebugPackets;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.ai.village.poi.PoiTypes; import net.minecraft.world.entity.ai.village.poi.PoiTypes;
@ -617,7 +619,7 @@ public abstract class Contraption {
blockstate = blockstate.setValue(RedstoneContactBlock.POWERED, true); blockstate = blockstate.setValue(RedstoneContactBlock.POWERED, true);
if (AllBlocks.POWERED_SHAFT.has(blockstate)) if (AllBlocks.POWERED_SHAFT.has(blockstate))
blockstate = BlockHelper.copyProperties(blockstate, AllBlocks.SHAFT.getDefaultState()); blockstate = BlockHelper.copyProperties(blockstate, AllBlocks.SHAFT.getDefaultState());
if (blockstate.getBlock() instanceof ControlsBlock && getType() == ContraptionType.CARRIAGE) if (blockstate.getBlock() instanceof ControlsBlock && AllContraptionTypeTags.OPENS_CONTROLS.matches(this.getType()))
blockstate = blockstate.setValue(ControlsBlock.OPEN, true); blockstate = blockstate.setValue(ControlsBlock.OPEN, true);
if (blockstate.hasProperty(SlidingDoorBlock.VISIBLE)) if (blockstate.hasProperty(SlidingDoorBlock.VISIBLE))
blockstate = blockstate.setValue(SlidingDoorBlock.VISIBLE, false); blockstate = blockstate.setValue(SlidingDoorBlock.VISIBLE, false);
@ -662,10 +664,10 @@ public abstract class Contraption {
captureMultiblock(localPos, structureBlockInfo, be); captureMultiblock(localPos, structureBlockInfo, be);
if (AllMovementBehaviours.getBehaviour(state) != null) if (MovementBehaviour.REGISTRY.get(state) != null)
actors.add(MutablePair.of(structureBlockInfo, null)); actors.add(MutablePair.of(structureBlockInfo, null));
MovingInteractionBehaviour interactionBehaviour = AllInteractionBehaviours.getBehaviour(state); MovingInteractionBehaviour interactionBehaviour = MovingInteractionBehaviour.REGISTRY.get(state);
if (interactionBehaviour != null) if (interactionBehaviour != null)
interactors.put(localPos, interactionBehaviour); interactors.put(localPos, interactionBehaviour);
@ -685,7 +687,7 @@ public abstract class Contraption {
if (nbt.contains("Controller")) if (nbt.contains("Controller"))
controllerPos = toLocalPos(NBTHelper.readBlockPos(nbt, "Controller")); controllerPos = toLocalPos(NBTHelper.readBlockPos(nbt, "Controller"));
nbt.put("Controller", NbtUtils.writeBlockPos(controllerPos)); nbt.put("Controller", NbtUtils.writeBlockPos(controllerPos));
if (updateTags.containsKey(localPos)) if (updateTags.containsKey(localPos))
updateTags.get(localPos).put("Controller", NbtUtils.writeBlockPos(controllerPos)); updateTags.get(localPos).put("Controller", NbtUtils.writeBlockPos(controllerPos));
@ -791,7 +793,7 @@ public abstract class Contraption {
StructureBlockInfo structureBlockInfo = getBlocks().get(pos); StructureBlockInfo structureBlockInfo = getBlocks().get(pos);
if (structureBlockInfo == null) if (structureBlockInfo == null)
return; return;
MovingInteractionBehaviour behaviour = AllInteractionBehaviours.getBehaviour(structureBlockInfo.state()); MovingInteractionBehaviour behaviour = MovingInteractionBehaviour.REGISTRY.get(structureBlockInfo.state());
if (behaviour != null) if (behaviour != null)
interactors.put(pos, behaviour); interactors.put(pos, behaviour);
}); });
@ -806,7 +808,8 @@ public abstract class Contraption {
public CompoundTag writeNBT(HolderLookup.Provider registries, boolean spawnPacket) { public CompoundTag writeNBT(HolderLookup.Provider registries, boolean spawnPacket) {
CompoundTag nbt = new CompoundTag(); CompoundTag nbt = new CompoundTag();
nbt.putString("Type", getType().id); ResourceLocation typeId = this.getType().holder.key().location();
nbt.putString("Type", typeId.toString());
CompoundTag blocksNBT = writeBlocksCompound(spawnPacket); CompoundTag blocksNBT = writeBlocksCompound(spawnPacket);
@ -829,7 +832,7 @@ public abstract class Contraption {
ListTag actorsNBT = new ListTag(); ListTag actorsNBT = new ListTag();
for (MutablePair<StructureBlockInfo, MovementContext> actor : getActors()) { for (MutablePair<StructureBlockInfo, MovementContext> actor : getActors()) {
MovementBehaviour behaviour = AllMovementBehaviours.getBehaviour(actor.left.state()); MovementBehaviour behaviour = MovementBehaviour.REGISTRY.get(actor.left.state());
if (behaviour == null) if (behaviour == null)
continue; continue;
CompoundTag compound = new CompoundTag(); CompoundTag compound = new CompoundTag();
@ -995,7 +998,7 @@ public abstract class Contraption {
presentBlockEntities.put(info.pos(), be); presentBlockEntities.put(info.pos(), be);
modelData.put(info.pos(), be.getModelData()); modelData.put(info.pos(), be.getModelData());
MovementBehaviour movementBehaviour = AllMovementBehaviours.getBehaviour(info.state()); MovementBehaviour movementBehaviour = MovementBehaviour.REGISTRY.get(info.state());
if (movementBehaviour == null || !movementBehaviour.disableBlockEntityRendering()) { if (movementBehaviour == null || !movementBehaviour.disableBlockEntityRendering()) {
renderedBlockEntities.add(be); renderedBlockEntities.add(be);
} }
@ -1321,7 +1324,7 @@ public abstract class Contraption {
for (MutablePair<StructureBlockInfo, MovementContext> pair : actors) { for (MutablePair<StructureBlockInfo, MovementContext> pair : actors) {
MovementContext context = new MovementContext(world, pair.left, this); MovementContext context = new MovementContext(world, pair.left, this);
MovementBehaviour behaviour = AllMovementBehaviours.getBehaviour(pair.left.state()); MovementBehaviour behaviour = MovementBehaviour.REGISTRY.get(pair.left.state());
if (behaviour != null) if (behaviour != null)
behaviour.startMoving(context); behaviour.startMoving(context);
pair.setRight(context); pair.setRight(context);
@ -1351,7 +1354,7 @@ public abstract class Contraption {
public void setActorsActive(ItemStack referenceStack, boolean enable) { public void setActorsActive(ItemStack referenceStack, boolean enable) {
for (MutablePair<StructureBlockInfo, MovementContext> pair : actors) { for (MutablePair<StructureBlockInfo, MovementContext> pair : actors) {
MovementBehaviour behaviour = AllMovementBehaviours.getBehaviour(pair.left.state()); MovementBehaviour behaviour = MovementBehaviour.REGISTRY.get(pair.left.state());
if (behaviour == null) if (behaviour == null)
continue; continue;
ItemStack behaviourStack = behaviour.canBeDisabledVia(pair.right); ItemStack behaviourStack = behaviour.canBeDisabledVia(pair.right);
@ -1381,7 +1384,7 @@ public abstract class Contraption {
public void forEachActor(Level world, BiConsumer<MovementBehaviour, MovementContext> callBack) { public void forEachActor(Level world, BiConsumer<MovementBehaviour, MovementContext> callBack) {
for (MutablePair<StructureBlockInfo, MovementContext> pair : actors) { for (MutablePair<StructureBlockInfo, MovementContext> pair : actors) {
MovementBehaviour behaviour = AllMovementBehaviours.getBehaviour(pair.getLeft().state()); MovementBehaviour behaviour = MovementBehaviour.REGISTRY.get(pair.getLeft().state());
if (behaviour == null) if (behaviour == null)
continue; continue;
callBack.accept(behaviour, pair.getRight()); callBack.accept(behaviour, pair.getRight());
@ -1560,7 +1563,7 @@ public abstract class Contraption {
public boolean containsBlockBreakers() { public boolean containsBlockBreakers() {
for (MutablePair<StructureBlockInfo, MovementContext> pair : actors) { for (MutablePair<StructureBlockInfo, MovementContext> pair : actors) {
MovementBehaviour behaviour = AllMovementBehaviours.getBehaviour(pair.getLeft().state()); MovementBehaviour behaviour = MovementBehaviour.REGISTRY.get(pair.getLeft().state());
if (behaviour instanceof BlockBreakingMovementBehaviour || behaviour instanceof HarvesterMovementBehaviour) if (behaviour instanceof BlockBreakingMovementBehaviour || behaviour instanceof HarvesterMovementBehaviour)
return true; return true;
} }

View file

@ -9,18 +9,18 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import org.apache.commons.lang3.mutable.MutableBoolean; import org.apache.commons.lang3.mutable.MutableBoolean;
import org.apache.commons.lang3.mutable.MutableFloat; import org.apache.commons.lang3.mutable.MutableFloat;
import org.apache.commons.lang3.mutable.MutableObject; import org.apache.commons.lang3.mutable.MutableObject;
import org.apache.commons.lang3.tuple.MutablePair; import org.apache.commons.lang3.tuple.MutablePair;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllMovementBehaviours; import com.simibubi.create.api.behaviour.interaction.MovingInteractionBehaviour;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity.ContraptionRotationState; import com.simibubi.create.content.contraptions.AbstractContraptionEntity.ContraptionRotationState;
import com.simibubi.create.content.contraptions.ContraptionColliderLockPacket.ContraptionColliderLockPacketRequest; import com.simibubi.create.content.contraptions.ContraptionColliderLockPacket.ContraptionColliderLockPacketRequest;
import com.simibubi.create.content.contraptions.actors.harvester.HarvesterMovementBehaviour; import com.simibubi.create.content.contraptions.actors.harvester.HarvesterMovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovingInteractionBehaviour;
import com.simibubi.create.content.contraptions.sync.ClientMotionPacket; import com.simibubi.create.content.contraptions.sync.ClientMotionPacket;
import com.simibubi.create.content.kinetics.base.BlockBreakingMovementBehaviour; import com.simibubi.create.content.kinetics.base.BlockBreakingMovementBehaviour;
import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; import com.simibubi.create.content.trains.entity.CarriageContraptionEntity;
@ -763,7 +763,7 @@ public class ContraptionCollider {
if (collidedState.getBlock() instanceof CocoaBlock) if (collidedState.getBlock() instanceof CocoaBlock)
continue; continue;
MovementBehaviour movementBehaviour = AllMovementBehaviours.getBehaviour(blockInfo.state()); MovementBehaviour movementBehaviour = MovementBehaviour.REGISTRY.get(blockInfo.state());
if (movementBehaviour != null) { if (movementBehaviour != null) {
if (movementBehaviour instanceof BlockBreakingMovementBehaviour behaviour) { if (movementBehaviour instanceof BlockBreakingMovementBehaviour behaviour) {
if (!behaviour.canBreak(world, colliderPos, collidedState) && !emptyCollider) if (!behaviour.canBreak(world, colliderPos, collidedState) && !emptyCollider)

View file

@ -1,60 +0,0 @@
package com.simibubi.create.content.contraptions;
import com.simibubi.create.foundation.utility.AttachedRegistry;
import com.simibubi.create.infrastructure.config.AllConfigs;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
import net.neoforged.neoforge.common.extensions.IBlockExtension;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.function.Supplier;
public enum ContraptionMovementSetting {
MOVABLE, NO_PICKUP, UNMOVABLE;
private static final AttachedRegistry<Block, Supplier<ContraptionMovementSetting>> SETTING_SUPPLIERS = new AttachedRegistry<>(BuiltInRegistries.BLOCK);
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
public static ContraptionMovementSetting get(Block block) {
if (block instanceof IMovementSettingProvider provider)
return provider.getContraptionMovementSetting();
Supplier<ContraptionMovementSetting> supplier = SETTING_SUPPLIERS.get(block);
if (supplier == null)
return null;
return supplier.get();
}
public static boolean allAre(Collection<StructureTemplate.StructureBlockInfo> blocks, ContraptionMovementSetting are) {
return blocks.stream().anyMatch(b -> get(b.state().getBlock()) == are);
}
public static boolean isNoPickup(Collection<StructureTemplate.StructureBlockInfo> blocks) {
return allAre(blocks, ContraptionMovementSetting.NO_PICKUP);
}
public static void registerDefaults() {
register(Blocks.SPAWNER, () -> AllConfigs.server().kinetics.spawnerMovement.get());
register(Blocks.BUDDING_AMETHYST, () -> AllConfigs.server().kinetics.amethystMovement.get());
register(Blocks.OBSIDIAN, () -> AllConfigs.server().kinetics.obsidianMovement.get());
register(Blocks.CRYING_OBSIDIAN, () -> AllConfigs.server().kinetics.obsidianMovement.get());
register(Blocks.RESPAWN_ANCHOR, () -> AllConfigs.server().kinetics.obsidianMovement.get());
register(Blocks.REINFORCED_DEEPSLATE, () -> AllConfigs.server().kinetics.reinforcedDeepslateMovement.get());
}
public interface IMovementSettingProvider extends IBlockExtension {
ContraptionMovementSetting getContraptionMovementSetting();
}
}

View file

@ -1,53 +0,0 @@
package com.simibubi.create.content.contraptions;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Supplier;
import com.simibubi.create.content.contraptions.bearing.BearingContraption;
import com.simibubi.create.content.contraptions.bearing.ClockworkContraption;
import com.simibubi.create.content.contraptions.bearing.StabilizedContraption;
import com.simibubi.create.content.contraptions.elevator.ElevatorContraption;
import com.simibubi.create.content.contraptions.gantry.GantryContraption;
import com.simibubi.create.content.contraptions.mounted.MountedContraption;
import com.simibubi.create.content.contraptions.piston.PistonContraption;
import com.simibubi.create.content.contraptions.pulley.PulleyContraption;
import com.simibubi.create.content.trains.entity.CarriageContraption;
public class ContraptionType {
public static final Map<String, ContraptionType> ENTRIES = new HashMap<>();
public static final ContraptionType
PISTON = register("piston", PistonContraption::new),
BEARING = register("bearing", BearingContraption::new),
PULLEY = register("pulley", PulleyContraption::new),
CLOCKWORK = register("clockwork", ClockworkContraption::new),
MOUNTED = register("mounted", MountedContraption::new),
STABILIZED = register("stabilized", StabilizedContraption::new),
GANTRY = register("gantry", GantryContraption::new),
CARRIAGE = register("carriage", CarriageContraption::new),
ELEVATOR = register("elevator", ElevatorContraption::new);
Supplier<? extends Contraption> factory;
String id;
public static ContraptionType register(String id, Supplier<? extends Contraption> factory) {
ContraptionType value = new ContraptionType(id, factory);
ENTRIES.put(id, value);
return value;
}
private ContraptionType(String id, Supplier<? extends Contraption> factory) {
this.factory = factory;
this.id = id;
}
public static Contraption fromType(String type) {
for (Entry<String, ContraptionType> allContraptionTypes : ENTRIES.entrySet())
if (type.equals(allContraptionTypes.getKey()))
return allContraptionTypes.getValue().factory.get();
return null;
}
}

View file

@ -2,8 +2,8 @@ package com.simibubi.create.content.contraptions;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllEntityTypes; import com.simibubi.create.AllEntityTypes;
import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import com.simibubi.create.content.contraptions.bearing.BearingContraption; import com.simibubi.create.content.contraptions.bearing.BearingContraption;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import dev.engine_room.flywheel.lib.transform.TransformStack; import dev.engine_room.flywheel.lib.transform.TransformStack;

View file

@ -17,7 +17,6 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.collect.Sets.SetView; import com.google.common.collect.Sets.SetView;
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.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 +143,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 = MountedItemStorageType.REGISTRY.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 +151,7 @@ public class MountedStorageManager {
} }
} }
MountedFluidStorageType<?> fluidType = MountedStorageTypeRegistry.FLUID_LOOKUP.find(state); MountedFluidStorageType<?> fluidType = MountedFluidStorageType.REGISTRY.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 +166,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 = MountedItemStorageType.REGISTRY.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 +174,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 = MountedFluidStorageType.REGISTRY.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,14 +4,13 @@ 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 org.jetbrains.annotations.Nullable; 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 com.simibubi.create.api.contraption.transformable.TransformableBlock; import com.simibubi.create.api.contraption.transformable.TransformableBlock;
import com.simibubi.create.api.contraption.transformable.TransformableBlockEntity; import com.simibubi.create.api.contraption.transformable.TransformableBlockEntity;
import com.simibubi.create.impl.contraption.transformable.ContraptionTransformableRegistryImpl;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import net.createmod.catnip.codecs.stream.CatnipStreamCodecBuilders;
import net.createmod.catnip.codecs.stream.CatnipStreamCodecs; import net.createmod.catnip.codecs.stream.CatnipStreamCodecs;
import net.createmod.catnip.math.VecHelper; import net.createmod.catnip.math.VecHelper;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -40,28 +39,25 @@ import net.minecraft.world.phys.Vec3;
public class StructureTransform { public class StructureTransform {
public static final StreamCodec<ByteBuf, StructureTransform> STREAM_CODEC = StreamCodec.composite( public static final StreamCodec<ByteBuf, StructureTransform> STREAM_CODEC = StreamCodec.composite(
BlockPos.STREAM_CODEC, transform -> transform.offset, BlockPos.STREAM_CODEC, i -> i.offset,
ByteBufCodecs.VAR_INT, transform -> transform.angle, ByteBufCodecs.INT, i -> i.angle,
CatnipStreamCodecBuilders.nullable(CatnipStreamCodecs.AXIS), transform -> transform.rotationAxis, CatnipStreamCodecs.AXIS, i -> i.rotationAxis,
CatnipStreamCodecBuilders.nullable(CatnipStreamCodecs.ROTATION), transform -> transform.rotation, CatnipStreamCodecs.ROTATION, i -> i.rotation,
CatnipStreamCodecBuilders.nullable(CatnipStreamCodecs.MIRROR), transform -> transform.mirror, CatnipStreamCodecs.MIRROR, i -> i.mirror,
StructureTransform::new StructureTransform::new
); );
// Assuming structures cannot be rotated around multiple axes at once
public Axis rotationAxis;
public BlockPos offset; public BlockPos offset;
public int angle; public int angle;
// Assuming structures cannot be rotated around multiple axes at once
@Nullable
public Axis rotationAxis;
@Nullable
public Rotation rotation; public Rotation rotation;
@Nullable
public Mirror mirror; public Mirror mirror;
private StructureTransform(BlockPos offset, int angle, @Nullable Axis axis, @Nullable Rotation rotation, @Nullable Mirror mirror) { private StructureTransform(BlockPos offset, int angle, Axis axis, Rotation rotation, Mirror mirror) {
this.offset = offset; this.offset = offset;
this.angle = angle; this.angle = angle;
this.rotationAxis = axis; rotationAxis = axis;
this.rotation = rotation; this.rotation = rotation;
this.mirror = mirror; this.mirror = mirror;
} }
@ -149,9 +145,9 @@ public class StructureTransform {
} }
public void apply(BlockEntity be) { public void apply(BlockEntity be) {
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 TransformableBlockEntity itbe) { } else if (be instanceof TransformableBlockEntity itbe) {
itbe.transform(be, this); itbe.transform(be, this);
} }
@ -164,9 +160,9 @@ public class StructureTransform {
*/ */
public BlockState apply(BlockState state) { public BlockState apply(BlockState state) {
Block block = state.getBlock(); Block block = state.getBlock();
TransformableBlock transformableBlock = ContraptionTransformableRegistryImpl.get(block); BlockTransformer transformer = MovedBlockTransformerRegistries.BLOCK_TRANSFORMERS.get(block);
if (transformableBlock != null) { if (transformer != null) {
return transformableBlock.transform(state, this); return transformer.transform(state, this);
} else if (block instanceof TransformableBlock transformable) { } else if (block instanceof TransformableBlock transformable) {
return transformable.transform(state, this); return transformable.transform(state, this);
} }

View file

@ -1,7 +1,7 @@
package com.simibubi.create.content.contraptions.actors.contraptionControls; package com.simibubi.create.content.contraptions.actors.contraptionControls;
import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import com.simibubi.create.content.contraptions.Contraption; import com.simibubi.create.content.contraptions.Contraption;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.simibubi.create.content.contraptions.elevator.ElevatorContraption; import com.simibubi.create.content.contraptions.elevator.ElevatorContraption;
import com.simibubi.create.content.contraptions.render.ContraptionMatrices; import com.simibubi.create.content.contraptions.render.ContraptionMatrices;

View file

@ -1,17 +1,22 @@
package com.simibubi.create.content.contraptions.actors.contraptionControls; package com.simibubi.create.content.contraptions.actors.contraptionControls;
import com.simibubi.create.AllMovementBehaviours; import java.util.Iterator;
import java.util.List;
import org.apache.commons.lang3.tuple.MutablePair;
import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.api.behaviour.interaction.MovingInteractionBehaviour;
import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.Contraption; import com.simibubi.create.content.contraptions.Contraption;
import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovement.ElevatorFloorSelection; import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovement.ElevatorFloorSelection;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.simibubi.create.content.contraptions.behaviour.MovingInteractionBehaviour;
import com.simibubi.create.content.contraptions.elevator.ElevatorContraption; import com.simibubi.create.content.contraptions.elevator.ElevatorContraption;
import com.simibubi.create.content.contraptions.elevator.ElevatorTargetFloorPacket; import com.simibubi.create.content.contraptions.elevator.ElevatorTargetFloorPacket;
import net.createmod.catnip.platform.CatnipServices;
import net.createmod.catnip.platform.CatnipServices;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
@ -20,11 +25,6 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import org.apache.commons.lang3.tuple.MutablePair;
import java.util.Iterator;
import java.util.List;
public class ContraptionControlsMovingInteraction extends MovingInteractionBehaviour { public class ContraptionControlsMovingInteraction extends MovingInteractionBehaviour {
@Override @Override
@ -70,7 +70,7 @@ public class ContraptionControlsMovingInteraction extends MovingInteractionBehav
if (invert) { if (invert) {
for (MutablePair<StructureBlockInfo, MovementContext> pair : contraption.getActors()) { for (MutablePair<StructureBlockInfo, MovementContext> pair : contraption.getActors()) {
MovementBehaviour behaviour = AllMovementBehaviours.getBehaviour(pair.left.state()); MovementBehaviour behaviour = MovementBehaviour.REGISTRY.get(pair.left.state());
if (behaviour == null) if (behaviour == null)
continue; continue;
ItemStack behaviourStack = behaviour.canBeDisabledVia(pair.right); ItemStack behaviourStack = behaviour.canBeDisabledVia(pair.right);

View file

@ -6,8 +6,8 @@ import net.neoforged.neoforge.common.SpecialPlantable;
import org.apache.commons.lang3.mutable.MutableBoolean; import org.apache.commons.lang3.mutable.MutableBoolean;
import com.simibubi.create.AllTags; import com.simibubi.create.AllTags.AllBlockTags;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.simibubi.create.content.contraptions.render.ActorVisual; import com.simibubi.create.content.contraptions.render.ActorVisual;
import com.simibubi.create.content.contraptions.render.ContraptionMatrices; import com.simibubi.create.content.contraptions.render.ContraptionMatrices;
@ -172,7 +172,7 @@ public class HarvesterMovementBehaviour implements MovementBehaviour {
if (block == Blocks.SWEET_BERRY_BUSH) { if (block == Blocks.SWEET_BERRY_BUSH) {
return state.setValue(BlockStateProperties.AGE_3, Integer.valueOf(1)); return state.setValue(BlockStateProperties.AGE_3, Integer.valueOf(1));
} }
if (state.is(AllTags.AllBlockTags.SUGAR_CANE_VARIANTS.tag) || block instanceof GrowingPlantBlock) { if (AllBlockTags.SUGAR_CANE_VARIANTS.matches(block) || block instanceof GrowingPlantBlock) {
if (state.getFluidState() if (state.getFluidState()
.isEmpty()) .isEmpty())
return Blocks.AIR.defaultBlockState(); return Blocks.AIR.defaultBlockState();

View file

@ -4,7 +4,7 @@ import java.util.Optional;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.simibubi.create.content.contraptions.render.ActorVisual; import com.simibubi.create.content.contraptions.render.ActorVisual;
import com.simibubi.create.content.contraptions.render.ContraptionMatrices; import com.simibubi.create.content.contraptions.render.ContraptionMatrices;

View file

@ -1,8 +1,8 @@
package com.simibubi.create.content.contraptions.actors.seat; package com.simibubi.create.content.contraptions.actors.seat;
import com.simibubi.create.api.behaviour.interaction.MovingInteractionBehaviour;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.Contraption; import com.simibubi.create.content.contraptions.Contraption;
import com.simibubi.create.content.contraptions.behaviour.MovingInteractionBehaviour;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;

View file

@ -3,8 +3,8 @@ package com.simibubi.create.content.contraptions.actors.seat;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import net.createmod.catnip.math.VecHelper; import net.createmod.catnip.math.VecHelper;

View file

@ -4,12 +4,13 @@ import java.util.UUID;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.api.behaviour.interaction.MovingInteractionBehaviour;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.behaviour.MovingInteractionBehaviour;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.neoforged.api.distmarker.Dist; import net.neoforged.api.distmarker.Dist;
public class ControlsInteractionBehaviour extends MovingInteractionBehaviour { public class ControlsInteractionBehaviour extends MovingInteractionBehaviour {

View file

@ -2,8 +2,8 @@ package com.simibubi.create.content.contraptions.actors.trainControls;
import java.util.Collection; import java.util.Collection;
import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.simibubi.create.content.contraptions.render.ContraptionMatrices; import com.simibubi.create.content.contraptions.render.ContraptionMatrices;
import com.simibubi.create.content.trains.entity.CarriageContraptionEntity; import com.simibubi.create.content.trains.entity.CarriageContraptionEntity;

View file

@ -1,19 +1,19 @@
package com.simibubi.create.content.contraptions.bearing; package com.simibubi.create.content.contraptions.bearing;
import net.minecraft.core.HolderLookup;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllContraptionTypes;
import com.simibubi.create.AllTags.AllBlockTags; import com.simibubi.create.AllTags.AllBlockTags;
import com.simibubi.create.api.contraption.ContraptionType;
import com.simibubi.create.content.contraptions.AssemblyException; import com.simibubi.create.content.contraptions.AssemblyException;
import com.simibubi.create.content.contraptions.Contraption; import com.simibubi.create.content.contraptions.Contraption;
import com.simibubi.create.content.contraptions.ContraptionType;
import com.simibubi.create.content.decoration.copycat.CopycatBlockEntity; import com.simibubi.create.content.decoration.copycat.CopycatBlockEntity;
import com.simibubi.create.infrastructure.config.AllConfigs; import com.simibubi.create.infrastructure.config.AllConfigs;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
@ -50,7 +50,7 @@ public class BearingContraption extends Contraption {
@Override @Override
public ContraptionType getType() { public ContraptionType getType() {
return ContraptionType.BEARING; return AllContraptionTypes.BEARING.value();
} }
@Override @Override

View file

@ -4,17 +4,17 @@ import java.util.HashSet;
import java.util.Queue; import java.util.Queue;
import java.util.Set; import java.util.Set;
import net.minecraft.core.HolderLookup;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllContraptionTypes;
import com.simibubi.create.api.contraption.ContraptionType;
import com.simibubi.create.content.contraptions.AssemblyException; import com.simibubi.create.content.contraptions.AssemblyException;
import com.simibubi.create.content.contraptions.Contraption; import com.simibubi.create.content.contraptions.Contraption;
import com.simibubi.create.content.contraptions.ContraptionType;
import net.createmod.catnip.nbt.NBTHelper; import net.createmod.catnip.nbt.NBTHelper;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
@ -27,7 +27,7 @@ public class ClockworkContraption extends Contraption {
@Override @Override
public ContraptionType getType() { public ContraptionType getType() {
return ContraptionType.CLOCKWORK; return AllContraptionTypes.CLOCKWORK.value();
} }
private void ignoreBlocks(Set<BlockPos> blocks, BlockPos anchor) { private void ignoreBlocks(Set<BlockPos> blocks, BlockPos anchor) {

View file

@ -6,10 +6,10 @@ import org.joml.Quaternionf;
import com.mojang.math.Axis; import com.mojang.math.Axis;
import com.simibubi.create.AllPartialModels; import com.simibubi.create.AllPartialModels;
import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.ControlledContraptionEntity; import com.simibubi.create.content.contraptions.ControlledContraptionEntity;
import com.simibubi.create.content.contraptions.OrientedContraptionEntity; import com.simibubi.create.content.contraptions.OrientedContraptionEntity;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.simibubi.create.content.contraptions.render.ActorVisual; import com.simibubi.create.content.contraptions.render.ActorVisual;
import com.simibubi.create.content.contraptions.render.ContraptionMatrices; import com.simibubi.create.content.contraptions.render.ContraptionMatrices;

View file

@ -1,8 +1,9 @@
package com.simibubi.create.content.contraptions.bearing; package com.simibubi.create.content.contraptions.bearing;
import com.simibubi.create.AllContraptionTypes;
import com.simibubi.create.api.contraption.ContraptionType;
import com.simibubi.create.content.contraptions.AssemblyException; import com.simibubi.create.content.contraptions.AssemblyException;
import com.simibubi.create.content.contraptions.Contraption; import com.simibubi.create.content.contraptions.Contraption;
import com.simibubi.create.content.contraptions.ContraptionType;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
@ -38,7 +39,7 @@ public class StabilizedContraption extends Contraption {
@Override @Override
public ContraptionType getType() { public ContraptionType getType() {
return ContraptionType.STABILIZED; return AllContraptionTypes.STABILIZED.value();
} }
@Override @Override

View file

@ -1,6 +1,7 @@
package com.simibubi.create.content.contraptions.behaviour; package com.simibubi.create.content.contraptions.behaviour;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import com.simibubi.create.content.contraptions.Contraption; import com.simibubi.create.content.contraptions.Contraption;
import com.simibubi.create.content.contraptions.elevator.ElevatorContraption; import com.simibubi.create.content.contraptions.elevator.ElevatorContraption;
import com.simibubi.create.content.equipment.bell.AbstractBellBlock; import com.simibubi.create.content.equipment.bell.AbstractBellBlock;

View file

@ -1,5 +1,7 @@
package com.simibubi.create.content.contraptions.behaviour; package com.simibubi.create.content.contraptions.behaviour;
import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import net.minecraft.core.particles.ParticleTypes; import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.CampfireBlock; import net.minecraft.world.level.block.CampfireBlock;

View file

@ -1,5 +1,6 @@
package com.simibubi.create.content.contraptions.behaviour; package com.simibubi.create.content.contraptions.behaviour;
import com.simibubi.create.api.behaviour.interaction.MovingInteractionBehaviour;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.Contraption; import com.simibubi.create.content.contraptions.Contraption;

View file

@ -4,8 +4,8 @@ import java.util.function.Predicate;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import com.simibubi.create.api.contraption.storage.item.MountedItemStorage; import com.simibubi.create.api.contraption.storage.item.MountedItemStorage;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.simibubi.create.foundation.item.ItemHelper; import com.simibubi.create.foundation.item.ItemHelper;

View file

@ -12,7 +12,7 @@ import java.util.function.Function;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllKeys; import com.simibubi.create.AllKeys;
import com.simibubi.create.content.contraptions.BlockMovementChecks; import com.simibubi.create.api.contraption.BlockMovementChecks;
import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.CenteredSideValueBoxTransform; import com.simibubi.create.foundation.blockEntity.behaviour.CenteredSideValueBoxTransform;

View file

@ -7,19 +7,20 @@ import org.apache.commons.lang3.tuple.Pair;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllContraptionTypes;
import com.simibubi.create.api.contraption.ContraptionType;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.AssemblyException; import com.simibubi.create.content.contraptions.AssemblyException;
import com.simibubi.create.content.contraptions.ContraptionType;
import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovement.ElevatorFloorSelection; import com.simibubi.create.content.contraptions.actors.contraptionControls.ContraptionControlsMovement.ElevatorFloorSelection;
import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.simibubi.create.content.contraptions.elevator.ElevatorColumn.ColumnCoords; import com.simibubi.create.content.contraptions.elevator.ElevatorColumn.ColumnCoords;
import com.simibubi.create.content.contraptions.pulley.PulleyContraption; import com.simibubi.create.content.contraptions.pulley.PulleyContraption;
import com.simibubi.create.content.redstone.contact.RedstoneContactBlock; import com.simibubi.create.content.redstone.contact.RedstoneContactBlock;
import net.createmod.catnip.platform.CatnipServices;
import com.simibubi.create.foundation.utility.CreateLang; import com.simibubi.create.foundation.utility.CreateLang;
import net.createmod.catnip.data.Couple; import net.createmod.catnip.data.Couple;
import net.createmod.catnip.data.IntAttached; import net.createmod.catnip.data.IntAttached;
import net.createmod.catnip.platform.CatnipServices;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis; import net.minecraft.core.Direction.Axis;
@ -170,7 +171,7 @@ public class ElevatorContraption extends PulleyContraption {
@Override @Override
public ContraptionType getType() { public ContraptionType getType() {
return ContraptionType.ELEVATOR; return AllContraptionTypes.ELEVATOR.value();
} }
public void setClientYTarget(int clientYTarget) { public void setClientYTarget(int clientYTarget) {

View file

@ -1,8 +1,9 @@
package com.simibubi.create.content.contraptions.gantry; package com.simibubi.create.content.contraptions.gantry;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllContraptionTypes;
import com.simibubi.create.api.contraption.ContraptionType;
import com.simibubi.create.content.contraptions.AssemblyException; import com.simibubi.create.content.contraptions.AssemblyException;
import com.simibubi.create.content.contraptions.ContraptionType;
import com.simibubi.create.content.contraptions.TranslatingContraption; import com.simibubi.create.content.contraptions.TranslatingContraption;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -50,7 +51,7 @@ public class GantryContraption extends TranslatingContraption {
@Override @Override
public ContraptionType getType() { public ContraptionType getType() {
return ContraptionType.GANTRY; return AllContraptionTypes.GANTRY.value();
} }
public Direction getFacing() { public Direction getFacing() {

View file

@ -12,8 +12,8 @@ import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllEntityTypes; import com.simibubi.create.AllEntityTypes;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.api.contraption.BlockMovementChecks;
import com.simibubi.create.api.schematic.requirement.SpecialEntityItemRequirement; import com.simibubi.create.api.schematic.requirement.SpecialEntityItemRequirement;
import com.simibubi.create.content.contraptions.BlockMovementChecks;
import com.simibubi.create.content.contraptions.bearing.BearingBlock; import com.simibubi.create.content.contraptions.bearing.BearingBlock;
import com.simibubi.create.content.contraptions.chassis.AbstractChassisBlock; import com.simibubi.create.content.contraptions.chassis.AbstractChassisBlock;
import com.simibubi.create.content.kinetics.base.DirectionalKineticBlock; import com.simibubi.create.content.kinetics.base.DirectionalKineticBlock;

View file

@ -4,7 +4,7 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.content.contraptions.BlockMovementChecks; import com.simibubi.create.api.contraption.BlockMovementChecks;
import net.createmod.catnip.platform.CatnipServices; import net.createmod.catnip.platform.CatnipServices;
import net.createmod.catnip.data.Iterate; import net.createmod.catnip.data.Iterate;

View file

@ -5,7 +5,7 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import com.simibubi.create.content.contraptions.BlockMovementChecks; import com.simibubi.create.api.contraption.BlockMovementChecks;
import net.createmod.catnip.data.Iterate; import net.createmod.catnip.data.Iterate;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;

View file

@ -8,10 +8,10 @@ import org.apache.commons.lang3.tuple.MutablePair;
import com.simibubi.create.AllDataComponents; import com.simibubi.create.AllDataComponents;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.AllMovementBehaviours; import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import com.simibubi.create.api.contraption.ContraptionMovementSetting;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.Contraption; import com.simibubi.create.content.contraptions.Contraption;
import com.simibubi.create.content.contraptions.ContraptionMovementSetting;
import com.simibubi.create.content.contraptions.OrientedContraptionEntity; import com.simibubi.create.content.contraptions.OrientedContraptionEntity;
import com.simibubi.create.content.contraptions.actors.psi.PortableStorageInterfaceMovement; import com.simibubi.create.content.contraptions.actors.psi.PortableStorageInterfaceMovement;
import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.content.contraptions.behaviour.MovementContext;
@ -245,7 +245,7 @@ public class MinecartContraptionItem extends Item {
contraption.stop(event.getLevel()); contraption.stop(event.getLevel());
for (MutablePair<StructureBlockInfo, MovementContext> pair : contraption.getActors()) for (MutablePair<StructureBlockInfo, MovementContext> pair : contraption.getActors())
if (AllMovementBehaviours.getBehaviour(pair.left.state()) instanceof PortableStorageInterfaceMovement psim) if (MovementBehaviour.REGISTRY.get(pair.left.state()) instanceof PortableStorageInterfaceMovement psim)
psim.reset(pair.right); psim.reset(pair.right);
ItemStack generatedStack = create(type, oce); ItemStack generatedStack = create(type, oce);

View file

@ -4,14 +4,13 @@ import static com.simibubi.create.content.contraptions.mounted.CartAssemblerBloc
import java.util.Queue; import java.util.Queue;
import net.minecraft.core.HolderLookup;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllContraptionTypes;
import com.simibubi.create.api.contraption.ContraptionType;
import com.simibubi.create.content.contraptions.AssemblyException; import com.simibubi.create.content.contraptions.AssemblyException;
import com.simibubi.create.content.contraptions.Contraption; import com.simibubi.create.content.contraptions.Contraption;
import com.simibubi.create.content.contraptions.ContraptionType;
import com.simibubi.create.content.contraptions.mounted.CartAssemblerBlockEntity.CartMovementMode; import com.simibubi.create.content.contraptions.mounted.CartAssemblerBlockEntity.CartMovementMode;
import net.createmod.catnip.data.Iterate; import net.createmod.catnip.data.Iterate;
@ -20,6 +19,7 @@ import net.createmod.catnip.nbt.NBTHelper;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis; import net.minecraft.core.Direction.Axis;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.Container; import net.minecraft.world.Container;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
@ -50,7 +50,7 @@ public class MountedContraption extends Contraption {
@Override @Override
public ContraptionType getType() { public ContraptionType getType() {
return ContraptionType.MOUNTED; return AllContraptionTypes.MOUNTED.value();
} }
@Override @Override

View file

@ -12,14 +12,12 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Queue; import java.util.Queue;
import net.minecraft.core.HolderLookup;
import net.minecraft.world.phys.Vec3;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllContraptionTypes;
import com.simibubi.create.api.contraption.BlockMovementChecks;
import com.simibubi.create.api.contraption.ContraptionType;
import com.simibubi.create.content.contraptions.AssemblyException; import com.simibubi.create.content.contraptions.AssemblyException;
import com.simibubi.create.content.contraptions.BlockMovementChecks;
import com.simibubi.create.content.contraptions.ContraptionType;
import com.simibubi.create.content.contraptions.TranslatingContraption; import com.simibubi.create.content.contraptions.TranslatingContraption;
import com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock.PistonState; import com.simibubi.create.content.contraptions.piston.MechanicalPistonBlock.PistonState;
import com.simibubi.create.infrastructure.config.AllConfigs; import com.simibubi.create.infrastructure.config.AllConfigs;
@ -27,6 +25,7 @@ import com.simibubi.create.infrastructure.config.AllConfigs;
import net.createmod.catnip.math.VecHelper; import net.createmod.catnip.math.VecHelper;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelAccessor;
@ -38,6 +37,7 @@ import net.minecraft.world.level.block.state.properties.PistonType;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
import net.minecraft.world.level.material.PushReaction; import net.minecraft.world.level.material.PushReaction;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
public class PistonContraption extends TranslatingContraption { public class PistonContraption extends TranslatingContraption {
@ -50,10 +50,11 @@ public class PistonContraption extends TranslatingContraption {
@Override @Override
public ContraptionType getType() { public ContraptionType getType() {
return ContraptionType.PISTON; return AllContraptionTypes.PISTON.value();
} }
public PistonContraption() {} public PistonContraption() {
}
public PistonContraption(Direction direction, boolean retract) { public PistonContraption(Direction direction, boolean retract) {
orientation = direction; orientation = direction;
@ -129,8 +130,8 @@ public class PistonContraption extends TranslatingContraption {
extensionLength = extensionsInBack + extensionsInFront; extensionLength = extensionsInBack + extensionsInFront;
initialExtensionProgress = extensionsInFront; initialExtensionProgress = extensionsInFront;
pistonExtensionCollisionBox = new AABB( pistonExtensionCollisionBox = new AABB(
Vec3.atLowerCornerOf(BlockPos.ZERO.relative(direction, -1)), Vec3.atLowerCornerOf(BlockPos.ZERO.relative(direction, -1)),
Vec3.atLowerCornerOf(BlockPos.ZERO.relative(direction, -extensionLength - 1)) Vec3.atLowerCornerOf(BlockPos.ZERO.relative(direction, -extensionLength - 1))
).expandTowards(1, 1, 1); ).expandTowards(1, 1, 1);
if (extensionLength == 0) if (extensionLength == 0)

View file

@ -7,9 +7,9 @@ import java.util.List;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.api.contraption.BlockMovementChecks;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.AssemblyException; import com.simibubi.create.content.contraptions.AssemblyException;
import com.simibubi.create.content.contraptions.BlockMovementChecks;
import com.simibubi.create.content.contraptions.ContraptionCollider; import com.simibubi.create.content.contraptions.ContraptionCollider;
import com.simibubi.create.content.contraptions.ControlledContraptionEntity; import com.simibubi.create.content.contraptions.ControlledContraptionEntity;
import com.simibubi.create.content.contraptions.piston.LinearActuatorBlockEntity; import com.simibubi.create.content.contraptions.piston.LinearActuatorBlockEntity;

View file

@ -1,7 +1,8 @@
package com.simibubi.create.content.contraptions.pulley; package com.simibubi.create.content.contraptions.pulley;
import com.simibubi.create.AllContraptionTypes;
import com.simibubi.create.api.contraption.ContraptionType;
import com.simibubi.create.content.contraptions.AssemblyException; import com.simibubi.create.content.contraptions.AssemblyException;
import com.simibubi.create.content.contraptions.ContraptionType;
import com.simibubi.create.content.contraptions.TranslatingContraption; import com.simibubi.create.content.contraptions.TranslatingContraption;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -15,7 +16,7 @@ public class PulleyContraption extends TranslatingContraption {
@Override @Override
public ContraptionType getType() { public ContraptionType getType() {
return ContraptionType.PULLEY; return AllContraptionTypes.PULLEY.value();
} }
public PulleyContraption() {} public PulleyContraption() {}

View file

@ -4,10 +4,9 @@ import org.apache.commons.lang3.tuple.Pair;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import com.simibubi.create.AllMovementBehaviours; import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.Contraption; import com.simibubi.create.content.contraptions.Contraption;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.simibubi.create.foundation.render.BlockEntityRenderHelper; import com.simibubi.create.foundation.render.BlockEntityRenderHelper;
import com.simibubi.create.foundation.virtualWorld.VirtualRenderWorld; import com.simibubi.create.foundation.virtualWorld.VirtualRenderWorld;
@ -99,7 +98,7 @@ public class ContraptionEntityRenderer<C extends AbstractContraptionEntity> exte
context.world = level; context.world = level;
StructureTemplate.StructureBlockInfo blockInfo = actor.getLeft(); StructureTemplate.StructureBlockInfo blockInfo = actor.getLeft();
MovementBehaviour movementBehaviour = AllMovementBehaviours.getBehaviour(blockInfo.state()); MovementBehaviour movementBehaviour = MovementBehaviour.REGISTRY.get(blockInfo.state());
if (movementBehaviour != null) { if (movementBehaviour != null) {
if (c.isHiddenInPortal(blockInfo.pos())) if (c.isHiddenInPortal(blockInfo.pos()))
continue; continue;

View file

@ -6,11 +6,10 @@ import java.util.List;
import org.apache.commons.lang3.tuple.MutablePair; import org.apache.commons.lang3.tuple.MutablePair;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllMovementBehaviours; import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.Contraption; import com.simibubi.create.content.contraptions.Contraption;
import com.simibubi.create.content.contraptions.Contraption.RenderedBlocks; import com.simibubi.create.content.contraptions.Contraption.RenderedBlocks;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.simibubi.create.foundation.utility.worldWrappers.WrappedBlockAndTintGetter; import com.simibubi.create.foundation.utility.worldWrappers.WrappedBlockAndTintGetter;
import com.simibubi.create.foundation.virtualWorld.VirtualRenderWorld; import com.simibubi.create.foundation.virtualWorld.VirtualRenderWorld;
@ -167,7 +166,7 @@ public class ContraptionVisual<E extends AbstractContraptionEntity> extends Abst
StructureTemplate.StructureBlockInfo blockInfo = actor.getLeft(); StructureTemplate.StructureBlockInfo blockInfo = actor.getLeft();
MovementBehaviour movementBehaviour = AllMovementBehaviours.getBehaviour(blockInfo.state()); MovementBehaviour movementBehaviour = MovementBehaviour.REGISTRY.get(blockInfo.state());
if (movementBehaviour == null) { if (movementBehaviour == null) {
return; return;
} }

View file

@ -1,6 +1,6 @@
package com.simibubi.create.content.contraptions.render; package com.simibubi.create.content.contraptions.render;
import com.simibubi.create.content.contraptions.ContraptionType; import com.simibubi.create.AllTags.AllContraptionTypeTags;
import com.simibubi.create.content.contraptions.OrientedContraptionEntity; import com.simibubi.create.content.contraptions.OrientedContraptionEntity;
import net.minecraft.client.renderer.culling.Frustum; import net.minecraft.client.renderer.culling.Frustum;
@ -16,9 +16,9 @@ public class OrientedContraptionEntityRenderer extends ContraptionEntityRenderer
double cameraZ) { double cameraZ) {
if (!super.shouldRender(entity, frustum, cameraX, cameraY, cameraZ)) if (!super.shouldRender(entity, frustum, cameraX, cameraY, cameraZ))
return false; return false;
if (entity.getContraption() if (entity.getVehicle() == null && AllContraptionTypeTags.REQUIRES_VEHICLE_FOR_RENDER.matches(entity.getContraption().getType()))
.getType() == ContraptionType.MOUNTED && entity.getVehicle() == null)
return false; return false;
return true; return true;
} }
} }

View file

@ -3,8 +3,8 @@ package com.simibubi.create.content.decoration.slidingDoor;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.Map; import java.util.Map;
import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import com.simibubi.create.content.contraptions.Contraption; import com.simibubi.create.content.contraptions.Contraption;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.simibubi.create.content.contraptions.elevator.ElevatorColumn; import com.simibubi.create.content.contraptions.elevator.ElevatorColumn;
import com.simibubi.create.content.contraptions.elevator.ElevatorColumn.ColumnCoords; import com.simibubi.create.content.contraptions.elevator.ElevatorColumn.ColumnCoords;

View file

@ -2,14 +2,11 @@ package com.simibubi.create.content.fluids;
import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED; import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED;
import java.util.ArrayList;
import java.util.List;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.simibubi.create.AllFluids; import com.simibubi.create.AllFluids;
import com.simibubi.create.api.effect.OpenPipeEffectHandler;
import com.simibubi.create.content.fluids.pipes.VanillaFluidTargets; import com.simibubi.create.content.fluids.pipes.VanillaFluidTargets;
import com.simibubi.create.content.fluids.potion.PotionFluidHandler;
import com.simibubi.create.foundation.ICapabilityProvider; import com.simibubi.create.foundation.ICapabilityProvider;
import com.simibubi.create.foundation.advancement.AdvancementBehaviour; import com.simibubi.create.foundation.advancement.AdvancementBehaviour;
import com.simibubi.create.foundation.advancement.AllAdvancements; import com.simibubi.create.foundation.advancement.AllAdvancements;
@ -21,23 +18,11 @@ 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.HolderLookup; import net.minecraft.core.HolderLookup;
import net.minecraft.core.component.DataComponents;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource; import net.minecraft.sounds.SoundSource;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.FluidTags; import net.minecraft.tags.FluidTags;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.alchemy.PotionContents;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.AbstractCandleBlock;
import net.minecraft.world.level.block.CampfireBlock;
import net.minecraft.world.level.block.LiquidBlock; import net.minecraft.world.level.block.LiquidBlock;
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;
@ -45,24 +30,13 @@ import net.minecraft.world.level.material.FlowingFluid;
import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids; import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
import net.neoforged.neoforge.common.EffectCures;
import net.neoforged.neoforge.common.Tags;
import net.neoforged.neoforge.fluids.FluidStack; import net.neoforged.neoforge.fluids.FluidStack;
import net.neoforged.neoforge.fluids.capability.IFluidHandler; import net.neoforged.neoforge.fluids.capability.IFluidHandler;
import net.neoforged.neoforge.fluids.capability.templates.FluidTank; import net.neoforged.neoforge.fluids.capability.templates.FluidTank;
public class OpenEndedPipe extends FlowSource { public class OpenEndedPipe extends FlowSource {
private static final List<IEffectHandler> EFFECT_HANDLERS = new ArrayList<>();
static {
registerEffectHandler(new PotionEffectHandler());
registerEffectHandler(new MilkEffectHandler());
registerEffectHandler(new WaterEffectHandler());
registerEffectHandler(new LavaEffectHandler());
registerEffectHandler(new TeaEffectHandler());
}
private Level world; private Level world;
private BlockPos pos; private BlockPos pos;
private AABB aoe; private AABB aoe;
@ -71,9 +45,6 @@ public class OpenEndedPipe extends FlowSource {
private BlockPos outputPos; private BlockPos outputPos;
private boolean wasPulling; private boolean wasPulling;
private FluidStack cachedFluid;
private PotionContents cachedEffects;
private final ICapabilityProvider<IFluidHandler> fluidHandlerProvider = ICapabilityProvider.of(() -> fluidHandler); private final ICapabilityProvider<IFluidHandler> fluidHandlerProvider = ICapabilityProvider.of(() -> fluidHandler);
public OpenEndedPipe(BlockFace face) { public OpenEndedPipe(BlockFace face) {
@ -86,10 +57,6 @@ public class OpenEndedPipe extends FlowSource {
aoe = aoe.expandTowards(0, -1, 0); aoe = aoe.expandTowards(0, -1, 0);
} }
public static void registerEffectHandler(IEffectHandler handler) {
EFFECT_HANDLERS.add(handler);
}
public Level getWorld() { public Level getWorld() {
return world; return world;
} }
@ -252,23 +219,6 @@ public class OpenEndedPipe extends FlowSource {
return true; return true;
} }
private boolean canApplyEffects(FluidStack fluid) {
for (IEffectHandler handler : EFFECT_HANDLERS) {
if (handler.canApplyEffects(this, fluid)) {
return true;
}
}
return false;
}
private void applyEffects(FluidStack fluid) {
for (IEffectHandler handler : EFFECT_HANDLERS) {
if (handler.canApplyEffects(this, fluid)) {
handler.applyEffects(this, fluid);
}
}
}
private class OpenEndFluidHandler extends FluidTank { private class OpenEndFluidHandler extends FluidTank {
public OpenEndFluidHandler() { public OpenEndFluidHandler() {
@ -294,14 +244,22 @@ public class OpenEndedPipe extends FlowSource {
setFluid(FluidStack.EMPTY); setFluid(FluidStack.EMPTY);
if (wasPulling) if (wasPulling)
wasPulling = false; wasPulling = false;
if (canApplyEffects(resource) && !hasBlockState)
OpenPipeEffectHandler effectHandler = OpenPipeEffectHandler.REGISTRY.get(resource.getFluid());
if (effectHandler != null && !hasBlockState)
resource = FluidHelper.copyStackWithAmount(resource, 1); resource = FluidHelper.copyStackWithAmount(resource, 1);
int fill = super.fill(resource, action); int fill = super.fill(resource, action);
if (action.simulate()) if (action.simulate())
return fill; return fill;
if (!resource.isEmpty())
applyEffects(resource); if (effectHandler != null && !resource.isEmpty()) {
// resource should be copied before giving it to the handler.
// if hasBlockState is false, it was already copied above.
FluidStack exposed = hasBlockState ? resource.copy() : resource;
effectHandler.apply(world, aoe, exposed);
}
if (getFluidAmount() == 1000 || !hasBlockState) if (getFluidAmount() == 1000 || !hasBlockState)
if (provideFluidToSpace(containedFluidStack, false)) if (provideFluidToSpace(containedFluidStack, false))
setFluid(FluidStack.EMPTY); setFluid(FluidStack.EMPTY);
@ -359,132 +317,4 @@ public class OpenEndedPipe extends FlowSource {
} }
} }
public interface IEffectHandler {
boolean canApplyEffects(OpenEndedPipe pipe, FluidStack fluid);
void applyEffects(OpenEndedPipe pipe, FluidStack fluid);
}
public static class PotionEffectHandler implements IEffectHandler {
@Override
public boolean canApplyEffects(OpenEndedPipe pipe, FluidStack fluid) {
return fluid.getFluid()
.isSame(AllFluids.POTION.get());
}
@Override
public void applyEffects(OpenEndedPipe pipe, FluidStack fluid) {
if (pipe.cachedFluid == null || pipe.cachedEffects == null || !FluidStack.isSameFluidSameComponents(fluid, pipe.cachedFluid)) {
FluidStack copy = fluid.copy();
copy.setAmount(250);
ItemStack bottle = PotionFluidHandler.fillBottle(new ItemStack(Items.GLASS_BOTTLE), fluid);
pipe.cachedEffects = bottle.get(DataComponents.POTION_CONTENTS);
}
if (pipe.cachedEffects == null)
return;
List<LivingEntity> entities = pipe.getWorld()
.getEntitiesOfClass(LivingEntity.class, pipe.getAOE(), LivingEntity::isAffectedByPotions);
for (LivingEntity entity : entities) {
pipe.cachedEffects.forEachEffect(effectInstance -> {
MobEffect effect = effectInstance.getEffect().value();
if (effect.isInstantenous()) {
effect.applyInstantenousEffect(null, null, entity, effectInstance.getAmplifier(), 0.5D);
} else {
entity.addEffect(new MobEffectInstance(effectInstance));
}
});
}
}
}
public static class MilkEffectHandler implements IEffectHandler {
@Override
public boolean canApplyEffects(OpenEndedPipe pipe, FluidStack fluid) {
return FluidHelper.isTag(fluid, Tags.Fluids.MILK);
}
@Override
public void applyEffects(OpenEndedPipe pipe, FluidStack fluid) {
Level world = pipe.getWorld();
if (world.getGameTime() % 5 != 0)
return;
List<LivingEntity> entities =
world.getEntitiesOfClass(LivingEntity.class, pipe.getAOE(), LivingEntity::isAffectedByPotions);
for (LivingEntity entity : entities)
entity.removeEffectsCuredBy(EffectCures.MILK);
}
}
public static class WaterEffectHandler implements IEffectHandler {
@Override
public boolean canApplyEffects(OpenEndedPipe pipe, FluidStack fluid) {
return FluidHelper.isTag(fluid, FluidTags.WATER);
}
@Override
public void applyEffects(OpenEndedPipe pipe, FluidStack fluid) {
Level world = pipe.getWorld();
if (world.getGameTime() % 5 != 0)
return;
List<Entity> entities = world.getEntities((Entity) null, pipe.getAOE(), Entity::isOnFire);
for (Entity entity : entities)
entity.clearFire();
BlockPos.betweenClosedStream(pipe.getAOE())
.forEach(pos -> dowseFire(world, pos));
}
// Adapted from ThrownPotion
private static void dowseFire(Level level, BlockPos pos) {
BlockState state = level.getBlockState(pos);
if (state.is(BlockTags.FIRE)) {
level.removeBlock(pos, false);
} else if (AbstractCandleBlock.isLit(state)) {
AbstractCandleBlock.extinguish(null, state, level, pos);
} else if (CampfireBlock.isLitCampfire(state)) {
level.levelEvent(null, 1009, pos, 0);
CampfireBlock.dowse(null, level, pos, state);
level.setBlockAndUpdate(pos, state.setValue(CampfireBlock.LIT, false));
}
}
}
public static class LavaEffectHandler implements IEffectHandler {
@Override
public boolean canApplyEffects(OpenEndedPipe pipe, FluidStack fluid) {
return FluidHelper.isTag(fluid, FluidTags.LAVA);
}
@Override
public void applyEffects(OpenEndedPipe pipe, FluidStack fluid) {
Level world = pipe.getWorld();
if (world.getGameTime() % 5 != 0)
return;
List<Entity> entities = world.getEntities((Entity) null, pipe.getAOE(), entity -> !entity.fireImmune());
for (Entity entity : entities)
entity.igniteForSeconds(3);
}
}
public static class TeaEffectHandler implements IEffectHandler {
@Override
public boolean canApplyEffects(OpenEndedPipe pipe, FluidStack fluid) {
return fluid.getFluid().isSame(AllFluids.TEA.get());
}
@Override
public void applyEffects(OpenEndedPipe pipe, FluidStack fluid) {
Level world = pipe.getWorld();
if (world.getGameTime() % 5 != 0)
return;
List<LivingEntity> entities = world
.getEntitiesOfClass(LivingEntity.class, pipe.getAOE(), LivingEntity::isAffectedByPotions);
for (LivingEntity entity : entities) {
entity.addEffect(new MobEffectInstance(MobEffects.DIG_SPEED, 21, 0, false, false, false));
}
}
}
} }

View file

@ -9,7 +9,7 @@ import java.util.List;
import com.simibubi.create.AllBlockEntityTypes; import com.simibubi.create.AllBlockEntityTypes;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.api.behaviour.BlockSpoutingBehaviour; import com.simibubi.create.api.behaviour.spouting.BlockSpoutingBehaviour;
import com.simibubi.create.api.equipment.goggles.IHaveGoggleInformation; import com.simibubi.create.api.equipment.goggles.IHaveGoggleInformation;
import com.simibubi.create.content.fluids.FluidFX; import com.simibubi.create.content.fluids.FluidFX;
import com.simibubi.create.content.kinetics.belt.behaviour.BeltProcessingBehaviour; import com.simibubi.create.content.kinetics.belt.behaviour.BeltProcessingBehaviour;
@ -23,7 +23,6 @@ import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour; import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.fluid.SmartFluidTankBehaviour; import com.simibubi.create.foundation.blockEntity.behaviour.fluid.SmartFluidTankBehaviour;
import com.simibubi.create.foundation.fluid.FluidHelper; import com.simibubi.create.foundation.fluid.FluidHelper;
import com.simibubi.create.impl.behaviour.BlockSpoutingBehaviourImpl;
import net.createmod.catnip.math.VecHelper; import net.createmod.catnip.math.VecHelper;
import net.createmod.catnip.nbt.NBTHelper; import net.createmod.catnip.nbt.NBTHelper;
@ -205,15 +204,13 @@ public class SpoutBlockEntity extends SmartBlockEntity implements IHaveGoggleInf
FluidStack currentFluidInTank = getCurrentFluidInTank(); FluidStack currentFluidInTank = getCurrentFluidInTank();
if (processingTicks == -1 && (isVirtual() || !level.isClientSide()) && !currentFluidInTank.isEmpty()) { if (processingTicks == -1 && (isVirtual() || !level.isClientSide()) && !currentFluidInTank.isEmpty()) {
BlockSpoutingBehaviourImpl.forEach(behaviour -> { BlockPos filling = this.worldPosition.below(2);
if (customProcess != null) BlockSpoutingBehaviour behavior = BlockSpoutingBehaviour.get(this.level, filling);
return; if (behavior != null && behavior.fillBlock(this.level, filling, this, currentFluidInTank.copy(), true) > 0) {
if (behaviour.fillBlock(level, worldPosition.below(2), this, currentFluidInTank.copy(), true) > 0) { processingTicks = FILLING_TIME;
processingTicks = FILLING_TIME; customProcess = behavior;
customProcess = behaviour; notifyUpdate();
notifyUpdate(); }
}
});
} }
if (processingTicks >= 0) { if (processingTicks >= 0) {

View file

@ -10,6 +10,7 @@ import org.jetbrains.annotations.NotNull;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.api.boiler.BoilerHeater;
import com.simibubi.create.content.decoration.steamWhistle.WhistleBlock; import com.simibubi.create.content.decoration.steamWhistle.WhistleBlock;
import com.simibubi.create.content.decoration.steamWhistle.WhistleBlockEntity; import com.simibubi.create.content.decoration.steamWhistle.WhistleBlockEntity;
import com.simibubi.create.content.kinetics.BlockStressValues; import com.simibubi.create.content.kinetics.BlockStressValues;
@ -392,7 +393,7 @@ public class BoilerData {
for (int zOffset = 0; zOffset < controller.width; zOffset++) { for (int zOffset = 0; zOffset < controller.width; zOffset++) {
BlockPos pos = controllerPos.offset(xOffset, -1, zOffset); BlockPos pos = controllerPos.offset(xOffset, -1, zOffset);
BlockState blockState = level.getBlockState(pos); BlockState blockState = level.getBlockState(pos);
float heat = BoilerHeaters.getActiveHeat(level, pos, blockState); float heat = BoilerHeater.findHeat(level, pos, blockState);
if (heat == 0) { if (heat == 0) {
passiveHeat = true; passiveHeat = true;
} else if (heat > 0) { } else if (heat > 0) {

View file

@ -1,95 +1,38 @@
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.boiler.BoilerHeater;
import com.simibubi.create.api.registry.SimpleRegistry;
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.core.registries.BuiltInRegistries;
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.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
public class BoilerHeaters { public class BoilerHeaters {
private static final AttachedRegistry<Block, Heater> BLOCK_HEATERS = new AttachedRegistry<>(BuiltInRegistries.BLOCK);
private static final List<HeaterProvider> GLOBAL_HEATERS = new ArrayList<>();
public static void registerHeater(ResourceLocation block, Heater heater) {
BLOCK_HEATERS.register(block, heater);
}
public static void registerHeater(Block block, Heater heater) {
BLOCK_HEATERS.register(block, heater);
}
public static void registerHeaterProvider(HeaterProvider provider) {
GLOBAL_HEATERS.add(provider);
}
/**
* A return value of {@code -1} represents no heat.
* A return value of {@code 0} represents passive heat.
* All other positive values are used as the amount of active heat.
*/
public static float getActiveHeat(Level level, BlockPos pos, BlockState state) {
Heater heater = BLOCK_HEATERS.get(state.getBlock());
if (heater != null) {
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) -> { BoilerHeater.REGISTRY.register(AllBlocks.BLAZE_BURNER.get(), BoilerHeater.BLAZE_BURNER);
HeatLevel value = state.getValue(BlazeBurnerBlock.HEAT_LEVEL); BoilerHeater.REGISTRY.registerProvider(SimpleRegistry.Provider.forBlockTag(AllBlockTags.PASSIVE_BOILER_HEATERS.tag, BoilerHeater.PASSIVE));
if (value == HeatLevel.NONE) {
return -1;
}
if (value == HeatLevel.SEETHING) {
return 2;
}
if (value.isAtLeast(HeatLevel.FADING)) {
return 1;
}
return 0;
});
registerHeaterProvider((level, pos, state) -> {
if (AllBlockTags.PASSIVE_BOILER_HEATERS.matches(state) && BlockHelper.isNotUnheated(state)) {
return (level1, pos1, state1) -> 0;
}
return null;
});
} }
public interface Heater { public static int passive(Level level, BlockPos pos, BlockState state) {
/** return BlockHelper.isNotUnheated(state) ? BoilerHeater.PASSIVE_HEAT : BoilerHeater.NO_HEAT;
* A return value of {@code -1} represents no heat.
* A return value of {@code 0} represents passive heat.
* All other positive values are used as the amount of active heat.
*/
float getActiveHeat(Level level, BlockPos pos, BlockState state);
} }
public interface HeaterProvider { public static int blazeBurner(Level level, BlockPos pos, BlockState state) {
@Nullable HeatLevel value = state.getValue(BlazeBurnerBlock.HEAT_LEVEL);
Heater getHeater(Level level, BlockPos pos, BlockState state); if (value == HeatLevel.NONE) {
return BoilerHeater.NO_HEAT;
}
if (value == HeatLevel.SEETHING) {
return 2;
}
if (value.isAtLeast(HeatLevel.FADING)) {
return 1;
}
return BoilerHeater.PASSIVE_HEAT;
} }
} }

View file

@ -1,6 +1,6 @@
package com.simibubi.create.content.fluids.tank; package com.simibubi.create.content.fluids.tank;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour; import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;

View file

@ -2,6 +2,7 @@ package com.simibubi.create.content.kinetics.base;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import com.simibubi.create.AllTags.AllBlockTags;
import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.BlockHelper;
import net.createmod.catnip.math.VecHelper; import net.createmod.catnip.math.VecHelper;
@ -132,7 +133,7 @@ public abstract class BlockBreakingKineticBlockEntity extends KineticBlockEntity
} }
public static boolean isBreakable(BlockState stateToBreak, float blockHardness) { public static boolean isBreakable(BlockState stateToBreak, float blockHardness) {
return !(stateToBreak.liquid() || stateToBreak.getBlock() instanceof AirBlock || blockHardness == -1); return !(stateToBreak.liquid() || stateToBreak.getBlock() instanceof AirBlock || blockHardness == -1 || AllBlockTags.NON_BREAKABLE.matches(stateToBreak));
} }
public void onBlockBroken(BlockState stateToBreak) { public void onBlockBroken(BlockState stateToBreak) {

View file

@ -1,8 +1,8 @@
package com.simibubi.create.content.kinetics.base; package com.simibubi.create.content.kinetics.base;
import com.simibubi.create.api.behaviour.movement.MovementBehaviour;
import com.simibubi.create.content.contraptions.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.OrientedContraptionEntity; import com.simibubi.create.content.contraptions.OrientedContraptionEntity;
import com.simibubi.create.content.contraptions.behaviour.MovementBehaviour;
import com.simibubi.create.content.contraptions.behaviour.MovementContext; import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.simibubi.create.content.contraptions.mounted.MountedContraption; import com.simibubi.create.content.contraptions.mounted.MountedContraption;
import com.simibubi.create.content.trains.entity.CarriageContraption; import com.simibubi.create.content.trains.entity.CarriageContraption;

View file

@ -2,7 +2,7 @@ package com.simibubi.create.content.kinetics.belt.transport;
import java.util.Random; import java.util.Random;
import com.simibubi.create.AllRegistries; import com.simibubi.create.api.registry.CreateBuiltInRegistries;
import com.simibubi.create.content.kinetics.belt.BeltHelper; import com.simibubi.create.content.kinetics.belt.BeltHelper;
import com.simibubi.create.content.kinetics.fan.processing.AllFanProcessingTypes; import com.simibubi.create.content.kinetics.fan.processing.AllFanProcessingTypes;
import com.simibubi.create.content.kinetics.fan.processing.FanProcessingType; import com.simibubi.create.content.kinetics.fan.processing.FanProcessingType;
@ -82,8 +82,8 @@ public class TransportedItemStack implements Comparable<TransportedItemStack> {
nbt.putInt("Angle", angle); nbt.putInt("Angle", angle);
nbt.putInt("InDirection", insertedFrom.get3DDataValue()); nbt.putInt("InDirection", insertedFrom.get3DDataValue());
if (processedBy != null && processedBy != AllFanProcessingTypes.NONE) { if (processedBy != null) {
ResourceLocation key = AllRegistries.FAN_PROCESSING_TYPE.getKey(processedBy); ResourceLocation key = CreateBuiltInRegistries.FAN_PROCESSING_TYPE.getKey(processedBy);
if (key == null) if (key == null)
throw new IllegalArgumentException("Could not get id for FanProcessingType " + processedBy + "!"); throw new IllegalArgumentException("Could not get id for FanProcessingType " + processedBy + "!");

Some files were not shown because too many files have changed in this diff Show more