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 9f8005fc5..ce41434f4 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 @@ -186,7 +186,7 @@ private void processVoteForDefinition(VotingPluginUser user, VoteStreakDefinitio state.streakCount++; int interval = Math.max(1, def.getRequiredAmount()); - boolean shouldReward = state.streakCount > 0 && (state.streakCount % interval) == 0; + boolean shouldReward = shouldReward(def, state.streakCount); plugin.extraDebug("[VoteStreak] period satisfied: streakCount=" + state.streakCount + " interval=" + interval + " shouldReward=" + shouldReward); @@ -211,6 +211,18 @@ private void processVoteForDefinition(VotingPluginUser user, VoteStreakDefinitio + rawAfter.length() + " readLen=" + readBack.length() + ")"); } + private boolean shouldReward(VoteStreakDefinition def, int streakCount) { + if (streakCount <= 0) { + return false; + } + + int interval = Math.max(1, def.getRequiredAmount()); + if (def.isRecurring()) { + return (streakCount % interval) == 0; + } + return streakCount == interval; + } + /** * When periods change, we determine if previous periods were misses. * @@ -626,6 +638,8 @@ private boolean loadLegacyType(ConfigurationSection voteStreaks, ConfigurationSe ConfigurationSection rewards = defSec.getConfigurationSection("Rewards"); if (rewards != null) { migrated.createSection("Rewards", rewards.getValues(false)); + } else if (defSec.isList("Rewards")) { + migrated.set("Rewards", defSec.getList("Rewards")); } migratedAny = true; 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 14e430268..6ae391d67 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 @@ -11,8 +11,11 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import java.lang.reflect.Method; import java.time.LocalDateTime; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.UUID; import java.util.logging.Level; @@ -135,6 +138,20 @@ private static YamlConfiguration rootWithDisabledLegacyWeek() { return root; } + private static YamlConfiguration rootWithLegacyListRewards() { + YamlConfiguration root = new YamlConfiguration(); + + ConfigurationSection legacy = root.createSection("VoteStreak"); + ConfigurationSection day = legacy.createSection("Day"); + day.set("Enabled", true); + + ConfigurationSection enabledOneTime = day.createSection("3"); + enabledOneTime.set("Enabled", true); + enabledOneTime.set("Rewards", Arrays.asList("VoteSteak_3_Rewards_Online", "VoteSteak_3_Rewards_Offline")); + + return root; + } + /** * periodKey|streakCount|votesThisPeriod|countedThisPeriod|missWindowStartKey|missesUsed * @@ -159,6 +176,12 @@ private void setSpecialRewardsRoot(FileConfiguration root) { when(plugin.getSpecialRewardsConfig().getData()).thenReturn(root); } + private boolean shouldReward(VoteStreakDefinition def, int streakCount) throws Exception { + Method m = VoteStreakHandler.class.getDeclaredMethod("shouldReward", VoteStreakDefinition.class, int.class); + m.setAccessible(true); + return (boolean) m.invoke(handler, def, streakCount); + } + @Test void configLoader_loadsDefinition_andGetDefinitionWorks() { MemoryConfiguration root = rootWithOneStreak("DailyStreak", "DAILY", true, 5, 2, 0, 0); @@ -222,6 +245,22 @@ void processVote_acceptsOldFiveFieldFormat_andUpgradesState() { assertEquals("2", p[5], "missesUsed preserved"); } + @Test + void shouldReward_respectsRecurringFlag() throws Exception { + VoteStreakDefinition oneTime = new VoteStreakDefinition("oneTime", VoteStreakType.DAILY, true, 3, 1, 0, 0, + false); + VoteStreakDefinition recurring = new VoteStreakDefinition("recurring", VoteStreakType.DAILY, true, 3, 1, 0, 0, + true); + + assertFalse(shouldReward(oneTime, 2)); + assertTrue(shouldReward(oneTime, 3)); + assertFalse(shouldReward(oneTime, 6)); + + assertFalse(shouldReward(recurring, 2)); + assertTrue(shouldReward(recurring, 3)); + assertTrue(shouldReward(recurring, 6)); + } + @Test void migrateLegacyConfigManually_migratesOnlyEnabledLegacyEntries() { YamlConfiguration root = rootWithLegacyVoteStreaks(); @@ -299,4 +338,20 @@ void migrateLegacyConfigManually_copiesRewardsWithoutFlattenedDuplicatePaths() { "Rewards should not contain flattened Messages.Player key"); } -} \ No newline at end of file + @Test + void migrateLegacyConfigManually_copiesListBasedRewards() { + YamlConfiguration root = rootWithLegacyListRewards(); + setSpecialRewardsRoot(root); + + handler.migrateLegacyConfigManually(); + + ConfigurationSection migrated = root.getConfigurationSection("VoteStreaks.LegacyDAILY3OneTime"); + assertNotNull(migrated); + + List rewards = migrated.getStringList("Rewards"); + assertEquals(Arrays.asList("VoteSteak_3_Rewards_Online", "VoteSteak_3_Rewards_Offline"), rewards); + assertFalse(migrated.isConfigurationSection("Rewards"), + "list-based reward references should remain list-based"); + } + +}