diff --git a/src/main/java/com/simibubi/create/CreateClient.java b/src/main/java/com/simibubi/create/CreateClient.java index 4d04b9c97..b5c6f2a9d 100644 --- a/src/main/java/com/simibubi/create/CreateClient.java +++ b/src/main/java/com/simibubi/create/CreateClient.java @@ -2,6 +2,7 @@ package com.simibubi.create; import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueSelectionHandler; +import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.TrainHUD; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; import com.simibubi.create.content.contraptions.components.structureMovement.render.SBBContraptionManager; import com.simibubi.create.content.contraptions.goggles.GoggleOverlayRenderer; @@ -102,6 +103,7 @@ public class CreateClient { private static void registerOverlays() { // Register overlays in reverse order OverlayRegistry.registerOverlayAbove(ForgeIngameGui.AIR_LEVEL_ELEMENT, "Create's Remaining Air", CopperBacktankArmorLayer.REMAINING_AIR_OVERLAY); + OverlayRegistry.registerOverlayAbove(ForgeIngameGui.EXPERIENCE_BAR_ELEMENT, "Create's Train Driver HUD", TrainHUD.OVERLAY); OverlayRegistry.registerOverlayAbove(ForgeIngameGui.HOTBAR_ELEMENT, "Create's Toolboxes", ToolboxHandlerClient.OVERLAY); OverlayRegistry.registerOverlayAbove(ForgeIngameGui.HOTBAR_ELEMENT, "Create's Goggle Information", GoggleOverlayRenderer.OVERLAY); OverlayRegistry.registerOverlayAbove(ForgeIngameGui.HOTBAR_ELEMENT, "Create's Blueprints", BlueprintOverlayRenderer.OVERLAY); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsHandler.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsHandler.java index 405485ff7..1da4473a5 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsHandler.java @@ -106,11 +106,11 @@ public class ControlsHandler { // Keepalive Pressed Keys if (packetCooldown == 0) { - if (!pressedKeys.isEmpty()) { +// if (!pressedKeys.isEmpty()) { AllPackets.channel .sendToServer(new ControlsInputPacket(pressedKeys, true, entity.getId(), controlsPos, false)); packetCooldown = PACKET_RATE; - } +// } } currentlyPressed = pressedKeys; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/TrainHUD.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/TrainHUD.java new file mode 100644 index 000000000..4803ffed0 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/TrainHUD.java @@ -0,0 +1,153 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls; + +import com.mojang.blaze3d.vertex.PoseStack; +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.Train; +import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.gui.AllGuiTextures; +import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.animation.LerpedFloat; +import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser; +import com.simibubi.create.foundation.utility.placement.PlacementHelpers; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; +import net.minecraftforge.client.gui.ForgeIngameGui; +import net.minecraftforge.client.gui.IIngameOverlay; + +public class TrainHUD { + + public static final IIngameOverlay OVERLAY = TrainHUD::renderOverlay; + + static LerpedFloat displayedSpeed = LerpedFloat.linear(); + static LerpedFloat displayedThrottle = LerpedFloat.linear(); + + static Double editedThrottle = null; + static int hudPacketCooldown = 5; + + public static void tick() { + Carriage carriage = getCarriage(); + if (carriage == null) + return; + + Train train = carriage.train; + double value = + Math.abs(train.speed) / (train.maxSpeed() * AllConfigs.SERVER.trains.manualTrainSpeedModifier.getF()); + value = Mth.clamp(value + 0.05f, 0, 1); + displayedSpeed.chase((int) (value * 18) / 18f, .5f, Chaser.EXP); + displayedSpeed.tickChaser(); + displayedThrottle.chase(editedThrottle != null ? editedThrottle : train.throttle, .75f, Chaser.EXP); + displayedThrottle.tickChaser(); + + if (editedThrottle == null) + return; + if (Mth.equal(editedThrottle, train.throttle)) { + editedThrottle = null; + hudPacketCooldown = 5; + return; + } + + if (hudPacketCooldown-- > 0) + return; + AllPackets.channel.sendToServer(new TrainHUDUpdatePacket.Serverbound(train, editedThrottle)); + hudPacketCooldown = 5; + } + + private static Carriage getCarriage() { + if (!(ControlsHandler.entityRef.get() instanceof CarriageContraptionEntity cce)) + return null; + return cce.getCarriage(); + } + + public static void renderOverlay(ForgeIngameGui gui, PoseStack poseStack, float partialTicks, int width, + int height) { + if (!(ControlsHandler.entityRef.get() instanceof CarriageContraptionEntity cce)) + return; + Carriage carriage = cce.getCarriage(); + if (carriage == null) + return; + Entity cameraEntity = Minecraft.getInstance() + .getCameraEntity(); + if (cameraEntity == null) + return; + BlockPos localPos = ControlsHandler.controlsPos; + if (localPos == null) + return; + + poseStack.pushPose(); + poseStack.translate(width / 2 - 91, height - 29, 0); + + // Speed, Throttle + + AllGuiTextures.TRAIN_HUD_FRAME.render(poseStack, -2, 1); + AllGuiTextures.TRAIN_HUD_SPEED_BG.render(poseStack, 0, 0); + + int w = (int) (AllGuiTextures.TRAIN_HUD_SPEED.width * displayedSpeed.getValue(partialTicks)); + int h = AllGuiTextures.TRAIN_HUD_SPEED.height; + + AllGuiTextures.TRAIN_HUD_SPEED.bind(); + GuiComponent.blit(poseStack, 0, 0, 0, AllGuiTextures.TRAIN_HUD_SPEED.startX, + AllGuiTextures.TRAIN_HUD_SPEED.startY, w, h, 256, 256); + + AllGuiTextures.TRAIN_HUD_DIRECTION.render(poseStack, 77, -20); + + w = (int) (AllGuiTextures.TRAIN_HUD_THROTTLE.width * (1 - displayedThrottle.getValue(partialTicks))); + AllGuiTextures.TRAIN_HUD_THROTTLE.bind(); + int invW = AllGuiTextures.TRAIN_HUD_THROTTLE.width - w; + GuiComponent.blit(poseStack, invW, 0, 0, AllGuiTextures.TRAIN_HUD_THROTTLE.startX + invW, + AllGuiTextures.TRAIN_HUD_THROTTLE.startY, w, h, 256, 256); + AllGuiTextures.TRAIN_HUD_THROTTLE_POINTER.render(poseStack, + Math.max(1, AllGuiTextures.TRAIN_HUD_THROTTLE.width - w) - 3, -2); + + // Direction + + StructureBlockInfo info = cce.getContraption() + .getBlocks() + .get(localPos); + Direction initialOrientation = cce.getInitialOrientation() + .getCounterClockWise(); + boolean inverted = false; + if (info != null && info.state.hasProperty(ControlsBlock.FACING)) + inverted = !info.state.getValue(ControlsBlock.FACING) + .equals(initialOrientation); + + boolean reversing = ControlsHandler.currentlyPressed.contains(1); + inverted ^= reversing; + int angleOffset = (ControlsHandler.currentlyPressed.contains(2) ? -45 : 0) + + (ControlsHandler.currentlyPressed.contains(3) ? 45 : 0); + if (reversing) + angleOffset *= -1; + + float snapSize = 22.5f; + float diff = AngleHelper.getShortestAngleDiff(cameraEntity.getYRot(), cce.yaw) + (inverted ? -90 : 90); + if (Math.abs(diff) < 60) + diff = 0; + + float angle = diff + angleOffset; + float snappedAngle = (snapSize * Math.round(angle / snapSize)) % 360f; + + poseStack.translate(91, -9, 0); + poseStack.scale(0.925f, 0.925f, 1); + PlacementHelpers.textured(poseStack, 0, 0, 1, snappedAngle); + + poseStack.popPose(); + } + + public static boolean onScroll(double delta) { + Carriage carriage = getCarriage(); + if (carriage == null) + return false; + + double prevThrottle = editedThrottle == null ? carriage.train.throttle : editedThrottle; + editedThrottle = Mth.clamp(prevThrottle + (delta > 0 ? 1 : -1) / 18f, 1 / 18f, 1); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/TrainHUDUpdatePacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/TrainHUDUpdatePacket.java new file mode 100644 index 000000000..d70180213 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/TrainHUDUpdatePacket.java @@ -0,0 +1,82 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls; + +import java.util.UUID; +import java.util.function.Supplier; + +import com.simibubi.create.Create; +import com.simibubi.create.content.logistics.trains.entity.Train; +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraftforge.network.NetworkEvent.Context; + +public class TrainHUDUpdatePacket extends SimplePacketBase { + + UUID trainId; + + Double throttle; + double speed; + int fuelTicks; + + public TrainHUDUpdatePacket() {} + + public TrainHUDUpdatePacket(Train train) { + trainId = train.id; + throttle = train.throttle; + speed = train.speedBeforeStall == null ? train.speed : train.speedBeforeStall; + fuelTicks = train.fuelTicks; + } + + public TrainHUDUpdatePacket(FriendlyByteBuf buffer) { + trainId = buffer.readUUID(); + if (buffer.readBoolean()) + throttle = buffer.readDouble(); + speed = buffer.readDouble(); + fuelTicks = buffer.readInt(); + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeUUID(trainId); + buffer.writeBoolean(throttle != null); + if (throttle != null) + buffer.writeDouble(throttle); + buffer.writeDouble(speed); + buffer.writeInt(fuelTicks); + } + + @Override + public void handle(Supplier context) { + Context c = context.get(); + c.enqueueWork(() -> { + ServerPlayer sender = c.getSender(); + boolean clientSide = sender == null; + Train train = Create.RAILWAYS.sided(clientSide ? null : sender.level).trains.get(trainId); + if (train == null) + return; + + if (throttle != null) + train.throttle = throttle; + if (clientSide) { + train.speed = speed; + train.fuelTicks = fuelTicks; + } + + }); + c.setPacketHandled(true); + } + + public static class Serverbound extends TrainHUDUpdatePacket { + + public Serverbound(FriendlyByteBuf buffer) { + super(buffer); + } + + public Serverbound(Train train, Double sendThrottle) { + trainId = train.id; + throttle = sendThrottle; + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java index 026d36477..a62be655f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java @@ -11,7 +11,6 @@ import java.util.UUID; import javax.annotation.Nullable; import com.google.common.base.Strings; -import com.jozufozu.flywheel.repack.joml.Math; import com.simibubi.create.AllEntityDataSerializers; import com.simibubi.create.AllEntityTypes; import com.simibubi.create.Create; @@ -21,6 +20,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Mov import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsBlock; +import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.TrainHUDUpdatePacket; import com.simibubi.create.content.contraptions.particle.CubeParticleData; import com.simibubi.create.content.logistics.trains.TrackGraph; import com.simibubi.create.content.logistics.trains.entity.Carriage.DimensionalCarriageEntity; @@ -45,6 +45,7 @@ import net.minecraft.network.chat.TextComponent; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; @@ -279,7 +280,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity { if (sounds == null) sounds = new CarriageSounds(this); sounds.tick(dce); - + if (particles == null) particles = new CarriageParticles(this); particles.tick(dce); @@ -503,6 +504,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity { } double navDistanceTotal = 0; + int hudPacketCooldown = 0; @Override public boolean control(BlockPos controlsLocalPos, Collection heldControls, Player player) { @@ -527,6 +529,11 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity { inverted = !info.state.getValue(ControlsBlock.FACING) .equals(initialOrientation); + if (hudPacketCooldown-- <= 0 && player instanceof ServerPlayer sp) { + AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> sp), new TrainHUDUpdatePacket(carriage.train)); + hudPacketCooldown = 5; + } + int targetSpeed = 0; if (heldControls.contains(0)) targetSpeed++; @@ -584,6 +591,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity { int targetColor = arrived ? 0x00_91EA44 : 0x00_ffffff; player.displayClientMessage(greenComponent.withStyle(st -> st.withColor(mixedColor)) .append(whiteComponent.withStyle(st -> st.withColor(targetColor))), true); + carriage.train.manualTick = true; return true; } } @@ -609,14 +617,15 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity { targetSteer < 0 ? SteerDirection.RIGHT : targetSteer > 0 ? SteerDirection.LEFT : SteerDirection.NONE; double topSpeed = carriage.train.maxSpeed() * AllConfigs.SERVER.trains.manualTrainSpeedModifier.getF(); + double cappedTopSpeed = topSpeed * carriage.train.throttle; if (carriage.getLeadingPoint().edge != null && carriage.getLeadingPoint().edge.isTurn() || carriage.getTrailingPoint().edge != null && carriage.getTrailingPoint().edge.isTurn()) topSpeed = carriage.train.maxTurnSpeed(); - carriage.train.targetSpeed = topSpeed * targetSpeed; if (slow) - carriage.train.targetSpeed /= 6; + topSpeed /= 4; + carriage.train.targetSpeed = Math.min(topSpeed, cappedTopSpeed) * targetSpeed; boolean counteringAcceleration = Math.abs(Math.signum(targetSpeed) - Math.signum(carriage.train.speed)) > 1.5f; carriage.train.manualTick = true; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java index e772b435f..c7557a931 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java @@ -17,7 +17,6 @@ import javax.annotation.Nullable; import org.apache.commons.lang3.mutable.MutableDouble; import org.apache.commons.lang3.mutable.MutableObject; -import com.jozufozu.flywheel.repack.joml.Math; import com.simibubi.create.Create; import com.simibubi.create.content.logistics.trains.DimensionPalette; import com.simibubi.create.content.logistics.trains.TrackEdge; @@ -158,8 +157,8 @@ public class Navigation { boolean primary = entering.equals(signal.groups.getFirst()); boolean crossSignal = signal.types.get(primary) == SignalType.CROSS_SIGNAL; - boolean occupied = - signal.isForcedRed(nodes.getSecond()) || signalEdgeGroup.isOccupiedUnless(train); + boolean occupied = !train.manualTick + && (signal.isForcedRed(nodes.getSecond()) || signalEdgeGroup.isOccupiedUnless(train)); if (!crossSignalTracked) { if (crossSignal) { // Now entering cross signal path @@ -244,7 +243,6 @@ public class Navigation { train.burnFuel(); double topSpeed = train.maxSpeed(); - double turnTopSpeed = train.maxTurnSpeed(); if (targetDistance < 10) { double target = topSpeed * ((targetDistance) / 10); @@ -253,6 +251,9 @@ public class Navigation { return; } } + + topSpeed *= train.throttle; + double turnTopSpeed = Math.min(topSpeed, train.maxTurnSpeed()); double targetSpeed = targetDistance > brakingDistance ? topSpeed * speedMod : 0; @@ -279,6 +280,8 @@ public class Navigation { } private boolean currentSignalResolved() { + if (train.manualTick) + return true; if (distanceToDestination < .5f) return true; SignalBoundary signal = train.graph.getPoint(EdgePointType.SIGNAL, waitingForSignal.getFirst()); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java index 41f860d99..11c237443 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java @@ -77,6 +77,9 @@ public class Train { public double speed = 0; public double targetSpeed = 0; public Double speedBeforeStall = null; + + public double throttle = 1; + public boolean honk = false; public UUID id; public UUID owner; @@ -886,15 +889,16 @@ public class Train { } public void approachTargetSpeed(float accelerationMod) { - if (Mth.equal(targetSpeed, speed)) + double actualTarget = targetSpeed; + if (Mth.equal(actualTarget, speed)) return; if (manualTick) leaveStation(); double acceleration = acceleration(); - if (speed < targetSpeed) - speed = Math.min(speed + acceleration * accelerationMod, targetSpeed); - else if (speed > targetSpeed) - speed = Math.max(speed - acceleration * accelerationMod, targetSpeed); + if (speed < actualTarget) + speed = Math.min(speed + acceleration * accelerationMod, actualTarget); + else if (speed > actualTarget) + speed = Math.max(speed - acceleration * accelerationMod, actualTarget); } public void collectInitiallyOccupiedSignalBlocks() { @@ -1060,6 +1064,7 @@ public class Train { tag.putIntArray("CarriageSpacing", carriageSpacing); tag.putBoolean("DoubleEnded", doubleEnded); tag.putDouble("Speed", speed); + tag.putDouble("Throttle", throttle); if (speedBeforeStall != null) tag.putDouble("SpeedBeforeStall", speedBeforeStall); tag.putInt("Fuel", fuelTicks); @@ -1113,6 +1118,7 @@ public class Train { Train train = new Train(id, owner, graph, carriages, carriageSpacing, doubleEnded); train.speed = tag.getDouble("Speed"); + train.throttle = tag.getDouble("Throttle"); if (tag.contains("SpeedBeforeStall")) train.speedBeforeStall = tag.getDouble("SpeedBeforeStall"); train.targetSpeed = tag.getDouble("TargetSpeed"); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackRemoval.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackRemoval.java deleted file mode 100644 index d629b6598..000000000 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackRemoval.java +++ /dev/null @@ -1,139 +0,0 @@ -package com.simibubi.create.content.logistics.trains.track; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import com.simibubi.create.AllItems; -import com.simibubi.create.content.logistics.trains.ITrackBlock; -import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation; -import com.simibubi.create.content.logistics.trains.entity.TrainRelocator; -import com.simibubi.create.foundation.networking.AllPackets; - -import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.TextComponent; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.HitResult.Type; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -public class TrackRemoval { - - static BlockPos startPos; - static BlockPos hoveringPos; - static Set toRemove; - - // TODO localisation - - public static void sneakWrenched(BlockPos pos) { - LocalPlayer player = Minecraft.getInstance().player; - if (startPos != null) { - startPos = null; - player.displayClientMessage(new TextComponent("Track removal aborted").withStyle(ChatFormatting.RED), true); - return; - } - startPos = pos; - } - - public static void wrenched(BlockPos pos) { - if (startPos == null || hoveringPos == null || toRemove == null) - return; - if (TrainRelocator.isRelocating()) - return; - AllPackets.channel.sendToServer(new TrackRemovalPacket(toRemove)); - startPos = null; - } - - @OnlyIn(Dist.CLIENT) - public static void clientTick() { - if (startPos == null) - return; - - LocalPlayer player = Minecraft.getInstance().player; - ItemStack stack = player.getMainHandItem(); - HitResult hitResult = Minecraft.getInstance().hitResult; - - if (hitResult == null) - return; - if (hitResult.getType() != Type.BLOCK) - return; - - if (!AllItems.WRENCH.isIn(stack)) { - hoveringPos = null; - startPos = null; - player.displayClientMessage(new TextComponent("Track removal aborted").withStyle(ChatFormatting.RED), true); - return; - } - - BlockHitResult result = (BlockHitResult) hitResult; - BlockPos blockPos = result.getBlockPos(); - Level level = player.level; - BlockState blockState = level.getBlockState(blockPos); - if (!(blockState.getBlock()instanceof ITrackBlock track)) { - player.displayClientMessage(new TextComponent("Select a second track piece, Unequip Wrench to abort"), - true); - return; - } - - if (blockPos.equals(hoveringPos)) { - if (hoveringPos.equals(startPos)) { - player.displayClientMessage( - new TextComponent("Starting point selected. Right-Click a second Track piece"), true); - } else if (toRemove == null) { - player.displayClientMessage(new TextComponent("Starting point not reachable, Sneak-Click to abort") - .withStyle(ChatFormatting.RED), true); - } else - player.displayClientMessage(new TextComponent("Right-Click to confirm").withStyle(ChatFormatting.GREEN), - true); - - // - - return; - } - - hoveringPos = blockPos; - toRemove = new HashSet<>(); - - List frontier = new ArrayList<>(); - Set visited = new HashSet<>(); - - if (search(level, hoveringPos, frontier, visited, 0)) { - toRemove.add(hoveringPos); - toRemove.add(startPos); - return; - } - - toRemove = null; - } - - private static boolean search(Level level, BlockPos pos, List frontier, Set visited, - int depth) { - if (pos.equals(startPos)) - return true; - if (depth > 32) - return false; - if (!visited.add(pos)) - return false; - BlockState blockState = level.getBlockState(pos); - if (!(blockState.getBlock()instanceof ITrackBlock track)) - return false; - for (DiscoveredLocation discoveredLocation : track.getConnected(level, pos, blockState, false, null)) { - for (BlockPos blockPos : discoveredLocation.allAdjacent()) { - if (!search(level, blockPos, frontier, visited, depth + 1)) - continue; - toRemove.add(pos); - return true; - } - } - return false; - } - -} diff --git a/src/main/java/com/simibubi/create/events/ClientEvents.java b/src/main/java/com/simibubi/create/events/ClientEvents.java index 073b27a43..b01cb5cea 100644 --- a/src/main/java/com/simibubi/create/events/ClientEvents.java +++ b/src/main/java/com/simibubi/create/events/ClientEvents.java @@ -16,6 +16,7 @@ import com.simibubi.create.content.contraptions.components.steam.SteamEngineBloc import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionHandler; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.ChassisRangeDisplay; import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsHandler; +import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.TrainHUD; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingHandlerClient; import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingPhysics; @@ -44,7 +45,6 @@ import com.simibubi.create.content.logistics.trains.management.schedule.TrainHat import com.simibubi.create.content.logistics.trains.track.CurvedTrackInteraction; import com.simibubi.create.content.logistics.trains.track.TrackBlockOutline; import com.simibubi.create.content.logistics.trains.track.TrackPlacement; -import com.simibubi.create.content.logistics.trains.track.TrackRemoval; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.config.ui.BaseConfigScreen; import com.simibubi.create.foundation.fluid.FluidHelper; @@ -164,11 +164,11 @@ public class ClientEvents { ToolboxHandlerClient.clientTick(); TrackTargetingClient.clientTick(); TrackPlacement.clientTick(); - TrackRemoval.clientTick(); TrainRelocator.clientTick(); DisplayLinkBlockItem.clientTick(); CurvedTrackInteraction.clientTick(); CameraDistanceModifier.tick(); + TrainHUD.tick(); } @SubscribeEvent diff --git a/src/main/java/com/simibubi/create/events/InputEvents.java b/src/main/java/com/simibubi/create/events/InputEvents.java index 25eb34b58..b40b720cd 100644 --- a/src/main/java/com/simibubi/create/events/InputEvents.java +++ b/src/main/java/com/simibubi/create/events/InputEvents.java @@ -1,6 +1,7 @@ package com.simibubi.create.events; import com.simibubi.create.CreateClient; +import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.TrainHUD; import com.simibubi.create.content.curiosities.toolbox.ToolboxHandlerClient; import com.simibubi.create.content.logistics.item.LinkedControllerClientHandler; import com.simibubi.create.content.logistics.trains.entity.TrainRelocator; @@ -42,7 +43,7 @@ public class InputEvents { // CollisionDebugger.onScroll(delta); boolean cancelled = CreateClient.SCHEMATIC_HANDLER.mouseScrolled(delta) || CreateClient.SCHEMATIC_AND_QUILL_HANDLER.mouseScrolled(delta) || FilteringHandler.onScroll(delta) - || ScrollValueHandler.onScroll(delta); + || ScrollValueHandler.onScroll(delta) || TrainHUD.onScroll(delta); event.setCanceled(cancelled); } diff --git a/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java b/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java index a5e172909..0b4f1b1dc 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java +++ b/src/main/java/com/simibubi/create/foundation/gui/AllGuiTextures.java @@ -161,6 +161,13 @@ public enum AllGuiTextures implements ScreenElement { SPEECH_TOOLTIP_BACKGROUND("widgets", 0, 24, 8, 8), SPEECH_TOOLTIP_COLOR("widgets", 8, 24, 8, 8), + + TRAIN_HUD_SPEED_BG("widgets", 0, 190, 182, 5), + TRAIN_HUD_SPEED("widgets", 0, 185, 182, 5), + TRAIN_HUD_THROTTLE("widgets", 0, 195, 182, 5), + TRAIN_HUD_THROTTLE_POINTER("widgets", 0, 209, 6, 9), + TRAIN_HUD_FRAME("widgets", 0, 200, 186, 7), + TRAIN_HUD_DIRECTION("widgets", 77, 165, 28, 20), // PlacementIndicator PLACEMENT_INDICATOR_SHEET("placement_indicator", 0, 0, 16, 256); diff --git a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java index b85e84673..f216ae966 100644 --- a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java +++ b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java @@ -18,6 +18,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.glu import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueSelectionPacket; import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsInputPacket; import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsStopControllingPacket; +import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.TrainHUDUpdatePacket; import com.simibubi.create.content.contraptions.components.structureMovement.sync.ClientMotionPacket; import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionFluidPacket; import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionInteractionPacket; @@ -94,7 +95,7 @@ public enum AllPackets { CONFIGURE_SCHEMATICANNON(ConfigureSchematicannonPacket.class, ConfigureSchematicannonPacket::new, PLAY_TO_SERVER), CONFIGURE_STOCKSWITCH(ConfigureStockswitchPacket.class, ConfigureStockswitchPacket::new, PLAY_TO_SERVER), CONFIGURE_SEQUENCER(ConfigureSequencedGearshiftPacket.class, ConfigureSequencedGearshiftPacket::new, - PLAY_TO_SERVER), + PLAY_TO_SERVER), PLACE_SCHEMATIC(SchematicPlacePacket.class, SchematicPlacePacket::new, PLAY_TO_SERVER), UPLOAD_SCHEMATIC(SchematicUploadPacket.class, SchematicUploadPacket::new, PLAY_TO_SERVER), CLEAR_CONTAINER(ClearContainerPacket.class, ClearContainerPacket::new, PLAY_TO_SERVER), @@ -114,10 +115,12 @@ public enum AllPackets { EJECTOR_ELYTRA(EjectorElytraPacket.class, EjectorElytraPacket::new, PLAY_TO_SERVER), LINKED_CONTROLLER_INPUT(LinkedControllerInputPacket.class, LinkedControllerInputPacket::new, PLAY_TO_SERVER), LINKED_CONTROLLER_BIND(LinkedControllerBindPacket.class, LinkedControllerBindPacket::new, PLAY_TO_SERVER), - LINKED_CONTROLLER_USE_LECTERN(LinkedControllerStopLecternPacket.class, LinkedControllerStopLecternPacket::new, PLAY_TO_SERVER), + LINKED_CONTROLLER_USE_LECTERN(LinkedControllerStopLecternPacket.class, LinkedControllerStopLecternPacket::new, + PLAY_TO_SERVER), C_CONFIGURE_CONFIG(CConfigureConfigPacket.class, CConfigureConfigPacket::new, PLAY_TO_SERVER), SUBMIT_GHOST_ITEM(GhostItemSubmitPacket.class, GhostItemSubmitPacket::new, PLAY_TO_SERVER), - BLUEPRINT_COMPLETE_RECIPE(BlueprintAssignCompleteRecipePacket.class, BlueprintAssignCompleteRecipePacket::new, PLAY_TO_SERVER), + BLUEPRINT_COMPLETE_RECIPE(BlueprintAssignCompleteRecipePacket.class, BlueprintAssignCompleteRecipePacket::new, + PLAY_TO_SERVER), CONFIGURE_SYMMETRY_WAND(ConfigureSymmetryWandPacket.class, ConfigureSymmetryWandPacket::new, PLAY_TO_SERVER), CONFIGURE_WORLDSHAPER(ConfigureWorldshaperPacket.class, ConfigureWorldshaperPacket::new, PLAY_TO_SERVER), TOOLBOX_EQUIP(ToolboxEquipPacket.class, ToolboxEquipPacket::new, PLAY_TO_SERVER), @@ -135,6 +138,7 @@ public enum AllPackets { GLUE_IN_AREA(SuperGlueSelectionPacket.class, SuperGlueSelectionPacket::new, PLAY_TO_SERVER), GLUE_REMOVED(SuperGlueRemovalPacket.class, SuperGlueRemovalPacket::new, PLAY_TO_SERVER), TRAIN_COLLISION(TrainCollisionPacket.class, TrainCollisionPacket::new, PLAY_TO_SERVER), + C_TRAIN_HUD(TrainHUDUpdatePacket.Serverbound.class, TrainHUDUpdatePacket.Serverbound::new, PLAY_TO_SERVER), // Server to Client SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new, PLAY_TO_CLIENT), @@ -156,14 +160,17 @@ public enum AllPackets { FUNNEL_FLAP(FunnelFlapPacket.class, FunnelFlapPacket::new, PLAY_TO_CLIENT), POTATO_CANNON(PotatoCannonPacket.class, PotatoCannonPacket::new, PLAY_TO_CLIENT), SOUL_PULSE(SoulPulseEffectPacket.class, SoulPulseEffectPacket::new, PLAY_TO_CLIENT), - PERSISTENT_DATA(ISyncPersistentData.PersistentDataPacket.class, ISyncPersistentData.PersistentDataPacket::new, PLAY_TO_CLIENT), - SYNC_POTATO_PROJECTILE_TYPES(PotatoProjectileTypeManager.SyncPacket.class, PotatoProjectileTypeManager.SyncPacket::new, PLAY_TO_CLIENT), + PERSISTENT_DATA(ISyncPersistentData.PersistentDataPacket.class, ISyncPersistentData.PersistentDataPacket::new, + PLAY_TO_CLIENT), + SYNC_POTATO_PROJECTILE_TYPES(PotatoProjectileTypeManager.SyncPacket.class, + PotatoProjectileTypeManager.SyncPacket::new, PLAY_TO_CLIENT), SYNC_RAIL_GRAPH(TrackGraphSyncPacket.class, TrackGraphSyncPacket::new, PLAY_TO_CLIENT), SYNC_EDGE_GROUP(SignalEdgeGroupPacket.class, SignalEdgeGroupPacket::new, PLAY_TO_CLIENT), SYNC_TRAIN(TrainPacket.class, TrainPacket::new, PLAY_TO_CLIENT), REMOVE_TE(RemoveTileEntityPacket.class, RemoveTileEntityPacket::new, PLAY_TO_CLIENT), S_CONFIGURE_TRAIN(TrainEditReturnPacket.class, TrainEditReturnPacket::new, PLAY_TO_CLIENT), CONTROLS_ABORT(ControlsStopControllingPacket.class, ControlsStopControllingPacket::new, PLAY_TO_CLIENT), + S_TRAIN_HUD(TrainHUDUpdatePacket.class, TrainHUDUpdatePacket::new, PLAY_TO_CLIENT), ; @@ -190,8 +197,9 @@ public enum AllPackets { } public static void sendToNear(Level world, BlockPos pos, int range, Object message) { - channel.send(PacketDistributor.NEAR - .with(TargetPoint.p(pos.getX(), pos.getY(), pos.getZ(), range, world.dimension())), message); + channel.send( + PacketDistributor.NEAR.with(TargetPoint.p(pos.getX(), pos.getY(), pos.getZ(), range, world.dimension())), + message); } private static class LoadedPacket { diff --git a/src/main/java/com/simibubi/create/foundation/utility/placement/PlacementHelpers.java b/src/main/java/com/simibubi/create/foundation/utility/placement/PlacementHelpers.java index afe1b427f..537ba31a4 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/placement/PlacementHelpers.java +++ b/src/main/java/com/simibubi/create/foundation/utility/placement/PlacementHelpers.java @@ -245,7 +245,7 @@ public class PlacementHelpers { ms.popPose(); } - private static void textured(PoseStack ms, float centerX, float centerY, float alpha, float snappedAngle) { + public static void textured(PoseStack ms, float centerX, float centerY, float alpha, float snappedAngle) { RenderSystem.enableTexture(); AllGuiTextures.PLACEMENT_INDICATOR_SHEET.bind(); RenderSystem.enableDepthTest(); diff --git a/src/main/resources/assets/create/textures/gui/widgets.png b/src/main/resources/assets/create/textures/gui/widgets.png index f51f71fc6..978685b26 100644 Binary files a/src/main/resources/assets/create/textures/gui/widgets.png and b/src/main/resources/assets/create/textures/gui/widgets.png differ