diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..a03a380
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,50 @@
+
+ 4.0.0
+ com.allocinit
+ SkyJot
+ 1.0.0-SNAPSHOT
+ BlockHunt
+
+
+
+ spigot-repo
+ https://hub.spigotmc.org/nexus/content/repositories/snapshots/
+
+
+
+
+
+ org.bukkit
+ bukkit
+ 1.8.8-R0.1-SNAPSHOT
+
+
+
+
+
+
+ .
+ true
+ ${basedir}/src/main/resources
+
+ plugin.yml
+
+
+
+
+ src
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 2.3.2
+
+ 1.7
+ 1.7
+ UTF-8
+
+
+
+
+
diff --git a/src/main/java/com/allocinit/skyjot/Character.java b/src/main/java/com/allocinit/skyjot/Character.java
new file mode 100644
index 0000000..bfbea62
--- /dev/null
+++ b/src/main/java/com/allocinit/skyjot/Character.java
@@ -0,0 +1,39 @@
+package com.allocinit.skyjot;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class Character
+{
+ private List path = new ArrayList<>();
+ private int width = 0;
+
+ public Character(String... rows)
+ {
+ for (int i = 0; i < rows.length; i++)
+ {
+ String row = rows [rows.length - i - 1];
+
+ for (int j = 0; j < row.length(); j++)
+ {
+ if (j >= width)
+ width = j + 1;
+
+ char dot = row.charAt(j);
+ if (dot != ' ')
+ path.add(new Integer [] { j, i });
+ }
+ }
+ }
+
+ public int getWidth()
+ {
+ return width;
+ }
+
+ public List getPath()
+ {
+ return path;
+ }
+}
diff --git a/src/main/java/com/allocinit/skyjot/DirectionHelper.java b/src/main/java/com/allocinit/skyjot/DirectionHelper.java
new file mode 100644
index 0000000..893ec0f
--- /dev/null
+++ b/src/main/java/com/allocinit/skyjot/DirectionHelper.java
@@ -0,0 +1,40 @@
+package com.allocinit.skyjot;
+
+import org.bukkit.Location;
+import org.bukkit.entity.Player;
+import org.bukkit.util.Vector;
+
+class DirectionHelper
+{
+ private double xAdd;
+ private double zAdd;
+
+ public DirectionHelper()
+ {
+ }
+
+ public void setFromPlayerView(Player player)
+ {
+ Vector direction = player.getLocation().getDirection();
+
+ direction.setY(0);
+
+ if (Math.abs(direction.getX()) < Math.abs(direction.getZ()))
+ {
+ xAdd = direction.getZ() > 0 ? -1 : 1;
+ zAdd = 0;
+ }
+ else
+ {
+ zAdd = direction.getX() < 0 ? -1 : 1;
+ xAdd = 0;
+ }
+ }
+
+ public void move(Location loc, int xoff, int yoff)
+ {
+ loc.setX(loc.getX() + xoff * xAdd);
+ loc.setZ(loc.getZ() + xoff * zAdd);
+ loc.setY(loc.getY() + yoff);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/allocinit/skyjot/Font.java b/src/main/java/com/allocinit/skyjot/Font.java
new file mode 100644
index 0000000..0976d73
--- /dev/null
+++ b/src/main/java/com/allocinit/skyjot/Font.java
@@ -0,0 +1,322 @@
+package com.allocinit.skyjot;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class Font
+{
+ private Character SPACE = new Character()
+ {
+ @Override
+ public int getWidth()
+ {
+ return 2;
+ }
+ };
+
+ private Character A = new Character(//
+ "XXX", //
+ "X X", //
+ "XXX", //
+ "X X", //
+ "X X");
+
+ private Character B = new Character(//
+ "XXX", //
+ "X X", //
+ "XXX", //
+ "X X", //
+ "XXX");
+
+ private Character C = new Character(//
+ "XXX", //
+ "X", //
+ "X", //
+ "X", //
+ "XXX");
+
+ private Character D = new Character(//
+ "XXX", //
+ "X X", //
+ "X X", //
+ "X X", //
+ "XXX");
+
+ private Character E = new Character(//
+ "XXX", //
+ "X", //
+ "XX", //
+ "X", //
+ "XXX");
+
+ private Character F = new Character(//
+ "XXX", //
+ "X", //
+ "XX", //
+ "X", //
+ "X");
+
+ private Character G = new Character(//
+ "XXX", //
+ "X", //
+ "X", //
+ "X X", //
+ "XXX");
+
+ private Character H = new Character(//
+ "X X", //
+ "X X", //
+ "XXX", //
+ "X X", //
+ "X X");
+
+ private Character I = new Character(//
+ "XXX", //
+ " X", //
+ " X", //
+ " X", //
+ "XXX");
+
+ private Character J = new Character(//
+ "XXXX", //
+ " X", //
+ " X", //
+ " X", //
+ "XXX");
+
+ private Character K = new Character(//
+ "X X", //
+ "X X", //
+ "XX", //
+ "X X", //
+ "X X");
+
+ private Character L = new Character(//
+ "X", //
+ "X", //
+ "X", //
+ "X", //
+ "XXX");
+
+ private Character M = new Character(//
+ "XX XX", //
+ "X X X", //
+ "X X X", //
+ "X X", //
+ "X X");
+
+ private Character N = new Character(//
+ "X X", //
+ "XX X", //
+ "X X X", //
+ "X XX", //
+ "X X");
+
+ private Character O = new Character(//
+ " XX ", //
+ "X X", //
+ "X X", //
+ "X X", //
+ " XX");
+
+ private Character P = new Character(//
+ "XXX", //
+ "X X", //
+ "XXX", //
+ "X", //
+ "X");
+
+ private Character Q = new Character(//
+ " XXX ", //
+ "X X", //
+ "X X X", //
+ "X XX", //
+ " XXX");
+
+ private Character R = new Character(//
+ "XXX", //
+ "X X", //
+ "XX", //
+ "X X", //
+ "X X");
+
+ private Character S = new Character(//
+ "XXX", //
+ "X", //
+ "XXX", //
+ " X", //
+ "XXX");
+
+ private Character T = new Character(//
+ "XXX", //
+ " X", //
+ " X", //
+ " X", //
+ " X");
+
+ private Character U = new Character(//
+ "X X", //
+ "X X", //
+ "X X", //
+ "X X", //
+ " XX");
+
+ private Character V = new Character(//
+ "X X", //
+ "X X", //
+ " X X", //
+ " X X", //
+ " X");
+
+ private Character W = new Character(//
+ "X X", //
+ "X X", //
+ "X X X", //
+ "X X X", //
+ " X X");
+
+ private Character X = new Character(//
+ "X X", //
+ "X X", //
+ " X", //
+ "X X", //
+ "X X");
+
+ private Character Y = new Character(//
+ "X X", //
+ "X X", //
+ " X", //
+ " X", //
+ " X");
+
+ private Character Z = new Character(//
+ "XXX", //
+ " X", //
+ " X", //
+ "X", //
+ "XXX");
+
+ private Character N1 = new Character(//
+ "XX", //
+ " X", //
+ " X", //
+ " X", //
+ "XXX");
+
+ private Character N2 = new Character(//
+ "XXX", //
+ " X", //
+ "XXX", //
+ "X", //
+ "XXX");
+
+ private Character N3 = new Character(//
+ "XXX", //
+ " X", //
+ "XXX", //
+ " X", //
+ "XXX");
+
+ private Character N4 = new Character(//
+ "X X", //
+ "X X", //
+ "XXX", //
+ " X", //
+ " X");
+
+ private Character N5 = new Character(//
+ "XXX", //
+ "X", //
+ "XXX", //
+ " X", //
+ "XXX");
+
+ private Character N6 = new Character(//
+ "XXX", //
+ "X", //
+ "XXX", //
+ "X X", //
+ "XXX");
+
+ private Character N7 = new Character(//
+ "XXX", //
+ " X", //
+ " X", //
+ " X", //
+ " X");
+
+ private Character N8 = new Character(//
+ "XXX", //
+ "X X", //
+ "XXX", //
+ "X X", //
+ "XXX");
+
+ private Character N9 = new Character(//
+ "XXX", //
+ "X X", //
+ "XXX", //
+ " X", //
+ " X");
+
+ private Character N0 = new Character(//
+ "XXX", //
+ "X X", //
+ "X X", //
+ "X X", //
+ "XXX");
+
+ private Map font = new HashMap<>();
+
+ public Font()
+ {
+ font.put(" ", SPACE);
+ font.put("A", A);
+ font.put("B", B);
+ font.put("C", C);
+ font.put("D", D);
+ font.put("E", E);
+ font.put("F", F);
+ font.put("G", G);
+ font.put("H", H);
+ font.put("I", I);
+ font.put("J", J);
+ font.put("K", K);
+ font.put("L", L);
+ font.put("M", M);
+ font.put("N", N);
+ font.put("O", O);
+ font.put("P", P);
+ font.put("Q", Q);
+ font.put("R", R);
+ font.put("S", S);
+ font.put("T", T);
+ font.put("U", U);
+ font.put("V", V);
+ font.put("W", W);
+ font.put("X", X);
+ font.put("Y", Y);
+ font.put("Z", Z);
+ font.put("0", N0);
+ font.put("1", N1);
+ font.put("2", N2);
+ font.put("3", N3);
+ font.put("4", N4);
+ font.put("5", N5);
+ font.put("6", N6);
+ font.put("7", N7);
+ font.put("8", N8);
+ font.put("9", N9);
+ }
+
+ public int getHeight()
+ {
+ return 5;
+ }
+
+ public Character get(String c)
+ {
+ return font.get(c);
+ }
+}
diff --git a/src/main/java/com/allocinit/skyjot/SkyJot.java b/src/main/java/com/allocinit/skyjot/SkyJot.java
new file mode 100644
index 0000000..a1fadec
--- /dev/null
+++ b/src/main/java/com/allocinit/skyjot/SkyJot.java
@@ -0,0 +1,75 @@
+package com.allocinit.skyjot;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.java.JavaPlugin;
+
+
+public class SkyJot extends JavaPlugin
+{
+ private Map playerState = new HashMap<>();
+ private SubCommand writeCommand = new WriteCommand(this);
+ private SubCommand undoCommand = new UndoCommand(this);
+
+ @Override
+ public void onEnable()
+ {
+ this.getCommand("skyjot").setExecutor(new CommandExecutor()
+ {
+ @Override
+ public boolean onCommand(CommandSender sender, Command cmd,
+ String label, String [] args)
+ {
+ Player player = (Player) sender;
+
+ if (!player.hasPermission("skyjot"))
+ {
+ player.sendMessage("&cPermission Denied");
+ return true;
+ }
+
+ if (args.length < 1)
+ {
+ writeUsage(player);
+ return true;
+ }
+
+ String subCmd = args [0];
+
+ args = Arrays.copyOfRange(args, 1, args.length);
+
+ if ("write".equals(subCmd))
+ writeCommand.doCommand(sender, args);
+ else if ("undo".equals(subCmd))
+ undoCommand.doCommand(sender, args);
+ else
+ writeUsage(player);
+
+ return true;
+ }
+ });
+
+ }
+
+ private void writeUsage(Player player)
+ {
+ writeCommand.writeUsage(player);
+ undoCommand.writeUsage(player);
+ }
+
+ @Override
+ public void onDisable()
+ {
+ }
+
+ public Map getPlayerState()
+ {
+ return playerState;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/allocinit/skyjot/SubCommand.java b/src/main/java/com/allocinit/skyjot/SubCommand.java
new file mode 100644
index 0000000..059895a
--- /dev/null
+++ b/src/main/java/com/allocinit/skyjot/SubCommand.java
@@ -0,0 +1,12 @@
+package com.allocinit.skyjot;
+
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+
+public interface SubCommand
+{
+ public void doCommand(CommandSender sender, String [] args);
+
+ public void writeUsage(Player player);
+}
diff --git a/src/main/java/com/allocinit/skyjot/Undo.java b/src/main/java/com/allocinit/skyjot/Undo.java
new file mode 100644
index 0000000..10e3464
--- /dev/null
+++ b/src/main/java/com/allocinit/skyjot/Undo.java
@@ -0,0 +1,38 @@
+package com.allocinit.skyjot;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.bukkit.Location;
+import org.bukkit.block.Block;
+import org.bukkit.material.MaterialData;
+
+
+public class Undo
+{
+ private Map undoMap = new HashMap<>();
+
+ public Undo()
+ {
+ }
+
+ public void saveLocation(Location where)
+ {
+ MaterialData what = where.getBlock().getState().getData();
+ undoMap.put(where, what);
+ }
+
+ public void undo()
+ {
+ for (Map.Entry entry : undoMap.entrySet())
+ {
+ MaterialData data = entry.getValue();
+
+ Block block = entry.getKey().getBlock();
+ block.setType(data.getItemType());
+ block.setData(data.getData());
+ }
+
+ undoMap.clear();
+ }
+}
diff --git a/src/main/java/com/allocinit/skyjot/UndoCommand.java b/src/main/java/com/allocinit/skyjot/UndoCommand.java
new file mode 100644
index 0000000..6f5e5f1
--- /dev/null
+++ b/src/main/java/com/allocinit/skyjot/UndoCommand.java
@@ -0,0 +1,30 @@
+package com.allocinit.skyjot;
+
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+
+public class UndoCommand implements SubCommand
+{
+ private SkyJot skyjot;
+
+ public UndoCommand(SkyJot skyjot)
+ {
+ this.skyjot = skyjot;
+ }
+
+ public void doCommand(CommandSender sender, String [] args)
+ {
+ Player player = (Player) sender;
+
+ Undo undo = skyjot.getPlayerState().get(player.getName());
+
+ if (undo != null)
+ undo.undo();
+ }
+
+ public void writeUsage(Player player)
+ {
+ player.sendMessage("skyjot undo");
+ }
+}
diff --git a/src/main/java/com/allocinit/skyjot/WriteCommand.java b/src/main/java/com/allocinit/skyjot/WriteCommand.java
new file mode 100644
index 0000000..024d54f
--- /dev/null
+++ b/src/main/java/com/allocinit/skyjot/WriteCommand.java
@@ -0,0 +1,168 @@
+package com.allocinit.skyjot;
+
+import java.util.Arrays;
+
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.material.MaterialData;
+
+
+public class WriteCommand implements SubCommand
+{
+ private SkyJot skyjot;
+ private Font font = new Font();
+
+ public WriteCommand(SkyJot skyjot)
+ {
+ this.skyjot = skyjot;
+ }
+
+ public void doCommand(CommandSender sender, String [] args)
+ {
+ Player player = (Player) sender;
+
+ char justification = 'c';
+ DirectionHelper dirHelper = new DirectionHelper();
+ MaterialData material = new MaterialData(Material.STONE);
+ dirHelper.setFromPlayerView(player);
+
+ // write [b:block type] [j:left|right|center] text ...
+
+ while (args.length > 4)
+ {
+ String arg = args [0];
+
+ if (arg.startsWith("j:"))
+ {
+ justification = arg.charAt(2);
+ }
+ else if (arg.startsWith("b:"))
+ {
+ String val = arg.substring(2);
+ material = parseMaterial(val);
+ }
+ else
+ break;
+
+ args = Arrays.copyOfRange(args, 1, args.length);
+ }
+
+ if (args.length < 4)
+ {
+ writeUsage(player);
+ return;
+ }
+
+ Location where = player.getLocation();
+ where.setX(parseCoord(where.getX(), args [0]));
+ where.setY(parseCoord(where.getY(), args [1]));
+ where.setZ(parseCoord(where.getZ(), args [2]));
+
+ Undo undo = new Undo();
+ skyjot.getPlayerState().put(player.getName(), undo);
+
+ Location cursor = where.clone();
+
+ String complete = "";
+ for (int i = 3; i < args.length; i++)
+ complete += args [i] + " ";
+
+ // For now
+ complete = complete.toUpperCase();
+
+ String [] lines = complete.split("\\\\N");
+
+ for (String line : lines)
+ {
+ if (justification == 'c' || justification == 'r')
+ {
+ // Get a total width
+ int width = 0;
+
+ int letterCnt = 0;
+ for (int j = 0; j < line.length(); j++)
+ {
+ String letter = line.substring(j, j + 1);
+ Character c = font.get(letter);
+ if (c != null)
+ {
+ letterCnt++;
+ width += c.getWidth();
+ }
+ }
+
+ // The gap between letters
+ width += letterCnt - 1;
+
+ if (justification == 'c')
+ dirHelper.move(cursor, -width / 2, 0);
+ else if (justification == 'r')
+ dirHelper.move(cursor, -width, 0);
+ }
+
+ for (int j = 0; j < line.length(); j++)
+ {
+ String letter = line.substring(j, j + 1);
+
+ Character c = font.get(letter);
+
+ if (c == null)
+ continue;
+
+ for (Integer [] offset : c.getPath())
+ {
+ Location blockLoc = cursor.clone();
+
+ dirHelper.move(blockLoc, offset [0], offset [1]);
+
+ undo.saveLocation(blockLoc);
+
+ Block block = blockLoc.getBlock();
+ block.setType(material.getItemType());
+ block.setData(material.getData());
+ }
+
+ dirHelper.move(cursor, c.getWidth() + 1, 0);
+ }
+
+ // New line
+ cursor.setX(where.getX());
+ cursor.setZ(where.getZ());
+ cursor.setY(cursor.getY() - font.getHeight() - 2);
+ }
+ }
+
+ private MaterialData parseMaterial(String val)
+ {
+ byte data = 0;
+
+ String [] parts = val.split(":", 2);
+ Material material = Material.matchMaterial(parts [0]);
+ if (parts.length > 1)
+ data = (byte) Integer.parseInt(parts [1]);
+
+ return new MaterialData(material, data);
+ }
+
+ private double parseCoord(double d, String coord)
+ {
+ if (coord.startsWith("~"))
+ {
+ if (coord.length() > 1)
+ d += Integer.parseInt(coord.substring(1));
+ return d;
+ }
+
+ return Integer.parseInt(coord);
+ }
+
+ public void writeUsage(Player player)
+ {
+ player.sendMessage(
+ "skyjot write [b:block type] [a:left|right|center] text ...");
+ }
+
+}
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
new file mode 100644
index 0000000..f7351cf
--- /dev/null
+++ b/src/main/resources/plugin.yml
@@ -0,0 +1,11 @@
+name: RW
+main: com.allocinit.skyjot.SkyJot
+version: 1.0.0-SNAPSHOT
+
+commands:
+ skyjot:
+
+permissions:
+ skyjot:
+ default: op
+
\ No newline at end of file