Posted May 16, 2018 (edited) # # A little mod to make my life easier; provides the #goto command for GM's. # I was SO fed up with having to use the wand. # That's it. # # Someone else probably already made a mod for this and I just did not know about it. # # Usage: Type #goto in any tab. # # Syntax: #goto <x y> # or #goto <deed name> # or #goto <player name> # # If the deed is multiple words, use quotes. E.g. #goto "Friya's Fantastic Fellowship" # If there is a deed called Friya and also a player with the same name, distinguish the two by doing #goto deed Friya or #goto player Friya # If going to coordinate, make sure it is within the map boundaries. # You cannot go to invisible GMs. # # - Friya, 2018 # Download And here's the source code for anyone wanting to do ... more. package com.friya.wurmonline.server.admin; import java.util.ArrayList; import java.util.StringTokenizer; import org.gotti.wurmunlimited.modloader.interfaces.PlayerMessageListener; import org.gotti.wurmunlimited.modloader.interfaces.WurmServerMod; import com.wurmonline.server.Players; import com.wurmonline.server.creatures.Communicator; import com.wurmonline.server.players.Player; import com.wurmonline.server.villages.NoSuchVillageException; import com.wurmonline.server.villages.Village; import com.wurmonline.server.villages.Villages; import com.wurmonline.server.zones.Zones; public class Mod implements WurmServerMod, PlayerMessageListener { @Override public boolean onPlayerMessage(Communicator com, String msg) { if(com.getPlayer().getPower() > 0) { // Verbose because I -may- want to add more GM commands. if(msg.startsWith("#goto")) { return cmdGoto(com, msg); } } return false; } private boolean cmdGoto(Communicator com, String cmd) { String[] tokens = translateCommandline(cmd); Location loc = null; if(tokens.length == 1) { tell(com, "Syntax:"); tell(com, " #goto <x y> or #goto <deed name> or #goto <player name>"); tell(com, "Examples:"); tell(com, " #goto 500 500"); tell(com, " #goto \"Friya's Home\""); tell(com, " #goto friya"); tell(com, "Notes:"); tell(com, " If the deed name is multiple words, use quotes. E.g. #goto \"Friya's Fantastic Fellowship\""); tell(com, " If there is a deed called Friya and also a player with the sane name, separate the two by doing #goto deed Friya or #goto player Friya"); tell(com, " If going to coordinate, make sure it is within the map boundaries."); tell(com, " You cannot go to invisible GMs."); return true; } if(tokens.length == 3) { if(isNumericUgly(tokens[1]) && isNumericUgly(tokens[2])) { // #goto x y loc = getCoordinateLocation(tokens[1], tokens[2]); } else if(tokens[1].equals("deed")) { // #goto deed loc = getDeedLocationByName(tokens[2]); } else if(tokens[1].equals("player")) { // #goto player loc = getPlayerLocationByName(tokens[2]); } } else if(tokens.length == 2) { // #goto <player name> loc = getPlayerLocationByName(tokens[1]); if(loc == null) { // #goto <deed name> loc = getDeedLocationByName(tokens[1]); } } if(loc == null || gotoTarget(com, loc) == false) { tell(com, "No idea how to go there... Typo? Coordinate is outside map? Target is invisible? Not a player? Already teleporting?"); } else { tell(com, "The fabric of space opens and you appear at " + loc.getName() + " ... or so you hope."); } return true; } private boolean gotoTarget(Communicator c, Location loc) { Player p = c.getPlayer(); p.setTeleportPoints((short)loc.getX(), (short)loc.getY(), loc.getLayer(), 0); if (p.startTeleporting()) { c.sendTeleport(false); p.teleport(); return true; } return false; } private Location getCoordinateLocation(String sx, String sy) { int x = Integer.parseInt(sx); int y = Integer.parseInt(sy); if(x < 1 || x > Zones.worldTileSizeX || y < 1 || y > Zones.worldTileSizeY) { return null; } return new Location(x + "x" + y, x, y, 0); } private Location getPlayerLocationByName(String name) { Player p = Players.getInstance().getPlayerOrNull(name.substring(0, 1).toUpperCase() + name.substring(1).toLowerCase()); // if target is an invisible GM, disallow going to them (caller will give a generic error) if(p == null || (p.getPower() > 0 && p.isVisible() == false)) { return null; } return new Location(p.getName(), p.getTileX(), p.getTileY(), p.getLayer()); } private Location getDeedLocationByName(String name) { Village d = null; try { d = Villages.getVillage(name); } catch (NoSuchVillageException e) { } if(d == null) { return null; } return new Location(d.getName(), d.getTokenX(), d.getTokenY(), 0); } /** * Crack a command line. * * Shamelessly lifted from another mod of mine which shamelessly lifted it from * Apache Commons. See https://commons.apache.org/proper/commons-exec/apidocs/src-html/org/apache/commons/exec/CommandLine.html * * @param toProcess the command line to process. * @return the command line broken into strings. * * An empty or null toProcess parameter results in a zero sized array. */ private String[] translateCommandline(String toProcess) { if (toProcess == null || toProcess.length() == 0) { return new String[0]; } final int normal = 0; final int inQuote = 1; final int inDoubleQuote = 2; int state = normal; final StringTokenizer tok = new StringTokenizer(toProcess, "\"\' ", true); final ArrayList<String> result = new ArrayList<String>(); final StringBuilder current = new StringBuilder(); boolean lastTokenHasBeenQuoted = false; while (tok.hasMoreTokens()) { String nextTok = tok.nextToken(); switch (state) { case inQuote: if ("\'".equals(nextTok)) { lastTokenHasBeenQuoted = true; state = normal; } else { current.append(nextTok); } break; case inDoubleQuote: if ("\"".equals(nextTok)) { lastTokenHasBeenQuoted = true; state = normal; } else { current.append(nextTok); } break; default: if ("\'".equals(nextTok)) { state = inQuote; } else if ("\"".equals(nextTok)) { state = inDoubleQuote; } else if (" ".equals(nextTok)) { if (lastTokenHasBeenQuoted || current.length() != 0) { result.add(current.toString()); current.setLength(0); } } else { current.append(nextTok); } lastTokenHasBeenQuoted = false; break; } } if (lastTokenHasBeenQuoted || current.length() != 0) { result.add(current.toString()); } if (state == inQuote || state == inDoubleQuote) { throw new RuntimeException("unbalanced quotes in " + toProcess); } return result.toArray(new String[result.size()]); } /** * Despite this using an exception for functionality, I am okay with it. It's executed rarely enough and definitely rare enough to trigger the exception. * * @param str * @return */ private boolean isNumericUgly(String str) { try { @SuppressWarnings("unused") double d = Double.parseDouble(str); } catch(NumberFormatException nfe) { return false; } return true; } private void tell(Communicator c, String msg) { c.sendNormalServerMessage(msg); } } /* ------------------------------------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------------------------------------- */ package com.friya.wurmonline.server.admin; class Location { private String _name; private int _x; private int _y; private int _layer = 0; Location(String name, int x, int y, int layer) { _name = name; _x = x; _y = y; _layer = layer; } String getName() { return _name; } int getX() { return _x; } int getY() { return _y; } public int getLayer() { return _layer; } } Edited May 16, 2018 by Friya 3 Share this post Link to post Share on other sites
Posted May 21, 2018 (edited) On 5/16/2018 at 7:01 AM, Friya said: # Syntax: #goto <x y> # or #goto <deed name> # or #goto <player name> Comma or space needed between the x y coordinates? For example, will this work? #goto 1200,1200 Also, will this work for all levels of GM, or just those normally using an ebony wand? <--- If that's a dumb question, then thanks for your patience. I'm still figuring this stuff out. ? Edited May 21, 2018 by Batta Share this post Link to post Share on other sites
Posted May 30, 2018 Turns out that the #goto coordinates works only if there is a space but no comma, like this: #goto 1200 900 For the next guy, also note that deed names that are longer than 1 word must have quotation marks around them: #goto "Spawn Island" 1 Share this post Link to post Share on other sites