Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Command to check when player was last online #18

Merged
merged 5 commits into from
May 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions src/main/java/pro/cloudnode/smp/smpcore/Configuration.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
package pro.cloudnode.smp.smpcore;

import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Formatter;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.jetbrains.annotations.NotNull;

import java.time.temporal.ChronoUnit;
import java.util.Objects;

public final class Configuration extends BaseConfig {
public Configuration() {
super("config.yml");
Expand All @@ -25,4 +34,30 @@ public int membersInactiveDays() {
public int altsMax() {
return config.getInt("alts.max");
}

public @NotNull Component relativeTime(final int t, final @NotNull ChronoUnit unit) {
final @NotNull String formatString = Objects.requireNonNull(config.getString("relative-time." + switch (unit) {
case SECONDS -> "seconds";
case MINUTES -> "minutes";
case HOURS -> "hours";
case DAYS -> "days";
case MONTHS -> "months";
case YEARS -> "years";
default -> {
throw new IllegalStateException("No relative time format for ChronoUnit " + unit);
}
}));
return MiniMessage.miniMessage()
.deserialize(formatString, Formatter.number("t", t), Formatter.choice("format", Math.abs(t)));
}

public @NotNull Component relativeTimeFuture(final @NotNull Component relativeTime) {
return MiniMessage.miniMessage()
.deserialize(Objects.requireNonNull(config.getString("relative-time.future")), Placeholder.component("t", relativeTime));
}

public @NotNull Component relativeTimePast(final @NotNull Component relativeTime) {
return MiniMessage.miniMessage()
.deserialize(Objects.requireNonNull(config.getString("relative-time.past")), Placeholder.component("t", relativeTime));
}
}
35 changes: 35 additions & 0 deletions src/main/java/pro/cloudnode/smp/smpcore/Messages.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Formatter;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.time.ZoneOffset;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
Expand Down Expand Up @@ -141,6 +144,32 @@ public Messages() {
.ofNullable(alt.player().getName()).orElse(alt.player().getUniqueId().toString())));
}

public @NotNull Component seen(final @NotNull Member member) {
if (member.player().isOnline()) return MiniMessage.miniMessage()
.deserialize(Objects.requireNonNull(config.getString("seen.online")), Placeholder.unparsed("player", Optional
.ofNullable(member.player().getName()).orElse(member.uuid.toString())));
final @NotNull Date lastSeen = new Date(member.player().getLastSeen());
return MiniMessage.miniMessage()
.deserialize(Objects.requireNonNull(config.getString(member.isActive() ? "seen.active" : "seen.inactive")), Placeholder.unparsed("player", Optional
.ofNullable(member.player().getName())
.orElse(member.uuid.toString())), Formatter.date("last-seen", lastSeen.toInstant()
.atZone(ZoneOffset.UTC)
.toLocalDateTime()), Placeholder.component("last-seen-relative", SMPCore.relativeTime(lastSeen)));
}

public @NotNull Component seen(final @NotNull OfflinePlayer player) {
if (player.isOnline()) return MiniMessage.miniMessage()
.deserialize(Objects.requireNonNull(config.getString("seen.online")), Placeholder.unparsed("player", Optional
.ofNullable(player.getName()).orElse(player.getUniqueId().toString())));
final @NotNull Date lastSeen = new Date(player.getLastSeen());
return MiniMessage.miniMessage()
.deserialize(Objects.requireNonNull(config.getString("seen.non-member")), Placeholder.unparsed("player", Optional
.ofNullable(player.getName())
.orElse(player.getUniqueId().toString())), Formatter.date("last-seen", lastSeen.toInstant()
.atZone(ZoneOffset.UTC)
.toLocalDateTime()), Placeholder.component("last-seen-relative", SMPCore.relativeTime(lastSeen)));
}

// errors

public @NotNull Component errorNoPermission() {
Expand Down Expand Up @@ -204,6 +233,12 @@ public Messages() {
.ofNullable(player.player().getName()).orElse(player.player().getUniqueId().toString())));
}

public @NotNull Component errorNeverJoined(final @NotNull OfflinePlayer player) {
return MiniMessage.miniMessage()
.deserialize(Objects.requireNonNull(config.getString("error.never-joined")), Placeholder.unparsed("player", Optional
.ofNullable(player.getName()).orElse(player.getUniqueId().toString())));
}

public record SubCommandArgument(@NotNull String name, boolean required) {
public @NotNull Component component() {
return required ? SMPCore.messages().subCommandArgumentRequired(name) : SMPCore.messages()
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/pro/cloudnode/smp/smpcore/Permission.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,6 @@ public final class Permission {
* Remove an alt that has joined the server
*/
public static @NotNull String ALT_REMOVE_JOINED = "smpcore.alt.remove.joined";

public static @NotNull String SEEN = "smpcore.seen";
}
30 changes: 30 additions & 0 deletions src/main/java/pro/cloudnode/smp/smpcore/SMPCore.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import net.kyori.adventure.text.Component;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import pro.cloudnode.smp.smpcore.command.AltsCommand;
import pro.cloudnode.smp.smpcore.command.BanCommand;
import pro.cloudnode.smp.smpcore.command.Command;
import pro.cloudnode.smp.smpcore.command.MainCommand;
import pro.cloudnode.smp.smpcore.command.SeenCommand;
import pro.cloudnode.smp.smpcore.command.UnbanCommand;
import pro.cloudnode.smp.smpcore.listener.NationTeamUpdaterListener;

Expand All @@ -17,6 +19,8 @@
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
Expand Down Expand Up @@ -68,6 +72,7 @@ public void onEnable() {
put("smpcore", new MainCommand());
put("ban", new BanCommand());
put("unban", new UnbanCommand());
put("seen", new SeenCommand());
}};
commands.put("alts", new AltsCommand(commands.get("smpcore")));
for (final @NotNull Map.Entry<@NotNull String, @NotNull Command> entry : commands.entrySet())
Expand Down Expand Up @@ -162,4 +167,29 @@ public static boolean ifDisallowedCharacters(final @NotNull String source, final
}
return false;
}

