Add api to add custom conductors to trains

This commit is contained in:
agnor99 2024-10-06 18:31:50 +02:00
parent aa15182005
commit d37b37964b
5 changed files with 97 additions and 23 deletions

View file

@ -3,6 +3,9 @@ package com.simibubi.create;
import static com.simibubi.create.AllInteractionBehaviours.interactionBehaviour; import static com.simibubi.create.AllInteractionBehaviours.interactionBehaviour;
import static com.simibubi.create.AllMovementBehaviours.movementBehaviour; import static com.simibubi.create.AllMovementBehaviours.movementBehaviour;
import static com.simibubi.create.Create.REGISTRATE; import static com.simibubi.create.Create.REGISTRATE;
import com.simibubi.create.api.contraption.train.TrainConductorHandler;
import static com.simibubi.create.content.redstone.displayLink.AllDisplayBehaviours.assignDataBehaviour; import static com.simibubi.create.content.redstone.displayLink.AllDisplayBehaviours.assignDataBehaviour;
import static com.simibubi.create.foundation.data.BlockStateGen.axisBlock; import static com.simibubi.create.foundation.data.BlockStateGen.axisBlock;
import static com.simibubi.create.foundation.data.BlockStateGen.simpleCubeAll; import static com.simibubi.create.foundation.data.BlockStateGen.simpleCubeAll;
@ -185,7 +188,7 @@ import com.simibubi.create.content.processing.basin.BasinGenerator;
import com.simibubi.create.content.processing.basin.BasinMovementBehaviour; import com.simibubi.create.content.processing.basin.BasinMovementBehaviour;
import com.simibubi.create.content.processing.burner.BlazeBurnerBlock; import com.simibubi.create.content.processing.burner.BlazeBurnerBlock;
import com.simibubi.create.content.processing.burner.BlazeBurnerBlockItem; import com.simibubi.create.content.processing.burner.BlazeBurnerBlockItem;
import com.simibubi.create.content.processing.burner.BlazeBurnerInteractionBehaviour; import com.simibubi.create.content.processing.burner.BlockBasedTrainConductorInteractionBehaviour;
import com.simibubi.create.content.processing.burner.BlazeBurnerMovementBehaviour; import com.simibubi.create.content.processing.burner.BlazeBurnerMovementBehaviour;
import com.simibubi.create.content.processing.burner.LitBlazeBurnerBlock; import com.simibubi.create.content.processing.burner.LitBlazeBurnerBlock;
import com.simibubi.create.content.redstone.RoseQuartzLampBlock; import com.simibubi.create.content.redstone.RoseQuartzLampBlock;
@ -708,7 +711,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(interactionBehaviour(new BlazeBurnerInteractionBehaviour())) .onRegister(block -> TrainConductorHandler.registerBlazeBurner())
.item(BlazeBurnerBlockItem::withBlaze) .item(BlazeBurnerBlockItem::withBlaze)
.model(AssetLookup.customBlockItemModel("blaze_burner", "block_with_blaze")) .model(AssetLookup.customBlockItemModel("blaze_burner", "block_with_blaze"))
.build() .build()

View file

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

View file

