diff --git a/src/main/java/pro/cloudnode/smp/smpcore/Configuration.java b/src/main/java/pro/cloudnode/smp/smpcore/Configuration.java index 624e4bb..04f01c5 100644 --- a/src/main/java/pro/cloudnode/smp/smpcore/Configuration.java +++ b/src/main/java/pro/cloudnode/smp/smpcore/Configuration.java @@ -101,4 +101,12 @@ public boolean deathBanEnabled() { Objects.requireNonNull(config.getString("relative-time.duration-indefinite")) ); } + + public @NotNull String staffTeamId() { + return Objects.requireNonNull(config.getString("staff-team.id")); + } + + public @NotNull Component staffTeamName() { + return MiniMessage.miniMessage().deserialize(Objects.requireNonNull(config.getString("staff-team.name"))); + } } diff --git a/src/main/java/pro/cloudnode/smp/smpcore/Member.java b/src/main/java/pro/cloudnode/smp/smpcore/Member.java index 01e6f3e..1ef1955 100644 --- a/src/main/java/pro/cloudnode/smp/smpcore/Member.java +++ b/src/main/java/pro/cloudnode/smp/smpcore/Member.java @@ -1,7 +1,10 @@ package pro.cloudnode.smp.smpcore; import io.papermc.paper.ban.BanListType; +import net.kyori.adventure.text.Component; import org.bukkit.OfflinePlayer; +import org.bukkit.scoreboard.Scoreboard; +import org.bukkit.scoreboard.Team; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -212,6 +215,21 @@ public boolean delete() { return members; } + public static @NotNull Set<@NotNull Member> getStaff() { + final @NotNull Set<@NotNull Member> members = new HashSet<>(); + try ( + final @NotNull PreparedStatement stmt = SMPCore.getInstance().conn + .prepareStatement("SELECT * FROM `members` WHERE `staff` = true") + ) { + final @NotNull ResultSet rs = stmt.executeQuery(); + while (rs.next()) members.add(new Member(rs)); + } + catch (final @NotNull SQLException e) { + SMPCore.getInstance().getLogger().log(Level.SEVERE, "could not get staff members", e); + } + return members; + } + public static int count() { try ( final @NotNull PreparedStatement stmt = SMPCore.getInstance().conn.prepareStatement("SELECT COUNT(*) as `n` FROM `members`") @@ -235,4 +253,34 @@ public static int count() { public static @NotNull Set<@NotNull String> getAltNames() { return get().stream().filter(Member::isAlt).map(m -> m.player().getName()).filter(Objects::nonNull).collect(Collectors.toSet()); } + + public static @NotNull Team createStaffTeam() { + final Scoreboard scoreboard = SMPCore.getInstance().getServer().getScoreboardManager().getMainScoreboard(); + + final Optional existing = Optional.ofNullable(scoreboard.getTeam(SMPCore.config().staffTeamId())); + existing.ifPresent(Team::unregister); + + final Team team = scoreboard.registerNewTeam(SMPCore.config().staffTeamId()); + + team.setAllowFriendlyFire(false); + team.setCanSeeFriendlyInvisibles(true); + + team.setOption(Team.Option.DEATH_MESSAGE_VISIBILITY, Team.OptionStatus.FOR_OWN_TEAM); + + team.displayName(SMPCore.config().staffTeamName()); + team.prefix(SMPCore.config().staffTeamName().append(Component.text(" "))); + + for (final Member staff : getStaff()) + team.addPlayer(staff.player()); + + return team; + } + + public static @NotNull Team getStaffTeam() { + return Optional.ofNullable( + SMPCore.getInstance().getServer().getScoreboardManager().getMainScoreboard().getTeam( + SMPCore.config().staffTeamId() + ) + ).orElseGet(Member::createStaffTeam); + } } diff --git a/src/main/java/pro/cloudnode/smp/smpcore/Nation.java b/src/main/java/pro/cloudnode/smp/smpcore/Nation.java index c7e125e..b12cbe1 100644 --- a/src/main/java/pro/cloudnode/smp/smpcore/Nation.java +++ b/src/main/java/pro/cloudnode/smp/smpcore/Nation.java @@ -9,7 +9,6 @@ import org.bukkit.scoreboard.Team; import org.jetbrains.annotations.NotNull; -import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -128,6 +127,9 @@ public Nation(final @NotNull String id, final @NotNull String name, final @NotNu team.displayName(Component.text(shortName).color(TextColor.color(Integer.decode("0x" + color))).hoverEvent(HoverEvent.showText(Component.text(name)))); team.prefix(Component.text(shortName + " ").color(TextColor.color(Integer.decode("0x" + color))).hoverEvent(HoverEvent.showText(Component.text(name)))); for (final @NotNull Member member : citizens()) try { + if (member.staff) + continue; + team.addPlayer(member.player()); } catch (final @NotNull IllegalArgumentException ignored) {} @@ -145,7 +147,9 @@ public void add(final @NotNull Member member) { member.nation().ifPresent(nation -> nation.remove(member)); member.nationID = id; member.save(); - getTeam().addPlayer(member.player()); + + if (!member.staff) + getTeam().addPlayer(member.player()); Audience.audience(onlinePlayers()).sendMessage(SMPCore.messages().nationJoinJoined(member)); diff --git a/src/main/java/pro/cloudnode/smp/smpcore/SMPCore.java b/src/main/java/pro/cloudnode/smp/smpcore/SMPCore.java index 99c0e42..e8ed2a2 100644 --- a/src/main/java/pro/cloudnode/smp/smpcore/SMPCore.java +++ b/src/main/java/pro/cloudnode/smp/smpcore/SMPCore.java @@ -111,6 +111,7 @@ public void reload() { config.reload(); if (messages != null) messages.reload(); setupDatabase(); + Member.createStaffTeam(); if (rest != null) rest.javalin.stop(); rest = new REST(config.apiPort()); } diff --git a/src/main/java/pro/cloudnode/smp/smpcore/listener/PlayerJoinListener.java b/src/main/java/pro/cloudnode/smp/smpcore/listener/PlayerJoinListener.java index bbadd86..a17985b 100644 --- a/src/main/java/pro/cloudnode/smp/smpcore/listener/PlayerJoinListener.java +++ b/src/main/java/pro/cloudnode/smp/smpcore/listener/PlayerJoinListener.java @@ -21,12 +21,26 @@ public void putPlayerInNationTeam(final @NotNull PlayerJoinEvent event) { final @NotNull Optional<@NotNull Member> member = Member.get(player); final @NotNull Optional<@NotNull Team> team = Optional.ofNullable(player.getScoreboard() .getPlayerTeam(player)); + final Team staffTeam = Member.getStaffTeam(); + final @NotNull Optional<@NotNull Nation> nationFromTeam = team.flatMap(Nation::get); if (member.isEmpty()) { // no longer a member, but in a nation's team? nationFromTeam.ifPresent(ignored -> team.get().removePlayer(player)); + staffTeam.removePlayer(player); + return; + } + + if (member.get().staff) { + if (team.isPresent() && !team.get().equals(staffTeam)) + team.get().removePlayer(player); + + staffTeam.addPlayer(player); + return; } + staffTeam.removePlayer(player); + final @NotNull Optional<@NotNull Nation> nation = member.get().nation(); if (nation.isEmpty() && team.isPresent()) { // no longer in a nation, but in a nation's team? diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index ee1baa8..fcfc296 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -47,3 +47,7 @@ relative-time: past: ago duration: for duration-indefinite: forever + +staff-team: + id: staff + name: STAFF