First Commit 0.2.0
authorencode32 <jesusreto@gmail.com>
Tue, 11 May 2021 19:25:47 +0000 (21:25 +0200)
committerencode32 <jesusreto@gmail.com>
Tue, 11 May 2021 19:25:47 +0000 (21:25 +0200)
29 files changed:
src/com/wurmonline/client/renderer/gui/CheckBoxListener.java [new file with mode: 0644]
src/com/wurmonline/client/renderer/gui/EspWCheckBox.java [new file with mode: 0644]
src/com/wurmonline/client/renderer/gui/WurmEspWindow.java [new file with mode: 0644]
src/net/encode/wurmesp/Unit.java [new file with mode: 0644]
src/net/encode/wurmesp/WurmEspMod.java [new file with mode: 0644]
src/net/encode/wurmesp/feature/Feature.java [new file with mode: 0644]
src/net/encode/wurmesp/feature/FeatureFlowerTiles.java [new file with mode: 0644]
src/net/encode/wurmesp/feature/FeatureTilesCloseBy.java [new file with mode: 0644]
src/net/encode/wurmesp/feature/FeatureTilesHighlight.java [new file with mode: 0644]
src/net/encode/wurmesp/feature/FeatureTilesWalkable.java [new file with mode: 0644]
src/net/encode/wurmesp/feature/FeatureXRay.java [new file with mode: 0644]
src/net/encode/wurmesp/feature/hook/CmdShowDeedPlan.java [new file with mode: 0644]
src/net/encode/wurmesp/feature/hook/GroundItemCellRenderableInit.java [new file with mode: 0644]
src/net/encode/wurmesp/feature/hook/GroundItemCellRenderableRemove.java [new file with mode: 0644]
src/net/encode/wurmesp/feature/hook/HandleDevInput.java [new file with mode: 0644]
src/net/encode/wurmesp/feature/hook/HeadsUpDisplayInit.java [new file with mode: 0644]
src/net/encode/wurmesp/feature/hook/Hook.java [new file with mode: 0644]
src/net/encode/wurmesp/feature/hook/HookFeature.java [new file with mode: 0644]
src/net/encode/wurmesp/feature/hook/MobileModelRenderableInit.java [new file with mode: 0644]
src/net/encode/wurmesp/feature/hook/MobileModelRenderableRemove.java [new file with mode: 0644]
src/net/encode/wurmesp/feature/hook/ProjectileCellRenderable.java [new file with mode: 0644]
src/net/encode/wurmesp/feature/hook/RenderPickedItem.java [new file with mode: 0644]
src/net/encode/wurmesp/util/ConfigUtils.java [new file with mode: 0644]
src/net/encode/wurmesp/util/CronoManager.java [new file with mode: 0644]
src/net/encode/wurmesp/util/ReUtils.java [new file with mode: 0644]
src/net/encode/wurmesp/util/RenderUtils.java [new file with mode: 0644]
src/net/encode/wurmesp/util/SoundUtils.java [new file with mode: 0644]
src/net/encode/wurmesp/util/TerrainUtils.java [new file with mode: 0644]
src/net/encode/wurmesp/util/XrayColors.java [new file with mode: 0644]