@ -2,10 +2,10 @@ package com.simibubi.create.content.processing.burner;
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.contraptions.behaviour.MovingInteractionBehaviour;
import com.simibubi.create.content.processing.burner.BlazeBurnerBlock.HeatLevel;
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;
@ -21,9 +21,21 @@ import net.minecraft.core.Direction;
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.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
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.StructureBlockInfo; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
public class BlazeBurnerInteractionBehaviour extends MovingInteractionBehaviour { import java.util.function.Predicate;
public class BlockBasedTrainConductorInteractionBehaviour extends MovingInteractionBehaviour {
private final Predicate<BlockState> isValidConductor;
private final TrainConductorHandler.UpdateScheduleCallback callback;
public BlockBasedTrainConductorInteractionBehaviour(Predicate<BlockState> isValidConductor, TrainConductorHandler.UpdateScheduleCallback callback) {
this.isValidConductor = isValidConductor;
this.callback = callback;
}
@Override @Override
public boolean handlePlayerInteraction(Player player, InteractionHand activeHand, BlockPos localPos, public boolean handlePlayerInteraction(Player player, InteractionHand activeHand, BlockPos localPos,
@ -40,8 +52,7 @@ public class BlazeBurnerInteractionBehaviour extends MovingInteractionBehaviour
StructureBlockInfo info = carriageContraption.getBlocks() StructureBlockInfo info = carriageContraption.getBlocks()
.get(localPos); .get(localPos);
if (info == null || !info.state().hasProperty(BlazeBurnerBlock.HEAT_LEVEL) if (info == null || !isValidConductor.test(info.state()))
|| info.state().getValue(BlazeBurnerBlock.HEAT_LEVEL) == HeatLevel.NONE)
return false; return false;
Direction assemblyDirection = carriageContraption.getAssemblyDirection(); Direction assemblyDirection = carriageContraption.getAssemblyDirection();
@ -74,6 +85,7 @@ public class BlazeBurnerInteractionBehaviour extends MovingInteractionBehaviour
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.setItemInHand(activeHand, train.runtime.returnSchedule());
callback.update(false, info.state(), newBlockState -> setBlockState(localPos, contraptionEntity, newBlockState));
return true; return true;
} }
@ -89,7 +101,7 @@ public class BlazeBurnerInteractionBehaviour extends MovingInteractionBehaviour
player.displayClientMessage(Lang.translateDirect("schedule.no_stops"), true); player.displayClientMessage(Lang.translateDirect("schedule.no_stops"), true);
return true; return true;
} }
callback.update(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);
@ -105,4 +117,10 @@ public class BlazeBurnerInteractionBehaviour extends MovingInteractionBehaviour
return true; return true;
} }
private void setBlockState(BlockPos localPos, AbstractContraptionEntity contraption, BlockState newState) {
StructureTemplate.StructureBlockInfo info = contraption.getContraption().getBlocks().get(localPos);
if (info != null) {
setContraptionBlockData(contraption, localPos, new StructureTemplate.StructureBlockInfo(info.pos(), newState, info.nbt()));
}
}
} }

View file

