diff --git a/README.md b/README.md index 7b4ea3c..f744c92 100644 --- a/README.md +++ b/README.md @@ -53,12 +53,15 @@ style: fill-opacity: 0.35 # Path to icons on web or a link # Town home - home-icon-enabled: false + # If you want to have towns have the option to use their own image markers (By default it's only a locked to 1 default image for every town) + # "disabled", if you want to disable the home icon, "only-default" for default, "preset" as customizable within a preset of images inside a folder created by the plugin, "link" as letting the town/players choose their own town marker via a link (BE WARNED THAT YOU HAVE TO TRUST THE GOODWILL OF YOUR PLAYERS FOR THIS) + # Changing between the "preset" and "link" types will break existing home markers + home-icon-style: "only-default" home-icon: assets/house.png # Nation capital capital-icon-enabled: false capital-icon: assets/king.png - # Icon during war + # Icon during War war-icon-enabled: false war-icon: assets/war.png # Icon for ruined towns @@ -107,6 +110,12 @@ style: | `%battle_points_defender%` | Battle points on the defender's side | | `%battle_time_left%` | Time left in the Battle Session | +### Permissions + +| Permission | Content | +|----------------------------|---------------------------------------------| +| `towny.command.town.set.townmarker` | Able to set their own Town Markers with /town set marker | + ## Building `./gradlew clean build` diff --git a/src/main/java/codes/antti/bluemaptowny/BlueMapTowny.java b/src/main/java/codes/antti/bluemaptowny/BlueMapTowny.java index 4838e33..dacb805 100644 --- a/src/main/java/codes/antti/bluemaptowny/BlueMapTowny.java +++ b/src/main/java/codes/antti/bluemaptowny/BlueMapTowny.java @@ -1,52 +1,51 @@ package codes.antti.bluemaptowny; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - +import codes.antti.bluemaptowny.TownyCommands.SetTownMarker; import com.flowpowered.math.vector.Vector2d; -import com.technicjelle.BMUtils.Cheese; -import de.bluecolored.bluemap.api.markers.*; -import org.apache.commons.lang.WordUtils; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.configuration.Configuration; -import org.bukkit.entity.Player; -import org.bukkit.plugin.java.JavaPlugin; - import com.flowpowered.math.vector.Vector2i; import com.gmail.goosius.siegewar.SiegeWarAPI; import com.gmail.goosius.siegewar.enums.SiegeSide; import com.gmail.goosius.siegewar.objects.Siege; import com.gmail.goosius.siegewar.settings.SiegeWarSettings; import com.palmergames.bukkit.config.ConfigNodes; -import com.palmergames.bukkit.towny.TownyAPI; -import com.palmergames.bukkit.towny.TownyEconomyHandler; -import com.palmergames.bukkit.towny.TownyFormatter; -import com.palmergames.bukkit.towny.TownySettings; +import com.palmergames.bukkit.towny.*; +import com.palmergames.bukkit.towny.object.AddonCommand; import com.palmergames.bukkit.towny.object.Town; import com.palmergames.bukkit.towny.object.TownyObject; import com.palmergames.bukkit.towny.object.TownyWorld; import com.palmergames.bukkit.towny.utils.TownRuinUtil; +import com.technicjelle.BMUtils.Cheese; import com.technicjelle.UpdateChecker; - import de.bluecolored.bluemap.api.BlueMapAPI; +import de.bluecolored.bluemap.api.markers.Marker; +import de.bluecolored.bluemap.api.markers.MarkerSet; +import de.bluecolored.bluemap.api.markers.POIMarker; +import de.bluecolored.bluemap.api.markers.ShapeMarker; import de.bluecolored.bluemap.api.math.Color; import de.bluecolored.bluemap.api.math.Shape; +import org.apache.commons.lang.WordUtils; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.configuration.Configuration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; public final class BlueMapTowny extends JavaPlugin { + + private final Map townMarkerSets = new ConcurrentHashMap<>(); private Configuration config; + public static BlueMapTowny plugin; + @Override public void onEnable() { try { @@ -61,7 +60,10 @@ public void onEnable() { reloadConfig(); saveDefaultConfig(); this.config = getConfig(); + this.plugin = this; initMarkerSets(); + registerCommands(); + makeAssetsFolder(); if (isFolia) { Bukkit.getServer().getAsyncScheduler().runAtFixedRate(this, task -> this.updateMarkers(), 1L, this.config.getLong("update-interval"), TimeUnit.SECONDS); } else { @@ -205,7 +207,8 @@ private String fillPlaceholders(String template, Town town) { flags.add("Nation: " + nation); if (TownySettings.getBoolean(ConfigNodes.TOWN_RUINING_TOWN_RUINS_ENABLED)) { String ruinedString = "Ruined: " + town.isRuined(); - if (town.isRuined()) ruinedString += " (Time left: " + (TownySettings.getTownRuinsMaxDurationHours() - TownRuinUtil.getTimeSinceRuining(town)) + " hours)"; + if (town.isRuined()) + ruinedString += " (Time left: " + (TownySettings.getTownRuinsMaxDurationHours() - TownRuinUtil.getTimeSinceRuining(town)) + " hours)"; flags.add(ruinedString); } t = t.replace("%flags%", String.join("
", flags)); @@ -222,7 +225,7 @@ private String fillPlaceholders(String template, Town town) { t = t.replace("%town_resources%", ""); } - if(getServer().getPluginManager().isPluginEnabled("SiegeWar")) { + if (getServer().getPluginManager().isPluginEnabled("SiegeWar")) { if (SiegeWarAPI.hasSiege(town)) { Siege siege = SiegeWarAPI.getSiege(town).get(); t = t.replace("%attacker%", siege.getAttackerNameForDisplay()); @@ -240,7 +243,7 @@ private String fillPlaceholders(String template, Town town) { } t = t.replace("%banner_control%", WordUtils.capitalizeFully(siege.getBannerControllingSide().name()) - + (siege.getBannerControllingSide() == SiegeSide.NOBODY ? "" : " (" + siege.getBannerControllingResidents().size() + ")")); + + (siege.getBannerControllingSide() == SiegeSide.NOBODY ? "" : " (" + siege.getBannerControllingResidents().size() + ")")); t = t.replace("%siege_status%", siege.getStatus().getName()); @@ -258,6 +261,29 @@ private String fillPlaceholders(String template, Town town) { return t; } + private String fillTownyIcons(Town town) { + String icon; + if (town.hasMeta("mapMarker")){ + switch (config.getString("home-icon-style")) { + case "preset" -> { + icon = "assets/townmarkers/" + town.getMetadata("mapMarker").getValue().toString(); + return icon; + } + case "link" -> { + icon = town.getMetadata("mapMarker").getValue().toString(); + return icon; + } + default -> { + icon = this.config.getString("style.home-icon"); + return icon; + } + } + }else{ + icon = this.config.getString("style.home-icon"); + } + return icon; + } + private void updateMarkers() { BlueMapAPI.getInstance().ifPresent((api) -> { for (World world : Bukkit.getWorlds()) { @@ -324,11 +350,11 @@ private void updateMarkers() { .build(); markers.put("towny." + townName + ".icon", iconMarker); - } else if (this.config.getBoolean("style.home-icon-enabled")) { + } else if (!this.config.getString("style.home-icon-style").equalsIgnoreCase("disabled")) { POIMarker iconMarker = new POIMarker.Builder() .label(townName) .detail(townDetails) - .icon(this.config.getString("style.home-icon"), 8, 8) + .icon(fillTownyIcons(town), 8, 8) .styleClasses("towny-icon") .position(spawn.get().getX(), layerY, spawn.get().getZ()) .build(); @@ -351,4 +377,21 @@ private void updateMarkers() { } }); } + + private void registerCommands(){ + AddonCommand setTownMarker = new AddonCommand(TownyCommandAddonAPI.CommandType.TOWN_SET, "marker", new SetTownMarker()); + if(config.getString("home-icon-style").equalsIgnoreCase("preset")|| config.getString("home-icon-style").equalsIgnoreCase("link")){ + TownyCommandAddonAPI.addSubCommand(setTownMarker); + }else{ + TownyCommandAddonAPI.removeSubCommand(setTownMarker); + } + + } + + private void makeAssetsFolder(){ + File file = new File(BlueMapAPI.getInstance().get().getWebApp().getWebRoot().toFile(), "/assets/townmarkers"); + if(!file.exists()){ + file.mkdir(); + } + } } diff --git a/src/main/java/codes/antti/bluemaptowny/TownyCommands/SetTownMarker.java b/src/main/java/codes/antti/bluemaptowny/TownyCommands/SetTownMarker.java new file mode 100644 index 0000000..207f833 --- /dev/null +++ b/src/main/java/codes/antti/bluemaptowny/TownyCommands/SetTownMarker.java @@ -0,0 +1,85 @@ +package codes.antti.bluemaptowny.TownyCommands; + +import codes.antti.bluemaptowny.BlueMapTowny; +import com.palmergames.bukkit.towny.TownyMessaging; +import com.palmergames.bukkit.towny.TownyUniverse; +import com.palmergames.bukkit.towny.object.Resident; +import com.palmergames.bukkit.towny.object.metadata.StringDataField; +import de.bluecolored.bluemap.api.BlueMapAPI; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class SetTownMarker implements CommandExecutor, TabExecutor { + + Plugin plugin = BlueMapTowny.plugin; + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (!(sender instanceof Player)) { + TownyMessaging.sendErrorMsg(sender, "Must be run by a Player!"); + return true; + } + Resident resident = TownyUniverse.getInstance().getResident(((Player) sender).getUniqueId()); + + if (!resident.hasTown()) { + TownyMessaging.sendErrorMsg(sender, "You don't have a town!"); + return true; + } + + if (!resident.isMayor() || !((Player) sender).getPlayer().hasPermission("towny.command.town.set.townmarker")) { + TownyMessaging.sendErrorMsg(sender, "You don't have permission for this or aren't the Mayor!"); + return true; + } + + if(plugin.getConfig().getString("home-icon-style").equalsIgnoreCase("preset")){ + if(ifFileExists(String.join(" ", args)) == false){ + TownyMessaging.sendErrorMsg(resident, "This file isn't a valid file!"); + return true; + } + } + TownyMessaging.sendPrefixedTownMessage(resident.getTownOrNull(), "Town Marker has been set to: " + String.join(" ", args)); + resident.getTownOrNull().addMetaData(new StringDataField("mapMarker", String.join(" ", args))); + + + return true; + } + + @Override + public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + switch (plugin.getConfig().getInt("use-links-as-image-source")) { + case 1 -> { + File file = new File(BlueMapAPI.getInstance().get().getWebApp().getWebRoot().toFile(), "/assets/TownMarkers"); + String[] listOfFiles = file.list(); + if (args.length == 1) { + return Arrays.stream(listOfFiles).toList(); + } + return Collections.emptyList(); + } + case 2 -> { + return Collections.singletonList(""); + } + default -> { + return Collections.emptyList(); + } + } + } + + public boolean ifFileExists(String string){ + File file = new File(BlueMapAPI.getInstance().get().getWebApp().getWebRoot().toFile(), "/assets/townmarkers/" + string); + if(file.isFile()) { + return true; + } + return false; + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 8d9f95f..6dbdb83 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -26,7 +26,10 @@ style: fill-opacity: 0.35 # Path to icons on web or a link # Town home - home-icon-enabled: false + # If you want to have towns have the option to use their own image markers (By default it's only a locked to 1 default image for every town) + # "disabled", if you want to disable the home icon, "only-default" for default, "preset" as customizable within a preset of images inside a folder created by the plugin, "link" as letting the town/players choose their own town marker via a link (BE WARNED THAT YOU HAVE TO TRUST THE GOODWILL OF YOUR PLAYERS FOR THIS) + # Changing between the "preset" and "link" types will break existing home markers + home-icon-style: "only-default" home-icon: assets/house.png # Nation capital capital-icon-enabled: false