diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/FTBChunksWorldConfig.java b/common/src/main/java/dev/ftb/mods/ftbchunks/FTBChunksWorldConfig.java index b6a01816..5f7bc216 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/FTBChunksWorldConfig.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/FTBChunksWorldConfig.java @@ -45,7 +45,7 @@ public interface FTBChunksWorldConfig { SNBTConfig WAYPOINT_SHARING = CONFIG.addGroup("waypoint_sharing"); BooleanValue WAYPOINT_SHARING_SERVER = WAYPOINT_SHARING.addBoolean("waypoint_sharing_server", true).comment("Allow players to share waypoints with the entire server."); BooleanValue WAYPOINT_SHARING_PARTY = WAYPOINT_SHARING.addBoolean("waypoint_sharing_party", true).comment("Allow players to share waypoints with their party."); - BooleanValue WAYPOINT_SHARING_TEAM = WAYPOINT_SHARING.addBoolean("waypoint_sharing_players", true).comment("Allow players to share waypoints with other players."); + BooleanValue WAYPOINT_SHARING_PLAYERS = WAYPOINT_SHARING.addBoolean("waypoint_sharing_players", true).comment("Allow players to share waypoints with other players."); static int getMaxClaimedChunks(ChunkTeamData playerData, ServerPlayer player) { if (player != null) { diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/FTBChunksClient.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/FTBChunksClient.java index 0cc92358..039c5ca5 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/client/FTBChunksClient.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/FTBChunksClient.java @@ -26,6 +26,7 @@ import dev.ftb.mods.ftbchunks.client.gui.AddWaypointOverlay; import dev.ftb.mods.ftbchunks.client.gui.ChunkScreen; import dev.ftb.mods.ftbchunks.client.gui.LargeMapScreen; +import dev.ftb.mods.ftbchunks.client.gui.PointerIcon; import dev.ftb.mods.ftbchunks.client.gui.WaypointEditorScreen; import dev.ftb.mods.ftbchunks.client.map.*; import dev.ftb.mods.ftbchunks.client.map.color.ColorUtils; @@ -1089,6 +1090,7 @@ private void mapIcons(MapIconEvent event) { if (!event.getMapType().isMinimap()) { event.add(new EntityMapIcon(mc.player, FaceIcon.getFace(mc.player.getGameProfile()))); + event.add(new PointerIcon()); } } diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/PointerIcon.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/PointerIcon.java new file mode 100644 index 00000000..37c89e14 --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/PointerIcon.java @@ -0,0 +1,46 @@ +package dev.ftb.mods.ftbchunks.client.gui; + +import com.mojang.math.Axis; +import dev.ftb.mods.ftbchunks.api.FTBChunksAPI; +import dev.ftb.mods.ftbchunks.api.client.icon.MapIcon; +import dev.ftb.mods.ftbchunks.api.client.icon.MapType; +import dev.ftb.mods.ftblibrary.icon.Icon; +import dev.ftb.mods.ftblibrary.ui.BaseScreen; +import dev.ftb.mods.ftblibrary.ui.input.Key; +import dev.ftb.mods.ftblibrary.ui.input.MouseButton; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; + +public class PointerIcon implements MapIcon { + + private static final Icon POINTER = Icon.getIcon(FTBChunksAPI.rl("textures/player.png")); + + @Override + public Vec3 getPos(float partialTick) { + Player player = Minecraft.getInstance().player; + return partialTick >= 1F ? player.position() : player.getPosition(partialTick); + } + + @Override + public boolean onMousePressed(BaseScreen screen, MouseButton button) { + return false; + } + + @Override + public boolean onKeyPressed(BaseScreen screen, Key key) { + return false; + } + + @Override + public void draw(MapType mapType, GuiGraphics graphics, int x, int y, int w, int h, boolean outsideVisibleArea, int iconAlpha) { + Player player = Minecraft.getInstance().player; + graphics.pose().pushPose(); + graphics.pose().translate(x + w / 2f, y + h / 2f, 0F); + graphics.pose().scale(2f, 2f, 2f); + graphics.pose().mulPose(Axis.ZP.rotationDegrees(player.getYRot() + 180F)); + POINTER.draw(graphics, - w / 2, -h / 2, w, h); + graphics.pose().popPose(); + } +} diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/WaypointEditorScreen.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/WaypointEditorScreen.java index 41c09735..3c9a03f6 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/WaypointEditorScreen.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/WaypointEditorScreen.java @@ -1,6 +1,5 @@ package dev.ftb.mods.ftbchunks.client.gui; -import com.mojang.blaze3d.systems.RenderSystem; import dev.ftb.mods.ftbchunks.client.map.MapManager; import dev.ftb.mods.ftbchunks.client.map.WaypointImpl; import dev.ftb.mods.ftbchunks.net.TeleportFromMapPacket; @@ -9,216 +8,178 @@ import dev.ftb.mods.ftblibrary.icon.Color4I; import dev.ftb.mods.ftblibrary.icon.Icon; import dev.ftb.mods.ftblibrary.icon.Icons; -import dev.ftb.mods.ftblibrary.icon.ImageIcon; -import dev.ftb.mods.ftblibrary.ui.Button; -import dev.ftb.mods.ftblibrary.ui.Panel; -import dev.ftb.mods.ftblibrary.ui.TextField; +import dev.ftb.mods.ftblibrary.icon.ItemIcon; import dev.ftb.mods.ftblibrary.ui.*; import dev.ftb.mods.ftblibrary.ui.input.Key; import dev.ftb.mods.ftblibrary.ui.input.MouseButton; +import dev.ftb.mods.ftblibrary.ui.misc.AbstractButtonListScreen; import dev.ftb.mods.ftblibrary.util.TooltipList; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.player.LocalPlayer; -import net.minecraft.core.BlockPos; +import net.minecraft.commands.Commands; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.FormattedText; +import net.minecraft.network.chat.HoverEvent; import net.minecraft.network.chat.Style; +import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.Level; +import org.lwjgl.glfw.GLFW; -import java.awt.*; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Objects; +import java.util.*; -public class WaypointEditorScreen extends BaseScreen { - public static final Color4I COLOR_BACKGROUND = Color4I.rgba(0x99333333); - private static final Icon PEARL_ICON = ImageIcon.getIcon(new ResourceLocation("minecraft", "textures/item/ender_pearl.png")); +import static dev.ftb.mods.ftblibrary.util.TextComponentUtils.hotkeyTooltip; +import static net.minecraft.network.chat.CommonComponents.ELLIPSIS; - public static final Theme THEME = new Theme() { - @Override - public void drawScrollBarBackground(GuiGraphics graphics, int x, int y, int w, int h, WidgetType type) { - Color4I.BLACK.withAlpha(70).draw(graphics, x, y, w, h); - } - - @Override - public void drawScrollBar(GuiGraphics graphics, int x, int y, int w, int h, WidgetType type, boolean vertical) { - getContentColor(WidgetType.NORMAL).withAlpha(100).withBorder(Color4I.GRAY.withAlpha(100), false).draw(graphics, x, y, w, h); - } - }; - - private static final Component TITLE = Component.translatable("ftbchunks.gui.waypoints").withStyle(ChatFormatting.BOLD); - - private final Panel waypointPanel; - private final PanelScrollBar scrollbar; - private final List rows; +public class WaypointEditorScreen extends AbstractButtonListScreen { + private final Map, Boolean> collapsed = new HashMap<>(); + private final Map, List> waypoints = new HashMap<>(); private final Button buttonCollapseAll, buttonExpandAll; - private int maxWidth; public WaypointEditorScreen() { - waypointPanel = new WaypointPanel(this); - scrollbar = new PanelScrollBar(this, waypointPanel) { - @Override - public void drawBackground(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) { - if (getMaxValue() > parent.height) { - super.drawBackground(graphics, theme, x, y, w, h); - } - } - }; - rows = new ArrayList<>(); - - buttonCollapseAll = new ExpanderButton(this, false); - buttonExpandAll = new ExpanderButton(this, true); + showBottomPanel(false); + showCloseButton(true); - for (DimWayPoints entry : collectWaypoints()) { - rows.add(new VerticalSpaceWidget(waypointPanel,4)); - - boolean thisDimension = Minecraft.getInstance().level.dimension().location().equals(entry.levelKey); - GroupButton groupButton = new GroupButton(waypointPanel, Component.literal(entry.levelKey.toString()).withStyle(ChatFormatting.YELLOW), !thisDimension); - rows.add(groupButton); - - for (WaypointImpl wp : entry.waypoints) { - rows.add(new RowPanel(waypointPanel, groupButton, wp)); - } + for (Map.Entry, List> resourceKeyListEntry : collectWaypoints().entrySet()) { + collapsed.put(resourceKeyListEntry.getKey(), false); + waypoints.put(resourceKeyListEntry.getKey(), new ArrayList<>(resourceKeyListEntry.getValue())); } - } - - private List collectWaypoints() { - List res = new ArrayList<>(); - Player player = Objects.requireNonNull(Minecraft.getInstance().player); - MapManager manager = MapManager.getInstance().orElseThrow(); - manager.getDimensions().values().stream() - .filter(dim -> !dim.getWaypointManager().isEmpty()) - .sorted((dim1, dim2) -> { - // put vanilla dimensions first - ResourceLocation dim1id = dim1.dimension.location(); - ResourceLocation dim2id = dim2.dimension.location(); - if (dim1id.getNamespace().equals("minecraft") && !dim2id.getNamespace().equals("minecraft")) { - return -1; - } - int i = dim1id.getNamespace().compareTo(dim2id.getNamespace()); - return i == 0 ? dim1id.getPath().compareTo(dim2id.getPath()) : i; - }) - .forEach(dim -> res.add(new DimWayPoints(dim.dimension.location(), dim.getWaypointManager().stream() - .sorted(Comparator.comparingDouble(wp -> wp.getDistanceSq(player))) - .toList())) - ); + buttonExpandAll = new SimpleButton(topPanel, List.of(Component.translatable("gui.expand_all"), hotkeyTooltip("="), hotkeyTooltip("+")), Icons.UP, + (widget, button) -> toggleAll(false)); + buttonCollapseAll = new SimpleButton(topPanel, List.of(Component.translatable("gui.collapse_all"), hotkeyTooltip("-")), Icons.DOWN, + (widget, button) -> toggleAll(true)); + } - return res; + private static FormattedText ellipsize(Font font, FormattedText text, int maxWidth) { + final int strWidth = font.width(text); + final int ellipsisWidth = font.width(ELLIPSIS); + if (strWidth > maxWidth) { + return ellipsisWidth >= maxWidth ? + font.substrByWidth(text, maxWidth) : + FormattedText.composite(font.substrByWidth(text, maxWidth - ellipsisWidth), ELLIPSIS); + } + return text; } - @Override - public boolean onInit() { - boolean r = setFullscreen(); - maxWidth = Math.min(maxWidth, getGui().width / 2); - return r; + private void toggleAll(boolean collapsed) { + this.collapsed.keySet().forEach(levelResourceKey -> this.collapsed.put(levelResourceKey, collapsed)); + scrollBar.setValue(0); + getGui().refreshWidgets(); } @Override - public void addWidgets() { - add(waypointPanel); - add(scrollbar); - - add(buttonCollapseAll); - add(buttonExpandAll); + protected void doCancel() { } @Override - public void alignWidgets() { - waypointPanel.setPosAndSize(0, 20, width, height - 20); - waypointPanel.alignWidgets(); - scrollbar.setPosAndSize(width - 16, 20, 16, height - 20); - buttonExpandAll.setPos(width - 18, 2); - buttonCollapseAll.setPos(width - 38, 2); + protected void doAccept() { } @Override - public Theme getTheme() { - return super.getTheme(); + public boolean onInit() { + setWidth(220); + setHeight(getScreen().getGuiScaledHeight() * 4 / 5); + return true; } @Override - public Component getTitle() { - return TITLE; + protected int getTopPanelHeight() { + return 22; } @Override - public void drawBackground(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) { - COLOR_BACKGROUND.draw(graphics, 0, 0, w, 20); - theme.drawString(graphics, getTitle(), 6, 6, Theme.SHADOW); + protected Panel createTopPanel() { + return new CustomTopPanel(); } @Override - public boolean keyPressed(Key key) { - if (key.esc() && getContextMenu().isPresent()) { - closeContextMenu(); - return true; - } - return super.keyPressed(key); + public void addButtons(Panel panel) { + waypoints.forEach((key, value) -> { + boolean startCollapsed = collapsed.get(key); + GroupButton groupButton = new GroupButton(panel, key, startCollapsed, value); + panel.add(groupButton); + if (!startCollapsed) { + panel.addAll(groupButton.collectPanels()); + } + }); } - private class WaypointPanel extends Panel { - public WaypointPanel(Panel panel) { - super(panel); - } + protected class CustomTopPanel extends TopPanel { + private final TextField titleLabel = new TextField(this); @Override public void addWidgets() { - maxWidth = 0; - for (var row : rows) { - if (!(row instanceof RowPanel rowPanel) || !rowPanel.groupButton.collapsed && !rowPanel.deleted) { - add(row); - if (row instanceof RowPanel rp) maxWidth = Math.max(maxWidth, getTheme().getStringWidth(rp.wp.getName())); - } + titleLabel.setText(Component.translatable("ftbchunks.gui.waypoints")); + titleLabel.addFlags(Theme.CENTERED_V); + add(titleLabel); + + if (waypoints.size() > 1) { + add(buttonExpandAll); + add(buttonCollapseAll); } - maxWidth = Math.min(maxWidth, getGui().width / 2); } @Override public void alignWidgets() { - align(WidgetLayout.VERTICAL); - int sbWidth = scrollbar.getMaxValue() > 0 ? 16 : 0; - scrollbar.setWidth(sbWidth); - widgets.forEach(w -> { - int prevWidth = w.width; - w.setWidth(width - sbWidth); - if (w.width != prevWidth && w instanceof Panel p) p.alignWidgets(); - }); + titleLabel.setPosAndSize(4, 0, titleLabel.width, height); + if (waypoints.size() > 1) { + buttonExpandAll.setPos(width - 18, 2); + buttonCollapseAll.setPos(width - 38, 2); + } } } - private static class GroupButton extends Button { - private boolean collapsed; + private class GroupButton extends Button { private final Component titleText; + private final List rowPanels; + private final ResourceKey dim; - public GroupButton(Panel panel, Component titleText, boolean startCollapsed) { + public GroupButton(Panel panel, ResourceKey dim, boolean startCollapsed, List waypoints) { super(panel); - this.titleText = titleText; + + this.dim = dim; + //Todo move the to library or define / get some standard for dim names + //Might need to show more with dim types / level ids + this.titleText = Component.translatableWithFallback(dim.location().toLanguageKey("dimension"), dim.location().getPath()); setCollapsed(startCollapsed); + this.rowPanels = new ArrayList<>(); + for (WaypointImpl waypoint : waypoints) { + rowPanels.add(new RowPanel(panel, waypoint)); + } + } + + public List collectPanels() { + return isCollapsed() ? List.of() : List.copyOf(rowPanels); } @Override public void onClicked(MouseButton button) { - setCollapsed(!collapsed); - getGui().refreshWidgets(); + setCollapsed(!isCollapsed()); + parent.refreshWidgets(); + refreshWidgets(); + playClickSound(); + } + + public boolean isCollapsed() { + return collapsed.get(dim); } - void setCollapsed(boolean collapsed) { - this.collapsed = collapsed; - setTitle(Component.literal(collapsed ? "[>] " : "[v] ").withStyle(collapsed ? ChatFormatting.RED : ChatFormatting.GREEN).append(titleText)); + public void setCollapsed(boolean collapsed) { + WaypointEditorScreen.this.collapsed.put(dim, collapsed); + boolean isCollapsed = isCollapsed(); + setTitle(Component.literal(isCollapsed ? "▶ " : "▼ ").withStyle(isCollapsed ? ChatFormatting.RED : ChatFormatting.GREEN).append(titleText)); } @Override public void draw(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) { - COLOR_BACKGROUND.draw(graphics, x, y, w, h); - theme.drawString(graphics, getTitle(), x + 3, y + 1 + (h - theme.getFontHeight()) / 2); - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - - Color4I.GRAY.withAlpha(80).draw(graphics, 0, y, width, 1); - Color4I.GRAY.withAlpha(80).draw(graphics, 0, y, 1, height); + theme.drawWidget(graphics, x, y, w, h, getWidgetType()); + theme.drawString(graphics, getTitle(), x + 3, y + 3); if (isMouseOver()) { Color4I.WHITE.withAlpha(33).draw(graphics, x, y, w, h); } @@ -226,43 +187,69 @@ public void draw(GuiGraphics graphics, Theme theme, int x, int y, int w, int h) @Override public void addMouseOverText(TooltipList list) { + list.add(Component.literal(dim.location().toString())); } } private class RowPanel extends Panel { - private final GroupButton groupButton; + private static final Component DELETE = Component.translatable("ftbchunks.gui.delete"); + private static final Component QUICK_DELETE = Component.translatable("ftbchunks.gui.quick_delete"); + private final WaypointImpl wp; - private boolean deleted = false; + private TextField nameField; + private TextField distField; + private SimpleButton hideButton; + private SimpleButton deleteButton; - public RowPanel(Panel panel, GroupButton groupButton, WaypointImpl wp) { + public RowPanel(Panel panel, WaypointImpl wp) { super(panel); - this.groupButton = groupButton; + this.wp = wp; setHeight(18); } @Override public void addWidgets() { - add(new SimpleButton(this, Component.empty(), wp.isHidden() ? Icons.REMOVE_GRAY : Icons.ACCEPT, (w, mb) -> { + add(hideButton = new SimpleButton(this, Component.empty(), wp.isHidden() ? Icons.REMOVE_GRAY : Icons.ACCEPT, (w, mb) -> { wp.setHidden(!wp.isHidden()); w.setIcon(wp.isHidden() ? Icons.REMOVE_GRAY : Icons.ACCEPT); })); - add(new TextField(this).setMaxWidth(maxWidth).setTrim().setText(wp.getName()).setColor(Color4I.rgb(wp.getColor())).addFlags(Theme.SHADOW)); + add(nameField = new TextField(this).setTrim().setColor(Color4I.rgb(wp.getColor())).addFlags(Theme.SHADOW)); LocalPlayer player = Minecraft.getInstance().player; String distStr = player.level().dimension().equals(wp.getDimension()) ? String.format("%.1fm", Math.sqrt(wp.getDistanceSq(player))) : ""; - add(new TextField(this).setText(distStr).setColor(Color4I.GRAY)); + add(distField = new TextField(this).setText(distStr).setColor(Color4I.WHITE)); + add(deleteButton = new SimpleButton(this, DELETE, Icons.BIN, (w, mb) -> deleteWaypoint(!isShiftKeyDown())) { + @Override + public Component getTitle() { + return isShiftKeyDown() ? QUICK_DELETE : DELETE; + } + }); } @Override public void alignWidgets() { - if (widgets.size() == 3) { + } + + @Override + public void setWidth(int newWidth) { + super.setWidth(newWidth); + + if (newWidth > 0) { + int farRight = newWidth - 8; + int yOff = (this.height - getTheme().getFontHeight()) / 2 + 1; - widgets.get(0).setPos(10, 1); - widgets.get(1).setPos(30, yOff); - widgets.get(2).setPos(maxWidth + 40, yOff); + + hideButton.setPos(farRight - 8 - 16, 1); + deleteButton.setPos(farRight - 8, 1); + + distField.setPos(hideButton.getPosX() - 5 - distField.width, yOff); + + nameField.setPos(5, yOff); + nameField.setText(ellipsize(getTheme().getFont(), Component.literal(wp.getName()),distField.getPosX() - 5).getString()); + nameField.setHeight(getTheme().getFontHeight() + 2); } } @@ -284,6 +271,8 @@ public boolean mousePressed(MouseButton button) { list.add(makeTitleMenuItem()); list.add(ContextMenuItem.SEPARATOR); + WaypointShareMenu.makeShareMenu(Minecraft.getInstance().player, wp).ifPresent(list::add); + list.add(new ContextMenuItem(Component.translatable("gui.rename"), Icons.CHAT, btn -> { StringConfig config = new StringConfig(); config.setDefaultValue(""); @@ -310,29 +299,45 @@ public boolean mousePressed(MouseButton button) { }); })); } - if (Minecraft.getInstance().player.hasPermissions(2)) { // permissions are checked again on server! - list.add(new ContextMenuItem(Component.translatable("ftbchunks.gui.teleport"), PEARL_ICON, btn -> { - BlockPos pos = wp.getPos().above(); - new TeleportFromMapPacket(pos, false, wp.getDimension()).sendToServer(); + if (Minecraft.getInstance().player.hasPermissions(Commands.LEVEL_GAMEMASTERS)) { // permissions are checked again on server! + list.add(new ContextMenuItem(Component.translatable("ftbchunks.gui.teleport"), ItemIcon.getItemIcon(Items.ENDER_PEARL),btn -> { + new TeleportFromMapPacket(wp.getPos().above(), false, wp.getDimension()).sendToServer(); closeGui(false); })); } - list.add(new ContextMenuItem(Component.translatable("gui.remove"), Icons.REMOVE, btn -> { - getGui().openYesNo(Component.translatable("ftbchunks.gui.delete_waypoint", Component.literal(wp.getName()) - .withStyle(Style.EMPTY.withColor(wp.getColor()))), Component.empty(), () -> { - wp.removeFromManager(); - deleted = true; - getGui().refreshWidgets(); - }); - }) - ); + list.add(new ContextMenuItem(Component.translatable("gui.remove"), Icons.REMOVE, btn -> deleteWaypoint(true))); getGui().openContextMenu(list); return true; } return super.mousePressed(button); } - + + @Override + public boolean keyPressed(Key key) { + if (key.is(GLFW.GLFW_KEY_DELETE)) { + deleteWaypoint(!isShiftKeyDown()); + return true; + } else { + return super.keyPressed(key); + } + } + + private void deleteWaypoint(boolean gui) { + if (gui) { + getGui().openYesNo(Component.translatable("ftbchunks.gui.delete_waypoint", Component.literal(wp.getName()) + .withStyle(Style.EMPTY.withColor(wp.getColor()))), Component.empty(), () -> { + wp.removeFromManager(); + WaypointEditorScreen.this.waypoints.get(wp.getDimension()).remove(wp); + getGui().refreshWidgets(); + }); + } else { + wp.removeFromManager(); + WaypointEditorScreen.this.waypoints.get(wp.getDimension()).remove(wp); + getGui().refreshWidgets(); + } + } + private ContextMenuItem makeTitleMenuItem() { return new ContextMenuItem(Component.literal(wp.getName()), Icon.empty(), null) { @Override @@ -343,16 +348,28 @@ public Icon getIcon() { } } - private class ExpanderButton extends SimpleButton { - public ExpanderButton(Panel panel, boolean expand) { - super(panel, Component.translatable(expand ? "gui.expand_all" : "gui.collapse_all"), expand ? Icons.DOWN : Icons.UP, (btn, mb) -> { - rows.stream().filter(w -> w instanceof GroupButton).map(w -> (GroupButton) w).forEach(g -> g.setCollapsed(!expand)); - scrollbar.setValue(0); - btn.getGui().refreshWidgets(); - }); - } - } + private static Map, List> collectWaypoints() { + Map, List> res = new HashMap<>(); + + Player player = Objects.requireNonNull(Minecraft.getInstance().player); + MapManager manager = MapManager.getInstance().orElseThrow(); + manager.getDimensions().values().stream() + .filter(dim -> !dim.getWaypointManager().isEmpty()) + .sorted((dim1, dim2) -> { + // put vanilla dimensions first + ResourceLocation dim1id = dim1.dimension.location(); + ResourceLocation dim2id = dim2.dimension.location(); + if (dim1id.getNamespace().equals("minecraft") && !dim2id.getNamespace().equals("minecraft")) { + return -1; + } + int i = dim1id.getNamespace().compareTo(dim2id.getNamespace()); + return i == 0 ? dim1id.getPath().compareTo(dim2id.getPath()) : i; + }) + .forEach(dim -> res.put(dim.dimension, dim.getWaypointManager().stream() + .sorted(Comparator.comparingDouble(wp -> wp.getDistanceSq(player))) + .toList()) + ); - private record DimWayPoints(ResourceLocation levelKey, List waypoints) { + return res; } -} +} \ No newline at end of file diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/WaypointShareMenu.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/WaypointShareMenu.java new file mode 100644 index 00000000..efd8ca1a --- /dev/null +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/gui/WaypointShareMenu.java @@ -0,0 +1,98 @@ +package dev.ftb.mods.ftbchunks.client.gui; + +import com.mojang.authlib.GameProfile; +import dev.ftb.mods.ftbchunks.FTBChunksWorldConfig; +import dev.ftb.mods.ftbchunks.api.client.waypoint.Waypoint; +import dev.ftb.mods.ftbchunks.net.ShareWaypointPacket; +import dev.ftb.mods.ftblibrary.icon.FaceIcon; +import dev.ftb.mods.ftblibrary.icon.Icons; +import dev.ftb.mods.ftblibrary.ui.ContextMenuItem; +import dev.ftb.mods.ftblibrary.ui.NordButton; +import dev.ftb.mods.ftblibrary.ui.Panel; +import dev.ftb.mods.ftblibrary.ui.input.MouseButton; +import dev.ftb.mods.ftblibrary.ui.misc.AbstractButtonListScreen; +import dev.ftb.mods.ftblibrary.ui.misc.SimpleToast; +import dev.ftb.mods.ftbteams.api.FTBTeamsAPI; +import dev.ftb.mods.ftbteams.api.client.KnownClientPlayer; +import net.minecraft.ChatFormatting; +import net.minecraft.core.GlobalPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Player; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +public class WaypointShareMenu { + public static Optional makeShareMenu(Player sharingPlayer, Waypoint waypoint) { + List items = new ArrayList<>(); + + if (FTBChunksWorldConfig.WAYPOINT_SHARING_SERVER.get()) { + items.add(new ContextMenuItem(Component.translatable("ftbchunks.waypoint.share.server"), Icons.BEACON, + b -> shareWaypoint(waypoint, ShareWaypointPacket.ShareType.SERVER, List.of()))); + } + if (FTBChunksWorldConfig.WAYPOINT_SHARING_PARTY.get()) { + items.add(new ContextMenuItem(Component.translatable("ftbchunks.waypoint.share.party"), Icons.BELL, + b -> shareWaypoint(waypoint, ShareWaypointPacket.ShareType.PARTY, List.of()))); + } + if (FTBChunksWorldConfig.WAYPOINT_SHARING_PLAYERS.get()) { + items.add(new ContextMenuItem(Component.translatable("ftbchunks.waypoint.share.player"), Icons.PLAYER, b -> { + Collection knownClientPlayers = FTBTeamsAPI.api().getClientManager().knownClientPlayers(); + List list = knownClientPlayers.stream() + .filter(KnownClientPlayer::online) + .filter(p -> !p.id().equals(sharingPlayer.getGameProfile().getId())) + .map(KnownClientPlayer::profile).toList(); + List selectedProfiles = new ArrayList<>(); + new AbstractButtonListScreen() { + @Override + protected void doCancel() { + closeGui(); + } + + @Override + protected void doAccept() { + List toShare = selectedProfiles.stream().map(GameProfile::getId).toList(); + if (!toShare.isEmpty()) { + shareWaypoint(waypoint, ShareWaypointPacket.ShareType.PLAYER, toShare); + } + closeGui(); + } + + @Override + public void addButtons(Panel panel) { + for (GameProfile gameProfile : list) { + Component unchecked = (Component.literal("☐ ")).append(gameProfile.getName()); + Component checked = (Component.literal("☑ ").withStyle(ChatFormatting.GREEN)).append(gameProfile.getName()); + NordButton widget = new NordButton(panel, unchecked, FaceIcon.getFace(gameProfile)) { + @Override + public void onClicked(MouseButton button) { + if (selectedProfiles.contains(gameProfile)) { + selectedProfiles.remove(gameProfile); + title = unchecked; + } else { + selectedProfiles.add(gameProfile); + title = checked; + } + playClickSound(); + } + }; + panel.add(widget); + } + } + }.openGui(); + })); + } + + return items.isEmpty() ? + Optional.empty() : + Optional.of(ContextMenuItem.subMenu(Component.translatable("ftbchunks.waypoint.share"), Icons.INFO, items)); + } + + private static void shareWaypoint(Waypoint waypoint, ShareWaypointPacket.ShareType type, List targets) { + GlobalPos waypointPos = GlobalPos.of(waypoint.getDimension(), waypoint.getPos()); + new ShareWaypointPacket(waypoint.getName(), waypointPos, type, targets).sendToServer(); + SimpleToast.info(Component.translatable("ftbchunks.waypoint.shared_by_you", waypoint.getName()), Component.empty()); + } +} \ No newline at end of file diff --git a/common/src/main/java/dev/ftb/mods/ftbchunks/client/mapicon/WaypointMapIcon.java b/common/src/main/java/dev/ftb/mods/ftbchunks/client/mapicon/WaypointMapIcon.java index 612526e2..f1a30ce2 100644 --- a/common/src/main/java/dev/ftb/mods/ftbchunks/client/mapicon/WaypointMapIcon.java +++ b/common/src/main/java/dev/ftb/mods/ftbchunks/client/mapicon/WaypointMapIcon.java @@ -1,53 +1,34 @@ package dev.ftb.mods.ftbchunks.client.mapicon; -import com.mojang.authlib.GameProfile; import com.mojang.blaze3d.systems.RenderSystem; import dev.architectury.networking.NetworkManager; -import dev.ftb.mods.ftbchunks.FTBChunksWorldConfig; import dev.ftb.mods.ftbchunks.api.client.icon.MapType; import dev.ftb.mods.ftbchunks.api.client.icon.WaypointIcon; import dev.ftb.mods.ftbchunks.client.gui.LargeMapScreen; +import dev.ftb.mods.ftbchunks.client.gui.WaypointShareMenu; import dev.ftb.mods.ftbchunks.client.map.WaypointImpl; -import dev.ftb.mods.ftbchunks.net.ShareWaypointPacket; import dev.ftb.mods.ftbchunks.net.TeleportFromMapPacket; import dev.ftb.mods.ftblibrary.config.ColorConfig; import dev.ftb.mods.ftblibrary.config.StringConfig; -import dev.ftb.mods.ftblibrary.icon.Color4I; -import dev.ftb.mods.ftblibrary.icon.FaceIcon; -import dev.ftb.mods.ftblibrary.icon.Icon; -import dev.ftb.mods.ftblibrary.icon.Icons; -import dev.ftb.mods.ftblibrary.icon.ImageIcon; -import dev.ftb.mods.ftblibrary.icon.ItemIcon; +import dev.ftb.mods.ftblibrary.icon.*; import dev.ftb.mods.ftblibrary.math.MathUtils; import dev.ftb.mods.ftblibrary.ui.BaseScreen; import dev.ftb.mods.ftblibrary.ui.ColorSelectorPanel; import dev.ftb.mods.ftblibrary.ui.ContextMenuItem; -import dev.ftb.mods.ftblibrary.ui.NordButton; -import dev.ftb.mods.ftblibrary.ui.Panel; -import dev.ftb.mods.ftblibrary.ui.Widget; import dev.ftb.mods.ftblibrary.ui.input.Key; import dev.ftb.mods.ftblibrary.ui.input.MouseButton; -import dev.ftb.mods.ftblibrary.ui.misc.AbstractButtonListScreen; import dev.ftb.mods.ftblibrary.util.TooltipList; -import dev.ftb.mods.ftbteams.api.FTBTeamsAPI; -import dev.ftb.mods.ftbteams.api.client.KnownClientPlayer; -import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.player.LocalPlayer; import net.minecraft.commands.Commands; -import net.minecraft.core.GlobalPos; import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; import net.minecraft.world.item.Items; import org.lwjgl.glfw.GLFW; -import java.awt.*; import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; import java.util.List; -import java.util.Optional; public class WaypointMapIcon extends StaticMapIcon implements WaypointIcon { private final WaypointImpl waypoint; @@ -119,82 +100,8 @@ private void openWPContextMenu(LargeMapScreen screen) { contextMenu.add(ContextMenuItem.SEPARATOR); LocalPlayer player = Minecraft.getInstance().player; - GlobalPos waypointPos = GlobalPos.of(waypoint.getDimension(), waypoint.getPos()); - if(player.hasPermissions(Commands.LEVEL_GAMEMASTERS)) { - contextMenu.add(new ContextMenuItem(Component.translatable("ftbchunks.gui.teleport"), ItemIcon.getItemIcon(Items.ENDER_PEARL), b -> { - new TeleportFromMapPacket(waypoint.getPos().above(), false, waypoint.getDimension()).sendToServer(); - screen.closeGui(false); - })); - } - boolean shareServer = FTBChunksWorldConfig.WAYPOINT_SHARING_SERVER.get(); - boolean shareParty = FTBChunksWorldConfig.WAYPOINT_SHARING_PARTY.get(); - boolean sharePlayers = FTBChunksWorldConfig.WAYPOINT_SHARING_TEAM.get(); - - List shareMenu = new ArrayList<>(); - if(shareServer) { - shareMenu.add(new ContextMenuItem(Component.translatable("ftbchunks.waypoint.share.server"), Icons.BEACON, b -> { - new ShareWaypointPacket(waypoint.getName(), waypointPos, ShareWaypointPacket.ShareType.SERVER, Collections.emptyList()).sendToServer(); - screen.closeGui(false); - })); - } - if(shareParty) { - shareMenu.add(new ContextMenuItem(Component.translatable("ftbchunks.waypoint.share.party"), Icons.BELL, b -> { - new ShareWaypointPacket(waypoint.getName(), waypointPos, ShareWaypointPacket.ShareType.PARTY, Collections.emptyList()).sendToServer(); - screen.closeGui(false); - })); - } - if(sharePlayers) { - shareMenu.add(new ContextMenuItem(Component.translatable("ftbchunks.waypoint.share.player"), Icons.PLAYER, b -> { - Collection knownClientPlayers = FTBTeamsAPI.api().getClientManager().knownClientPlayers(); - List list = knownClientPlayers.stream() - .filter(KnownClientPlayer::online) - .filter(p -> !p.id().equals(player.getGameProfile().getId())) - .map(KnownClientPlayer::profile).toList(); - List selectedProfiles = new ArrayList<>(); - new AbstractButtonListScreen() { - - @Override - protected void doCancel() { - screen.closeGui(true); - } - - @Override - protected void doAccept() { - new ShareWaypointPacket(waypoint.getName(), waypointPos, ShareWaypointPacket.ShareType.PLAYER, selectedProfiles.stream().map(GameProfile::getId).toList()).sendToServer(); - screen.closeGui(false); - } - - @Override - public void addButtons(Panel panel) { - for (GameProfile gameProfile : list) { - Component unchecked = (Component.literal("☐ ")).append(gameProfile.getName()); - Component checked = (Component.literal("☑ ").withStyle(ChatFormatting.GREEN)).append(gameProfile.getName()); - NordButton widget = new NordButton(panel, unchecked, FaceIcon.getFace(gameProfile)) { - @Override - public void onClicked(MouseButton button) { - if(selectedProfiles.contains(gameProfile)) { - selectedProfiles.remove(gameProfile); - title = unchecked; - } else { - selectedProfiles.add(gameProfile); - title = checked; - } - screen.refreshWidgets(); - playClickSound(); - } - }; - panel.add(widget); - } - } - }.openGui(); - - })); - - } - if(shareServer || shareParty || sharePlayers) { - contextMenu.add(ContextMenuItem.subMenu(Component.translatable("ftbchunks.waypoint.share"), Icons.INFO, shareMenu)); - } + WaypointShareMenu.makeShareMenu(player, waypoint).ifPresent(contextMenu::add); contextMenu.add(new ContextMenuItem(Component.translatable("gui.rename"), Icons.CHAT, b -> { StringConfig config = new StringConfig(); @@ -227,6 +134,13 @@ public void onClicked(MouseButton button) { screen.refreshWidgets(); })); + if (player.hasPermissions(Commands.LEVEL_GAMEMASTERS)) { + contextMenu.add(new ContextMenuItem(Component.translatable("ftbchunks.gui.teleport"), ItemIcon.getItemIcon(Items.ENDER_PEARL), b -> { + new TeleportFromMapPacket(waypoint.getPos().above(), false, waypoint.getDimension()).sendToServer(); + screen.closeGui(false); + })); + } + contextMenu.add(new ContextMenuItem(Component.translatable("gui.remove"), Icons.REMOVE, b -> { waypoint.removeFromManager(); screen.refreshIcons(); diff --git a/common/src/main/resources/assets/ftbchunks/lang/en_us.json b/common/src/main/resources/assets/ftbchunks/lang/en_us.json index a0e34060..97bb3148 100644 --- a/common/src/main/resources/assets/ftbchunks/lang/en_us.json +++ b/common/src/main/resources/assets/ftbchunks/lang/en_us.json @@ -115,6 +115,8 @@ "ftbchunks.gui.large_map_info.text": "Mouse\nLeft Button;Click/Drag to move map view\nRight Button;Context Menu\nMouse Wheel;Rotate to zoom\n\nKeys\nSpace;Center view on player\nC;Open chunk claim screen\nT;Teleport to point (op required)\nS;Open settings screen\nCtrl + S;Open server settings screen (op required)\nF3+G;Toggle Chunk Grid", "ftbchunks.gui.chunk_info": "Chunk Claiming Reference", "ftbchunks.gui.chunk_info.text": "Claiming\nLeft Button;Drag to claim an area\nRight Button;Drag to unclaim an area\n\nForceloading\nShift + Left Button;Drag to forceload an area\nShift + Right Button;Drag to unforceload an area\nMouse Wheel;Rotate on forceloaded chunk to adjust auto-expiry\n\nMisc\nTab;Hold to hide chunk grid\nAlt;Hold to show absolute chunk claim/force times", + "ftbchunks.gui.delete": "Delete", + "ftbchunks.gui.quick_delete": "Quick Delete", "ftbteamsconfig.ftbchunks": "FTB Chunks Properties", "ftbteamsconfig.ftbchunks.allow_fake_players": "Allow All Fake Players", "ftbteamsconfig.ftbchunks.allow_fake_players.tooltip": "Treat ALL fake players as allies of the team.\nWARNING: Setting this to true could allow hostile players to access your claims via any fake player. Set this to false if you're unsure.", @@ -199,7 +201,14 @@ "ftbchunks.label.show": "Show", "ftbchunks.label.hide": "Hide", "ftbchunks.message.no_pvp": "PvP combat is disabled here", - "ftbchunks.waypoint.shared": "Has shared %s with you", + "ftbchunks.game_time": "Game Time: %s", + "ftbchunks.real_time": "Real Time: %s", + "ftbchunks.fps": "FPS: %d", + "ftbchunks.minimap.show_game_time": "Show Game Time", + "ftbchunks.minimap.show_fps": "Show FPS", + "ftbchunks.minimap.show_real_time": "Show Real Time", + "ftbchunks.waypoint.shared": "Has shared waypoint '%s' with you! Click to add", + "ftbchunks.waypoint.shared_by_you": "You shared waypoint '%s' !", "ftbchunks.waypoint.share": "Share", "ftbchunks.waypoint.share.server": "Server", "ftbchunks.waypoint.share.party": "Party", @@ -207,11 +216,5 @@ "ftbchunks.waypoint_sharing": "Waypoint Sharing", "ftbchunks.waypoint_sharing.waypoint_sharing_party": "Allow Sharing waypoints with Party", "ftbchunks.waypoint_sharing.waypoint_sharing_server": "Allow Sharing waypoints with Server", - "ftbchunks.waypoint_sharing.waypoint_sharing_players": "Allow Sharing waypoints with Players", - "ftbchunks.game_time": "Game Time: %s", - "ftbchunks.real_time": "Real Time: %s", - "ftbchunks.fps": "FPS: %d", - "ftbchunks.minimap.show_game_time": "Show Game Time", - "ftbchunks.minimap.show_fps": "Show FPS", - "ftbchunks.minimap.show_real_time": "Show Real Time" + "ftbchunks.waypoint_sharing.waypoint_sharing_players": "Allow Sharing waypoints with Players" } \ No newline at end of file