diff --git a/build.gradle.kts b/build.gradle.kts index c57a098..052a512 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -32,7 +32,7 @@ dependencies { // APIs api("dev.emortal.api:module-system:1.0.0") api("dev.emortal.api:agones-sdk:1.0.7") - api("dev.emortal.api:common-proto-sdk:f8231a7") + api("dev.emortal.api:common-proto-sdk:6a9ad1a") api("dev.emortal.api:live-config-parser:f0728b0") api("io.kubernetes:client-java:18.0.1") diff --git a/src/main/java/dev/emortal/minestom/core/module/core/profile/ProfileCommand.java b/src/main/java/dev/emortal/minestom/core/module/core/profile/ProfileCommand.java index 7982052..384ea0d 100644 --- a/src/main/java/dev/emortal/minestom/core/module/core/profile/ProfileCommand.java +++ b/src/main/java/dev/emortal/minestom/core/module/core/profile/ProfileCommand.java @@ -6,6 +6,9 @@ import dev.emortal.minestom.core.utils.command.argument.ArgumentMcPlayer; import dev.emortal.minestom.core.utils.resolver.LocalMcPlayer; import dev.emortal.minestom.core.utils.resolver.PlayerResolver; +import io.grpc.StatusRuntimeException; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import net.minestom.server.command.builder.Command; import net.minestom.server.command.builder.arguments.ArgumentString; import net.minestom.server.entity.Player; @@ -14,6 +17,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.UUID; import java.util.function.Supplier; public class ProfileCommand extends Command { @@ -43,7 +47,7 @@ public ProfileCommand(@NotNull McPlayerService playerService, @NotNull PlayerRes return; } - this.execute(player, player.getUsername()); + this.execute(player, player.getUuid()); }); this.addSyntax((commandSender, context) -> { @@ -53,12 +57,28 @@ public ProfileCommand(@NotNull McPlayerService playerService, @NotNull PlayerRes } LocalMcPlayer target = context.>get("player").get(); - this.execute(player, target.username()); + if (target == null) { + player.sendMessage(Component.text("Player '%s' not found".formatted(context.getRaw("player")), NamedTextColor.RED)); + return; + } + + this.execute(player, target.uuid()); }, playerArgument); } - private void execute(@NotNull Player executor, @NotNull String targetUsername) { - McPlayer player = this.playerService.getPlayerByUsername(targetUsername); + private void execute(@NotNull Player executor, @NotNull UUID targetId) { + McPlayer player; + try { + player = this.playerService.getPlayerById(targetId); + } catch (StatusRuntimeException exception) { + LOGGER.error("Failed to get player to open profile of target {}", targetId, exception); + return; + } + + if (player == null) { + LOGGER.error("Player not found for target (is null) {}", targetId); + return; + } Inventory inventory = new ProfileGui(player); executor.openInventory(inventory); diff --git a/src/main/java/dev/emortal/minestom/core/module/core/profile/ProfileGui.java b/src/main/java/dev/emortal/minestom/core/module/core/profile/ProfileGui.java index bbe497f..7b29d1a 100644 --- a/src/main/java/dev/emortal/minestom/core/module/core/profile/ProfileGui.java +++ b/src/main/java/dev/emortal/minestom/core/module/core/profile/ProfileGui.java @@ -12,14 +12,15 @@ import net.minestom.server.entity.PlayerSkin; import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; -import net.minestom.server.inventory.condition.InventoryConditionResult; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.item.metadata.PlayerHeadMeta; import org.jetbrains.annotations.NotNull; +import java.text.SimpleDateFormat; import java.time.Duration; import java.time.Instant; +import java.util.Date; public class ProfileGui extends Inventory { private static final int[] BLOCKED_SLOTS = new int[]{0, 1, 2, 3, 5, 6, 7, 8, @@ -34,6 +35,8 @@ public class ProfileGui extends Inventory { private static final int ACHIEVEMENTS_SLOT = 21; private static final int GAME_HISTORY_SLOT = 23; + private static final SimpleDateFormat FIRST_LOGIN_FORMAT = new SimpleDateFormat("yyyy-MM-dd hh:mm"); + private final @NotNull McPlayer targetPlayer; public ProfileGui(@NotNull McPlayer targetPlayer) { @@ -62,8 +65,9 @@ private ItemStack createPlayerIcon() { .lore( Component.empty(), this.levelLine().decoration(TextDecoration.ITALIC, false), - this.playtimeLine().decoration(TextDecoration.ITALIC, false), - this.lastOnlineLine().decoration(TextDecoration.ITALIC, false) + this.firstLoginLine().decoration(TextDecoration.ITALIC, false), + this.lastOnlineLine().decoration(TextDecoration.ITALIC, false), + this.playtimeLine().decoration(TextDecoration.ITALIC, false) ) .build(); } @@ -73,9 +77,12 @@ private Component levelLine() { int level = EmortalXP.toLevel(xp); long xpOfLevel = EmortalXP.toXp(level); + long xpOfNextLevel = EmortalXP.toXp(level + 1); + long xpIntoNextLevel = xp - xpOfLevel; + float progress = (float) xpIntoNextLevel / (xpOfNextLevel - xpOfLevel); + return Component.text("Level: ", NamedTextColor.GRAY) - .append(Component.text(level, NamedTextColor.GOLD)) - .append(Component.text(" (+%s XP)".formatted(xp - xpOfLevel), NamedTextColor.YELLOW)); + .append(Component.text("%.2f".formatted(level + progress), NamedTextColor.GOLD)); } private Component playtimeLine() { @@ -86,6 +93,13 @@ private Component playtimeLine() { .append(Component.text(playtimeFormatted, NamedTextColor.GOLD)); } + private Component firstLoginLine() { + Instant firstLogin = ProtoTimestampConverter.fromProto(this.targetPlayer.getFirstLogin()); + + return Component.text("First Login: ", NamedTextColor.GRAY) + .append(Component.text(FIRST_LOGIN_FORMAT.format(Date.from(firstLogin)), NamedTextColor.GOLD)); + } + private Component lastOnlineLine() { TextComponent.Builder builder = Component.text() .append(Component.text("Last Online: ", NamedTextColor.GRAY));