Saber-Factions/src/main/java/com/massivecraft/factions/integration/dynmap/EngineDynmap.java

1096 lines
27 KiB
Java

package com.massivecraft.factions.integration.dynmap;
import com.massivecraft.factions.*;
import com.massivecraft.factions.integration.Econ;
import com.massivecraft.factions.struct.Role;
import com.massivecraft.factions.zcore.persist.MemoryBoard;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.plugin.Plugin;
import org.dynmap.DynmapAPI;
import org.dynmap.markers.*;
import org.dynmap.utils.TileFlags;
import java.awt.Point;
import java.util.*;
import java.util.Map.Entry;
// This source code is a heavily modified version of mikeprimms plugin Dynmap-Factions.
public class EngineDynmap
{
/**
* @author FactionsUUID Team
*/
// -------------------------------------------- //
// CONSTANTS
// -------------------------------------------- //
public final static int BLOCKS_PER_CHUNK = 16;
public final static String DYNMAP_INTEGRATION = "\u00A7dDynmap Integration: \u00A7e";
public final static String FACTIONS = "factions";
public final static String FACTIONS_ = FACTIONS + "_";
public final static String FACTIONS_MARKERSET = FACTIONS_ + "markerset";
public final static String FACTIONS_HOME = FACTIONS_ + "home";
public final static String FACTIONS_HOME_ = FACTIONS_HOME + "_";
public final static String FACTIONS_PLAYERSET = FACTIONS_ + "playerset";
public final static String FACTIONS_PLAYERSET_ = FACTIONS_PLAYERSET + "_";
// -------------------------------------------- //
// INSTANCE & CONSTRUCT
// -------------------------------------------- //
private static final EngineDynmap i = new EngineDynmap();
public DynmapAPI dynmapApi;
public MarkerAPI markerApi;
public MarkerSet markerset;
List<List<Point>> polyLine = new ArrayList<List<Point>>();
private EngineDynmap()
{
}
public static EngineDynmap getInstance()
{
return i;
}
public static String getHtmlPlayerString(Collection<FPlayer> playersOfficersList)
{
StringBuilder ret = new StringBuilder();
for (FPlayer fplayer : playersOfficersList)
{
if (ret.length() > 0)
{
ret.append(", ");
}
ret.append(getHtmlPlayerName(fplayer));
}
return ret.toString();
}
public static String getHtmlPlayerName(FPlayer fplayer)
{
return fplayer != null ? escapeHtml(fplayer.getName()) : "none";
}
public static String escapeHtml(String string)
{
if (string == null)
{
return "";
}
StringBuilder out = new StringBuilder(Math.max(16, string.length()));
for (int i = 0; i < string.length(); i++)
{
char c = string.charAt(i);
if (c > 127 || c == '"' || c == '<' || c == '>' || c == '&')
{
out.append("&#").append((int) c).append(';');
}
else
{
out.append(c);
}
}
return out.toString();
}
// Thread Safe / Asynchronous: Yes
public static void info(String msg)
{
System.out.println(DYNMAP_INTEGRATION + msg);
}
// -------------------------------------------- //
// UPDATE: HOMES
// -------------------------------------------- //
// Thread Safe / Asynchronous: Yes
public static void severe(String msg)
{
System.out.println(DYNMAP_INTEGRATION + ChatColor.RED.toString() + msg);
}
public void init()
{
Plugin dynmap = Bukkit.getServer().getPluginManager().getPlugin("dynmap");
if (dynmap == null || !dynmap.isEnabled())
{
return;
}
// Should we even use dynmap?
if (!Conf.dynmapUse)
{
if (this.markerset != null)
{
this.markerset.deleteMarkerSet();
this.markerset = null;
}
return;
}
// Shedule non thread safe sync at the end!
Bukkit.getScheduler().scheduleSyncRepeatingTask(FactionsPlugin.getInstance(), () ->
{
final Map<String, TempMarker> homes = createHomes();
final Map<String, TempAreaMarker> areas = createAreas();
final Map<String, TempPolyLineMarker> polys = createPolys(areas);
final Map<String, Set<String>> playerSets = createPlayersets();
if (!updateCore())
{
return;
}
// createLayer() is thread safe but it makes use of fields set in updateCore() so we must have it after.
if (!updateLayer(createLayer()))
{
return;
}
updateHomes(homes);
updateAreas(areas);
updatePolys(polys);
updatePlayersets(playerSets);
}, 100L, 100L);
}
// -------------------------------------------- //
// UPDATE: AREAS
// -------------------------------------------- //
// Thread Safe / Asynchronous: No
public boolean updateCore()
{
// Get DynmapAPI
this.dynmapApi = (DynmapAPI) Bukkit.getPluginManager().getPlugin("dynmap");
if (this.dynmapApi == null)
{
severe("Could not retrieve the DynmapAPI.");
return false;
}
// Get MarkerAPI
this.markerApi = this.dynmapApi.getMarkerAPI();
if (this.markerApi == null)
{
severe("Could not retrieve the MarkerAPI.");
return false;
}
return true;
}
// Thread Safe / Asynchronous: Yes
public TempMarkerSet createLayer()
{
TempMarkerSet ret = new TempMarkerSet();
ret.label = Conf.dynmapLayerName;
ret.minimumZoom = Conf.dynmapLayerMinimumZoom;
ret.priority = Conf.dynmapLayerPriority;
ret.hideByDefault = !Conf.dynmapLayerVisible;
return ret;
}
// Thread Safe / Asynchronous: No
public boolean updateLayer(TempMarkerSet temp)
{
this.markerset = this.markerApi.getMarkerSet(FACTIONS_MARKERSET);
if (this.markerset == null)
{
this.markerset = temp.create(this.markerApi, FACTIONS_MARKERSET);
if (this.markerset == null)
{
severe("Could not create the Faction Markerset/Layer");
return false;
}
}
else
{
temp.update(this.markerset);
}
return true;
}
// Thread Safe / Asynchronous: Yes
public Map<String, TempMarker> createHomes()
{
Map<String, TempMarker> ret = new HashMap<>();
// Loop current factions
for (Faction faction : Factions.getInstance().getAllFactions())
{
Location ps = faction.getHome();
if (ps == null)
{
continue;
}
DynmapStyle style = getStyle(faction);
String markerId = FACTIONS_HOME_ + faction.getId();
TempMarker temp = new TempMarker();
temp.label = ChatColor.stripColor(faction.getTag());
temp.world = ps.getWorld().toString();
temp.x = ps.getX();
temp.y = ps.getY();
temp.z = ps.getZ();
temp.iconName = style.getHomeMarker();
temp.description = getDescription(faction);
ret.put(markerId, temp);
}
return ret;
}
// Thread Safe / Asynchronous: No
// This method places out the faction home markers into the factions markerset.
public void updateHomes(Map<String, TempMarker> homes)
{
// Put all current faction markers in a map
Map<String, Marker> markers = new HashMap<>();
for (Marker marker : this.markerset.getMarkers())
{
markers.put(marker.getMarkerID(), marker);
}
// Loop homes
for (Entry<String, TempMarker> entry : homes.entrySet())
{
String markerId = entry.getKey();
TempMarker temp = entry.getValue();
// Get Creative
// NOTE: I remove from the map created just in the beginning of this method.
// NOTE: That way what is left at the end will be outdated markers to remove.
Marker marker = markers.remove(markerId);
if (marker == null)
{
marker = temp.create(this.markerApi, this.markerset, markerId);
marker = temp.create(this.markerApi, this.markerset, markerId);
if (marker == null)
{
EngineDynmap.severe("Could not get/create the home marker " + markerId);
}
}
else
{
temp.update(this.markerApi, marker);
}
}
// Delete Deprecated Markers
// Only old markers should now be left
for (Marker marker : markers.values())
{
marker.deleteMarker();
}
}
// -------------------------------------------- //
// UPDATE: PLAYERSET
// -------------------------------------------- //
// Thread Safe: YES
public Map<String, TempPolyLineMarker> createPolys(Map<String, TempAreaMarker> areas)
{
Map<String, TempPolyLineMarker> ret = new HashMap<String, TempPolyLineMarker>();
for (Entry<String, TempAreaMarker> entry : areas.entrySet())
{
String markerID = entry.getKey();
TempAreaMarker area = entry.getValue();
int counter = 0;
for (List<Point> points : area.getPolyLine())
{
markerID = markerID + "_poly_" + counter;
TempPolyLineMarker tempPoly = new TempPolyLineMarker();
tempPoly.polyLine = points;
tempPoly.lineColor = area.lineColor;
tempPoly.lineOpacity = area.lineOpacity;
tempPoly.lineWeight = area.lineWeight;
tempPoly.world = area.world;
ret.put(markerID, tempPoly);
counter++;
}
}
return ret;
}
public Map<String, TempAreaMarker> createAreas()
{
Map<String, Map<Faction, Set<FLocation>>> worldFactionChunks = createWorldFactionChunks();
return createAreas(worldFactionChunks);
}
// Thread Safe: YES
public Map<String, Map<Faction, Set<FLocation>>> createWorldFactionChunks()
{
// Create map "world name --> faction --> set of chunk coords"
Map<String, Map<Faction, Set<FLocation>>> worldFactionChunks = new HashMap<>();
// Note: The board is the world. The board id is the world name.
MemoryBoard board = (MemoryBoard) Board.getInstance();
for (Entry<FLocation, String> entry : board.flocationIds.entrySet())
{
String world = entry.getKey().getWorldName();
Faction chunkOwner = Factions.getInstance().getFactionById(entry.getValue());
Map<Faction, Set<FLocation>> factionChunks = worldFactionChunks.get(world);
if (factionChunks == null)
{
factionChunks = new HashMap<>();
worldFactionChunks.put(world, factionChunks);
}
Set<FLocation> factionTerritory = factionChunks.get(chunkOwner);
if (factionTerritory == null)
{
factionTerritory = new HashSet<>();
factionChunks.put(chunkOwner, factionTerritory);
}
factionTerritory.add(entry.getKey());
}
return worldFactionChunks;
}
// Thread Safe: YES
public Map<String, TempAreaMarker> createAreas(Map<String, Map<Faction, Set<FLocation>>> worldFactionChunks)
{
Map<String, TempAreaMarker> ret = new HashMap<>();
// For each world
for (Entry<String, Map<Faction, Set<FLocation>>> entry : worldFactionChunks.entrySet())
{
String world = entry.getKey();
Map<Faction, Set<FLocation>> factionChunks = entry.getValue();
// For each faction and its chunks in that world
for (Entry<Faction, Set<FLocation>> entry1 : factionChunks.entrySet())
{
Faction faction = entry1.getKey();
Set<FLocation> chunks = entry1.getValue();
Map<String, TempAreaMarker> worldFactionMarkers = createAreas(world, faction, chunks);
ret.putAll(worldFactionMarkers);
}
}
return ret;
}
// Thread Safe: YES
// Handle specific faction on specific world
// "handle faction on world"
public Map<String, TempAreaMarker> createAreas(String world, Faction faction, Set<FLocation> chunks)
{
Map<String, TempAreaMarker> ret = new HashMap<>();
// If the faction is visible ...
if (!isVisible(faction, world))
{
return ret;
}
// ... and has any chunks ...
if (chunks.isEmpty())
{
return ret;
}
// Index of polygon for given faction
int markerIndex = 0;
// Create the info window
String description = getDescription(faction);
// Fetch Style
DynmapStyle style = this.getStyle(faction);
// Loop through chunks: set flags on chunk map
TileFlags allChunkFlags = new TileFlags();
LinkedList<FLocation> allChunks = new LinkedList<>();
for (FLocation chunk : chunks)
{
allChunkFlags.setFlag((int) chunk.getX(), (int) chunk.getZ(), true); // Set flag for chunk
allChunks.addLast(chunk);
}
// Loop through until we don't find more areas
while (allChunks != null)
{
TileFlags ourChunkFlags = null;
LinkedList<FLocation> ourChunks = null;
LinkedList<FLocation> newChunks = null;
for (FLocation chunk : allChunks)
{
int chunkX = (int) chunk.getX();
int chunkZ = (int) chunk.getZ();
// If we need to start shape, and this block is not part of one yet
if (ourChunkFlags == null && allChunkFlags.getFlag(chunkX, chunkZ))
{
ourChunkFlags = new TileFlags(); // Create map for shape
ourChunks = new LinkedList<>();
floodFillTarget(allChunkFlags, ourChunkFlags, chunkX, chunkZ); // Copy shape
ourChunks.add(chunk); // Add it to our chunk list
}
// If shape found, and we're in it, add to our node list
else if (ourChunkFlags != null && ourChunkFlags.getFlag(chunkX, chunkZ))
{
ourChunks.add(chunk);
}
// Else, keep it in the list for the next polygon
else
{
if (newChunks == null)
{
newChunks = new LinkedList<>();
}
newChunks.add(chunk);
}
}
// Replace list (null if no more to process)
allChunks = newChunks;
if (ourChunkFlags == null)
{
continue;
}
List<TempLine> outputLines = new ArrayList<TempLine>();
Map<TempLine, Integer> lines = new HashMap<TempLine, Integer>();
if (ourChunks == null)
{
continue;
}
for (FLocation loc : ourChunks)
{
int x = loc.getChunk().getX();
int z = loc.getChunk().getZ();
TempLine line = new TempLine(new Point(x * 16, z * 16), new Point(x * 16 + 16, z * 16));
if (lines.containsKey(line))
{
lines.put(line, lines.get(line) + 1);
}
else
{
lines.put(line, 1);
}
line = new TempLine(new Point(x * 16 + 16, z * 16), new Point(x * 16 + 16, z * 16 + 16));
if (lines.containsKey(line))
{
lines.put(line, lines.get(line) + 1);
}
else
{
lines.put(line, 1);
}
line = new TempLine(new Point(x * 16 + 16, z * 16 + 16), new Point(x * 16, z * 16 + 16));
if (lines.containsKey(line))
{
lines.put(line, lines.get(line) + 1);
}
else
{
lines.put(line, 1);
}
line = new TempLine(new Point(x * 16, z * 16 + 16), new Point(x * 16, z * 16));
if (lines.containsKey(line))
{
lines.put(line, lines.get(line) + 1);
}
else
{
lines.put(line, 1);
}
}
Iterator<Entry<TempLine, Integer>> iterator = lines.entrySet().iterator();
List<TempLine> lineList = new ArrayList<TempLine>();
lineList.addAll(lines.keySet());
while (iterator.hasNext())
{
Entry<TempLine, Integer> entry = iterator.next();
if (entry.getValue() > 1)
{
lineList.remove(entry.getKey());
}
}
// Find the leftmost MCRWPoint
TempLine l = null;
for (Iterator<TempLine> it = lineList.iterator(); it.hasNext();)
{
TempLine tl = it.next();
if (l == null || tl.getP1().x < l.getP1().x)
l = tl;
}
for (Iterator<TempLine> it = lineList.iterator(); it.hasNext();)
{
TempLine tl = it.next();
if (tl.getP2().x < l.getP2().x)
l = tl;
}
outputLines.add(l);
lineList.remove(l);
while (lineList.size() > 0)
{
// MCRWPoint targetp = new MCRWPoint((int) lastLine.x1, (int) lastLine.y1);
// MCRWPointWLines.get(targetp);
TempLine nextLine = null;
for (Iterator<TempLine> it = lineList.iterator(); it.hasNext();)
{
TempLine line = it.next();
if (l.getP2().x == line.getP1().x && l.getP2().y == line.getP1().y)
{
nextLine = line;
}
}
if (nextLine != null)
{
outputLines.add(nextLine);
lineList.remove(nextLine);
l = nextLine;
}
else
{
outputLines.get(outputLines.size() - 1).addAdditionLines(CamScan1(lineList));
break;
}
}
List<Point> outputPoints = new ArrayList<Point>();
List<Point> polyPoints = new ArrayList<Point>();
for (int i = 0; i < outputLines.size(); i++)
{
Point p = new Point(outputLines.get(i).getP1().x, outputLines.get(i).getP1().y);
outputPoints.add(p);
polyPoints.add(p);
if (outputLines.get(i).getConnectedLines().size() > 0)
{
outputPoints.addAll(addRecursivePoints(new Point((int) outputLines.get(i).getP1().x, (int) outputLines.get(i).getP1().y), outputLines.get(i)));
}
p = new Point((int) outputLines.get(i).getP2().x, (int) outputLines.get(i).getP2().y);
outputPoints.add(p);
polyPoints.add(p);
}
polyLine.add(polyPoints);
// Build information for specific area
double[] x = new double[outputPoints.size()];
double[] z = new double[outputPoints.size()];
for (int i = 0; i < outputPoints.size(); i++)
{
x[i] = outputPoints.get(i).x;
z[i] = outputPoints.get(i).y;
}
String markerId = FACTIONS_ + world + "__" + faction.getId() + "__" + markerIndex;
TempAreaMarker temp = new TempAreaMarker();
temp.label = faction.getTag();
temp.world = world;
temp.x = x;
temp.z = z;
temp.description = description;
temp.lineColor = style.getLineColor();
temp.lineOpacity = style.getLineOpacity();
temp.lineWeight = style.getLineWeight();
temp.fillColor = style.getFillColor();
temp.fillOpacity = style.getFillOpacity();
temp.boost = style.getBoost();
temp.setPolyLine(polyLine);
ret.put(markerId, temp);
polyLine.clear();
markerIndex++;
}
return ret;
}
public List<Point> addRecursivePoints(Point returnPoint, TempLine line)
{
List<Point> ret = new ArrayList<Point>();
boolean shouldReturn = false;
List<TempLine> connectedLines = line.getConnectedLines();
List<Point> polyPoints = new ArrayList<Point>();
for (TempLine line2 : connectedLines)
{
Point p = new Point((int) line2.getP1().x, (int) line2.getP1().y);
ret.add(p);
polyPoints.add(p);
shouldReturn = true;
if (line2.getConnectedLines().size() > 0)
{
ret.addAll(addRecursivePoints(new Point((int) line2.getP1().x, (int) line2.getP1().y), line2));
}
p = new Point((int) line2.getP2().x, (int) line2.getP2().y);
ret.add(p);
polyPoints.add(p);
}
if (shouldReturn)
{
ret.add(returnPoint);
}
polyLine.add(polyPoints);
return ret;
}
private List<TempLine> CamScan1(List<TempLine> lineList)
{
List<TempLine> ret = new ArrayList<TempLine>();
// Find the leftmost MCRWPoint
TempLine l = null;
for (Iterator<TempLine> it = lineList.iterator(); it.hasNext();)
{
TempLine tl = it.next();
if (l == null || tl.getP1().x < l.getP1().x)
l = tl;
}
for (Iterator<TempLine> it = lineList.iterator(); it.hasNext();)
{
TempLine tl = it.next();
if (tl.getP2().x < l.getP2().x)
l = tl;
}
ret.add(l);
lineList.remove(l);
while (lineList.size() > 0)
{
// MCRWPoint targetp = new MCRWPoint((int) lastLine.x1, (int) lastLine.y1);
// MCRWPointWLines.get(targetp);
TempLine thisChunkLine = null;
for (Iterator<TempLine> it = lineList.iterator(); it.hasNext();)
{
TempLine line = it.next();
if (l.getP2().x == line.getP1().x && l.getP2().y == line.getP1().y)
{
thisChunkLine = line;
}
}
if (thisChunkLine != null)
{
ret.add(thisChunkLine);
lineList.remove(thisChunkLine);
l = thisChunkLine;
}
else
{
// break;
ret.get(ret.size() - 1).addAdditionLines(CamScan1(lineList));
}
}
return ret;
}
// -------------------------------------------- //
// UTIL & SHARED
// -------------------------------------------- //
public void updatePolys(Map<String, TempPolyLineMarker> polys)
{
// Map Current
Map<String, PolyLineMarker> markers = new HashMap<>();
for (PolyLineMarker marker : this.markerset.getPolyLineMarkers())
{
markers.put(marker.getMarkerID(), marker);
}
// Loop New
for (Entry<String, TempPolyLineMarker> entry : polys.entrySet())
{
String markerId = entry.getKey();
TempPolyLineMarker temp = entry.getValue();
// Get Creative
// NOTE: I remove from the map created just in the beginning of this method.
// NOTE: That way what is left at the end will be outdated markers to remove.
PolyLineMarker marker = markers.remove(markerId);
if (marker == null)
{
marker = temp.create(this.markerset, markerId);
if (marker == null)
{
severe("Could not get/create the area marker " + markerId);
}
}
else
{
temp.update(marker);
}
}
// Only old/outdated should now be left. Delete them.
for (PolyLineMarker marker : markers.values())
{
marker.deleteMarker();
}
}
// Thread Safe: NO
public void updateAreas(Map<String, TempAreaMarker> areas)
{
// Map Current
Map<String, AreaMarker> markers = new HashMap<>();
for (AreaMarker marker : this.markerset.getAreaMarkers())
{
markers.put(marker.getMarkerID(), marker);
}
// Loop New
for (Entry<String, TempAreaMarker> entry : areas.entrySet())
{
String markerId = entry.getKey();
TempAreaMarker temp = entry.getValue();
// Get Creative
// NOTE: I remove from the map created just in the beginning of this method.
// NOTE: That way what is left at the end will be outdated markers to remove.
AreaMarker marker = markers.remove(markerId);
if (marker == null)
{
marker = temp.create(this.markerset, markerId);
if (marker == null)
{
severe("Could not get/create the area marker " + markerId);
}
}
else
{
temp.update(marker);
}
}
// Only old/outdated should now be left. Delete them.
for (AreaMarker marker : markers.values())
{
marker.deleteMarker();
}
}
// Thread Safe / Asynchronous: Yes
public String createPlayersetId(Faction faction)
{
if (faction == null)
{
return null;
}
if (faction.isWilderness())
{
return null;
}
String factionId = faction.getId();
if (factionId == null)
{
return null;
}
return FACTIONS_PLAYERSET_ + factionId;
}
// Thread Safe / Asynchronous: Yes
public Set<String> createPlayerset(Faction faction)
{
if (faction == null)
{
return null;
}
if (faction.isWilderness())
{
return null;
}
Set<String> ret = new HashSet<>();
for (FPlayer fplayer : faction.getFPlayers())
{
// NOTE: We add both UUID and name. This might be a good idea for future proofing.
ret.add(fplayer.getId());
ret.add(fplayer.getName());
}
return ret;
}
// Thread Safe / Asynchronous: Yes
public Map<String, Set<String>> createPlayersets()
{
if (!Conf.dynmapVisibilityByFaction)
{
return null;
}
Map<String, Set<String>> ret = new HashMap<>();
for (Faction faction : Factions.getInstance().getAllFactions())
{
String playersetId = createPlayersetId(faction);
if (playersetId == null)
{
continue;
}
Set<String> playerIds = createPlayerset(faction);
if (playerIds == null)
{
continue;
}
ret.put(playersetId, playerIds);
}
return ret;
}
// Thread Safe / Asynchronous: No
public void updatePlayersets(Map<String, Set<String>> playersets)
{
if (playersets == null)
{
return;
}
// Remove
for (PlayerSet set : this.markerApi.getPlayerSets())
{
if (!set.getSetID().startsWith(FACTIONS_PLAYERSET_))
{
continue;
}
// (Null means remove all)
if (playersets.containsKey(set.getSetID()))
{
continue;
}
set.deleteSet();
}
// Add / Update
for (Entry<String, Set<String>> entry : playersets.entrySet())
{
// Extract from Entry
String setId = entry.getKey();
Set<String> playerIds = entry.getValue();
// Get Creatively
PlayerSet set = this.markerApi.getPlayerSet(setId);
if (set == null)
{
set = this.markerApi.createPlayerSet(setId, // id
true, // symmetric
playerIds, // players
false // persistent
);
}
if (set == null)
{
severe("Could not get/create the player set " + setId);
continue;
}
// Set Content
set.setPlayers(playerIds);
}
}
// Thread Safe / Asynchronous: Yes
private String getDescription(Faction faction)
{
String ret = "<div class=\"regioninfo\">" + Conf.dynmapDescription + "</div>";
// Name
String name = faction.getTag();
name = escapeHtml(ChatColor.stripColor(name));
ret = ret.replace("%name%", name);
// Description
String description = faction.getDescription();
description = escapeHtml(ChatColor.stripColor(description));
ret = ret.replace("%description%", description);
// Money
String money = "unavailable";
if (Conf.bankEnabled && Conf.dynmapDescriptionMoney)
money = String.format("%.2f", Econ.getBalance(faction.getAccountId()));
ret = ret.replace("%money%", money);
// Players
Set<FPlayer> playersList = faction.getFPlayers();
String playersCount = String.valueOf(playersList.size());
String players = getHtmlPlayerString(playersList);
FPlayer playersLeaderObject = faction.getFPlayerAdmin();
String playersLeader = getHtmlPlayerName(playersLeaderObject);
ArrayList<FPlayer> playersCoAdminsList = faction.getFPlayersWhereRole(Role.COLEADER);
String playersCoAdminsCount = String.valueOf(playersCoAdminsList.size());
String playersCoAdmins = getHtmlPlayerString(playersCoAdminsList);
ArrayList<FPlayer> playersModeratorsList = faction.getFPlayersWhereRole(Role.MODERATOR);
String playersModeratorsCount = String.valueOf(playersModeratorsList.size());
String playersModerators = getHtmlPlayerString(playersModeratorsList);
ArrayList<FPlayer> playersNormalsList = faction.getFPlayersWhereRole(Role.NORMAL);
String playersNormalsCount = String.valueOf(playersNormalsList.size());
String playersNormals = getHtmlPlayerString(playersNormalsList);
ret = ret.replace("%players%", players);
ret = ret.replace("%players.count%", playersCount);
ret = ret.replace("%players.leader%", playersLeader);
ret = ret.replace("%players.admins%", playersCoAdmins);
ret = ret.replace("%players.admins.count%", playersCoAdminsCount);
ret = ret.replace("%players.moderators%", playersModerators);
ret = ret.replace("%players.moderators.count%", playersModeratorsCount);
ret = ret.replace("%players.normals%", playersNormals);
ret = ret.replace("%players.normals.count%", playersNormalsCount);
return ret;
}
// Thread Safe / Asynchronous: Yes
private boolean isVisible(Faction faction, String world)
{
if (faction == null)
{
return false;
}
final String factionId = faction.getId();
if (factionId == null)
{
return false;
}
final String factionName = faction.getTag();
if (factionName == null)
{
return false;
}
Set<String> visible = Conf.dynmapVisibleFactions;
Set<String> hidden = Conf.dynmapHiddenFactions;
if (!visible.isEmpty() && !visible.contains(factionId) && !visible.contains(factionName) && !visible.contains("world:" + world))
{
return false;
}
return !hidden.contains(factionId) && !hidden.contains(factionName) && !hidden.contains("world:" + world);
}
// Thread Safe / Asynchronous: Yes
public DynmapStyle getStyle(Faction faction)
{
DynmapStyle ret;
ret = Conf.dynmapFactionStyles.get(faction.getId());
if (ret != null)
{
return ret;
}
ret = Conf.dynmapFactionStyles.get(faction.getTag());
if (ret != null)
{
return ret;
}
return Conf.dynmapDefaultStyle;
}
// Find all contiguous blocks, set in target and clear in source
private int floodFillTarget(TileFlags source, TileFlags destination, int x, int y)
{
int cnt = 0;
ArrayDeque<int[]> stack = new ArrayDeque<>();
stack.push(new int[] { x, y });
while (!stack.isEmpty())
{
int[] nxt = stack.pop();
x = nxt[0];
y = nxt[1];
if (source.getFlag(x, y))
{ // Set in src
source.setFlag(x, y, false); // Clear source
destination.setFlag(x, y, true); // Set in destination
cnt++;
if (source.getFlag(x + 1, y))
{
stack.push(new int[] { x + 1, y });
}
if (source.getFlag(x - 1, y))
{
stack.push(new int[] { x - 1, y });
}
if (source.getFlag(x, y + 1))
{
stack.push(new int[] { x, y + 1 });
}
if (source.getFlag(x, y - 1))
{
stack.push(new int[] { x, y - 1 });
}
}
}
return cnt;
}
enum Direction
{
XPLUS, ZPLUS, XMINUS, ZMINUS
}
}