)"),
70 |
71 | INFOWINDOW_ROOT("infowindow","","",""),
72 | INFOWINDOW_TOWN_POPUP("infowindow.town_info_window",
73 | "%regionname% (%nation%)
Mayor %playerowners%
Associates %playermanagers%
Flags
%flags%
",
74 | "","# Format for town popup."),
75 | INFOWINDOW_NO_NATION_SLUG("infowindow.noNationSlug",
76 | "",
77 | "","# What is shown in the info window's %nation% when a town has no nation."),
78 |
79 | REGIONSTYLE_ROOT("regionstyle","","",""),
80 | REGIONSTYLE_STROKE_COLOUR("regionstyle.strokeColor", "#FF0000"),
81 | REGIONSTYLE_STROKE_OPACITY("regionstyle.strokeOpacity", "0.8"),
82 | REGIONSTYLE_STROKE_WEIGHT("regionstyle.strokeWeight", "3"),
83 | REGIONSTYLE_FILL_COLOUR("regionstyle.fillColor", "#FF0000"),
84 | REGIONSTYLE_FILL_OPACITY("regionstyle.fillOpacity", "0.35"),
85 | REGIONSTYLE_BOOST("regionstyle.boost", "false"),
86 | REGIONSTYLE_ICONS_ROOT("regionstyle.icons","","",
87 | "# Allowed icon names found here: https://github.com/webbukkit/dynmap/wiki/Using-Markers",
88 | "# If you want to not show outposts, put in a invalid marker name ie: 'outpostIcon: boot'."),
89 | REGIONSTYLE_HOME_ICON("regionstyle.icons.homeIcon",
90 | "blueflag"),
91 | REGIONSTYLE_CAPITAL_ICON("regionstyle.icons.capitalIcon",
92 | "king"),
93 | REGIONSTYLE_OUTPOST_ICON("regionstyle.icons.outpostIcon",
94 | "tower"),
95 | REGIONSTYLE_RUIN_ICON("regionstyle.icons.ruinIcon",
96 | "warning"),
97 |
98 | VISIBLE_ROOT("visibleregions","","",
99 | "# Optional setting to limit which regions to show, by name - if commented out, all regions are shown.",
100 | "# To show all regions on a given world, add 'world:' to the list."),
101 | HIDDEN_ROOT("hiddenregions","","",
102 | "# Optional setting to hide specific regions, by name.",
103 | "# To hide all regions on a given world, add 'world:' to the list."),
104 |
105 | CUSTOMSTYLE_ROOT("custstyle","","",""),
106 | NATIONSTYLE_ROOT("nationstyle","","",""),
107 |
108 | CHAT_ROOT("chat","","","# Chat settings for use with TownyChat."),
109 | CHAT_SEND_LOGIN("chat.sendlogin","true"),
110 | CHAT_SEND_QUIT("chat.sendquit","true"),
111 | CHAT_FORMAT("chat.format","&color;2[WEB] %playername%: &color;f%message%"),
112 |
113 | LANGUAGE("language",
114 | "english.yml",
115 | "# The language file you wish to use");
116 |
117 | private final String Root;
118 | private final String Default;
119 | private String[] comments;
120 |
121 | ConfigNodes(String root, String def, String... comments) {
122 |
123 | this.Root = root;
124 | this.Default = def;
125 | this.comments = comments;
126 | }
127 |
128 | /**
129 | * Retrieves the root for a config option
130 | *
131 | * @return The root for a config option
132 | */
133 | public String getRoot() {
134 |
135 | return Root;
136 | }
137 |
138 | /**
139 | * Retrieves the default value for a config path
140 | *
141 | * @return The default value for a config path
142 | */
143 | public String getDefault() {
144 |
145 | return Default;
146 | }
147 |
148 | /**
149 | * Retrieves the comment for a config path
150 | *
151 | * @return The comments for a config path
152 | */
153 | public String[] getComments() {
154 |
155 | if (comments != null) {
156 | return comments;
157 | }
158 |
159 | String[] comments = new String[1];
160 | comments[0] = "";
161 | return comments;
162 | }
163 |
164 | }
165 |
--------------------------------------------------------------------------------
/src/main/java/org/dynmap/towny/DynmapTownyPlugin.java:
--------------------------------------------------------------------------------
1 | package org.dynmap.towny;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 | import java.util.Set;
6 | import java.util.logging.Level;
7 | import java.util.logging.Logger;
8 | import java.util.stream.Collectors;
9 |
10 | import org.bukkit.plugin.Plugin;
11 | import org.bukkit.plugin.PluginManager;
12 | import org.bukkit.plugin.java.JavaPlugin;
13 | import org.dynmap.DynmapAPI;
14 | import org.dynmap.markers.AreaMarker;
15 | import org.dynmap.markers.Marker;
16 | import org.dynmap.markers.MarkerAPI;
17 | import org.dynmap.markers.MarkerSet;
18 | import org.dynmap.markers.PlayerSet;
19 | import org.dynmap.towny.listeners.DynmapTownyListener;
20 | import org.dynmap.towny.mapupdate.AreaStyleHolder;
21 | import org.dynmap.towny.mapupdate.UpdateTowns;
22 | import org.dynmap.towny.settings.Settings;
23 |
24 | import com.palmergames.bukkit.towny.Towny;
25 | import com.palmergames.bukkit.towny.TownyAPI;
26 | import com.palmergames.bukkit.towny.TownyUniverse;
27 | import com.palmergames.bukkit.towny.exceptions.initialization.TownyInitException;
28 | import com.palmergames.bukkit.towny.object.Nation;
29 | import com.palmergames.bukkit.towny.object.Town;
30 | import com.palmergames.bukkit.towny.scheduling.ScheduledTask;
31 | import com.palmergames.bukkit.towny.scheduling.TaskScheduler;
32 | import com.palmergames.bukkit.towny.scheduling.impl.BukkitTaskScheduler;
33 | import com.palmergames.bukkit.towny.scheduling.impl.FoliaTaskScheduler;
34 |
35 | public class DynmapTownyPlugin extends JavaPlugin {
36 |
37 | private static final String requiredTownyVersion = "0.100.4.0";
38 | private static Logger log;
39 | private static DynmapTownyPlugin plugin;
40 | private final TaskScheduler scheduler;
41 | private ScheduledTask task;
42 | private UpdateTowns townUpdater;
43 | private DynmapAPI dynmapAPI;
44 | private MarkerAPI markerAPI;
45 | private MarkerSet markerSet;
46 | private Map areaMarkers = new HashMap();
47 | private Map markers = new HashMap();
48 |
49 | public DynmapTownyPlugin() {
50 | this.scheduler = isFoliaClassPresent() ? new FoliaTaskScheduler(this) : new BukkitTaskScheduler(this);
51 | plugin = this;
52 | }
53 |
54 | @Override
55 | public void onLoad() {
56 | log = this.getLogger();
57 | }
58 |
59 | public void onEnable() {
60 | info("Initializing DynmapTowny.");
61 |
62 | Plugin dynmap = null;
63 | Plugin towny = null;
64 | Plugin townychat = null;
65 | PluginManager pm = getServer().getPluginManager();
66 |
67 | /* Get dynmap */
68 | dynmap = pm.getPlugin("dynmap");
69 | if (dynmap == null || !dynmap.isEnabled()) {
70 | severe("Cannot find dynmap, check your logs to see if it enabled properly?!");
71 | return;
72 | }
73 |
74 | /* Get Towny */
75 | towny = pm.getPlugin("Towny");
76 | if (towny == null || !towny.isEnabled()) {
77 | severe("Cannot find Towny, check your logs to see if it enabled properly?!");
78 | return;
79 | }
80 |
81 | /* Get DynmapAPI */
82 | dynmapAPI = (DynmapAPI) dynmap;
83 |
84 | // Make sure the Towny version is new enough.
85 | if (!townyVersionCheck()) {
86 | getLogger().severe("Towny version does not meet required minimum version: " + requiredTownyVersion);
87 | this.getServer().getPluginManager().disablePlugin(this);
88 | return;
89 | } else {
90 | getLogger().info("Towny version " + towny.getDescription().getVersion() + " found.");
91 | }
92 |
93 | if (!loadConfig()) {
94 | onDisable();
95 | return;
96 | }
97 |
98 | /* Register the event listener. */
99 | new DynmapTownyListener(pm, this);
100 |
101 | /* Kick off the rest of the plugin. */
102 | activate();
103 |
104 | /* Check if TownyChat is present. */
105 | townychat = pm.getPlugin("TownyChat");
106 | if (townychat != null && townychat.isEnabled()) {
107 | dynmapAPI.setDisableChatToWebProcessing(true);
108 | Settings.setUsingTownyChat(true);
109 | info("TownyChat detect: disabling normal chat-to-web processing in Dynmap");
110 | }
111 | }
112 |
113 | private boolean loadConfig() {
114 | try {
115 | Settings.loadConfig();
116 | } catch (TownyInitException e) {
117 | e.printStackTrace();
118 | severe("Config.yml failed to load! Disabling!");
119 | return false;
120 | }
121 | info("Config.yml loaded successfully.");
122 | return true;
123 | }
124 |
125 | private void activate() {
126 | markerAPI = dynmapAPI.getMarkerAPI();
127 | if (markerAPI == null) {
128 | severe("Error loading dynmap marker API!");
129 | return;
130 | }
131 |
132 | /* We might be reloading and have a set already in use. */
133 | if (markerSet != null) {
134 | markerSet.deleteMarkerSet();
135 | markerSet = null;
136 | }
137 |
138 | /* Initialize the critical Towny MarkerSet. */
139 | if (!initializeMarkerSet()) {
140 | severe("Error creating Towny marker set!");
141 | return;
142 | }
143 |
144 | /* Initialize the Styles from the config for use by the TownyUpdate task. */
145 | AreaStyleHolder.initialize();
146 |
147 | /* Create our UpdateTowns instance, used to actually draw the towns. */
148 | townUpdater = new UpdateTowns();
149 |
150 | /* Set up update job - based on period */
151 | long per = Math.max(15, Settings.getUpdatePeriod()) * 20L;
152 | task = scheduler.runAsyncRepeating(new TownyUpdate(), 40, per);
153 |
154 | info("version " + this.getDescription().getVersion() + " is activated");
155 | }
156 |
157 | private boolean initializeMarkerSet() {
158 | markerSet = markerAPI.getMarkerSet("towny.markerset");
159 | if (markerSet == null)
160 | markerSet = markerAPI.createMarkerSet("towny.markerset", Settings.getLayerName(), null, false);
161 | else
162 | markerSet.setMarkerSetLabel(Settings.getLayerName());
163 |
164 | if (markerSet == null)
165 | return false;
166 |
167 | int minzoom = Settings.getMinZoom();
168 | if (minzoom > 0)
169 | markerSet.setMinZoom(minzoom);
170 | markerSet.setLayerPriority(Settings.getLayerPriority());
171 | markerSet.setHideByDefault(Settings.getLayerHiddenByDefault());
172 | return true;
173 | }
174 |
175 | public void onDisable() {
176 | if (markerSet != null) {
177 | markerSet.deleteMarkerSet();
178 | markerSet = null;
179 | }
180 | task.cancel();
181 | }
182 |
183 | private static boolean isFoliaClassPresent() {
184 | try {
185 | Class.forName("io.papermc.paper.threadedregions.RegionizedServer");
186 | return true;
187 | } catch (ClassNotFoundException e) {
188 | return false;
189 | }
190 | }
191 |
192 | public static DynmapTownyPlugin getPlugin() {
193 | return plugin;
194 | }
195 |
196 | public static String getPrefix() {
197 | return "[" + plugin.getName() + "]";
198 | }
199 |
200 | private boolean townyVersionCheck() {
201 | try {
202 | return Towny.isTownyVersionSupported(requiredTownyVersion);
203 | } catch (NoSuchMethodError e) {
204 | return false;
205 | }
206 | }
207 |
208 | public String getVersion() {
209 | return this.getDescription().getVersion();
210 | }
211 |
212 | public static void info(String msg) {
213 | log.log(Level.INFO, msg);
214 | }
215 |
216 | public static void severe(String msg) {
217 | log.log(Level.SEVERE, msg);
218 | }
219 |
220 | public DynmapAPI getDynmapAPI() {
221 | return dynmapAPI;
222 | }
223 |
224 | public MarkerSet getMarkerSet() {
225 | return markerSet;
226 | }
227 |
228 | public Map getAreaMarkers() {
229 | return areaMarkers;
230 | }
231 |
232 | public Map getMarkers() {
233 | return markers;
234 | }
235 |
236 | private class TownyUpdate implements Runnable {
237 | public void run() {
238 | if (TownyUniverse.getInstance().getDataSource() != null) {
239 | scheduler.runAsync(townUpdater);
240 |
241 | if (Settings.getPlayerVisibilityByTown())
242 | TownyAPI.getInstance().getTowns().forEach(t -> updateTown(t));
243 |
244 | if (Settings.getPlayerVisibilityByNation())
245 | TownyAPI.getInstance().getNations().forEach(n -> updateNation(n));
246 | }
247 | }
248 | }
249 |
250 | private void updateTown(Town town) {
251 | Set plids = town.getResidents().stream().map(r -> r.getName()).collect(Collectors.toSet());
252 | String setid = "towny.town." + town.getName();
253 | PlayerSet set = markerAPI.getPlayerSet(setid); /* See if set exists */
254 | if (set == null) {
255 | set = markerAPI.createPlayerSet(setid, true, plids, false);
256 | info("Added player visibility set '" + setid + "' for town " + town.getName());
257 | return;
258 | }
259 | set.setPlayers(plids);
260 | }
261 |
262 | private void updateNation(Nation nat) {
263 | Set plids = nat.getResidents().stream().map(r -> r.getName()).collect(Collectors.toSet());
264 | String setid = "towny.nation." + nat.getName();
265 | PlayerSet set = markerAPI.getPlayerSet(setid); /* See if set exists */
266 | if (set == null) {
267 | set = markerAPI.createPlayerSet(setid, true, plids, false);
268 | info("Added player visibility set '" + setid + "' for nation " + nat.getName());
269 | return;
270 | }
271 | set.setPlayers(plids);
272 | }
273 | }
274 |
--------------------------------------------------------------------------------
/src/main/java/org/dynmap/towny/mapupdate/AreaStyle.java:
--------------------------------------------------------------------------------
1 | package org.dynmap.towny.mapupdate;
2 |
3 | import org.bukkit.configuration.file.FileConfiguration;
4 | import org.dynmap.markers.MarkerAPI;
5 | import org.dynmap.markers.MarkerIcon;
6 | import org.dynmap.towny.DynmapTownyPlugin;
7 | import org.dynmap.towny.settings.Settings;
8 |
9 | import com.palmergames.bukkit.towny.object.TownBlockType;
10 |
11 | public class AreaStyle {
12 | int strokecolor;
13 | double strokeopacity;
14 | int strokeweight;
15 | int fillcolor;
16 | double fillopacity;
17 | int fillcolor_shops;
18 | int fillcolor_embassies;
19 | int fillcolor_arenas;
20 | int fillcolor_wilds;
21 | MarkerIcon homeicon;
22 | MarkerIcon capitalicon;
23 | MarkerIcon ruinicon;
24 | MarkerIcon outposticon;
25 | int yc;
26 | boolean boost;
27 |
28 | /**
29 | * Used to create AreaStyles based off of what is in the config used on all
30 | * non-custom and non-nation styles.
31 | */
32 | public AreaStyle() {
33 | String sc = Settings.getStrokeColour();
34 | strokeopacity = Settings.getStrokeOpacity();
35 | strokeweight = Settings.getStrokeWeight();
36 | String fc = Settings.getFillColour();
37 | String fcs = Settings.getShopsFillColour();
38 | String fca = Settings.getArenaFillColour();
39 | String fce = Settings.getEmbassyFillColour();
40 | String fcw = Settings.getWildsFillColour();
41 | yc = 64;
42 | boost = Settings.getBoost();
43 |
44 | strokecolor = -1;
45 | fillcolor = -1;
46 | fillcolor_shops = -1;
47 | fillcolor_arenas = -1;
48 | fillcolor_embassies = -1;
49 | fillcolor_wilds = -1;
50 | try {
51 | if (sc != null)
52 | strokecolor = Integer.parseInt(sc.substring(1), 16);
53 | if (fc != null)
54 | fillcolor = Integer.parseInt(fc.substring(1), 16);
55 | if (fcs != null)
56 | fillcolor_shops = Integer.parseInt(fcs.substring(1), 16);
57 | if (fca != null)
58 | fillcolor_arenas = Integer.parseInt(fca.substring(1), 16);
59 | if (fce != null)
60 | fillcolor_embassies = Integer.parseInt(fce.substring(1), 16);
61 | if (fcw != null)
62 | fillcolor_wilds = Integer.parseInt(fcw.substring(1), 16);
63 | } catch (NumberFormatException nfx) {
64 | }
65 |
66 | fillopacity = Settings.getFillOpacity();
67 | homeicon = Settings.getHomeIcon();
68 | capitalicon = Settings.getCapitalIcon();
69 | outposticon = Settings.getOutpostIcon();
70 | ruinicon = Settings.getRuinIcon();
71 | }
72 |
73 | /**
74 | * Used to contain non-default style AreaStyles, used for CustomeStyles and
75 | * NationStyles configured in the config.
76 | *
77 | * @param path The path of the config containing nationstyle + id or
78 | * custstyle + id.
79 | * @param markerapi Instance of the MarkerAPI we are using.
80 | */
81 | public AreaStyle(String path, MarkerAPI markerapi) {
82 | FileConfiguration cfg = DynmapTownyPlugin.getPlugin().getConfig();
83 | String sc = cfg.getString(path + ".strokecolor", null);
84 | strokeopacity = cfg.getDouble(path + ".strokeopacity", -1);
85 | strokeweight = cfg.getInt(path + ".strokeweight", -1);
86 | String fc = cfg.getString(path + ".fillcolor", null);
87 | String fcs = cfg.getString(path + ".fillcolorshops", null);
88 | String fca = cfg.getString(path + ".fillcolorarenas", null);
89 | String fce = cfg.getString(path + ".fillcolorembassies", null);
90 | String fcw = cfg.getString(path + ".fillColorwilds", null);
91 | yc = cfg.getInt(path + ".y", -1);
92 | boost = cfg.getBoolean(path + ".boost", false);
93 |
94 | strokecolor = -1;
95 | fillcolor = -1;
96 | fillcolor_shops = -1;
97 | fillcolor_arenas = -1;
98 | fillcolor_embassies = -1;
99 | fillcolor_wilds = -1;
100 | try {
101 | if (sc != null)
102 | strokecolor = Integer.parseInt(sc.substring(1), 16);
103 | if (fc != null)
104 | fillcolor = Integer.parseInt(fc.substring(1), 16);
105 | if (fcs != null)
106 | fillcolor_shops = Integer.parseInt(fcs.substring(1), 16);
107 | if (fca != null)
108 | fillcolor_arenas = Integer.parseInt(fca.substring(1), 16);
109 | if (fce != null)
110 | fillcolor_embassies = Integer.parseInt(fce.substring(1), 16);
111 | if (fcw != null)
112 | fillcolor_wilds = Integer.parseInt(fcw.substring(1), 16);
113 | } catch (NumberFormatException nfx) {
114 | }
115 |
116 | fillopacity = cfg.getDouble(path + ".fillopacity", -1);
117 | String homemarker = cfg.getString(path + ".homeicon", null);
118 | if (homemarker != null) {
119 | homeicon = markerapi.getMarkerIcon(homemarker);
120 | if (homeicon == null) {
121 | homeicon = markerapi.getMarkerIcon("blueicon");
122 | }
123 | }
124 | String capitalmarker = cfg.getString(path + ".capitalicon", null);
125 | if (capitalmarker != null) {
126 | capitalicon = markerapi.getMarkerIcon(capitalmarker);
127 | if (capitalicon == null) {
128 | capitalicon = markerapi.getMarkerIcon("king");
129 | }
130 | }
131 | ruinicon = markerapi.getMarkerIcon("warning");
132 |
133 | String outpostmarker = cfg.getString(path + ".outposticon", null);
134 | if (outpostmarker != null) {
135 | outposticon = markerapi.getMarkerIcon(outpostmarker);
136 | if (outposticon == null)
137 | outposticon = markerapi.getMarkerIcon("tower");
138 | }
139 | }
140 |
141 | public int getStrokeColor(AreaStyle cust, AreaStyle nat) {
142 | if ((cust != null) && (cust.strokecolor >= 0))
143 | return cust.strokecolor;
144 | else if ((nat != null) && (nat.strokecolor >= 0))
145 | return nat.strokecolor;
146 | else if (strokecolor >= 0)
147 | return strokecolor;
148 | else
149 | return 0xFF0000;
150 | }
151 |
152 | public double getStrokeOpacity(AreaStyle cust, AreaStyle nat) {
153 | if ((cust != null) && (cust.strokeopacity >= 0))
154 | return cust.strokeopacity;
155 | else if ((nat != null) && (nat.strokeopacity >= 0))
156 | return nat.strokeopacity;
157 | else if (strokeopacity >= 0)
158 | return strokeopacity;
159 | else
160 | return 0.8;
161 | }
162 |
163 | public int getStrokeWeight(AreaStyle cust, AreaStyle nat) {
164 | if ((cust != null) && (cust.strokeweight >= 0))
165 | return cust.strokeweight;
166 | else if ((nat != null) && (nat.strokeweight >= 0))
167 | return nat.strokeweight;
168 | else if (strokeweight >= 0)
169 | return strokeweight;
170 | else
171 | return 3;
172 | }
173 |
174 | public int getFillColor(TownBlockType btype) {
175 | if (btype == TownBlockType.COMMERCIAL)
176 | return fillcolor_shops;
177 | if (btype == TownBlockType.ARENA)
178 | return fillcolor_arenas;
179 | if (btype == TownBlockType.EMBASSY)
180 | return fillcolor_embassies;
181 | if (btype == TownBlockType.WILDS)
182 | return fillcolor_wilds;
183 | return -1;
184 | }
185 |
186 | public int getFillColor(AreaStyle cust, AreaStyle nat, TownBlockType btype) {
187 | if (btype == TownBlockType.COMMERCIAL) {
188 | if ((cust != null) && (cust.fillcolor_shops >= 0))
189 | return cust.fillcolor_shops;
190 | else if ((nat != null) && (nat.fillcolor_shops >= 0))
191 | return nat.fillcolor_shops;
192 | else if (fillcolor_shops >= 0)
193 | return fillcolor_shops;
194 | else
195 | return 0xFF0000;
196 | } else if (btype == TownBlockType.ARENA) {
197 | if ((cust != null) && (cust.fillcolor_arenas >= 0))
198 | return cust.fillcolor_shops;
199 | else if ((nat != null) && (nat.fillcolor_arenas >= 0))
200 | return nat.fillcolor_arenas;
201 | else if (fillcolor_arenas >= 0)
202 | return fillcolor_arenas;
203 | else
204 | return 0xFF0000;
205 | } else if (btype == TownBlockType.EMBASSY) {
206 | if ((cust != null) && (cust.fillcolor_embassies >= 0))
207 | return cust.fillcolor_embassies;
208 | else if ((nat != null) && (nat.fillcolor_embassies >= 0))
209 | return nat.fillcolor_embassies;
210 | else if (fillcolor_embassies >= 0)
211 | return fillcolor_embassies;
212 | else
213 | return 0xFF0000;
214 | } else if (btype == TownBlockType.WILDS) {
215 | if ((cust != null) && (cust.fillcolor_wilds >= 0))
216 | return cust.fillcolor_wilds;
217 | else if ((nat != null) && (nat.fillcolor_wilds >= 0))
218 | return nat.fillcolor_wilds;
219 | else if (fillcolor_wilds >= 0)
220 | return fillcolor_wilds;
221 | else
222 | return 0xFF0000;
223 | }
224 | if ((cust != null) && (cust.fillcolor >= 0))
225 | return cust.fillcolor;
226 | else if ((nat != null) && (nat.fillcolor >= 0))
227 | return nat.fillcolor;
228 | else if (fillcolor >= 0)
229 | return fillcolor;
230 | else
231 | return 0xFF0000;
232 | }
233 |
234 | public double getFillOpacity(AreaStyle cust, AreaStyle nat) {
235 | if ((cust != null) && (cust.fillopacity >= 0))
236 | return cust.fillopacity;
237 | else if ((nat != null) && (nat.fillopacity >= 0))
238 | return nat.fillopacity;
239 | else if (fillopacity >= 0)
240 | return fillopacity;
241 | else
242 | return 0.35;
243 | }
244 |
245 | public MarkerIcon getHomeMarker(AreaStyle cust, AreaStyle nat) {
246 | if ((cust != null) && (cust.homeicon != null))
247 | return cust.homeicon;
248 | else if ((nat != null) && (nat.homeicon != null))
249 | return nat.homeicon;
250 | else
251 | return homeicon;
252 | }
253 |
254 | public MarkerIcon getCapitalMarker(AreaStyle cust, AreaStyle nat) {
255 | if ((cust != null) && (cust.capitalicon != null))
256 | return cust.capitalicon;
257 | else if ((nat != null) && (nat.capitalicon != null))
258 | return nat.capitalicon;
259 | else if (capitalicon != null)
260 | return capitalicon;
261 | else
262 | return getHomeMarker(cust, nat);
263 | }
264 |
265 | public MarkerIcon getOutpostMarker(AreaStyle cust, AreaStyle nat) {
266 | if ((cust != null) && (cust.outposticon != null))
267 | return cust.outposticon;
268 | else if ((nat != null) && (nat.outposticon != null))
269 | return nat.outposticon;
270 | else if (outposticon != null)
271 | return outposticon;
272 | else
273 | return Settings.getOutpostIcon();
274 | }
275 |
276 | public MarkerIcon getRuinIcon() {
277 | return ruinicon;
278 | }
279 |
280 | public int getY(AreaStyle cust, AreaStyle nat) {
281 | if ((cust != null) && (cust.yc >= 0))
282 | return cust.yc;
283 | else if ((nat != null) && (nat.yc >= 0))
284 | return nat.yc;
285 | else if (yc >= 0)
286 | return yc;
287 | else
288 | return 64;
289 | }
290 |
291 | public boolean getBoost(AreaStyle cust, AreaStyle nat) {
292 | if ((cust != null) && cust.boost)
293 | return cust.boost;
294 | else if ((nat != null) && nat.boost)
295 | return nat.boost;
296 | else
297 | return boost;
298 | }
299 | }
300 |
--------------------------------------------------------------------------------
/src/main/java/org/dynmap/towny/settings/Settings.java:
--------------------------------------------------------------------------------
1 | package org.dynmap.towny.settings;
2 |
3 | import java.nio.file.Path;
4 | import java.util.ArrayList;
5 | import java.util.HashSet;
6 | import java.util.List;
7 | import java.util.Locale;
8 | import java.util.Set;
9 |
10 | import org.bukkit.configuration.ConfigurationSection;
11 | import org.dynmap.markers.MarkerIcon;
12 | import org.dynmap.towny.DynmapTownyPlugin;
13 |
14 | import com.palmergames.bukkit.config.CommentedConfiguration;
15 | import com.palmergames.bukkit.towny.exceptions.initialization.TownyInitException;
16 | import com.palmergames.util.FileMgmt;
17 |
18 | public class Settings {
19 | private static final String NATIONSTYLE_ROOT = "nationstyle";
20 | private static final String CUSTSTYLE_ROOT = "custstyle";
21 | private static CommentedConfiguration config, newConfig;
22 | private static Path configPath = DynmapTownyPlugin.getPlugin().getDataFolder().toPath().resolve("config.yml");
23 | private static boolean usingTownyChat;
24 | private static MarkerIcon outpostIcon = null;
25 | private static MarkerIcon homeIcon = null;
26 | private static MarkerIcon capitalIcon = null;
27 | private static MarkerIcon ruinIcon = null;
28 | private static boolean visByTownSet;
29 | private static boolean visByNationSet;
30 | private static boolean visByNation;
31 | private static boolean visByTown;
32 | private static Set visibleRegions = null;
33 | private static Set hiddenRegions = null;
34 |
35 | public static void loadConfig() {
36 | if (FileMgmt.checkOrCreateFile(configPath.toString())) {
37 |
38 | // read the config.yml into memory
39 | config = new CommentedConfiguration(configPath);
40 | if (!config.load())
41 | throw new TownyInitException("Failed to load config.yml.", TownyInitException.TownyError.MAIN_CONFIG);
42 |
43 | setDefaults(DynmapTownyPlugin.getPlugin().getVersion(), configPath);
44 | config.save();
45 | }
46 | }
47 |
48 | public static void addComment(String root, String... comments) {
49 |
50 | newConfig.addComment(root.toLowerCase(), comments);
51 | }
52 |
53 | private static void setNewProperty(String root, Object value) {
54 |
55 | if (value == null) {
56 | value = "";
57 | }
58 | newConfig.set(root.toLowerCase(), value.toString());
59 | }
60 |
61 | @SuppressWarnings("unused")
62 | private static void setProperty(String root, Object value) {
63 |
64 | config.set(root.toLowerCase(), value.toString());
65 | }
66 |
67 | /**
68 | * Builds a new config reading old config data.
69 | */
70 | private static void setDefaults(String version, Path configPath) {
71 |
72 | newConfig = new CommentedConfiguration(configPath);
73 | newConfig.load();
74 |
75 | for (ConfigNodes root : ConfigNodes.values()) {
76 | if (root.getComments().length > 0)
77 | addComment(root.getRoot(), root.getComments());
78 | if (root.getRoot() == ConfigNodes.VERSION.getRoot())
79 | setNewProperty(root.getRoot(), version);
80 | else
81 | setNewProperty(root.getRoot(), (config.get(root.getRoot().toLowerCase()) != null) ? config.get(root.getRoot().toLowerCase()) : root.getDefault());
82 | }
83 |
84 | trySetDefaultCustomAndNationStyles();
85 | config = newConfig;
86 | newConfig = null;
87 | }
88 |
89 | private static void trySetDefaultCustomAndNationStyles() {
90 | if(config.contains(CUSTSTYLE_ROOT)) // Custstyle already exists.
91 | newConfig.set(CUSTSTYLE_ROOT, config.get(CUSTSTYLE_ROOT));
92 | else { // Make a new custstyle.
93 | DynmapTownyPlugin.getPlugin().getLogger().info("Config: Creating default custom styles.");
94 |
95 | newConfig.createSection(CUSTSTYLE_ROOT);
96 | ConfigurationSection configurationSection = newConfig.getConfigurationSection(CUSTSTYLE_ROOT);
97 | configurationSection.set(".customregion1.strokecolor", "#00FF00");
98 | configurationSection.set(".customregion1.y", "64");
99 | configurationSection.set(".customregion2.strokecolor", "#007F00");
100 | configurationSection.set(".customregion2.y", "64");
101 | configurationSection.set(".customregion2.boost", "false");
102 | }
103 |
104 | if(config.contains(NATIONSTYLE_ROOT)) // Custstyle already exists.
105 | newConfig.set(NATIONSTYLE_ROOT, config.get(NATIONSTYLE_ROOT));
106 | else { // Make a new nationstyle.
107 | DynmapTownyPlugin.getPlugin().getLogger().info("Config: Creating default nation styles.");
108 |
109 | newConfig.createSection(NATIONSTYLE_ROOT);
110 | ConfigurationSection configurationSection = newConfig.getConfigurationSection(NATIONSTYLE_ROOT);
111 | configurationSection.set(".NationOfBlue.strokecolor", "#0000FF");
112 | configurationSection.set(".NationOfBlue.fillcolor", "#0000FF");
113 | configurationSection.set(".NationOfBlue.boost", "false");
114 | configurationSection.set("._none_.homeicon", "greenflag");
115 | }
116 | }
117 |
118 | public static String getString(String root, String def) {
119 |
120 | String data = config.getString(root.toLowerCase(), def);
121 | if (data == null) {
122 | sendError(root.toLowerCase() + " from config.yml");
123 | return "";
124 | }
125 | return data;
126 | }
127 |
128 | private static void sendError(String msg) {
129 |
130 | DynmapTownyPlugin.severe("Error could not read " + msg);
131 | }
132 |
133 | public static boolean getBoolean(ConfigNodes node) {
134 |
135 | return Boolean.parseBoolean(config.getString(node.getRoot().toLowerCase(), node.getDefault()));
136 | }
137 |
138 | public static double getDouble(ConfigNodes node) {
139 |
140 | try {
141 | return Double.parseDouble(config.getString(node.getRoot().toLowerCase(), node.getDefault()).trim());
142 | } catch (NumberFormatException e) {
143 | sendError(node.getRoot().toLowerCase() + " from config.yml");
144 | return 0.0;
145 | }
146 | }
147 |
148 | public static int getInt(ConfigNodes node) {
149 |
150 | try {
151 | return Integer.parseInt(config.getString(node.getRoot().toLowerCase(), node.getDefault()).trim());
152 | } catch (NumberFormatException e) {
153 | sendError(node.getRoot().toLowerCase() + " from config.yml");
154 | return 0;
155 | }
156 | }
157 |
158 | public static String getString(ConfigNodes node) {
159 |
160 | return config.getString(node.getRoot().toLowerCase(), node.getDefault());
161 | }
162 |
163 | public static List getStrArr(ConfigNodes node) {
164 |
165 | String[] strArray = getString(node.getRoot().toLowerCase(Locale.ROOT), node.getDefault()).split(",");
166 | List list = new ArrayList<>();
167 |
168 | for (String string : strArray)
169 | if (string != null && !string.isEmpty())
170 | list.add(string.trim());
171 |
172 | return list;
173 | }
174 |
175 | public static void setUsingTownyChat(boolean value) {
176 | usingTownyChat = value;
177 | }
178 |
179 | public static boolean usingTownyChat() {
180 | return usingTownyChat;
181 | }
182 |
183 | public static boolean sendLoginMessage() {
184 | return getBoolean(ConfigNodes.CHAT_SEND_LOGIN);
185 | }
186 |
187 | public static boolean sendQuitMessage() {
188 | return getBoolean(ConfigNodes.CHAT_SEND_QUIT);
189 | }
190 |
191 | public static String getChatFormat() {
192 | return getString(ConfigNodes.CHAT_FORMAT);
193 | }
194 |
195 | public static String getTownInfoWindow() {
196 | return getString(ConfigNodes.INFOWINDOW_TOWN_POPUP);
197 | }
198 |
199 | public static String noNationSlug() {
200 | return getString(ConfigNodes.INFOWINDOW_NO_NATION_SLUG);
201 | }
202 |
203 | public static MarkerIcon getOutpostIcon() {
204 | if (outpostIcon == null)
205 | outpostIcon = DynmapTownyPlugin.getPlugin().getDynmapAPI().getMarkerAPI().getMarkerIcon(getString(ConfigNodes.REGIONSTYLE_OUTPOST_ICON));
206 | return outpostIcon;
207 | }
208 |
209 | public static MarkerIcon getHomeIcon() {
210 | if (homeIcon == null)
211 | homeIcon = DynmapTownyPlugin.getPlugin().getDynmapAPI().getMarkerAPI().getMarkerIcon(getString(ConfigNodes.REGIONSTYLE_HOME_ICON));
212 | return homeIcon;
213 | }
214 |
215 | public static MarkerIcon getCapitalIcon() {
216 | if (capitalIcon == null)
217 | capitalIcon = DynmapTownyPlugin.getPlugin().getDynmapAPI().getMarkerAPI().getMarkerIcon(getString(ConfigNodes.REGIONSTYLE_CAPITAL_ICON));
218 | return capitalIcon;
219 | }
220 |
221 | public static MarkerIcon getRuinIcon() {
222 | if (ruinIcon == null)
223 | ruinIcon = DynmapTownyPlugin.getPlugin().getDynmapAPI().getMarkerAPI().getMarkerIcon(getString(ConfigNodes.REGIONSTYLE_RUIN_ICON));
224 | return ruinIcon;
225 | }
226 |
227 | public static String getStrokeColour() {
228 | return getString(ConfigNodes.REGIONSTYLE_STROKE_COLOUR);
229 | }
230 |
231 | public static double getStrokeOpacity() {
232 | return getDouble(ConfigNodes.REGIONSTYLE_STROKE_OPACITY);
233 | }
234 |
235 | public static int getStrokeWeight() {
236 | return getInt(ConfigNodes.REGIONSTYLE_STROKE_WEIGHT);
237 | }
238 |
239 | public static String getFillColour() {
240 | return getString(ConfigNodes.REGIONSTYLE_FILL_COLOUR);
241 | }
242 |
243 | public static String getShopsFillColour() {
244 | return getString(ConfigNodes.TOWNBLOCK_SHOP_FILL_COLOUR);
245 | }
246 |
247 | public static String getArenaFillColour() {
248 | return getString(ConfigNodes.TOWNBLOCK_SHOP_FILL_COLOUR);
249 | }
250 |
251 | public static String getEmbassyFillColour() {
252 | return getString(ConfigNodes.TOWNBLOCK_SHOP_FILL_COLOUR);
253 | }
254 |
255 | public static String getWildsFillColour() {
256 | return getString(ConfigNodes.TOWNBLOCK_SHOP_FILL_COLOUR);
257 | }
258 |
259 | public static double getFillOpacity() {
260 | return getDouble(ConfigNodes.REGIONSTYLE_FILL_OPACITY);
261 | }
262 |
263 |
264 | public static boolean getBoost() {
265 | return getBoolean(ConfigNodes.REGIONSTYLE_BOOST);
266 | }
267 |
268 | public static String getLayerName() {
269 | return getString(ConfigNodes.LAYER_NAME);
270 | }
271 |
272 | public static int getMinZoom() {
273 | return getInt(ConfigNodes.LAYER_MIN_ZOOM);
274 | }
275 |
276 | public static int getLayerPriority() {
277 | return getInt(ConfigNodes.LAYER_PRIORITY);
278 | }
279 |
280 | public static boolean getLayerHiddenByDefault() {
281 | return getBoolean(ConfigNodes.LAYER_HIDE_BY_DEFAULT);
282 | }
283 |
284 | public static boolean getPlayerVisibilityByTown() {
285 | if (visByTownSet)
286 | return visByTown;
287 |
288 | visByTownSet = true;
289 | if (getBoolean(ConfigNodes.VISIBILITY_BY_TOWN)) {
290 | try {
291 | if (!DynmapTownyPlugin.getPlugin().getDynmapAPI().testIfPlayerInfoProtected()) {
292 | visByTown = false;
293 | DynmapTownyPlugin.getPlugin().getLogger().info("Dynmap does not have player-info-protected enabled - visibility-by-nation will have no effect");
294 | return visByTown;
295 | }
296 | } catch (NoSuchMethodError x) {
297 | visByTown = false;
298 | DynmapTownyPlugin.getPlugin().getLogger().info("Dynmap does not support function needed for 'visibility-by-nation' - need to upgrade to 0.60 or later");
299 | return visByTown;
300 | }
301 | visByTown = true;
302 | }
303 | return visByTown;
304 | }
305 |
306 | public static boolean getPlayerVisibilityByNation() {
307 | if (visByNationSet)
308 | return visByNation;
309 |
310 | visByNationSet = true;
311 | if (getBoolean(ConfigNodes.VISIBILITY_BY_NATION)) {
312 | try {
313 | if (!DynmapTownyPlugin.getPlugin().getDynmapAPI().testIfPlayerInfoProtected()) {
314 | visByNation = false;
315 | DynmapTownyPlugin.getPlugin().getLogger().info("Dynmap does not have player-info-protected enabled - visibility-by-nation will have no effect");
316 | return visByNation;
317 | }
318 | } catch (NoSuchMethodError x) {
319 | visByNation = false;
320 | DynmapTownyPlugin.getPlugin().getLogger().info("Dynmap does not support function needed for 'visibility-by-nation' - need to upgrade to 0.60 or later");
321 | return visByNation;
322 | }
323 | visByNation = true;
324 | }
325 | return visByNation;
326 | }
327 |
328 | public static boolean usingDynamicNationColours() {
329 | return getBoolean(ConfigNodes.DYNAMIC_COLOURS_NATION);
330 | }
331 |
332 | public static boolean usingDynamicTownColours() {
333 | return getBoolean(ConfigNodes.DYNAMIC_COLOURS_TOWN);
334 | }
335 |
336 | public static int getUpdatePeriod() {
337 | return getInt(ConfigNodes.UPDATE_PERIOD);
338 | }
339 |
340 | public static boolean showingShops() {
341 | return getBoolean(ConfigNodes.TOWNBLOCK_SHOW_SHOPS);
342 | }
343 |
344 | public static boolean showingArenas() {
345 | return getBoolean(ConfigNodes.TOWNBLOCK_SHOW_ARENAS);
346 | }
347 |
348 | public static boolean showingEmbassies() {
349 | return getBoolean(ConfigNodes.TOWNBLOCK_SHOW_EMBASSIES);
350 | }
351 |
352 | public static boolean showingWilds() {
353 | return getBoolean(ConfigNodes.TOWNBLOCK_SHOW_WILDSPLOTS);
354 | }
355 |
356 | public static Set getVisibleRegions() {
357 | if (visibleRegions == null)
358 | visibleRegions = new HashSet<>(getStrArr(ConfigNodes.VISIBLE_ROOT));
359 | return visibleRegions;
360 | }
361 |
362 | public static boolean visibleRegionsAreSet() {
363 | Set visibleRegions = getVisibleRegions();
364 | // Pre-CommentedConfiguration configs will have their region set to [], which throws off the results.
365 | return visibleRegions.size() > 0 && !(visibleRegions.size() == 1 && visibleRegions.contains("[]"));
366 | }
367 |
368 | public static Set getHiddenRegions() {
369 | if (hiddenRegions == null)
370 | hiddenRegions = new HashSet<>(getStrArr(ConfigNodes.HIDDEN_ROOT));
371 | return hiddenRegions;
372 | }
373 |
374 | public static boolean hiddenRegionsAreSet() {
375 | Set hiddenRegions = getHiddenRegions();
376 | // Pre-CommentedConfiguration configs will have their region set to [], which throws off the results.
377 | return hiddenRegions.size() > 0 && !(hiddenRegions.size() == 1 && hiddenRegions.contains("[]"));
378 | }
379 | }
380 |
--------------------------------------------------------------------------------
/src/main/java/org/dynmap/towny/mapupdate/UpdateTowns.java:
--------------------------------------------------------------------------------
1 | package org.dynmap.towny.mapupdate;
2 |
3 | import java.util.ArrayDeque;
4 | import java.util.ArrayList;
5 | import java.util.Collection;
6 | import java.util.HashMap;
7 | import java.util.LinkedList;
8 | import java.util.Map;
9 | import java.util.stream.Collectors;
10 |
11 | import org.bukkit.Bukkit;
12 | import org.bukkit.Location;
13 | import org.dynmap.markers.AreaMarker;
14 | import org.dynmap.markers.Marker;
15 | import org.dynmap.markers.MarkerIcon;
16 | import org.dynmap.markers.MarkerSet;
17 | import org.dynmap.towny.DynmapTownyPlugin;
18 | import org.dynmap.towny.events.BuildTownMarkerDescriptionEvent;
19 | import org.dynmap.towny.events.TownRenderEvent;
20 | import org.dynmap.towny.events.TownSetMarkerIconEvent;
21 | import org.dynmap.towny.settings.Settings;
22 |
23 | import com.palmergames.bukkit.towny.TownyAPI;
24 | import com.palmergames.bukkit.towny.TownySettings;
25 | import com.palmergames.bukkit.towny.object.Town;
26 | import com.palmergames.bukkit.towny.object.TownBlock;
27 | import com.palmergames.bukkit.towny.object.TownBlockType;
28 | import com.palmergames.bukkit.towny.object.TownBlockTypeCache.CacheType;
29 | import com.palmergames.bukkit.towny.object.TownyWorld;
30 | import com.palmergames.bukkit.towny.object.Translation;
31 |
32 | public class UpdateTowns implements Runnable {
33 |
34 | private final int TOWNBLOCKSIZE = TownySettings.getTownBlockSize();
35 | private final DynmapTownyPlugin plugin = DynmapTownyPlugin.getPlugin();
36 | private final MarkerSet set = plugin.getMarkerSet();
37 | private Map existingAreaMarkers = plugin.getAreaMarkers();
38 | private Map existingMarkers = plugin.getMarkers();
39 |
40 | private final AreaStyle defstyle = AreaStyleHolder.getDefaultStyle();
41 | private final Map cusstyle = AreaStyleHolder.getCustomStyles();
42 | private final Map nationstyle = AreaStyleHolder.getNationStyles();
43 |
44 | enum direction {XPLUS, ZPLUS, XMINUS, ZMINUS};
45 |
46 | @Override
47 | public void run() {
48 | Map newmap = new HashMap(); /* Build new map */
49 | Map newmark = new HashMap(); /* Build new map */
50 |
51 | /* Loop through towns */
52 | for (Town t : TownyAPI.getInstance().getTowns()) {
53 | try {
54 | handleTown(t, newmap, newmark, null);
55 | if (Settings.showingShops() && townHasTBsOfType(t, TownBlockType.COMMERCIAL)) {
56 | handleTown(t, newmap, newmark, TownBlockType.COMMERCIAL);
57 | }
58 | if (Settings.showingArenas() && townHasTBsOfType(t, TownBlockType.ARENA)) {
59 | handleTown(t, newmap, newmark, TownBlockType.ARENA);
60 | }
61 | if (Settings.showingEmbassies() && townHasTBsOfType(t, TownBlockType.EMBASSY)) {
62 | handleTown(t, newmap, newmark, TownBlockType.EMBASSY);
63 | }
64 | if (Settings.showingWilds() && townHasTBsOfType(t, TownBlockType.WILDS)) {
65 | handleTown(t, newmap, newmark, TownBlockType.WILDS);
66 | }
67 | } catch (Exception e) {
68 | plugin.getLogger().info(e.getMessage());
69 | }
70 | }
71 | /* Now, review old maps - anything left is removed */
72 | existingAreaMarkers.values().forEach(a -> a.deleteMarker());
73 | existingMarkers.values().forEach(m -> m.deleteMarker());
74 |
75 | /* And replace with new map */
76 | existingAreaMarkers = newmap;
77 | existingMarkers = newmark;
78 | }
79 |
80 | private boolean townHasTBsOfType(Town t, TownBlockType tbType) {
81 | return t.getTownBlockTypeCache().getNumTownBlocks(tbType, CacheType.ALL) > 0;
82 | }
83 |
84 | /* Handle specific town */
85 | private void handleTown(Town town, Map newWorldNameAreaMarkerMap, Map newWorldNameMarkerMap, TownBlockType btype) throws Exception {
86 | String townName = town.getName();
87 | int poly_index = 0; /* Index of polygon for when a town has multiple shapes. */
88 |
89 | /* Get the Town's Townblocks or the Towns' Townblocks of one TownBlockType. */
90 | Collection townBlocks = filterTownBlocks(town, btype);
91 | if (townBlocks.isEmpty())
92 | return;
93 |
94 | /* Build popup */
95 | BuildTownMarkerDescriptionEvent event = new BuildTownMarkerDescriptionEvent(town);
96 | Bukkit.getPluginManager().callEvent(event);
97 | String infoWindowPopup = event.getDescription();
98 |
99 | HashMap worldNameShapeMap = new HashMap();
100 | LinkedList townBlocksToDraw = new LinkedList();
101 | TownyWorld currentWorld = null;
102 | TileFlags currentShape = null;
103 | boolean vis = false;
104 | /* Loop through blocks: set flags on blockmaps for worlds */
105 | for(TownBlock townBlock : townBlocks) {
106 | if(townBlock.getWorld() != currentWorld) { /* Not same world */
107 | String worldName = townBlock.getWorld().getName();
108 | vis = isVisible(townName, worldName); /* See if visible */
109 | if(vis) { /* Only accumulate for visible areas */
110 | currentShape = worldNameShapeMap.get(worldName); /* Find existing */
111 | if(currentShape == null) {
112 | currentShape = new TileFlags();
113 | worldNameShapeMap.put(worldName, currentShape); /* Add fresh one */
114 | }
115 | }
116 | currentWorld = townBlock.getWorld();
117 | }
118 | if(vis) {
119 | currentShape.setFlag(townBlock.getX(), townBlock.getZ(), true); /* Set flag for block */
120 | townBlocksToDraw.addLast(townBlock);
121 | }
122 | }
123 | /* Loop through until we don't find more areas */
124 | while(townBlocksToDraw != null) {
125 | LinkedList ourTownBlocks = null;
126 | LinkedList townBlockLeftToDraw = null;
127 | TileFlags ourShape = null;
128 | int minx = Integer.MAX_VALUE;
129 | int minz = Integer.MAX_VALUE;
130 | for(TownBlock tb : townBlocksToDraw) {
131 | int tbX = tb.getX();
132 | int tbZ = tb.getZ();
133 | if(ourShape == null) { /* If not started, switch to world for this block first */
134 | if(tb.getWorld() != currentWorld) {
135 | currentWorld = tb.getWorld();
136 | currentShape = worldNameShapeMap.get(currentWorld.getName());
137 | }
138 | }
139 | /* If we need to start shape, and this block is not part of one yet */
140 | if((ourShape == null) && currentShape.getFlag(tbX, tbZ)) {
141 | ourShape = new TileFlags(); /* Create map for shape */
142 | ourTownBlocks = new LinkedList();
143 | floodFillTarget(currentShape, ourShape, tbX, tbZ); /* Copy shape */
144 | ourTownBlocks.add(tb); /* Add it to our node list */
145 | minx = tbX; minz = tbZ;
146 | }
147 | /* If shape found, and we're in it, add to our node list */
148 | else if((ourShape != null) && (tb.getWorld() == currentWorld) &&
149 | (ourShape.getFlag(tbX, tbZ))) {
150 | ourTownBlocks.add(tb);
151 | if(tbX < minx) {
152 | minx = tbX; minz = tbZ;
153 | }
154 | else if((tbX == minx) && (tbZ < minz)) {
155 | minz = tbZ;
156 | }
157 | }
158 | else { /* Else, keep it in the list for the next polygon */
159 | if(townBlockLeftToDraw == null)
160 | townBlockLeftToDraw = new LinkedList();
161 | townBlockLeftToDraw.add(tb);
162 | }
163 | }
164 | townBlocksToDraw = townBlockLeftToDraw; /* Replace list (null if no more to process) */
165 | if(ourShape != null) {
166 | poly_index = traceTownOutline(town, newWorldNameAreaMarkerMap, btype, poly_index, infoWindowPopup, currentWorld.getName(), ourShape, minx, minz);
167 | }
168 | }
169 |
170 | /* We're showing only specific TownBlockTypes on this pass, dont render townspawns and outposts.*/
171 | if (btype != null)
172 | return;
173 |
174 | drawTownMarkers(town, newWorldNameMarkerMap, townName, infoWindowPopup);
175 | }
176 |
177 | private Collection filterTownBlocks(Town town, TownBlockType btype) {
178 | if (btype == null)
179 | return town.getTownBlocks();
180 | return town.getTownBlocks().stream()
181 | .filter(tb -> tb.getTypeName().equalsIgnoreCase(btype.getName()))
182 | .collect(Collectors.toList());
183 | }
184 |
185 | private int traceTownOutline(Town town, Map newWorldNameMarkerMap, TownBlockType btype, int poly_index,
186 | String infoWindowPopup, String worldName, TileFlags ourShape, int minx, int minz) throws Exception {
187 |
188 | double[] x;
189 | double[] z;
190 | /* Trace outline of blocks - start from minx, minz going to x+ */
191 | int init_x = minx;
192 | int init_z = minz;
193 | int cur_x = minx;
194 | int cur_z = minz;
195 | direction dir = direction.XPLUS;
196 | ArrayList linelist = new ArrayList();
197 | linelist.add(new int[] { init_x, init_z } ); // Add start point
198 | while((cur_x != init_x) || (cur_z != init_z) || (dir != direction.ZMINUS)) {
199 | switch(dir) {
200 | case XPLUS: /* Segment in X+ direction */
201 | if(!ourShape.getFlag(cur_x+1, cur_z)) { /* Right turn? */
202 | linelist.add(new int[] { cur_x+1, cur_z }); /* Finish line */
203 | dir = direction.ZPLUS; /* Change direction */
204 | }
205 | else if(!ourShape.getFlag(cur_x+1, cur_z-1)) { /* Straight? */
206 | cur_x++;
207 | }
208 | else { /* Left turn */
209 | linelist.add(new int[] { cur_x+1, cur_z }); /* Finish line */
210 | dir = direction.ZMINUS;
211 | cur_x++; cur_z--;
212 | }
213 | break;
214 | case ZPLUS: /* Segment in Z+ direction */
215 | if(!ourShape.getFlag(cur_x, cur_z+1)) { /* Right turn? */
216 | linelist.add(new int[] { cur_x+1, cur_z+1 }); /* Finish line */
217 | dir = direction.XMINUS; /* Change direction */
218 | }
219 | else if(!ourShape.getFlag(cur_x+1, cur_z+1)) { /* Straight? */
220 | cur_z++;
221 | }
222 | else { /* Left turn */
223 | linelist.add(new int[] { cur_x+1, cur_z+1 }); /* Finish line */
224 | dir = direction.XPLUS;
225 | cur_x++; cur_z++;
226 | }
227 | break;
228 | case XMINUS: /* Segment in X- direction */
229 | if(!ourShape.getFlag(cur_x-1, cur_z)) { /* Right turn? */
230 | linelist.add(new int[] { cur_x, cur_z+1 }); /* Finish line */
231 | dir = direction.ZMINUS; /* Change direction */
232 | }
233 | else if(!ourShape.getFlag(cur_x-1, cur_z+1)) { /* Straight? */
234 | cur_x--;
235 | }
236 | else { /* Left turn */
237 | linelist.add(new int[] { cur_x, cur_z+1 }); /* Finish line */
238 | dir = direction.ZPLUS;
239 | cur_x--; cur_z++;
240 | }
241 | break;
242 | case ZMINUS: /* Segment in Z- direction */
243 | if(!ourShape.getFlag(cur_x, cur_z-1)) { /* Right turn? */
244 | linelist.add(new int[] { cur_x, cur_z }); /* Finish line */
245 | dir = direction.XPLUS; /* Change direction */
246 | }
247 | else if(!ourShape.getFlag(cur_x-1, cur_z-1)) { /* Straight? */
248 | cur_z--;
249 | }
250 | else { /* Left turn */
251 | linelist.add(new int[] { cur_x, cur_z }); /* Finish line */
252 | dir = direction.XMINUS;
253 | cur_x--; cur_z--;
254 | }
255 | break;
256 | }
257 | }
258 | /* Build information for specific area */
259 | String polyid = town.getName() + "__" + poly_index;
260 | if(btype != null) {
261 | polyid += "_" + btype.getName();
262 | }
263 | int sz = linelist.size();
264 | x = new double[sz];
265 | z = new double[sz];
266 | for(int i = 0; i < sz; i++) {
267 | int[] line = linelist.get(i);
268 | x[i] = (double)line[0] * (double)TOWNBLOCKSIZE;
269 | z[i] = (double)line[1] * (double)TOWNBLOCKSIZE;
270 | }
271 | /* Find existing one */
272 | AreaMarker areaMarker = existingAreaMarkers.remove(polyid); /* Existing area? */
273 | if(areaMarker == null) {
274 | areaMarker = set.createAreaMarker(polyid, town.getName(), false, worldName, x, z, false);
275 | if(areaMarker == null) {
276 | areaMarker = set.findAreaMarker(polyid);
277 | if (areaMarker == null) {
278 | throw new Exception("Error adding area marker " + polyid);
279 | }
280 | }
281 | }
282 | else {
283 | areaMarker.setCornerLocations(x, z); /* Replace corner locations */
284 | areaMarker.setLabel(town.getName()); /* Update label */
285 | }
286 | /* Set popup */
287 | areaMarker.setDescription(infoWindowPopup);
288 | /* Set line and fill properties */
289 | addStyle(town, areaMarker, btype);
290 |
291 | /* Fire an event allowing other plugins to alter the AreaMarker */
292 | TownRenderEvent renderEvent = new TownRenderEvent(town, areaMarker);
293 | Bukkit.getPluginManager().callEvent(renderEvent);
294 | areaMarker = renderEvent.getAreaMarker();
295 |
296 | /* Add to map */
297 | newWorldNameMarkerMap.put(polyid, areaMarker);
298 | poly_index++;
299 | return poly_index;
300 | }
301 |
302 | /**
303 | * Find all contiguous blocks, set in target and clear in source
304 | */
305 | private static int floodFillTarget(TileFlags src, TileFlags dest, int x, int y) {
306 | int cnt = 0;
307 | ArrayDeque stack = new ArrayDeque();
308 | stack.push(new int[] { x, y });
309 |
310 | while (stack.isEmpty() == false) {
311 | int[] nxt = stack.pop();
312 | x = nxt[0];
313 | y = nxt[1];
314 | if (src.getFlag(x, y)) { /* Set in src */
315 | src.setFlag(x, y, false); /* Clear source */
316 | dest.setFlag(x, y, true); /* Set in destination */
317 | cnt++;
318 | if (src.getFlag(x + 1, y))
319 | stack.push(new int[] { x + 1, y });
320 | if (src.getFlag(x - 1, y))
321 | stack.push(new int[] { x - 1, y });
322 | if (src.getFlag(x, y + 1))
323 | stack.push(new int[] { x, y + 1 });
324 | if (src.getFlag(x, y - 1))
325 | stack.push(new int[] { x, y - 1 });
326 | }
327 | }
328 | return cnt;
329 | }
330 |
331 | private static boolean isVisible(String id, String worldname) {
332 |
333 | if (Settings.visibleRegionsAreSet() &&
334 | (Settings.getVisibleRegions().contains("world:" + worldname) == false || Settings.getVisibleRegions().contains(id) == false))
335 | return false;
336 |
337 | if (Settings.hiddenRegionsAreSet() &&
338 | (Settings.getHiddenRegions().contains(id) || Settings.getHiddenRegions().contains("world:" + worldname)))
339 | return false;
340 | return true;
341 | }
342 |
343 | private void addStyle(Town town, AreaMarker m, TownBlockType btype) {
344 | AreaStyle as = cusstyle.get(town.getName()); /* Look up custom style for town, if any */
345 | AreaStyle ns = nationstyle.get(getNationNameOrNone(town)); /* Look up nation style, if any */
346 |
347 | if(btype == null) {
348 | m.setLineStyle(defstyle.getStrokeWeight(as, ns), defstyle.getStrokeOpacity(as, ns), defstyle.getStrokeColor(as, ns));
349 | }
350 | else {
351 | m.setLineStyle(1, 0, 0);
352 | }
353 | m.setFillStyle(defstyle.getFillOpacity(as, ns), defstyle.getFillColor(as, ns, btype));
354 | double y = defstyle.getY(as, ns);
355 | m.setRangeY(y, y);
356 | m.setBoostFlag(defstyle.getBoost(as, ns));
357 |
358 | // We're dealing with something that has a custom AreaStyle applied via the
359 | // custstyle or nationstyle in the config.yml, do not apply dynamic colours.
360 | if (as != null || (ns != null && ns.fillcolor > -1 && ns.strokecolor > -1))
361 | return;
362 |
363 | //Read dynamic colors from town/nation objects
364 | if(Settings.usingDynamicTownColours() || Settings.usingDynamicNationColours()) {
365 | try {
366 | String colorHexCode;
367 | Integer townFillColorInteger = null;
368 | Integer townBorderColorInteger = null;
369 |
370 | //CALCULATE FILL COLOUR
371 | if (Settings.usingDynamicTownColours()) {
372 | //Here we know the server is using town colors. This takes top priority for fill
373 | colorHexCode = town.getMapColorHexCode();
374 | if(!colorHexCode.isEmpty()) {
375 | //If town has a color, use it
376 | townFillColorInteger = Integer.parseInt(colorHexCode, 16);
377 | townBorderColorInteger = townFillColorInteger;
378 | }
379 | } else {
380 | //Here we know the server is using nation colors
381 | colorHexCode = town.getNationMapColorHexCode();
382 | if(colorHexCode != null && !colorHexCode.isEmpty()) {
383 | //If nation has a color, use it
384 | townFillColorInteger = Integer.parseInt(colorHexCode, 16);
385 | }
386 | }
387 |
388 | //CALCULATE BORDER COLOR
389 | if (Settings.usingDynamicNationColours()) {
390 | //Here we know the server is using nation colors. This takes top priority for border
391 | colorHexCode = town.getNationMapColorHexCode();
392 | if(colorHexCode != null && !colorHexCode.isEmpty()) {
393 | //If nation has a color, use it
394 | townBorderColorInteger = Integer.parseInt(colorHexCode, 16);
395 | }
396 | } else {
397 | //Here we know the server is using town colors
398 | colorHexCode = town.getMapColorHexCode();
399 | if(!colorHexCode.isEmpty()) {
400 | //If town has a color, use it
401 | townBorderColorInteger = Integer.parseInt(colorHexCode, 16);
402 | }
403 | }
404 |
405 | //SET FILL COLOR
406 | if(townFillColorInteger != null) {
407 | //Set fill style
408 | double fillOpacity = m.getFillOpacity();
409 | //Allow special fills for some townblock types
410 | int townblockcolor = defstyle.getFillColor(btype);
411 | m.setFillStyle(fillOpacity, townblockcolor >= 0 ? townblockcolor : townFillColorInteger);
412 | }
413 |
414 | //SET BORDER COLOR
415 | if(townBorderColorInteger != null) {
416 | //Set stroke style
417 | double strokeOpacity = m.getLineOpacity();
418 | int strokeWeight = m.getLineWeight();
419 | m.setLineStyle(strokeWeight, strokeOpacity, townBorderColorInteger);
420 | }
421 |
422 | } catch (Exception ex) {}
423 | }
424 | }
425 |
426 |
427 | /*
428 | * Town Marker Drawing Methods
429 | */
430 |
431 | private void drawTownMarkers(Town town, Map newWorldNameMarkerMap, String townName, String desc) {
432 | /* Now, add marker for home block */
433 | TownBlock homeBlock = town.getHomeBlockOrNull();
434 |
435 | if (homeBlock != null && isVisible(townName, homeBlock.getWorld().getName())) {
436 | MarkerIcon townHomeBlockIcon = getMarkerIcon(town);
437 |
438 | /* Fire an event allowing other plugins to alter the MarkerIcon */
439 | TownSetMarkerIconEvent iconEvent = new TownSetMarkerIconEvent(town, townHomeBlockIcon);
440 | Bukkit.getPluginManager().callEvent(iconEvent);
441 | townHomeBlockIcon = iconEvent.getIcon();
442 |
443 | if (townHomeBlockIcon != null)
444 | drawHomeBlockSpawn(newWorldNameMarkerMap, townName, desc, homeBlock, townHomeBlockIcon);
445 | }
446 |
447 | if (town.hasOutpostSpawn() && Settings.getOutpostIcon() != null)
448 | drawOutpostIcons(town, newWorldNameMarkerMap, desc);
449 | }
450 |
451 | private MarkerIcon getMarkerIcon(Town town) {
452 | if (town.isRuined())
453 | return defstyle.getRuinIcon();;
454 |
455 | AreaStyle as = cusstyle.get(town.getName());
456 | AreaStyle ns = nationstyle.get(getNationNameOrNone(town));
457 |
458 | return town.isCapital() ? defstyle.getCapitalMarker(as, ns) : defstyle.getHomeMarker(as, ns);
459 | }
460 |
461 | private String getNationNameOrNone(Town town) {
462 | return town.hasNation() ? town.getNationOrNull().getName() : "_none_";
463 | }
464 |
465 | private void drawHomeBlockSpawn(Map newWorldNameMarkerMap, String townName, String desc, TownBlock townBlock, MarkerIcon ico) {
466 | String markid = townName + "__home";
467 | Marker home = existingMarkers.remove(markid);
468 | double xx = TOWNBLOCKSIZE * townBlock.getX() + (TOWNBLOCKSIZE / 2);
469 | double zz = TOWNBLOCKSIZE * townBlock.getZ() + (TOWNBLOCKSIZE / 2);
470 | if(home == null) {
471 | home = set.createMarker(markid, townName, townBlock.getWorld().getName(), xx, 64, zz, ico, false);
472 | if (home == null)
473 | return;
474 | } else {
475 | home.setLocation(townBlock.getWorld().getName(), xx, 64, zz);
476 | home.setLabel(townName); /* Update label */
477 | home.setMarkerIcon(ico);
478 | }
479 | /* Set popup */
480 | home.setDescription(desc);
481 |
482 | newWorldNameMarkerMap.put(markid, home);
483 | }
484 |
485 | private void drawOutpostIcons(Town town, Map newWorldNameMarkerMap, String desc) {
486 | AreaStyle as = cusstyle.get(town.getName());
487 | AreaStyle ns = nationstyle.get(getNationNameOrNone(town));
488 | MarkerIcon outpostIco = defstyle.getOutpostMarker(as, ns);
489 |
490 | int i = 0;
491 | for (Location loc : town.getAllOutpostSpawns()) {
492 | i++;
493 | TownBlock townBlock = TownyAPI.getInstance().getTownBlock(loc);
494 | if (townBlock == null || !isVisible(town.getName(), townBlock.getWorld().getName()))
495 | continue;
496 |
497 | double xx = TOWNBLOCKSIZE * townBlock.getX() + (TOWNBLOCKSIZE / 2);
498 | double zz = TOWNBLOCKSIZE * townBlock.getZ() + (TOWNBLOCKSIZE / 2);
499 | String outpostMarkerID = town.getName() + "_Outpost_" + i;
500 | String outpostName = "%s %s %s".formatted(town.getName(),
501 | Translation.of("outpost"),
502 | townBlock.getFormattedName().isEmpty() ? i : townBlock.getFormattedName());
503 | Marker outpostMarker = existingMarkers.remove(outpostMarkerID);
504 | if (outpostMarker == null) {
505 | outpostMarker = set.createMarker(outpostMarkerID, outpostName, townBlock.getWorld().getName(), xx, 64, zz, outpostIco, true);
506 | if (outpostMarker == null)
507 | continue;
508 | } else {
509 | outpostMarker.setLocation(townBlock.getWorld().getName(), xx, 64, zz);
510 | outpostMarker.setLabel(outpostName);
511 | outpostMarker.setMarkerIcon(outpostIco);
512 | }
513 | outpostMarker.setDescription(desc);
514 | newWorldNameMarkerMap.put(outpostMarkerID, outpostMarker);
515 | }
516 | }
517 |
518 | }
519 |
--------------------------------------------------------------------------------