Sign in to follow this  
Friya

[Released] GM Goto (server)

Recommended Posts

#
# 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 by Friya
  • Like 3

Share this post


Link to post
Share on other sites
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 by Batta

Share this post


Link to post
Share on other sites

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"

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this