diff --git a/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/CommandLoader.java b/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/CommandLoader.java index ef86cc96e..694aba5d9 100644 --- a/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/CommandLoader.java +++ b/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/CommandLoader.java @@ -85,6 +85,7 @@ import com.bencodez.votingplugin.presets.VoteSitePresetSetupHandler; import com.bencodez.votingplugin.specialrewards.votemilestones.VoteMilestonesManager; import com.bencodez.votingplugin.specialrewards.votestreak.VoteStreakDefinition; +import com.bencodez.votingplugin.specialrewards.votestreak.VoteStreakType; import com.bencodez.votingplugin.topvoter.TopVoter; import com.bencodez.votingplugin.user.VotingPluginUser; import com.bencodez.votingplugin.votesites.VoteSite; @@ -904,6 +905,46 @@ public void execute(CommandSender sender, String[] args) { } }); + plugin.getAdminVoteCommand() + .add(new CommandHandler(plugin, new String[] { "User", "(player)", "ResetVoteStreaks" }, + "VotingPlugin.Commands.AdminVote.ResetVoteStreaks|" + adminPerm, + "Reset configured VoteStreaks state for player") { + + @Override + public void execute(CommandSender sender, String[] args) { + VotingPluginUser user = plugin.getVotingPluginUserManager().getVotingPluginUser(args[1]); + int reset = plugin.getVoteStreakHandler().resetVoteStreaks(user); + sendMessage(sender, "&cReset " + reset + " VoteStreaks for '" + args[1] + "'"); + } + }); + + plugin.getAdminVoteCommand() + .add(new CommandHandler(plugin, new String[] { "User", "(player)", "ResetVoteStreaks", "(votestreak)" }, + "VotingPlugin.Commands.AdminVote.ResetVoteStreaks|" + adminPerm, + "Reset configured VoteStreaks state for player by type or id") { + + @Override + public void execute(CommandSender sender, String[] args) { + VotingPluginUser user = plugin.getVotingPluginUserManager().getVotingPluginUser(args[1]); + String target = args[3]; + + try { + VoteStreakType type = VoteStreakType.from(target); + int reset = plugin.getVoteStreakHandler().resetVoteStreaks(user, type); + sendMessage(sender, + "&cReset " + reset + " " + type.name() + " VoteStreaks for '" + args[1] + "'"); + return; + } catch (Exception ignored) { + } + + if (plugin.getVoteStreakHandler().resetVoteStreak(user, target)) { + sendMessage(sender, "&cReset VoteStreak '" + target + "' for '" + args[1] + "'"); + } else { + sendMessage(sender, "&cVoteStreak not found: &e" + target); + } + } + }); + for (final TopVoter top : TopVoter.values()) { plugin.getAdminVoteCommand() .add(new CommandHandler(plugin, @@ -3500,4 +3541,4 @@ public void processSlotClick(Player player, VotingPluginUser user, String slot) public void setCommands(HashMap commands) { this.commands = commands; } -} \ No newline at end of file +} diff --git a/VotingPlugin/src/main/java/com/bencodez/votingplugin/specialrewards/votestreak/VoteStreakHandler.java b/VotingPlugin/src/main/java/com/bencodez/votingplugin/specialrewards/votestreak/VoteStreakHandler.java index d02946f9b..61e954ad1 100644 --- a/VotingPlugin/src/main/java/com/bencodez/votingplugin/specialrewards/votestreak/VoteStreakHandler.java +++ b/VotingPlugin/src/main/java/com/bencodez/votingplugin/specialrewards/votestreak/VoteStreakHandler.java @@ -451,6 +451,48 @@ public boolean forceVoteStreakReward(VotingPluginUser user, String id, int strea return true; } + public int resetVoteStreaks(VotingPluginUser user) { + if (user == null) { + return 0; + } + + int reset = 0; + for (VoteStreakDefinition def : ordered) { + writeStateString(user, getColumnName(def), ""); + reset++; + } + return reset; + } + + public int resetVoteStreaks(VotingPluginUser user, VoteStreakType type) { + if (user == null || type == null) { + return 0; + } + + int reset = 0; + for (VoteStreakDefinition def : ordered) { + if (def.getType() == type) { + writeStateString(user, getColumnName(def), ""); + reset++; + } + } + return reset; + } + + public boolean resetVoteStreak(VotingPluginUser user, String id) { + if (user == null || id == null || id.trim().isEmpty()) { + return false; + } + + VoteStreakDefinition def = getDefinition(id); + if (def == null) { + return false; + } + + writeStateString(user, getColumnName(def), ""); + return true; + } + private void giveRewards(VotingPluginUser user, VoteStreakDefinition def, UUID voteUUID, int streakCount) { PlayerSpecialRewardEvent event = new PlayerSpecialRewardEvent(user, SpecialRewardType.VOTESTREAKS.setType(def.getType().toString()).setAmount(def.getVotesRequired()), diff --git a/VotingPlugin/src/test/java/com/bencodez/votingplugin/tests/votestreak/VoteStreakHandlerTest.java b/VotingPlugin/src/test/java/com/bencodez/votingplugin/tests/votestreak/VoteStreakHandlerTest.java index b3f3d92f8..56613e52e 100644 --- a/VotingPlugin/src/test/java/com/bencodez/votingplugin/tests/votestreak/VoteStreakHandlerTest.java +++ b/VotingPlugin/src/test/java/com/bencodez/votingplugin/tests/votestreak/VoteStreakHandlerTest.java @@ -152,6 +152,31 @@ private static YamlConfiguration rootWithLegacyListRewards() { return root; } + private static MemoryConfiguration rootWithThreeStreaks() { + MemoryConfiguration root = new MemoryConfiguration(); + ConfigurationSection voteStreaks = root.createSection("VoteStreaks"); + + addStreak(voteStreaks, "Daily3", "DAILY", true, 3, 1, 1, 7); + addStreak(voteStreaks, "Daily7", "DAILY", true, 7, 1, 1, 7); + addStreak(voteStreaks, "Weekly2", "WEEKLY", true, 2, 1, 0, 0); + + return root; + } + + private static void addStreak(ConfigurationSection voteStreaks, String id, String type, boolean enabled, + int intervalAmount, int votesRequired, int allowMissedAmount, int allowMissedPeriod) { + ConfigurationSection def = voteStreaks.createSection(id); + def.set("Type", type); + def.set("Enabled", enabled); + + ConfigurationSection req = def.createSection("Requirements"); + req.set("Amount", intervalAmount); + req.set("VotesRequired", votesRequired); + + def.set("AllowMissedAmount", allowMissedAmount); + def.set("AllowMissedPeriod", allowMissedPeriod); + } + /** * periodKey|streakCount|votesThisPeriod|countedThisPeriod|missWindowStartKey|missesUsed * @@ -265,6 +290,74 @@ void shouldReward_respectsRecurringFlag() throws Exception { assertTrue(shouldReward(recurring, 6)); } + @Test + void resetVoteStreaks_resetsAllConfiguredDefinitions() { + loadFromRoot(rootWithThreeStreaks()); + + Map backing = new HashMap<>(); + VotingPluginUser user = mapBackedUser(UUID.randomUUID(), "Ben", backing); + for (VoteStreakDefinition def : handler.getDefinitions()) { + backing.put(handler.getColumnName(def), "2026-01-10|5|1|true||0"); + } + + int reset = handler.resetVoteStreaks(user); + + assertEquals(3, reset); + for (VoteStreakDefinition def : handler.getDefinitions()) { + assertEquals("", backing.get(handler.getColumnName(def))); + } + } + + @Test + void resetVoteStreaks_byTypeResetsOnlyMatchingDefinitions() { + loadFromRoot(rootWithThreeStreaks()); + + Map backing = new HashMap<>(); + VotingPluginUser user = mapBackedUser(UUID.randomUUID(), "Ben", backing); + VoteStreakDefinition daily3 = handler.getDefinition("Daily3"); + VoteStreakDefinition daily7 = handler.getDefinition("Daily7"); + VoteStreakDefinition weekly2 = handler.getDefinition("Weekly2"); + + backing.put(handler.getColumnName(daily3), "2026-01-10|3|1|true||0"); + backing.put(handler.getColumnName(daily7), "2026-01-10|7|1|true||0"); + backing.put(handler.getColumnName(weekly2), "2026-W02|2|1|true||0"); + + int reset = handler.resetVoteStreaks(user, VoteStreakType.DAILY); + + assertEquals(2, reset); + assertEquals("", backing.get(handler.getColumnName(daily3))); + assertEquals("", backing.get(handler.getColumnName(daily7))); + assertEquals("2026-W02|2|1|true||0", backing.get(handler.getColumnName(weekly2))); + } + + @Test + void resetVoteStreak_byIdResetsOnlyMatchingDefinition() { + loadFromRoot(rootWithThreeStreaks()); + + Map backing = new HashMap<>(); + VotingPluginUser user = mapBackedUser(UUID.randomUUID(), "Ben", backing); + VoteStreakDefinition daily3 = handler.getDefinition("Daily3"); + VoteStreakDefinition weekly2 = handler.getDefinition("Weekly2"); + + backing.put(handler.getColumnName(daily3), "2026-01-10|3|1|true||0"); + backing.put(handler.getColumnName(weekly2), "2026-W02|2|1|true||0"); + + assertTrue(handler.resetVoteStreak(user, "daily3")); + assertEquals("", backing.get(handler.getColumnName(daily3))); + assertEquals("2026-W02|2|1|true||0", backing.get(handler.getColumnName(weekly2))); + } + + @Test + void resetVoteStreak_unknownIdReturnsFalse() { + loadFromRoot(rootWithThreeStreaks()); + + Map backing = new HashMap<>(); + VotingPluginUser user = mapBackedUser(UUID.randomUUID(), "Ben", backing); + + assertFalse(handler.resetVoteStreak(user, "missing")); + assertTrue(backing.isEmpty()); + } + @Test void migrateLegacyConfigManually_migratesOnlyEnabledLegacyEntries() { YamlConfiguration root = rootWithLegacyVoteStreaks();