From 396bcfc68b8e167751513bcb138792659a1669fb Mon Sep 17 00:00:00 2001 From: EpicKnarvik97 Date: Sat, 24 Jun 2023 15:07:03 +0200 Subject: [PATCH] Adds proper support for dual-side paid signs --- pom.xml | 2 +- .../paidsigns/container/TrackedSign.java | 38 +++++- .../paidsigns/listener/SignListener.java | 5 +- .../paidsigns/manager/TrackedSignManager.java | 109 ++++++++++++++++-- 4 files changed, 138 insertions(+), 16 deletions(-) diff --git a/pom.xml b/pom.xml index 0d16e7e..1288698 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.knarcraft paidsigns - 1.0.2 + 1.0.3-SNAPSHOT jar Paid Signs diff --git a/src/main/java/net/knarcraft/paidsigns/container/TrackedSign.java b/src/main/java/net/knarcraft/paidsigns/container/TrackedSign.java index 0b5b290..7836097 100644 --- a/src/main/java/net/knarcraft/paidsigns/container/TrackedSign.java +++ b/src/main/java/net/knarcraft/paidsigns/container/TrackedSign.java @@ -1,13 +1,45 @@ package net.knarcraft.paidsigns.container; +import org.bukkit.block.sign.Side; + import java.util.UUID; /** * A representation of a sign placed by a player that matched a paid sign * - * @param playerId

The unique id of the player that created the sign

- * @param cost

The cost the player paid for creating the sign

+ * @param playerId

The unique id of the player that created the sign

+ * @param frontCost

The cost the player paid for creating the front of the sign

+ * @param backCost

The cost the player paid for creating the back of the sign

*/ -public record TrackedSign(UUID playerId, double cost) { +public record TrackedSign(UUID playerId, double frontCost, double backCost) { + + /** + * Gets an instance of a tracked sign + * + * @param playerId

The unique id of the player that created the sign

+ * @param side

The side the player paid for

+ * @param cost

The cost the player paid for creating the side of the sign

+ * @return

A tracked sign instance

+ */ + public static TrackedSign getInstance(UUID playerId, Side side, double cost) { + if (side == Side.FRONT) { + return new TrackedSign(playerId, cost, 0); + } else { + return new TrackedSign(playerId, 0, cost); + } + } + + /** + * Gets the cost paid for the given side + * + * @param side

The side to check the cost for

+ * @return

The cost the player paid

+ */ + public double getCost(Side side) { + return switch (side) { + case FRONT -> frontCost; + case BACK -> backCost; + }; + } } diff --git a/src/main/java/net/knarcraft/paidsigns/listener/SignListener.java b/src/main/java/net/knarcraft/paidsigns/listener/SignListener.java index 5c5ef34..7356290 100644 --- a/src/main/java/net/knarcraft/paidsigns/listener/SignListener.java +++ b/src/main/java/net/knarcraft/paidsigns/listener/SignListener.java @@ -39,7 +39,8 @@ public class SignListener implements Listener { // As signs can be edited now, this event might be triggered on an already registered sign, so unregister if (SignHelper.isSign(event.getBlock())) { try { - TrackedSignManager.removeTrackedSign(event.getBlock().getLocation(), true, false); + TrackedSignManager.removeTrackedSign(event.getBlock().getLocation(), true, false, + event.getSide()); } catch (IOException ignored) { } } @@ -164,7 +165,7 @@ public class SignListener implements Listener { EconomyManager.withdraw(player, cost); PaidSigns.getStringFormatter().displaySuccessMessage(player, replaceCost(cost, PaidSignsTranslatableMessage.SUCCESS_PAID_FOR_SIGN)); try { - TrackedSignManager.addTrackedSign(event.getBlock().getLocation(), player.getUniqueId(), cost); + TrackedSignManager.addTrackedSign(event.getBlock().getLocation(), player.getUniqueId(), cost, event.getSide()); } catch (IOException ignored) { } } diff --git a/src/main/java/net/knarcraft/paidsigns/manager/TrackedSignManager.java b/src/main/java/net/knarcraft/paidsigns/manager/TrackedSignManager.java index 8b41082..b9a28fc 100644 --- a/src/main/java/net/knarcraft/paidsigns/manager/TrackedSignManager.java +++ b/src/main/java/net/knarcraft/paidsigns/manager/TrackedSignManager.java @@ -7,6 +7,7 @@ import net.knarcraft.paidsigns.utility.SignHelper; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.OfflinePlayer; +import org.bukkit.block.sign.Side; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; @@ -36,13 +37,72 @@ public final class TrackedSignManager { * * @param signLocation

The location the sign was created at

* @param playerId

The unique id of the player that created the sign

+ * @param cost

The cost the player paid

+ * @param side

The side of the sign the player paid for

* @throws IOException

If unable to save the tracked signs

*/ - public static void addTrackedSign(Location signLocation, UUID playerId, double cost) throws IOException { - trackedSigns.put(signLocation, new TrackedSign(playerId, cost)); + public static void addTrackedSign(Location signLocation, UUID playerId, double cost, Side side) throws IOException { + if (trackedSigns.containsKey(signLocation)) { + // If there is already a tracked sign, overwrite it, while updating only the correct cost + TrackedSign oldSign = trackedSigns.get(signLocation); + if (side == Side.FRONT) { + trackedSigns.put(signLocation, new TrackedSign(playerId, cost, oldSign.backCost())); + } else { + trackedSigns.put(signLocation, new TrackedSign(playerId, oldSign.frontCost(), cost)); + } + } else { + trackedSigns.put(signLocation, TrackedSign.getInstance(playerId, side, cost)); + } saveTrackedSigns(); } + /** + * Removes a tracked sign from the manager + * + * @param signLocation

The location the sign was removed from

+ * @param refund

Whether to perform a refund after un-tracking the sign

+ * @param forceRefund

Whether to force a refund, even if refunding is disabled

+ * @param side

The side of the sign to un-track

+ * @throws IOException

If unable to save the tracked signs

+ */ + public static void removeTrackedSign(Location signLocation, boolean refund, boolean forceRefund, + Side side) throws IOException { + if (!trackedSigns.containsKey(signLocation)) { + return; + } + TrackedSign trackedSign = trackedSigns.get(signLocation); + + Side oppositeSide = getOppositeSide(side); + double oppositeCost = trackedSign.getCost(oppositeSide); + boolean isInUse = oppositeCost > 0; + + if (!isInUse) { + trackedSigns.remove(signLocation); + } else { + // If the opposite side has a cost, create a new sign with only that cost + trackedSigns.put(signLocation, TrackedSign.getInstance(trackedSign.playerId(), oppositeSide, oppositeCost)); + } + + saveTrackedSigns(); + if (trackedSign.getCost(side) > 0) { + refund(trackedSign, refund, forceRefund, side); + } + } + + /** + * Gets the opposite sign side of the given side + * + * @param side

The side to get the opposite of

+ * @return

The opposite sign side

+ */ + private static Side getOppositeSide(Side side) { + if (side == Side.FRONT) { + return Side.BACK; + } else { + return Side.FRONT; + } + } + /** * Removes a tracked sign from the manager * @@ -58,7 +118,7 @@ public final class TrackedSignManager { TrackedSign trackedSign = trackedSigns.get(signLocation); trackedSigns.remove(signLocation); saveTrackedSigns(); - refund(trackedSign, refund, forceRefund); + refundBothSides(trackedSign, refund, forceRefund); } /** @@ -105,16 +165,27 @@ public final class TrackedSignManager { return; } - double cost = signSection.getDouble(key + ".cost"); + double frontCost; + double backCost = 0; + if (signSection.contains(key + ".cost")) { + // Migrate from single side cost to two side cost + frontCost = signSection.getDouble(key + ".cost"); + signSection.set(key + ".cost", null); + } else { + frontCost = signSection.getDouble(key + ".frontCost"); + } + if (signSection.contains(key + ".backCost")) { + backCost = signSection.getDouble(key + ".backCost"); + } UUID playerId = UUID.fromString(Objects.requireNonNull(signSection.getString(key + ".playerId"))); - TrackedSign trackedSign = new TrackedSign(playerId, cost); + TrackedSign trackedSign = new TrackedSign(playerId, frontCost, backCost); //Prevent destroyed signs from being tracked indefinitely if (!SignHelper.isSign(signLocation.getBlock())) { Bukkit.getScheduler().scheduleSyncDelayedTask(PaidSigns.getInstance(), () -> { PaidSigns.getInstance().getLogger().log(Level.WARNING, "The sign at " + signLocation + " no longer exists. Removing from sign tracker. Refunding the player."); - refund(trackedSign, true, false); + refundBothSides(trackedSign, true, false); }, 100); return; } @@ -135,7 +206,8 @@ public final class TrackedSignManager { TrackedSign sign = trackedSigns.get(signLocation); String locationString = Objects.requireNonNull(signLocation.getWorld()).getUID() + "," + signLocation.getBlockX() + "," + signLocation.getBlockY() + "," + signLocation.getBlockZ(); - signSection.set(locationString + ".cost", sign.cost()); + signSection.set(locationString + ".frontCost", sign.frontCost()); + signSection.set(locationString + ".backCost", sign.backCost()); signSection.set(locationString + ".playerId", sign.playerId().toString()); } configuration.save(signsFile); @@ -148,17 +220,18 @@ public final class TrackedSignManager { * @param refund

Whether to actually refund

* @param forceRefund

Whether to force a refund, even if refunding is disabled

*/ - private static void refund(TrackedSign trackedSign, boolean refund, boolean forceRefund) { + private static void refund(TrackedSign trackedSign, boolean refund, boolean forceRefund, Side signSide) { if ((!PaidSigns.getInstance().areRefundsEnabled() || !refund) && !forceRefund) { return; } + double cost = trackedSign.getCost(signSide); OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(trackedSign.playerId()); double refundSum; if (forceRefund) { //In the case where a refund is forced, the normal refund rate should not apply - refundSum = trackedSign.cost(); + refundSum = cost; } else { - refundSum = trackedSign.cost() / 100 * PaidSigns.getInstance().getRefundPercentage(); + refundSum = cost / 100 * PaidSigns.getInstance().getRefundPercentage(); } EconomyManager.deposit(offlinePlayer, refundSum); if (offlinePlayer instanceof Player player) { @@ -168,4 +241,20 @@ public final class TrackedSignManager { } } + /** + * Refunds the costs for both sides of a paid sign + * + * @param trackedSign

The tracked sign to refund for

+ * @param refund

Whether to perform a refund after un-tracking the sign

+ * @param forceRefund

Whether to force a refund, even if refunding is disabled

+ */ + private static void refundBothSides(TrackedSign trackedSign, boolean refund, boolean forceRefund) { + if (trackedSign.frontCost() > 0) { + refund(trackedSign, refund, forceRefund, Side.FRONT); + } + if (trackedSign.backCost() > 0) { + refund(trackedSign, refund, forceRefund, Side.BACK); + } + } + }