From 77641ecefd2f4ca143ae3f05aebeb8ae9f571796 Mon Sep 17 00:00:00 2001 From: ehko Date: Fri, 29 May 2026 13:29:56 -0400 Subject: [PATCH] bug fix with default rank --- .../java/net/kewwbec/ranks/RanksPlugin.java | 20 ++++++ .../net/kewwbec/ranks/config/RanksConfig.java | 18 +++++ .../ranks/config/RanksConfigLoader.java | 1 + .../ranks/listener/DefaultRankAssigner.java | 68 +++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 src/main/java/net/kewwbec/ranks/listener/DefaultRankAssigner.java diff --git a/src/main/java/net/kewwbec/ranks/RanksPlugin.java b/src/main/java/net/kewwbec/ranks/RanksPlugin.java index 704dcaf..75a7d80 100644 --- a/src/main/java/net/kewwbec/ranks/RanksPlugin.java +++ b/src/main/java/net/kewwbec/ranks/RanksPlugin.java @@ -2,6 +2,7 @@ package net.kewwbec.ranks; import com.hypixel.hytale.logger.HytaleLogger; import com.hypixel.hytale.server.core.event.events.player.PlayerChatEvent; +import com.hypixel.hytale.server.core.event.events.player.PlayerConnectEvent; import com.hypixel.hytale.server.core.permissions.PermissionsModule; import com.hypixel.hytale.server.core.permissions.provider.PermissionProvider; import com.hypixel.hytale.server.core.plugin.JavaPlugin; @@ -9,6 +10,9 @@ import com.hypixel.hytale.server.core.plugin.JavaPluginInit; import net.kewwbec.networkcore.NetworkCore; import net.kewwbec.networkcore.api.DatabaseService; import net.kewwbec.networkcore.api.MessageBus; +import net.kewwbec.networkcore.api.ranks.RankInfo; +import net.kewwbec.networkcore.api.ranks.RankLookup; +import net.kewwbec.ranks.model.Rank; import net.kewwbec.ranks.command.GrantCommands; import net.kewwbec.ranks.command.rank.RankCommand; import net.kewwbec.ranks.config.RanksConfig; @@ -18,6 +22,7 @@ import net.kewwbec.ranks.db.RankRepository; import net.kewwbec.ranks.db.SchemaBootstrap; import net.kewwbec.ranks.db.UserPermRepository; import net.kewwbec.ranks.listener.ChatPrefixListener; +import net.kewwbec.ranks.listener.DefaultRankAssigner; import net.kewwbec.ranks.provider.RanksPermissionProvider; import net.kewwbec.ranks.service.RankService; import net.kewwbec.ranks.service.RanksCache; @@ -104,9 +109,24 @@ public final class RanksPlugin extends JavaPlugin { RankService service = new RankService(rankRepo, grantRepo, userPermRepo, cache); + RankLookup lookup = uuid -> { + try { + Rank r = service.getPrimaryRank(uuid); + if (r == null) return null; + return new RankInfo(r.id(), r.displayName(), r.prefix(), r.color()); + } catch (SQLException e) { + LOGGER.at(Level.WARNING).log("RankLookup failed for %s: %s", uuid, e.getMessage()); + return null; + } + }; + core.registerService(RankLookup.class, lookup); + ChatPrefixListener prefixListener = new ChatPrefixListener(service, config.chat); getEventRegistry().registerGlobal(PlayerChatEvent.class, prefixListener::onChat); + DefaultRankAssigner defaultAssigner = new DefaultRankAssigner(service, config.defaults); + getEventRegistry().registerGlobal(PlayerConnectEvent.class, defaultAssigner::onConnect); + getCommandRegistry().registerCommand(new RankCommand(service)); getCommandRegistry().registerCommand(new GrantCommands.Grant(service)); getCommandRegistry().registerCommand(new GrantCommands.TempGrant(service)); diff --git a/src/main/java/net/kewwbec/ranks/config/RanksConfig.java b/src/main/java/net/kewwbec/ranks/config/RanksConfig.java index 57aad3f..a83e6eb 100644 --- a/src/main/java/net/kewwbec/ranks/config/RanksConfig.java +++ b/src/main/java/net/kewwbec/ranks/config/RanksConfig.java @@ -6,6 +6,7 @@ public final class RanksConfig { public ProviderSection provider = new ProviderSection(); public ChatSection chat = new ChatSection(); public CacheSection cache = new CacheSection(); + public DefaultsSection defaults = new DefaultsSection(); public static final class TableSection { public String ranks = "ranks"; @@ -33,6 +34,23 @@ public final class RanksConfig { public String prefix_format = "{prefix} "; } + public static final class DefaultsSection { + /** + * Rank id every player gets on first connect if they have no active grants. Also promoted + * to primary if the player has no primary rank yet. Set null/blank to disable. + */ + public String default_rank_id = "hytale:None"; + /** + * UUID used as the "granted_by" actor for system-issued default grants. Use a stable + * non-real UUID so audit queries can identify these. + */ + public String system_actor_uuid = "00000000-0000-0000-0000-000000000000"; + /** + * Display name for the system actor. + */ + public String system_actor_name = "SYSTEM"; + } + public static final class CacheSection { /** * Channel used to broadcast cache-invalidation messages across servers. diff --git a/src/main/java/net/kewwbec/ranks/config/RanksConfigLoader.java b/src/main/java/net/kewwbec/ranks/config/RanksConfigLoader.java index e6e2da2..765ae36 100644 --- a/src/main/java/net/kewwbec/ranks/config/RanksConfigLoader.java +++ b/src/main/java/net/kewwbec/ranks/config/RanksConfigLoader.java @@ -32,6 +32,7 @@ public final class RanksConfigLoader { if (parsed.provider == null) parsed.provider = new RanksConfig.ProviderSection(); if (parsed.chat == null) parsed.chat = new RanksConfig.ChatSection(); if (parsed.cache == null) parsed.cache = new RanksConfig.CacheSection(); + if (parsed.defaults == null) parsed.defaults = new RanksConfig.DefaultsSection(); return parsed; } } diff --git a/src/main/java/net/kewwbec/ranks/listener/DefaultRankAssigner.java b/src/main/java/net/kewwbec/ranks/listener/DefaultRankAssigner.java new file mode 100644 index 0000000..a2b923f --- /dev/null +++ b/src/main/java/net/kewwbec/ranks/listener/DefaultRankAssigner.java @@ -0,0 +1,68 @@ +package net.kewwbec.ranks.listener; + +import com.hypixel.hytale.logger.HytaleLogger; +import com.hypixel.hytale.server.core.event.events.player.PlayerConnectEvent; +import com.hypixel.hytale.server.core.universe.PlayerRef; +import net.kewwbec.ranks.config.RanksConfig; +import net.kewwbec.ranks.service.RankService; + +import javax.annotation.Nonnull; +import java.sql.SQLException; +import java.util.Set; +import java.util.UUID; +import java.util.logging.Level; + +/** + * On PlayerConnectEvent: if the player has no active rank grants, grant them the configured + * default rank (e.g. {@code hytale:None}). If they have grants but no primary rank set, promote + * the default (when present in their active grants) to primary. + * + * Idempotent: a player with existing grants is left alone. Race-tolerant: if two servers see the + * connect at the same time, both attempt a grant; the cache invalidation cleans it up and the + * surplus grant is harmless (still maps to the same primary rank). + */ +public final class DefaultRankAssigner { + + private static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass(); + + private final RankService service; + private final RanksConfig.DefaultsSection cfg; + private final UUID systemActor; + + public DefaultRankAssigner(@Nonnull RankService service, @Nonnull RanksConfig.DefaultsSection cfg) { + this.service = service; + this.cfg = cfg; + UUID parsed; + try { parsed = UUID.fromString(cfg.system_actor_uuid); } + catch (RuntimeException e) { parsed = new UUID(0L, 0L); } + this.systemActor = parsed; + } + + public void onConnect(@Nonnull PlayerConnectEvent event) { + if (cfg.default_rank_id == null || cfg.default_rank_id.isBlank()) return; + PlayerRef ref = event.getPlayerRef(); + if (ref == null) return; + UUID uuid = ref.getUuid(); + String name = ref.getUsername(); + try { + Set active = service.getActiveRankIds(uuid); + if (active.isEmpty()) { + long id = service.grant(uuid, cfg.default_rank_id, systemActor, cfg.system_actor_name, null); + if (id > 0) { + service.setPrimary(uuid, cfg.default_rank_id); + LOGGER.at(Level.INFO).log("Granted default rank '%s' to %s (%s)", cfg.default_rank_id, name, uuid); + } else { + LOGGER.at(Level.WARNING).log("Default rank '%s' not found in DB; cannot grant to %s", cfg.default_rank_id, name); + } + return; + } + String primary = service.getPrimaryRankId(uuid); + if (primary == null && active.contains(cfg.default_rank_id)) { + service.setPrimary(uuid, cfg.default_rank_id); + } + } catch (SQLException e) { + ((HytaleLogger.Api) LOGGER.at(Level.WARNING).withCause(e)) + .log("Default rank assignment failed for %s", uuid); + } + } +}