diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index 7050f3c44..506607afc 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -566,7 +566,7 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo 7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json 3054a5519fbf91481b0c9c8160a20679fa9530da assets/create/lang/en_ud.json -8db7da2dab7745aa409e536d7a36cbe9fcce21a4 assets/create/lang/en_us.json +093dfa9846e481071cd27239b4d66760848b160e assets/create/lang/en_us.json 487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json 3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json diff --git a/src/generated/resources/assets/create/lang/en_us.json b/src/generated/resources/assets/create/lang/en_us.json index ec960fbc1..ae444941a 100644 --- a/src/generated/resources/assets/create/lang/en_us.json +++ b/src/generated/resources/assets/create/lang/en_us.json @@ -1654,6 +1654,20 @@ "create.contraption.controls.actor_toggle.on": "On", "create.contraption.controls.actor_toggle.off": "Off", "create.contraption.controls.floor_unreachable": "Unreachable", + "create.contraption.door_control": "Onboard Door Control", + "create.contraption.door_control.all": "Open All Doors", + "create.contraption.door_control.all.short": "Open All", + "create.contraption.door_control.north": "North Side Only", + "create.contraption.door_control.north.short": "North", + "create.contraption.door_control.east": "East Side Only", + "create.contraption.door_control.east.short": "East", + "create.contraption.door_control.south": "South Side Only", + "create.contraption.door_control.south.short": "South", + "create.contraption.door_control.west": "West Side Only", + "create.contraption.door_control.west.short": "West", + "create.contraption.door_control.none": "Keep Doors Closed", + "create.contraption.door_control.none.short": "None", + "create.contraption.door_control.player_facing": "You are facing: %1$s", "create.display_link.set": "Targeted position selected", "create.display_link.success": "Successfully bound to targeted position", diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DoorControl.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DoorControl.java new file mode 100644 index 000000000..f6cf7af1d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DoorControl.java @@ -0,0 +1,76 @@ +package com.simibubi.create.content.contraptions.components.actors; + +import java.util.Arrays; +import java.util.function.Consumer; + +import com.simibubi.create.foundation.gui.widget.Label; +import com.simibubi.create.foundation.gui.widget.ScrollInput; +import com.simibubi.create.foundation.gui.widget.SelectionScrollInput; +import com.simibubi.create.foundation.utility.Components; +import com.simibubi.create.foundation.utility.Lang; +import com.simibubi.create.foundation.utility.Pair; + +import net.minecraft.client.Minecraft; +import net.minecraft.core.Direction; +import net.minecraft.world.entity.Entity; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public enum DoorControl { + + ALL, NORTH, EAST, SOUTH, WEST, NONE; + + private static String[] valuesAsString() { + DoorControl[] values = values(); + return Arrays.stream(values) + .map(dc -> Lang.asId(dc.name())) + .toList() + .toArray(new String[values.length]); + } + + public boolean matches(Direction doorDirection) { + return switch (this) { + case ALL -> true; + case NORTH -> doorDirection == Direction.NORTH; + case EAST -> doorDirection == Direction.EAST; + case SOUTH -> doorDirection == Direction.SOUTH; + case WEST -> doorDirection == Direction.WEST; + default -> false; + }; + } + + @OnlyIn(Dist.CLIENT) + public static Pair createWidget(int x, int y, Consumer callback, + DoorControl initial) { + + DoorControl playerFacing = NONE; + Entity cameraEntity = Minecraft.getInstance().cameraEntity; + if (cameraEntity != null) { + Direction direction = cameraEntity.getDirection(); + if (direction == Direction.EAST) + playerFacing = EAST; + if (direction == Direction.WEST) + playerFacing = WEST; + if (direction == Direction.NORTH) + playerFacing = NORTH; + if (direction == Direction.SOUTH) + playerFacing = SOUTH; + } + + Label label = new Label(x + 4, y + 6, Components.empty()).withShadow(); + ScrollInput input = new SelectionScrollInput(x, y, 53, 16) + .forOptions(Lang.translatedOptions("contraption.door_control", valuesAsString())) + .titled(Lang.translateDirect("contraption.door_control")) + .calling(s -> { + DoorControl mode = values()[s]; + label.text = Lang.translateDirect("contraption.door_control." + Lang.asId(mode.name()) + ".short"); + callback.accept(mode); + }) + .addHint(Lang.translateDirect("contraption.door_control.player_facing", + Lang.translateDirect("contraption.door_control." + Lang.asId(playerFacing.name()) + ".short"))) + .setState(initial.ordinal()); + input.onChanged(); + return Pair.of(input, label); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/DoorControlBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DoorControlBehaviour.java new file mode 100644 index 000000000..df25f85d2 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/DoorControlBehaviour.java @@ -0,0 +1,45 @@ +package com.simibubi.create.content.contraptions.components.actors; + +import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour; +import com.simibubi.create.foundation.blockEntity.SmartBlockEntity; +import com.simibubi.create.foundation.blockEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.utility.NBTHelper; + +import net.minecraft.nbt.CompoundTag; + +public class DoorControlBehaviour extends BlockEntityBehaviour { + + public static final BehaviourType TYPE = new BehaviourType<>(); + + public DoorControl mode; + + public DoorControlBehaviour(SmartBlockEntity be) { + super(be); + mode = DoorControl.ALL; + } + + public void set(DoorControl mode) { + if (this.mode == mode) + return; + this.mode = mode; + blockEntity.notifyUpdate(); + } + + @Override + public void write(CompoundTag nbt, boolean clientPacket) { + NBTHelper.writeEnum(nbt, "DoorControl", mode); + super.write(nbt, clientPacket); + } + + @Override + public void read(CompoundTag nbt, boolean clientPacket) { + mode = NBTHelper.readEnum(nbt, "DoorControl", DoorControl.class); + super.read(nbt, clientPacket); + } + + @Override + public BehaviourType getType() { + return TYPE; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/elevator/ElevatorContactBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/elevator/ElevatorContactBlock.java index 931f09a15..319ef50e0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/elevator/ElevatorContactBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/elevator/ElevatorContactBlock.java @@ -212,7 +212,8 @@ public class ElevatorContactBlock extends WrenchableDirectionalBlock @OnlyIn(value = Dist.CLIENT) protected void displayScreen(ElevatorContactBlockEntity be, Player player) { if (player instanceof LocalPlayer) - ScreenOpener.open(new ElevatorContactScreen(be.getBlockPos(), be.shortName, be.longName)); + ScreenOpener + .open(new ElevatorContactScreen(be.getBlockPos(), be.shortName, be.longName, be.doorControls.mode)); } public static int getLight(BlockState state) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/elevator/ElevatorContactBlockEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/elevator/ElevatorContactBlockEntity.java index 93d992fc8..f46f67bf4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/elevator/ElevatorContactBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/elevator/ElevatorContactBlockEntity.java @@ -2,6 +2,7 @@ package com.simibubi.create.content.contraptions.components.structureMovement.el import java.util.List; +import com.simibubi.create.content.contraptions.components.actors.DoorControlBehaviour; import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorColumn.ColumnCoords; import com.simibubi.create.content.logistics.block.display.DisplayLinkBlock; import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour; @@ -16,6 +17,7 @@ import net.minecraft.world.level.block.state.BlockState; public class ElevatorContactBlockEntity extends SmartBlockEntity { + public DoorControlBehaviour doorControls; public ColumnCoords columnCoords; public boolean activateBlock; @@ -35,7 +37,9 @@ public class ElevatorContactBlockEntity extends SmartBlockEntity { } @Override - public void addBehaviours(List behaviours) {} + public void addBehaviours(List behaviours) { + behaviours.add(doorControls = new DoorControlBehaviour(this)); + } @Override protected void write(CompoundTag tag, boolean clientPacket) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/elevator/ElevatorContactEditPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/elevator/ElevatorContactEditPacket.java index 8407c5ba3..6011ef81e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/elevator/ElevatorContactEditPacket.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/elevator/ElevatorContactEditPacket.java @@ -1,40 +1,47 @@ package com.simibubi.create.content.contraptions.components.structureMovement.elevator; +import com.simibubi.create.content.contraptions.components.actors.DoorControl; import com.simibubi.create.foundation.networking.BlockEntityConfigurationPacket; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.util.Mth; public class ElevatorContactEditPacket extends BlockEntityConfigurationPacket { private String shortName; private String longName; + private DoorControl doorControl; - public ElevatorContactEditPacket(BlockPos pos, String shortName, String longName) { + public ElevatorContactEditPacket(BlockPos pos, String shortName, String longName, DoorControl doorControl) { super(pos); this.shortName = shortName; this.longName = longName; + this.doorControl = doorControl; } - + public ElevatorContactEditPacket(FriendlyByteBuf buffer) { super(buffer); } - + @Override protected void writeSettings(FriendlyByteBuf buffer) { buffer.writeUtf(shortName, 4); buffer.writeUtf(longName, 30); + buffer.writeVarInt(doorControl.ordinal()); } @Override protected void readSettings(FriendlyByteBuf buffer) { shortName = buffer.readUtf(4); longName = buffer.readUtf(30); + doorControl = DoorControl.values()[Mth.clamp(buffer.readVarInt(), 0, DoorControl.values().length)]; } @Override protected void applySettings(ElevatorContactBlockEntity be) { be.updateName(shortName, longName); + be.doorControls.set(doorControl); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/elevator/ElevatorContactScreen.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/elevator/ElevatorContactScreen.java index 31e712eb1..10cdb1a9c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/elevator/ElevatorContactScreen.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/elevator/ElevatorContactScreen.java @@ -5,15 +5,19 @@ import org.lwjgl.glfw.GLFW; import com.google.common.collect.ImmutableList; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.components.actors.DoorControl; import com.simibubi.create.foundation.gui.AbstractSimiScreen; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.gui.AllIcons; import com.simibubi.create.foundation.gui.element.GuiGameElement; import com.simibubi.create.foundation.gui.widget.IconButton; +import com.simibubi.create.foundation.gui.widget.Label; +import com.simibubi.create.foundation.gui.widget.ScrollInput; import com.simibubi.create.foundation.gui.widget.TooltipArea; import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.Components; import com.simibubi.create.foundation.utility.Lang; +import com.simibubi.create.foundation.utility.Pair; import net.minecraft.ChatFormatting; import net.minecraft.client.gui.components.EditBox; @@ -31,12 +35,14 @@ public class ElevatorContactScreen extends AbstractSimiScreen { private String shortName; private String longName; + private DoorControl doorControl; private BlockPos pos; - public ElevatorContactScreen(BlockPos pos, String prevShortName, String prevLongName) { + public ElevatorContactScreen(BlockPos pos, String prevShortName, String prevLongName, DoorControl prevDoorControl) { super(Lang.translateDirect("elevator_contact.title")); this.pos = pos; + this.doorControl = prevDoorControl; background = AllGuiTextures.ELEVATOR_CONTACT; this.shortName = prevShortName; this.longName = prevLongName; @@ -88,6 +94,10 @@ public class ElevatorContactScreen extends AbstractSimiScreen { .component(), rmbToEdit))); + Pair doorControlWidgets = + DoorControl.createWidget(x + 58, y + 57, mode -> doorControl = mode, doorControl); + addRenderableWidget(doorControlWidgets.getFirst()); + addRenderableWidget(doorControlWidgets.getSecond()); } private int centerInput(int x) { @@ -122,6 +132,7 @@ public class ElevatorContactScreen extends AbstractSimiScreen { .scale(5) .render(ms); + itemRenderer.renderGuiItem(AllBlocks.TRAIN_DOOR.asStack(), x + 37, y + 58); } @Override @@ -164,7 +175,8 @@ public class ElevatorContactScreen extends AbstractSimiScreen { } private void confirm() { - AllPackets.getChannel().sendToServer(new ElevatorContactEditPacket(pos, shortName, longName)); + AllPackets.getChannel() + .sendToServer(new ElevatorContactEditPacket(pos, shortName, longName, doorControl)); onClose(); } diff --git a/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorMovementBehaviour.java b/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorMovementBehaviour.java index 8ea99ade6..b8e08bc8e 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorMovementBehaviour.java @@ -1,23 +1,37 @@ package com.simibubi.create.content.curiosities.deco; +import java.lang.ref.WeakReference; import java.util.Map; +import com.simibubi.create.content.contraptions.components.actors.DoorControl; +import com.simibubi.create.content.contraptions.components.actors.DoorControlBehaviour; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; +import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorColumn; +import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorColumn.ColumnCoords; import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorContraption; +import com.simibubi.create.content.logistics.trains.entity.Carriage; import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity; -import com.simibubi.create.content.logistics.trains.entity.CarriageSyncData; +import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation; +import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour; import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Direction.AxisDirection; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; +import net.minecraft.world.level.Level; import net.minecraft.world.level.block.DoorBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; +import net.minecraft.world.phys.Vec3; public class SlidingDoorMovementBehaviour implements MovementBehaviour { @@ -25,12 +39,12 @@ public class SlidingDoorMovementBehaviour implements MovementBehaviour { public boolean renderAsNormalBlockEntity() { return true; } - + @Override public boolean mustTickWhileDisabled() { return true; } - + @Override public void tick(MovementContext context) { StructureBlockInfo structureBlockInfo = context.contraption.getBlocks() @@ -43,7 +57,7 @@ public class SlidingDoorMovementBehaviour implements MovementBehaviour { tickOpen(context, open); Map tes = context.contraption.presentBlockEntities; - if (!(tes.get(context.localPos) instanceof SlidingDoorBlockEntity doorTE)) + if (!(tes.get(context.localPos)instanceof SlidingDoorBlockEntity doorTE)) return; boolean wasSettled = doorTE.animation.settled(); doorTE.animation.chase(open ? 1 : 0, .15f, Chaser.LINEAR); @@ -105,14 +119,90 @@ public class SlidingDoorMovementBehaviour implements MovementBehaviour { protected boolean shouldOpen(MovementContext context) { if (context.disabled) return false; - if (context.contraption instanceof ElevatorContraption ec && ec.arrived) - return true; - if (context.contraption.entity instanceof CarriageContraptionEntity cce) { - CarriageSyncData carriageData = cce.getCarriageData(); - if (Math.abs(carriageData.distanceToDestination) > 1) - return false; + Contraption contraption = context.contraption; + boolean canOpen = context.motion.length() < 1 / 128f && !contraption.entity.isStalled() + || contraption instanceof ElevatorContraption ec && ec.arrived; + + if (!canOpen) { + context.temporaryData = null; + return false; } - return context.motion.length() < 1 / 128f && !context.contraption.entity.isStalled(); + + if (context.temporaryData instanceof WeakReference wr && wr.get()instanceof DoorControlBehaviour dcb) + if (dcb.blockEntity != null && !dcb.blockEntity.isRemoved()) + return shouldOpenAt(dcb, context); + + context.temporaryData = null; + DoorControlBehaviour doorControls = null; + + if (contraption instanceof ElevatorContraption ec) + doorControls = getElevatorDoorControl(ec, context); + if (context.contraption.entity instanceof CarriageContraptionEntity cce) + doorControls = getTrainStationDoorControl(cce, context); + + if (doorControls == null) + return false; + + context.temporaryData = new WeakReference<>(doorControls); + return shouldOpenAt(doorControls, context); + } + + protected boolean shouldOpenAt(DoorControlBehaviour controller, MovementContext context) { + if (controller.mode == DoorControl.ALL) + return true; + if (controller.mode == DoorControl.NONE) + return false; + return controller.mode.matches(getDoorFacing(context)); + } + + protected DoorControlBehaviour getElevatorDoorControl(ElevatorContraption ec, MovementContext context) { + Integer currentTargetY = ec.getCurrentTargetY(context.world); + if (currentTargetY == null) + return null; + ColumnCoords columnCoords = ec.getGlobalColumn(); + if (columnCoords == null) + return null; + ElevatorColumn elevatorColumn = ElevatorColumn.get(context.world, columnCoords); + if (elevatorColumn == null) + return null; + return BlockEntityBehaviour.get(context.world, elevatorColumn.contactAt(currentTargetY), + DoorControlBehaviour.TYPE); + } + + protected DoorControlBehaviour getTrainStationDoorControl(CarriageContraptionEntity cce, MovementContext context) { + Carriage carriage = cce.getCarriage(); + if (carriage == null || carriage.train == null) + return null; + GlobalStation currentStation = carriage.train.getCurrentStation(); + if (currentStation == null) + return null; + + BlockPos stationPos = currentStation.getBlockEntityPos(); + ResourceKey stationDim = currentStation.getBlockEntityDimension(); + MinecraftServer server = context.world.getServer(); + if (server == null) + return null; + ServerLevel stationLevel = server.getLevel(stationDim); + if (stationLevel == null || !stationLevel.isLoaded(stationPos)) + return null; + return BlockEntityBehaviour.get(stationLevel, stationPos, DoorControlBehaviour.TYPE); + } + + protected Direction getDoorFacing(MovementContext context) { + Direction stateFacing = context.state.getValue(DoorBlock.FACING); + Direction originalFacing = Direction.get(AxisDirection.POSITIVE, stateFacing.getAxis()); + Vec3 centerOfContraption = context.contraption.bounds.getCenter(); + Vec3 diff = Vec3.atCenterOf(context.localPos) + .add(Vec3.atLowerCornerOf(stateFacing.getNormal()) + .scale(-.45f)) + .subtract(centerOfContraption); + if (originalFacing.getAxis() + .choose(diff.x, diff.y, diff.z) < 0) + originalFacing = originalFacing.getOpposite(); + + Vec3 directionVec = Vec3.atLowerCornerOf(originalFacing.getNormal()); + directionVec = context.rotation.apply(directionVec); + return Direction.getNearest(directionVec.x, directionVec.y, directionVec.z); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AssemblyScreen.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AssemblyScreen.java index 81e19290d..82ce98601 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AssemblyScreen.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AssemblyScreen.java @@ -65,14 +65,16 @@ public class AssemblyScreen extends AbstractStationScreen { toggleAssemblyButton.active = false; toggleAssemblyButton.setToolTip(Lang.translateDirect("station.assemble_train")); toggleAssemblyButton.withCallback(() -> { - AllPackets.getChannel().sendToServer(StationEditPacket.tryAssemble(blockEntity.getBlockPos())); + AllPackets.getChannel() + .sendToServer(StationEditPacket.tryAssemble(blockEntity.getBlockPos())); }); quitAssembly = new IconButton(x + 73, by, AllIcons.I_DISABLE); quitAssembly.active = true; quitAssembly.setToolTip(Lang.translateDirect("station.cancel")); quitAssembly.withCallback(() -> { - AllPackets.getChannel().sendToServer(StationEditPacket.configure(blockEntity.getBlockPos(), false, station.name)); + AllPackets.getChannel() + .sendToServer(StationEditPacket.configure(blockEntity.getBlockPos(), false, station.name, null)); minecraft.setScreen(new StationScreen(blockEntity, station)); }); @@ -90,7 +92,8 @@ public class AssemblyScreen extends AbstractStationScreen { toggleAssemblyButton.active = blockEntity.bogeyCount > 0 || train != null; if (train != null) { - AllPackets.getChannel().sendToServer(StationEditPacket.configure(blockEntity.getBlockPos(), false, station.name)); + AllPackets.getChannel() + .sendToServer(StationEditPacket.configure(blockEntity.getBlockPos(), false, station.name, null)); minecraft.setScreen(new StationScreen(blockEntity, station)); for (Carriage carriage : train.carriages) carriage.updateConductors(); @@ -105,10 +108,12 @@ public class AssemblyScreen extends AbstractStationScreen { toggleAssemblyButton.setToolTip(Lang.translateDirect("station.assemble_train")); toggleAssemblyButton.setIcon(AllGuiTextures.I_ASSEMBLE_TRAIN); toggleAssemblyButton.withCallback(() -> { - AllPackets.getChannel().sendToServer(StationEditPacket.tryAssemble(blockEntity.getBlockPos())); + AllPackets.getChannel() + .sendToServer(StationEditPacket.tryAssemble(blockEntity.getBlockPos())); }); } else { - AllPackets.getChannel().sendToServer(StationEditPacket.configure(blockEntity.getBlockPos(), false, station.name)); + AllPackets.getChannel() + .sendToServer(StationEditPacket.configure(blockEntity.getBlockPos(), false, station.name, null)); minecraft.setScreen(new StationScreen(blockEntity, station)); } } @@ -128,8 +133,8 @@ public class AssemblyScreen extends AbstractStationScreen { font.draw(ms, text, x + 97 - font.width(text) / 2, y + 47, 0x775B5B); int offset = 0; if (blockEntity.failedCarriageIndex != -1) { - font.draw(ms, Lang.translateDirect("station.carriage_number", blockEntity.failedCarriageIndex), x + 30, y + 67, - 0x7A7A7A); + font.draw(ms, Lang.translateDirect("station.carriage_number", blockEntity.failedCarriageIndex), x + 30, + y + 67, 0x7A7A7A); offset += 10; } font.drawWordWrap(lastAssemblyException.component, x + 30, y + 67 + offset, 134, 0x775B5B); @@ -158,7 +163,8 @@ public class AssemblyScreen extends AbstractStationScreen { if (train != null) { ResourceLocation iconId = iconTypes.get(iconTypeScroll.getState()); train.icon = TrainIconType.byId(iconId); - AllPackets.getChannel().sendToServer(new TrainEditPacket(train.id, "", iconId)); + AllPackets.getChannel() + .sendToServer(new TrainEditPacket(train.id, "", iconId)); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationBlockEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationBlockEntity.java index 54457b894..f2d76cbc6 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationBlockEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationBlockEntity.java @@ -16,6 +16,7 @@ import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.AllSoundEvents; import com.simibubi.create.Create; +import com.simibubi.create.content.contraptions.components.actors.DoorControlBehaviour; import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlockEntity; import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; @@ -80,6 +81,7 @@ import net.minecraftforge.network.PacketDistributor; public class StationBlockEntity extends SmartBlockEntity implements ITransformableBlockEntity { public TrackTargetingBehaviour edgePoint; + public DoorControlBehaviour doorControls; public LerpedFloat flag; protected int failedCarriageIndex; @@ -111,6 +113,7 @@ public class StationBlockEntity extends SmartBlockEntity implements ITransformab @Override public void addBehaviours(List behaviours) { behaviours.add(edgePoint = new TrackTargetingBehaviour<>(this, EdgePointType.STATION)); + behaviours.add(doorControls = new DoorControlBehaviour(this)); behaviours.add(depotBehaviour = new DepotBehaviour(this).onlyAccepts(AllItems.SCHEDULE::isIn) .withCallback(s -> applyAutoSchedule())); depotBehaviour.addSubBehaviours(behaviours); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationEditPacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationEditPacket.java index e90c10f0f..5f545f510 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationEditPacket.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationEditPacket.java @@ -1,6 +1,7 @@ package com.simibubi.create.content.logistics.trains.management.edgePoint.station; import com.simibubi.create.Create; +import com.simibubi.create.content.contraptions.components.actors.DoorControl; import com.simibubi.create.content.logistics.trains.GraphLocation; import com.simibubi.create.content.logistics.trains.entity.Train; import com.simibubi.create.foundation.networking.BlockEntityConfigurationPacket; @@ -9,6 +10,7 @@ import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.Mth; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; @@ -20,6 +22,7 @@ public class StationEditPacket extends BlockEntityConfigurationPacket AllPackets.getChannel().sendToServer(StationEditPacket.dropSchedule(blockEntity.getBlockPos()))); + dropScheduleButton.withCallback(() -> AllPackets.getChannel() + .sendToServer(StationEditPacket.dropSchedule(blockEntity.getBlockPos()))); addRenderableWidget(dropScheduleButton); onTextChanged = s -> trainNameBox.x = nameBoxX(s, trainNameBox); @@ -103,6 +110,11 @@ public class StationScreen extends AbstractStationScreen { trainNameBox.active = false; tickTrainDisplay(); + + Pair doorControlWidgets = + DoorControl.createWidget(x + 35, y + 102, mode -> doorControl = mode, doorControl); + addRenderableWidget(doorControlWidgets.getFirst()); + addRenderableWidget(doorControlWidgets.getSecond()); } @Override @@ -192,12 +204,13 @@ public class StationScreen extends AbstractStationScreen { } boolean trainAtStation = trainPresent(); - disassembleTrainButton.active = trainAtStation && blockEntity.trainCanDisassemble && blockEntity.edgePoint.isOrthogonal(); + disassembleTrainButton.active = + trainAtStation && blockEntity.trainCanDisassemble && blockEntity.edgePoint.isOrthogonal(); dropScheduleButton.active = blockEntity.trainHasSchedule; if (blockEntity.trainHasSchedule) - dropScheduleButton.setToolTip( - Lang.translateDirect(blockEntity.trainHasAutoSchedule ? "station.remove_auto_schedule" : "station.remove_schedule")); + dropScheduleButton.setToolTip(Lang.translateDirect( + blockEntity.trainHasAutoSchedule ? "station.remove_auto_schedule" : "station.remove_schedule")); else dropScheduleButton.getToolTip() .clear(); @@ -237,6 +250,8 @@ public class StationScreen extends AbstractStationScreen { if (!nameBox.isFocused()) AllGuiTextures.STATION_EDIT_NAME.render(ms, nameBoxX(text, nameBox) + font.width(text) + 5, y + 1); + itemRenderer.renderGuiItem(AllBlocks.TRAIN_DOOR.asStack(), x + 14, y + 103); + Train train = displayedTrain.get(); if (train == null) { MutableComponent header = Lang.translateDirect("station.idle"); @@ -333,32 +348,38 @@ public class StationScreen extends AbstractStationScreen { Train train = displayedTrain.get(); if (train != null && !trainNameBox.getValue() .equals(train.name.getString())) - AllPackets.getChannel().sendToServer(new TrainEditPacket(train.id, trainNameBox.getValue(), train.icon.getId())); + AllPackets.getChannel() + .sendToServer(new TrainEditPacket(train.id, trainNameBox.getValue(), train.icon.getId())); } private void syncStationName() { if (!nameBox.getValue() .equals(station.name)) - AllPackets.getChannel().sendToServer(StationEditPacket.configure(blockEntity.getBlockPos(), false, nameBox.getValue())); + AllPackets.getChannel() + .sendToServer( + StationEditPacket.configure(blockEntity.getBlockPos(), false, nameBox.getValue(), doorControl)); } @Override public void removed() { super.removed(); AllPackets.getChannel() - .sendToServer(StationEditPacket.configure(blockEntity.getBlockPos(), switchingToAssemblyMode, nameBox.getValue())); + .sendToServer(StationEditPacket.configure(blockEntity.getBlockPos(), switchingToAssemblyMode, + nameBox.getValue(), doorControl)); Train train = displayedTrain.get(); if (train == null) return; if (!switchingToAssemblyMode) - AllPackets.getChannel().sendToServer(new TrainEditPacket(train.id, trainNameBox.getValue(), train.icon.getId())); + AllPackets.getChannel() + .sendToServer(new TrainEditPacket(train.id, trainNameBox.getValue(), train.icon.getId())); else blockEntity.imminentTrain = null; } @Override protected PartialModel getFlag(float partialTicks) { - return blockEntity.flag.getValue(partialTicks) > 0.75f ? AllPartialModels.STATION_ON : AllPartialModels.STATION_OFF; + return blockEntity.flag.getValue(partialTicks) > 0.75f ? AllPartialModels.STATION_ON + : AllPartialModels.STATION_OFF; } } diff --git a/src/main/java/com/simibubi/create/foundation/gui/widget/AbstractSimiWidget.java b/src/main/java/com/simibubi/create/foundation/gui/widget/AbstractSimiWidget.java index 6d0d747c3..01a459aca 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/widget/AbstractSimiWidget.java +++ b/src/main/java/com/simibubi/create/foundation/gui/widget/AbstractSimiWidget.java @@ -17,6 +17,7 @@ import net.minecraft.network.chat.Component; public abstract class AbstractSimiWidget extends AbstractWidget implements TickableGuiEventListener { public static final int HEADER_RGB = 0x5391E1; + public static final int HINT_RGB = 0x96B7E0; protected float z; protected boolean wasHovered = false; diff --git a/src/main/java/com/simibubi/create/foundation/gui/widget/ScrollInput.java b/src/main/java/com/simibubi/create/foundation/gui/widget/ScrollInput.java index 6635db7a9..98a78ed5e 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/widget/ScrollInput.java +++ b/src/main/java/com/simibubi/create/foundation/gui/widget/ScrollInput.java @@ -22,6 +22,7 @@ public class ScrollInput extends AbstractSimiWidget { protected Component title = Lang.translateDirect("gui.scrollInput.defaultTitle"); protected final Component scrollToModify = Lang.translateDirect("gui.scrollInput.scrollToModify"); protected final Component shiftScrollsFaster = Lang.translateDirect("gui.scrollInput.shiftScrollsFaster"); + protected Component hint = null; protected Label displayLabel; protected boolean inverted; protected Function formatter; @@ -76,6 +77,12 @@ public class ScrollInput extends AbstractSimiWidget { return this; } + public ScrollInput addHint(MutableComponent hint) { + this.hint = hint; + updateTooltip(); + return this; + } + public ScrollInput withStepFunction(Function step) { this.step = step; return this; @@ -128,7 +135,10 @@ public class ScrollInput extends AbstractSimiWidget { clampState(); if (priorState != state) { - Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(AllSoundEvents.SCROLL_VALUE.getMainEvent(), 1.5f + 0.1f * (state-min)/(max-min))); + Minecraft.getInstance() + .getSoundManager() + .play(SimpleSoundInstance.forUI(AllSoundEvents.SCROLL_VALUE.getMainEvent(), + 1.5f + 0.1f * (state - min) / (max - min))); onChanged(); } @@ -160,6 +170,9 @@ public class ScrollInput extends AbstractSimiWidget { return; toolTip.add(title.plainCopy() .withStyle(s -> s.withColor(HEADER_RGB))); + if (hint != null) + toolTip.add(hint.plainCopy() + .withStyle(s -> s.withColor(HINT_RGB))); toolTip.add(scrollToModify.plainCopy() .withStyle(ChatFormatting.ITALIC, ChatFormatting.DARK_GRAY)); toolTip.add(shiftScrollsFaster.plainCopy() diff --git a/src/main/java/com/simibubi/create/foundation/gui/widget/SelectionScrollInput.java b/src/main/java/com/simibubi/create/foundation/gui/widget/SelectionScrollInput.java index 097f21b32..158175120 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/widget/SelectionScrollInput.java +++ b/src/main/java/com/simibubi/create/foundation/gui/widget/SelectionScrollInput.java @@ -43,7 +43,8 @@ public class SelectionScrollInput extends ScrollInput { if (this.min + 1 == min) min--; if (min > this.min) - toolTip.add(Components.literal("> ...").withStyle(ChatFormatting.GRAY)); + toolTip.add(Components.literal("> ...") + .withStyle(ChatFormatting.GRAY)); if (this.max - 1 == max) max++; for (int i = min; i < max; i++) { @@ -59,8 +60,12 @@ public class SelectionScrollInput extends ScrollInput { .withStyle(ChatFormatting.GRAY)); } if (max < this.max) - toolTip.add(Components.literal("> ...").withStyle(ChatFormatting.GRAY)); + toolTip.add(Components.literal("> ...") + .withStyle(ChatFormatting.GRAY)); + if (hint != null) + toolTip.add(hint.plainCopy() + .withStyle(s -> s.withColor(HINT_RGB))); toolTip.add(scrollToSelect.plainCopy() .withStyle(ChatFormatting.DARK_GRAY, ChatFormatting.ITALIC)); } diff --git a/src/main/resources/assets/create/lang/default/interface.json b/src/main/resources/assets/create/lang/default/interface.json index 9e38399db..cffbf4879 100644 --- a/src/main/resources/assets/create/lang/default/interface.json +++ b/src/main/resources/assets/create/lang/default/interface.json @@ -814,6 +814,21 @@ "create.contraption.controls.actor_toggle.on": "On", "create.contraption.controls.actor_toggle.off": "Off", "create.contraption.controls.floor_unreachable": "Unreachable", + + "create.contraption.door_control": "Onboard Door Control", + "create.contraption.door_control.all": "Open All Doors", + "create.contraption.door_control.all.short": "Open All", + "create.contraption.door_control.north": "North Side Only", + "create.contraption.door_control.north.short": "North", + "create.contraption.door_control.east": "East Side Only", + "create.contraption.door_control.east.short": "East", + "create.contraption.door_control.south": "South Side Only", + "create.contraption.door_control.south.short": "South", + "create.contraption.door_control.west": "West Side Only", + "create.contraption.door_control.west.short": "West", + "create.contraption.door_control.none": "Keep Doors Closed", + "create.contraption.door_control.none.short": "None", + "create.contraption.door_control.player_facing": "You are facing: %1$s", "create.display_link.set": "Targeted position selected", "create.display_link.success": "Successfully bound to targeted position", diff --git a/src/main/resources/assets/create/textures/gui/display_link.png b/src/main/resources/assets/create/textures/gui/display_link.png index 216ab336a..14a18c49e 100644 Binary files a/src/main/resources/assets/create/textures/gui/display_link.png and b/src/main/resources/assets/create/textures/gui/display_link.png differ diff --git a/src/main/resources/assets/create/textures/gui/schedule_2.png b/src/main/resources/assets/create/textures/gui/schedule_2.png index aca4d1fe8..ef60c2f16 100644 Binary files a/src/main/resources/assets/create/textures/gui/schedule_2.png and b/src/main/resources/assets/create/textures/gui/schedule_2.png differ