@ -7,6 +7,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import com.simibubi.create.api.contraption.train.TrainConductorHandler;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
@ -17,8 +19,6 @@ import com.simibubi.create.content.contraptions.ContraptionType;
import com.simibubi.create.content.contraptions.MountedStorageManager; import com.simibubi.create.content.contraptions.MountedStorageManager;
import com.simibubi.create.content.contraptions.actors.trainControls.ControlsBlock; import com.simibubi.create.content.contraptions.actors.trainControls.ControlsBlock;
import com.simibubi.create.content.contraptions.minecart.TrainCargoManager; import com.simibubi.create.content.contraptions.minecart.TrainCargoManager;
import com.simibubi.create.content.processing.burner.BlazeBurnerBlock;
import com.simibubi.create.content.processing.burner.BlazeBurnerBlock.HeatLevel;
import com.simibubi.create.content.trains.bogey.AbstractBogeyBlock; import com.simibubi.create.content.trains.bogey.AbstractBogeyBlock;
import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
@ -51,7 +51,7 @@ public class CarriageContraption extends Contraption {
private boolean forwardControls; private boolean forwardControls;
private boolean backwardControls; private boolean backwardControls;
public Couple<Boolean> blazeBurnerConductors; public Couple<Boolean> blockConductors;
public Map<BlockPos, Couple<Boolean>> conductorSeats; public Map<BlockPos, Couple<Boolean>> conductorSeats;
public ArrivalSoundQueue soundQueue; public ArrivalSoundQueue soundQueue;
@ -61,7 +61,7 @@ public class CarriageContraption extends Contraption {
private int bogeys; private int bogeys;
private boolean sidewaysControls; private boolean sidewaysControls;
private BlockPos secondBogeyPos; private BlockPos secondBogeyPos;
private List<BlockPos> assembledBlazeBurners; private List<BlockPos> assembledBlockConductors;
// render // render
public int portalCutoffMin; public int portalCutoffMin;
@ -72,8 +72,8 @@ public class CarriageContraption extends Contraption {
public CarriageContraption() { public CarriageContraption() {
conductorSeats = new HashMap<>(); conductorSeats = new HashMap<>();
assembledBlazeBurners = new ArrayList<>(); assembledBlockConductors = new ArrayList<>();
blazeBurnerConductors = Couple.create(false, false); blockConductors = Couple.create(false, false);
soundQueue = new ArrivalSoundQueue(); soundQueue = new ArrivalSoundQueue();
portalCutoffMin = Integer.MIN_VALUE; portalCutoffMin = Integer.MIN_VALUE;
portalCutoffMax = Integer.MAX_VALUE; portalCutoffMax = Integer.MAX_VALUE;
@ -103,10 +103,10 @@ public class CarriageContraption extends Contraption {
if (sidewaysControls) if (sidewaysControls)
throw new AssemblyException(Lang.translateDirect("train_assembly.sideways_controls")); throw new AssemblyException(Lang.translateDirect("train_assembly.sideways_controls"));
for (BlockPos blazePos : assembledBlazeBurners) for (BlockPos blazePos : assembledBlockConductors)
for (Direction direction : Iterate.directionsInAxis(assemblyDirection.getAxis())) for (Direction direction : Iterate.directionsInAxis(assemblyDirection.getAxis()))
if (inControl(blazePos, direction)) if (inControl(blazePos, direction))
blazeBurnerConductors.set(direction != assemblyDirection, true); blockConductors.set(direction != assemblyDirection, true);
for (BlockPos seatPos : getSeats()) for (BlockPos seatPos : getSeats())
for (Direction direction : Iterate.directionsInAxis(assemblyDirection.getAxis())) for (Direction direction : Iterate.directionsInAxis(assemblyDirection.getAxis()))
if (inControl(seatPos, direction)) if (inControl(seatPos, direction))
@ -166,9 +166,8 @@ public class CarriageContraption extends Contraption {
captureBE ? world.getBlockEntity(pos) : null); captureBE ? world.getBlockEntity(pos) : null);
} }
if (AllBlocks.BLAZE_BURNER.has(blockState) if (TrainConductorHandler.CONDUCTOR_HANDLERS.stream().anyMatch(handler -> handler.isValidConductor(blockState)))
&& blockState.getValue(BlazeBurnerBlock.HEAT_LEVEL) != HeatLevel.NONE) assembledBlockConductors.add(toLocalPos(pos));
assembledBlazeBurners.add(toLocalPos(pos));
if (AllBlocks.TRAIN_CONTROLS.has(blockState)) { if (AllBlocks.TRAIN_CONTROLS.has(blockState)) {
Direction facing = blockState.getValue(ControlsBlock.FACING); Direction facing = blockState.getValue(ControlsBlock.FACING);
@ -192,8 +191,8 @@ public class CarriageContraption extends Contraption {
NBTHelper.writeEnum(tag, "AssemblyDirection", getAssemblyDirection()); NBTHelper.writeEnum(tag, "AssemblyDirection", getAssemblyDirection());
tag.putBoolean("FrontControls", forwardControls); tag.putBoolean("FrontControls", forwardControls);
tag.putBoolean("BackControls", backwardControls); tag.putBoolean("BackControls", backwardControls);
tag.putBoolean("FrontBlazeConductor", blazeBurnerConductors.getFirst()); tag.putBoolean("FrontBlazeConductor", blockConductors.getFirst());
tag.putBoolean("BackBlazeConductor", blazeBurnerConductors.getSecond()); tag.putBoolean("BackBlazeConductor", blockConductors.getSecond());
ListTag list = NBTHelper.writeCompoundList(conductorSeats.entrySet(), e -> { ListTag list = NBTHelper.writeCompoundList(conductorSeats.entrySet(), e -> {
CompoundTag compoundTag = new CompoundTag(); CompoundTag compoundTag = new CompoundTag();
compoundTag.put("Pos", NbtUtils.writeBlockPos(e.getKey())); compoundTag.put("Pos", NbtUtils.writeBlockPos(e.getKey()));
@ -213,7 +212,7 @@ public class CarriageContraption extends Contraption {
assemblyDirection = NBTHelper.readEnum(nbt, "AssemblyDirection", Direction.class); assemblyDirection = NBTHelper.readEnum(nbt, "AssemblyDirection", Direction.class);
forwardControls = nbt.getBoolean("FrontControls"); forwardControls = nbt.getBoolean("FrontControls");
backwardControls = nbt.getBoolean("BackControls"); backwardControls = nbt.getBoolean("BackControls");
blazeBurnerConductors = blockConductors =
Couple.create(nbt.getBoolean("FrontBlazeConductor"), nbt.getBoolean("BackBlazeConductor")); Couple.create(nbt.getBoolean("FrontBlazeConductor"), nbt.getBoolean("BackBlazeConductor"));
conductorSeats.clear(); conductorSeats.clear();
NBTHelper.iterateCompoundList(nbt.getList("ConductorSeats", Tag.TAG_COMPOUND), NBTHelper.iterateCompoundList(nbt.getList("ConductorSeats", Tag.TAG_COMPOUND),

View file

@ -492,8 +492,8 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
if (!(contraption instanceof CarriageContraption cc)) if (!(contraption instanceof CarriageContraption cc))
return sides; return sides;
sides.setFirst(cc.blazeBurnerConductors.getFirst()); sides.setFirst(cc.blockConductors.getFirst());
sides.setSecond(cc.blazeBurnerConductors.getSecond()); sides.setSecond(cc.blockConductors.getSecond());
for (Entity entity : getPassengers()) { for (Entity entity : getPassengers()) {
if (entity instanceof Player) if (entity instanceof Player)