diff --git a/shared/src/main/java/net/blay09/mods/waystones/command/ListWaystonesCommand.java b/shared/src/main/java/net/blay09/mods/waystones/command/ListWaystonesCommand.java deleted file mode 100644 index d01ebc5d..00000000 --- a/shared/src/main/java/net/blay09/mods/waystones/command/ListWaystonesCommand.java +++ /dev/null @@ -1,121 +0,0 @@ -package net.blay09.mods.waystones.command; - -import com.mojang.brigadier.Command; -import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.blay09.mods.waystones.api.IWaystone; -import net.blay09.mods.waystones.core.PlayerWaystoneManager; -import net.minecraft.ChatFormatting; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.arguments.selector.EntitySelector; -import net.minecraft.network.chat.ClickEvent; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.Style; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.Level; - -import java.util.*; -import java.util.stream.Collectors; - -public class ListWaystonesCommand implements Command { - - private final boolean listNotOwned; - - public ListWaystonesCommand(boolean listNotOwned) { - this.listNotOwned = listNotOwned; - } - - - @Override - public int run(CommandContext ctx) throws CommandSyntaxException { - ServerPlayer player = ctx.getArgument("player", EntitySelector.class).findSinglePlayer(ctx.getSource()); - ServerPlayer op = ctx.getSource().getPlayerOrException(); - - final var sortedWaystones = ownedOrActivatedByDistance(player, op); - - final var headerKey = listNotOwned ? "commands.waystones.list.activated.header" : "commands.waystones.list.owned.header"; - ctx.getSource().sendSystemMessage(Component.translatable(headerKey, player.getScoreboardName())); - - CommandSourceStack commandSourceStack = ctx.getSource(); - for (IWaystone waystone : sortedWaystones.get(WaystoneOwnership.OWNED)) { - commandSourceStack.sendSystemMessage(componentForWaystone(ctx.getSource(), WaystoneOwnership.OWNED, waystone)); - } - if (listNotOwned) { - for (IWaystone waystone : sortedWaystones.get(WaystoneOwnership.ACTIVATED)) { - commandSourceStack.sendSystemMessage(componentForWaystone(ctx.getSource(), WaystoneOwnership.ACTIVATED, waystone)); - } - } - - int totalCount = sortedWaystones.size(); - int ownedCount = sortedWaystones.get(WaystoneOwnership.OWNED).size(); - - if (listNotOwned) { - ctx.getSource().sendSuccess(() -> Component.translatable("commands.waystones.list.activated.footer", totalCount, ownedCount), false); - return totalCount; - } else { - ctx.getSource().sendSuccess(() -> Component.translatable("commands.waystones.list.owned.footer", ownedCount), false); - return ownedCount; - } - } - - public static Map> ownedOrActivatedByDistance(Player target, Player commandOp) { - Comparator distanceComparator = createDistanceComparator(commandOp); - - EnumMap> ownedAndActivated = PlayerWaystoneManager.getWaystones(target) - .stream() - //we only mark as owned the waystones that are truly bound to the target player's uuid - .collect(Collectors.groupingBy( - w -> target.getGameProfile().getId().equals(w.getOwnerUid()) ? WaystoneOwnership.OWNED : WaystoneOwnership.ACTIVATED, - () -> new EnumMap<>(WaystoneOwnership.class), - Collectors.toList()) - ); - - List owned = ownedAndActivated.computeIfAbsent(WaystoneOwnership.OWNED, k -> Collections.emptyList()); - List activated = ownedAndActivated.computeIfAbsent(WaystoneOwnership.ACTIVATED, k -> Collections.emptyList()); - owned.sort(distanceComparator); - activated.sort(distanceComparator); - return ownedAndActivated; - } - - public static Comparator createDistanceComparator(final Player player) { - return Comparator.comparingDouble(w -> { - ResourceKey targetDimension = w.getDimension(); - if (targetDimension == null) return Double.MAX_VALUE; - if (!targetDimension.equals(player.level().dimension())) return Double.MAX_VALUE - 1; - - return player.position().distanceTo(w.getPos().getCenter()); - }); - } - - private Component componentForWaystone(CommandSourceStack source, WaystoneOwnership ownership, IWaystone waystone) throws CommandSyntaxException { - final var op = source.getPlayerOrException(); - - final var waystoneDimensionId = waystone.getDimension().location(); - final var waystonePos = waystone.getPos(); - Component location; - if(waystone.getDimension() != op.level().dimension()) { - location = Component.translatable("commands.waystones.list.in_dimension", waystoneDimensionId); - } else { - final var distance = (int) op.position().distanceTo(waystonePos.getCenter()); - location = Component.translatable("commands.waystones.list.at_distance", distance); - } - - final var suggestedCommand = String.format("/execute in %s run teleport %d %d %d", waystoneDimensionId, waystonePos.getX(), waystonePos.getY(), waystonePos.getZ()); - - final var coordinates = Component.translatable("commands.waystones.list.coordinates", waystonePos.getX(), waystonePos.getY(), waystonePos.getZ()) - .withStyle(ChatFormatting.YELLOW) - .withStyle(Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, suggestedCommand))); - - final var waystoneName = Component.literal(waystone.getName()) - .withStyle(ChatFormatting.GREEN) - .withStyle(Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, suggestedCommand))); - - final var entryKey = switch (ownership) { - case OWNED -> "commands.waystones.list.owned.entry"; - case ACTIVATED -> "commands.waystones.list.activated.entry"; - }; - return Component.translatable(entryKey, location, coordinates, waystoneName); - } -} diff --git a/shared/src/main/java/net/blay09/mods/waystones/command/ModCommands.java b/shared/src/main/java/net/blay09/mods/waystones/command/ModCommands.java index 55f57cda..ffe5b40c 100644 --- a/shared/src/main/java/net/blay09/mods/waystones/command/ModCommands.java +++ b/shared/src/main/java/net/blay09/mods/waystones/command/ModCommands.java @@ -1,24 +1,91 @@ package net.blay09.mods.waystones.command; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; import net.blay09.mods.balm.api.command.BalmCommands; -import net.minecraft.commands.CommandSourceStack; +import net.blay09.mods.waystones.api.IWaystone; +import net.blay09.mods.waystones.comparator.WaystoneComparators; +import net.blay09.mods.waystones.core.PlayerWaystoneManager; +import net.minecraft.ChatFormatting; +import net.minecraft.commands.Commands; import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.commands.arguments.selector.EntitySelector; +import net.minecraft.network.chat.ClickEvent; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.Style; +import net.minecraft.server.level.ServerPlayer; import static net.minecraft.commands.Commands.argument; public class ModCommands { public static void initialize(BalmCommands commands) { - commands.register(dispatcher -> dispatcher.register(LiteralArgumentBuilder.literal("waystones") + commands.register(dispatcher -> dispatcher.register(Commands.literal("waystones") .requires(source -> source.isPlayer() && source.hasPermission(2)) - .then(LiteralArgumentBuilder.literal("count") + .then(Commands.literal("count") .then(argument("player", EntityArgument.player()).executes(new CountWaystonesCommand()))) - .then(LiteralArgumentBuilder.literal("owned") - .then(argument("player", EntityArgument.player()).executes(new ListWaystonesCommand(false)))) - .then(LiteralArgumentBuilder.literal("activated") - .then(argument("player", EntityArgument.player()).executes(new ListWaystonesCommand(true)))) - .then(LiteralArgumentBuilder.literal("gui") + .then(Commands.literal("list") + .then(argument("player", EntityArgument.player()).executes(ctx -> { + final var caller = ctx.getSource().getPlayerOrException(); + final var target = ctx.getArgument("player", EntitySelector.class).findSinglePlayer(ctx.getSource()); + final var waystones = PlayerWaystoneManager.getWaystones(target) + .stream() + .filter(it -> it.isOwner(target)) + .sorted(WaystoneComparators.forAdminInspection(caller, target)) + .toList(); + ctx.getSource().sendSystemMessage(Component.translatable("commands.waystones.list.header", target.getScoreboardName())); + for (var waystone : waystones) { + ctx.getSource().sendSystemMessage(componentForWaystoneList(caller, target, waystone)); + } + final var result = Component.translatable("commands.waystones.list.footer", waystones.size()); + ctx.getSource().sendSuccess(() -> result, false); + return waystones.size(); + }) + .then(Commands.literal("all").executes(ctx -> { + final var caller = ctx.getSource().getPlayerOrException(); + final var target = ctx.getArgument("player", EntitySelector.class).findSinglePlayer(ctx.getSource()); + final var waystones = PlayerWaystoneManager.getWaystones(target) + .stream() + .sorted(WaystoneComparators.forAdminInspection(caller, target)) + .toList(); + ctx.getSource().sendSystemMessage(Component.translatable("commands.waystones.list.all.header", target.getScoreboardName())); + for (var waystone : waystones) { + ctx.getSource().sendSystemMessage(componentForWaystoneList(caller, target, waystone)); + } + final var ownedCount = waystones.stream().filter(it -> it.isOwner(target)).count(); + final var result = Component.translatable("commands.waystones.list.all.footer", waystones.size(), ownedCount); + ctx.getSource().sendSuccess(() -> result, false); + return waystones.size(); + })))) + .then(Commands.literal("gui") .then(argument("player", EntityArgument.player()).executes(new OpenPlayerWaystonesGuiCommand()))) )); } + + private static Component componentForWaystoneList(ServerPlayer caller, ServerPlayer target, IWaystone waystone) { + final var waystoneDimensionId = waystone.getDimension().location(); + final var waystonePos = waystone.getPos(); + Component location; + if (waystone.getDimension() != caller.level().dimension()) { + location = Component.translatable("commands.waystones.list.in_dimension", waystoneDimensionId); + } else { + final var distance = (int) caller.position().distanceTo(waystonePos.getCenter()); + location = Component.translatable("commands.waystones.list.at_distance", distance); + } + + final var suggestedCommand = String.format("/execute in %s run teleport %d %d %d", + waystoneDimensionId, + waystonePos.getX(), + waystonePos.getY(), + waystonePos.getZ()); + + final var coordinates = Component.translatable("commands.waystones.list.coordinates", waystonePos.getX(), waystonePos.getY(), waystonePos.getZ()) + .withStyle(ChatFormatting.YELLOW) + .withStyle(Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, suggestedCommand))); + + final var waystoneName = Component.literal(waystone.getName()) + .withStyle(ChatFormatting.GREEN) + .withStyle(Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, suggestedCommand))); + + final var entryKey = waystone.isOwner(target) ? "commands.waystones.list.entry.owned" : "commands.waystones.list.entry.activated"; + return Component.translatable(entryKey, location, coordinates, waystoneName); + } } diff --git a/shared/src/main/java/net/blay09/mods/waystones/command/OpenPlayerWaystonesGuiCommand.java b/shared/src/main/java/net/blay09/mods/waystones/command/OpenPlayerWaystonesGuiCommand.java index cd5a6826..85a009b4 100644 --- a/shared/src/main/java/net/blay09/mods/waystones/command/OpenPlayerWaystonesGuiCommand.java +++ b/shared/src/main/java/net/blay09/mods/waystones/command/OpenPlayerWaystonesGuiCommand.java @@ -5,7 +5,8 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.blay09.mods.balm.api.Balm; import net.blay09.mods.balm.api.menu.BalmMenuProvider; -import net.blay09.mods.waystones.api.IWaystone; +import net.blay09.mods.waystones.comparator.WaystoneComparators; +import net.blay09.mods.waystones.core.PlayerWaystoneManager; import net.blay09.mods.waystones.core.Waystone; import net.blay09.mods.waystones.menu.WaystoneSelectionMenu; import net.minecraft.commands.CommandSourceStack; @@ -17,10 +18,6 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - public class OpenPlayerWaystonesGuiCommand implements Command { @Override public int run(CommandContext ctx) throws CommandSyntaxException { @@ -29,7 +26,7 @@ public int run(CommandContext ctx) throws CommandSyntaxExcep BalmMenuProvider menuProvider = new BalmMenuProvider() { @Override public Component getDisplayName() { - return Component.translatable( "container.waystones.waystone_admin_selection", target.getScoreboardName()); + return Component.translatable("container.waystones.waystone_admin_selection", target.getScoreboardName()); } @Override @@ -39,10 +36,8 @@ public AbstractContainerMenu createMenu(int i, Inventory playerInventory, Player @Override public void writeScreenOpeningData(ServerPlayer player, FriendlyByteBuf buf) { - Map> all = ListWaystonesCommand.ownedOrActivatedByDistance(player, op); - List waystones = new ArrayList<>(); - waystones.addAll(all.get(WaystoneOwnership.OWNED)); - waystones.addAll(all.get(WaystoneOwnership.ACTIVATED)); + final var waystones = PlayerWaystoneManager.getWaystones(target); + waystones.sort(WaystoneComparators.forAdminInspection(player, target)); buf.writeInt(waystones.size()); waystones.forEach(w -> Waystone.write(buf, w)); } diff --git a/shared/src/main/java/net/blay09/mods/waystones/comparator/DistanceToPlayerComparator.java b/shared/src/main/java/net/blay09/mods/waystones/comparator/DistanceToPlayerComparator.java new file mode 100644 index 00000000..133a1b50 --- /dev/null +++ b/shared/src/main/java/net/blay09/mods/waystones/comparator/DistanceToPlayerComparator.java @@ -0,0 +1,22 @@ +package net.blay09.mods.waystones.comparator; + +import net.blay09.mods.waystones.api.IWaystone; +import net.minecraft.world.entity.player.Player; + +import java.util.Comparator; + +public class DistanceToPlayerComparator implements Comparator { + + private final Player player; + + public DistanceToPlayerComparator(Player player) { + this.player = player; + } + + @Override + public int compare(IWaystone o1, IWaystone o2) { + double distance1 = o1.getPos().distSqr(player.blockPosition()); + double distance2 = o2.getPos().distSqr(player.blockPosition()); + return Double.compare(distance1, distance2); + } +} diff --git a/shared/src/main/java/net/blay09/mods/waystones/comparator/PreferOwnedComparator.java b/shared/src/main/java/net/blay09/mods/waystones/comparator/PreferOwnedComparator.java new file mode 100644 index 00000000..71477d17 --- /dev/null +++ b/shared/src/main/java/net/blay09/mods/waystones/comparator/PreferOwnedComparator.java @@ -0,0 +1,26 @@ +package net.blay09.mods.waystones.comparator; + +import net.blay09.mods.waystones.api.IWaystone; +import net.minecraft.world.entity.player.Player; + +import java.util.Comparator; + +public class PreferOwnedComparator implements Comparator { + + private final Player owner; + + public PreferOwnedComparator(Player owner) { + this.owner = owner; + } + + @Override + public int compare(IWaystone o1, IWaystone o2) { + if (o1.isOwner(owner) && !o2.isOwner(owner)) { + return -1; + } else if (!o1.isOwner(owner) && o2.isOwner(owner)) { + return 1; + } + + return 0; + } +} diff --git a/shared/src/main/java/net/blay09/mods/waystones/comparator/PreferSameDimensionComparator.java b/shared/src/main/java/net/blay09/mods/waystones/comparator/PreferSameDimensionComparator.java new file mode 100644 index 00000000..0057c594 --- /dev/null +++ b/shared/src/main/java/net/blay09/mods/waystones/comparator/PreferSameDimensionComparator.java @@ -0,0 +1,27 @@ +package net.blay09.mods.waystones.comparator; + +import net.blay09.mods.waystones.api.IWaystone; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.Level; + +import java.util.Comparator; + +public class PreferSameDimensionComparator implements Comparator { + + private final ResourceKey dimensionId; + + public PreferSameDimensionComparator(ResourceKey dimensionId) { + this.dimensionId = dimensionId; + } + + @Override + public int compare(IWaystone o1, IWaystone o2) { + if (o1.getDimension().equals(dimensionId) && !o2.getDimension().equals(dimensionId)) { + return -1; + } else if (!o1.getDimension().equals(dimensionId) && o2.getDimension().equals(dimensionId)) { + return 1; + } + + return 0; + } +} diff --git a/shared/src/main/java/net/blay09/mods/waystones/comparator/WaystoneComparators.java b/shared/src/main/java/net/blay09/mods/waystones/comparator/WaystoneComparators.java new file mode 100644 index 00000000..bc723ad4 --- /dev/null +++ b/shared/src/main/java/net/blay09/mods/waystones/comparator/WaystoneComparators.java @@ -0,0 +1,14 @@ +package net.blay09.mods.waystones.comparator; + +import net.blay09.mods.waystones.api.IWaystone; +import net.minecraft.world.entity.player.Player; + +import java.util.Comparator; + +public class WaystoneComparators { + public static Comparator forAdminInspection(Player caller, Player target) { + return new PreferOwnedComparator(target) + .thenComparing(new PreferSameDimensionComparator(caller.level().dimension()) + .thenComparing(new DistanceToPlayerComparator(caller))); + } +} diff --git a/shared/src/main/java/net/blay09/mods/waystones/menu/WaystoneSelectionMenu.java b/shared/src/main/java/net/blay09/mods/waystones/menu/WaystoneSelectionMenu.java index 7779b587..db1b8e46 100644 --- a/shared/src/main/java/net/blay09/mods/waystones/menu/WaystoneSelectionMenu.java +++ b/shared/src/main/java/net/blay09/mods/waystones/menu/WaystoneSelectionMenu.java @@ -2,8 +2,7 @@ import net.blay09.mods.waystones.api.IWaystone; import net.blay09.mods.waystones.block.SharestoneBlock; -import net.blay09.mods.waystones.command.ListWaystonesCommand; -import net.blay09.mods.waystones.command.WaystoneOwnership; +import net.blay09.mods.waystones.comparator.WaystoneComparators; import net.blay09.mods.waystones.core.PlayerWaystoneManager; import net.blay09.mods.waystones.core.WarpMode; import net.blay09.mods.waystones.core.WaystoneManager; @@ -18,9 +17,7 @@ import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; public class WaystoneSelectionMenu extends AbstractContainerMenu { @@ -76,11 +73,9 @@ public static WaystoneSelectionMenu createSharestoneSelection(MinecraftServer se return new WaystoneSelectionMenu(ModMenus.sharestoneSelection.get(), WarpMode.SHARESTONE_TO_SHARESTONE, fromWaystone, windowId, waystones); } - public static WaystoneSelectionMenu createAdminSelection(int windowId, Player op, Player target) { - Map> all = ListWaystonesCommand.ownedOrActivatedByDistance(target, op); - List waystones = new ArrayList<>(); - waystones.addAll(all.get(WaystoneOwnership.OWNED)); - waystones.addAll(all.get(WaystoneOwnership.ACTIVATED)); + public static WaystoneSelectionMenu createAdminSelection(int windowId, Player player, Player target) { + final var waystones = PlayerWaystoneManager.getWaystones(target); + waystones.sort(WaystoneComparators.forAdminInspection(player, target)); return new WaystoneSelectionMenu(ModMenus.adminSelection.get(), WarpMode.CUSTOM, null, windowId, waystones); } } diff --git a/shared/src/main/resources/assets/waystones/lang/en_us.json b/shared/src/main/resources/assets/waystones/lang/en_us.json index 4fc1d775..09b6d589 100644 --- a/shared/src/main/resources/assets/waystones/lang/en_us.json +++ b/shared/src/main/resources/assets/waystones/lang/en_us.json @@ -95,12 +95,12 @@ "stat.waystones.waystone_activated": "Waystones Activated", "waystones:warp_plate": "Warp Plate", "commands.waystones.count": "%s has %d waystones activated and owns %d of those", - "commands.waystones.list.activated.header": "Waystones (x, y, z) by %s:", - "commands.waystones.list.activated.entry": "- activated %s (%s): %s", - "commands.waystones.list.activated.footer": "%d waystones total, %d owned", - "commands.waystones.list.owned.header": "Waystones (x, y, z) by %s (owned only):", - "commands.waystones.list.owned.entry": "- owned %s (%s): %s", - "commands.waystones.list.owned.footer": "%d waystones owned", + "commands.waystones.list.header": "Waystones (x, y, z) by %s (owned only):", + "commands.waystones.list.entry.owned": "- owned %s (%s): %s", + "commands.waystones.list.entry.activated": "- activated %s (%s): %s", + "commands.waystones.list.footer": "%d waystones owned", + "commands.waystones.list.all.header": "Waystones (x, y, z) by %s:", + "commands.waystones.list.all.footer": "%d waystones total, %d owned", "commands.waystones.list.coordinates": "%d, %d, %d", "commands.waystones.list.in_dimension": "in %s", "commands.waystones.list.at_distance": "at %d blocks away",