mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-11-18 16:02:19 +01:00
Central sta.. Tab, Enter.
- Added auto-completion functionality to schedules' destination editor
This commit is contained in:
parent
b85c0ed93f
commit
48dcf583c1
5 changed files with 202 additions and 22 deletions
|
@ -45,6 +45,8 @@ public class GlobalStation extends SingleTileEdgePoint {
|
||||||
super.read(buffer);
|
super.read(buffer);
|
||||||
name = buffer.readUtf();
|
name = buffer.readUtf();
|
||||||
assembling = buffer.readBoolean();
|
assembling = buffer.readBoolean();
|
||||||
|
if (buffer.readBoolean())
|
||||||
|
tilePos = buffer.readBlockPos();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -59,6 +61,9 @@ public class GlobalStation extends SingleTileEdgePoint {
|
||||||
super.write(buffer);
|
super.write(buffer);
|
||||||
buffer.writeUtf(name);
|
buffer.writeUtf(name);
|
||||||
buffer.writeBoolean(assembling);
|
buffer.writeBoolean(assembling);
|
||||||
|
buffer.writeBoolean(tilePos != null);
|
||||||
|
if (tilePos != null)
|
||||||
|
buffer.writeBlockPos(tilePos);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canApproachFrom(TrackNode side) {
|
public boolean canApproachFrom(TrackNode side) {
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
package com.simibubi.create.content.logistics.trains.management.schedule;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.context.StringRange;
|
||||||
|
import com.mojang.brigadier.suggestion.Suggestion;
|
||||||
|
import com.simibubi.create.foundation.utility.IntAttached;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.Font;
|
||||||
|
import net.minecraft.client.gui.components.CommandSuggestions;
|
||||||
|
import net.minecraft.client.gui.components.EditBox;
|
||||||
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
|
||||||
|
public class DestinationSuggestions extends CommandSuggestions {
|
||||||
|
|
||||||
|
private EditBox textBox;
|
||||||
|
private List<IntAttached<String>> viableStations;
|
||||||
|
private String previous = "<>";
|
||||||
|
private Font font;
|
||||||
|
private boolean active;
|
||||||
|
|
||||||
|
List<Suggestion> currentSuggestions;
|
||||||
|
private int yOffset;
|
||||||
|
|
||||||
|
public DestinationSuggestions(Minecraft pMinecraft, Screen pScreen, EditBox pInput, Font pFont,
|
||||||
|
List<IntAttached<String>> viableStations, int yOffset) {
|
||||||
|
super(pMinecraft, pScreen, pInput, pFont, true, true, 0, 7, false, 0xee_303030);
|
||||||
|
this.textBox = pInput;
|
||||||
|
this.font = pFont;
|
||||||
|
this.viableStations = viableStations;
|
||||||
|
this.yOffset = yOffset;
|
||||||
|
currentSuggestions = new ArrayList<>();
|
||||||
|
active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick() {
|
||||||
|
if (suggestions == null)
|
||||||
|
textBox.setSuggestion("");
|
||||||
|
if (active == textBox.isFocused())
|
||||||
|
return;
|
||||||
|
active = textBox.isFocused();
|
||||||
|
updateCommandInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateCommandInfo() {
|
||||||
|
String value = this.textBox.getValue();
|
||||||
|
if (value.equals(previous))
|
||||||
|
return;
|
||||||
|
if (!active) {
|
||||||
|
suggestions = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
previous = value;
|
||||||
|
currentSuggestions = viableStations.stream()
|
||||||
|
.filter(ia -> !ia.getValue()
|
||||||
|
.equals(value) && ia.getValue()
|
||||||
|
.toLowerCase()
|
||||||
|
.startsWith(value.toLowerCase()))
|
||||||
|
.sorted((ia1, ia2) -> Integer.compare(ia1.getFirst(), ia2.getFirst()))
|
||||||
|
.map(IntAttached::getValue)
|
||||||
|
.map(s -> new Suggestion(new StringRange(0, s.length()), s))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
showSuggestions(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showSuggestions(boolean pNarrateFirstSuggestion) {
|
||||||
|
if (currentSuggestions.isEmpty()) {
|
||||||
|
suggestions = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int width = 0;
|
||||||
|
for (Suggestion suggestion : currentSuggestions)
|
||||||
|
width = Math.max(width, this.font.width(suggestion.getText()));
|
||||||
|
int x = Mth.clamp(textBox.getScreenX(0), 0, textBox.getScreenX(0) + textBox.getInnerWidth() - width);
|
||||||
|
suggestions = new CommandSuggestions.SuggestionsList(x, 72 + yOffset, width, currentSuggestions, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,8 +2,11 @@ package com.simibubi.create.content.logistics.trains.management.schedule;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
@ -16,6 +19,11 @@ import com.mojang.blaze3d.platform.InputConstants;
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.math.Matrix4f;
|
import com.mojang.math.Matrix4f;
|
||||||
|
import com.simibubi.create.Create;
|
||||||
|
import com.simibubi.create.content.logistics.trains.GlobalRailwayManager;
|
||||||
|
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||||
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
||||||
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation;
|
||||||
import com.simibubi.create.content.logistics.trains.management.schedule.condition.ScheduleWaitCondition;
|
import com.simibubi.create.content.logistics.trains.management.schedule.condition.ScheduleWaitCondition;
|
||||||
import com.simibubi.create.content.logistics.trains.management.schedule.condition.ScheduledDelay;
|
import com.simibubi.create.content.logistics.trains.management.schedule.condition.ScheduledDelay;
|
||||||
import com.simibubi.create.content.logistics.trains.management.schedule.condition.TimedWaitCondition.TimeUnit;
|
import com.simibubi.create.content.logistics.trains.management.schedule.condition.TimedWaitCondition.TimeUnit;
|
||||||
|
@ -33,6 +41,7 @@ import com.simibubi.create.foundation.gui.widget.Indicator.State;
|
||||||
import com.simibubi.create.foundation.gui.widget.Label;
|
import com.simibubi.create.foundation.gui.widget.Label;
|
||||||
import com.simibubi.create.foundation.gui.widget.SelectionScrollInput;
|
import com.simibubi.create.foundation.gui.widget.SelectionScrollInput;
|
||||||
import com.simibubi.create.foundation.networking.AllPackets;
|
import com.simibubi.create.foundation.networking.AllPackets;
|
||||||
|
import com.simibubi.create.foundation.utility.IntAttached;
|
||||||
import com.simibubi.create.foundation.utility.Lang;
|
import com.simibubi.create.foundation.utility.Lang;
|
||||||
import com.simibubi.create.foundation.utility.Pair;
|
import com.simibubi.create.foundation.utility.Pair;
|
||||||
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
|
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
|
||||||
|
@ -53,6 +62,7 @@ import net.minecraft.util.Mth;
|
||||||
import net.minecraft.world.entity.player.Inventory;
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.Items;
|
import net.minecraft.world.item.Items;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
import net.minecraftforge.client.gui.GuiUtils;
|
import net.minecraftforge.client.gui.GuiUtils;
|
||||||
|
|
||||||
public class ScheduleScreen extends AbstractSimiContainerScreen<ScheduleContainer> {
|
public class ScheduleScreen extends AbstractSimiContainerScreen<ScheduleContainer> {
|
||||||
|
@ -84,6 +94,8 @@ public class ScheduleScreen extends AbstractSimiContainerScreen<ScheduleContaine
|
||||||
private List<Pair<GuiEventListener, BiConsumer<IScheduleInput, GuiEventListener>>> editorSubWidgets;
|
private List<Pair<GuiEventListener, BiConsumer<IScheduleInput, GuiEventListener>>> editorSubWidgets;
|
||||||
private List<Integer> editorDividers;
|
private List<Integer> editorDividers;
|
||||||
|
|
||||||
|
private DestinationSuggestions destinationSuggestions;
|
||||||
|
|
||||||
public ScheduleScreen(ScheduleContainer container, Inventory inv, Component title) {
|
public ScheduleScreen(ScheduleContainer container, Inventory inv, Component title) {
|
||||||
super(container, inv, title);
|
super(container, inv, title);
|
||||||
schedule = new Schedule();
|
schedule = new Schedule();
|
||||||
|
@ -225,6 +237,11 @@ public class ScheduleScreen extends AbstractSimiContainerScreen<ScheduleContaine
|
||||||
addRenderableWidget(editorDelete);
|
addRenderableWidget(editorDelete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onDestinationEdited(String text) {
|
||||||
|
if (destinationSuggestions != null)
|
||||||
|
destinationSuggestions.updateCommandInfo();
|
||||||
|
}
|
||||||
|
|
||||||
protected void stopEditing() {
|
protected void stopEditing() {
|
||||||
confirmButton.visible = true;
|
confirmButton.visible = true;
|
||||||
cyclicButton.visible = true;
|
cyclicButton.visible = true;
|
||||||
|
@ -235,6 +252,8 @@ public class ScheduleScreen extends AbstractSimiContainerScreen<ScheduleContaine
|
||||||
if (editingCondition == null && editingDestination == null)
|
if (editingCondition == null && editingDestination == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
destinationSuggestions = null;
|
||||||
|
|
||||||
removeWidget(scrollInput);
|
removeWidget(scrollInput);
|
||||||
removeWidget(scrollInputLabel);
|
removeWidget(scrollInputLabel);
|
||||||
removeWidget(editorConfirm);
|
removeWidget(editorConfirm);
|
||||||
|
@ -259,6 +278,7 @@ public class ScheduleScreen extends AbstractSimiContainerScreen<ScheduleContaine
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateEditorSubwidgets(IScheduleInput field) {
|
protected void updateEditorSubwidgets(IScheduleInput field) {
|
||||||
|
destinationSuggestions = null;
|
||||||
menu.targetSlotActive = field.needsSlot();
|
menu.targetSlotActive = field.needsSlot();
|
||||||
editorSubWidgets.forEach(p -> removeWidget(p.getFirst()));
|
editorSubWidgets.forEach(p -> removeWidget(p.getFirst()));
|
||||||
editorSubWidgets.clear();
|
editorSubWidgets.clear();
|
||||||
|
@ -268,6 +288,17 @@ public class ScheduleScreen extends AbstractSimiContainerScreen<ScheduleContaine
|
||||||
|
|
||||||
if (editorSubWidgets.isEmpty())
|
if (editorSubWidgets.isEmpty())
|
||||||
editorDividers = null;
|
editorDividers = null;
|
||||||
|
|
||||||
|
if (field instanceof DestinationInstruction) {
|
||||||
|
EditBox destinationBox = (EditBox) editorSubWidgets.get(0)
|
||||||
|
.getFirst();
|
||||||
|
destinationSuggestions = new DestinationSuggestions(this.minecraft, this, destinationBox, this.font,
|
||||||
|
getViableStations(field), topPos + 33);
|
||||||
|
destinationSuggestions.setAllowSuggestions(true);
|
||||||
|
destinationSuggestions.updateCommandInfo();
|
||||||
|
destinationBox.setResponder(this::onDestinationEdited);
|
||||||
|
}
|
||||||
|
|
||||||
editorSubWidgets.forEach(pair -> {
|
editorSubWidgets.forEach(pair -> {
|
||||||
GuiEventListener e = pair.getFirst();
|
GuiEventListener e = pair.getFirst();
|
||||||
if (e instanceof AbstractSimiWidget)
|
if (e instanceof AbstractSimiWidget)
|
||||||
|
@ -277,6 +308,42 @@ public class ScheduleScreen extends AbstractSimiContainerScreen<ScheduleContaine
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<IntAttached<String>> getViableStations(IScheduleInput field) {
|
||||||
|
GlobalRailwayManager railwayManager = Create.RAILWAYS.sided(null);
|
||||||
|
Set<TrackGraph> viableGraphs = new HashSet<>(railwayManager.trackNetworks.values());
|
||||||
|
|
||||||
|
for (ScheduleEntry entry : schedule.entries) {
|
||||||
|
if (!(entry.instruction instanceof DestinationInstruction destination))
|
||||||
|
continue;
|
||||||
|
if (destination == field)
|
||||||
|
continue;
|
||||||
|
String filter = destination.getFilter()
|
||||||
|
.replace("*", ".*");
|
||||||
|
if (filter.isBlank())
|
||||||
|
continue;
|
||||||
|
Graphs: for (Iterator<TrackGraph> iterator = viableGraphs.iterator(); iterator.hasNext();) {
|
||||||
|
TrackGraph trackGraph = iterator.next();
|
||||||
|
for (GlobalStation station : trackGraph.getPoints(EdgePointType.STATION)) {
|
||||||
|
if (station.name.matches(filter))
|
||||||
|
continue Graphs;
|
||||||
|
}
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 position = minecraft.player.position();
|
||||||
|
Set<String> visited = new HashSet<>();
|
||||||
|
|
||||||
|
return viableGraphs.stream()
|
||||||
|
.flatMap(g -> g.getPoints(EdgePointType.STATION)
|
||||||
|
.stream())
|
||||||
|
.filter(station -> station.tilePos != null)
|
||||||
|
.filter(station -> visited.add(station.name))
|
||||||
|
.map(station -> IntAttached.with((int) Vec3.atBottomCenterOf(station.tilePos)
|
||||||
|
.distanceTo(position), station.name))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void containerTick() {
|
protected void containerTick() {
|
||||||
super.containerTick();
|
super.containerTick();
|
||||||
|
@ -284,6 +351,9 @@ public class ScheduleScreen extends AbstractSimiContainerScreen<ScheduleContaine
|
||||||
for (LerpedFloat lerpedFloat : horizontalScrolls)
|
for (LerpedFloat lerpedFloat : horizontalScrolls)
|
||||||
lerpedFloat.tickChaser();
|
lerpedFloat.tickChaser();
|
||||||
|
|
||||||
|
if (destinationSuggestions != null)
|
||||||
|
destinationSuggestions.tick();
|
||||||
|
|
||||||
schedule.savedProgress =
|
schedule.savedProgress =
|
||||||
schedule.entries.isEmpty() ? 0 : Mth.clamp(schedule.savedProgress, 0, schedule.entries.size() - 1);
|
schedule.entries.isEmpty() ? 0 : Mth.clamp(schedule.savedProgress, 0, schedule.entries.size() - 1);
|
||||||
resetProgress.active = schedule.savedProgress > 0;
|
resetProgress.active = schedule.savedProgress > 0;
|
||||||
|
@ -813,6 +883,9 @@ public class ScheduleScreen extends AbstractSimiContainerScreen<ScheduleContaine
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) {
|
public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) {
|
||||||
|
if (destinationSuggestions != null
|
||||||
|
&& destinationSuggestions.mouseClicked((int) pMouseX, (int) pMouseY, pButton))
|
||||||
|
return true;
|
||||||
if (editorConfirm != null && editorConfirm.isMouseOver(pMouseX, pMouseY) && onEditorClose != null) {
|
if (editorConfirm != null && editorConfirm.isMouseOver(pMouseX, pMouseY) && onEditorClose != null) {
|
||||||
onEditorClose.accept(true);
|
onEditorClose.accept(true);
|
||||||
stopEditing();
|
stopEditing();
|
||||||
|
@ -831,6 +904,8 @@ public class ScheduleScreen extends AbstractSimiContainerScreen<ScheduleContaine
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
|
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
|
||||||
|
if (destinationSuggestions != null && destinationSuggestions.keyPressed(pKeyCode, pScanCode, pModifiers))
|
||||||
|
return true;
|
||||||
if (editingCondition == null && editingDestination == null)
|
if (editingCondition == null && editingDestination == null)
|
||||||
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
|
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
|
||||||
InputConstants.Key mouseKey = InputConstants.getKey(pKeyCode, pScanCode);
|
InputConstants.Key mouseKey = InputConstants.getKey(pKeyCode, pScanCode);
|
||||||
|
@ -846,6 +921,8 @@ public class ScheduleScreen extends AbstractSimiContainerScreen<ScheduleContaine
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mouseScrolled(double pMouseX, double pMouseY, double pDelta) {
|
public boolean mouseScrolled(double pMouseX, double pMouseY, double pDelta) {
|
||||||
|
if (destinationSuggestions != null && destinationSuggestions.mouseScrolled(Mth.clamp(pDelta, -1.0D, 1.0D)))
|
||||||
|
return true;
|
||||||
if (editingCondition != null || editingDestination != null)
|
if (editingCondition != null || editingDestination != null)
|
||||||
return super.mouseScrolled(pMouseX, pMouseY, pDelta);
|
return super.mouseScrolled(pMouseX, pMouseY, pDelta);
|
||||||
|
|
||||||
|
@ -910,7 +987,15 @@ public class ScheduleScreen extends AbstractSimiContainerScreen<ScheduleContaine
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void renderForeground(PoseStack matrixStack, int mouseX, int mouseY, float partialTicks) {
|
protected void renderForeground(PoseStack matrixStack, int mouseX, int mouseY, float partialTicks) {
|
||||||
|
if (destinationSuggestions != null) {
|
||||||
|
matrixStack.pushPose();
|
||||||
|
matrixStack.translate(0, 0, 500);
|
||||||
|
destinationSuggestions.render(matrixStack, mouseX, mouseY);
|
||||||
|
matrixStack.popPose();
|
||||||
|
}
|
||||||
|
|
||||||
super.renderForeground(matrixStack, mouseX, mouseY, partialTicks);
|
super.renderForeground(matrixStack, mouseX, mouseY, partialTicks);
|
||||||
|
|
||||||
GuiGameElement.of(menu.contentHolder).<GuiGameElement
|
GuiGameElement.of(menu.contentHolder).<GuiGameElement
|
||||||
.GuiRenderBuilder>at(leftPos + AllGuiTextures.SCHEDULE.width, topPos + AllGuiTextures.SCHEDULE.height - 56,
|
.GuiRenderBuilder>at(leftPos + AllGuiTextures.SCHEDULE.width, topPos + AllGuiTextures.SCHEDULE.height - 56,
|
||||||
-200)
|
-200)
|
||||||
|
|
|
@ -197,6 +197,7 @@ public class TrackPlacement {
|
||||||
|
|
||||||
if (parallel) {
|
if (parallel) {
|
||||||
double[] sTest = VecHelper.intersect(end1, end2, normedAxis1, cross2, Axis.Y);
|
double[] sTest = VecHelper.intersect(end1, end2, normedAxis1, cross2, Axis.Y);
|
||||||
|
if (sTest != null) {
|
||||||
double t = Math.abs(sTest[0]);
|
double t = Math.abs(sTest[0]);
|
||||||
double u = Math.abs(sTest[1]);
|
double u = Math.abs(sTest[1]);
|
||||||
|
|
||||||
|
@ -228,6 +229,7 @@ public class TrackPlacement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Slope
|
// Slope
|
||||||
|
|
||||||
|
|
|
@ -38,3 +38,6 @@ public net.minecraft.client.model.AgeableListModel f_170339_ # babyZHeadOffset
|
||||||
public net.minecraft.client.model.AgeableListModel f_102010_ # babyHeadScale
|
public net.minecraft.client.model.AgeableListModel f_102010_ # babyHeadScale
|
||||||
public net.minecraft.client.model.AgeableListModel f_102011_ # babyBodyScale
|
public net.minecraft.client.model.AgeableListModel f_102011_ # babyBodyScale
|
||||||
public net.minecraft.client.model.AgeableListModel f_102012_ # bodyYOffset
|
public net.minecraft.client.model.AgeableListModel f_102012_ # bodyYOffset
|
||||||
|
|
||||||
|
public net.minecraft.client.gui.components.CommandSuggestions f_93866_ # suggestions
|
||||||
|
public net.minecraft.client.gui.components.CommandSuggestions$SuggestionsList <init>(Lnet/minecraft/client/gui/components/CommandSuggestions;IIILjava/util/List;Z)V # <init>
|
Loading…
Reference in a new issue