diff --git a/src/com/wurmonline/client/renderer/gui/CheckBoxListener.java b/src/com/wurmonline/client/renderer/gui/CheckBoxListener.java
new file mode 100644 (file)
index 0000000..9584a77
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Decompiled with CFR 0.151.
+ */
+package com.wurmonline.client.renderer.gui;
+
+public interface CheckBoxListener {
+    public void checkboxClicked(EspWCheckBox var1);
+}
+
diff --git a/src/com/wurmonline/client/renderer/gui/EspWCheckBox.java b/src/com/wurmonline/client/renderer/gui/EspWCheckBox.java
new file mode 100644 (file)
index 0000000..53ee5a8
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.client.renderer.Matrix
+ *  com.wurmonline.client.renderer.PickData
+ *  com.wurmonline.client.renderer.backend.Primitive
+ *  com.wurmonline.client.renderer.backend.Primitive$TexEnv
+ *  com.wurmonline.client.renderer.backend.Primitive$Type
+ *  com.wurmonline.client.renderer.backend.Queue
+ *  com.wurmonline.client.renderer.backend.VertexBuffer
+ *  com.wurmonline.client.renderer.backend.VertexBuffer$Usage
+ *  com.wurmonline.client.renderer.gui.ConfirmListener
+ *  com.wurmonline.client.renderer.gui.ConfirmWindow
+ *  com.wurmonline.client.renderer.gui.FlexComponent
+ *  com.wurmonline.client.renderer.gui.HeadsUpDisplay
+ */
+package com.wurmonline.client.renderer.gui;
+
+import com.wurmonline.client.renderer.Matrix;
+import com.wurmonline.client.renderer.PickData;
+import com.wurmonline.client.renderer.backend.Primitive;
+import com.wurmonline.client.renderer.backend.Queue;
+import com.wurmonline.client.renderer.backend.VertexBuffer;
+import java.nio.FloatBuffer;
+
+final class EspWCheckBox
+extends FlexComponent
+implements ConfirmListener {
+    private String label;
+    boolean checked = false;
+    boolean enabled = true;
+    private boolean needsConfirmOnTick = false;
+    private String confirmMessageOnTick;
+    private String confirmQuestionOnTick;
+    private boolean needsConfirmUnTick = false;
+    private String confirmMessageUnTick;
+    private String confirmQuestionUnTick;
+    private ConfirmWindow confirmWindow = null;
+    private String hoverString;
+    private float customR = 1.0f;
+    private float customG = 1.0f;
+    private float customB = 1.0f;
+    private static final VertexBuffer vbo = VertexBuffer.create((VertexBuffer.Usage)VertexBuffer.Usage.GUI, (int)12, (boolean)true, (boolean)false, (boolean)false, (boolean)false, (boolean)false, (int)0, (int)0, (boolean)false, (boolean)true);
+    private final Matrix modelMatrix;
+    private CheckBoxListener checkboxListener;
+
+    EspWCheckBox(String label, CheckBoxListener checkboxListener) {
+        super("Checkbox " + label);
+        this.height = this.text.getHeight() + 1;
+        this.setLabel(label);
+        this.modelMatrix = Matrix.createIdentity();
+        this.checkboxListener = checkboxListener;
+    }
+
+    public void setLabel(String newLabel) {
+        this.label = newLabel;
+        this.setSize(this.text.getWidth(this.label) + 16, this.height);
+    }
+
+    protected void renderComponent(Queue queue, float alpha) {
+        float colR = 0.8f;
+        float colG = 0.8f;
+        float colB = 0.8f;
+        if (this.enabled) {
+            colR = this.customR;
+            colG = this.customG;
+            colB = this.customB;
+        }
+        Primitive prim = queue.reservePrimitive();
+        prim.type = Primitive.Type.LINES;
+        prim.num = this.checked ? 6 : 4;
+        prim.r = colR;
+        prim.g = colG;
+        prim.b = colB;
+        prim.a = 1.0f;
+        prim.texture[1] = null;
+        prim.texture[0] = null;
+        prim.texenv[0] = Primitive.TexEnv.MODULATE;
+        prim.vertex = vbo;
+        prim.index = null;
+        prim.clipRect = HeadsUpDisplay.scissor.getCurrent();
+        int dy = (this.height - 8) / 2;
+        this.modelMatrix.setTranslation((float)this.x, (float)(this.y + dy), 0.0f);
+        queue.queue(prim, this.modelMatrix);
+        this.text.moveTo(this.x + this.height, this.y + this.text.getHeight());
+        this.text.paint(queue, this.label, colR, colG, colB, 1.0f);
+    }
+
+    protected void leftPressed(int xMouse, int yMouse, int clickCount) {
+        if (this.enabled && xMouse <= this.x + 16 && xMouse >= this.x && yMouse >= this.y && yMouse <= this.y + this.height) {
+            if (this.needsConfirmOnTick && !this.checked) {
+                this.confirmWindow = new ConfirmWindow((ConfirmListener)this, this.getConfirmMessageOnTick(), this.getConfirmQuestionOnTick());
+            } else if (this.needsConfirmUnTick && this.checked) {
+                this.confirmWindow = new ConfirmWindow((ConfirmListener)this, this.getConfirmMessageUnTick(), this.getConfirmQuestionUnTick());
+            } else {
+                this.checked = !this.checked;
+            }
+            this.checkboxListener.checkboxClicked(this);
+        }
+    }
+
+    protected int getMouseCursor(int x, int y) {
+        if (this.enabled && x <= this.x + 16 && x >= this.x && y >= this.y && y <= this.y + this.height) {
+            return 1;
+        }
+        return super.getMouseCursor(x, y);
+    }
+
+    public void pick(PickData pickData, int xMouse, int yMouse) {
+        if (this.hoverString != null) {
+            pickData.addText(this.hoverString);
+        }
+    }
+
+    void setCustomColor(float r, float g, float b) {
+        this.customR = r;
+        this.customG = g;
+        this.customB = b;
+    }
+
+    public void setHoverString(String description) {
+        this.hoverString = description;
+    }
+
+    final void setConfirmOnTickMessage(String message) {
+        this.confirmMessageOnTick = message;
+    }
+
+    final void setConfirmOnTickQuestion(String question) {
+        this.confirmQuestionOnTick = question;
+        this.needsConfirmOnTick = true;
+    }
+
+    final void setConfirm(String messageOnTick, String questionOnTick, String messageUnTick, String questionUnTick) {
+        this.confirmMessageOnTick = messageOnTick;
+        this.confirmQuestionOnTick = questionOnTick;
+        this.confirmMessageUnTick = messageUnTick;
+        this.confirmQuestionUnTick = questionUnTick;
+        this.needsConfirmOnTick = questionOnTick.length() > 0;
+        this.needsConfirmUnTick = questionUnTick.length() > 0;
+    }
+
+    public String getConfirmMessageOnTick() {
+        return this.confirmMessageOnTick;
+    }
+
+    public String getConfirmQuestionOnTick() {
+        return this.confirmQuestionOnTick;
+    }
+
+    public String getConfirmMessageUnTick() {
+        return this.confirmMessageUnTick;
+    }
+
+    public String getConfirmQuestionUnTick() {
+        return this.confirmQuestionUnTick;
+    }
+
+    public void closeConfirmWindow() {
+        if (this.confirmWindow != null) {
+            this.confirmWindow.close();
+            this.confirmWindow = null;
+        }
+    }
+
+    public void confirmed() {
+        this.closeConfirmWindow();
+        this.checked = !this.checked;
+    }
+
+    public void cancelled() {
+        this.closeConfirmWindow();
+    }
+
+    static {
+        FloatBuffer vertex = vbo.lock();
+        vertex.put(4.0f);
+        vertex.put(0.0f);
+        vertex.put(0.0f);
+        vertex.put(13.0f);
+        vertex.put(0.0f);
+        vertex.put(0.0f);
+        vertex.put(3.0f);
+        vertex.put(8.0f);
+        vertex.put(0.0f);
+        vertex.put(13.0f);
+        vertex.put(8.0f);
+        vertex.put(0.0f);
+        vertex.put(4.0f);
+        vertex.put(0.0f);
+        vertex.put(0.0f);
+        vertex.put(4.0f);
+        vertex.put(8.0f);
+        vertex.put(0.0f);
+        vertex.put(13.0f);
+        vertex.put(0.0f);
+        vertex.put(0.0f);
+        vertex.put(13.0f);
+        vertex.put(8.0f);
+        vertex.put(0.0f);
+        vertex.put(6.0f);
+        vertex.put(2.0f);
+        vertex.put(0.0f);
+        vertex.put(11.0f);
+        vertex.put(7.0f);
+        vertex.put(0.0f);
+        vertex.put(11.0f);
+        vertex.put(2.0f);
+        vertex.put(0.0f);
+        vertex.put(6.0f);
+        vertex.put(7.0f);
+        vertex.put(0.0f);
+        vbo.unlock();
+    }
+}
+
diff --git a/src/com/wurmonline/client/renderer/gui/WurmEspWindow.java b/src/com/wurmonline/client/renderer/gui/WurmEspWindow.java
new file mode 100644 (file)
index 0000000..697fd24
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.client.renderer.gui.FlexComponent
+ *  com.wurmonline.client.renderer.gui.WWindow
+ *  com.wurmonline.client.renderer.gui.WurmArrayPanel
+ *  com.wurmonline.client.renderer.gui.WurmBorderPanel
+ *  com.wurmonline.client.renderer.gui.WurmComponent
+ */
+package com.wurmonline.client.renderer.gui;
+
+import net.encode.wurmesp.WurmEspMod;
+
+public class WurmEspWindow
+extends WWindow {
+    private WurmBorderPanel mainPanel;
+
+    public WurmEspWindow() {
+        super("Esp", true);
+        this.setTitle("Esp");
+        this.resizable = true;
+        this.closeable = true;
+        this.setInitialSize(100, 300, true);
+        this.mainPanel = new WurmBorderPanel("Esp");
+        WurmArrayPanel<FlexComponent> checkboxes = new WurmArrayPanel<FlexComponent>("Esp CheckBoxes", 0);
+        EspWCheckBox playersCheckBox = new EspWCheckBox("Players", new CheckBoxListener(){
+
+            @Override
+            public void checkboxClicked(EspWCheckBox checkbox) {
+                WurmEspMod.players = checkbox.checked;
+            }
+        });
+        playersCheckBox.checked = WurmEspMod.players;
+        EspWCheckBox mobsCheckBox = new EspWCheckBox("Aggro Mobs", new CheckBoxListener(){
+
+            @Override
+            public void checkboxClicked(EspWCheckBox checkbox) {
+                WurmEspMod.mobs = checkbox.checked;
+            }
+        });
+        mobsCheckBox.checked = WurmEspMod.mobs;
+        EspWCheckBox animalsCheckBox = new EspWCheckBox("Animals", new CheckBoxListener(){
+
+            @Override
+            public void checkboxClicked(EspWCheckBox checkbox) {
+                WurmEspMod.animals = checkbox.checked;
+            }
+        });
+        animalsCheckBox.checked = WurmEspMod.animals;
+        EspWCheckBox specialsCheckBox = new EspWCheckBox("Specials", new CheckBoxListener(){
+
+            @Override
+            public void checkboxClicked(EspWCheckBox checkbox) {
+                WurmEspMod.specials = checkbox.checked;
+            }
+        });
+        specialsCheckBox.checked = WurmEspMod.specials;
+        EspWCheckBox itemsCheckBox = new EspWCheckBox("Items", new CheckBoxListener(){
+
+            @Override
+            public void checkboxClicked(EspWCheckBox checkbox) {
+                WurmEspMod.items = checkbox.checked;
+            }
+        });
+        itemsCheckBox.checked = WurmEspMod.items;
+        EspWCheckBox tilesSearchCheckBox = new EspWCheckBox("Flower Tiles", new CheckBoxListener(){
+
+            @Override
+            public void checkboxClicked(EspWCheckBox checkbox) {
+                WurmEspMod.tilesFlower = checkbox.checked;
+            }
+        });
+        tilesSearchCheckBox.checked = WurmEspMod.tilesFlower;
+        EspWCheckBox uniquesCheckBox = new EspWCheckBox("Uniques", new CheckBoxListener(){
+
+            @Override
+            public void checkboxClicked(EspWCheckBox checkbox) {
+                WurmEspMod.uniques = checkbox.checked;
+            }
+        });
+        uniquesCheckBox.checked = WurmEspMod.uniques;
+        EspWCheckBox championsCheckBox = new EspWCheckBox("Conditioned", new CheckBoxListener(){
+
+            @Override
+            public void checkboxClicked(EspWCheckBox checkbox) {
+                WurmEspMod.conditioned = checkbox.checked;
+            }
+        });
+        championsCheckBox.checked = WurmEspMod.conditioned;
+        EspWCheckBox xrayCheckBox = new EspWCheckBox("Xray", new CheckBoxListener(){
+
+            @Override
+            public void checkboxClicked(EspWCheckBox checkbox) {
+                WurmEspMod.xray = checkbox.checked;
+            }
+        });
+        xrayCheckBox.checked = WurmEspMod.xray;
+        EspWCheckBox tilesCheckBox = new EspWCheckBox("Tiles", new CheckBoxListener(){
+
+            @Override
+            public void checkboxClicked(EspWCheckBox checkbox) {
+                WurmEspMod.tilescloseby = checkbox.checked;
+            }
+        });
+        tilesCheckBox.checked = WurmEspMod.tilesclosebynotrideable;
+        EspWCheckBox tilesWalkableCheckBox = new EspWCheckBox("Rideable Tiles", new CheckBoxListener(){
+
+            @Override
+            public void checkboxClicked(EspWCheckBox checkbox) {
+                WurmEspMod.tilesclosebynotrideable = checkbox.checked;
+            }
+        });
+        tilesWalkableCheckBox.checked = WurmEspMod.tilescloseby;
+        EspWCheckBox deedCheckBox = new EspWCheckBox("Deed", new CheckBoxListener(){
+
+            @Override
+            public void checkboxClicked(EspWCheckBox checkbox) {
+                WurmEspMod.deedsize = checkbox.checked;
+            }
+        });
+        deedCheckBox.checked = WurmEspMod.deedsize;
+        checkboxes.addComponent((FlexComponent)playersCheckBox);
+        checkboxes.addComponent((FlexComponent)mobsCheckBox);
+        checkboxes.addComponent((FlexComponent)animalsCheckBox);
+        checkboxes.addComponent((FlexComponent)specialsCheckBox);
+        checkboxes.addComponent((FlexComponent)itemsCheckBox);
+        checkboxes.addComponent((FlexComponent)tilesSearchCheckBox);
+        checkboxes.addComponent((FlexComponent)uniquesCheckBox);
+        checkboxes.addComponent((FlexComponent)championsCheckBox);
+        checkboxes.addComponent((FlexComponent)xrayCheckBox);
+        checkboxes.addComponent((FlexComponent)tilesCheckBox);
+        checkboxes.addComponent((FlexComponent)tilesWalkableCheckBox);
+        checkboxes.addComponent((FlexComponent)deedCheckBox);
+        this.mainPanel.setComponent((FlexComponent)checkboxes, 0);
+        this.setComponent((FlexComponent)this.mainPanel);
+    }
+
+    public void closePressed() {
+        hud.toggleComponent((WurmComponent)this);
+    }
+
+    public void toggle() {
+        hud.toggleComponent((WurmComponent)this);
+    }
+}
+
diff --git a/src/net/encode/wurmesp/Unit.java b/src/net/encode/wurmesp/Unit.java
new file mode 100644 (file)
index 0000000..fc7a72b
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.client.renderer.Color
+ *  com.wurmonline.client.renderer.PickRenderer
+ *  com.wurmonline.client.renderer.PickRenderer$CustomPickFillDepthRender
+ *  com.wurmonline.client.renderer.PickRenderer$CustomPickFillRender
+ *  com.wurmonline.client.renderer.PickRenderer$CustomPickOutlineRender
+ *  com.wurmonline.client.renderer.PickableUnit
+ *  com.wurmonline.client.renderer.backend.Primitive$BlendMode
+ *  com.wurmonline.client.renderer.backend.Primitive$TestFunc
+ *  com.wurmonline.client.renderer.backend.Queue
+ *  com.wurmonline.client.renderer.backend.RenderState
+ */
+package net.encode.wurmesp;
+
+import com.wurmonline.client.game.World;
+import com.wurmonline.client.renderer.Color;
+import com.wurmonline.client.renderer.PickRenderer;
+import com.wurmonline.client.renderer.PickableUnit;
+import com.wurmonline.client.renderer.WorldRender;
+import com.wurmonline.client.renderer.backend.Primitive;
+import com.wurmonline.client.renderer.backend.Queue;
+import com.wurmonline.client.renderer.backend.RenderState;
+import net.encode.wurmesp.util.ReUtils;
+
+public class Unit {
+       private World world;
+    private long id;
+    private String modelName;
+    private String hoverName;
+    private PickableUnit pickableUnit;
+    private float[] color = new float[]{0.0f, 0.0f, 0.0f};
+    private float[] conditionedcolor = new float[]{0.0f, 0.0f, 0.0f};
+    private String condition;
+    public static float[] colorPlayers = new float[]{0.0f, 0.0f, 0.0f};
+    public static float[] colorPlayersEnemy = new float[]{0.0f, 0.0f, 0.0f};
+    public static float[] colorMobs = new float[]{0.0f, 0.0f, 0.0f};
+    public static float[] colorMobsAggro = new float[]{0.0f, 0.0f, 0.0f};
+    public static float[] colorSpecials = new float[]{0.0f, 0.0f, 0.0f};
+    public static float[] colorSpotted = new float[]{0.0f, 0.0f, 0.0f};
+    public static float[] colorUniques = new float[]{0.0f, 0.0f, 0.0f};
+    public static float[] colorAlert = new float[]{0.0f, 0.0f, 0.0f};
+    public static float[] colorAngry = new float[]{0.0f, 0.0f, 0.0f};
+    public static float[] colorChampion = new float[]{0.0f, 0.0f, 0.0f};
+    public static float[] colorDiseased = new float[]{0.0f, 0.0f, 0.0f};
+    public static float[] colorFierce = new float[]{0.0f, 0.0f, 0.0f};
+    public static float[] colorGreenish = new float[]{0.0f, 0.0f, 0.0f};
+    public static float[] colorHardened = new float[]{0.0f, 0.0f, 0.0f};
+    public static float[] colorLurking = new float[]{0.0f, 0.0f, 0.0f};
+    public static float[] colorRaging = new float[]{0.0f, 0.0f, 0.0f};
+    public static float[] colorScared = new float[]{0.0f, 0.0f, 0.0f};
+    public static float[] colorSlow = new float[]{0.0f, 0.0f, 0.0f};
+    public static float[] colorSly = new float[]{0.0f, 0.0f, 0.0f};
+    public static String[] aggroMOBS;
+    public static String[] uniqueMOBS;
+    public static String[] specialITEMS;
+    public static String[] spottedITEMS;
+    public static String[] conditionedMOBS;
+
+    public Unit(World world, long id, PickableUnit pickableUnit, String modelName, String hoverName) {
+       this.world = world;
+        this.id = id;
+        this.pickableUnit = pickableUnit;
+        this.modelName = modelName;
+        this.hoverName = hoverName;
+        this.determineColor();
+    }
+
+    public long getId() {
+        return this.id;
+    }
+
+    public PickableUnit getPickableUnit() {
+        return this.pickableUnit;
+    }
+
+    public float[] getColor() {
+        return this.color;
+    }
+
+    public float[] getConditionedColor() {
+        return this.conditionedcolor;
+    }
+
+    public String getHoverName() {
+        return this.hoverName;
+    }
+
+    public String getModelName() {
+        return this.modelName;
+    }
+
+    public boolean isPlayer() {
+        return this.getModelName().contains("model.creature.humanoid.human.player") && !this.getModelName().contains("zombie");
+    }
+
+    public boolean isEnemyPlayer() {
+        return this.getModelName().contains("ENEMY");
+    }
+
+    public boolean isMob() {
+        return this.getModelName().contains("model.creature") && !this.getModelName().contains("humanoid.human");
+    }
+
+    public boolean isAggroMob() {
+        for (String mob : aggroMOBS) {
+            if (!this.getHoverName().contains(mob)) continue;
+            return true;
+        }
+        return false;
+    }
+
+    public boolean isChampion() {
+        return this.getHoverName().contains("champion");
+    }
+
+    public boolean isConditioned() {
+        for (String condition : conditionedMOBS) {
+            if (!this.getHoverName().contains(condition)) continue;
+            this.condition = condition;
+            return true;
+        }
+        return false;
+    }
+
+    public boolean isUnique() {
+        for (String mob : uniqueMOBS) {
+            if (!this.getHoverName().contains(mob)) continue;
+            return true;
+        }
+        return false;
+    }
+
+    public boolean isSpecial() {
+        for (String item : specialITEMS) {
+            if (this.getHoverName().contains(item)) {
+                return true;
+            }
+            if (!this.getModelName().contains(WurmEspMod.search)) continue;
+            return true;
+        }
+        return false;
+    }
+
+    public boolean isSpotted() {
+        for (String item : spottedITEMS) {
+            if (this.getHoverName().contains(item)) {
+                return true;
+            }
+            if (!this.getModelName().contains(WurmEspMod.search)) continue;
+            return true;
+        }
+        if (WurmEspMod.searchType == WurmEspMod.SEARCHTYPE.HOVER) {
+            if (this.getHoverName().contains(WurmEspMod.search)) {
+                return true;
+            }
+        } else if (WurmEspMod.searchType == WurmEspMod.SEARCHTYPE.MODEL) {
+            if (this.getModelName().contains(WurmEspMod.search)) {
+                return true;
+            }
+        } else if (WurmEspMod.searchType == WurmEspMod.SEARCHTYPE.BOTH) {
+            if (this.getHoverName().contains(WurmEspMod.search)) {
+                return true;
+            }
+            if (this.getModelName().contains(WurmEspMod.search)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void determineColor() {
+        if (this.isPlayer()) {
+            this.color = !this.isEnemyPlayer() ? colorPlayers : colorPlayersEnemy;
+        } else if (this.isUnique()) {
+            this.color = colorUniques;
+        } else if (this.isAggroMob()) {
+            this.color = colorMobsAggro;
+        } else if (this.isMob()) {
+            this.color = colorMobs;
+        } else if (this.isSpecial()) {
+            this.color = colorSpecials;
+        } else if (this.isSpotted()) {
+            this.color = colorSpotted;
+        }
+        if (this.isConditioned()) {
+            float[] color = new float[]{0.0f, 0.0f, 0.0f};
+            switch (this.condition) {
+                case "alert": {
+                    color = colorAlert;
+                    break;
+                }
+                case "angry": {
+                    color = colorAngry;
+                    break;
+                }
+                case "champion": {
+                    color = colorChampion;
+                    break;
+                }
+                case "diseased": {
+                    color = colorDiseased;
+                    break;
+                }
+                case "fierce": {
+                    color = colorFierce;
+                    break;
+                }
+                case "greenish": {
+                    color = colorGreenish;
+                    break;
+                }
+                case "hardened": {
+                    color = colorHardened;
+                    break;
+                }
+                case "lurking": {
+                    color = colorLurking;
+                    break;
+                }
+                case "raging": {
+                    color = colorRaging;
+                    break;
+                }
+                case "scared": {
+                    color = colorScared;
+                    break;
+                }
+                case "slow": {
+                    color = colorSlow;
+                    break;
+                }
+                case "sly": {
+                    color = colorSly;
+                }
+            }
+            this.conditionedcolor = color;
+        }
+    }
+
+    public void renderUnit(Queue queue, boolean showconditioned) {
+        if (this.pickableUnit == null) {
+            return;
+        }
+        float br = 3.5f;
+        RenderState renderStateFill = new RenderState();
+        RenderState renderStateFillDepth = new RenderState();
+        RenderState renderStateOutline = new RenderState();
+        Color color = new Color();
+        if (this.isConditioned() && showconditioned) {
+            color.set(this.conditionedcolor[0], this.conditionedcolor[1], this.conditionedcolor[2]);
+        } else {
+            color.set(this.color[0], this.color[1], this.color[2]);
+        }
+        renderStateFill.alphaval = color.a = br;
+        color.a *= this.pickableUnit.getOutlineColor().a;
+        
+        WorldRender worldRenderer = (WorldRender)ReUtils.getField(this.world, "worldRenderer");
+        PickRenderer.CustomPickFillRender customPickFill = (PickRenderer.CustomPickFillRender)ReUtils.getField(worldRenderer, "customPickFill");
+        PickRenderer.CustomPickFillDepthRender customPickFillDepth = (PickRenderer.CustomPickFillDepthRender)ReUtils.getField(worldRenderer, "customPickFillDepth");
+        PickRenderer.CustomPickOutlineRender customPickOutline = (PickRenderer.CustomPickOutlineRender)ReUtils.getField(worldRenderer, "customPickOutline");
+        renderStateFill.twosided = false;
+        renderStateFill.depthtest = Primitive.TestFunc.ALWAYS;
+        renderStateFill.depthwrite = true;
+        renderStateFill.customstate = customPickFill;
+        this.pickableUnit.renderPicked(queue, renderStateFill, color);
+        renderStateOutline.alphaval = color.a = br * 0.25f;
+        color.a *= this.pickableUnit.getOutlineColor().a;
+        renderStateOutline.twosided = false;
+        renderStateOutline.depthtest = Primitive.TestFunc.LESS;
+        renderStateOutline.depthwrite = false;
+        renderStateOutline.blendmode = Primitive.BlendMode.ALPHABLEND;
+        renderStateOutline.customstate = customPickOutline;
+        this.pickableUnit.renderPicked(queue, renderStateOutline, color);
+        renderStateFillDepth.customstate = customPickFillDepth;
+        renderStateFillDepth.depthtest = Primitive.TestFunc.ALWAYS;
+        this.pickableUnit.renderPicked(queue, renderStateFillDepth, color);
+    }
+}
+
diff --git a/src/net/encode/wurmesp/WurmEspMod.java b/src/net/encode/wurmesp/WurmEspMod.java
new file mode 100644 (file)
index 0000000..e5c9bab
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.client.game.CaveDataBuffer
+ *  com.wurmonline.client.game.NearTerrainDataBuffer
+ *  com.wurmonline.client.renderer.PickRenderer
+ *  com.wurmonline.client.renderer.gui.HeadsUpDisplay
+ *  org.gotti.wurmunlimited.modloader.interfaces.Configurable
+ *  org.gotti.wurmunlimited.modloader.interfaces.Initable
+ *  org.gotti.wurmunlimited.modloader.interfaces.WurmClientMod
+ */
+package net.encode.wurmesp;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.gotti.wurmunlimited.modloader.interfaces.Configurable;
+import org.gotti.wurmunlimited.modloader.interfaces.Initable;
+import org.gotti.wurmunlimited.modloader.interfaces.WurmClientMod;
+
+import com.wurmonline.client.game.CaveDataBuffer;
+import com.wurmonline.client.game.NearTerrainDataBuffer;
+import com.wurmonline.client.renderer.PickRenderer;
+import com.wurmonline.client.renderer.gui.HeadsUpDisplay;
+
+import net.encode.wurmesp.feature.FeatureFlowerTiles;
+import net.encode.wurmesp.feature.FeatureTilesCloseBy;
+import net.encode.wurmesp.feature.FeatureTilesHighlight;
+import net.encode.wurmesp.feature.FeatureTilesWalkable;
+import net.encode.wurmesp.feature.FeatureXRay;
+import net.encode.wurmesp.feature.hook.CmdShowDeedPlan;
+import net.encode.wurmesp.feature.hook.GroundItemCellRenderableInit;
+import net.encode.wurmesp.feature.hook.GroundItemCellRenderableRemove;
+import net.encode.wurmesp.feature.hook.HandleDevInput;
+import net.encode.wurmesp.feature.hook.HeadsUpDisplayInit;
+import net.encode.wurmesp.feature.hook.MobileModelRenderableInit;
+import net.encode.wurmesp.feature.hook.MobileModelRenderableRemove;
+import net.encode.wurmesp.feature.hook.ProjectileCellRenderable;
+import net.encode.wurmesp.feature.hook.RenderPickedItem;
+import net.encode.wurmesp.util.ConfigUtils;
+import net.encode.wurmesp.util.CronoManager;
+
+public class WurmEspMod
+implements WurmClientMod,
+Initable,
+Configurable {
+    public static HeadsUpDisplay hud;
+    public static Logger logger;
+    public static Properties modProperties;
+    public static List<Unit> pickableUnits;
+    public static List<Unit> toRemove;
+    public static CronoManager xrayCronoManager;
+    public static CronoManager tilesFlowerCronoManager;
+    public static CronoManager tilesCloseByCronoManager;
+    public static CronoManager tilesHighlightCronoManager;
+    public static CronoManager tilesCloseByWalkableCronoManager;
+    public static FeatureXRay xrayManager;
+    public static FeatureFlowerTiles tilesFlowerManager;
+    public static FeatureTilesCloseBy tilesCloseByManager;
+    public static FeatureTilesHighlight tilesHighlightManager;
+    public static FeatureTilesWalkable tilesCloseByWalkableManager;
+    public static CaveDataBuffer _caveBuffer;
+    public static NearTerrainDataBuffer _terrainBuffer;
+    public static NearTerrainDataBuffer _terrainBuffer2;
+    public static CopyOnWriteArrayList<float[]> _terrain;
+    public static CopyOnWriteArrayList<float[]> _flowerTerrain;
+    public static CopyOnWriteArrayList<float[]> _closeByTerrain;
+    public static CopyOnWriteArrayList<float[]> _closeByWalkableTerrain;
+    public static CopyOnWriteArrayList<int[]> _tilesHighlightBase;
+    public static CopyOnWriteArrayList<float[]> _tilesHighlightTerrain;
+    public static String search;
+    public static SEARCHTYPE searchType;
+    public static boolean players;
+    public static boolean mobs;
+    public static boolean animals;
+    public static boolean specials;
+    public static boolean items;
+    public static boolean tilesFlower;
+    public static boolean uniques;
+    public static boolean conditioned;
+    public static boolean tilescloseby;
+    public static boolean deedsize;
+    public static boolean tileshighlight;
+    public static boolean tilesclosebynotrideable;
+    public static boolean xray;
+    public static boolean xraythread;
+    public static boolean xrayrefreshthread;
+    public static int xraydiameter;
+    public static int xrayrefreshrate;
+    public static int tilenotrideable;
+    public static int flowerdiameter;
+    public static boolean playsoundspecial;
+    public static boolean playsounditem;
+    public static boolean playsoundunique;
+    public static String soundspecial;
+    public static String sounditem;
+    public static String soundunique;
+    public static boolean conditionedcolorsallways;
+    public static boolean championmcoloralways;
+    public static String[] tilesFlowerSearch;
+    public static PickRenderer _pickRenderer;
+
+    public void init() {
+        logger.log(Level.INFO, "[WurmEspMod] Initializing");
+        xrayManager = new FeatureXRay();
+        tilesFlowerManager = new FeatureFlowerTiles();
+        tilesCloseByManager = new FeatureTilesCloseBy();
+        tilesHighlightManager = new FeatureTilesHighlight();
+        tilesCloseByWalkableManager = new FeatureTilesWalkable();
+        xrayCronoManager = new CronoManager(xrayrefreshrate * 1000);
+        tilesFlowerCronoManager = new CronoManager(1000L);
+        tilesCloseByCronoManager = new CronoManager(1000L);
+        tilesHighlightCronoManager = new CronoManager(1000L);
+        tilesCloseByWalkableCronoManager = new CronoManager(1000L);
+        new HandleDevInput();
+        new ProjectileCellRenderable();
+        new HeadsUpDisplayInit();
+        new RenderPickedItem();
+        new MobileModelRenderableInit();
+        new MobileModelRenderableRemove();
+        new GroundItemCellRenderableInit();
+        new GroundItemCellRenderableRemove();
+        new CmdShowDeedPlan();
+    }
+
+    public void configure(Properties properties) {
+        ConfigUtils.DoConfig(properties);
+        logger.log(Level.INFO, "[WurmEspMod] Config loaded");
+    }
+
+    static {
+        logger = Logger.getLogger("WurmEspMod");
+        modProperties = new Properties();
+        pickableUnits = new ArrayList<Unit>();
+        toRemove = new ArrayList<Unit>();
+        _caveBuffer = null;
+        _terrainBuffer = null;
+        _terrainBuffer2 = null;
+        _terrain = new CopyOnWriteArrayList<float[]>();
+        _flowerTerrain = new CopyOnWriteArrayList<float[]>();
+        _closeByTerrain = new CopyOnWriteArrayList<float[]>();
+        _closeByWalkableTerrain = new CopyOnWriteArrayList<float[]>();
+        _tilesHighlightBase = new CopyOnWriteArrayList<int[]>();
+        _tilesHighlightTerrain = new CopyOnWriteArrayList<float[]>();
+        search = "defaultnosearch";
+        searchType = SEARCHTYPE.NONE;
+        players = true;
+        mobs = false;
+        animals = false;
+        specials = true;
+        items = true;
+        tilesFlower = false;
+        uniques = true;
+        conditioned = true;
+        tilescloseby = false;
+        deedsize = false;
+        tileshighlight = false;
+        tilesclosebynotrideable = false;
+        xray = false;
+        xraythread = true;
+        xrayrefreshthread = true;
+        xraydiameter = 32;
+        xrayrefreshrate = 5;
+        tilenotrideable = 40;
+        flowerdiameter = 64;
+        playsoundspecial = true;
+        playsounditem = true;
+        playsoundunique = true;
+        soundspecial = "sound.fx.conch";
+        sounditem = "sound.fx.conch";
+        soundunique = "sound.fx.conch";
+        conditionedcolorsallways = false;
+        championmcoloralways = false;
+    }
+
+    public static enum SEARCHTYPE {
+        NONE,
+        HOVER,
+        MODEL,
+        BOTH;
+
+    }
+}
+
diff --git a/src/net/encode/wurmesp/feature/Feature.java b/src/net/encode/wurmesp/feature/Feature.java
new file mode 100644 (file)
index 0000000..a7cee1e
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.client.game.World
+ *  com.wurmonline.client.renderer.backend.Queue
+ */
+package net.encode.wurmesp.feature;
+
+import com.wurmonline.client.game.World;
+import com.wurmonline.client.renderer.backend.Queue;
+
+public abstract class Feature {
+    protected Queue queuePick;
+    protected World world;
+    public boolean first = true;
+
+    public void setWorldQueue(World world, Queue queue) {
+        this.world = world;
+        this.queuePick = queue;
+    }
+
+    public abstract void refresh();
+
+    public abstract void queue();
+}
+
diff --git a/src/net/encode/wurmesp/feature/FeatureFlowerTiles.java b/src/net/encode/wurmesp/feature/FeatureFlowerTiles.java
new file mode 100644 (file)
index 0000000..75079e1
--- /dev/null
@@ -0,0 +1,67 @@
+package net.encode.wurmesp.feature;
+
+import com.wurmonline.client.game.PlayerPosition;
+import com.wurmonline.mesh.GrassData;
+import com.wurmonline.mesh.Tiles;
+
+import net.encode.wurmesp.WurmEspMod;
+import net.encode.wurmesp.util.RenderUtils;
+
+public class FeatureFlowerTiles 
+extends Feature {
+
+       @Override
+       public void refresh() {
+               WurmEspMod._flowerTerrain.clear();
+        WurmEspMod._terrainBuffer = this.world.getNearTerrainBuffer();
+        PlayerPosition pos = this.world.getPlayer().getPos();
+        int px = pos.getTileX();
+        int py = pos.getTileY();
+        int size = WurmEspMod.flowerdiameter;
+        int sx = px - size / 2;
+        int sy = py - size / 2;
+        float ox = this.world.getRenderOriginX();
+        float oy = this.world.getRenderOriginY();
+        for (int x = 0; x < size + 1; ++x) {
+            for (int y = 0; y < size + 1; ++y) {
+                float tileX = x + sx;
+                float tileY = y + sy;
+                byte data = WurmEspMod._terrainBuffer.getData((int)tileX, (int)tileY);
+                Tiles.Tile tileType = WurmEspMod._terrainBuffer.getTileType((int)tileX, (int)tileY);
+                if (tileType.isGrass() && !tileType.isBush() && !tileType.isTree()) {
+                       for(String name : WurmEspMod.tilesFlowerSearch)
+                       {
+                               if(GrassData.getFlowerTypeName(data).contains(name))
+                        {
+                               float curX = tileX * 4.0f - ox;
+                            float curY = tileY * 4.0f - oy;
+                               float nextX = (tileX + 1.0f) * 4.0f - ox;
+                            float nextY = (tileY + 1.0f) * 4.0f - oy;
+                            float x0 = curX + 0.1f;
+                            float y0 = curY + 0.1f;
+                            float x1 = nextX - 0.1f;
+                            float y1 = nextY - 0.1f;
+                            float z0 = WurmEspMod._terrainBuffer.getHeight((int)tileX, (int)tileY);
+                            float z1 = WurmEspMod._terrainBuffer.getHeight((int)tileX + 1, (int)tileY);
+                            float z2 = WurmEspMod._terrainBuffer.getHeight((int)tileX, (int)tileY + 1);
+                            float z3 = WurmEspMod._terrainBuffer.getHeight((int)tileX + 1, (int)tileY + 1);
+                            WurmEspMod._flowerTerrain.add(new float[]{x0, z0, y0, x1, z1, y0, x0, z2, y1, x1, z3, y1});
+                        }
+                       }
+                }
+            }
+        }
+       }
+
+       @Override
+       public void queue() {
+               if (WurmEspMod._flowerTerrain == null) {
+            return;
+        }
+        WurmEspMod._flowerTerrain.forEach(t -> {
+            float[] color = new float[]{0.0f, 1.0f, 0.0f, 0.5f};
+            int[] indexdata = new int[]{1, 0, 0, 2, 2, 3, 3, 1};
+            RenderUtils.renderPrimitiveLines(4, t, indexdata, this.queuePick, color);
+        });
+       }
+}
diff --git a/src/net/encode/wurmesp/feature/FeatureTilesCloseBy.java b/src/net/encode/wurmesp/feature/FeatureTilesCloseBy.java
new file mode 100644 (file)
index 0000000..2fde55a
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.client.game.PlayerPosition
+ */
+package net.encode.wurmesp.feature;
+
+import com.wurmonline.client.game.PlayerPosition;
+import net.encode.wurmesp.WurmEspMod;
+import net.encode.wurmesp.util.RenderUtils;
+import net.encode.wurmesp.util.TerrainUtils;
+
+public class FeatureTilesCloseBy
+extends Feature {
+    @Override
+    public void refresh() {
+        WurmEspMod._closeByTerrain.clear();
+        WurmEspMod._terrainBuffer = this.world.getNearTerrainBuffer();
+        PlayerPosition pos = this.world.getPlayer().getPos();
+        int px = pos.getTileX();
+        int py = pos.getTileY();
+        int size = 6;
+        int sx = px - size / 2;
+        int sy = py - size / 2;
+        float ox = this.world.getRenderOriginX();
+        float oy = this.world.getRenderOriginY();
+        for (int x = 0; x < size + 1; ++x) {
+            for (int y = 0; y < size + 1; ++y) {
+                float tileX = x + sx;
+                float tileY = y + sy;
+                float curX = tileX * 4.0f - ox;
+                float curY = tileY * 4.0f - oy;
+                float nextX = (tileX + 1.0f) * 4.0f - ox;
+                float nextY = (tileY + 1.0f) * 4.0f - oy;
+                float x0 = curX + 0.1f;
+                float y0 = curY + 0.1f;
+                float x1 = nextX - 0.1f;
+                float y1 = nextY - 0.1f;
+                float z0 = WurmEspMod._terrainBuffer.getHeight((int)tileX, (int)tileY);
+                float z1 = WurmEspMod._terrainBuffer.getHeight((int)tileX + 1, (int)tileY);
+                float z2 = WurmEspMod._terrainBuffer.getHeight((int)tileX, (int)tileY + 1);
+                float z3 = WurmEspMod._terrainBuffer.getHeight((int)tileX + 1, (int)tileY + 1);
+                WurmEspMod._closeByTerrain.add(new float[]{x0, z0, y0, x1, z1, y0, x0, z2, y1, x1, z3, y1});
+            }
+        }
+    }
+
+    @Override
+    public void queue() {
+        if (WurmEspMod._closeByTerrain == null) {
+            return;
+        }
+        WurmEspMod._closeByTerrain.forEach(t -> {
+            float[] color = TerrainUtils.isFlat(t) ? new float[]{0.0f, 1.0f, 0.0f, 0.5f} : new float[]{1.0f, 1.0f, 0.0f, 0.5f};
+            int[] indexdata = new int[]{1, 0, 0, 2, 2, 3, 3, 1};
+            RenderUtils.renderPrimitiveLines(4, t, indexdata, this.queuePick, color);
+        });
+    }
+}
+
diff --git a/src/net/encode/wurmesp/feature/FeatureTilesHighlight.java b/src/net/encode/wurmesp/feature/FeatureTilesHighlight.java
new file mode 100644 (file)
index 0000000..aacb491
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.client.game.PlayerPosition
+ *  com.wurmonline.client.game.World
+ */
+package net.encode.wurmesp.feature;
+
+import com.wurmonline.client.game.PlayerPosition;
+import com.wurmonline.client.game.World;
+import net.encode.wurmesp.WurmEspMod;
+import net.encode.wurmesp.util.RenderUtils;
+
+public class FeatureTilesHighlight
+extends Feature {
+    @Override
+    public void refresh() {
+        WurmEspMod._tilesHighlightTerrain.clear();
+        WurmEspMod._terrainBuffer = this.world.getNearTerrainBuffer();
+        float ox = this.world.getRenderOriginX();
+        float oy = this.world.getRenderOriginY();
+        WurmEspMod._tilesHighlightBase.forEach(base -> {
+            float curX = (float)(base[0] * 4) - ox;
+            float curY = (float)(base[1] * 4) - oy;
+            float nextX = (float)((base[0] + 1) * 4) - ox;
+            float nextY = (float)((base[1] + 1) * 4) - oy;
+            float x0 = curX + 0.1f;
+            float y0 = curY + 0.1f;
+            float x1 = nextX - 0.1f;
+            float y1 = nextY - 0.1f;
+            float z0 = WurmEspMod._terrainBuffer.getHeight(base[0], base[1]);
+            float z1 = WurmEspMod._terrainBuffer.getHeight(base[0] + 1, base[1]);
+            float z2 = WurmEspMod._terrainBuffer.getHeight(base[0], base[1] + 1);
+            float z3 = WurmEspMod._terrainBuffer.getHeight(base[0] + 1, base[1] + 1);
+            WurmEspMod._tilesHighlightTerrain.add(new float[]{x0, z0, y0, x1, z1, y0, x0, z2, y1, x1, z3, y1, x0, 0.0f, y0, x1, 0.0f, y0, x0, 0.0f, y1, x1, 0.0f, y1});
+        });
+    }
+
+    @Override
+    public void queue() {
+        if (WurmEspMod._tilesHighlightTerrain == null) {
+            return;
+        }
+        WurmEspMod._tilesHighlightTerrain.forEach(t -> {
+            float[] color = new float[]{1.0f, 0.0f, 0.0f, 1.0f};
+            int[] indexdata = new int[]{1, 0, 0, 2, 2, 3, 3, 1, 1, 2, 0, 3, 5, 4, 4, 6, 6, 7, 7, 5, 0, 4, 1, 5, 2, 6, 3, 7};
+            RenderUtils.renderPrimitiveLines(8, t, indexdata, this.queuePick, color);
+        });
+    }
+
+    public void setWorld(World world) {
+        this.world = world;
+    }
+
+    public void addData(String direction, int tiles, int times, int space) {
+        PlayerPosition pos = this.world.getPlayer().getPos();
+        int baseTileX = pos.getTileX();
+        int baseTileY = pos.getTileY();
+        WurmEspMod._tilesHighlightBase.add(new int[]{baseTileX, baseTileY});
+        block12: for (int i = 0; i < times; ++i) {
+            switch (direction) {
+                case "n": {
+                    int s;
+                    baseTileY -= tiles;
+                    for (s = 1; s < space + 1; ++s) {
+                        WurmEspMod._tilesHighlightBase.add(new int[]{baseTileX, --baseTileY});
+                    }
+                    continue block12;
+                }
+                case "s": {
+                    int s;
+                    baseTileY += tiles;
+                    for (s = 1; s < space + 1; ++s) {
+                        WurmEspMod._tilesHighlightBase.add(new int[]{baseTileX, ++baseTileY});
+                    }
+                    continue block12;
+                }
+                case "e": {
+                    int s;
+                    baseTileX += tiles;
+                    for (s = 1; s < space + 1; ++s) {
+                        WurmEspMod._tilesHighlightBase.add(new int[]{++baseTileX, baseTileY});
+                    }
+                    continue block12;
+                }
+                case "w": {
+                    int s;
+                    baseTileX -= tiles;
+                    for (s = 1; s < space + 1; ++s) {
+                        WurmEspMod._tilesHighlightBase.add(new int[]{--baseTileX, baseTileY});
+                    }
+                    continue block12;
+                }
+            }
+        }
+    }
+
+    public void addData(int x, int y) {
+        WurmEspMod._tilesHighlightBase.add(new int[]{x, y});
+    }
+
+    public void addData(int radius) {
+        int tileX = this.world.getPlayer().getPos().getTileX();
+        int tileY = this.world.getPlayer().getPos().getTileY();
+        int startX = tileX - radius;
+        int startY = tileY - radius;
+        int endX = tileX + radius;
+        int endY = tileY + radius;
+        this.addData(startX, startY, endX, endY);
+    }
+
+    public void addData(int startX, int startY, int endX, int endY) {
+        WurmEspMod._tilesHighlightBase.add(new int[]{startX, startY});
+        WurmEspMod._tilesHighlightBase.add(new int[]{startX, endY});
+        WurmEspMod._tilesHighlightBase.add(new int[]{endX, startY});
+        WurmEspMod._tilesHighlightBase.add(new int[]{endX, endY});
+    }
+}
+
diff --git a/src/net/encode/wurmesp/feature/FeatureTilesWalkable.java b/src/net/encode/wurmesp/feature/FeatureTilesWalkable.java
new file mode 100644 (file)
index 0000000..2f7b853
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.client.game.PlayerPosition
+ */
+package net.encode.wurmesp.feature;
+
+import com.wurmonline.client.game.PlayerPosition;
+import net.encode.wurmesp.WurmEspMod;
+import net.encode.wurmesp.util.RenderUtils;
+import net.encode.wurmesp.util.TerrainUtils;
+
+public class FeatureTilesWalkable
+extends Feature {
+    @Override
+    public void refresh() {
+        WurmEspMod._closeByWalkableTerrain.clear();
+        WurmEspMod._terrainBuffer2 = this.world.getNearTerrainBuffer();
+        PlayerPosition pos = this.world.getPlayer().getPos();
+        int px = pos.getTileX();
+        int py = pos.getTileY();
+        int size = 6;
+        int sx = px - size / 2;
+        int sy = py - size / 2;
+        float ox = this.world.getRenderOriginX();
+        float oy = this.world.getRenderOriginY();
+        for (int x = 0; x < size + 1; ++x) {
+            for (int y = 0; y < size + 1; ++y) {
+                float tileX = x + sx;
+                float tileY = y + sy;
+                float curX = tileX * 4.0f - ox;
+                float curY = tileY * 4.0f - oy;
+                float nextX = (tileX + 1.0f) * 4.0f - ox;
+                float nextY = (tileY + 1.0f) * 4.0f - oy;
+                float x0 = curX + 0.2f;
+                float y0 = curY + 0.2f;
+                float x1 = nextX - 0.2f;
+                float y1 = nextY - 0.2f;
+                float z0 = WurmEspMod._terrainBuffer2.getHeight((int)tileX, (int)tileY);
+                float z1 = WurmEspMod._terrainBuffer2.getHeight((int)tileX + 1, (int)tileY);
+                float z2 = WurmEspMod._terrainBuffer2.getHeight((int)tileX, (int)tileY + 1);
+                float z3 = WurmEspMod._terrainBuffer2.getHeight((int)tileX + 1, (int)tileY + 1);
+                WurmEspMod._closeByWalkableTerrain.add(new float[]{x0, z0, y0, x1, z1, y0, x0, z2, y1, x1, z3, y1});
+            }
+        }
+    }
+
+    @Override
+    public void queue() {
+        if (WurmEspMod._closeByWalkableTerrain == null) {
+            return;
+        }
+        WurmEspMod._closeByWalkableTerrain.stream().filter(t -> TerrainUtils.isNotRideable(t)).forEachOrdered(t -> {
+            float[] color = new float[]{1.0f, 0.0f, 0.0f, 0.5f};
+            int[] indexdata = new int[]{1, 0, 0, 2, 2, 3, 3, 1};
+            RenderUtils.renderPrimitiveLines(4, t, indexdata, this.queuePick, color);
+        });
+    }
+}
+
diff --git a/src/net/encode/wurmesp/feature/FeatureXRay.java b/src/net/encode/wurmesp/feature/FeatureXRay.java
new file mode 100644 (file)
index 0000000..d2d677e
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.client.game.PlayerPosition
+ *  com.wurmonline.client.renderer.Color
+ *  com.wurmonline.client.renderer.HitNamesData
+ *  com.wurmonline.client.renderer.backend.RenderState
+ *  com.wurmonline.client.renderer.cave.CaveRender
+ *  com.wurmonline.mesh.Tiles$Tile
+ */
+package net.encode.wurmesp.feature;
+
+import com.wurmonline.client.game.PlayerPosition;
+import com.wurmonline.mesh.Tiles;
+import java.awt.Color;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import net.encode.wurmesp.WurmEspMod;
+import net.encode.wurmesp.util.RenderUtils;
+import net.encode.wurmesp.util.XrayColors;
+
+public class FeatureXRay
+extends Feature {
+    @Override
+    public void refresh() {
+        if (!this.world.isOwnBodyAdded()) {
+            return;
+        }
+        WurmEspMod._terrain.clear();
+        WurmEspMod._caveBuffer = this.world.getCaveBuffer();
+        PlayerPosition pos = this.world.getPlayer().getPos();
+        int px = pos.getTileX();
+        int py = pos.getTileY();
+        int size = WurmEspMod.xraydiameter;
+        int sx = px - size / 2;
+        int sy = py - size / 2;
+        float ox = this.world.getRenderOriginX();
+        float oy = this.world.getRenderOriginY();
+        for (int x = 0; x < size; ++x) {
+            for (int y = size - 1; y >= 0; --y) {
+                try {
+                    int tileX = x + sx;
+                    int tileY = y + sy;
+                    Tiles.Tile tile = WurmEspMod._caveBuffer.getTileType(tileX, tileY);
+                    if (tile == null || !tile.isOreCave()) continue;
+                    Color color = XrayColors.getColorFor(tile);
+                    float[] colorF = new float[]{(float)color.getRed() / 255.0f, (float)color.getGreen() / 255.0f, (float)color.getBlue() / 255.0f};
+                    float curX = (float)(tileX * 4) - ox;
+                    float curY = (float)(tileY * 4) - oy;
+                    float nextX = (float)((tileX + 1) * 4) - ox;
+                    float nextY = (float)((tileY + 1) * 4) - oy;
+                    float x0 = curX + 0.2f;
+                    float y0 = curY + 0.2f;
+                    float x1 = nextX - 0.2f;
+                    float y1 = nextY - 0.2f;
+                    WurmEspMod._terrain.add(new float[]{x0, y0, x1, y1, colorF[0], colorF[1], colorF[2]});
+                    continue;
+                }
+                catch (IllegalArgumentException | SecurityException ex) {
+                    Logger.getLogger(FeatureXRay.class.getName()).log(Level.SEVERE, null, ex);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void queue() {
+       if (WurmEspMod._terrain == null) {
+            return;
+        }
+       WurmEspMod._terrain.stream().forEach(t -> {
+               float x0 = t[0];
+                       float y0 = t[1];
+                       float x1 = t[2];
+                       float y1 = t[3];
+                       
+                       float[] color = new float[]{t[4],t[5],t[6], 1.0F};
+                       PlayerPosition pos = this.world.getPlayer().getPos();
+
+                       float z0 = pos.getH();
+                       float z1 = z0 + 3;
+                       
+                       float[] vertexdata = new float[] { 
+                                       x1, z0, y0, 
+                                       x1, z1, y0, 
+                                       x0, z1, y0, 
+                                       x0, z0, y0, 
+                                       x1, z0, y1, 
+                                       x1, z1, y1, 
+                                       x0, z1, y1, 
+                                       x0, z0, y1 };
+                       
+                       int[] indexdata = new int[] { 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 };
+            RenderUtils.renderPrimitiveLines(8, vertexdata, indexdata, this.queuePick, color);
+        });
+       /*
+        if (!this.world.isOwnBodyAdded()) {
+            return;
+        }
+        WurmEspMod._terrain.clear();
+        WurmEspMod._caveBuffer = this.world.getCaveBuffer();
+        PlayerPosition pos = this.world.getPlayer().getPos();
+        int px = pos.getTileX();
+        int py = pos.getTileY();
+        int size = WurmEspMod.xraydiameter;
+        int sx = px - size / 2;
+        int sy = py - size / 2;
+        WorldRender worldRenderer = (WorldRender)ReUtils.getField(this.world, "worldRenderer");
+        CaveRender caveRenderer = (CaveRender)ReUtils.getField(worldRenderer, "caveRenderer");
+        for (int x = 0; x < size; ++x) {
+            for (int y = size - 1; y >= 0; --y) {
+                try {
+                    int tileX = x + sx;
+                    int tileY = y + sy;
+                    for (int side = 0; side < 7; ++side) {
+                        IntBuffer intBuffer = IntBuffer.allocate(3);
+                        intBuffer.put(tileX);
+                        intBuffer.put(tileY);
+                        intBuffer.put(side);
+                        Class<HitNamesData> cls = HitNamesData.class;
+                        Constructor<HitNamesData> constructor = cls.getDeclaredConstructor(IntBuffer.class, Integer.TYPE);
+                        constructor.setAccessible(true);
+                        HitNamesData hitNames = (HitNamesData)constructor.newInstance(intBuffer, 3);
+                        caveRenderer.getPickedWall(hitNames).renderPicked(this.queuePick, RenderState.RENDERSTATE_DEFAULT, com.wurmonline.client.renderer.Color.GREEN);
+                    }
+                    continue;
+                }
+                catch (IllegalAccessException | IllegalArgumentException | InstantiationException | NoSuchMethodException | SecurityException | InvocationTargetException ex) {
+                    Logger.getLogger(FeatureXRay.class.getName()).log(Level.SEVERE, null, ex);
+                }
+            }
+        }*/
+    }
+}
+
diff --git a/src/net/encode/wurmesp/feature/hook/CmdShowDeedPlan.java b/src/net/encode/wurmesp/feature/hook/CmdShowDeedPlan.java
new file mode 100644 (file)
index 0000000..f50cd6f
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.client.comm.SimpleServerConnectionClass
+ */
+package net.encode.wurmesp.feature.hook;
+
+import com.wurmonline.client.comm.SimpleServerConnectionClass;
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.util.logging.Level;
+import net.encode.wurmesp.WurmEspMod;
+
+public class CmdShowDeedPlan
+extends Hook {
+    public CmdShowDeedPlan() {
+        this.prepareHook("com.wurmonline.client.comm.SimpleServerConnectionClass", "reallyHandleCmdShowDeedPlan", "(Ljava/nio/ByteBuffer;)V", () -> (proxy, method, args) -> {
+            if (WurmEspMod.deedsize) {
+                ByteBuffer bb = (ByteBuffer)args[0];
+                byte type = bb.get();
+                switch (type) {
+                    case 0: {
+                        int qId = bb.getInt();
+                        SimpleServerConnectionClass simpleServerConnectionClass = (SimpleServerConnectionClass)proxy;
+                        Method readStringByteLengthMethod = simpleServerConnectionClass.getClass().getDeclaredMethod("readStringByteLength", ByteBuffer.class);
+                        readStringByteLengthMethod.setAccessible(true);
+                        Object[] readStringByteLengthArgs = new Object[]{bb};
+                        String deedName = (String)readStringByteLengthMethod.invoke(simpleServerConnectionClass, readStringByteLengthArgs);
+                        int tokenX = bb.getInt();
+                        int tokenY = bb.getInt();
+                        int startX = bb.getInt();
+                        int startY = bb.getInt();
+                        int endX = bb.getInt();
+                        int endY = bb.getInt();
+                        int perimSize = bb.getInt();
+                        WurmEspMod.tilesHighlightManager.addData(startX, startY, endX, endY);
+                        WurmEspMod.tileshighlight = true;
+                    }
+                }
+            } else {
+                method.invoke(proxy, args);
+            }
+            return null;
+        });
+        WurmEspMod.logger.log(Level.INFO, "[WurmEspMod] SimpleServerConnectionClass.reallyHandleCmdShowDeedPlan hooked");
+    }
+}
+
diff --git a/src/net/encode/wurmesp/feature/hook/GroundItemCellRenderableInit.java b/src/net/encode/wurmesp/feature/hook/GroundItemCellRenderableInit.java
new file mode 100644 (file)
index 0000000..3d6b94d
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.client.renderer.GroundItemData
+ *  com.wurmonline.client.renderer.PickableUnit
+ *  org.gotti.wurmunlimited.modloader.ReflectionUtil
+ */
+package net.encode.wurmesp.feature.hook;
+
+import com.wurmonline.client.renderer.GroundItemData;
+import com.wurmonline.client.renderer.PickableUnit;
+import com.wurmonline.client.renderer.cell.CellRenderable;
+
+import java.lang.reflect.Field;
+import java.util.logging.Level;
+import net.encode.wurmesp.Unit;
+import net.encode.wurmesp.WurmEspMod;
+import net.encode.wurmesp.util.SoundUtils;
+import org.gotti.wurmunlimited.modloader.ReflectionUtil;
+
+public class GroundItemCellRenderableInit
+extends Hook {
+    public GroundItemCellRenderableInit() {
+        this.prepareHook("com.wurmonline.client.renderer.cell.GroundItemCellRenderable", "initialize", "()V", () -> (proxy, method, args) -> {
+            method.invoke(proxy, args);
+            Class<?> cls = proxy.getClass();
+            PickableUnit pUnit = (PickableUnit)proxy;
+            GroundItemData item = (GroundItemData)ReflectionUtil.getPrivateField((Object)proxy, (Field)ReflectionUtil.getField(cls, (String)"item"));
+            Unit unit = new Unit(CellRenderable.world, item.getId(), pUnit, item.getModelName().toString(), ((PickableUnit)proxy).getHoverName());
+            if (unit.isSpecial()) {
+                WurmEspMod.pickableUnits.add(unit);
+                if (WurmEspMod.specials && WurmEspMod.playsoundspecial) {
+                    SoundUtils.playSound(WurmEspMod.soundspecial);
+                }
+            } else if (unit.isSpotted()) {
+                WurmEspMod.pickableUnits.add(unit);
+                if (WurmEspMod.items && WurmEspMod.playsounditem) {
+                    SoundUtils.playSound(WurmEspMod.sounditem);
+                }
+            }
+            return null;
+        });
+        WurmEspMod.logger.log(Level.INFO, "[WurmEspMod] GroundItemCellRenderable.initialize hooked");
+    }
+}
+
diff --git a/src/net/encode/wurmesp/feature/hook/GroundItemCellRenderableRemove.java b/src/net/encode/wurmesp/feature/hook/GroundItemCellRenderableRemove.java
new file mode 100644 (file)
index 0000000..eea7b59
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.client.renderer.GroundItemData
+ *  org.gotti.wurmunlimited.modloader.ReflectionUtil
+ */
+package net.encode.wurmesp.feature.hook;
+
+import java.lang.reflect.Field;
+import java.util.logging.Level;
+
+import org.gotti.wurmunlimited.modloader.ReflectionUtil;
+
+import com.wurmonline.client.renderer.GroundItemData;
+
+import net.encode.wurmesp.Unit;
+import net.encode.wurmesp.WurmEspMod;
+
+public class GroundItemCellRenderableRemove
+extends Hook {
+    public GroundItemCellRenderableRemove() {
+        this.prepareHook("com.wurmonline.client.renderer.cell.GroundItemCellRenderable", "removed", "(Z)V", () -> (proxy, method, args) -> {
+            method.invoke(proxy, args);
+            Class<?> cls = proxy.getClass();
+            GroundItemData item = (GroundItemData)ReflectionUtil.getPrivateField((Object)proxy, (Field)ReflectionUtil.getField(cls, (String)"item"));
+            for (Unit unit : WurmEspMod.pickableUnits) {
+                if (unit.getId() != item.getId()) continue;
+                WurmEspMod.toRemove.add(unit);
+            }
+            for (Unit unit : WurmEspMod.toRemove) {
+                if (unit.getId() != item.getId()) continue;
+                WurmEspMod.pickableUnits.remove(unit);
+            }
+            WurmEspMod.toRemove.clear();
+            return null;
+        });
+        WurmEspMod.logger.log(Level.INFO, "[WurmEspMod] GroundItemCellRenderable.removed hooked");
+    }
+}
+
diff --git a/src/net/encode/wurmesp/feature/hook/HandleDevInput.java b/src/net/encode/wurmesp/feature/hook/HandleDevInput.java
new file mode 100644 (file)
index 0000000..8e068f2
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.client.game.PlayerPosition
+ *  javassist.CannotCompileException
+ *  javassist.ClassPool
+ *  javassist.CtClass
+ *  javassist.NotFoundException
+ *  org.gotti.wurmunlimited.modloader.classhooks.HookManager
+ */
+package net.encode.wurmesp.feature.hook;
+
+import com.wurmonline.client.game.PlayerPosition;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javassist.CannotCompileException;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.NotFoundException;
+import net.encode.wurmesp.WurmEspMod;
+import net.encode.wurmesp.util.ConfigUtils;
+import org.gotti.wurmunlimited.modloader.classhooks.HookManager;
+
+public class HandleDevInput {
+    public HandleDevInput() {
+        try {
+            ClassPool classPool = HookManager.getInstance().getClassPool();
+            CtClass ctWurmConsole = classPool.getCtClass("com.wurmonline.client.console.WurmConsole");
+            ctWurmConsole.getMethod("handleDevInput", "(Ljava/lang/String;[Ljava/lang/String;)Z").insertBefore("if (net.encode.wurmesp.feature.hook.HandleDevInput.handleInput($1,$2)) return true;");
+            WurmEspMod.logger.log(Level.INFO, "[WurmEspMod] Return inserted on handleDevInput");
+        }
+        catch (CannotCompileException | NotFoundException ex) {
+            Logger.getLogger(HandleDevInput.class.getName()).log(Level.SEVERE, null, ex);
+        }
+        WurmEspMod.logger.log(Level.INFO, "[WurmEspMod] Return inserted on handleDevInput");
+    }
+
+    public static boolean handleInput(String cmd, String[] data) {
+        if (cmd.equals("esp")) {
+            if (data.length == 2) {
+                switch (data[1]) {
+                    case "players": {
+                        WurmEspMod.players = !WurmEspMod.players;
+                        WurmEspMod.hud.consoleOutput("ESP players changed to: " + Boolean.toString(WurmEspMod.players));
+                        break;
+                    }
+                    case "mobs": {
+                        WurmEspMod.mobs = !WurmEspMod.mobs;
+                        WurmEspMod.hud.consoleOutput("ESP mobs changed to: " + Boolean.toString(WurmEspMod.mobs));
+                        break;
+                    }
+                    case "specials": {
+                        WurmEspMod.specials = !WurmEspMod.specials;
+                        WurmEspMod.hud.consoleOutput("ESP specials changed to: " + Boolean.toString(WurmEspMod.specials));
+                        break;
+                    }
+                    case "uniques": {
+                        WurmEspMod.uniques = !WurmEspMod.uniques;
+                        WurmEspMod.hud.consoleOutput("ESP uniques changed to: " + Boolean.toString(WurmEspMod.uniques));
+                        break;
+                    }
+                    case "conditioned": {
+                        WurmEspMod.conditioned = !WurmEspMod.conditioned;
+                        WurmEspMod.hud.consoleOutput("ESP champions changed to: " + Boolean.toString(WurmEspMod.conditioned));
+                        break;
+                    }
+                    case "xray": {
+                        WurmEspMod.xray = !WurmEspMod.xray;
+                        WurmEspMod.hud.consoleOutput("ESP xray changed to: " + Boolean.toString(WurmEspMod.xray));
+                        break;
+                    }
+                    case "tilescloseby": {
+                        WurmEspMod.tilescloseby = !WurmEspMod.tilescloseby;
+                        WurmEspMod.hud.consoleOutput("ESP tilescloseby changed to: " + Boolean.toString(WurmEspMod.tilescloseby));
+                        break;
+                    }
+                    case "deedsize": {
+                        WurmEspMod.deedsize = !WurmEspMod.deedsize;
+                        WurmEspMod.hud.consoleOutput("ESP deedsize changed to: " + Boolean.toString(WurmEspMod.deedsize));
+                        break;
+                    }
+                    case "search": {
+                        WurmEspMod.hud.consoleOutput("Usage: esp search {h/m/hm/off} <name>");
+                        break;
+                    }
+                    case "planner": {
+                        WurmEspMod.hud.consoleOutput("Usage: esp planner {n/s/e/w} <tiles> <times> <space>");
+                        WurmEspMod.hud.consoleOutput("Usage: esp planner square <startX> <startY> <endX> <endY>");
+                        WurmEspMod.hud.consoleOutput("Usage: esp planner square <radius>");
+                        WurmEspMod.hud.consoleOutput("Usage: esp planner tile <tileX> <tileY>");
+                        WurmEspMod.hud.consoleOutput("Usage: esp planner clear");
+                        break;
+                    }
+                    case "reload": {
+                        ConfigUtils.loadProperties("wurmesp");
+                        ConfigUtils.DoConfig(WurmEspMod.modProperties);
+                        WurmEspMod.hud.consoleOutput("[WurmEspMod] Config Reloaded");
+                        break;
+                    }
+                    default: {
+                        WurmEspMod.hud.consoleOutput("Usage: esp {players|mobs|specials|uniques|conditioned|xray|tilescloseby|deedsize|reload}");
+                    }
+                }
+                return true;
+            }
+            if (data.length > 2) {
+                switch (data[1]) {
+                    case "search": {
+                        if (data[2].equals("h")) {
+                            WurmEspMod.search = data[3];
+                            WurmEspMod.searchType = WurmEspMod.SEARCHTYPE.HOVER;
+                            WurmEspMod.hud.consoleOutput("Searching for " + WurmEspMod.search + " in HoverName");
+                            break;
+                        }
+                        if (data[2].equals("m")) {
+                            WurmEspMod.search = data[3];
+                            WurmEspMod.searchType = WurmEspMod.SEARCHTYPE.MODEL;
+                            WurmEspMod.hud.consoleOutput("Searching for " + WurmEspMod.search + " in ModelName");
+                            break;
+                        }
+                        if (data[2].equals("hm")) {
+                            WurmEspMod.search = data[3];
+                            WurmEspMod.searchType = WurmEspMod.SEARCHTYPE.BOTH;
+                            WurmEspMod.hud.consoleOutput("Searching for " + WurmEspMod.search + " in HoverName and ModelName");
+                            break;
+                        }
+                        if (data[2].equals("off")) {
+                            WurmEspMod.search = "";
+                            WurmEspMod.searchType = WurmEspMod.SEARCHTYPE.NONE;
+                            WurmEspMod.hud.consoleOutput("Searching off");
+                            break;
+                        }
+                        WurmEspMod.hud.consoleOutput("Usage: esp search {h/m/hm/off} <name>");
+                        break;
+                    }
+                    case "planner": {
+                        if (data.length == 3 && data[2].equals("clear")) {
+                            WurmEspMod._tilesHighlightBase.clear();
+                            WurmEspMod.tileshighlight = false;
+                            WurmEspMod.hud.consoleOutput("Planner data cleared.");
+                            break;
+                        }
+                        if (data.length == 3 && data[2].equals("tile")) {
+                            PlayerPosition pos = WurmEspMod.hud.getWorld().getPlayer().getPos();
+                            int tileX = pos.getTileX();
+                            int tileY = pos.getTileY();
+                            WurmEspMod.tilesHighlightManager.addData(tileX, tileY);
+                            WurmEspMod.tileshighlight = true;
+                            WurmEspMod.hud.consoleOutput("Added planner data. [TileX: " + String.valueOf(tileX) + "][tileY: " + String.valueOf(tileY) + "]");
+                            break;
+                        }
+                        if (data.length == 4 && data[2].equals("square")) {
+                            int radius = Integer.parseInt(data[3]);
+                            WurmEspMod.tilesHighlightManager.addData(radius);
+                            WurmEspMod.tileshighlight = true;
+                            WurmEspMod.hud.consoleOutput("Added planner data. [radius: " + data[3] + "]");
+                            break;
+                        }
+                        if (data.length == 5 && data[2].equals("tile")) {
+                            int tileX = Integer.parseInt(data[3]);
+                            int tileY = Integer.parseInt(data[4]);
+                            WurmEspMod.tilesHighlightManager.addData(tileX, tileY);
+                            WurmEspMod.tileshighlight = true;
+                            WurmEspMod.hud.consoleOutput("Added planner data. [TileX: " + data[3] + "][tileY: " + data[4] + "]");
+                            break;
+                        }
+                        if (data.length == 6 && "nsew".contains(data[2])) {
+                            String direction = data[2];
+                            int tiles = Integer.parseInt(data[3]);
+                            int times = Integer.parseInt(data[4]);
+                            int space = Integer.parseInt(data[5]);
+                            WurmEspMod.tilesHighlightManager.addData(direction, tiles, times, space);
+                            WurmEspMod.tileshighlight = true;
+                            WurmEspMod.hud.consoleOutput("Added planner data. [direction: " + direction + "][tiles: " + data[3] + "][times: " + data[4] + "][space: " + data[5] + "]");
+                            break;
+                        }
+                        if (data.length == 7 && data[2].equals("square")) {
+                            int startX = Integer.parseInt(data[3]);
+                            int startY = Integer.parseInt(data[4]);
+                            int endX = Integer.parseInt(data[5]);
+                            int endY = Integer.parseInt(data[6]);
+                            WurmEspMod.tilesHighlightManager.addData(startX, startY, endX, endY);
+                            WurmEspMod.tileshighlight = true;
+                            WurmEspMod.hud.consoleOutput("Added planner data. [startX: " + data[3] + "][startY: " + data[4] + "][endX: " + data[5] + "][endY: " + data[6] + "]");
+                            break;
+                        }
+                        WurmEspMod.hud.consoleOutput("Usage: esp planner {n/s/e/w} <tiles> <times> <space>");
+                        WurmEspMod.hud.consoleOutput("Usage: esp planner square <startX> <startY> <endX> <endY>");
+                        WurmEspMod.hud.consoleOutput("Usage: esp planner square <radius>");
+                        WurmEspMod.hud.consoleOutput("Usage: esp planner tile <tileX> <tileY>");
+                        WurmEspMod.hud.consoleOutput("Usage: esp planner clear");
+                        break;
+                    }
+                    default: {
+                        WurmEspMod.hud.consoleOutput("Error.");
+                    }
+                }
+                return true;
+            }
+            WurmEspMod.hud.consoleOutput("Error.");
+            return true;
+        }
+        return false;
+    }
+}
+
diff --git a/src/net/encode/wurmesp/feature/hook/HeadsUpDisplayInit.java b/src/net/encode/wurmesp/feature/hook/HeadsUpDisplayInit.java
new file mode 100644 (file)
index 0000000..d896030
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.client.renderer.gui.HeadsUpDisplay
+ *  com.wurmonline.client.renderer.gui.MainMenu
+ *  com.wurmonline.client.renderer.gui.WindowSerializer
+ *  com.wurmonline.client.renderer.gui.WurmComponent
+ *  com.wurmonline.client.settings.SavePosManager
+ *  org.gotti.wurmunlimited.modloader.ReflectionUtil
+ */
+package net.encode.wurmesp.feature.hook;
+
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.logging.Level;
+
+import org.gotti.wurmunlimited.modloader.ReflectionUtil;
+
+import com.wurmonline.client.renderer.gui.HeadsUpDisplay;
+import com.wurmonline.client.renderer.gui.MainMenu;
+import com.wurmonline.client.renderer.gui.WindowSerializer;
+import com.wurmonline.client.renderer.gui.WurmComponent;
+import com.wurmonline.client.renderer.gui.WurmEspWindow;
+import com.wurmonline.client.settings.SavePosManager;
+
+import net.encode.wurmesp.WurmEspMod;
+
+public class HeadsUpDisplayInit
+extends Hook {
+    public HeadsUpDisplayInit() {
+        this.prepareHook("com.wurmonline.client.renderer.gui.HeadsUpDisplay", "init", "(II)V", () -> (proxy, method, args) -> {
+            method.invoke(proxy, args);
+            WurmEspMod.hud = (HeadsUpDisplay)proxy;
+            this.initEspWR();
+            return null;
+        });
+        WurmEspMod.logger.log(Level.INFO, "[WurmEspMod] HeadsUpDisplay.init hooked");
+    }
+
+    private void initEspWR() {
+        try {
+            WurmEspWindow wurmEspWindow = new WurmEspWindow();
+            MainMenu mainMenu = (MainMenu)ReflectionUtil.getPrivateField((Object)WurmEspMod.hud, (Field)ReflectionUtil.getField(WurmEspMod.hud.getClass(), (String)"mainMenu"));
+            mainMenu.registerComponent("Esp", (WurmComponent)wurmEspWindow);
+            @SuppressWarnings("unchecked")
+                       List<WurmEspWindow> components = (List<WurmEspWindow>)ReflectionUtil.getPrivateField((Object)WurmEspMod.hud, (Field)ReflectionUtil.getField(WurmEspMod.hud.getClass(), (String)"components"));
+            components.add(wurmEspWindow);
+            SavePosManager savePosManager = (SavePosManager)ReflectionUtil.getPrivateField((Object)WurmEspMod.hud, (Field)ReflectionUtil.getField(WurmEspMod.hud.getClass(), (String)"savePosManager"));
+            savePosManager.registerAndRefresh((WindowSerializer)wurmEspWindow, "wurmespwindow");
+        }
+        catch (ClassCastException | IllegalAccessException | IllegalArgumentException | NoSuchFieldException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
+
diff --git a/src/net/encode/wurmesp/feature/hook/Hook.java b/src/net/encode/wurmesp/feature/hook/Hook.java
new file mode 100644 (file)
index 0000000..9e3806c
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  org.gotti.wurmunlimited.modloader.classhooks.HookManager
+ *  org.gotti.wurmunlimited.modloader.classhooks.InvocationHandlerFactory
+ */
+package net.encode.wurmesp.feature.hook;
+
+import org.gotti.wurmunlimited.modloader.classhooks.HookManager;
+import org.gotti.wurmunlimited.modloader.classhooks.InvocationHandlerFactory;
+
+public class Hook {
+    public void prepareHook(String path, String methodName, String descriptor, InvocationHandlerFactory invocationHandlerFactory) {
+        HookManager.getInstance().registerHook(path, methodName, descriptor, invocationHandlerFactory);
+    }
+}
+
diff --git a/src/net/encode/wurmesp/feature/hook/HookFeature.java b/src/net/encode/wurmesp/feature/hook/HookFeature.java
new file mode 100644 (file)
index 0000000..c838b5d
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  org.gotti.wurmunlimited.modloader.classhooks.HookManager
+ *  org.gotti.wurmunlimited.modloader.classhooks.InvocationHandlerFactory
+ */
+package net.encode.wurmesp.feature.hook;
+
+import org.gotti.wurmunlimited.modloader.classhooks.HookManager;
+import org.gotti.wurmunlimited.modloader.classhooks.InvocationHandlerFactory;
+
+public class HookFeature {
+    public void prepareHook(String path, String methodName, String descriptor, InvocationHandlerFactory invocationHandlerFactory) {
+        HookManager.getInstance().registerHook(path, methodName, descriptor, invocationHandlerFactory);
+    }
+}
+
diff --git a/src/net/encode/wurmesp/feature/hook/MobileModelRenderableInit.java b/src/net/encode/wurmesp/feature/hook/MobileModelRenderableInit.java
new file mode 100644 (file)
index 0000000..603400e
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.client.renderer.PickableUnit
+ *  com.wurmonline.client.renderer.cell.CreatureCellRenderable
+ */
+package net.encode.wurmesp.feature.hook;
+
+import com.wurmonline.client.renderer.PickableUnit;
+import com.wurmonline.client.renderer.cell.CellRenderable;
+import com.wurmonline.client.renderer.cell.CreatureCellRenderable;
+import java.util.logging.Level;
+import net.encode.wurmesp.Unit;
+import net.encode.wurmesp.WurmEspMod;
+import net.encode.wurmesp.util.SoundUtils;
+
+public class MobileModelRenderableInit
+extends Hook {
+    public MobileModelRenderableInit() {
+        this.prepareHook("com.wurmonline.client.renderer.cell.MobileModelRenderable", "initialize", "()V", () -> (proxy, method, args) -> {
+            method.invoke(proxy, args);
+            PickableUnit pUnit = (PickableUnit)proxy;
+            Unit unit = new Unit(CellRenderable.world, pUnit.getId(), pUnit, ((CreatureCellRenderable)proxy).getModelName().toString(), ((CreatureCellRenderable)proxy).getHoverName());
+            if (unit.isPlayer() || unit.isMob()) {
+                WurmEspMod.pickableUnits.add(unit);
+                if (unit.isUnique() && WurmEspMod.uniques && WurmEspMod.playsoundunique) {
+                    SoundUtils.playSound(WurmEspMod.soundunique);
+                }
+            } else if (unit.isSpecial()) {
+                WurmEspMod.pickableUnits.add(unit);
+                if (WurmEspMod.specials && WurmEspMod.playsoundspecial) {
+                    SoundUtils.playSound(WurmEspMod.soundspecial);
+                }
+            } else if (unit.isSpotted()) {
+                WurmEspMod.pickableUnits.add(unit);
+                if (WurmEspMod.items && WurmEspMod.playsounditem) {
+                    SoundUtils.playSound(WurmEspMod.sounditem);
+                }
+            }
+            return null;
+        });
+        WurmEspMod.logger.log(Level.INFO, "[WurmEspMod] MobileModelRenderable.initialize hooked");
+    }
+}
+
diff --git a/src/net/encode/wurmesp/feature/hook/MobileModelRenderableRemove.java b/src/net/encode/wurmesp/feature/hook/MobileModelRenderableRemove.java
new file mode 100644 (file)
index 0000000..b961afb
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.client.renderer.PickableUnit
+ */
+package net.encode.wurmesp.feature.hook;
+
+import java.util.logging.Level;
+
+import com.wurmonline.client.renderer.PickableUnit;
+
+import net.encode.wurmesp.Unit;
+import net.encode.wurmesp.WurmEspMod;
+
+public class MobileModelRenderableRemove
+extends Hook {
+    public MobileModelRenderableRemove() {
+        this.prepareHook("com.wurmonline.client.renderer.cell.MobileModelRenderable", "removed", "(Z)V", () -> (proxy, method, args) -> {
+            method.invoke(proxy, args);
+            PickableUnit item = (PickableUnit)proxy;
+            for (Unit unit : WurmEspMod.pickableUnits) {
+                if (unit.getId() != item.getId()) continue;
+                WurmEspMod.toRemove.add(unit);
+            }
+            for (Unit unit : WurmEspMod.toRemove) {
+                if (unit.getId() != item.getId()) continue;
+                WurmEspMod.pickableUnits.remove(unit);
+            }
+            WurmEspMod.toRemove.clear();
+            return null;
+        });
+        WurmEspMod.logger.log(Level.INFO, "[WurmEspMod] MobileModelRenderable.removed hooked");
+    }
+}
+
diff --git a/src/net/encode/wurmesp/feature/hook/ProjectileCellRenderable.java b/src/net/encode/wurmesp/feature/hook/ProjectileCellRenderable.java
new file mode 100644 (file)
index 0000000..41c49c6
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  javassist.CannotCompileException
+ *  javassist.ClassPool
+ *  javassist.CtClass
+ *  javassist.CtMethod
+ *  javassist.CtNewMethod
+ *  javassist.NotFoundException
+ *  org.gotti.wurmunlimited.modloader.classhooks.HookManager
+ */
+package net.encode.wurmesp.feature.hook;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javassist.CannotCompileException;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtMethod;
+import javassist.CtNewMethod;
+import javassist.NotFoundException;
+import net.encode.wurmesp.WurmEspMod;
+import org.gotti.wurmunlimited.modloader.classhooks.HookManager;
+
+public class ProjectileCellRenderable {
+    public ProjectileCellRenderable() {
+        try {
+            ClassPool classPool = HookManager.getInstance().getClassPool();
+            CtClass ctWurmArrow = classPool.getCtClass("com.wurmonline.client.renderer.cell.ProjectileCellRenderable");
+            CtMethod m = CtNewMethod.make((String)"public void initialize() { return; }", (CtClass)ctWurmArrow);
+            ctWurmArrow.addMethod(m);
+            WurmEspMod.logger.log(Level.INFO, "[WurmEspMod] Added method initialize on ProjectileCellRenderable");
+        }
+        catch (CannotCompileException | NotFoundException ex) {
+            Logger.getLogger(ProjectileCellRenderable.class.getName()).log(Level.SEVERE, null, ex);
+        }
+    }
+}
+
diff --git a/src/net/encode/wurmesp/feature/hook/RenderPickedItem.java b/src/net/encode/wurmesp/feature/hook/RenderPickedItem.java
new file mode 100644 (file)
index 0000000..b52166c
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.client.game.World
+ *  com.wurmonline.client.renderer.PickRenderer
+ *  com.wurmonline.client.renderer.backend.Queue
+ *  org.gotti.wurmunlimited.modloader.ReflectionUtil
+ */
+package net.encode.wurmesp.feature.hook;
+
+import java.lang.reflect.Field;
+import java.util.logging.Level;
+
+import org.gotti.wurmunlimited.modloader.ReflectionUtil;
+
+import com.wurmonline.client.game.World;
+import com.wurmonline.client.renderer.PickRenderer;
+import com.wurmonline.client.renderer.backend.Queue;
+
+import net.encode.wurmesp.WurmEspMod;
+
+public class RenderPickedItem
+extends Hook {
+       
+    public RenderPickedItem() {
+        this.prepareHook("com.wurmonline.client.renderer.WorldRender", "renderPickedItem", "(Lcom/wurmonline/client/renderer/backend/Queue;)V", () -> (proxy, method, args) -> {
+            method.invoke(proxy, args);
+            Class<?> cls = proxy.getClass();
+            World world = (World)ReflectionUtil.getPrivateField((Object)proxy, (Field)ReflectionUtil.getField(cls, (String)"world"));
+            WurmEspMod._pickRenderer = (PickRenderer)ReflectionUtil.getPrivateField((Object)proxy, (Field)ReflectionUtil.getField(cls, (String)"pickRenderer"));
+            Queue queuePick = (Queue)ReflectionUtil.getPrivateField((Object)proxy, (Field)ReflectionUtil.getField(cls, (String)"queuePick"));
+            WurmEspMod.pickableUnits.stream().filter(unit -> WurmEspMod.players && unit.isPlayer() || WurmEspMod.uniques && unit.isUnique() || WurmEspMod.conditioned && unit.isConditioned() || WurmEspMod.animals && (unit.isMob() && !unit.isAggroMob()) || WurmEspMod.mobs && unit.isAggroMob() || WurmEspMod.specials && unit.isSpecial() || WurmEspMod.items && unit.isSpotted()).forEachOrdered(unit -> {
+                if (unit.isConditioned() && WurmEspMod.conditioned || unit.isConditioned() && WurmEspMod.conditionedcolorsallways || unit.isChampion() && WurmEspMod.championmcoloralways) {
+                    unit.renderUnit(queuePick, true);
+                } else {
+                    unit.renderUnit(queuePick, false);
+                }
+            });
+            if (WurmEspMod.tileshighlight) {
+                WurmEspMod.tilesHighlightManager.setWorldQueue(world, queuePick);
+                if (WurmEspMod.tilesHighlightManager.first) {
+                    WurmEspMod.tilesHighlightManager.refresh();
+                    WurmEspMod.tilesHighlightManager.first = false;
+                } else if (WurmEspMod.tilesHighlightCronoManager.hasEnded()) {
+                    WurmEspMod.tilesHighlightManager.refresh();
+                    WurmEspMod.tilesHighlightCronoManager.restart(5000L);
+                }
+                Thread tilesHighlightThread = new Thread(() -> WurmEspMod.tilesHighlightManager.queue());
+                tilesHighlightThread.setPriority(10);
+                tilesHighlightThread.start();
+            } else {
+                WurmEspMod.tilesHighlightManager.setWorld(world);
+            }
+            if (WurmEspMod.tilescloseby && world.getPlayer().getPos().getLayer() >= 0) {
+                WurmEspMod.tilesCloseByManager.setWorldQueue(world, queuePick);
+                if (WurmEspMod.tilesCloseByManager.first) {
+                    WurmEspMod.tilesCloseByManager.refresh();
+                    WurmEspMod.tilesCloseByManager.first = false;
+                } else if (WurmEspMod.tilesCloseByCronoManager.hasEnded()) {
+                    WurmEspMod.tilesCloseByManager.refresh();
+                    WurmEspMod.tilesCloseByCronoManager.restart(1000L);
+                }
+                Thread tilesThread = new Thread(() -> WurmEspMod.tilesCloseByManager.queue());
+                tilesThread.setPriority(10);
+                tilesThread.start();
+            }
+            if (WurmEspMod.tilesclosebynotrideable && world.getPlayer().getPos().getLayer() >= 0) {
+                WurmEspMod.tilesCloseByWalkableManager.setWorldQueue(world, queuePick);
+                if (WurmEspMod.tilesCloseByWalkableManager.first) {
+                    WurmEspMod.tilesCloseByWalkableManager.refresh();
+                    WurmEspMod.tilesCloseByWalkableManager.first = false;
+                } else if (WurmEspMod.tilesCloseByWalkableCronoManager.hasEnded()) {
+                    WurmEspMod.tilesCloseByWalkableManager.refresh();
+                    WurmEspMod.tilesCloseByWalkableCronoManager.restart(1000L);
+                }
+                Thread tilesWalkableThread = new Thread(() -> WurmEspMod.tilesCloseByWalkableManager.queue());
+                tilesWalkableThread.setPriority(10);
+                tilesWalkableThread.start();
+            }
+            if (WurmEspMod.tilesFlower && world.getPlayer().getPos().getLayer() >= 0) {
+                WurmEspMod.tilesFlowerManager.setWorldQueue(world, queuePick);
+                if (WurmEspMod.tilesFlowerManager.first) {
+                    WurmEspMod.tilesFlowerManager.refresh();
+                    WurmEspMod.tilesFlowerManager.first = false;
+                } else if (WurmEspMod.tilesFlowerCronoManager.hasEnded()) {
+                    WurmEspMod.tilesFlowerManager.refresh();
+                    WurmEspMod.tilesFlowerCronoManager.restart(1000L);
+                }
+                Thread tilesFlowerThread = new Thread(() -> WurmEspMod.tilesFlowerManager.queue());
+                tilesFlowerThread.setPriority(10);
+                tilesFlowerThread.start();
+            }
+            if (WurmEspMod.xray && world.getPlayer().getPos().getLayer() < 0) {
+                Thread refreshThread;
+                WurmEspMod.xrayManager.setWorldQueue(world, queuePick);
+                if (WurmEspMod.xrayManager.first) {
+                    if (WurmEspMod.xrayrefreshthread) {
+                        refreshThread = new Thread(() -> WurmEspMod.xrayManager.refresh());
+                        refreshThread.setPriority(10);
+                        refreshThread.start();
+                    } else {
+                        WurmEspMod.xrayManager.refresh();
+                    }
+                    WurmEspMod.xrayManager.first = false;
+                } else if (WurmEspMod.xrayCronoManager.hasEnded()) {
+                    if (WurmEspMod.xrayrefreshthread) {
+                        refreshThread = new Thread(() -> WurmEspMod.xrayManager.refresh());
+                        refreshThread.setPriority(10);
+                        refreshThread.start();
+                    } else {
+                        WurmEspMod.xrayManager.refresh();
+                    }
+                    WurmEspMod.xrayCronoManager.restart(WurmEspMod.xrayrefreshrate * 1000);
+                }
+                if (WurmEspMod.xraythread) {
+                    Thread xrayThread = new Thread(() -> WurmEspMod.xrayManager.queue());
+                    xrayThread.setPriority(10);
+                    xrayThread.start();
+                } else {
+                    WurmEspMod.xrayManager.queue();
+                }
+            }
+            return null;
+        });
+        WurmEspMod.logger.log(Level.INFO, "[WurmEspMod] WorldRender.renderPickedItem hooked");
+    }
+}
+
diff --git a/src/net/encode/wurmesp/util/ConfigUtils.java b/src/net/encode/wurmesp/util/ConfigUtils.java
new file mode 100644 (file)
index 0000000..3bdf985
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.mesh.Tiles$Tile
+ */
+package net.encode.wurmesp.util;
+
+import com.wurmonline.mesh.Tiles;
+import java.awt.Color;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Properties;
+import net.encode.wurmesp.Unit;
+import net.encode.wurmesp.WurmEspMod;
+
+public class ConfigUtils {
+    /*
+     * WARNING - Removed try catching itself - possible behaviour change.
+     */
+    public static void loadProperties(String name) {
+        WurmEspMod.modProperties.clear();
+        InputStream inputStream = null;
+        Path path = Paths.get("mods", new String[0]);
+        path = path.resolve(name + ".properties");
+        try {
+            inputStream = Files.newInputStream(path, new OpenOption[0]);
+            WurmEspMod.modProperties.load(inputStream);
+        }
+        catch (IOException e) {
+            e.printStackTrace();
+        }
+        finally {
+            if (inputStream != null) {
+                try {
+                    inputStream.close();
+                }
+                catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    public static void DoConfig(Properties properties) {
+        WurmEspMod.players = Boolean.valueOf(properties.getProperty("players", Boolean.toString(WurmEspMod.players)));
+        WurmEspMod.mobs = Boolean.valueOf(properties.getProperty("mobs", Boolean.toString(WurmEspMod.mobs)));
+        WurmEspMod.animals = Boolean.valueOf(properties.getProperty("animals", Boolean.toString(WurmEspMod.animals)));
+        WurmEspMod.specials = Boolean.valueOf(properties.getProperty("specials", Boolean.toString(WurmEspMod.specials)));
+        WurmEspMod.items = Boolean.valueOf(properties.getProperty("items", Boolean.toString(WurmEspMod.items)));
+        WurmEspMod.uniques = Boolean.valueOf(properties.getProperty("uniques", Boolean.toString(WurmEspMod.uniques)));
+        WurmEspMod.conditioned = Boolean.valueOf(properties.getProperty("conditioned", Boolean.toString(WurmEspMod.conditioned)));
+        WurmEspMod.tilescloseby = Boolean.valueOf(properties.getProperty("tilescloseby", Boolean.toString(WurmEspMod.tilescloseby)));
+        WurmEspMod.deedsize = Boolean.valueOf(properties.getProperty("deedsize", Boolean.toString(WurmEspMod.deedsize)));
+        WurmEspMod.xray = Boolean.valueOf(properties.getProperty("xray", Boolean.toString(WurmEspMod.xray)));
+        WurmEspMod.xraythread = Boolean.valueOf(properties.getProperty("xraythread", Boolean.toString(WurmEspMod.xraythread)));
+        WurmEspMod.xrayrefreshthread = Boolean.valueOf(properties.getProperty("xrayrefreshthread", Boolean.toString(WurmEspMod.xrayrefreshthread)));
+        WurmEspMod.xraydiameter = Integer.parseInt(properties.getProperty("xraydiameter", Integer.toString(WurmEspMod.xraydiameter)));
+        WurmEspMod.xrayrefreshrate = Integer.parseInt(properties.getProperty("xrayrefreshrate", Integer.toString(WurmEspMod.xrayrefreshrate)));
+        WurmEspMod.tilenotrideable = Integer.parseInt(properties.getProperty("tilenotrideable", Integer.toString(WurmEspMod.tilenotrideable)));
+        WurmEspMod.flowerdiameter = Integer.parseInt(properties.getProperty("flowerdiameter", Integer.toString(WurmEspMod.flowerdiameter)));
+        WurmEspMod.playsoundspecial = Boolean.valueOf(properties.getProperty("playsoundspecial", Boolean.toString(WurmEspMod.playsoundspecial)));
+        WurmEspMod.playsounditem = Boolean.valueOf(properties.getProperty("playsounditem", Boolean.toString(WurmEspMod.playsounditem)));
+        WurmEspMod.playsoundunique = Boolean.valueOf(properties.getProperty("playsoundunique", Boolean.toString(WurmEspMod.playsoundunique)));
+        WurmEspMod.soundspecial = properties.getProperty("soundspecial", WurmEspMod.soundspecial);
+        WurmEspMod.sounditem = properties.getProperty("sounditem", WurmEspMod.sounditem);
+        WurmEspMod.soundunique = properties.getProperty("soundunique", WurmEspMod.soundunique);
+        WurmEspMod.conditionedcolorsallways = Boolean.valueOf(properties.getProperty("conditionedcolorsallways", Boolean.toString(WurmEspMod.conditionedcolorsallways)));
+        WurmEspMod.championmcoloralways = Boolean.valueOf(properties.getProperty("championmcoloralways", Boolean.toString(WurmEspMod.championmcoloralways)));
+        Unit.colorPlayers = ConfigUtils.colorStringToFloatA(properties.getProperty("colorPlayers", ConfigUtils.colorFloatAToString(Unit.colorPlayers)));
+        Unit.colorPlayersEnemy = ConfigUtils.colorStringToFloatA(properties.getProperty("colorPlayersEnemy", ConfigUtils.colorFloatAToString(Unit.colorPlayersEnemy)));
+        Unit.colorMobs = ConfigUtils.colorStringToFloatA(properties.getProperty("colorMobs", ConfigUtils.colorFloatAToString(Unit.colorMobs)));
+        Unit.colorMobsAggro = ConfigUtils.colorStringToFloatA(properties.getProperty("colorMobsAggro", ConfigUtils.colorFloatAToString(Unit.colorMobsAggro)));
+        Unit.colorSpecials = ConfigUtils.colorStringToFloatA(properties.getProperty("colorSpecials", ConfigUtils.colorFloatAToString(Unit.colorSpecials)));
+        Unit.colorSpotted = ConfigUtils.colorStringToFloatA(properties.getProperty("colorSpotted", ConfigUtils.colorFloatAToString(Unit.colorSpotted)));
+        Unit.colorUniques = ConfigUtils.colorStringToFloatA(properties.getProperty("colorUniques", ConfigUtils.colorFloatAToString(Unit.colorUniques)));
+        Unit.colorAlert = ConfigUtils.colorStringToFloatA(properties.getProperty("colorAlert", ConfigUtils.colorFloatAToString(Unit.colorAlert)));
+        Unit.colorAngry = ConfigUtils.colorStringToFloatA(properties.getProperty("colorAngry", ConfigUtils.colorFloatAToString(Unit.colorAngry)));
+        Unit.colorChampion = ConfigUtils.colorStringToFloatA(properties.getProperty("colorChampion", ConfigUtils.colorFloatAToString(Unit.colorChampion)));
+        Unit.colorDiseased = ConfigUtils.colorStringToFloatA(properties.getProperty("colorDiseased", ConfigUtils.colorFloatAToString(Unit.colorDiseased)));
+        Unit.colorFierce = ConfigUtils.colorStringToFloatA(properties.getProperty("colorFierce", ConfigUtils.colorFloatAToString(Unit.colorFierce)));
+        Unit.colorGreenish = ConfigUtils.colorStringToFloatA(properties.getProperty("colorGreenish", ConfigUtils.colorFloatAToString(Unit.colorGreenish)));
+        Unit.colorHardened = ConfigUtils.colorStringToFloatA(properties.getProperty("colorHardened", ConfigUtils.colorFloatAToString(Unit.colorHardened)));
+        Unit.colorLurking = ConfigUtils.colorStringToFloatA(properties.getProperty("colorLurking", ConfigUtils.colorFloatAToString(Unit.colorLurking)));
+        Unit.colorRaging = ConfigUtils.colorStringToFloatA(properties.getProperty("colorRaging", ConfigUtils.colorFloatAToString(Unit.colorRaging)));
+        Unit.colorScared = ConfigUtils.colorStringToFloatA(properties.getProperty("colorScared", ConfigUtils.colorFloatAToString(Unit.colorScared)));
+        Unit.colorSlow = ConfigUtils.colorStringToFloatA(properties.getProperty("colorSlow", ConfigUtils.colorFloatAToString(Unit.colorSlow)));
+        Unit.colorSly = ConfigUtils.colorStringToFloatA(properties.getProperty("colorSly", ConfigUtils.colorFloatAToString(Unit.colorSly)));
+        String oreColorOreIron = properties.getProperty("oreColorOreIron", "default");
+        if (!oreColorOreIron.equals("default")) {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_ORE_IRON, ConfigUtils.colorStringToFloatA(oreColorOreIron));
+        } else {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_ORE_IRON, Color.RED.darker());
+        }
+        String oreColorOreCopper = properties.getProperty("oreColorOreCopper", "default");
+        if (!oreColorOreCopper.equals("default")) {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_ORE_COPPER, ConfigUtils.colorStringToFloatA(oreColorOreCopper));
+        } else {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_ORE_COPPER, Color.GREEN);
+        }
+        String oreColorOreTin = properties.getProperty("oreColorOreTin", "default");
+        if (!oreColorOreTin.equals("default")) {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_ORE_TIN, ConfigUtils.colorStringToFloatA(oreColorOreTin));
+        } else {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_ORE_TIN, Color.GRAY);
+        }
+        String oreColorOreGold = properties.getProperty("oreColorOreGold", "default");
+        if (!oreColorOreGold.equals("default")) {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_ORE_GOLD, ConfigUtils.colorStringToFloatA(oreColorOreGold));
+        } else {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_ORE_GOLD, Color.YELLOW.darker());
+        }
+        String oreColorOreAdamantine = properties.getProperty("oreColorOreAdamantine", "default");
+        if (!oreColorOreAdamantine.equals("default")) {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_ORE_ADAMANTINE, ConfigUtils.colorStringToFloatA(oreColorOreAdamantine));
+        } else {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_ORE_ADAMANTINE, Color.CYAN);
+        }
+        String oreColorOreGlimmersteel = properties.getProperty("oreColorOreGlimmersteel", "default");
+        if (!oreColorOreGlimmersteel.equals("default")) {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_ORE_GLIMMERSTEEL, ConfigUtils.colorStringToFloatA(oreColorOreGlimmersteel));
+        } else {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_ORE_GLIMMERSTEEL, Color.YELLOW.brighter());
+        }
+        String oreColorOreSilver = properties.getProperty("oreColorOreSilver", "default");
+        if (!oreColorOreSilver.equals("default")) {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_ORE_SILVER, ConfigUtils.colorStringToFloatA(oreColorOreSilver));
+        } else {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_ORE_SILVER, Color.LIGHT_GRAY);
+        }
+        String oreColorOreLead = properties.getProperty("oreColorOreLead", "default");
+        if (!oreColorOreLead.equals("default")) {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_ORE_LEAD, ConfigUtils.colorStringToFloatA(oreColorOreLead));
+        } else {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_ORE_LEAD, Color.PINK.darker().darker());
+        }
+        String oreColorOreZinc = properties.getProperty("oreColorOreZinc", "default");
+        if (!oreColorOreZinc.equals("default")) {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_ORE_ZINC, ConfigUtils.colorStringToFloatA(oreColorOreZinc));
+        } else {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_ORE_ZINC, new Color(235, 235, 235));
+        }
+        String oreColorSlate = properties.getProperty("oreColorSlate", "default");
+        if (!oreColorSlate.equals("default")) {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_SLATE, ConfigUtils.colorStringToFloatA(oreColorSlate));
+        } else {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_SLATE, Color.BLACK);
+        }
+        String oreColorMarble = properties.getProperty("oreColorMarble", "default");
+        if (!oreColorMarble.equals("default")) {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_MARBLE, ConfigUtils.colorStringToFloatA(oreColorMarble));
+        } else {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_MARBLE, Color.WHITE);
+        }
+        String oreColorSandstone = properties.getProperty("oreColorSandstone", "default");
+        if (!oreColorSandstone.equals("default")) {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_SANDSTONE, ConfigUtils.colorStringToFloatA(oreColorSandstone));
+        } else {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_SANDSTONE, Color.YELLOW.darker().darker());
+        }
+        String oreColorRocksalt = properties.getProperty("oreColorRocksalt", "default");
+        if (!oreColorRocksalt.equals("default")) {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_ROCKSALT, ConfigUtils.colorStringToFloatA(oreColorRocksalt));
+        } else {
+            XrayColors.addMapping(Tiles.Tile.TILE_CAVE_WALL_ROCKSALT, Color.WHITE.darker());
+        }
+        Unit.aggroMOBS = properties.getProperty("aggroMOBS").split(";");
+        Unit.uniqueMOBS = properties.getProperty("uniqueMOBS").split(";");
+        Unit.specialITEMS = properties.getProperty("specialITEMS").split(";");
+        Unit.spottedITEMS = properties.getProperty("spottedITEMS").split(";");
+        Unit.conditionedMOBS = properties.getProperty("conditionedMOBS").split(";");
+        WurmEspMod.tilesFlowerSearch = properties.getProperty("tilesFlowerSearch").split(";");
+    }
+
+    private static float[] colorStringToFloatA(String color) {
+        String[] colors = color.split(",");
+        float[] colorf = new float[]{Float.valueOf(colors[0]).floatValue() / 255.0f, Float.valueOf(colors[1]).floatValue() / 255.0f, Float.valueOf(colors[2]).floatValue() / 255.0f};
+        return colorf;
+    }
+
+    private static String colorFloatAToString(float[] color) {
+        String colors = String.valueOf(color[0] * 255.0f) + "," + String.valueOf(color[1] * 255.0f) + "," + String.valueOf(color[2] * 255.0f);
+        return colors;
+    }
+}
+
diff --git a/src/net/encode/wurmesp/util/CronoManager.java b/src/net/encode/wurmesp/util/CronoManager.java
new file mode 100644 (file)
index 0000000..b17b9ae
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Decompiled with CFR 0.151.
+ */
+package net.encode.wurmesp.util;
+
+import java.util.HashMap;
+
+public class CronoManager {
+    private long timelapse;
+    private long time;
+    private long remaining;
+    private long future;
+    private long last;
+
+    public CronoManager(long timelapse) {
+        this.timelapse = timelapse;
+        this.time = System.currentTimeMillis();
+        this.future = this.time + this.timelapse;
+        this.last = this.remaining = (this.future - System.currentTimeMillis()) / 1000L;
+    }
+
+    public void restart(long timelapse) {
+        this.timelapse = timelapse;
+        this.time = System.currentTimeMillis();
+        this.future = this.time + this.timelapse;
+        this.last = this.remaining = (this.future - System.currentTimeMillis()) / 1000L;
+    }
+
+    public HashMap<CronoDataType, Long> getTime() {
+        this.last = this.remaining = (this.future - System.currentTimeMillis()) / 1000L;
+        long days = (long)Math.floor(this.remaining / 86400L);
+        long hours = (long)Math.floor(this.remaining % 86400L / 3600L);
+        long minutes = (long)Math.floor(this.remaining % 86400L % 3600L / 60L);
+        long seconds = (long)Math.floor(this.remaining % 86400L % 3600L % 60L);
+        HashMap<CronoDataType, Long> returnedTime = new HashMap<CronoDataType, Long>();
+        returnedTime.put(CronoDataType.DAYS, days);
+        returnedTime.put(CronoDataType.HOURS, hours);
+        returnedTime.put(CronoDataType.MINUTES, minutes);
+        returnedTime.put(CronoDataType.SECONDS, seconds);
+        return returnedTime;
+    }
+
+    public int getDays() {
+        this.last = this.remaining = (this.future - System.currentTimeMillis()) / 1000L;
+        long days = (long)Math.floor(this.remaining / 86400L);
+        return (int)days;
+    }
+
+    public int getHours() {
+        this.last = this.remaining = (this.future - System.currentTimeMillis()) / 1000L;
+        long hours = (long)Math.floor(this.remaining % 86400L / 3600L);
+        return (int)hours;
+    }
+
+    public int getMinutes() {
+        this.last = this.remaining = (this.future - System.currentTimeMillis()) / 1000L;
+        long minutes = (long)Math.floor(this.remaining % 86400L % 3600L / 60L);
+        return (int)minutes;
+    }
+
+    public int getSeconds() {
+        this.last = this.remaining = (this.future - System.currentTimeMillis()) / 1000L;
+        long seconds = (long)Math.floor(this.remaining % 86400L % 3600L % 60L);
+        return (int)seconds;
+    }
+
+    public boolean hasNext() {
+        this.remaining = (this.future - System.currentTimeMillis()) / 1000L;
+        return this.remaining < this.last;
+    }
+
+    public boolean hasEnded() {
+        return System.currentTimeMillis() > this.future;
+    }
+
+    public static enum CronoDataType {
+        DAYS,
+        HOURS,
+        MINUTES,
+        SECONDS;
+
+    }
+}
+
diff --git a/src/net/encode/wurmesp/util/ReUtils.java b/src/net/encode/wurmesp/util/ReUtils.java
new file mode 100644 (file)
index 0000000..c182c68
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  org.gotti.wurmunlimited.modloader.ReflectionUtil
+ */
+package net.encode.wurmesp.util;
+
+import java.lang.reflect.Field;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import net.encode.wurmesp.feature.hook.Hook;
+import org.gotti.wurmunlimited.modloader.ReflectionUtil;
+
+public class ReUtils {
+    @SuppressWarnings("unchecked")
+       public static <T> T getField(Object proxy, String fieldname) {
+        Class<?> cls = proxy.getClass();
+        Object returnedObject = null;
+        try {
+            Field field = ReflectionUtil.getField(cls, (String)fieldname);
+            returnedObject = ReflectionUtil.getPrivateField((Object)proxy, (Field)field);
+        }
+        catch (ClassCastException | IllegalAccessException | IllegalArgumentException | NoSuchFieldException ex) {
+            Logger.getLogger(Hook.class.getName()).log(Level.SEVERE, null, ex);
+        }
+        return (T)returnedObject;
+    }
+}
+
diff --git a/src/net/encode/wurmesp/util/RenderUtils.java b/src/net/encode/wurmesp/util/RenderUtils.java
new file mode 100644 (file)
index 0000000..6103e5a
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.client.renderer.backend.IndexBuffer
+ *  com.wurmonline.client.renderer.backend.Primitive
+ *  com.wurmonline.client.renderer.backend.Primitive$Type
+ *  com.wurmonline.client.renderer.backend.Queue
+ *  com.wurmonline.client.renderer.backend.RenderState
+ *  com.wurmonline.client.renderer.backend.VertexBuffer
+ *  com.wurmonline.client.renderer.backend.VertexBuffer$Usage
+ */
+package net.encode.wurmesp.util;
+
+import com.wurmonline.client.renderer.PickRenderer;
+import com.wurmonline.client.renderer.PickRenderer.CustomPickOutlineRender;
+import com.wurmonline.client.renderer.backend.IndexBuffer;
+import com.wurmonline.client.renderer.backend.Primitive;
+import com.wurmonline.client.renderer.backend.Queue;
+import com.wurmonline.client.renderer.backend.RenderState;
+import com.wurmonline.client.renderer.backend.VertexBuffer;
+
+import net.encode.wurmesp.WurmEspMod;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+
+public class RenderUtils {
+    public static void renderPrimitiveLines(int numvertex, float[] vertexdata, int[] indexdata, Queue queue, float[] color) {
+        VertexBuffer _vBuffer = VertexBuffer.create((VertexBuffer.Usage)VertexBuffer.Usage.PICK, (int)numvertex, (boolean)true, (boolean)false, (boolean)false, (boolean)false, (boolean)false, (int)0, (int)0, (boolean)false, (boolean)true);
+        FloatBuffer vdata = _vBuffer.lock();
+        vdata.put(vertexdata);
+        _vBuffer.unlock();
+        IndexBuffer _iBuffer = IndexBuffer.create((int)indexdata.length, (boolean)false, (boolean)true);
+        IntBuffer idata = _iBuffer.lock();
+        idata.put(indexdata);
+        _iBuffer.unlock();
+        
+        PickRenderer tmp1257_1254 = WurmEspMod._pickRenderer;
+               CustomPickOutlineRender customPickOutline = tmp1257_1254.new CustomPickOutlineRender();
+
+               RenderState renderStateOutline = new RenderState();
+               renderStateOutline.alphaval = 0.5F;
+               renderStateOutline.twosided = false;
+               renderStateOutline.depthtest = Primitive.TestFunc.LESS;
+               renderStateOutline.depthwrite = false;
+               renderStateOutline.blendmode = Primitive.BlendMode.ALPHABLEND;
+               renderStateOutline.customstate = customPickOutline;
+        
+        Primitive p = queue.reservePrimitive();
+        p.copyStateFrom(renderStateOutline);
+        p.vertex = _vBuffer;
+        p.index = _iBuffer;
+        p.num = _iBuffer.getNumIndex() / 2;
+        p.type = Primitive.Type.LINES;
+        p.nolight = true;
+        p.nofog = true;
+        p.texture[0] = null;
+        p.setColor(color[0], color[1], color[2], color[3]);
+        queue.queue(p, null);
+    }
+}
+
diff --git a/src/net/encode/wurmesp/util/SoundUtils.java b/src/net/encode/wurmesp/util/SoundUtils.java
new file mode 100644 (file)
index 0000000..4bcba35
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.client.game.PlayerPosition
+ *  com.wurmonline.client.renderer.cell.CellRenderable
+ *  com.wurmonline.client.sound.FixedSoundSource
+ *  com.wurmonline.client.sound.SoundSource
+ */
+package net.encode.wurmesp.util;
+
+import com.wurmonline.client.game.PlayerPosition;
+import com.wurmonline.client.renderer.cell.CellRenderable;
+import com.wurmonline.client.sound.FixedSoundSource;
+import com.wurmonline.client.sound.SoundSource;
+
+public class SoundUtils {
+    public static void playSound(String sound) {
+        PlayerPosition pos = CellRenderable.world.getPlayer().getPos();
+        CellRenderable.world.getSoundEngine().play(sound, (SoundSource)new FixedSoundSource(pos.getX(), pos.getY(), 2.0f), 1.0f, 5.0f, 1.0f, false, false);
+    }
+}
+
diff --git a/src/net/encode/wurmesp/util/TerrainUtils.java b/src/net/encode/wurmesp/util/TerrainUtils.java
new file mode 100644 (file)
index 0000000..7de0785
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Decompiled with CFR 0.151.
+ */
+package net.encode.wurmesp.util;
+
+import net.encode.wurmesp.WurmEspMod;
+
+public class TerrainUtils {
+    public static boolean isFlat(float[] tile) {
+        return tile[1] == tile[4] && tile[4] == tile[7] && tile[7] == tile[10];
+    }
+
+    public static boolean isNotRideable(float[] tile) {
+        return TerrainUtils.getTileSteepness(tile)[1] >= WurmEspMod.tilenotrideable;
+    }
+
+    public static short[] getTileSteepness(float[] tile) {
+        short highest = -100;
+        short lowest = 32000;
+        for (int i = 1; i <= 10; i += 3) {
+            short height = 0;
+            height = (short)(tile[i] * 10.0f);
+            if (height > highest) {
+                highest = height;
+            }
+            if (height >= lowest) continue;
+            lowest = height;
+        }
+        int med = (highest + lowest) / 2;
+        return new short[]{(short)med, (short)(highest - lowest)};
+    }
+}
+
diff --git a/src/net/encode/wurmesp/util/XrayColors.java b/src/net/encode/wurmesp/util/XrayColors.java
new file mode 100644 (file)
index 0000000..7e099f8
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Decompiled with CFR 0.151.
+ * 
+ * Could not load the following classes:
+ *  com.wurmonline.mesh.Tiles$Tile
+ */
+package net.encode.wurmesp.util;
+
+import com.wurmonline.mesh.Tiles;
+import com.wurmonline.mesh.Tiles.Tile;
+
+import java.awt.Color;
+import java.util.EnumMap;
+
+public class XrayColors {
+    private static final EnumMap<Tiles.Tile, Color> MAPPINGS = new EnumMap<Tile, Color>(Tiles.Tile.class);
+
+    public static void addMapping(Tiles.Tile tile, Color color) {
+        MAPPINGS.put(tile, color);
+    }
+
+    public static void addMapping(Tiles.Tile tile, float[] color) {
+        MAPPINGS.put(tile, new Color(color[0], color[1], color[2]));
+    }
+
+    public static Color getColorFor(Tiles.Tile tile) {
+        return MAPPINGS.getOrDefault(tile, Color.PINK);
+    }
+}
+