diff --git a/src/com/massivecraft/factions/Const.java b/src/com/massivecraft/factions/Const.java index 8cbfac71..f2c71a50 100644 --- a/src/com/massivecraft/factions/Const.java +++ b/src/com/massivecraft/factions/Const.java @@ -1,20 +1,7 @@ package com.massivecraft.factions; -import org.bukkit.ChatColor; - public class Const { - // ASCII Map - public static final int MAP_WIDTH = 48; - public static final int MAP_HEIGHT = 8; - public static final int MAP_HEIGHT_FULL = 17; - - public static final char[] MAP_KEY_CHARS = "\\/#?笣$%=&^ABCDEFGHJKLMNOPQRSTUVWXYZÄÖÜÆØÅ1234567890abcdeghjmnopqrsuvwxyÿzäöüæøåâêîûô".toCharArray(); - public static final String MAP_KEY_WILDERNESS = ChatColor.GRAY.toString() + "-"; - public static final String MAP_KEY_SEPARATOR = ChatColor.AQUA.toString() + "+"; - public static final String MAP_KEY_OVERFLOW = ChatColor.MAGIC.toString() + "-" + ChatColor.RESET.toString(); - public static final String MAP_OVERFLOW_MESSAGE = MAP_KEY_OVERFLOW + ": Too Many Factions (>" + MAP_KEY_CHARS.length + ") on this Map."; - // SHOW public static final String BASENAME = "factions"; public static final String BASENAME_ = BASENAME+"_"; diff --git a/src/com/massivecraft/factions/cmd/CmdFactionsMap.java b/src/com/massivecraft/factions/cmd/CmdFactionsMap.java index 928c4717..52277864 100644 --- a/src/com/massivecraft/factions/cmd/CmdFactionsMap.java +++ b/src/com/massivecraft/factions/cmd/CmdFactionsMap.java @@ -1,14 +1,10 @@ package com.massivecraft.factions.cmd; -import com.massivecraft.factions.Const; -import com.massivecraft.factions.entity.BoardColl; +import com.massivecraft.factions.util.AsciiMap; import com.massivecraft.massivecore.MassiveException; import com.massivecraft.massivecore.command.requirement.RequirementIsPlayer; import com.massivecraft.massivecore.command.type.primitive.TypeBooleanYes; -import com.massivecraft.massivecore.ps.PS; -import org.bukkit.Location; - -import java.util.List; +import com.massivecraft.massivecore.util.Txt; public class CmdFactionsMap extends FactionsCommand { @@ -32,34 +28,30 @@ public class CmdFactionsMap extends FactionsCommand @Override public void perform() throws MassiveException { - if ( ! this.argIsSet()) - { - showMap(Const.MAP_WIDTH, Const.MAP_HEIGHT_FULL); - return; - } + // NOTE: Map show is performed when auto == true || once + boolean argSet = this.argIsSet(); + boolean showMap = true; - if (this.readArg(!msender.isMapAutoUpdating())) - { - // And show the map once - showMap(Const.MAP_WIDTH, Const.MAP_HEIGHT); - - // Turn on - msender.setMapAutoUpdating(true); - msg("Map auto update ENABLED."); - } - else - { - // Turn off - msender.setMapAutoUpdating(false); - msg("Map auto update DISABLED."); - } + // Auto update + if (argSet) showMap = this.adjustAutoUpdating(); + if (!showMap) return; + + // Show Map + AsciiMap map = new AsciiMap(msender, me, !argSet); + message(map.render()); } - public void showMap(int width, int height) + private boolean adjustAutoUpdating() throws MassiveException { - Location location = me.getLocation(); - List message = BoardColl.get().getMap(msenderFaction, PS.valueOf(location), location.getYaw(), width, height); - message(message); + // Get + boolean autoUpdating = this.readArg(!msender.isMapAutoUpdating()); + + // Set + msender.setMapAutoUpdating(autoUpdating); + + // Inform + msg("Map auto update %s.", Txt.parse(autoUpdating ? "ENABLED" : "DISABLED")); + return autoUpdating; } } diff --git a/src/com/massivecraft/factions/engine/EngineMoveChunk.java b/src/com/massivecraft/factions/engine/EngineMoveChunk.java index df31e952..991ac698 100644 --- a/src/com/massivecraft/factions/engine/EngineMoveChunk.java +++ b/src/com/massivecraft/factions/engine/EngineMoveChunk.java @@ -1,11 +1,11 @@ package com.massivecraft.factions.engine; -import com.massivecraft.factions.Const; import com.massivecraft.factions.TerritoryAccess; import com.massivecraft.factions.entity.BoardColl; import com.massivecraft.factions.entity.Faction; import com.massivecraft.factions.entity.MConf; import com.massivecraft.factions.entity.MPlayer; +import com.massivecraft.factions.util.AsciiMap; import com.massivecraft.massivecore.Engine; import com.massivecraft.massivecore.mixin.MixinMessage; import com.massivecraft.massivecore.mixin.MixinTitle; @@ -18,7 +18,6 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.player.PlayerMoveEvent; import java.util.Collections; -import java.util.List; public class EngineMoveChunk extends Engine { @@ -64,8 +63,8 @@ public class EngineMoveChunk extends Engine // send host faction info updates if (mplayer.isMapAutoUpdating()) { - List message = BoardColl.get().getMap(mplayer, chunkTo, player.getLocation().getYaw(), Const.MAP_WIDTH, Const.MAP_HEIGHT); - mplayer.message(message); + AsciiMap map = new AsciiMap(mplayer, player, false); + mplayer.message(map.render()); } else if (factionFrom != factionTo) { diff --git a/src/com/massivecraft/factions/entity/Board.java b/src/com/massivecraft/factions/entity/Board.java index 0da9f7f4..07627f97 100644 --- a/src/com/massivecraft/factions/entity/Board.java +++ b/src/com/massivecraft/factions/entity/Board.java @@ -1,23 +1,16 @@ package com.massivecraft.factions.entity; -import com.massivecraft.factions.Const; import com.massivecraft.factions.Factions; -import com.massivecraft.factions.RelationParticipator; import com.massivecraft.factions.TerritoryAccess; -import com.massivecraft.factions.util.AsciiCompass; import com.massivecraft.massivecore.collections.MassiveMap; import com.massivecraft.massivecore.collections.MassiveSet; import com.massivecraft.massivecore.ps.PS; import com.massivecraft.massivecore.store.Entity; -import com.massivecraft.massivecore.util.Txt; import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken; import java.lang.reflect.Type; -import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -345,89 +338,4 @@ public class Board extends Entity implements BoardInterface return false; } - // MAP GENERATION - - @Override - public List getMap(RelationParticipator observer, PS centerPs, double inDegrees, int width, int height) - { - centerPs = centerPs.getChunkCoords(true); - - List ret = new ArrayList<>(); - Faction centerFaction = this.getFactionAt(centerPs); - - ret.add(Txt.titleize("(" + centerPs.getChunkX() + "," + centerPs.getChunkZ() + ") " + centerFaction.getName(observer))); - - int halfWidth = width / 2; - int halfHeight = height / 2; - width = halfWidth * 2 + 1; - height = halfHeight * 2 + 1; - - PS topLeftPs = centerPs.plusChunkCoords(-halfWidth, -halfHeight); - - // Get the compass - List asciiCompass = AsciiCompass.getAsciiCompass(inDegrees); - - // Make room for the list of names - height--; - - Map fList = new HashMap<>(); - int chrIdx = 0; - boolean overflown = false; - - // For each row - for (int dz = 0; dz < height; dz++) - { - // Draw and add that row - StringBuilder row = new StringBuilder(); - for (int dx = 0; dx < width; dx++) - { - if (dx == halfWidth && dz == halfHeight) - { - row.append(Const.MAP_KEY_SEPARATOR); - continue; - } - - if ( ! overflown && chrIdx >= Const.MAP_KEY_CHARS.length) overflown = true; - - PS herePs = topLeftPs.plusChunkCoords(dx, dz); - Faction hereFaction = this.getFactionAt(herePs); - boolean contains = fList.containsKey(hereFaction); - if (hereFaction.isNone()) - { - row.append(Const.MAP_KEY_WILDERNESS); - } - else if ( ! contains && overflown) - { - row.append(Const.MAP_KEY_OVERFLOW); - } - else - { - if ( ! contains) fList.put(hereFaction, Const.MAP_KEY_CHARS[chrIdx++]); - char fchar = fList.get(hereFaction); - row.append(hereFaction.getColorTo(observer).toString()).append(fchar); - } - } - - String line = row.toString(); - - // Add the compass - if (dz == 0) line = asciiCompass.get(0) + line.substring(3*3); - if (dz == 1) line = asciiCompass.get(1) + line.substring(3*3); - if (dz == 2) line = asciiCompass.get(2) + line.substring(3*3); - - ret.add(line); - } - - String fRow = ""; - for (Faction keyfaction : fList.keySet()) - { - fRow += keyfaction.getColorTo(observer).toString() + fList.get(keyfaction) + ": " + keyfaction.getName() + " "; - } - if (overflown) fRow += Const.MAP_OVERFLOW_MESSAGE; - fRow = fRow.trim(); - ret.add(fRow); - - return ret; - } - } diff --git a/src/com/massivecraft/factions/entity/BoardColl.java b/src/com/massivecraft/factions/entity/BoardColl.java index ad908f7b..43e3c78d 100644 --- a/src/com/massivecraft/factions/entity/BoardColl.java +++ b/src/com/massivecraft/factions/entity/BoardColl.java @@ -1,6 +1,5 @@ package com.massivecraft.factions.entity; -import com.massivecraft.factions.RelationParticipator; import com.massivecraft.factions.TerritoryAccess; import com.massivecraft.massivecore.collections.MassiveMap; import com.massivecraft.massivecore.collections.MassiveSet; @@ -12,7 +11,6 @@ import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -302,17 +300,6 @@ public class BoardColl extends Coll implements BoardInterface return false; } - // MAP GENERATION - - @Override - public List getMap(RelationParticipator observer, PS centerPs, double inDegrees, int width, int height) - { - if (centerPs == null) return null; - Board board = this.get(centerPs.getWorld()); - if (board == null) return null; - return board.getMap(observer, centerPs, inDegrees, width, height); - } - // -------------------------------------------- // // WORLDS // -------------------------------------------- // diff --git a/src/com/massivecraft/factions/entity/BoardInterface.java b/src/com/massivecraft/factions/entity/BoardInterface.java index c23d93a3..5ce05c04 100644 --- a/src/com/massivecraft/factions/entity/BoardInterface.java +++ b/src/com/massivecraft/factions/entity/BoardInterface.java @@ -1,10 +1,8 @@ package com.massivecraft.factions.entity; -import com.massivecraft.factions.RelationParticipator; import com.massivecraft.factions.TerritoryAccess; import com.massivecraft.massivecore.ps.PS; -import java.util.List; import java.util.Map; import java.util.Set; @@ -42,8 +40,4 @@ public interface BoardInterface boolean isConnectedPs(PS ps, Faction faction); boolean isAnyConnectedPs(Set pss, Faction faction); - // MAP - // TODO: Could the degrees be embedded in centerPs yaw instead? - List getMap(RelationParticipator observer, PS centerPs, double inDegrees, int width, int height); - } diff --git a/src/com/massivecraft/factions/util/AsciiMap.java b/src/com/massivecraft/factions/util/AsciiMap.java new file mode 100644 index 00000000..bb68141c --- /dev/null +++ b/src/com/massivecraft/factions/util/AsciiMap.java @@ -0,0 +1,219 @@ +package com.massivecraft.factions.util; + +import com.massivecraft.factions.RelationParticipator; +import com.massivecraft.factions.entity.Board; +import com.massivecraft.factions.entity.BoardColl; +import com.massivecraft.factions.entity.Faction; +import com.massivecraft.massivecore.collections.MassiveList; +import com.massivecraft.massivecore.mson.Mson; +import com.massivecraft.massivecore.ps.PS; +import com.massivecraft.massivecore.util.Txt; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import static com.massivecraft.massivecore.mson.Mson.EMPTY; +import static com.massivecraft.massivecore.mson.Mson.SPACE; +import static com.massivecraft.massivecore.mson.Mson.mson; + +public class AsciiMap +{ + // -------------------------------------------- // + // CONSTANTS + // -------------------------------------------- // + + private static final char[] FACTION_KEY_CHARS = "\\/#?笣$%=&^ABCDEFGHJKLMNOPQRSTUVWXYZÄÖÜÆØÅ1234567890abcdeghjmnopqrsuvwxyÿzäöüæøåâêîûô".toCharArray(); + private static final int KEY_SIZE = FACTION_KEY_CHARS.length; + + // Map Heights & Widths + private static final int WIDTH = 49; + private static final int WIDTH_HALF = WIDTH / 2; + private static final int HEIGHT = 8; + private static final int HEIGHT_HALF = HEIGHT / 2; + private static final int HEIGHT_EXTRA = 17; + private static final int HEIGHT_EXTRA_HALF = HEIGHT_EXTRA / 2; + + private static final String TITLE_FORMAT = "(%d,%d) %s"; + private static final Mson KEY_MIDDLE = mson("+").color(ChatColor.AQUA); + private static final Mson KEY_WILDERNESS = mson("-").color(ChatColor.GRAY).tooltip(); + private static final Mson KEY_OVERFLOW = mson("-").style(ChatColor.MAGIC).add(mson("").style(ChatColor.RESET)); + private static final Mson OVERFLOW_MESSAGE = Mson.format("%s: Too Many Factions (>%d) on this Map.", KEY_OVERFLOW.toPlain(true), FACTION_KEY_CHARS.length); + private static final Mson LEGEND_SEPARATOR = mson(": "); + + // -------------------------------------------- // + // FIELDS + // -------------------------------------------- // + + private final RelationParticipator relationParticipator; + public RelationParticipator getRelationParticipator() { return this.relationParticipator; } + + private final double angle; + public double getAngle() { return this.angle; } + + private final PS center; + public PS getCenter() { return this.center; } + + private final PS topLeft; + public PS getTopLeft() { return this.topLeft; } + + private final Board board; + public Board getBoard() { return this.board; } + + private final Map factionChars = new HashMap<>(); + public Map getFactionChars() { return this.factionChars; } + + private final int height; + private int getHeight() { return this.height; } + + private final int heightHalf; + private int getHeightHalf() { return this.heightHalf; } + + private boolean overflown = false; + public boolean isOverflown() { return this.overflown; } + public void setOverflown(boolean overflown) { this.overflown = overflown; } + + // -------------------------------------------- // + // CONSTRUCT + // -------------------------------------------- // + + public AsciiMap(RelationParticipator relationParticipator, Player player, boolean extraHeight) + { + this.relationParticipator = relationParticipator; + Location location = player.getLocation(); + this.angle = location.getYaw(); + this.center = PS.valueOf(location).getChunk(true); + this.height = extraHeight ? HEIGHT_EXTRA : HEIGHT; + this.heightHalf = extraHeight ? HEIGHT_EXTRA_HALF : HEIGHT_HALF; + this.topLeft = this.center.plusChunkCoords(-WIDTH_HALF, -this.heightHalf); + this.board = BoardColl.get().get(this.center.getWorld()); + } + + // -------------------------------------------- // + // RENDER + // -------------------------------------------- // + + public List render() + { + // Create + List ret = new ArrayList<>(); + + // Fill + ret.add(this.getTitle()); + ret.addAll(this.getLines()); + ret.add(this.getFactionLegend()); + + // Return + return ret; + } + + private Mson getTitle() + { + // Prepare + PS chunk = this.getCenter(); + Faction faction = this.getBoard().getFactionAt(chunk); + int chunkX = chunk.getChunkX(); + int chunkZ = chunk.getChunkZ(); + String factionName = faction.getName(this.getRelationParticipator()); + + // Titleize + return Txt.titleize(String.format(TITLE_FORMAT, chunkX, chunkZ, factionName)); + } + + private List getLines() + { + // Create + List ret = new MassiveList<>(); + List asciiCompass = AsciiCompass.getAsciiCompass(this.getAngle()); + + // Fill + for (int deltaZ = 0; deltaZ < this.getHeight(); deltaZ++) + { + ret.add(this.getLine(deltaZ, asciiCompass)); + } + + // Return + return ret; + } + + private Mson getLine(int deltaZ, List asciiCompass) + { + // Create + boolean isCompassLine = deltaZ < asciiCompass.size(); + int startX = isCompassLine ? 3 : 0; + Mson ret = isCompassLine ? mson(asciiCompass.get(deltaZ)) : EMPTY; + Mson factionChar; + + // Fill + for (int deltaX = startX; deltaX < WIDTH; deltaX++) + { + boolean isMiddle = deltaX == WIDTH_HALF && deltaZ == this.getHeightHalf(); + factionChar = isMiddle ? KEY_MIDDLE : this.getCharFaction(deltaZ, deltaX); + ret = ret.add(factionChar); + } + + // Return + return ret; + } + + private Mson getCharFaction(int deltaZ, int deltaX) + { + // Calculate overflow + int index = this.getFactionChars().size(); + if (!this.isOverflown() && index >= KEY_SIZE) this.setOverflown(true); + + PS herePs = this.getTopLeft().plusChunkCoords(deltaX, deltaZ); + Faction hereFaction = this.getBoard().getFactionAt(herePs); + Mson factionChar = this.getFactionChars().get(hereFaction); + + // Is Wilderness or known? + if (hereFaction.isNone()) return KEY_WILDERNESS; + if (factionChar != null) return factionChar; + + // Create descriptions + ChatColor color = hereFaction.getColorTo(this.getRelationParticipator()); + String name = hereFaction.getName(this.getRelationParticipator()); + String tooltip = color.toString() + name; + + // Is overflown? + if (this.isOverflown()) return KEY_OVERFLOW.tooltip(tooltip); + + // Create new one + factionChar = mson(String.valueOf(FACTION_KEY_CHARS[index])).color(color); + factionChar = factionChar.tooltip(tooltip); + + // Store for later use + this.getFactionChars().put(hereFaction, factionChar); + + // Return + return factionChar; + } + + private Mson getFactionLegend() + { + // Create + List ret = new MassiveList<>(); + + // Fill + for (Entry entry : this.getFactionChars().entrySet()) + { + Faction here = entry.getKey(); + Mson factionChar = entry.getValue(); + ChatColor color = here.getColorTo(this.getRelationParticipator()); + + ret.add(mson(factionChar, LEGEND_SEPARATOR, here.getName()).color(color)); + } + + // Add overflown message if needed + if (this.isOverflown()) ret.add(OVERFLOW_MESSAGE); + + // Return + return Mson.implode(ret, SPACE); + } + +}