Add Dynmap support
This commit is contained in:
		@@ -66,6 +66,7 @@ import com.massivecraft.factions.entity.migrator.MigratorMPlayer001Ranks;
 | 
			
		||||
import com.massivecraft.factions.entity.migrator.MigratorMPlayer002UsingAdminMode;
 | 
			
		||||
import com.massivecraft.factions.entity.migrator.MigratorTerritoryAccess001Restructure;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsChunkChangeType;
 | 
			
		||||
import com.massivecraft.factions.integration.dynmap.IntegrationDynmap;
 | 
			
		||||
import com.massivecraft.factions.integration.lwc.IntegrationLwc;
 | 
			
		||||
import com.massivecraft.factions.integration.placeholderapi.IntegrationPlaceholderAPI;
 | 
			
		||||
import com.massivecraft.factions.integration.venturechat.IntegrationVentureChat;
 | 
			
		||||
@@ -195,7 +196,8 @@ public class Factions extends MassivePlugin
 | 
			
		||||
			IntegrationPlaceholderAPI.class,
 | 
			
		||||
			IntegrationVentureChat.class,
 | 
			
		||||
			IntegrationLwc.class,
 | 
			
		||||
			IntegrationWorldGuard.class
 | 
			
		||||
			IntegrationWorldGuard.class,
 | 
			
		||||
			IntegrationDynmap.class
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,12 +4,15 @@ import com.massivecraft.factions.Factions;
 | 
			
		||||
import com.massivecraft.factions.Rel;
 | 
			
		||||
import com.massivecraft.factions.engine.EngineChat;
 | 
			
		||||
import com.massivecraft.factions.event.EventFactionsChunkChangeType;
 | 
			
		||||
import com.massivecraft.factions.integration.dynmap.DynmapStyle;
 | 
			
		||||
import com.massivecraft.factions.integration.dynmap.IntegrationDynmap;
 | 
			
		||||
import com.massivecraft.massivecore.collections.BackstringSet;
 | 
			
		||||
import com.massivecraft.massivecore.collections.MassiveSet;
 | 
			
		||||
import com.massivecraft.massivecore.collections.WorldExceptionSet;
 | 
			
		||||
import com.massivecraft.massivecore.command.editor.annotation.EditorName;
 | 
			
		||||
import com.massivecraft.massivecore.command.editor.annotation.EditorType;
 | 
			
		||||
import com.massivecraft.massivecore.command.editor.annotation.EditorTypeInner;
 | 
			
		||||
import com.massivecraft.massivecore.command.editor.annotation.EditorVisible;
 | 
			
		||||
import com.massivecraft.massivecore.command.type.TypeMillisDiff;
 | 
			
		||||
import com.massivecraft.massivecore.store.Entity;
 | 
			
		||||
import com.massivecraft.massivecore.util.MUtil;
 | 
			
		||||
