diff --git a/VotingPlugin/src/main/java/com/bencodez/votingplugin/backendproxy/messaging/BackendProxyMessageRouter.java b/VotingPlugin/src/main/java/com/bencodez/votingplugin/backendproxy/messaging/BackendProxyMessageRouter.java index ac24245af3..eaac8b3b33 100644 --- a/VotingPlugin/src/main/java/com/bencodez/votingplugin/backendproxy/messaging/BackendProxyMessageRouter.java +++ b/VotingPlugin/src/main/java/com/bencodez/votingplugin/backendproxy/messaging/BackendProxyMessageRouter.java @@ -595,7 +595,7 @@ private void handleVoteBroadcast(JsonEnvelope msg) { boolean online = fields.containsKey(VotingPluginWire.K_WAS_ONLINE) ? Boolean.parseBoolean(fields.get(VotingPluginWire.K_WAS_ONLINE)) : user.isOnline(); plugin.getBroadcastHandler().broadcastVote(user.getJavaUUID(), user.getPlayerName(), - voteSite.getDisplayNameForFormatting(), online, totals); + voteSite.getDisplayName(), online, totals); } private WireVoteResult handleWireVoteDelayRejected(JsonEnvelope msg) { diff --git a/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/gui/player/VoteLast.java b/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/gui/player/VoteLast.java index 437bea8643..34a696b8eb 100644 --- a/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/gui/player/VoteLast.java +++ b/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/gui/player/VoteLast.java @@ -71,7 +71,7 @@ public void onDialog(Player player) { continue; } - dialog.placeholder("sitename", site.getDisplayNameForFormatting()).button(site.getDisplayNameForFormatting(), + dialog.placeholder("sitename", site.getDisplayName()).button(site.getDisplayName(), user.voteCommandLastLine(site), payload -> { if (plugin.getGui().isChestVoteLastClickableLinks()) { @@ -83,7 +83,7 @@ public void onDialog(Player player) { HashMap placeholders = new HashMap(); placeholders.put("voteurl", site.getVoteURL()); - placeholders.put("sitename", site.getDisplayNameForFormatting()); + placeholders.put("sitename", site.getDisplayName()); placeholders.put("player", clicked.getName()); clickedUser.sendMessage(plugin.getGui().getChestVoteURLURLText(), placeholders); @@ -121,7 +121,7 @@ public void onChest(Player player) { for (VoteSite site : plugin.getVoteSiteManager().getVoteSitesEnabled()) { if (!site.isHidden()) { inv.addButton(inv.getNextSlot(), - new UpdatingBInventoryButton(plugin, site.getItem().setName(site.getDisplayNameForFormatting()) + new UpdatingBInventoryButton(plugin, site.getItem().setName(site.getDisplayName()) .setLore(user.voteCommandLastGUILine(site)).setAmountNone(1), 1000, 1000) { @Override @@ -139,7 +139,7 @@ public void onClick(ClickEvent event) { plugin.getGui() .getChestVoteURLURLText(), "voteurl", site.getVoteURL()), - "sitename", site.getDisplayNameForFormatting()), + "sitename", site.getDisplayName()), "player", player.getName())); } @@ -148,7 +148,7 @@ public void onClick(ClickEvent event) { @Override public ItemBuilder onUpdate(Player p) { - return site.getItem().setName(site.getDisplayNameForFormatting()) + return site.getItem().setName(site.getDisplayName()) .setLore(user.voteCommandLastGUILine(site)).setAmountNone(1); } }); diff --git a/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/gui/player/VoteNext.java b/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/gui/player/VoteNext.java index 3d4a93256d..008ed73bda 100644 --- a/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/gui/player/VoteNext.java +++ b/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/gui/player/VoteNext.java @@ -60,7 +60,7 @@ public ArrayList getChat(CommandSender sender) { msgLine = MessageAPI.replaceIgnoreCase(msgLine, "%info%", user.voteCommandNextInfo(voteSite)); - msgLine = MessageAPI.replaceIgnoreCase(msgLine, "%SiteName%", voteSite.getDisplayNameForFormatting()); + msgLine = MessageAPI.replaceIgnoreCase(msgLine, "%SiteName%", voteSite.getDisplayName()); msg.add(MessageAPI.colorize(msgLine)); } } @@ -81,10 +81,10 @@ public void onDialog(Player player) { String siteNameDisplay = plugin.getGui().getChestVoteNextCustomSiteNamesDisplays(site.getKey()); if (siteNameDisplay.isEmpty()) { - siteNameDisplay = site.getDisplayNameForFormatting(); + siteNameDisplay = site.getDisplayName(); } - dialog.placeholder("sitename", site.getDisplayNameForFormatting()).placeholder("SiteName", site.getDisplayNameForFormatting()) + dialog.placeholder("sitename", site.getDisplayName()).placeholder("SiteName", site.getDisplayName()) .placeholder("info", user.voteCommandNextInfo(site)) .button(siteNameDisplay, user.voteCommandNextInfo(site), payload -> { @@ -117,7 +117,7 @@ public void onBook(Player player) { if (!site.isHidden()) { Layout nextLayout = new Layout(new ArrayList<>(Arrays.asList("[Json]"))); nextLayout.replaceTextComponent("[Json]", - BookUtil.TextBuilder.of(book.colorize(site.getDisplayNameForFormatting())) + BookUtil.TextBuilder.of(book.colorize(site.getDisplayName())) .onClick(BookUtil.ClickAction.openUrl(site.getVoteURLJsonStrip())) .onHover(BookUtil.HoverAction.showText(user.voteCommandNextInfo(site))).build()); book.addLayout(nextLayout); @@ -141,7 +141,7 @@ public void onChest(Player player) { if (!site.isHidden()) { String siteNameDisplay = plugin.getGui().getChestVoteNextCustomSiteNamesDisplays(site.getKey()); if (siteNameDisplay.isEmpty()) { - siteNameDisplay = site.getDisplayNameForFormatting(); + siteNameDisplay = site.getDisplayName(); } inv.addButton(inv.getNextSlot(), new UpdatingBInventoryButton(plugin, @@ -159,7 +159,7 @@ public void onClick(ClickEvent clickEvent) { @Override public ItemBuilder onUpdate(Player player) { - return site.getItem().setName(site.getDisplayNameForFormatting()) + return site.getItem().setName(site.getDisplayName()) .setLore(user.voteCommandNextInfo(site)).setAmountNone(1) .addPlaceholder("player", user.getPlayerName()); } diff --git a/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/gui/player/VoteToday.java b/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/gui/player/VoteToday.java index 88fa311a3b..accbd1b3aa 100644 --- a/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/gui/player/VoteToday.java +++ b/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/gui/player/VoteToday.java @@ -52,9 +52,9 @@ public void onDialog(Player player) { final UUID uuid = topPlayer.getUuid(); dialog.placeholder("player", topPlayer.getPlayerName()).placeholder("votesite", voteSite.getKey()) - .placeholder("sitename", voteSite.getDisplayNameForFormatting()) - .placeholder("SiteName", voteSite.getDisplayNameForFormatting()) - .placeholder("VoteSite", voteSite.getDisplayNameForFormatting()).placeholder("time", timeString) + .placeholder("sitename", voteSite.getDisplayName()) + .placeholder("SiteName", voteSite.getDisplayName()) + .placeholder("VoteSite", voteSite.getDisplayName()).placeholder("time", timeString) .placeholder("Time", timeString).button("&e" + topPlayer.getPlayerName(), plugin.getConfigFile().getFormatCommandsVoteTodayLine(), payload -> { Player clicked = player.getServer().getPlayer(payload.owner()); @@ -136,9 +136,9 @@ public void onChest(Player player) { HashMap placeholders = new HashMap<>(); placeholders.put("player", user.getPlayerName()); placeholders.put("votesite", voteSite.getKey()); - placeholders.put("sitename", voteSite.getDisplayNameForFormatting()); - placeholders.put("SiteName", voteSite.getDisplayNameForFormatting()); - placeholders.put("VoteSite", voteSite.getDisplayNameForFormatting()); + placeholders.put("sitename", voteSite.getDisplayName()); + placeholders.put("SiteName", voteSite.getDisplayName()); + placeholders.put("VoteSite", voteSite.getDisplayName()); placeholders.put("time", timeString); placeholders.put("Time", timeString); @@ -204,7 +204,7 @@ public String[] voteToday() { HashMap placeholders = new HashMap<>(); placeholders.put("player", user.getPlayerName()); placeholders.put("votesite", voteSite.getKey()); - placeholders.put("sitename", voteSite.getDisplayNameForFormatting()); + placeholders.put("sitename", voteSite.getDisplayName()); placeholders.put("time", timeString); msg.add(PlaceholderUtils.replacePlaceHolder(plugin.getConfigFile().getFormatCommandsVoteTodayLine(), placeholders)); @@ -234,7 +234,7 @@ public String[] voteTodayGUI() { HashMap placeholders = new HashMap<>(); placeholders.put("player", user.getPlayerName()); placeholders.put("votesite", mostRecentSite.getKey()); - placeholders.put("sitename", mostRecentSite.getDisplayNameForFormatting()); + placeholders.put("sitename", mostRecentSite.getDisplayName()); placeholders.put("time", timeString); msg.add(PlaceholderUtils.replacePlaceHolder(plugin.getConfigFile().getFormatCommandsVoteTodayLine(), placeholders)); diff --git a/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/gui/player/VoteURL.java b/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/gui/player/VoteURL.java index 36a7e2c2e5..61ea8b80ee 100644 --- a/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/gui/player/VoteURL.java +++ b/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/gui/player/VoteURL.java @@ -71,7 +71,7 @@ public ArrayList getChat(CommandSender sender, boolean bypassCanVote) { plugin.getConfigFile().getFormatCommandsVoteURLS()); message.replacePlaceholder("num", Integer.toString(counter)) .replacePlaceholder("url", voteURL) - .replacePlaceholder("SiteName", voteSite.getDisplayNameForFormatting()); + .replacePlaceholder("SiteName", voteSite.getDisplayName()); if (user != null && user.getPlayerName() != null) { message.replacePlaceholder("player", "" + user.getPlayerName()) .replacePlaceholder("Next", "" + user.voteCommandNextInfo(voteSite)); @@ -150,14 +150,14 @@ public void onDialog(Player player) { boolean canVote = finalUser.canVoteSite(voteSite); String color = canVote ? "&a" : "&c"; - dialog.placeholder("sitename", voteSite.getDisplayNameForFormatting()) - .placeholder("SiteName", voteSite.getDisplayNameForFormatting()) - .placeholder("servicesite", voteSite.getServiceSiteForFormatting()) - .placeholder("ServiceSite", voteSite.getServiceSiteForFormatting()) + dialog.placeholder("sitename", voteSite.getDisplayName()) + .placeholder("SiteName", voteSite.getDisplayName()) + .placeholder("servicesite", voteSite.getServiceSite()) + .placeholder("ServiceSite", voteSite.getServiceSite()) .placeholder("VoteDelay", "" + voteSite.getVoteDelay()) .placeholder("VoteHour", "" + voteSite.getVoteDelayDailyHour()) .placeholder("Next", finalUser.voteCommandNextInfo(voteSite)) - .button(color + voteSite.getDisplayNameForFormatting(), + .button(color + voteSite.getDisplayName(), canVote ? "&aClick to view vote link" : "&c" + finalUser.voteCommandNextInfo(voteSite), payload -> { Player clicked = player.getServer().getPlayer(payload.owner()); @@ -166,9 +166,9 @@ public void onDialog(Player player) { .getVotingPluginUser(clicked); HashMap placeholders = new HashMap(); placeholders.put("voteurl", voteSite.getVoteURL()); - placeholders.put("sitename", voteSite.getDisplayNameForFormatting()); + placeholders.put("sitename", voteSite.getDisplayName()); placeholders.put("player", clicked.getName()); - placeholders.put("servicesite", voteSite.getServiceSiteForFormatting()); + placeholders.put("servicesite", voteSite.getServiceSite()); placeholders.put("VoteDelay", "" + voteSite.getVoteDelay()); placeholders.put("VoteHour", "" + voteSite.getVoteDelayDailyHour()); clickedUser.sendMessage(plugin.getGui().getChestVoteURLURLText(), placeholders); @@ -218,8 +218,8 @@ private ItemBuilder getItemVoteSite(VoteSite voteSite) { builder.setName(plugin.getGui().getChestVoteURLGUISiteName()); builder.addLoreLine(plugin.getGui().getChestVoteURLNextVote()); } - builder.addPlaceholder("ServiceSite", voteSite.getServiceSiteForFormatting()); - builder.addPlaceholder("Name", voteSite.getDisplayNameForFormatting()); + builder.addPlaceholder("ServiceSite", voteSite.getServiceSite()); + builder.addPlaceholder("Name", voteSite.getDisplayName()); builder.addPlaceholder("VoteDelay", "" + voteSite.getVoteDelay()); builder.addPlaceholder("VoteHour", "" + voteSite.getVoteDelayDailyHour()); builder.addPlaceholder("Info", user.voteCommandNextInfo(voteSite)); @@ -240,7 +240,7 @@ public void onBook(Player player) { if (!site.isHidden()) { if (site.getPermissionToView().isEmpty() || player.hasPermission(site.getPermissionToView())) { Layout layout = new Layout(plugin.getGui().getBookVoteURLBookGUILayout()) - .addPlaceholder("sitename", site.getDisplayNameForFormatting()).addPlaceholder("num", "" + i); + .addPlaceholder("sitename", site.getDisplayName()).addPlaceholder("num", "" + i); String text = plugin.getGui().getBookVoteURLBookGUIAlreadyVotedText(); ChatColor color = ChatColor.valueOf(plugin.getGui().getBookVoteURLBookGUIAlreadyVotedColor()); if (user.canVoteSite(site)) { @@ -342,9 +342,9 @@ public void onClick(ClickEvent event) { VotingPluginUser user = plugin.getVotingPluginUserManager().getVotingPluginUser(player); HashMap placeholders = new HashMap<>(); placeholders.put("voteurl", voteSite.getVoteURL()); - placeholders.put("sitename", voteSite.getDisplayNameForFormatting()); + placeholders.put("sitename", voteSite.getDisplayName()); placeholders.put("player", player.getName()); - placeholders.put("servicesite", voteSite.getServiceSiteForFormatting()); + placeholders.put("servicesite", voteSite.getServiceSite()); placeholders.put("VoteDelay", "" + voteSite.getVoteDelay()); placeholders.put("VoteHour", "" + voteSite.getVoteDelayDailyHour()); user.sendMessage(plugin.getGui().getChestVoteURLURLText(), placeholders); diff --git a/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/gui/player/VoteURLVoteSite.java b/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/gui/player/VoteURLVoteSite.java index 779227cc6b..7b203ef1c7 100644 --- a/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/gui/player/VoteURLVoteSite.java +++ b/VotingPlugin/src/main/java/com/bencodez/votingplugin/commands/gui/player/VoteURLVoteSite.java @@ -53,7 +53,7 @@ public void onChest(Player player) { } VoteSite site = plugin.getVoteSiteManager().getVoteSite(voteSite, true); BInventory inv = new BInventory(plugin.getGui().getChestVoteURLSiteName()); - inv.addPlaceholder("site", site.getDisplayNameForFormatting()); + inv.addPlaceholder("site", site.getDisplayName()); inv.setMeta(player, "VoteSite", site); if (!plugin.getConfigFile().isAlwaysCloseInventory()) { inv.dontClose(); @@ -117,10 +117,10 @@ public void onDialog(Player player) { VoteSite site = plugin.getVoteSiteManager().getVoteSite(voteSite, true); com.bencodez.simpleapi.dialog.MultiActionDialogBuilder dialog = plugin.getDialogService().multiAction(player) - .placeholder("player", user.getPlayerName()).placeholder("site", site.getDisplayNameForFormatting()) - .placeholder("sitename", site.getDisplayNameForFormatting()).placeholder("SiteName", site.getDisplayNameForFormatting()) - .placeholder("servicesite", site.getServiceSiteForFormatting()) - .placeholder("ServiceSite", site.getServiceSiteForFormatting()) + .placeholder("player", user.getPlayerName()).placeholder("site", site.getDisplayName()) + .placeholder("sitename", site.getDisplayName()).placeholder("SiteName", site.getDisplayName()) + .placeholder("servicesite", site.getServiceSite()) + .placeholder("ServiceSite", site.getServiceSite()) .placeholder("VoteDelay", "" + site.getVoteDelay()) .placeholder("VoteHour", "" + site.getVoteDelayDailyHour()) .placeholder("Next", user.voteCommandNextInfo(site)).placeholder("Last", user.voteCommandLastLine(site)) diff --git a/VotingPlugin/src/main/java/com/bencodez/votingplugin/config/ConfigVoteSites.java b/VotingPlugin/src/main/java/com/bencodez/votingplugin/config/ConfigVoteSites.java index e422baa340..a4432b010f 100644 --- a/VotingPlugin/src/main/java/com/bencodez/votingplugin/config/ConfigVoteSites.java +++ b/VotingPlugin/src/main/java/com/bencodez/votingplugin/config/ConfigVoteSites.java @@ -87,7 +87,7 @@ private boolean tryGenerateVoteSite(String siteName, boolean automatic) { setVoteDelay(siteName, "24h"); set(siteName, "DisplayItem.Material", "STONE"); set(siteName, "DisplayItem.Amount", 1); - set(siteName, "Rewards.Messages.Player", "&aThanks for voting on %SiteName%!"); + set(siteName, "Rewards.Messages.Player", "&aThanks for voting on %ServiceSite%!"); set(siteName, "WaitUntilVoteDelayRewards", Collections.emptyMap()); plugin.loadVoteSites(); diff --git a/VotingPlugin/src/main/java/com/bencodez/votingplugin/cooldown/CoolDownCheck.java b/VotingPlugin/src/main/java/com/bencodez/votingplugin/cooldown/CoolDownCheck.java index 2e370fe37c..de0140bc09 100644 --- a/VotingPlugin/src/main/java/com/bencodez/votingplugin/cooldown/CoolDownCheck.java +++ b/VotingPlugin/src/main/java/com/bencodez/votingplugin/cooldown/CoolDownCheck.java @@ -280,7 +280,6 @@ public void onCoolDownEnd(PlayerVoteCoolDownEndEvent event) { public void onCoolDownEnd(PlayerVoteSiteCoolDownEndEvent event) { plugin.getRewardHandler().giveReward(event.getPlayer(), event.getSite().getSiteData(), "CoolDownEndRewards", new RewardOptions().addPlaceholder("sitename", event.getSite().getDisplayName()) - .addDisplayPlaceholder("sitename", event.getSite().getDisplayNameForFormatting()) .addPlaceholder("url", event.getSite().getVoteURL(false))); } diff --git a/VotingPlugin/src/main/java/com/bencodez/votingplugin/listeners/PlayerVoteListener.java b/VotingPlugin/src/main/java/com/bencodez/votingplugin/listeners/PlayerVoteListener.java index 6b4d816681..7c573a7608 100644 --- a/VotingPlugin/src/main/java/com/bencodez/votingplugin/listeners/PlayerVoteListener.java +++ b/VotingPlugin/src/main/java/com/bencodez/votingplugin/listeners/PlayerVoteListener.java @@ -95,7 +95,7 @@ private BukkitOperations(VotingPluginMain plugin, PlayerVoteEvent event) { } @Override public boolean siteEnabled(VoteSite site) { return site.isEnabled(); } @Override public String siteKey(VoteSite site) { return site.getKey(); } - @Override public String siteDisplayName(VoteSite site) { return site.getDisplayNameForFormatting(); } + @Override public String siteDisplayName(VoteSite site) { return site.getDisplayName(); } @Override public VotingPluginUser resolveUser(String name) { if (event.getVotingPluginUser() != null) return event.getVotingPluginUser(); Player player = Bukkit.getPlayerExact(name); diff --git a/VotingPlugin/src/main/java/com/bencodez/votingplugin/proxy/bungee/VotingPluginBungee.java b/VotingPlugin/src/main/java/com/bencodez/votingplugin/proxy/bungee/VotingPluginBungee.java index 12764ca5e1..7ad8e2c8a2 100644 --- a/VotingPlugin/src/main/java/com/bencodez/votingplugin/proxy/bungee/VotingPluginBungee.java +++ b/VotingPlugin/src/main/java/com/bencodez/votingplugin/proxy/bungee/VotingPluginBungee.java @@ -36,6 +36,7 @@ import com.bencodez.votingplugin.proxy.VotingPluginProxyConfig; import com.bencodez.votingplugin.proxy.VotingPluginProxy.VoteRetryException; import com.bencodez.votingplugin.util.MinecraftUsernameValidator; +import com.bencodez.votingplugin.util.ServiceSiteValidator; import com.bencodez.votingplugin.timequeue.VoteTimeQueue; import lombok.Getter; @@ -676,7 +677,7 @@ private void processPendingIncomingVote(PendingIncomingVote pending) { } if (result == IncomingVoteRuntimeResult.PROCESSED) { getLogger().info("Vote received " + MinecraftUsernameValidator.sanitizeForLog(pending.getPlayer()) - + " from service site " + MinecraftUsernameValidator.sanitizeForLog(pending.getService())); + + " from service site " + ServiceSiteValidator.sanitizeForLog(pending.getService())); return; } if (result == IncomingVoteRuntimeResult.RETRY_AFTER_RELOAD) { diff --git a/VotingPlugin/src/main/java/com/bencodez/votingplugin/proxy/velocity/VotingPluginVelocity.java b/VotingPlugin/src/main/java/com/bencodez/votingplugin/proxy/velocity/VotingPluginVelocity.java index 88e9f8b458..1365243369 100644 --- a/VotingPlugin/src/main/java/com/bencodez/votingplugin/proxy/velocity/VotingPluginVelocity.java +++ b/VotingPlugin/src/main/java/com/bencodez/votingplugin/proxy/velocity/VotingPluginVelocity.java @@ -49,6 +49,7 @@ import com.bencodez.votingplugin.proxy.VotingPluginProxyConfig; import com.bencodez.votingplugin.proxy.VotingPluginProxy.VoteRetryException; import com.bencodez.votingplugin.util.MinecraftUsernameValidator; +import com.bencodez.votingplugin.util.ServiceSiteValidator; import com.bencodez.votingplugin.timequeue.VoteTimeQueue; import com.google.inject.Inject; import com.velocitypowered.api.command.CommandMeta; @@ -562,7 +563,7 @@ private void processPendingIncomingVote(PendingIncomingVote pending) { } if (result == IncomingVoteRuntimeResult.PROCESSED) { logger.info("Vote received " + MinecraftUsernameValidator.sanitizeForLog(pending.getPlayer()) - + " from service site " + MinecraftUsernameValidator.sanitizeForLog(pending.getService())); + + " from service site " + ServiceSiteValidator.sanitizeForLog(pending.getService())); return; } if (result == IncomingVoteRuntimeResult.RETRY_AFTER_RELOAD) { diff --git a/VotingPlugin/src/main/java/com/bencodez/votingplugin/user/VotingPluginUser.java b/VotingPlugin/src/main/java/com/bencodez/votingplugin/user/VotingPluginUser.java index d958a71dfc..5cb2c79bfd 100644 --- a/VotingPlugin/src/main/java/com/bencodez/votingplugin/user/VotingPluginUser.java +++ b/VotingPlugin/src/main/java/com/bencodez/votingplugin/user/VotingPluginUser.java @@ -2976,7 +2976,7 @@ public String voteCommandLastGUILine(VoteSite voteSite) { HashMap placeholders = new HashMap<>(); placeholders.put("time", timeString); - placeholders.put("SiteName", voteSite.getDisplayNameForFormatting()); + placeholders.put("SiteName", voteSite.getDisplayName()); placeholders.put("timesince", timeSince); return PlaceholderUtils.replacePlaceHolder(plugin.getGui().getChestVoteLastLine(), placeholders); @@ -2994,7 +2994,7 @@ public String voteCommandLastLine(VoteSite voteSite) { HashMap placeholders = new HashMap<>(); placeholders.put("time", timeString); - placeholders.put("SiteName", voteSite.getDisplayNameForFormatting()); + placeholders.put("SiteName", voteSite.getDisplayName()); placeholders.put("timesince", timeSince); return PlaceholderUtils.replacePlaceHolder(plugin.getConfigFile().getFormatCommandsVoteLastLine(), diff --git a/VotingPlugin/src/main/java/com/bencodez/votingplugin/votereminding/VoteRemindersListener.java b/VotingPlugin/src/main/java/com/bencodez/votingplugin/votereminding/VoteRemindersListener.java index ca775c6ce7..eb5cca3c57 100644 --- a/VotingPlugin/src/main/java/com/bencodez/votingplugin/votereminding/VoteRemindersListener.java +++ b/VotingPlugin/src/main/java/com/bencodez/votingplugin/votereminding/VoteRemindersListener.java @@ -7,7 +7,6 @@ import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerQuitEvent; -import com.bencodez.advancedcore.api.rewards.RewardDisplayPlaceholders; import com.bencodez.advancedcore.listeners.AdvancedCoreLoginEvent; import com.bencodez.votingplugin.VotingPluginMain; import com.bencodez.votingplugin.events.PlayerPostVoteEvent; @@ -38,8 +37,7 @@ public VoteRemindersListener(VotingPluginMain plugin) { */ @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) public void onPostVote(PlayerPostVoteEvent event) { - plugin.getVoteRemindersManager().onVoteCast(event.getUser(), event.getVoteSite().getDisplayName(), - event.getVoteSite().getDisplayNameForFormatting()); + plugin.getVoteRemindersManager().onVoteCast(event.getUser(), event.getVoteSite().getDisplayName()); } /** @@ -84,7 +82,6 @@ public void onCoolDownEnd(PlayerVoteCoolDownEndEvent event) { public void onCoolDownEnd(PlayerVoteSiteCoolDownEndEvent event) { HashMap placeholders = new HashMap<>(); placeholders.put("votesite", event.getSite().getDisplayName()); - RewardDisplayPlaceholders.put(placeholders, "votesite", event.getSite().getDisplayNameForFormatting()); placeholders.put("votesite_id", event.getSite().getKey()); plugin.getVoteRemindersManager().onCooldownTrigger(event.getPlayer(), VoteReminderType.COOLDOWN_END_ANY_SITE, placeholders); diff --git a/VotingPlugin/src/main/java/com/bencodez/votingplugin/votereminding/VoteRemindersManager.java b/VotingPlugin/src/main/java/com/bencodez/votingplugin/votereminding/VoteRemindersManager.java index 6a4ab5a1be..55c926c0fc 100644 --- a/VotingPlugin/src/main/java/com/bencodez/votingplugin/votereminding/VoteRemindersManager.java +++ b/VotingPlugin/src/main/java/com/bencodez/votingplugin/votereminding/VoteRemindersManager.java @@ -26,7 +26,6 @@ import org.bukkit.entity.Player; import com.bencodez.advancedcore.api.rewards.RewardBuilder; -import com.bencodez.advancedcore.api.rewards.RewardDisplayPlaceholders; import com.bencodez.simpleapi.time.ParsedDuration; import com.bencodez.votingplugin.VotingPluginMain; import com.bencodez.votingplugin.user.VotingPluginUser; @@ -488,10 +487,6 @@ public void onQuit(Player player) { } public void onVoteCast(VotingPluginUser user, String siteKey) { - onVoteCast(user, siteKey, siteKey); - } - - public void onVoteCast(VotingPluginUser user, String siteKey, String displaySite) { if (!isEnabled() || user == null) { return; } @@ -507,13 +502,17 @@ public void onVoteCast(VotingPluginUser user, String siteKey, String displaySite HashMap ph = new HashMap<>(); if (siteKey != null && !siteKey.isEmpty()) { ph.put("site", siteKey); - RewardDisplayPlaceholders.put(ph, "site", displaySite); } queueTrigger(user, VoteReminderType.VOTE_CAST, ph); flushSoon(user.getJavaUUID(), user.getPlayerName()); } + /** Compatibility overload; reminders use the original release site value. */ + public void onVoteCast(VotingPluginUser user, String siteKey, String displaySite) { + onVoteCast(user, siteKey); + } + public void onCooldownTrigger(VotingPluginUser user, VoteReminderType type, Map placeholders) { if (!isEnabled() || user == null) { return; diff --git a/VotingPlugin/src/main/java/com/bencodez/votingplugin/votesites/VoteSite.java b/VotingPlugin/src/main/java/com/bencodez/votingplugin/votesites/VoteSite.java index 654cee7db2..333b84b8bd 100644 --- a/VotingPlugin/src/main/java/com/bencodez/votingplugin/votesites/VoteSite.java +++ b/VotingPlugin/src/main/java/com/bencodez/votingplugin/votesites/VoteSite.java @@ -12,7 +12,6 @@ import com.bencodez.simpleapi.time.ParsedDuration; import com.bencodez.votingplugin.VotingPluginMain; import com.bencodez.votingplugin.user.VotingPluginUser; -import com.bencodez.votingplugin.util.ServiceSiteValidator; import lombok.Getter; import lombok.Setter; @@ -20,7 +19,6 @@ public class VoteSite { @Getter private String displayName; - private boolean displayNameFallback; @Getter @Setter @@ -159,12 +157,9 @@ public java.util.concurrent.CompletionStage giveRewardsAsync(VotingPluginU private RewardBuilder createRewardBuilder(String path, boolean online, boolean bungee) { // Reward placeholders also feed commands and other exact-value actions. The - // service identifier is already validated at ingress, so preserve it here; - // display-only callers use getServiceSiteForFormatting() instead. + // service identifier is already validated at ingress, so preserve it here. return new RewardBuilder(plugin.getConfigVoteSites().getData(), path).setOnline(online) .withPlaceHolder("ServiceSite", getServiceSite()).withPlaceHolder("SiteName", getDisplayName()) - .withDisplayPlaceHolder("ServiceSite", getServiceSiteForFormatting()) - .withDisplayPlaceHolder("SiteName", getDisplayNameForFormatting()) .withPlaceHolder("VoteDelay", "" + getVoteDelay()).withPlaceHolder("VoteURL", getVoteURL()) .setServer(bungee); } @@ -174,20 +169,19 @@ public boolean hasRewards() { plugin.getConfigVoteSites().getRewardsPath(key)); } - /** Returns the configured service identifier guarded for trusted templates. */ + /** Compatibility accessor returning the unchanged release formatting input. */ public String getServiceSiteForFormatting() { - return ServiceSiteValidator.inertForFormatting(getServiceSite()); + return getServiceSite(); } /** Sets an administrator-controlled display name. */ public void setDisplayName(String displayName) { this.displayName = displayName; - this.displayNameFallback = false; } - /** Returns the site label guarded only when it falls back to an external site key. */ + /** Returns the configured or fallback label without additional formatting guards. */ public String getDisplayNameForFormatting() { - return displayNameFallback ? ServiceSiteValidator.inertForFormatting(getDisplayName()) : getDisplayName(); + return getDisplayName(); } /** @@ -200,8 +194,7 @@ public void init() { setEnabled(plugin.getConfigVoteSites().getVoteSiteEnabled(key)); setPriority(plugin.getConfigVoteSites().getPriority(key)); displayName = plugin.getConfigVoteSites().getDisplayName(key); - displayNameFallback = displayName == null || displayName.equals(""); - if (displayNameFallback) { + if (displayName == null || displayName.equals("")) { displayName = key; } item = plugin.getConfigVoteSites().getItem(key); diff --git a/VotingPlugin/src/test/java/com/bencodez/votingplugin/proxy/ServiceSiteVoteLoggingRegressionTest.java b/VotingPlugin/src/test/java/com/bencodez/votingplugin/proxy/ServiceSiteVoteLoggingRegressionTest.java new file mode 100644 index 0000000000..ac998cd4a6 --- /dev/null +++ b/VotingPlugin/src/test/java/com/bencodez/votingplugin/proxy/ServiceSiteVoteLoggingRegressionTest.java @@ -0,0 +1,170 @@ +package com.bencodez.votingplugin.proxy; + +import static org.mockito.Mockito.CALLS_REAL_METHODS; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.times; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; + +import java.nio.file.Path; +import java.util.UUID; +import java.util.ArrayList; +import org.mockito.ArgumentCaptor; +import java.util.logging.Logger; + +import org.bstats.velocity.Metrics; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.bencodez.votingplugin.proxy.bungee.VotingPluginBungee; +import com.bencodez.votingplugin.proxy.velocity.VotingPluginVelocity; +import com.bencodez.votingplugin.util.ServiceSiteValidator; +import com.velocitypowered.api.proxy.ProxyServer; + +class ServiceSiteVoteLoggingRegressionTest { + @Test + void bungeeVoteProcessingUsesServiceSiteSanitizerForTheActualReceiptLog() throws Exception { + VotingPluginBungee plugin = mock(VotingPluginBungee.class, CALLS_REAL_METHODS); + VotingPluginProxy runtime = mock(VotingPluginProxy.class); + Logger logger = mock(Logger.class); + when(plugin.getLogger()).thenReturn(logger); + prepareBungee(plugin, runtime); + String[] services = { "Minecraft-MP.com", "PlanetMinecraft.com", "Minecraft Servers", "R&D", + "Top100Servers.net", "Safe\nName", "Safe\u2060Name", null }; + for (String service : services) { + processBungeeVote(plugin, service, "player.name"); + verify(runtime).vote(eq("player.name"), eq(service), eq(true), eq(true), eq(0L), eq(null), eq(null), + any(UUID.class)); + + } + String longService = "x".repeat(140); + processBungeeVote(plugin, longService, "example_player"); + verify(runtime).vote(eq("example_player"), eq(longService), eq(true), eq(true), eq(0L), eq(null), eq(null), + any(UUID.class)); + assertReceiptLogs(logger, services); + } + + @Test + void velocityVoteProcessingUsesServiceSiteSanitizerForTheActualReceiptLog(@TempDir Path dataDirectory) + throws Exception { + org.slf4j.Logger logger = mock(org.slf4j.Logger.class); + VotingPluginVelocity plugin = new VotingPluginVelocity(mock(ProxyServer.class), logger, + mock(Metrics.Factory.class), dataDirectory); + try { + VotingPluginProxy runtime = mock(VotingPluginProxy.class); + prepareVelocity(plugin, runtime); + String[] services = { "Minecraft-MP.com", "PlanetMinecraft.com", "Minecraft Servers", "R&D", + "Top100Servers.net", "Safe\nName", "Safe\u2060Name", null }; + for (String service : services) { + processVelocityVote(plugin, service, "player.name"); + verify(runtime).vote(eq("player.name"), eq(service), eq(true), eq(false), eq(0L), eq(null), eq(null), + any(UUID.class)); + + } + String longService = "x".repeat(140); + processVelocityVote(plugin, longService, "example_player"); + verify(runtime).vote(eq("example_player"), eq(longService), eq(true), eq(false), eq(0L), eq(null), eq(null), + any(UUID.class)); + ArgumentCaptor logs = ArgumentCaptor.forClass(String.class); + verify(logger, times(services.length + 1)).info(logs.capture()); + assertEquals(expectedReceiptLogs(services), logs.getAllValues()); + } finally { + plugin.getTimer().shutdownNow(); + } + } + + @Test + void serviceSiteLogSanitizationPreservesPunctuationAndBlocksControlCharacters() { + assertEquals("Minecraft-MP.com Servers", ServiceSiteValidator.sanitizeForLog("Minecraft-MP.com Servers")); + assertEquals("R&D", ServiceSiteValidator.sanitizeForLog("R&D")); + assertEquals("Safe?Name", ServiceSiteValidator.sanitizeForLog("Safe\nName")); + } + + private static void prepareBungee(VotingPluginBungee plugin, VotingPluginProxy runtime) throws Exception { + setField(plugin, "reloadLock", new Object()); + setField(plugin, "pendingIncomingVotes", new PendingIncomingVoteQueue()); + setField(plugin, "votingPluginProxy", runtime); + setField(plugin, "runtimeOperational", true); + } + + private static void prepareVelocity(VotingPluginVelocity plugin, VotingPluginProxy runtime) throws Exception { + setField(plugin, "reloadLock", new Object()); + setField(plugin, "pendingIncomingVotes", new PendingIncomingVoteQueue()); + setField(plugin, "votingPluginProxy", runtime); + setField(plugin, "runtimeOperational", true); + } + + private static void processBungeeVote(VotingPluginBungee plugin, String service, String player) throws Exception { + PendingIncomingVote pending = ((PendingIncomingVoteQueue) getField(plugin, "pendingIncomingVotes")) + .admit(player, service); + invokePendingProcessor(plugin, pending); + } + + private static void processVelocityVote(VotingPluginVelocity plugin, String service, String player) throws Exception { + PendingIncomingVote pending = ((PendingIncomingVoteQueue) getField(plugin, "pendingIncomingVotes")) + .admit(player, service); + invokePendingProcessor(plugin, pending); + } + + private static void assertReceiptLogs(Logger logger, String[] services) { + ArgumentCaptor logs = ArgumentCaptor.forClass(String.class); + verify(logger, times(services.length + 1)).info(logs.capture()); + assertEquals(expectedReceiptLogs(services), logs.getAllValues()); + } + + private static ArrayList expectedReceiptLogs(String[] services) { + ArrayList logs = new ArrayList<>(); + for (String service : services) logs.add("Vote received player?name from service site " + expectedServiceLog(service)); + logs.add("Vote received example_player from service site " + "x".repeat(128) + "..."); + return logs; + } + + private static String expectedServiceLog(String service) { + return service == null ? "" : service.replace("\n", "?").replace("\u2060", "?"); + } + + private static void invokePendingProcessor(Object plugin, PendingIncomingVote pending) throws Exception { + java.lang.reflect.Method method = findMethod(plugin.getClass(), "processPendingIncomingVote", + PendingIncomingVote.class); + method.setAccessible(true); + method.invoke(plugin, pending); + } + + private static void setField(Object target, String name, Object value) throws Exception { + java.lang.reflect.Field field = findField(target.getClass(), name); + field.setAccessible(true); + field.set(target, value); + } + + private static Object getField(Object target, String name) throws Exception { + java.lang.reflect.Field field = findField(target.getClass(), name); + field.setAccessible(true); + return field.get(target); + } + + private static java.lang.reflect.Field findField(Class type, String name) throws NoSuchFieldException { + for (Class current = type; current != null; current = current.getSuperclass()) { + try { + return current.getDeclaredField(name); + } catch (NoSuchFieldException ignored) { + // Continue through Mockito subclasses and the concrete plugin class. + } + } + throw new NoSuchFieldException(name); + } + + private static java.lang.reflect.Method findMethod(Class type, String name, Class parameter) + throws NoSuchMethodException { + for (Class current = type; current != null; current = current.getSuperclass()) { + try { + return current.getDeclaredMethod(name, parameter); + } catch (NoSuchMethodException ignored) { + // Continue through Mockito subclasses and the concrete plugin class. + } + } + throw new NoSuchMethodException(name); + } +} diff --git a/VotingPlugin/src/test/java/com/bencodez/votingplugin/tests/reminders/VoteRemindersListenerTest.java b/VotingPlugin/src/test/java/com/bencodez/votingplugin/tests/reminders/VoteRemindersListenerTest.java index 25962f2e3d..b959159585 100644 --- a/VotingPlugin/src/test/java/com/bencodez/votingplugin/tests/reminders/VoteRemindersListenerTest.java +++ b/VotingPlugin/src/test/java/com/bencodez/votingplugin/tests/reminders/VoteRemindersListenerTest.java @@ -25,7 +25,7 @@ class VoteRemindersListenerTest { @Test - void postVoteKeepsRawActionValueAndSeparateDisplayValue() { + void postVoteUsesTheOriginalReleaseValue() { VotingPluginMain plugin = mock(VotingPluginMain.class); VoteRemindersManager manager = mock(VoteRemindersManager.class); VoteSite site = mock(VoteSite.class); @@ -35,15 +35,14 @@ void postVoteKeepsRawActionValueAndSeparateDisplayValue() { when(event.getUser()).thenReturn(user); when(event.getVoteSite()).thenReturn(site); when(site.getDisplayName()).thenReturn("site_key"); - when(site.getDisplayNameForFormatting()).thenReturn("site_key"); new VoteRemindersListener(plugin).onPostVote(event); - verify(manager).onVoteCast(user, "site_key", "site_key"); + verify(manager).onVoteCast(user, "site_key"); } @Test - void cooldownKeepsRawActionValueAndSeparateDisplayValue() { + void cooldownUsesTheOriginalReleaseValue() { VotingPluginMain plugin = mock(VotingPluginMain.class); VoteRemindersManager manager = mock(VoteRemindersManager.class); VoteSite site = mock(VoteSite.class); @@ -53,7 +52,6 @@ void cooldownKeepsRawActionValueAndSeparateDisplayValue() { when(event.getPlayer()).thenReturn(user); when(event.getSite()).thenReturn(site); when(site.getDisplayName()).thenReturn("site_key"); - when(site.getDisplayNameForFormatting()).thenReturn("site_key"); when(site.getKey()).thenReturn("site_key"); new VoteRemindersListener(plugin).onCoolDownEnd(event); diff --git a/VotingPlugin/src/test/java/com/bencodez/votingplugin/tests/votesite/ReleaseSiteFormattingTest.java b/VotingPlugin/src/test/java/com/bencodez/votingplugin/tests/votesite/ReleaseSiteFormattingTest.java new file mode 100644 index 0000000000..7341c13807 --- /dev/null +++ b/VotingPlugin/src/test/java/com/bencodez/votingplugin/tests/votesite/ReleaseSiteFormattingTest.java @@ -0,0 +1,122 @@ +package com.bencodez.votingplugin.tests.votesite; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.CALLS_REAL_METHODS; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.concurrent.TimeUnit; + +import org.bukkit.ChatColor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.bencodez.advancedcore.api.messages.PlaceholderUtils; +import com.bencodez.simpleapi.messages.MessageAPI; +import com.bencodez.simpleapi.time.ParsedDuration; +import com.bencodez.votingplugin.VotingPluginMain; +import com.bencodez.votingplugin.config.Config; +import com.bencodez.votingplugin.config.ConfigVoteSites; +import com.bencodez.votingplugin.config.GUI; +import com.bencodez.votingplugin.user.VotingPluginUser; +import com.bencodez.votingplugin.votesites.VoteSite; + +class ReleaseSiteFormattingTest { + + private VotingPluginMain plugin; + private ConfigVoteSites config; + + @BeforeEach + void setup() { + plugin = mock(VotingPluginMain.class); + config = mock(ConfigVoteSites.class); + when(plugin.getConfigVoteSites()).thenReturn(config); + when(plugin.getConfigFile()).thenReturn(mock(Config.class)); + when(config.getDisplayName(anyString())).thenReturn(""); + when(config.getVoteDelay(anyString())).thenReturn(ParsedDuration.parse("12h", TimeUnit.HOURS)); + when(config.getServiceSite(anyString())).thenReturn("Example-Site.com"); + when(config.getVoteURL(anyString())).thenReturn("https://example.com/vote"); + } + + @Test + void fallbackSiteUsesOnlyConfiguredTemplateSpacingInFinalVisibleText() { + VoteSite site = new VoteSite(plugin, "Minecraft Menu"); + for (String[] row : new String[][] { + { "&7Site: &e%SiteName%", "Site: Minecraft Menu" }, + { "[%SiteName%]", "[Minecraft Menu]" }, + { "Vote on %SiteName%!", "Vote on Minecraft Menu!" }, + { "Site:%SiteName%", "Site:Minecraft Menu" }, + { "&a%SiteName%&7 - Vote now", "Minecraft Menu - Vote now" } }) { + assertEquals(row[1], visible(row[0].replace("%SiteName%", site.getDisplayNameForFormatting()))); + } + } + + @Test + void serviceIdentifierHasReleasePunctuationWithoutAddedSpaces() { + VoteSite site = new VoteSite(plugin, "example"); + assertEquals("Example-Site.com", site.getServiceSite()); + assertEquals("[Example-Site.com]", visible("[" + site.getServiceSiteForFormatting() + "]")); + } + + @Test + void explicitConfiguredFormattingAndWhitespaceRemainExact() { + when(config.getDisplayName("example")).thenReturn(" &aConfigured Name "); + VoteSite site = new VoteSite(plugin, "example"); + assertEquals(" &aConfigured Name ", site.getDisplayNameForFormatting()); + assertEquals("[ Configured Name ]", visible("[" + site.getDisplayNameForFormatting() + "]")); + assertEquals(" " + ChatColor.GREEN + "Configured Name ", + MessageAPI.colorize(site.getDisplayNameForFormatting())); + } + + @Test + void legacyDisplayValuesMatchTheReleaseWithoutSubstitutions() { + for (String value : new String[] { "R&D", "&aConfigured", "%player_name%", "{RED}", " Name " }) { + VoteSite site = new VoteSite(plugin, value); + assertEquals(value, site.getDisplayNameForFormatting()); + } + } + + @Test + void repeatedReadsDoNotAccumulateWhitespaceOrInvisibleMarkers() { + VoteSite site = new VoteSite(plugin, "Minecraft Menu"); + for (int refresh = 0; refresh < 5; refresh++) { + assertEquals("Minecraft Menu", site.getDisplayNameForFormatting()); + assertFalse(site.getDisplayNameForFormatting().contains("\u2060")); + } + } + + @Test + void realVoteLastChatLineUsesTheReleaseSiteValue() throws Exception { + VoteSite site = new VoteSite(plugin, "Minecraft Menu"); + VotingPluginUser user = messageUser(site); + when(plugin.getConfigFile().getFormatCommandsVoteLastLine()).thenReturn("&7Site: &e%SiteName%"); + assertEquals("Site: Minecraft Menu", visible(user.voteCommandLastLine(site))); + } + + @Test + void realVoteLastGuiLineUsesTheReleaseSiteValue() throws Exception { + VoteSite site = new VoteSite(plugin, "Minecraft Menu"); + VotingPluginUser user = messageUser(site); + GUI gui = mock(GUI.class); + when(plugin.getGui()).thenReturn(gui); + when(gui.getChestVoteLastLine()).thenReturn("&a[%SiteName%]"); + assertEquals("[Minecraft Menu]", visible(user.voteCommandLastGUILine(site))); + } + + private VotingPluginUser messageUser(VoteSite site) throws Exception { + VotingPluginUser user = mock(VotingPluginUser.class, CALLS_REAL_METHODS); + java.lang.reflect.Field pluginField = VotingPluginUser.class.getDeclaredField("plugin"); + pluginField.setAccessible(true); + pluginField.set(user, plugin); + doReturn("yesterday").when(user).voteCommandLastDate(site); + doReturn("one day").when(user).voteCommandLastDuration(site); + return user; + } + + private static String visible(String configuredText) { + return ChatColor.stripColor(PlaceholderUtils.parseJson(MessageAPI.colorize(configuredText)).toPlainText()); + } +} diff --git a/VotingPlugin/src/test/java/com/bencodez/votingplugin/tests/votesite/VoteSiteTest.java b/VotingPlugin/src/test/java/com/bencodez/votingplugin/tests/votesite/VoteSiteTest.java index f0d92aabf2..1a7ca54ecf 100644 --- a/VotingPlugin/src/test/java/com/bencodez/votingplugin/tests/votesite/VoteSiteTest.java +++ b/VotingPlugin/src/test/java/com/bencodez/votingplugin/tests/votesite/VoteSiteTest.java @@ -55,15 +55,14 @@ public void setUp() { } @Test - void legacyAutoCreatedFallbackIsVisibleAndInertWhileIdentityStaysExact() { + void legacyAutoCreatedFallbackMatchesReleaseWhileIdentityStaysExact() { for (String name : new String[] { "&kSpoofed", "%player_name%", "R&D" }) { when(plugin.getConfigVoteSites().getDisplayName(name)).thenReturn(""); VoteSite site = new VoteSite(plugin, name); site.setServiceSite(name); assertEquals(name, site.getServiceSite()); assertEquals(name, site.getDisplayName()); - assertFalse(site.getDisplayNameForFormatting().contains("&")); - assertFalse(site.getDisplayNameForFormatting().contains("%")); + assertEquals(name, site.getDisplayNameForFormatting()); assertFalse(site.getDisplayNameForFormatting().contains("\u2060")); } } @@ -83,10 +82,10 @@ public void testInitSetsValuesCorrectly() { } @Test - public void serviceSiteFormattingCannotJoinSurroundingColorCodes() { + public void serviceSiteFormattingReturnsTheUnchangedReleaseValue() { VoteSite voteSite = new VoteSite(plugin, "site.test"); - assertEquals(" ServiceSite ", voteSite.getServiceSiteForFormatting()); + assertEquals("ServiceSite", voteSite.getServiceSiteForFormatting()); assertFalse(voteSite.getServiceSiteForFormatting().contains("\u2060")); } @@ -100,12 +99,12 @@ public void rewardActionsReceiveTheExactValidatedServiceSite() throws Exception RewardBuilder builder = (RewardBuilder) factory.invoke(voteSite, "Rewards", true, false); assertEquals("ServiceSite", builder.getRewardOptions().getPlaceholders().get("ServiceSite")); - assertEquals(" ServiceSite ", RewardDisplayPlaceholders + assertEquals("ServiceSite", RewardDisplayPlaceholders .forDisplay(builder.getRewardOptions().getPlaceholders()).get("ServiceSite")); } @Test - public void fallbackDisplayNameStaysRawForActionsAndGuardedForFormatting() throws Exception { + public void fallbackDisplayNameMatchesReleaseForActionsAndFormatting() throws Exception { when(plugin.getConfigVoteSites().getDisplayName(anyString())).thenReturn(""); VoteSite voteSite = new VoteSite(plugin, "site.test"); java.lang.reflect.Method factory = VoteSite.class.getDeclaredMethod("createRewardBuilder", String.class, @@ -115,7 +114,7 @@ public void fallbackDisplayNameStaysRawForActionsAndGuardedForFormatting() throw assertEquals("site_test", voteSite.getDisplayName()); assertEquals("site_test", builder.getRewardOptions().getPlaceholders().get("SiteName")); - assertEquals(" site_test ", voteSite.getDisplayNameForFormatting()); + assertEquals("site_test", voteSite.getDisplayNameForFormatting()); assertFalse(voteSite.getDisplayNameForFormatting().contains("\u2060")); assertEquals(voteSite.getDisplayNameForFormatting(), RewardDisplayPlaceholders .forDisplay(builder.getRewardOptions().getPlaceholders()).get("SiteName")); diff --git a/docs/service-site-rendering.md b/docs/service-site-rendering.md index 730a45e3f8..a806799e10 100644 --- a/docs/service-site-rendering.md +++ b/docs/service-site-rendering.md @@ -1,33 +1,42 @@ # Voting-service identifiers and displayed names -Ordinary voting-site names retain their text, without WORD JOINER or other -font-dependent guards. External display values have an ASCII space on each side -to prevent adjacent template text from completing a formatting token. For example, -`[%SiteName%]` renders `[ Javascript=1 ]` for the literal service `Javascript=1`, -rather than creating an executable rich-format token. Administrator-authored display-name colors and placeholders -remain supported. The exact service identifier is preserved for matching, -action placeholders, and queued-vote recovery. +Bukkit/Paper site-name formatting follows the GitHub VotingPlugin `7.1.1` release baseline +(`39f4717f363beb1d338b353a060630eba6b60cbb`). Configured display names and +fallback site keys enter the existing formatter unchanged. No extra leading or +trailing spaces, invisible separators, or printable delimiter substitutions are +inserted. For example, `&7Site: &e%SiteName%` with `Minecraft Menu` displays +`Site: Minecraft Menu`, and `[%SiteName%]` displays `[Minecraft Menu]`. +Administrator-authored colors, placeholders and intentional whitespace retain +the release behavior. `R&D` remains `R&D` in formatting input. -Display-only values originating from external service identifiers or fallback -site keys use printable ASCII labels for interpreter delimiters: `&` becomes -`(ampersand)`, `%` becomes `(percent)`, `ยง` becomes `(section)`, and braces become -`(open brace)` / `(close brace)`. This avoids executing color/placeholder syntax -without relying on font support for hidden Unicode guards. For example, a legacy -`R&D` identifier matches exactly as before but its fallback display is -`R(ampersand)D`. An explicit trusted `DisplayName` can provide a preferred label. +The exact service identifier remains unchanged for matching, actions, storage +and proxy communication. Compatibility accessors `getDisplayNameForFormatting`, +`getServiceSiteForFormatting` remain available; their historical names do not +promise literal insertion or interpreter isolation. +All Bukkit GUI, book, dialog, broadcast, cooldown, reward and reminder callers +use the original raw getters. Display-only reward/reminder overrides introduced +with the guard are removed. Compatibility accessors simply return those values; +they are not an active formatting path. No AdvancedCore literal-rendering +extension is required. -This also protects already-persisted auto-created sites. It does not rename site -keys or change reward action identifiers. Existing service-name acceptance and -persisted ingress journals remain compatible: names containing `&` or `%`, -including legacy URL-shaped identifiers, remain replayable. Structural delimiters -such as quotes, brackets, backticks and backslashes, section-sign formatting codes, control characters and -oversized identifiers retain their existing rejection rules. Delayed-vote rejection messages additionally accept bounded legacy punctuation -for an enabled, loaded site whose configured `ServiceSite` matches (case-insensitively), -resolved without auto-creation. Display-name and YAML-key aliases alone cannot -authorize these legacy rejection rewards; unknown malformed -names, control characters and oversized values remain rejected before user lookup. -Legacy brackets, quotes, backticks and backslashes use printable display labels too. `VoteURL` is unchanged. +This deliberately restores the release's formatting trust semantics. The later +external-identifier guards are removed: external or fallback text can once again +participate in the configured color, placeholder or rich-text interpretation. +This change does not claim the previous protection against tokens formed across +placeholder boundaries. Input validation, bounded single-line logging, raw vote +identity, asynchronous reward ordering and delivery bookkeeping are retained. +The separate NeoForge replay adapter was not part of release `7.1.1`; its guarded +expansion and the shared `inertForFormatting` helper are unchanged. -No configuration or data migration is required. Minecraft client rendering of -the new printable labels has not been visually verified; automated tests cover -literal display values, trusted labels, queued-vote recovery and reward routing. +New auto-created sites use the release's original reward-message template, +`&aThanks for voting on %ServiceSite%!`. Existing site files and configured +messages are preserved; no configuration or database migration is required. + +Proxy receipt logs sanitize player names using the Minecraft-username sanitizer +and service identifiers using the separate service-site sanitizer. Service dots, +hyphens, spaces and ordinary punctuation survive; controls and unsupported +formatting characters cannot add log lines, and output remains bounded. +These display/log representations do not alter the received vote's identity. + +Automated component tests check final visible text and the actual BungeeCord and +Velocity receipt-log paths. Native Minecraft client rendering is not claimed.