diff --git a/src/main/java/net/tfminecraft/rpcharacters/Cache.java b/src/main/java/net/tfminecraft/rpcharacters/Cache.java index 99f03c7..dca9ab4 100644 --- a/src/main/java/net/tfminecraft/rpcharacters/Cache.java +++ b/src/main/java/net/tfminecraft/rpcharacters/Cache.java @@ -32,7 +32,6 @@ public class Cache { public static boolean requireCharacter; /** Playtest server: tag in-game creates and stop syncing characters with the website. */ - public static boolean devCharacters; public static boolean noCharacterFreeze; public static boolean lackingCluesFreeze; public static boolean excessCharactersFreeze; diff --git a/src/main/java/net/tfminecraft/rpcharacters/creation/CharacterCreation.java b/src/main/java/net/tfminecraft/rpcharacters/creation/CharacterCreation.java index 84a1813..60a185d 100644 --- a/src/main/java/net/tfminecraft/rpcharacters/creation/CharacterCreation.java +++ b/src/main/java/net/tfminecraft/rpcharacters/creation/CharacterCreation.java @@ -34,7 +34,6 @@ import net.tfminecraft.rpcharacters.RPCharacters; -import net.tfminecraft.rpcharacters.Cache; import net.tfminecraft.rpcharacters.loaders.StageLoader; @@ -828,12 +827,6 @@ public void finish() { character.update(); - if (Cache.devCharacters) { - - character.setDev(true); - - } - pd.addCharacter(character); net.tfminecraft.rpcharacters.lifecycle.CharacterLifecycle.fireCreated(p, pd.getUniqueId(), character); diff --git a/src/main/java/net/tfminecraft/rpcharacters/database/Database.java b/src/main/java/net/tfminecraft/rpcharacters/database/Database.java index d99b9ac..dedbea6 100644 --- a/src/main/java/net/tfminecraft/rpcharacters/database/Database.java +++ b/src/main/java/net/tfminecraft/rpcharacters/database/Database.java @@ -702,9 +702,6 @@ private void loadPersonaFields(RPCharacter character, JSONObject characterJson) if (characterJson.containsKey("hidden")) { character.setHidden(Boolean.parseBoolean(characterJson.get("hidden").toString())); } - if (characterJson.containsKey("dev")) { - character.setDev(Boolean.parseBoolean(characterJson.get("dev").toString())); - } if (characterJson.containsKey("kit-statuses")) { Object raw = characterJson.get("kit-statuses"); if (raw instanceof JSONObject statuses) { @@ -807,9 +804,6 @@ private void savePersonaFields(HashMap defaults, RPCharacter cha if (character.isHidden()) { defaults.put("hidden", "true"); } - if (character.isDev()) { - defaults.put("dev", "true"); - } if (!character.getKitStatuses().isEmpty()) { JSONObject statuses = new JSONObject(); for (var entry : character.getKitStatuses().entrySet()) { diff --git a/src/main/java/net/tfminecraft/rpcharacters/ingest/CharacterIngestService.java b/src/main/java/net/tfminecraft/rpcharacters/ingest/CharacterIngestService.java index 074207f..1abf096 100644 --- a/src/main/java/net/tfminecraft/rpcharacters/ingest/CharacterIngestService.java +++ b/src/main/java/net/tfminecraft/rpcharacters/ingest/CharacterIngestService.java @@ -16,7 +16,6 @@ import org.json.simple.JSONArray; import org.json.simple.JSONObject; -import net.tfminecraft.rpcharacters.Cache; import net.tfminecraft.rpcharacters.RPCharacters; import net.tfminecraft.rpcharacters.api.ProvinceSystemClient; import net.tfminecraft.rpcharacters.calendar.AgeCalculator; @@ -53,7 +52,7 @@ private CharacterIngestService() {} * Pull if the 15s cooldown has elapsed. Used by join, reload, and the timer. */ public static void tryPullAsync(JavaPlugin plugin) { - if (plugin == null || Cache.devCharacters) { + if (plugin == null) { return; } long now = System.currentTimeMillis(); @@ -74,12 +73,6 @@ public static void forcePullAsync(JavaPlugin plugin) { if (plugin == null) { return; } - if (Cache.devCharacters) { - plugin.getLogger().warning( - "[character-ingest] skipped: dev-characters is on, website characters are not synced" - ); - return; - } lastPullAtMs.set(System.currentTimeMillis()); pullAsync(plugin); } @@ -89,7 +82,7 @@ public static void forcePullAsync(JavaPlugin plugin) { * (or immediately if the pull is skipped). */ public static void tryPullForPlayerAsync(JavaPlugin plugin, UUID playerUuid) { - if (plugin == null || playerUuid == null || Cache.devCharacters) { + if (plugin == null || playerUuid == null) { return; } long now = System.currentTimeMillis(); @@ -127,7 +120,7 @@ public static void stopPeriodicPull() { } public static void pullAsync(JavaPlugin plugin) { - if (plugin == null || Cache.devCharacters) { + if (plugin == null) { return; } Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { @@ -153,7 +146,7 @@ public static void pullAsync(JavaPlugin plugin) { } public static void pullForPlayerAsync(JavaPlugin plugin, UUID playerUuid) { - if (plugin == null || playerUuid == null || Cache.devCharacters) { + if (plugin == null || playerUuid == null) { return; } Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { diff --git a/src/main/java/net/tfminecraft/rpcharacters/ingest/KitCustomiseIngestService.java b/src/main/java/net/tfminecraft/rpcharacters/ingest/KitCustomiseIngestService.java index 9c9872b..97acd72 100644 --- a/src/main/java/net/tfminecraft/rpcharacters/ingest/KitCustomiseIngestService.java +++ b/src/main/java/net/tfminecraft/rpcharacters/ingest/KitCustomiseIngestService.java @@ -13,7 +13,6 @@ import org.json.simple.JSONArray; import org.json.simple.JSONObject; -import net.tfminecraft.rpcharacters.Cache; import net.tfminecraft.rpcharacters.RPCharacters; import net.tfminecraft.rpcharacters.api.ProvinceSystemClient; import net.tfminecraft.rpcharacters.database.Database; @@ -43,7 +42,7 @@ public static void pullAsync(JavaPlugin plugin) { * Safe to call from {@link CharacterIngestService} after creates pull. */ public static void pullNow(JavaPlugin plugin) { - if (plugin == null || Cache.devCharacters) { + if (plugin == null) { return; } ProvinceSystemClient.SimpleResult pending = @@ -83,7 +82,7 @@ public static List applyReadyForCharacterOnMain( RPCharacter character, List all ) { - if (player == null || character == null || Cache.devCharacters) { + if (player == null || character == null) { return List.of(); } String characterId = character.getId(); diff --git a/src/main/java/net/tfminecraft/rpcharacters/ingest/RosterSyncService.java b/src/main/java/net/tfminecraft/rpcharacters/ingest/RosterSyncService.java index fc7d9f8..401595b 100644 --- a/src/main/java/net/tfminecraft/rpcharacters/ingest/RosterSyncService.java +++ b/src/main/java/net/tfminecraft/rpcharacters/ingest/RosterSyncService.java @@ -41,14 +41,14 @@ public final class RosterSyncService { private RosterSyncService() {} public static void pushRosterAsync(UUID playerUuid) { - if (playerUuid == null || RPCharacters.plugin == null || Cache.devCharacters) { + if (playerUuid == null || RPCharacters.plugin == null) { return; } Bukkit.getScheduler().runTaskAsynchronously(RPCharacters.plugin, () -> pushRosterNow(playerUuid)); } public static void pushRosterForPlayer(Player player) { - if (player == null || Cache.devCharacters) { + if (player == null) { return; } pushRosterAsync(player.getUniqueId()); @@ -56,7 +56,7 @@ public static void pushRosterForPlayer(Player player) { /** Push roster for every online player (e.g. after {@code /rpcharacter reload}). */ public static void pushAllOnlineAsync() { - if (RPCharacters.plugin == null || Cache.devCharacters) { + if (RPCharacters.plugin == null) { return; } for (Player player : Bukkit.getOnlinePlayers()) { @@ -68,7 +68,7 @@ public static void pushAllOnlineAsync() { @SuppressWarnings("unchecked") public static void pushRosterNow(UUID playerUuid) { - if (playerUuid == null || Cache.devCharacters) { + if (playerUuid == null) { return; } PlayerData pd = null; @@ -104,7 +104,7 @@ public static void pushRosterNow(UUID playerUuid) { root.put("player_uuid", playerUuid.toString()); JSONArray characters = new JSONArray(); for (RPCharacter c : pd.getCharacters()) { - if (c == null || c.getId() == null || c.isDev()) { + if (c == null || c.getId() == null) { continue; } JSONObject row = new JSONObject(); diff --git a/src/main/java/net/tfminecraft/rpcharacters/kit/KitService.java b/src/main/java/net/tfminecraft/rpcharacters/kit/KitService.java index 2e392b6..ba80f2d 100644 --- a/src/main/java/net/tfminecraft/rpcharacters/kit/KitService.java +++ b/src/main/java/net/tfminecraft/rpcharacters/kit/KitService.java @@ -15,7 +15,6 @@ import org.json.simple.JSONObject; import net.tfminecraft.tlibs.TLibs; -import net.tfminecraft.rpcharacters.Cache; import net.tfminecraft.rpcharacters.loaders.KitLoader; import net.tfminecraft.rpcharacters.managers.PlayerManager; import net.tfminecraft.rpcharacters.objects.PlayerData; @@ -148,27 +147,25 @@ public static void tryClaim(Player player, String kitIdRaw) { } List pendingItems = List.of(); - if (!Cache.devCharacters) { - ProvinceSystemClient.SimpleResult pending = - ProvinceSystemClient.fetchPendingLoreItems(); - if (!pending.ok) { - RPCharacters.plugin.getLogger().warning( - "[kit-customise] claim-pull failed: " + pending.error + ProvinceSystemClient.SimpleResult pending = + ProvinceSystemClient.fetchPendingLoreItems(); + if (!pending.ok) { + RPCharacters.plugin.getLogger().warning( + "[kit-customise] claim-pull failed: " + pending.error + ); + } else { + String body = pending.body != null ? pending.body : ""; + if (body.isBlank()) { + RPCharacters.plugin.getLogger().info( + "[kit-customise] claim-pull empty body char=" + characterId + + " uuid=" + playerId ); } else { - String body = pending.body != null ? pending.body : ""; - if (body.isBlank()) { - RPCharacters.plugin.getLogger().info( - "[kit-customise] claim-pull empty body char=" + characterId - + " uuid=" + playerId - ); - } else { - RPCharacters.plugin.getLogger().info( - "[kit-customise] claim-pull body=" + body - ); - } - pendingItems = ProvinceSystemClient.parsePendingLoreItems(pending.body); + RPCharacters.plugin.getLogger().info( + "[kit-customise] claim-pull body=" + body + ); } + pendingItems = ProvinceSystemClient.parsePendingLoreItems(pending.body); } List itemsForMain = pendingItems; diff --git a/src/main/java/net/tfminecraft/rpcharacters/loaders/ConfigLoader.java b/src/main/java/net/tfminecraft/rpcharacters/loaders/ConfigLoader.java index c1d32fe..9cc540e 100644 --- a/src/main/java/net/tfminecraft/rpcharacters/loaders/ConfigLoader.java +++ b/src/main/java/net/tfminecraft/rpcharacters/loaders/ConfigLoader.java @@ -46,7 +46,6 @@ public void load(File configFile) { Cache.backgroundTraitTypes = config.getStringList("background-trait-types"); Cache.continent = config.getString("continent", "Cerrith"); Cache.requireCharacter = config.getBoolean("require-character", false); - Cache.devCharacters = config.getBoolean("dev-characters", false); Cache.noCharacterFreeze = config.getBoolean("no-character-freeze", true); Cache.lackingCluesFreeze = config.getBoolean("lacking-clues-freeze", true); Cache.excessCharactersFreeze = config.getBoolean("excess-characters-freeze", true); diff --git a/src/main/java/net/tfminecraft/rpcharacters/managers/CommandManager.java b/src/main/java/net/tfminecraft/rpcharacters/managers/CommandManager.java index 9d0d351..f2a1af7 100644 --- a/src/main/java/net/tfminecraft/rpcharacters/managers/CommandManager.java +++ b/src/main/java/net/tfminecraft/rpcharacters/managers/CommandManager.java @@ -124,11 +124,6 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String RPTexts.send(sender, RPTexts.ERROR + "Usage: /rpcharacter pending sync"); return true; } - if (Cache.devCharacters) { - RPTexts.send(sender, RPTexts.ERROR + "Website character sync is off while " - + RPTexts.WARN + "dev-characters" + RPTexts.ERROR + " is enabled."); - return true; - } RPTexts.send(sender, RPTexts.COMMAND + "Pulling pending web character creates…"); net.tfminecraft.rpcharacters.ingest.CharacterIngestService.forcePullAsync(RPCharacters.plugin); RPTexts.send(sender, RPTexts.SUCCESS + "Pending sync started (see console for results)."); diff --git a/src/main/java/net/tfminecraft/rpcharacters/objects/RPCharacter.java b/src/main/java/net/tfminecraft/rpcharacters/objects/RPCharacter.java index a81f02d..e9db746 100644 --- a/src/main/java/net/tfminecraft/rpcharacters/objects/RPCharacter.java +++ b/src/main/java/net/tfminecraft/rpcharacters/objects/RPCharacter.java @@ -70,8 +70,6 @@ public class RPCharacter { private String slug; private boolean hidden; private boolean mailListed = true; - /** Throwaway character made in-game while dev-characters is on. */ - private boolean dev; /** Per grant-kit id. Empty/missing kit = legacy never claim for that kit. */ private final Map kitStatuses = new HashMap<>(); @@ -555,14 +553,6 @@ public void setHidden(boolean hidden) { this.hidden = hidden; } - public boolean isDev() { - return dev; - } - - public void setDev(boolean dev) { - this.dev = dev; - } - public Map getKitStatuses() { return kitStatuses; } diff --git a/src/main/java/net/tfminecraft/rpcharacters/utils/CommandTabCompleter.java b/src/main/java/net/tfminecraft/rpcharacters/utils/CommandTabCompleter.java index 82268e4..5bf5246 100644 --- a/src/main/java/net/tfminecraft/rpcharacters/utils/CommandTabCompleter.java +++ b/src/main/java/net/tfminecraft/rpcharacters/utils/CommandTabCompleter.java @@ -110,7 +110,7 @@ public List onTabComplete(CommandSender sender, Command cmd, String labe return filter(List.of("sync"), args[1]); } if (args[0].equalsIgnoreCase("wipe") && Permissions.isAdmin(sender)) { - return filter(List.of("website", "tagged"), args[1]); + return filter(List.of("website"), args[1]); } if (args[0].equalsIgnoreCase("stage") && Permissions.isAdmin(sender)) { return filter(List.of("preview"), args[1]); @@ -193,7 +193,7 @@ public List onTabComplete(CommandSender sender, Command cmd, String labe } } } else if (args[0].equalsIgnoreCase("wipe") && Permissions.isAdmin(sender) - && (args[1].equalsIgnoreCase("website") || args[1].equalsIgnoreCase("tagged"))) { + && args[1].equalsIgnoreCase("website")) { completions.add("confirm"); } else if (args[0].equalsIgnoreCase("discordgate") && Permissions.isAdmin(sender)) { completions.add("on"); diff --git a/src/main/java/net/tfminecraft/rpcharacters/wipe/CharacterWipeService.java b/src/main/java/net/tfminecraft/rpcharacters/wipe/CharacterWipeService.java deleted file mode 100644 index 324033f..0000000 --- a/src/main/java/net/tfminecraft/rpcharacters/wipe/CharacterWipeService.java +++ /dev/null @@ -1,191 +0,0 @@ -package net.tfminecraft.rpcharacters.wipe; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.function.Predicate; - -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - -import net.tfminecraft.rpcharacters.RPCharacters; -import net.tfminecraft.rpcharacters.database.Database; -import net.tfminecraft.rpcharacters.managers.PlayerManager; -import net.tfminecraft.rpcharacters.objects.PlayerData; -import net.tfminecraft.rpcharacters.objects.RPCharacter; -import net.tfminecraft.rpcharacters.enums.Status; -import net.tfminecraft.rpcharacters.ingest.RosterSyncService; -import net.tfminecraft.rpcharacters.mail.MailRecipientDirectory; -import net.tfminecraft.rpcharacters.wardrobe.WardrobeService; - -/** - * Hard-deletes characters from RPCharacters data. Unlike permakill this removes the - * character record instead of marking it dead. - */ -public final class CharacterWipeService { - - private static final String CHARACTER_DATA_PATH = "plugins/RPCharacters/data/characterdata"; - - private static final Database DB = new Database(); - - private CharacterWipeService() {} - - public static final class WipeResult { - public final int playersTouched; - public final int charactersDeleted; - public final List deletedIds; - - private WipeResult(int playersTouched, List deletedIds) { - this.playersTouched = playersTouched; - this.charactersDeleted = deletedIds.size(); - this.deletedIds = List.copyOf(deletedIds); - } - } - - /** Main thread only: activating a replacement syncs MMOCore and fires lifecycle events. */ - public static WipeResult wipeTagged() { - return wipe(RPCharacter::isDev); - } - - /** Read-only count of tagged characters on disk, for the wipe confirm prompt. */ - public static int countTagged() { - int tagged = 0; - File[] ownerDirs = new File(CHARACTER_DATA_PATH).listFiles(); - if (ownerDirs == null) { - return 0; - } - for (File ownerDir : ownerDirs) { - if (ownerDir == null || !ownerDir.isDirectory()) { - continue; - } - UUID uuid = parseUuid(ownerDir.getName()); - if (uuid == null) { - continue; - } - PlayerData pd = resolvePlayerData(uuid); - if (pd == null) { - continue; - } - for (RPCharacter c : pd.getCharacters()) { - if (c != null && c.getId() != null && c.isDev()) { - tagged++; - } - } - } - return tagged; - } - - private static WipeResult wipe(Predicate doomedTest) { - List deletedIds = new ArrayList<>(); - int playersTouched = 0; - File[] ownerDirs = new File(CHARACTER_DATA_PATH).listFiles(); - if (ownerDirs == null) { - return new WipeResult(0, deletedIds); - } - for (File ownerDir : ownerDirs) { - if (ownerDir == null || !ownerDir.isDirectory()) { - continue; - } - UUID uuid = parseUuid(ownerDir.getName()); - if (uuid == null) { - continue; - } - if (wipeOwner(uuid, doomedTest, deletedIds) > 0) { - playersTouched++; - } - } - return new WipeResult(playersTouched, deletedIds); - } - - private static PlayerData resolvePlayerData(UUID uuid) { - PlayerData pd = PlayerManager.get(uuid); - if (pd != null) { - return pd; - } - pd = DB.loadPlayerData(uuid); - if (pd == null) { - return null; - } - if (pd.getCharacters().isEmpty()) { - // No playerdata file, so loadPlayerData returned a blank record without characters. - DB.loadCharacters(pd); - } - return pd; - } - - private static int wipeOwner(UUID uuid, Predicate doomedTest, List deletedIds) { - PlayerData pd = resolvePlayerData(uuid); - if (pd == null) { - return 0; - } - - List doomed = new ArrayList<>(); - for (RPCharacter c : pd.getCharacters()) { - if (c != null && c.getId() != null && doomedTest.test(c)) { - doomed.add(c); - } - } - if (doomed.isEmpty()) { - return 0; - } - - boolean activeRemoved = false; - for (RPCharacter c : doomed) { - if (Boolean.TRUE.equals(c.isActive())) { - activeRemoved = true; - } - pd.getCharacters().remove(c); - boolean deleted = deleteCharacterFile(uuid, c.getId()); - MailRecipientDirectory.remove(c.getId()); - if (deleted) { - net.tfminecraft.rpcharacters.playtime.CharacterPlaytimeDirectory.remove(uuid, c.getId()); - } - deletedIds.add(c.getId()); - } - - Player online = Bukkit.getPlayer(uuid); - boolean replaced = false; - if (activeRemoved && online != null) { - // Offline owners are left without an active character: activate() needs a live - // owner for MMOCore. They hit the no-character freeze and pick from the menu. - List alive = pd.getCharacters(Status.ALIVE); - if (!alive.isEmpty()) { - pd.setActiveCharacter(alive.get(0)); - replaced = true; - } - } - - DB.savePlayer(pd); - - if (online != null) { - if (replaced) { - WardrobeService.refreshActiveAsync(online); - } - RPCharacters.getPlayerManager().reevaluateFreeze(online); - RosterSyncService.pushRosterForPlayer(online); - } - return doomed.size(); - } - - private static boolean deleteCharacterFile(UUID uuid, String characterId) { - File file = new File(new File(CHARACTER_DATA_PATH, uuid.toString()), characterId + ".json"); - if (!file.exists() || file.delete()) { - return true; - } - if (RPCharacters.plugin != null) { - RPCharacters.plugin.getLogger().warning( - "[wipe] could not delete character file " + file.getPath() - ); - } - return false; - } - - private static UUID parseUuid(String raw) { - try { - return UUID.fromString(raw); - } catch (IllegalArgumentException e) { - return null; - } - } -} diff --git a/src/main/java/net/tfminecraft/rpcharacters/wipe/WipeCommand.java b/src/main/java/net/tfminecraft/rpcharacters/wipe/WipeCommand.java index 94a993f..916fb65 100644 --- a/src/main/java/net/tfminecraft/rpcharacters/wipe/WipeCommand.java +++ b/src/main/java/net/tfminecraft/rpcharacters/wipe/WipeCommand.java @@ -1,14 +1,12 @@ package net.tfminecraft.rpcharacters.wipe; import java.util.HashMap; -import java.util.List; import java.util.Locale; import java.util.Map; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; -import net.tfminecraft.rpcharacters.Cache; import net.tfminecraft.rpcharacters.Permissions; import net.tfminecraft.rpcharacters.RPCharacters; import net.tfminecraft.rpcharacters.utils.RPTexts; @@ -16,86 +14,65 @@ import net.tfminecraft.rpcharacters.api.ProvinceSystemClient; /** - * {@code /rpcharacter wipe website|tagged [confirm]}. Admin only, console allowed. + * {@code /rpcharacter wipe website [confirm]}. Admin only, console allowed. * The first call arms a confirm for that sender; the confirm expires after 30s. */ public final class WipeCommand { private static final String WEBSITE = "website"; - private static final String TAGGED = "tagged"; private static final long CONFIRM_TTL_MS = 30_000L; - private static final String USAGE = "Usage: /rpcharacter wipe [confirm]"; + private static final String USAGE = "Usage: /rpcharacter wipe website [confirm]"; - private static final Map PENDING = new HashMap<>(); + /** Sender key to confirm expiry time. */ + private static final Map PENDING = new HashMap<>(); private WipeCommand() {} - private static final class Pending { - private final String action; - private final long expiresAtMs; - - private Pending(String action, long expiresAtMs) { - this.action = action; - this.expiresAtMs = expiresAtMs; - } - } - public static boolean handle(CommandSender sender, String[] args) { if (!Permissions.isAdmin(sender)) { RPTexts.send(sender, RPTexts.ERROR + "You do not have permission to use this command."); return true; } - String action = args.length >= 2 ? args[1].toLowerCase(Locale.ROOT) : ""; - if (!WEBSITE.equals(action) && !TAGGED.equals(action)) { + if (args.length < 2 || !WEBSITE.equalsIgnoreCase(args[1])) { RPTexts.send(sender, RPTexts.ERROR + USAGE); return true; } if (args.length == 2) { - return prelude(sender, action); + return prelude(sender); } if (args.length != 3 || !args[2].equalsIgnoreCase("confirm")) { RPTexts.send(sender, RPTexts.ERROR + USAGE); return true; } - if (!takeConfirm(sender, action)) { + if (!takeConfirm(sender)) { return true; } - if (WEBSITE.equals(action)) { - return wipeWebsite(sender); - } - return wipeTagged(sender); + return wipeWebsite(sender); } - private static boolean prelude(CommandSender sender, String action) { - if (WEBSITE.equals(action)) { - String realm = GatewayClient.realmId(); - if (realm == null) { - RPTexts.send(sender, RPTexts.ERROR + "Could not read the realm id from TFMCWeb. Website wipe aborted."); - return true; - } - RPTexts.send(sender, RPTexts.WARN + "Website wipe target: realm " + RPTexts.ACCENT + realm + RPTexts.WARN + "."); - RPTexts.send(sender, RPTexts.ERROR - + "This deletes every website character row for this realm, including pending donor creates."); - } else { - RPTexts.send(sender, RPTexts.WARN + "Tagged characters on disk: " - + RPTexts.ACCENT + CharacterWipeService.countTagged() + RPTexts.WARN + "."); + private static boolean prelude(CommandSender sender) { + String realm = GatewayClient.realmId(); + if (realm == null) { + RPTexts.send(sender, RPTexts.ERROR + "Could not read the realm id from TFMCWeb. Website wipe aborted."); + return true; } - PENDING.put(key(sender), new Pending(action, System.currentTimeMillis() + CONFIRM_TTL_MS)); - RPTexts.send(sender, RPTexts.COMMAND + "Type /rpcharacter wipe " + action + " confirm" + RPTexts.send(sender, RPTexts.WARN + "Website wipe target: realm " + RPTexts.ACCENT + realm + RPTexts.WARN + "."); + RPTexts.send(sender, RPTexts.ERROR + + "This deletes every website character row for this realm, including pending donor creates."); + PENDING.put(key(sender), System.currentTimeMillis() + CONFIRM_TTL_MS); + RPTexts.send(sender, RPTexts.COMMAND + "Type /rpcharacter wipe website confirm" + RPTexts.WARN + " within 30 seconds."); return true; } - /** True when this sender armed this exact action and it has not expired. */ - private static boolean takeConfirm(CommandSender sender, String action) { - String key = key(sender); - Pending pending = PENDING.get(key); - if (pending == null || !pending.action.equals(action)) { + /** True when this sender armed the wipe and it has not expired. */ + private static boolean takeConfirm(CommandSender sender) { + Long expiresAtMs = PENDING.remove(key(sender)); + if (expiresAtMs == null) { RPTexts.send(sender, RPTexts.ERROR + "Nothing to confirm."); return false; } - PENDING.remove(key); - if (System.currentTimeMillis() > pending.expiresAtMs) { + if (System.currentTimeMillis() > expiresAtMs) { RPTexts.send(sender, RPTexts.ERROR + "Confirm expired. Run the wipe command again."); return false; } @@ -129,41 +106,6 @@ private static boolean wipeWebsite(CommandSender sender) { return true; } - private static boolean wipeTagged(CommandSender sender) { - CharacterWipeService.WipeResult result = CharacterWipeService.wipeTagged(); - if (result.charactersDeleted == 0) { - RPTexts.send(sender, RPTexts.WARN + "No tagged characters found."); - return true; - } - RPTexts.send(sender, RPTexts.SUCCESS + "Deleted " + result.charactersDeleted - + " tagged character(s) across " + result.playersTouched + " player(s)."); - if (Cache.devCharacters) { - // Roster push is off while the flag is on, so the site has no mirror to clean. - return true; - } - String realm = GatewayClient.realmId(); - if (realm == null) { - RPTexts.send(sender, RPTexts.MUTED + "Skipped website cleanup: realm id unavailable."); - return true; - } - List ids = result.deletedIds; - Bukkit.getScheduler().runTaskAsynchronously(RPCharacters.plugin, () -> { - ProvinceSystemClient.SimpleResult cleanup = - ProvinceSystemClient.deleteCharacters(realm, ids); - if (cleanup.ok) { - return; - } - RPCharacters.plugin.getLogger().warning( - "[wipe] website cleanup failed for " + ids.size() + " id(s): " + cleanup.error - ); - Bukkit.getScheduler().runTask(RPCharacters.plugin, () -> RPTexts.send( - sender, - RPTexts.MUTED + "Website cleanup for those ids failed: " + cleanup.error - )); - }); - return true; - } - private static String key(CommandSender sender) { return sender.getName().toLowerCase(Locale.ROOT); } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 16784e1..cba3f94 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -37,10 +37,6 @@ base-profession-factor: -10 require-character: true -# When true: in-game creates are tagged as dev, and this server does not pull -# website characters. Keep false on a live world. -dev-characters: false - # Verbose RPCharacters feedback when /mmocore admin skill-points give|set runs (sync breakdown, stripped skills). skill-points-admin-debug-messages: false diff --git a/src/test/java/net/tfminecraft/rpcharacters/wipe/CharacterWipeDeletionTest.java b/src/test/java/net/tfminecraft/rpcharacters/wipe/CharacterWipeDeletionTest.java deleted file mode 100644 index b626f3b..0000000 --- a/src/test/java/net/tfminecraft/rpcharacters/wipe/CharacterWipeDeletionTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.tfminecraft.rpcharacters.wipe; - -import static org.junit.jupiter.api.Assertions.*; - -import java.lang.reflect.Method; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.UUID; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -class CharacterWipeDeletionTest { - private final UUID owner = UUID.randomUUID(); - private Path folder; - private Path file; - - @BeforeEach - void prepare() throws Exception { - folder = Files.createDirectories(Path.of("plugins/RPCharacters/data/characterdata", owner.toString())); - file = folder.resolve("test.json"); - } - - @AfterEach - void cleanup() throws Exception { - if (Files.isDirectory(file)) Files.deleteIfExists(file.resolve("blocking-child")); - Files.deleteIfExists(file); - Files.deleteIfExists(folder); - } - - private Object delete() throws Exception { - Method method = CharacterWipeService.class.getDeclaredMethod("deleteCharacterFile", UUID.class, String.class); - method.setAccessible(true); - return method.invoke(null, owner, "test"); - } - - @Test - void missingFileCountsAsAlreadyDeleted() throws Exception { - assertEquals(Boolean.TRUE, delete()); - } - - @Test - void existingFileReportsSuccessfulDeletion() throws Exception { - Files.writeString(file, "{}"); - assertEquals(Boolean.TRUE, delete()); - assertFalse(Files.exists(file)); - } - - @Test - void failedDeletionReportsFailureAndKeepsTheFile() throws Exception { - Files.createDirectory(file); - Files.writeString(file.resolve("blocking-child"), "preserve"); - assertEquals(Boolean.FALSE, delete()); - assertTrue(Files.exists(file.resolve("blocking-child"))); - } -}