public static @NotNull Component relativeTime(final @NotNull Date date1, final @NotNull Date date2) {
final long diff = date1.getTime() - date2.getTime();
final long abs = Math.abs(diff);
final double seconds = Math.floor(abs / 1000.0);
final double minutes = Math.floor(seconds / 60.0);
final double hours = Math.floor(minutes / 60.0);
final double days = Math.floor(hours / 24.0);
final double months = Math.floor(days / 30.0);
final double years = Math.floor(months / 12.0);

final @NotNull Component t;
if (years > 0) t = SMPCore.config().relativeTime((int) years, ChronoUnit.YEARS);
else if (months > 0) t = SMPCore.config().relativeTime((int) months, ChronoUnit.MONTHS);
else if (days > 0) t = SMPCore.config().relativeTime((int) days, ChronoUnit.DAYS);
else if (hours > 0) t = SMPCore.config().relativeTime((int) hours, ChronoUnit.HOURS);
else if (minutes > 0) t = SMPCore.config().relativeTime((int) minutes, ChronoUnit.MINUTES);
else t = SMPCore.config().relativeTime((int) seconds, ChronoUnit.SECONDS);

return diff < 0 ? SMPCore.config().relativeTimePast(t) : SMPCore.config().relativeTimeFuture(t);
}

public static @NotNull Component relativeTime(final @NotNull Date date) {
return relativeTime(date, new Date());
}
}
34 changes: 34 additions & 0 deletions src/main/java/pro/cloudnode/smp/smpcore/command/SeenCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package pro.cloudnode.smp.smpcore.command;

import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import pro.cloudnode.smp.smpcore.Member;
import pro.cloudnode.smp.smpcore.Permission;
import pro.cloudnode.smp.smpcore.SMPCore;

import java.util.List;
import java.util.Optional;

public final class SeenCommand extends Command {

@Override
public boolean run(@NotNull CommandSender sender, @NotNull String label, @NotNull String @NotNull [] args) {
if (!sender.hasPermission(Permission.SEEN)) return sendMessage(sender, SMPCore.messages().errorNoPermission());

if (args.length != 1) return sendMessage(sender, SMPCore.messages().usage(label, "<player>"));

final @NotNull OfflinePlayer player = sender.getServer().getOfflinePlayer(args[0]);

if (!player.hasPlayedBefore()) return sendMessage(sender, SMPCore.messages().errorNeverJoined(player));

final @NotNull Optional<@NotNull Member> member = Member.get(player.getUniqueId());
return member.map(m -> sendMessage(sender, SMPCore.messages().seen(m)))
.orElseGet(() -> sendMessage(sender, SMPCore.messages().seen(player)));
}

@Override
public @NotNull List<@NotNull String> tab(@NotNull CommandSender sender, @NotNull String label, @NotNull String @NotNull [] args) {
return Member.getNames().stream().toList();
}
}
10 changes: 10 additions & 0 deletions src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,13 @@ members:
alts:
# Maximum number of alts you can have
max: 10

relative-time:
seconds: <t> <format:'0#seconds|1#second|1<seconds'>
minutes: <t> <format:'0#minutes|1#minute|1<minutes'>
hours: <t> <format:'0#hours|1#hour|1<hours'>
days: <t> <format:'0#days|1#day|1<days'>
months: <t> <format:'0#months|1#month|1<months'>
years: <t> <format:'0#years|1#year|1<years'>
future: in <t>
past: <t> ago
7 changes: 7 additions & 0 deletions src/main/resources/messages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ alts:
created: <green>(!) Created member profile for <gray><alt></gray> and added as an alt.</green>
deleted: <green>(!) Deleted alt member profile for <gray><alt></gray>.</green>

seen:
online: <green>(!) Player <gray><player></gray> is online.</green>
active: <aqua>(!) Member <white><player></white> is <green>active</green> and last seen on <white><last-seen:'dd MMM yyyy HH:mm'> UTC</white> <gray>(<last-seen-relative>)</aqua>
inactive: <aqua>(!) Member <white><player></white> is <red>inactive</red> and last seen on <white><last-seen:'dd MMM yyyy HH:mm'> UTC</white> <gray>(<last-seen-relative>)</aqua>
non-member: <aqua>(!) Player <white><player></white> was last seen on <white><last-seen:'dd MMM yyyy HH:mm'> UTC</white> <gray>(<last-seen-relative>)</aqua>

error:
no-permission: <red>(!) You don't have permission to use this command.</red>
player-not-banned: <red>(!) Player <gray><player></gray> is not banned and is not a member.</red>
Expand All @@ -45,3 +51,4 @@ error:
max-alts-reached: <red>(!) You cannot have more than <gray><max></gray> alts.</red>
member-not-alt: <red>(!) Member <gray><player></gray> is not an alt.</red>
remove-joined-alt: <red>(!) You cannot remove alt player <gray><alt></gray> because they have played the server.</red>
never-joined: <red>(!) Player <gray><player></gray> has never played on the server.</red>
5 changes: 5 additions & 0 deletions src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,8 @@ commands:
description: Manage alternate accounts
usage: /<command>
aliases: [ alt ]
seen:
permission: smpcore.seen
description: Check when a player was last online
usage: /<command> <player>
aliases: [ lastseen ]
Loading