@@ -670,4 +673,78 @@ public class MConf extends Entity<MConf>
 | 
			
		||||
 | 
			
		||||
	public boolean useNewMoneySystem = false;
 | 
			
		||||
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// INTEGRATION: DYNMAP
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
 | 
			
		||||
	// Should the dynmap intagration be used?
 | 
			
		||||
	public boolean dynmapEnabled = true;
 | 
			
		||||
 | 
			
		||||
	// Should the dynmap updates be logged to console output?
 | 
			
		||||
	public boolean dynmapLogTimeSpent = false;
 | 
			
		||||
 | 
			
		||||
	// Name of the Factions layer
 | 
			
		||||
	public String dynmapLayerName = "Factions";
 | 
			
		||||
 | 
			
		||||
	// Should the layer be visible per default
 | 
			
		||||
	public boolean dynmapLayerHiddenByDefault = false;
 | 
			
		||||
 | 
			
		||||
	// Ordering priority in layer menu (low goes before high - default is 0)
 | 
			
		||||
	public int dynmapLayerPriority = 2;
 | 
			
		||||
 | 
			
		||||
	// (optional) set minimum zoom level before layer is visible (0 = defalt, always visible)
 | 
			
		||||
	public int dynmapLayerMinimumZoom = 0;
 | 
			
		||||
 | 
			
		||||
	// Format for popup - substitute values for macros
 | 
			
		||||
	//public String dynmapInfowindowFormat = "<div class=\"infowindow\"><span style=\"font-size:120%;\">%regionname%</span><br />Flags<br /><span style=\"font-weight:bold;\">%flags%</span></div>";
 | 
			
		||||
	public String dynmapFactionDescription =
 | 
			
		||||
		"<div class=\"infowindow\">\n" +
 | 
			
		||||
		"<span style=\"font-weight: bold; font-size: 150%;\">%name%</span></br>\n" +
 | 
			
		||||
		"<span style=\"font-style: italic; font-size: 110%;\">%description%</span></br>\n" +
 | 
			
		||||
		"</br>\n" +
 | 
			
		||||
		"<span style=\"font-weight: bold;\">Leader:</span> %players.leader%</br>\n" +
 | 
			
		||||
		"<span style=\"font-weight: bold;\">Members:</span> %players%</br>\n" +
 | 
			
		||||
		"</br>\n" +
 | 
			
		||||
		"<span style=\"font-weight: bold;\">Age:</span> %age%</br>\n" +
 | 
			
		||||
		"<span style=\"font-weight: bold;\">Bank:</span> %money%</br>\n" +
 | 
			
		||||
		"</br>\n" +
 | 
			
		||||
		"<span style=\"font-weight: bold;\">Flags:</span></br>\n" +
 | 
			
		||||
		"%flags.table3%\n" +
 | 
			
		||||
		"</div>";
 | 
			
		||||
 | 
			
		||||
	// Enable the %money% macro. Only do this if you know your economy manager is thread safe.
 | 
			
		||||
	public boolean dynmapShowMoneyInDescription = false;
 | 
			
		||||
 | 
			
		||||
	// Allow players in faction to see one another on Dynmap (only relevant if Dynmap has 'player-info-protected' enabled)
 | 
			
		||||
	//public boolean dynmapVisibilityByFaction = true;
 | 
			
		||||
 | 
			
		||||
	// Optional setting to limit which regions to show.
 | 
			
		||||
	// If empty all regions are shown.
 | 
			
		||||
	// Specify Faction either by name or UUID.
 | 
			
		||||
	// To show all regions on a given world, add 'world:<worldname>' to the list.
 | 
			
		||||
	public Set<String> dynmapVisibleFactions = new MassiveSet<>();
 | 
			
		||||
 | 
			
		||||
	// Optional setting to hide specific Factions.
 | 
			
		||||
	// Specify Faction either by name or UUID.
 | 
			
		||||
	// To hide all regions on a given world, add 'world:<worldname>' to the list.
 | 
			
		||||
	public Set<String> dynmapHiddenFactions = new MassiveSet<>();
 | 
			
		||||
 | 
			
		||||
	@EditorVisible(false)
 | 
			
		||||
	public DynmapStyle dynmapDefaultStyle = new DynmapStyle(
 | 
			
		||||
		IntegrationDynmap.DYNMAP_STYLE_LINE_COLOR,
 | 
			
		||||
		IntegrationDynmap.DYNMAP_STYLE_LINE_OPACITY,
 | 
			
		||||
		IntegrationDynmap.DYNMAP_STYLE_LINE_WEIGHT,
 | 
			
		||||
		IntegrationDynmap.DYNMAP_STYLE_FILL_COLOR,
 | 
			
		||||
		IntegrationDynmap.DYNMAP_STYLE_FILL_OPACITY,
 | 
			
		||||
		IntegrationDynmap.DYNMAP_STYLE_HOME_MARKER,
 | 
			
		||||
		IntegrationDynmap.DYNMAP_STYLE_BOOST
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	// Optional per Faction style overrides. Any defined replace those in dynmapDefaultStyle.
 | 
			
		||||
	// Specify Faction either by name or UUID.
 | 
			
		||||
	@EditorVisible(false)
 | 
			
		||||
	public Map<String, DynmapStyle> dynmapFactionStyles = MUtil.map(
 | 
			
		||||
		"SafeZone", new DynmapStyle().withLineColor("#FF00FF").withFillColor("#FF00FF").withBoost(false),
 | 
			
		||||
		"WarZone", new DynmapStyle().withLineColor("#FF0000").withFillColor("#FF0000").withBoost(false)
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,211 @@
 | 
			
		||||
package com.massivecraft.factions.integration.dynmap;
 | 
			
		||||
 | 
			
		||||
import com.massivecraft.massivecore.util.MUtil;
 | 
			
		||||
import org.dynmap.markers.AreaMarker;
 | 
			
		||||
import org.dynmap.markers.MarkerAPI;
 | 
			
		||||
import org.dynmap.markers.MarkerSet;
 | 
			
		||||
 | 
			
		||||
public class AreaMarkerValues
 | 
			
		||||
{
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// FIELDS
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
 | 
			
		||||
	private final String label;
 | 
			
		||||
	public String getLabel() { return label; }
 | 
			
		||||
	public AreaMarkerValues withLabel(String label) { return new AreaMarkerValues(label, world, x, z, description, lineColor, lineOpacity, lineWeight, fillColor, fillOpacity, boost); }
 | 
			
		||||
 | 
			
		||||
	private final String world;
 | 
			
		||||
	public String getWorld() { return world; }
 | 
			
		||||
	public AreaMarkerValues withWorld(String world) { return new AreaMarkerValues(label, world, x, z, description, lineColor, lineOpacity, lineWeight, fillColor, fillOpacity, boost); }
 | 
			
		||||
 | 
			
		||||
	private final double[] x;
 | 
			
		||||
	public double[] getX() { return x; }
 | 
			
		||||
	public AreaMarkerValues withX(double[] x) { return new AreaMarkerValues(label, world, x, z, description, lineColor, lineOpacity, lineWeight, fillColor, fillOpacity, boost); }
 | 
			
		||||
 | 
			
		||||
	private final double[] z;
 | 
			
		||||
	public double[] getZ() { return z; }
 | 
			
		||||
	public AreaMarkerValues withZ(double[] z) { return new AreaMarkerValues(label, world, x, z, description, lineColor, lineOpacity, lineWeight, fillColor, fillOpacity, boost); }
 | 
			
		||||
 | 
			
		||||
	private final String description;
 | 
			
		||||
	public String getDescription() { return description; }
 | 
			
		||||
	public AreaMarkerValues withDescription(String description) { return new AreaMarkerValues(label, world, x, z, description, lineColor, lineOpacity, lineWeight, fillColor, fillOpacity, boost); }
 | 
			
		||||
	
 | 
			
		||||
	private final int lineColor;
 | 
			
		||||
	public int getLineColor() { return lineColor; }
 | 
			
		||||
	public AreaMarkerValues withLineColor(int lineColor) { return new AreaMarkerValues(label, world, x, z, description, lineColor, lineOpacity, lineWeight, fillColor, fillOpacity, boost); }
 | 
			
		||||
 | 
			
		||||
	private final double lineOpacity;
 | 
			
		||||
	public double getLineOpacity() { return lineOpacity; }
 | 
			
		||||
	public AreaMarkerValues withLineOpacity(double lineOpacity) { return new AreaMarkerValues(label, world, x, z, description, lineColor, lineOpacity, lineWeight, fillColor, fillOpacity, boost); }
 | 
			
		||||
 | 
			
		||||
	private final int lineWeight;
 | 
			
		||||
	public int getLineWeight() { return lineWeight; }
 | 
			
		||||
	public AreaMarkerValues withLineWright(int lineWeight) { return new AreaMarkerValues(label, world, x, z, description, lineColor, lineOpacity, lineWeight, fillColor, fillOpacity, boost); }
 | 
			
		||||
 | 
			
		||||
	private final int fillColor;
 | 
			
		||||
	public int getFillColor() { return fillColor; }
 | 
			
		||||
	public AreaMarkerValues withFillColor(int fillColor) { return new AreaMarkerValues(label, world, x, z, description, lineColor, lineOpacity, lineWeight, fillColor, fillOpacity, boost); }
 | 
			
		||||
 | 
			
		||||
	private final double fillOpacity;
 | 
			
		||||
	public double getFillOpacity() { return fillOpacity; }
 | 
			
		||||
	public AreaMarkerValues withFillOpacity(double fillOpacity) { return new AreaMarkerValues(label, world, x, z, description, lineColor, lineOpacity, lineWeight, fillColor, fillOpacity, boost); }
 | 
			
		||||
	
 | 
			
		||||
	private final boolean boost;
 | 
			
		||||
	public boolean isBoost() { return boost; }
 | 
			
		||||
	public AreaMarkerValues withBoost(boolean boost) { return new AreaMarkerValues(label, world, x, z, description, lineColor, lineOpacity, lineWeight, fillColor, fillOpacity, boost); }
 | 
			
		||||
 | 
			
		||||
	public AreaMarkerValues withStyle(DynmapStyle style)
 | 
			
		||||
	{
 | 
			
		||||
		return new AreaMarkerValues(label, world, x, z, description, style);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// CONSTRUCTOR
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
 | 
			
		||||
	public AreaMarkerValues(String label, String world, double[] x, double[] z, String description, DynmapStyle style)
 | 
			
		||||
	{
 | 
			
		||||
		this(label, world, x, z, description, style.getLineColor(), style.getLineOpacity(), style.getLineWeight(), style.getFillColor(), style.getFillOpacity(), style.getBoost());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public AreaMarkerValues(String label, String world, double[] x, double[] z, String description, int lineColor, double lineOpacity, int lineWeight, int fillColor, double fillOpacity, boolean boost)
 | 
			
		||||
	{
 | 
			
		||||
		this.label = label;
 | 
			
		||||
		this.world = world;
 | 
			
		||||
		this.x = x;
 | 
			
		||||
		this.z = z;
 | 
			
		||||
		this.description = description;
 | 
			
		||||
		this.lineColor = lineColor;
 | 
			
		||||
		this.lineOpacity = lineOpacity;
 | 
			
		||||
		this.lineWeight = lineWeight;
 | 
			
		||||
		this.fillColor = fillColor;
 | 
			
		||||
		this.fillOpacity = fillOpacity;
 | 
			
		||||
		this.boost = boost;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// MASTER
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
 | 
			
		||||
	public AreaMarker ensureExistsAndUpdated(AreaMarker areaMarker, MarkerAPI markerApi, MarkerSet markerset, String markerId)
 | 
			
		||||
	{
 | 
			
		||||
		// 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.
 | 
			
		||||
		if (areaMarker == null)
 | 
			
		||||
		{
 | 
			
		||||
			areaMarker = create(markerApi, markerset, markerId);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			update(markerApi, markerset, areaMarker);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (areaMarker == null)
 | 
			
		||||
		{
 | 
			
		||||
			EngineDynmap.logSevere("Could not get/create the area marker " + markerId);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return areaMarker;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// CREATE
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	public AreaMarker create(MarkerAPI markerApi, MarkerSet markerset, String markerId)
 | 
			
		||||
	{
 | 
			
		||||
		AreaMarker ret = markerset.createAreaMarker(
 | 
			
		||||
			markerId,
 | 
			
		||||
			this.getLabel(),
 | 
			
		||||
			false,
 | 
			
		||||
			this.getWorld(),
 | 
			
		||||
			this.getX(),
 | 
			
		||||
			this.getZ(),
 | 
			
		||||
			false // not persistent
 | 
			
		||||
		);
 | 
			
		||||
		
 | 
			
		||||
		if (ret == null) return null;
 | 
			
		||||
		
 | 
			
		||||
		// Description
 | 
			
		||||
		ret.setDescription(this.getDescription());
 | 
			
		||||
		
 | 
			
		||||
		// Line Style
 | 
			
		||||
		ret.setLineStyle(this.getLineWeight(), this.getLineOpacity(), this.getLineColor());
 | 
			
		||||
		
 | 
			
		||||
		// Fill Style
 | 
			
		||||
		ret.setFillStyle(this.getFillOpacity(), this.getFillColor());
 | 
			
		||||
		
 | 
			
		||||
		// Boost Flag
 | 
			
		||||
		ret.setBoostFlag(this.isBoost());
 | 
			
		||||
		
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// UPDATE
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	public void update(MarkerAPI markerApi, MarkerSet markerset, AreaMarker marker)
 | 
			
		||||
	{
 | 
			
		||||
		// Corner Locations
 | 
			
		||||
		if (!equals(marker, this.x, this.z))
 | 
			
		||||
		{
 | 
			
		||||
			marker.setCornerLocations(this.x, this.z);			
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// Label
 | 
			
		||||
		MUtil.setIfDifferent(this.getLabel(), marker::getLabel, marker::setLabel);
 | 
			
		||||
		
 | 
			
		||||
		// Description
 | 
			
		||||
		MUtil.setIfDifferent(this.getDescription(), marker::getDescription, marker::setDescription);
 | 
			
		||||
		
 | 
			
		||||
		// Line Style
 | 
			
		||||
		if
 | 
			
		||||
		(
 | 
			
		||||
			!MUtil.equals(marker.getLineWeight(), this.lineWeight)
 | 
			
		||||
			||
 | 
			
		||||
			!MUtil.equals(marker.getLineOpacity(), this.lineOpacity)
 | 
			
		||||
			||
 | 
			
		||||
			!MUtil.equals(marker.getLineColor(), this.lineColor)
 | 
			
		||||
		)
 | 
			
		||||
		{
 | 
			
		||||
			marker.setLineStyle(this.lineWeight, this.lineOpacity, this.lineColor);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// Fill Style
 | 
			
		||||
		if
 | 
			
		||||
		(
 | 
			
		||||
			!MUtil.equals(marker.getFillOpacity(), this.fillOpacity)
 | 
			
		||||
			||
 | 
			
		||||
			!MUtil.equals(marker.getFillColor(), this.fillColor)
 | 
			
		||||
		)
 | 
			
		||||
		{
 | 
			
		||||
			marker.setFillStyle(this.fillOpacity, this.fillColor);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// Boost Flag
 | 
			
		||||
		MUtil.setIfDifferent(this.isBoost(), marker::getBoostFlag, marker::setBoostFlag);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// UTIL
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	public static boolean equals(AreaMarker marker, double[] x, double[] z)
 | 
			
		||||
	{
 | 
			
		||||
		int length = marker.getCornerCount();
 | 
			
		||||
		
 | 
			
		||||
		if (x.length != length) return false;
 | 
			
		||||
		if (z.length != length) return false;
 | 
			
		||||
		
 | 
			
		||||
		for (int i = 0; i < length; i++)
 | 
			
		||||
		{
 | 
			
		||||
			if (marker.getCornerX(i) != x[i]) return false;
 | 
			
		||||
			if (marker.getCornerZ(i) != z[i]) return false;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,90 @@
 | 
			
		||||
package com.massivecraft.factions.integration.dynmap;
 | 
			
		||||
 | 
			
		||||
import com.massivecraft.factions.entity.MConf;
 | 
			
		||||
 | 
			
		||||
public class DynmapStyle
 | 
			
		||||
{
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// FIELDS
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	public final String lineColor;
 | 
			
		||||
	public int getLineColor() { return getColor(coalesce(this.lineColor, MConf.get().dynmapDefaultStyle.lineColor, IntegrationDynmap.DYNMAP_STYLE_LINE_COLOR)); }
 | 
			
		||||
	public DynmapStyle withLineColor(String lineColor) { return new DynmapStyle(lineColor, lineOpacity, lineWeight, fillColor, fillOpacity, homeMarker, boost); }
 | 
			
		||||
	
 | 
			
		||||
	public final Double lineOpacity;
 | 
			
		||||
	public double getLineOpacity() { return coalesce(this.lineOpacity, MConf.get().dynmapDefaultStyle.lineOpacity, IntegrationDynmap.DYNMAP_STYLE_LINE_OPACITY); }
 | 
			
		||||
	public DynmapStyle withLineOpacity(Double lineOpacity) { return new DynmapStyle(lineColor, lineOpacity, lineWeight, fillColor, fillOpacity, homeMarker, boost); }
 | 
			
		||||
	
 | 
			
		||||
	public final Integer lineWeight;
 | 
			
		||||
	public int getLineWeight() { return coalesce(this.lineWeight, MConf.get().dynmapDefaultStyle.lineWeight, IntegrationDynmap.DYNMAP_STYLE_LINE_WEIGHT); }
 | 
			
		||||
	public DynmapStyle withLineWeight(Integer lineWeight) { return new DynmapStyle(lineColor, lineOpacity, lineWeight, fillColor, fillOpacity, homeMarker, boost); }
 | 
			
		||||
	
 | 
			
		||||
	public final String fillColor;
 | 
			
		||||
	public int getFillColor() { return getColor(coalesce(this.fillColor, MConf.get().dynmapDefaultStyle.fillColor, IntegrationDynmap.DYNMAP_STYLE_FILL_COLOR)); }
 | 
			
		||||
	public DynmapStyle withFillColor(String fillColor) { return new DynmapStyle(lineColor, lineOpacity, lineWeight, fillColor, fillOpacity, homeMarker, boost); }
 | 
			
		||||
	
 | 
			
		||||
	public final Double fillOpacity;
 | 
			
		||||
	public double getFillOpacity() { return coalesce(this.fillOpacity, MConf.get().dynmapDefaultStyle.fillOpacity, IntegrationDynmap.DYNMAP_STYLE_FILL_OPACITY); }
 | 
			
		||||
	public DynmapStyle withFillOpacity(Double fillOpacity) { return new DynmapStyle(lineColor, lineOpacity, lineWeight, fillColor, fillOpacity, homeMarker, boost); }
 | 
			
		||||
	
 | 
			
		||||
	// NOTE: We just return the string here. We do not return the resolved Dynmap MarkerIcon object.
 | 
			
		||||
	// The reason is we use this class in the MConf. For serialization to work Dynmap would have to be loaded and we can't require that.
 | 
			
		||||
	// Using dynmap is optional.
 | 
			
		||||
	public final String homeMarker;
 | 
			
		||||
	public String getHomeMarker() { return coalesce(this.homeMarker, MConf.get().dynmapDefaultStyle.homeMarker, IntegrationDynmap.DYNMAP_STYLE_HOME_MARKER); }
 | 
			
		||||
	public DynmapStyle withHomeMarker(String homeMarker) { return new DynmapStyle(lineColor, lineOpacity, lineWeight, fillColor, fillOpacity, homeMarker, boost); }
 | 
			
		||||
	
 | 
			
		||||
	public final Boolean boost;
 | 
			
		||||
	public boolean getBoost() { return coalesce(this.boost, MConf.get().dynmapDefaultStyle.boost, IntegrationDynmap.DYNMAP_STYLE_BOOST); }
 | 
			
		||||
	public DynmapStyle withBoost(Boolean boost) { return new DynmapStyle(lineColor, lineOpacity, lineWeight, fillColor, fillOpacity, homeMarker, boost); }
 | 
			
		||||
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// CONSTRUCTOR
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
 | 
			
		||||
	public DynmapStyle()
 | 
			
		||||
	{
 | 
			
		||||
		this(null, null, null, null, null, null, null);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public DynmapStyle(String lineColor, Double lineOpacity, Integer lineWeight, String fillColor, Double fillOpacity, String homeMarker, Boolean boost)
 | 
			
		||||
	{
 | 
			
		||||
		this.lineColor = lineColor;
 | 
			
		||||
		this.lineOpacity = lineOpacity;
 | 
			
		||||
		this.lineWeight = lineWeight;
 | 
			
		||||
		this.fillColor = fillColor;
 | 
			
		||||
		this.fillOpacity = fillOpacity;
 | 
			
		||||
		this.homeMarker = homeMarker;
 | 
			
		||||
		this.boost = boost;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// UTIL
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	@SafeVarargs
 | 
			
		||||
	public static <T> T coalesce(T... items)
 | 
			
		||||
	{
 | 
			
		||||
		for (T item : items)
 | 
			
		||||
		{
 | 
			
		||||
			if (item != null) return item;
 | 
			
		||||
		}
 | 
			
		||||
		return null;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public static int getColor(String string)
 | 
			
		||||
	{
 | 
			
		||||
		int ret = 0x00FF00;
 | 
			
		||||
		try
 | 
			
		||||
		{
 | 
			
		||||
			ret = Integer.parseInt(string.substring(1), 16);
 | 
			
		||||
		}
 | 
			
		||||
		catch (NumberFormatException nfx)
 | 
			
		||||
		{
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,691 @@
 | 
			
		||||
package com.massivecraft.factions.integration.dynmap;
 | 
			
		||||
 | 
			
		||||
import com.massivecraft.factions.Factions;
 | 
			
		||||
import com.massivecraft.factions.entity.BoardColl;
 | 
			
		||||
import com.massivecraft.factions.entity.Faction;
 | 
			
		||||
import com.massivecraft.factions.entity.MConf;
 | 
			
		||||
import com.massivecraft.factions.entity.MFlag;
 | 
			
		||||
import com.massivecraft.factions.entity.MPlayer;
 | 
			
		||||
import com.massivecraft.factions.integration.Econ;
 | 
			
		||||
import com.massivecraft.massivecore.Engine;
 | 
			
		||||
import com.massivecraft.massivecore.collections.MassiveList;
 | 
			
		||||
import com.massivecraft.massivecore.collections.MassiveMap;
 | 
			
		||||
import com.massivecraft.massivecore.collections.MassiveSet;
 | 
			
		||||
import com.massivecraft.massivecore.money.Money;
 | 
			
		||||
import com.massivecraft.massivecore.ps.PS;
 | 
			
		||||
import com.massivecraft.massivecore.util.MUtil;
 | 
			
		||||
import com.massivecraft.massivecore.util.TimeDiffUtil;
 | 
			
		||||
import com.massivecraft.massivecore.util.TimeUnit;
 | 
			
		||||
import com.massivecraft.massivecore.util.Txt;
 | 
			
		||||
import org.apache.commons.lang.StringEscapeUtils;
 | 
			
		||||
import org.bukkit.Bukkit;
 | 
			
		||||
import org.bukkit.ChatColor;
 | 
			
		||||
import org.dynmap.DynmapAPI;
 | 
			
		||||
import org.dynmap.markers.AreaMarker;
 | 
			
		||||
import org.dynmap.markers.MarkerAPI;
 | 
			
		||||
import org.dynmap.markers.MarkerSet;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayDeque;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.Iterator;
 | 
			
		||||
import java.util.LinkedHashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Map.Entry;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
import java.util.stream.Stream;
 | 
			
		||||
 | 
			
		||||
public class EngineDynmap extends Engine
 | 
			
		||||
{
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// INSTANCE & CONSTRUCT
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
 | 
			
		||||
	private static EngineDynmap i = new EngineDynmap();
 | 
			
		||||
	public static EngineDynmap get() { return i; }
 | 
			
		||||
	private EngineDynmap()
 | 
			
		||||
	{
 | 
			
		||||
		// Async
 | 
			
		||||
		this.setSync(false);
 | 
			
		||||
 | 
			
		||||
		// Every 15 seconds
 | 
			
		||||
		this.setPeriod(15 * 20L);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// FIELDS
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
 | 
			
		||||
	private DynmapAPI dynmapApi;
 | 
			
		||||
	private MarkerAPI markerApi;
 | 
			
		||||
	private MarkerSet markerset;
 | 
			
		||||
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// RUN: UPDATE
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	// Thread Safe / Asynchronous: Yes
 | 
			
		||||
	@Override
 | 
			
		||||
	public void run()
 | 
			
		||||
	{
 | 
			
		||||
		// Is Dynmap enabled?
 | 
			
		||||
		if (MConf.get().dynmapEnabled)
 | 
			
		||||
		{
 | 
			
		||||
			this.perform();
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			this.disable();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void perform()
 | 
			
		||||
	{
 | 
			
		||||
		long before = System.currentTimeMillis();
 | 
			
		||||
 | 
			
		||||
		// We do what we can here.
 | 
			
		||||
		// You /can/ run this method from the main server thread but it's not recommended at all.
 | 
			
		||||
		// This method is supposed to be run async to avoid locking the main server thread.
 | 
			
		||||
		//final Map<String, TempMarker> homes = createHomes();
 | 
			
		||||
		final Map<String, AreaMarkerValues> areas = createAreas();
 | 
			
		||||
 | 
			
		||||
		logTimeSpent("Async", before);
 | 
			
		||||
 | 
			
		||||
		// Shedule non thread safe sync at the end!
 | 
			
		||||
		Bukkit.getScheduler().scheduleSyncDelayedTask(Factions.get(), () -> this.updateFactionsDynmap(areas));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void updateFactionsDynmap(Map<String, AreaMarkerValues> areas)
 | 
			
		||||
	{
 | 
			
		||||
		long before = System.currentTimeMillis();
 | 
			
		||||
 | 
			
		||||
		if (!Bukkit.isPrimaryThread()) throw new IllegalStateException("async");
 | 
			
		||||
 | 
			
		||||
		if (!fetchDynmapAPI()) return;
 | 
			
		||||
 | 
			
		||||
		// createLayer() is thread safe but it makes use of fields set in fetchDynmapAPI() so we must have it after.
 | 
			
		||||
		if (!updateLayer(createLayer())) return;
 | 
			
		||||
 | 
			
		||||
		updateAreas(areas);
 | 
			
		||||
 | 
			
		||||
		logTimeSpent("Sync", before);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void disable()
 | 
			
		||||
	{
 | 
			
		||||
		if (this.markerset != null)
 | 
			
		||||
		{
 | 
			
		||||
			this.markerset.deleteMarkerSet();
 | 
			
		||||
			this.markerset = null;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// Thread Safe / Asynchronous: Yes
 | 
			
		||||
	public static void logTimeSpent(String name, long start)
 | 
			
		||||
	{
 | 
			
		||||
		if (!MConf.get().dynmapLogTimeSpent) return;
 | 
			
		||||
		long end = System.currentTimeMillis();
 | 
			
		||||
		long duration = end-start;
 | 
			
		||||
 | 
			
		||||
		String message = Txt.parse("<i>Dynmap %s took <h>%dms<i>.", name, duration);
 | 
			
		||||
		Factions.get().log(message);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// API
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	// Thread Safe / Asynchronous: No
 | 
			
		||||
	public boolean fetchDynmapAPI()
 | 
			
		||||
	{
 | 
			
		||||
		// Get DynmapAPI
 | 
			
		||||
		this.dynmapApi = (DynmapAPI) Bukkit.getPluginManager().getPlugin("dynmap");
 | 
			
		||||
		if (this.dynmapApi == null)
 | 
			
		||||
		{
 | 
			
		||||
			logSevere("Could not access the DynmapAPI.");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// Get MarkerAPI
 | 
			
		||||
		this.markerApi = this.dynmapApi.getMarkerAPI();
 | 
			
		||||
		if (this.markerApi == null)
 | 
			
		||||
		{
 | 
			
		||||
			logSevere("Could not access the MarkerAPI.");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// UPDATE: Layer
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	// Thread Safe / Asynchronous: Yes
 | 
			
		||||
	public LayerValues createLayer()
 | 
			
		||||
	{
 | 
			
		||||
		return new LayerValues(
 | 
			
		||||
			MConf.get().dynmapLayerName,
 | 
			
		||||
			MConf.get().dynmapLayerMinimumZoom,
 | 
			
		||||
			MConf.get().dynmapLayerPriority,
 | 
			
		||||
			MConf.get().dynmapLayerHiddenByDefault
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// Thread Safe / Asynchronous: No
 | 
			
		||||
	public boolean updateLayer(LayerValues temp)
 | 
			
		||||
	{
 | 
			
		||||
		this.markerset = temp.ensureExistsAndUpdated(this.markerApi, IntegrationDynmap.FACTIONS_MARKERSET);
 | 
			
		||||
		return this.markerset != null;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// UPDATE: AREAS
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	// Thread Safe: YES
 | 
			
		||||
	public Map<String, AreaMarkerValues> createAreas()
 | 
			
		||||
	{
 | 
			
		||||
		Map<String, Map<Faction, Set<PS>>> worldFactionChunks = BoardColl.get().getWorldToFactionToChunks(false);
 | 
			
		||||
		return createAreas(worldFactionChunks);
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// Thread Safe: YES
 | 
			
		||||
	public Map<String, AreaMarkerValues> createAreas(Map<String, Map<Faction, Set<PS>>> worldFactionChunks)
 | 
			
		||||
	{
 | 
			
		||||
		// For each world create the areas
 | 
			
		||||
		return worldFactionChunks.entrySet().stream()
 | 
			
		||||
			.map(this::createAreas)
 | 
			
		||||
			// And combine all of those into a single map:
 | 
			
		||||
			.map(Map::entrySet)
 | 
			
		||||
			.flatMap(Set::stream)
 | 
			
		||||
			.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public Map<String, AreaMarkerValues> createAreas(Entry<String, Map<Faction, Set<PS>>> superEntry)
 | 
			
		||||
	{
 | 
			
		||||
		return createAreas(superEntry.getKey(), superEntry.getValue());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public Map<String, AreaMarkerValues> createAreas(String world, Map<Faction, Set<PS>> map)
 | 
			
		||||
	{
 | 
			
		||||
		// For each entry convert it into the appropriate map (with method below)
 | 
			
		||||
		return map.entrySet().stream()
 | 
			
		||||
			.map(e -> createAreas(world, e))
 | 
			
		||||
			// And combine all of those into a single map:
 | 
			
		||||
			.map(Map::entrySet)
 | 
			
		||||
			.flatMap(Set::stream)
 | 
			
		||||
			.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public Map<String, AreaMarkerValues> createAreas(String world, Entry<Faction, Set<PS>> entry)
 | 
			
		||||
	{
 | 
			
		||||
		return createAreas(world, entry.getKey(), entry.getValue());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public Map<String, AreaMarkerValues> createAreas(String world, Faction faction, Set<PS> chunks)
 | 
			
		||||
	{
 | 
			
		||||
		// If the faction is visible ...
 | 
			
		||||
		if (!isVisible(faction, world)) return Collections.emptyMap();
 | 
			
		||||
 | 
			
		||||
		// ... and has any chunks ...
 | 
			
		||||
		if (chunks.isEmpty()) return Collections.emptyMap();
 | 
			
		||||
 | 
			
		||||
		Map<String, AreaMarkerValues> ret = new MassiveMap<>();
 | 
			
		||||
 | 
			
		||||
		// Get info
 | 
			
		||||
		String description = getDescription(faction);
 | 
			
		||||
		DynmapStyle style = this.getStyle(faction);
 | 
			
		||||
		
 | 
			
		||||
		// Here we start of with all chunks
 | 
			
		||||
		// This field is slowly cleared when the chunks are grouped into polygons
 | 
			
		||||
		Set<PS> allChunksSource = new MassiveSet<>(chunks);
 | 
			
		||||
 | 
			
		||||
		while (!allChunksSource.isEmpty())
 | 
			
		||||
		{
 | 
			
		||||
			PS somePs = allChunksSource.iterator().next();
 | 
			
		||||
 | 
			
		||||
			// Create the polygon
 | 
			
		||||
			Set<PS> polygonChunks = new MassiveSet<>();
 | 
			
		||||
			floodFillTarget(allChunksSource, polygonChunks, somePs);
 | 
			
		||||
			List<PS> linelist = getLineList(polygonChunks);
 | 
			
		||||
 | 
			
		||||
			// Calc the x and y arrays
 | 
			
		||||
			int sz = linelist.size();
 | 
			
		||||
			double[] x = new double[sz];
 | 
			
		||||
			double[] z = new double[sz];
 | 
			
		||||
 | 
			
		||||
			int i = 0;
 | 
			
		||||
			for (PS ps : linelist)
 | 
			
		||||
			{
 | 
			
		||||
				x[i] = ps.getLocationX(true);
 | 
			
		||||
				z[i] = ps.getLocationZ(true);
 | 
			
		||||
				i++;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Build information for specific area
 | 
			
		||||
			String markerId = calcMarkerId(world, faction);
 | 
			
		||||
			AreaMarkerValues values = new AreaMarkerValues(faction.getName(), world, x, z, description, style);
 | 
			
		||||
			ret.put(markerId, values);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static PS getMinimum(Collection<PS> pss)
 | 
			
		||||
	{
 | 
			
		||||
		int minimumX = Integer.MAX_VALUE;
 | 
			
		||||
		int minimumZ = Integer.MAX_VALUE;
 | 
			
		||||
 | 
			
		||||
		for (PS chunk : pss)
 | 
			
		||||
		{
 | 
			
		||||
			int chunkX = chunk.getChunkX();
 | 
			
		||||
			int chunkZ = chunk.getChunkZ();
 | 
			
		||||
 | 
			
		||||
			if (chunkX < minimumX)
 | 
			
		||||
			{
 | 
			
		||||
				minimumX = chunkX;
 | 
			
		||||
				minimumZ = chunkZ;
 | 
			
		||||
			}
 | 
			
		||||
			else if (chunkX == minimumX && chunkZ < minimumZ)
 | 
			
		||||
			{
 | 
			
		||||
				minimumZ = chunkZ;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return PS.valueOf(minimumX, minimumZ);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// XPLUS, ZPLUS, XMINUS, ZMINUS
 | 
			
		||||
	private static List<PS> getLineList(Set<PS> polygonChunks)
 | 
			
		||||
	{
 | 
			
		||||
		PS minimumChunk = getMinimum(polygonChunks);
 | 
			
		||||
 | 
			
		||||
		//final int initialX = minimumChunk.getChunkX();
 | 
			
		||||
		//final int initialZ = minimumChunk.getChunkZ();
 | 
			
		||||
		//int currentX = initialX;
 | 
			
		||||
		//int currentZ = initialZ;
 | 
			
		||||
 | 
			
		||||
		PS currentChunk = minimumChunk;
 | 
			
		||||
 | 
			
		||||
		Direction direction = Direction.XPLUS;
 | 
			
		||||
		List<PS> linelist = new MassiveList<>();
 | 
			
		||||
 | 
			
		||||
		linelist.add(minimumChunk); // Add start point
 | 
			
		||||
		while ((!currentChunk.equals(minimumChunk)) || (direction != Direction.ZMINUS))
 | 
			
		||||
		{
 | 
			
		||||
			PS adjacent = direction.adjacent(currentChunk);
 | 
			
		||||
			PS corner = direction.getCorner(currentChunk);
 | 
			
		||||
			// If the adjacent chunk is not present
 | 
			
		||||
 | 
			
		||||
			if (!polygonChunks.contains(adjacent))
 | 
			
		||||
			{ // Right turn?
 | 
			
		||||
				linelist.add(corner); // Finish line
 | 
			
		||||
				direction = direction.turnRight(); // Change direction
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// If the chunk left of the adjacent is not present
 | 
			
		||||
			else if (!polygonChunks.contains(direction.turnLeft().adjacent(adjacent)))
 | 
			
		||||
			{ // Straight?
 | 
			
		||||
				currentChunk = adjacent;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			else
 | 
			
		||||
			{ // Left turn
 | 
			
		||||
				linelist.add(corner); // Finish line
 | 
			
		||||
				direction = direction.turnLeft();
 | 
			
		||||
 | 
			
		||||
				// Left turn of adjacent
 | 
			
		||||
				currentChunk = direction.adjacent(adjacent);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return linelist;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// IS CLAIMED
 | 
			
		||||
 | 
			
		||||
	private static boolean isSoutheastClaimed(PS ps, Collection<PS> polygon)
 | 
			
		||||
	{
 | 
			
		||||
		return polygon.contains(PS.valueOf(ps.getChunkX() - 1, ps.getChunkZ() + 1));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static boolean isNortheastClaimed(PS ps, Collection<PS> polygon)
 | 
			
		||||
	{
 | 
			
		||||
		return polygon.contains(PS.valueOf(ps.getChunkX() + 1, ps.getChunkZ() + 1));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static boolean isSouthwestClaimed(PS ps, Collection<PS> polygon)
 | 
			
		||||
	{
 | 
			
		||||
		return polygon.contains(PS.valueOf(ps.getChunkX() - 1, ps.getChunkZ() - 1));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static boolean isNorthwestClaimed(PS ps, Collection<PS> polygon)
 | 
			
		||||
	{
 | 
			
		||||
		return polygon.contains(PS.valueOf(ps.getChunkX() + 1, ps.getChunkZ() - 1));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// GET CHUNKS
 | 
			
		||||
 | 
			
		||||
	private static PS getNortheastPS(PS ps)
 | 
			
		||||
	{
 | 
			
		||||
		return PS.valueOf(ps.getChunkX() + 1, ps.getChunkZ() + 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static PS getSoutheastPS(PS ps)
 | 
			
		||||
	{
 | 
			
		||||
		return PS.valueOf(ps.getChunkX(), ps.getChunkZ() + 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static PS getSouthwestPS(PS ps)
 | 
			
		||||
	{
 | 
			
		||||
		return PS.valueOf(ps.getChunkX(), ps.getChunkZ());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static PS getNorthwestPS(PS ps)
 | 
			
		||||
	{
 | 
			
		||||
		return PS.valueOf(ps.getChunkX() + 1, ps.getChunkZ());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// This markerIndex, is if a faction has several claims in a single world
 | 
			
		||||
	private int markerIdx = 0;
 | 
			
		||||
	private String lastPartialMarkerId = "";
 | 
			
		||||
	public String calcMarkerId(String world, Faction faction)
 | 
			
		||||
	{
 | 
			
		||||
		// Calc current partial
 | 
			
		||||
		String partial = IntegrationDynmap.FACTIONS_AREA_ + world + "__" + faction.getId() + "__";
 | 
			
		||||
 | 
			
		||||
		// If different than last time, then reset the counter
 | 
			
		||||
		if (!partial.equals(lastPartialMarkerId)) markerIdx = 0;
 | 
			
		||||
 | 
			
		||||
		this.lastPartialMarkerId = partial;
 | 
			
		||||
 | 
			
		||||
		return partial + markerIdx++;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// Thread Safe: NO
 | 
			
		||||
	public void updateAreas(Map<String, AreaMarkerValues> values)
 | 
			
		||||
	{
 | 
			
		||||
		// Cleanup old markers
 | 
			
		||||
		this.markerset.getAreaMarkers().stream() // Get current markers
 | 
			
		||||
			.filter(am -> !values.containsKey(am.getMarkerID())) // That are not in the new map
 | 
			
		||||
			.forEach(AreaMarker::deleteMarker); // and delete them
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		// Map Current
 | 
			
		||||
		Map<String, AreaMarker> markers = getMarkerMap(this.markerset);
 | 
			
		||||
 | 
			
		||||
		// Loop New
 | 
			
		||||
		values.forEach((markerId, value) ->
 | 
			
		||||
						  value.ensureExistsAndUpdated(markers.get(markerId), this.markerApi, this.markerset, markerId));
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static Map<String, AreaMarker> getMarkerMap(MarkerSet markerSet)
 | 
			
		||||
	{
 | 
			
		||||
		return markerSet.getAreaMarkers().stream().collect(Collectors.toMap(AreaMarker::getMarkerID, m->m));
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// UTIL & SHARED
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	// Thread Safe / Asynchronous: Yes
 | 
			
		||||
	private String getDescription(Faction faction)
 | 
			
		||||
	{
 | 
			
		||||
		String ret = "<div class=\"regioninfo\">" + MConf.get().dynmapFactionDescription + "</div>";
 | 
			
		||||
		
 | 
			
		||||
		// Name
 | 
			
		||||
		String name = faction.getName();
 | 
			
		||||
		ret = addToHtml(ret, "name", name);
 | 
			
		||||
		
 | 
			
		||||
		// Description
 | 
			
		||||
		String description = faction.getDescriptionDesc();
 | 
			
		||||
		ret = addToHtml(ret, "description", description);
 | 
			
		||||
 | 
			
		||||
		// MOTD (probably shouldn't be shown but if the server owner specifies it, I don't care)
 | 
			
		||||
		String motd = faction.getMotd();
 | 
			
		||||
		if (motd != null) ret = addToHtml(ret, "motd", motd);
 | 
			
		||||
		
 | 
			
		||||
		// Age
 | 
			
		||||
		long ageMillis = faction.getAge();
 | 
			
		||||
		LinkedHashMap<TimeUnit, Long> ageUnitcounts = TimeDiffUtil.limit(TimeDiffUtil.unitcounts(ageMillis, TimeUnit.getAllButMillisSecondsAndMinutes()), 3);
 | 
			
		||||
		String age = TimeDiffUtil.formatedVerboose(ageUnitcounts, "");
 | 
			
		||||
		ret = addToHtml(ret, "age", age);
 | 
			
		||||
		
 | 
			
		||||
		// Money
 | 
			
		||||
		String money = "unavailable";
 | 
			
		||||
		if (Econ.isEnabled() && MConf.get().dynmapShowMoneyInDescription)
 | 
			
		||||
		{
 | 
			
		||||
			money = Money.format(Econ.getMoney(faction));
 | 
			
		||||
		}
 | 
			
		||||
		ret = addToHtml(ret, "money", money);
 | 
			
		||||
		
 | 
			
		||||
		// Flags
 | 
			
		||||
		Map<MFlag, Boolean> flags = MFlag.getAll().stream()
 | 
			
		||||
			.filter(MFlag::isVisible)
 | 
			
		||||
			.collect(Collectors.toMap(m -> m, faction::getFlag));
 | 
			
		||||
 | 
			
		||||
		List<String> flagMapParts = new MassiveList<>();
 | 
			
		||||
		List<String> flagTableParts = new MassiveList<>();
 | 
			
		||||
		
 | 
			
		||||
		for (Entry<MFlag, Boolean> entry : flags.entrySet())
 | 
			
		||||
		{
 | 
			
		||||
			String flagName = entry.getKey().getName();
 | 
			
		||||
			boolean value = entry.getValue();
 | 
			
		||||
 | 
			
		||||
			String bool = String.valueOf(value);
 | 
			
		||||
			String color = calcBoolcolor(flagName, value);
 | 
			
		||||
			String boolcolor = calcBoolcolor(String.valueOf(value), value);
 | 
			
		||||
			
 | 
			
		||||
			ret = ret.replace("%" + flagName + ".bool%", bool); // true
 | 
			
		||||
			ret = ret.replace("%" + flagName + ".color%", color); // monsters (red or green)
 | 
			
		||||
			ret = ret.replace("%" + flagName + ".boolcolor%", boolcolor); // true (red or green)
 | 
			
		||||
 | 
			
		||||
			flagMapParts.add(flagName + ": " + boolcolor);
 | 
			
		||||
			flagTableParts.add(color);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		String flagMap = Txt.implode(flagMapParts, "<br>\n");
 | 
			
		||||
		ret = ret.replace("%flags.map%", flagMap);
 | 
			
		||||
 | 
			
		||||
		// The server can specify the wished number of columns
 | 
			
		||||
		// So we loop over the possibilities
 | 
			
		||||
		for (int cols = 1; cols <= 10; cols++)
 | 
			
		||||
		{
 | 
			
		||||
			String flagTable = getHtmlAsciTable(flagTableParts, cols);
 | 
			
		||||
			ret = ret.replace("%flags.table" + cols + "%", flagTable);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// Players
 | 
			
		||||
		List<MPlayer> playersList = faction.getMPlayers();
 | 
			
		||||
		String playersCount = String.valueOf(playersList.size());
 | 
			
		||||
		String players = getHtmlPlayerString(playersList);
 | 
			
		||||
		
 | 
			
		||||
		MPlayer playersLeaderObject = faction.getLeader();
 | 
			
		||||
		String playersLeader = getHtmlPlayerName(playersLeaderObject);
 | 
			
		||||
		
 | 
			
		||||
		ret = ret.replace("%players%", players);
 | 
			
		||||
		ret = ret.replace("%players.count%", playersCount);
 | 
			
		||||
		ret = ret.replace("%players.leader%", playersLeader);
 | 
			
		||||
		
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static String getHtmlAsciTable(Collection<String> strings, final int cols)
 | 
			
		||||
	{
 | 
			
		||||
		StringBuilder ret = new StringBuilder();
 | 
			
		||||
		
 | 
			
		||||
		int count = 0;
 | 
			
		||||
		for (Iterator<String> iter = strings.iterator(); iter.hasNext();)
 | 
			
		||||
		{
 | 
			
		||||
			String string = iter.next();
 | 
			
		||||
			count++;
 | 
			
		||||
			
 | 
			
		||||
			ret.append(string);
 | 
			
		||||
 | 
			
		||||
			if (iter.hasNext())
 | 
			
		||||
			{
 | 
			
		||||
				boolean lineBreak = count % cols == 0;
 | 
			
		||||
				ret.append(lineBreak ? "<br>" : " | ");
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		return ret.toString();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public static String getHtmlPlayerString(List<MPlayer> mplayers)
 | 
			
		||||
	{
 | 
			
		||||
		List<String> names = mplayers.stream().map(EngineDynmap::getHtmlPlayerName).collect(Collectors.toList());
 | 
			
		||||
		return Txt.implodeCommaAndDot(names);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public static String getHtmlPlayerName(MPlayer mplayer)
 | 
			
		||||
	{
 | 
			
		||||
		if (mplayer == null) return "none";
 | 
			
		||||
		return StringEscapeUtils.escapeHtml(mplayer.getName());
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public static String calcBoolcolor(String string, boolean bool)
 | 
			
		||||
	{
 | 
			
		||||
		return "<span style=\"color: " + (bool ? "#008000" : "#800000") + ";\">" + string + "</span>";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static String addToHtml(String ret, String target, String replace)
 | 
			
		||||
	{
 | 
			
		||||
		if (ret == null) throw new NullPointerException("ret");
 | 
			
		||||
		if (target == null) throw new NullPointerException("target");
 | 
			
		||||
		if (replace == null) throw new NullPointerException("replace");
 | 
			
		||||
 | 
			
		||||
		target = "%" + target + "%";
 | 
			
		||||
		replace = ChatColor.stripColor(replace);
 | 
			
		||||
		replace = StringEscapeUtils.escapeHtml(replace);
 | 
			
		||||
		return ret.replace(target, replace);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Thread Safe / Asynchronous: Yes
 | 
			
		||||
	private boolean isVisible(Faction faction, String world)
 | 
			
		||||
	{
 | 
			
		||||
		if (faction == null) throw new NullPointerException("faction");
 | 
			
		||||
		if (world == null) throw new NullPointerException("world");
 | 
			
		||||
 | 
			
		||||
		final String factionId = faction.getId();
 | 
			
		||||
		final String factionName = faction.getName();
 | 
			
		||||
		final String worldId =  "world:" + world;
 | 
			
		||||
 | 
			
		||||
		Set<String> ids = MUtil.set(factionId, factionName, worldId);
 | 
			
		||||
 | 
			
		||||
		if (factionId == null) throw new NullPointerException("faction id");
 | 
			
		||||
		if (factionName == null) throw new NullPointerException("faction name");
 | 
			
		||||
		
 | 
			
		||||
		Set<String> visible = MConf.get().dynmapVisibleFactions;
 | 
			
		||||
		Set<String> hidden = MConf.get().dynmapHiddenFactions;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		if (!visible.isEmpty() && visible.stream().noneMatch(ids::contains))
 | 
			
		||||
		{
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!hidden.isEmpty() && hidden.stream().anyMatch(ids::contains))
 | 
			
		||||
		{
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// Thread Safe / Asynchronous: Yes
 | 
			
		||||
	public DynmapStyle getStyle(Faction faction)
 | 
			
		||||
	{
 | 
			
		||||
		Map<String, DynmapStyle> styles = MConf.get().dynmapFactionStyles;
 | 
			
		||||
 | 
			
		||||
		return DynmapStyle.coalesce(
 | 
			
		||||
			styles.get(faction.getId()),
 | 
			
		||||
			styles.get(faction.getName()),
 | 
			
		||||
			MConf.get().dynmapDefaultStyle
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static void logSevere(String msg)
 | 
			
		||||
	{
 | 
			
		||||
		String message = ChatColor.RED.toString() + msg;
 | 
			
		||||
		Factions.get().log(message);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	enum Direction
 | 
			
		||||
	{
 | 
			
		||||
		XPLUS, ZPLUS, XMINUS, ZMINUS
 | 
			
		||||
 | 
			
		||||
		;
 | 
			
		||||
 | 
			
		||||
		public PS adjacent(PS ps)
 | 
			
		||||
		{
 | 
			
		||||
			switch (this)
 | 
			
		||||
			{
 | 
			
		||||
				case XPLUS: return PS.valueOf(ps.getChunkX() + 1, ps.getChunkZ());
 | 
			
		||||
				case ZPLUS: return PS.valueOf(ps.getChunkX(), ps.getChunkZ() + 1);
 | 
			
		||||
				case XMINUS: return PS.valueOf(ps.getChunkX() - 1, ps.getChunkZ());
 | 
			
		||||
				case ZMINUS: return PS.valueOf(ps.getChunkX(), ps.getChunkZ() - 1);
 | 
			
		||||
			}
 | 
			
		||||
			throw new RuntimeException("say what");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public PS getCorner(PS ps)
 | 
			
		||||
		{
 | 
			
		||||
			switch (this)
 | 
			
		||||
			{
 | 
			
		||||
				case XPLUS: return PS.valueOf(ps.getChunkX() + 1, ps.getChunkZ());
 | 
			
		||||
				case ZPLUS: return PS.valueOf(ps.getChunkX() + 1, ps.getChunkZ() + 1);
 | 
			
		||||
				case XMINUS: return PS.valueOf(ps.getChunkX(), ps.getChunkZ() + 1);
 | 
			
		||||
				case ZMINUS: return PS.valueOf(ps.getChunkX(), ps.getChunkZ());
 | 
			
		||||
			}
 | 
			
		||||
			throw new RuntimeException("say what");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public Direction turnRight()
 | 
			
		||||
		{
 | 
			
		||||
			return values()[(this.ordinal() + 1) % values().length];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public Direction turnAround()
 | 
			
		||||
		{
 | 
			
		||||
			return this.turnRight().turnRight();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public Direction turnLeft()
 | 
			
		||||
		{
 | 
			
		||||
			return this.turnRight().turnRight().turnRight();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void floodFillTarget(Collection<PS> source, Collection<PS> destination, PS startChunk)
 | 
			
		||||
	{
 | 
			
		||||
		// Create the deque
 | 
			
		||||
		ArrayDeque<PS> stack = new ArrayDeque<>();
 | 
			
		||||
		stack.push(startChunk);
 | 
			
		||||
 | 
			
		||||
		// And for each item in the queue
 | 
			
		||||
		while (!stack.isEmpty())
 | 
			
		||||
		{
 | 
			
		||||
			PS next = stack.pop();
 | 
			
		||||
 | 
			
		||||
			// If it is in the source
 | 
			
		||||
			// Remove it from there to avoid double-counting (and endless recursion)
 | 
			
		||||
			if (!source.remove(next)) continue;
 | 
			
		||||
 | 
			
		||||
			// Add to destination
 | 
			
		||||
			destination.add(next);
 | 
			
		||||
 | 
			
		||||
			// And look in adjacent chunks that are within the source
 | 
			
		||||
			Stream.of(Direction.values())
 | 
			
		||||
				.map(d -> d.adjacent(next))
 | 
			
		||||
				.filter(source::contains)
 | 
			
		||||
				.forEach(stack::push);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
package com.massivecraft.factions.integration.dynmap;
 | 
			
		||||
 | 
			
		||||
import com.massivecraft.factions.integration.worldguard.EngineWorldGuard;
 | 
			
		||||
import com.massivecraft.massivecore.Engine;
 | 
			
		||||
import com.massivecraft.massivecore.Integration;
 | 
			
		||||
 | 
			
		||||
public class IntegrationDynmap extends Integration
 | 
			
		||||
{
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// CONSTANTS
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
 | 
			
		||||
	// Constants must be here rather than in EngineDynmap.
 | 
			
		||||
	// MConf relies on DynmapStyle which relies on these constants
 | 
			
		||||
	// and we must be able to load MConf without EngineDynmap.
 | 
			
		||||
	public final static int BLOCKS_PER_CHUNK = 16;
 | 
			
		||||
 | 
			
		||||
	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_AREA = FACTIONS_ + "area";
 | 
			
		||||
	public final static String FACTIONS_AREA_ = FACTIONS_AREA + "_";
 | 
			
		||||
 | 
			
		||||
	public final static transient String DYNMAP_STYLE_LINE_COLOR = "#00FF00";
 | 
			
		||||
	public final static transient double DYNMAP_STYLE_LINE_OPACITY = 0.8D;
 | 
			
		||||
	public final static transient int DYNMAP_STYLE_LINE_WEIGHT = 3;
 | 
			
		||||
	public final static transient String DYNMAP_STYLE_FILL_COLOR = "#00FF00";
 | 
			
		||||
	public final static transient double DYNMAP_STYLE_FILL_OPACITY = 0.35D;
 | 
			
		||||
	public final static transient String DYNMAP_STYLE_HOME_MARKER = "greenflag";
 | 
			
		||||
	public final static transient boolean DYNMAP_STYLE_BOOST = false;
 | 
			
		||||
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// INSTANCE & CONSTRUCT
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
 | 
			
		||||
	private static IntegrationDynmap i = new IntegrationDynmap();
 | 
			
		||||
	public static IntegrationDynmap get() { return i; }
 | 
			
		||||
	private IntegrationDynmap()
 | 
			
		||||
	{
 | 
			
		||||
		this.setPluginName("dynmap");
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// OVERRIDE
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	@Override
 | 
			
		||||
	public Engine getEngine()
 | 
			
		||||
	{
 | 
			
		||||
		return EngineDynmap.get();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,107 @@
 | 
			
		||||
package com.massivecraft.factions.integration.dynmap;
 | 
			
		||||
 | 
			
		||||
import com.massivecraft.massivecore.util.MUtil;
 | 
			
		||||
import org.dynmap.markers.MarkerAPI;
 | 
			
		||||
import org.dynmap.markers.MarkerSet;
 | 
			
		||||
 | 
			
		||||
public class LayerValues
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// FIELDS
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
 | 
			
		||||
	private final String label;
 | 
			
		||||
	public String getLabel() { return label; }
 | 
			
		||||
	public LayerValues withLabel(String label) { return new LayerValues(label, minimumZoom, priority, hiddenByDefault); }
 | 
			
		||||
 | 
			
		||||
	private final int minimumZoom;
 | 
			
		||||
	public int getMinimumZoom() { return minimumZoom; }
 | 
			
		||||
	public LayerValues withMinimumZoom(int minimumZoom) { return new LayerValues(label, minimumZoom, priority, hiddenByDefault); }
 | 
			
		||||
 | 
			
		||||
	private final int priority;
 | 
			
		||||
	public int getPriority() { return priority; }
 | 
			
		||||
	public LayerValues withPriority(int priority) { return new LayerValues(label, minimumZoom, priority, hiddenByDefault); }
 | 
			
		||||
 | 
			
		||||
	private final boolean hiddenByDefault;
 | 
			
		||||
	public boolean isHiddenByDefault() { return hiddenByDefault; }
 | 
			
		||||
	public LayerValues withHidenByDefault(boolean hideByDefault) { return new LayerValues(label, minimumZoom, priority, hideByDefault); }
 | 
			
		||||
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// CONSTRUCTOR
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
 | 
			
		||||
	public LayerValues(String label, int minimumZoom, int priority, boolean hideByDefault)
 | 
			
		||||
	{
 | 
			
		||||
		this.label = label;
 | 
			
		||||
		this.minimumZoom = minimumZoom;
 | 
			
		||||
		this.priority = priority;
 | 
			
		||||
		this.hiddenByDefault = hideByDefault;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// MASTER
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
 | 
			
		||||
	public MarkerSet ensureExistsAndUpdated(MarkerAPI api, String id)
 | 
			
		||||
	{
 | 
			
		||||
		MarkerSet set = api.getMarkerSet(id);
 | 
			
		||||
		if (set == null)
 | 
			
		||||
		{
 | 
			
		||||
			set = this.create(api, id);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			this.update(set);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (set == null)
 | 
			
		||||
		{
 | 
			
		||||
			EngineDynmap.logSevere("Could not create the Faction Markerset/Layer");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return set;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// CREATE
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
 | 
			
		||||
	public MarkerSet create(MarkerAPI markerApi, String id)
 | 
			
		||||
	{
 | 
			
		||||
		MarkerSet ret = markerApi.createMarkerSet(id, this.label, null, false); // ("null, false" at the end means "all icons allowed, not perisistent")
 | 
			
		||||
		if (ret == null) return null;
 | 
			
		||||
 | 
			
		||||
		// Minimum Zoom
 | 
			
		||||
		if (this.minimumZoom > 0)
 | 
			
		||||
		{
 | 
			
		||||
			ret.setMinZoom(this.getMinimumZoom());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Priority
 | 
			
		||||
		ret.setLayerPriority(this.getPriority());
 | 
			
		||||
 | 
			
		||||
		// Hide by Default
 | 
			
		||||
		ret.setHideByDefault(this.isHiddenByDefault());
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// UPDATE
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
 | 
			
		||||
	public void update(MarkerSet markerset)
 | 
			
		||||
	{
 | 
			
		||||
		// Minimum Zoom
 | 
			
		||||
		if (this.minimumZoom > 0)
 | 
			
		||||
		{
 | 
			
		||||
			MUtil.setIfDifferent(this.getMinimumZoom(), markerset::getMinZoom, markerset::setMinZoom);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Set other values
 | 
			
		||||
		MUtil.setIfDifferent(this.getLabel(), markerset::getMarkerSetLabel, markerset::setMarkerSetLabel);
 | 
			
		||||
		MUtil.setIfDifferent(this.getPriority(), markerset::getLayerPriority, markerset::setLayerPriority);
 | 
			
		||||
		MUtil.setIfDifferent(this.isHiddenByDefault(), markerset::getHideByDefault, markerset::setHideByDefault);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,135 @@
 | 
			
		||||
package com.massivecraft.factions.integration.dynmap;
 | 
			
		||||
 | 
			
		||||
import com.massivecraft.massivecore.util.MUtil;
 | 
			
		||||
import org.dynmap.markers.Marker;
 | 
			
		||||
import org.dynmap.markers.MarkerAPI;
 | 
			
		||||
import org.dynmap.markers.MarkerIcon;
 | 
			
		||||
import org.dynmap.markers.MarkerSet;
 | 
			
		||||
 | 
			
		||||
public class MarkerValues
 | 
			
		||||
{
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// FIELDS
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	private final String label;
 | 
			
		||||
	public String getLabel() { return label; }
 | 
			
		||||
	public MarkerValues withLabel(String label) { return new MarkerValues(label, world, x, y, z, iconName, description); }
 | 
			
		||||
 | 
			
		||||
	private final String world;
 | 
			
		||||
	public String getWorld() { return world; }
 | 
			
		||||
	public MarkerValues withWorld(String world) { return new MarkerValues(label, world, x, y, z, iconName, description); }
 | 
			
		||||
 | 
			
		||||
	private final double x;
 | 
			
		||||
	public double getX() { return x; }
 | 
			
		||||
	public MarkerValues withX(double x) { return new MarkerValues(label, world, x, y, z, iconName, description); }
 | 
			
		||||
 | 
			
		||||
	private final double y;
 | 
			
		||||
	public double getY() { return y; }
 | 
			
		||||
	public MarkerValues withY(double y) { return new MarkerValues(label, world, x, y, z, iconName, description); }
 | 
			
		||||
 | 
			
		||||
	private final double z;
 | 
			
		||||
	public double getZ() { return z; }
 | 
			
		||||
	public MarkerValues withZ(double z) { return new MarkerValues(label, world, x, y, z, iconName, description); }
 | 
			
		||||
 | 
			
		||||
	private final String iconName;
 | 
			
		||||
	public String getIconName() { return iconName; }
 | 
			
		||||
	public MarkerValues withIconName(String iconName) { return new MarkerValues(label, world, x, y, z, iconName, description); }
 | 
			
		||||
 | 
			
		||||
	private final String description;
 | 
			
		||||
	public String getDescription() { return description; }
 | 
			
		||||
	public MarkerValues withDescription(String description) { return new MarkerValues(label, world, x, y, z, iconName, description); }
 | 
			
		||||
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// CONSTRUCTOR
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
 | 
			
		||||
	public MarkerValues(String label, String world, double x, double y, double z, String iconName, String description)
 | 
			
		||||
	{
 | 
			
		||||
		this.label = label;
 | 
			
		||||
		this.world = world;
 | 
			
		||||
		this.x = x;
 | 
			
		||||
		this.y = y;
 | 
			
		||||
		this.z = z;
 | 
			
		||||
		this.iconName = iconName;
 | 
			
		||||
		this.description = description;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// MAKE SURE EXISTS
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
 | 
			
		||||
	public Marker ensureExistsAndUpdated(MarkerAPI markerApi,  MarkerSet markerset, String id)
 | 
			
		||||
	{
 | 
			
		||||
		throw new UnsupportedOperationException("todo");
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// CREATE
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	public Marker create(MarkerAPI markerApi, MarkerSet markerset, String markerId)
 | 
			
		||||
	{
 | 
			
		||||
		Marker ret = markerset.createMarker(
 | 
			
		||||
			markerId,
 | 
			
		||||
			this.getLabel(),
 | 
			
		||||
			this.getWorld(),
 | 
			
		||||
			this.getX(),
 | 
			
		||||
			this.getY(),
 | 
			
		||||
			this.getZ(),
 | 
			
		||||
			getMarkerIcon(markerApi, this.getIconName()),
 | 
			
		||||
			false // not persistent
 | 
			
		||||
		);
 | 
			
		||||
		
 | 
			
		||||
		if (ret == null) return null;
 | 
			
		||||
		
 | 
			
		||||
		ret.setDescription(this.getDescription());
 | 
			
		||||
		
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// UPDATE
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	public void update(MarkerAPI markerApi, MarkerSet markerset, Marker marker)
 | 
			
		||||
	{
 | 
			
		||||
		if
 | 
			
		||||
		(
 | 
			
		||||
			!MUtil.equals(marker.getWorld(), this.getWorld())
 | 
			
		||||
			||
 | 
			
		||||
			marker.getX() != this.getX()
 | 
			
		||||
			||
 | 
			
		||||
			marker.getY() != this.getY()
 | 
			
		||||
			||
 | 
			
		||||
			marker.getZ() != this.getZ()
 | 
			
		||||
		)
 | 
			
		||||
		{
 | 
			
		||||
			marker.setLocation(
 | 
			
		||||
					this.getWorld(),
 | 
			
		||||
					this.getX(),
 | 
			
		||||
					this.getY(),
 | 
			
		||||
					this.getZ()
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		MUtil.setIfDifferent(this.getLabel(), marker::getLabel, marker::setLabel);
 | 
			
		||||
 | 
			
		||||
		MarkerIcon icon = getMarkerIcon(markerApi, this.iconName);
 | 
			
		||||
		MUtil.setIfDifferent(icon, marker::getMarkerIcon, marker::setMarkerIcon);
 | 
			
		||||
 | 
			
		||||
		MUtil.setIfDifferent(this.getDescription(), marker::getDescription, marker::setDescription);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	// UTIL
 | 
			
		||||
	// -------------------------------------------- //
 | 
			
		||||
	
 | 
			
		||||
	public static MarkerIcon getMarkerIcon(MarkerAPI markerApi, String name)
 | 
			
		||||
	{
 | 
			
		||||
		MarkerIcon ret = markerApi.getMarkerIcon(name);
 | 
			
		||||
		if (ret == null) ret = markerApi.getMarkerIcon(IntegrationDynmap.DYNMAP_STYLE_HOME_MARKER);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user