package com.laytonsmith.core.functions; import com.laytonsmith.PureUtilities.Common.StringUtils; import com.laytonsmith.PureUtilities.Vector3D; import com.laytonsmith.PureUtilities.Version; import com.laytonsmith.abstraction.MCChunk; import com.laytonsmith.abstraction.MCCommandSender; import com.laytonsmith.abstraction.MCItemStack; import com.laytonsmith.abstraction.MCLocation; import com.laytonsmith.abstraction.MCPlayer; import com.laytonsmith.abstraction.MCWorld; import com.laytonsmith.abstraction.MCWorldBorder; import com.laytonsmith.abstraction.MCWorldCreator; import com.laytonsmith.abstraction.StaticLayer; import com.laytonsmith.abstraction.entities.MCFallingBlock; import com.laytonsmith.abstraction.enums.MCDifficulty; import com.laytonsmith.abstraction.enums.MCGameRule; import com.laytonsmith.abstraction.enums.MCVersion; import com.laytonsmith.abstraction.enums.MCWorldEnvironment; import com.laytonsmith.abstraction.enums.MCWorldType; import com.laytonsmith.annotations.api; import com.laytonsmith.core.ArgumentValidation; import com.laytonsmith.core.CHVersion; import com.laytonsmith.core.ObjectGenerator; import com.laytonsmith.core.Static; import com.laytonsmith.core.constructs.CArray; import com.laytonsmith.core.constructs.CBoolean; import com.laytonsmith.core.constructs.CDouble; import com.laytonsmith.core.constructs.CInt; import com.laytonsmith.core.constructs.CNull; import com.laytonsmith.core.constructs.CString; import com.laytonsmith.core.constructs.CVoid; import com.laytonsmith.core.constructs.Construct; import com.laytonsmith.core.constructs.Target; import com.laytonsmith.core.environments.CommandHelperEnvironment; import com.laytonsmith.core.environments.Environment; import com.laytonsmith.core.exceptions.CRE.CRECastException; import com.laytonsmith.core.exceptions.CRE.CREFormatException; import com.laytonsmith.core.exceptions.CRE.CREInsufficientArgumentsException; import com.laytonsmith.core.exceptions.CRE.CREInvalidWorldException; import com.laytonsmith.core.exceptions.CRE.CRENotFoundException; import com.laytonsmith.core.exceptions.CRE.CRERangeException; import com.laytonsmith.core.exceptions.CRE.CREThrowable; import com.laytonsmith.core.exceptions.CancelCommandException; import com.laytonsmith.core.exceptions.ConfigRuntimeException; import java.io.IOException; import java.util.Enumeration; import java.util.Properties; import java.util.Random; import java.util.SortedMap; import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * */ public class World { public static String docs() { return "Provides functions for manipulating a world"; } @api(environments=CommandHelperEnvironment.class) public static class get_spawn extends AbstractFunction { @Override public String getName() { return "get_spawn"; } @Override public Integer[] numArgs() { return new Integer[]{0, 1}; } @Override public String docs() { return "array {[world]} Returns a location array for the specified world, or the current player's world, if not specified."; } @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREInvalidWorldException.class, CREFormatException.class}; } @Override public boolean isRestricted() { return true; } @Override public CHVersion since() { return CHVersion.V3_3_0; } @Override public Boolean runAsync() { return false; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { String world; if (args.length == 1) { world = args[0].val(); } else { if(environment.getEnv(CommandHelperEnvironment.class).GetPlayer() == null){ throw new CREInvalidWorldException("A world must be specified in a context with no player.", t); } world = environment.getEnv(CommandHelperEnvironment.class).GetPlayer().getWorld().getName(); } MCWorld w = Static.getServer().getWorld(world); if (w == null) { throw new CREInvalidWorldException("The specified world \"" + world + "\" is not a valid world.", t); } return ObjectGenerator.GetGenerator().location(w.getSpawnLocation(), false); } } @api(environments=CommandHelperEnvironment.class) public static class set_spawn extends AbstractFunction { @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREInvalidWorldException.class, CRECastException.class, CREFormatException.class}; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { MCWorld w = (environment.getEnv(CommandHelperEnvironment.class).GetPlayer() != null ? environment.getEnv(CommandHelperEnvironment.class).GetPlayer().getWorld() : null); int x = 0; int y = 0; int z = 0; if (args.length == 1) { MCLocation l = ObjectGenerator.GetGenerator().location(args[0], w, t); w = l.getWorld(); x = l.getBlockX(); y = l.getBlockY(); z = l.getBlockZ(); } else if (args.length == 3) { x = Static.getInt32(args[0], t); y = Static.getInt32(args[1], t); z = Static.getInt32(args[2], t); } else if (args.length == 4) { w = Static.getServer().getWorld(args[0].val()); x = Static.getInt32(args[1], t); y = Static.getInt32(args[2], t); z = Static.getInt32(args[3], t); } if (w == null) { throw new CREInvalidWorldException("Invalid world given.", t); } w.setSpawnLocation(x, y, z); return CVoid.VOID; } @Override public String getName() { return "set_spawn"; } @Override public Integer[] numArgs() { return new Integer[]{1, 3, 4}; } @Override public String docs() { return "void {locationArray | [world], x, y, z} Sets the spawn of the world. Note that in some cases, a plugin" + " may set the spawn differently, and this method will do nothing. In that case, you should use" + " the plugin's commands to set the spawn."; } @Override public CHVersion since() { return CHVersion.V3_3_1; } } @api(environments=CommandHelperEnvironment.class) public static class refresh_chunk extends AbstractFunction { @Override public String getName() { return "refresh_chunk"; } @Override public Integer[] numArgs() { return new Integer[]{1, 2, 3}; } @Override public String docs() { return "void {[world], x, z | [world], locationArray} Resends the chunk data to all clients, using the specified world, or the current" + " players world if not provided."; } @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CRECastException.class, CREFormatException.class, CREInvalidWorldException.class}; } @Override public boolean isRestricted() { return true; } @Override public CHVersion since() { return CHVersion.V3_3_0; } @Override public Boolean runAsync() { return false; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { MCPlayer m = environment.getEnv(CommandHelperEnvironment.class).GetPlayer(); MCWorld world; int x; int z; if (args.length == 1) { //Location array provided MCLocation l = ObjectGenerator.GetGenerator().location(args[0], m != null ? m.getWorld() : null, t); world = l.getWorld(); x = l.getBlockX(); z = l.getBlockZ(); } else if (args.length == 2) { //Either location array and world provided, or x and z. Test for array at pos 2 if (args[1] instanceof CArray) { world = Static.getServer().getWorld(args[0].val()); MCLocation l = ObjectGenerator.GetGenerator().location(args[1], null, t); x = l.getBlockX(); z = l.getBlockZ(); } else { if (m == null) { throw new CREInvalidWorldException("No world specified", t); } world = m.getWorld(); x = Static.getInt32(args[0], t); z = Static.getInt32(args[1], t); } } else { //world, x and z provided world = Static.getServer().getWorld(args[0].val()); if (world == null) { throw new CREInvalidWorldException("World " + args[0].val() + " does not exist.", t); } x = Static.getInt32(args[1], t); z = Static.getInt32(args[2], t); } world.refreshChunk(x, z); return CVoid.VOID; } } @api public static class load_chunk extends AbstractFunction { @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CRECastException.class, CREFormatException.class, CREInvalidWorldException.class}; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { MCPlayer m = environment.getEnv(CommandHelperEnvironment.class).GetPlayer(); MCWorld world; int x; int z; if (args.length == 1) { //Location array provided MCLocation l = ObjectGenerator.GetGenerator().location(args[0], m != null ? m.getWorld() : null, t); world = l.getWorld(); x = l.getBlockX(); z = l.getBlockZ(); } else if (args.length == 2) { //Either location array and world provided, or x and z. Test for array at pos 2 if (args[1] instanceof CArray) { world = Static.getServer().getWorld(args[0].val()); if (world == null) { throw new CREInvalidWorldException("The given world (" + args[0].val() + ") does not exist.", t); } MCLocation l = ObjectGenerator.GetGenerator().location(args[1], null, t); x = l.getBlockX(); z = l.getBlockZ(); } else { if (m == null) { throw new CREInvalidWorldException("No world specified", t); } world = m.getWorld(); x = Static.getInt32(args[0], t); z = Static.getInt32(args[1], t); } } else { //world, x and z provided world = Static.getServer().getWorld(args[0].val()); if (world == null) { throw new CREInvalidWorldException("The given world (" + args[0].val() + ") does not exist.", t); } x = Static.getInt32(args[1], t); z = Static.getInt32(args[2], t); } world.loadChunk(x, z); return CVoid.VOID; } @Override public String getName() { return "load_chunk"; } @Override public Integer[] numArgs() { return new Integer[]{1, 2, 3}; } @Override public String docs() { return "void {[world], x, z | [world], locationArray} Loads the chunk, using the specified world, or the current" + " players world if not provided."; } @Override public Version since() { return CHVersion.V3_3_1; } } @api(environments=CommandHelperEnvironment.class) public static class unload_chunk extends AbstractFunction { @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CRECastException.class, CREFormatException.class, CREInvalidWorldException.class}; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { MCPlayer m = environment.getEnv(CommandHelperEnvironment.class).GetPlayer(); MCWorld world; int x; int z; if (args.length == 1) { //Location array provided MCLocation l = ObjectGenerator.GetGenerator().location(args[0], m != null ? m.getWorld() : null, t); world = l.getWorld(); x = l.getBlockX(); z = l.getBlockZ(); } else if (args.length == 2) { //Either location array and world provided, or x and z. Test for array at pos 2 if (args[1] instanceof CArray) { world = Static.getServer().getWorld(args[0].val()); MCLocation l = ObjectGenerator.GetGenerator().location(args[1], null, t); x = l.getBlockX(); z = l.getBlockZ(); } else { if (m == null) { throw new CREInvalidWorldException("No world specified", t); } world = m.getWorld(); x = Static.getInt32(args[0], t); z = Static.getInt32(args[1], t); } } else { //world, x and z provided world = Static.getServer().getWorld(args[0].val()); x = Static.getInt32(args[1], t); z = Static.getInt32(args[2], t); } if (world == null) { // Happends when m is a fake console or null command sender. throw new CREInvalidWorldException("No world specified", t); } world.unloadChunk(x, z); return CVoid.VOID; } @Override public String getName() { return "unload_chunk"; } @Override public Integer[] numArgs() { return new Integer[]{1, 2, 3}; } @Override public String docs() { return "void {[world], x, z | [world], locationArray} Unloads the chunk, using the specified world, or the current" + " players world if not provided."; } @Override public Version since() { return CHVersion.V3_3_1; } } @api public static class get_loaded_chunks extends AbstractFunction { @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CRECastException.class, CREFormatException.class, CREInvalidWorldException.class, CRENotFoundException.class}; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { MCPlayer m = environment.getEnv(CommandHelperEnvironment.class).GetPlayer(); MCWorld world; if (args.length == 1) { // World Provided world = Static.getServer().getWorld(args[0].val()); } else { if (m == null) { throw new CREInvalidWorldException("No world specified", t); } world = m.getWorld(); } if (world == null) { // Happends when m is a fake console or null command sender. throw new CREInvalidWorldException("No world specified", t); } MCChunk[] chunks = world.getLoadedChunks(); if (chunks == null) { // Happends when m is a fake player. throw new CRENotFoundException( "Could not find the chunk objects of the world (are you running in cmdline mode?)", t); } CArray ret = new CArray(t); for (int i = 0; i < chunks.length; i++) { CArray chunk = new CArray(t); chunk.set("x", new CInt(chunks[i].getX(), t), t); chunk.set("z", new CInt(chunks[i].getZ(), t), t); chunk.set("world", chunks[i].getWorld().getName(), t); ret.set(i, chunk, t); } return ret; } @Override public String getName() { return "get_loaded_chunks"; } @Override public Integer[] numArgs() { return new Integer[] {0, 1}; } @Override public String docs() { return "array {[world]} Gets all currently loaded chunks, in the specified world, or the current" + " players world if not provided."; } @Override public Version since() { return CHVersion.V3_3_1; } } @api(environments=CommandHelperEnvironment.class) public static class regen_chunk extends AbstractFunction { @Override public String getName() { return "regen_chunk"; } @Override public Integer[] numArgs() { return new Integer[]{1, 2, 3}; } @Override public String docs() { return "void {x, z, [world]| locationArray, [world]} Regenerate the chunk, using the specified world, or the current" + " players world if not provided. Beware that this is destructive! Any data in this chunk will be lost!"; } @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CRECastException.class, CREFormatException.class, CREInvalidWorldException.class}; } @Override public boolean isRestricted() { return true; } @Override public CHVersion since() { return CHVersion.V3_3_1; } @Override public Boolean runAsync() { return false; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { MCPlayer m = environment.getEnv(CommandHelperEnvironment.class).GetPlayer(); MCWorld world; int x; int z; if (args.length == 1) { //Location array provided MCLocation l = ObjectGenerator.GetGenerator().location(args[0], m != null ? m.getWorld() : null, t); world = l.getWorld(); x = l.getChunk().getX(); z = l.getChunk().getZ(); } else if (args.length == 2) { //Either location array and world provided, or x and z. Test for array at pos 1 if (args[0] instanceof CArray) { world = Static.getServer().getWorld(args[1].val()); if (world == null) { throw new CREInvalidWorldException("World " + args[1].val() + " does not exist.", t); } MCLocation l = ObjectGenerator.GetGenerator().location(args[0], null, t); x = l.getChunk().getX(); z = l.getChunk().getZ(); } else { if (m == null) { throw new CREInvalidWorldException("No world specified", t); } world = m.getWorld(); x = Static.getInt32(args[0], t); z = Static.getInt32(args[1], t); } } else { //world, x and z provided x = Static.getInt32(args[0], t); z = Static.getInt32(args[1], t); world = Static.getServer().getWorld(args[2].val()); if (world == null) { throw new CREInvalidWorldException("World " + args[2].val() + " does not exist.", t); } } return CBoolean.get(world.regenerateChunk(x, z)); } } @api(environments=CommandHelperEnvironment.class) public static class is_slime_chunk extends AbstractFunction { @Override public String getName() { return "is_slime_chunk"; } @Override public Integer[] numArgs() { return new Integer[]{1, 2, 3}; } @Override public String docs() { return "boolean {x, z, [world]| locationArray, [world]} Returns if the chunk is a slime spawning chunk, using the specified world, or the current" + " players world if not provided."; } @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CRECastException.class, CREFormatException.class, CREInvalidWorldException.class}; } @Override public boolean isRestricted() { return true; } @Override public CHVersion since() { return CHVersion.V3_3_1; } @Override public Boolean runAsync() { return false; } Random rnd = new Random(); @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { MCPlayer m = environment.getEnv(CommandHelperEnvironment.class).GetPlayer(); MCWorld world; int x; int z; if (args.length == 1) { //Location array provided MCLocation l = ObjectGenerator.GetGenerator().location(args[0], m != null ? m.getWorld() : null, t); world = l.getWorld(); x = l.getChunk().getX(); z = l.getChunk().getZ(); } else if (args.length == 2) { //Either location array and world provided, or x and z. Test for array at pos 1 if (args[0] instanceof CArray) { world = Static.getServer().getWorld(args[1].val()); if (world == null) { throw new CREInvalidWorldException("The given world (" + args[1].val() + ") does not exist.", t); } MCLocation l = ObjectGenerator.GetGenerator().location(args[0], null, t); x = l.getChunk().getX(); z = l.getChunk().getZ(); } else { if (m == null) { throw new CREInvalidWorldException("No world specified", t); } world = m.getWorld(); x = Static.getInt32(args[0], t); z = Static.getInt32(args[1], t); } } else { //world, x and z provided x = Static.getInt32(args[0], t); z = Static.getInt32(args[1], t); world = Static.getServer().getWorld(args[2].val()); if (world == null) { throw new CREInvalidWorldException("The given world (" + args[2].val() + ") does not exist.", t); } } rnd.setSeed(world.getSeed() + x * x * 0x4c1906 + x * 0x5ac0db + z * z * 0x4307a7L + z * 0x5f24f ^ 0x3ad8025f); return CBoolean.get(rnd.nextInt(10) == 0); } } private static final SortedMap<String, Construct> TimeLookup = new TreeMap<String, Construct>(); static { synchronized (World.class) { Properties p = new Properties(); try { p.load(Minecraft.class.getResourceAsStream("/time_names.txt")); Enumeration e = p.propertyNames(); while (e.hasMoreElements()) { String name = e.nextElement().toString(); TimeLookup.put(name, new CString(p.getProperty(name).toString(), Target.UNKNOWN)); } } catch (IOException ex) { Logger.getLogger(World.class.getName()).log(Level.SEVERE, null, ex); } } } @api(environments=CommandHelperEnvironment.class) public static class set_world_time extends AbstractFunction { @Override public String getName() { return "set_world_time"; } @Override public Integer[] numArgs() { return new Integer[]{1, 2}; } @Override public String docs() { StringBuilder doc = new StringBuilder(); synchronized (World.class) { doc.append("void {[world], time} Sets the time of a given world. Should be a number from 0 to" + " 24000, if not, it is modulo scaled. ---- Alternatively, common time notation (9:30pm, 4:00 am)" + " is acceptable, and convenient english mappings also exist:"); doc.append("<ul>"); for (String key : TimeLookup.keySet()) { doc.append("<li>").append(key).append(" = ").append(TimeLookup.get(key)).append("</li>"); } doc.append("</ul>"); } return doc.toString(); } @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREInvalidWorldException.class, CREFormatException.class}; } @Override public boolean isRestricted() { return true; } @Override public CHVersion since() { return CHVersion.V3_3_0; } @Override public Boolean runAsync() { return false; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { MCWorld w = null; if (environment.getEnv(CommandHelperEnvironment.class).GetPlayer() != null) { w = environment.getEnv(CommandHelperEnvironment.class).GetPlayer().getWorld(); } if (args.length == 2) { w = Static.getServer().getWorld(args[0].val()); } if (w == null) { throw new CREInvalidWorldException("No world specified", t); } long time = 0; String stime = (args.length == 1 ? args[0] : args[1]).val().toLowerCase(); if (TimeLookup.containsKey(stime.replaceAll("[^a-z]", ""))) { stime = TimeLookup.get(stime.replaceAll("[^a-z]", "")).val(); } if (stime.matches("^([\\d]+)[:.]([\\d]+)[ ]*?(?:([pa])\\.*m\\.*){0,1}$")) { Pattern p = Pattern.compile("^([\\d]+)[:.]([\\d]+)[ ]*?(?:([pa])\\.*m\\.*){0,1}$"); Matcher m = p.matcher(stime); m.find(); int hour = Integer.parseInt(m.group(1)); int minute = Integer.parseInt(m.group(2)); String offset = "a"; if (m.group(3) != null) { offset = m.group(3); } if (offset.equals("p")) { hour += 12; } if (hour == 24) { hour = 0; } if (hour > 24) { throw new CREFormatException("Invalid time provided", t); } if (minute > 59) { throw new CREFormatException("Invalid time provided", t); } hour -= 6; hour = hour % 24; long ttime = hour * 1000; ttime += ((minute / 60.0) * 1000); stime = Long.toString(ttime); } try { Long.valueOf(stime); } catch (NumberFormatException e) { throw new CREFormatException("Invalid time provided", t); } time = Long.parseLong(stime); w.setTime(time); return CVoid.VOID; } } @api(environments=CommandHelperEnvironment.class) public static class get_world_time extends AbstractFunction { @Override public String getName() { return "get_world_time"; } @Override public Integer[] numArgs() { return new Integer[]{0, 1}; } @Override public String docs() { return "int {[world]} Returns the time of the specified world, as an integer from" + " 0 to 24000-1"; } @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREInvalidWorldException.class}; } @Override public boolean isRestricted() { return true; } @Override public CHVersion since() { return CHVersion.V3_3_0; } @Override public Boolean runAsync() { return false; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { MCWorld w = null; if (environment.getEnv(CommandHelperEnvironment.class).GetPlayer() != null) { w = environment.getEnv(CommandHelperEnvironment.class).GetPlayer().getWorld(); } if (args.length == 1) { w = Static.getServer().getWorld(args[0].val()); } if (w == null) { throw new CREInvalidWorldException("No world specified", t); } return new CInt(w.getTime(), t); } } @api(environments={CommandHelperEnvironment.class}) public static class create_world extends AbstractFunction{ @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREFormatException.class, CRECastException.class}; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException { MCWorldCreator creator = StaticLayer.GetConvertor().getWorldCreator(args[0].val()); if (args.length >= 3) { MCWorldType type; try { type = MCWorldType.valueOf(args[1].val().toUpperCase()); } catch (IllegalArgumentException e) { throw new CREFormatException(args[1].val() + " is not a valid world type. Must be one of: " + StringUtils.Join(MCWorldType.values(), ", "), t); } MCWorldEnvironment environment; try { environment = MCWorldEnvironment.valueOf(args[2].val().toUpperCase()); } catch (IllegalArgumentException e) { throw new CREFormatException(args[2].val() + " is not a valid environment type. Must be one of: " + StringUtils.Join(MCWorldEnvironment.values(), ", "), t); } creator.type(type).environment(environment); } if ((args.length >= 4) && !(args[3] instanceof CNull)) { if (args[3] instanceof CInt) { creator.seed(Static.getInt(args[3], t)); } else { creator.seed(args[3].val().hashCode()); } } if (args.length == 5) { creator.generator(args[4].val()); } creator.createWorld(); return CVoid.VOID; } @Override public String getName() { return "create_world"; } @Override public Integer[] numArgs() { return new Integer[]{1, 3, 4, 5}; } @Override public String docs() { return "void {name, [type, environment, [seed, [generator]]]} Creates a new world with the specified options." + " If the world already exists, it will be loaded from disk, and the last 3 arguments may be" + " ignored. name is the name of the world, type is one of " + StringUtils.Join(MCWorldType.values(), ", ") + " and environment is one of " + StringUtils.Join(MCWorldEnvironment.values(), ", ") + ". The seed can be an integer, a string (will be the hashcode), or null (will be random int)." + " Generator is the name of a world generator loaded on the server."; } @Override public CHVersion since() { return CHVersion.V3_3_1; } } @api(environments={CommandHelperEnvironment.class}) public static class get_worlds extends AbstractFunction{ @Override public Class<? extends CREThrowable>[] thrown() { return null; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { CArray worlds = new CArray(t); for(MCWorld w : Static.getServer().getWorlds()){ worlds.push(new CString(w.getName(), t), t); } return worlds; } @Override public String getName() { return "get_worlds"; } @Override public Integer[] numArgs() { return new Integer[]{0}; } @Override public String docs() { return "array {} Returns a list of all currently loaded worlds."; } @Override public CHVersion since() { return CHVersion.V3_3_1; } } @api(environments={CommandHelperEnvironment.class}) public static class get_chunk_loc extends AbstractFunction { @Override public String getName() { return "get_chunk_loc"; } @Override public Integer[] numArgs() { return new Integer[]{0, 1}; } @Override public Construct exec(Target t, Environment env, Construct... args) throws CancelCommandException, ConfigRuntimeException { MCCommandSender cs = env.getEnv(CommandHelperEnvironment.class).GetCommandSender(); MCPlayer p = null; MCWorld w = null; MCLocation l = null; if (cs instanceof MCPlayer) { p = (MCPlayer)cs; Static.AssertPlayerNonNull(p, t); l = p.getLocation(); if (l == null) { throw new CRENotFoundException( "Could not find the location of the given player (are you running in cmdline mode?)", t); } w = l.getWorld(); } if (args.length == 1) { if (args[0] instanceof CArray) { l = ObjectGenerator.GetGenerator().location(args[0], w, t); } else { throw new CREFormatException("expecting argument 1 of get_chunk_loc to be a location array", t); } } else { if (p == null) { throw new CREInsufficientArgumentsException("expecting a player context for get_chunk_loc when used without arguments", t); } } CArray chunk = new CArray(t, new CInt(l.getChunk().getX(), t), new CInt(l.getChunk().getZ(), t), new CString(l.getChunk().getWorld().getName(), t)); chunk.set("x", new CInt(l.getChunk().getX(), t), t); chunk.set("z", new CInt(l.getChunk().getZ(), t), t); chunk.set("world", l.getChunk().getWorld().getName(), t); return chunk; } @Override public String docs() { return "array {[location array]} Returns an array of x, z, world " + "coords of the chunk of either the location specified or the location of " + "the player running the command."; } @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREFormatException.class, CREInsufficientArgumentsException.class, CRENotFoundException.class}; } @Override public boolean isRestricted() { return false; } @Override public CHVersion since() { return CHVersion.V3_3_1; } @Override public Boolean runAsync() { return false; } } @api(environments={CommandHelperEnvironment.class}) public static class spawn_falling_block extends AbstractFunction{ @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREFormatException.class}; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException { MCPlayer p = env.getEnv(CommandHelperEnvironment.class).GetPlayer(); MCLocation loc = ObjectGenerator.GetGenerator().location(args[0], p != null ? p.getWorld() : null , t); MCItemStack item = Static.ParseItemNotation(this.getName(), args[1].val(), 1, t); Vector3D v = null; if (args.length == 3) { v = ObjectGenerator.GetGenerator().vector(args[2], t); } MCFallingBlock block = loc.getWorld().spawnFallingBlock(loc, item.getType().getType(), (byte)item.getData().getData()); if (v != null) { block.setVelocity(v); } return new CString(block.getUniqueId().toString(), t); } @Override public String getName() { return "spawn_falling_block"; } @Override public Integer[] numArgs() { return new Integer[]{2, 3}; } @Override public String docs() { return "integer {location array, id[:type], [vector array]} Spawns a" + " falling block of the specified id and type at the specified location, applying" + " vector array as a velocity if given. Values for the vector array are doubles, and 1.0" + " seems to imply about 3 times walking speed. Gravity applies for y."; } @Override public CHVersion since() { return CHVersion.V3_3_1; } } @api public static class world_info extends AbstractFunction { @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREInvalidWorldException.class}; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { MCWorld w = Static.getServer().getWorld(args[0].val()); if (w == null) { throw new CREInvalidWorldException("Unknown world: " + args[0], t); } CArray ret = CArray.GetAssociativeArray(t); ret.set("name", new CString(w.getName(), t), t); ret.set("seed", new CInt(w.getSeed(), t), t); ret.set("environment", new CString(w.getEnvironment().name(), t), t); ret.set("generator", new CString(w.getGenerator(), t), t); ret.set("worldtype", new CString(w.getWorldType().name(), t), t); ret.set("sealevel", new CInt(w.getSeaLevel(), t), t); ret.set("maxheight", new CInt(w.getMaxHeight(), t), t); return ret; } @Override public String getName() { return "world_info"; } @Override public Integer[] numArgs() { return new Integer[]{1}; } @Override public String docs() { return "array {world} Returns an associative array of all the info needed to duplicate the world." + " The keys are name, seed, environment, generator, worldtype, and sealevel."; } @Override public CHVersion since() { return CHVersion.V3_3_1; } } @api public static class unload_world extends AbstractFunction { @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREInvalidWorldException.class}; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { boolean save = true; if (args.length == 2) { save = Static.getBoolean(args[1]); } MCWorld world = Static.getServer().getWorld(args[0].val()); if (world == null) { throw new CREInvalidWorldException("Unknown world: " + args[0].val(), t); } return CBoolean.get(Static.getServer().unloadWorld(world, save)); } @Override public String getName() { return "unload_world"; } @Override public Integer[] numArgs() { return new Integer[]{1, 2}; } @Override public String docs() { return "boolean {world, [save]} Unloads a world, and saves it if save is true (defaults true)," + " and returns whether or not the operation was successful."; } @Override public Version since() { return CHVersion.V3_3_1; } } @api public static class get_difficulty extends AbstractFunction { @Override public String getName() { return "get_difficulty"; } @Override public Integer[] numArgs() { return new Integer[]{1}; } @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREInvalidWorldException.class}; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public String docs() { return "string {world} Returns the difficulty of the world, It will be one of " + StringUtils.Join(MCDifficulty.values(), ", ", ", or ", " or ") + "."; } @Override public Version since() { return CHVersion.V3_3_1; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { MCWorld world = Static.getServer().getWorld(args[0].val()); if (world == null) { throw new CREInvalidWorldException("Unknown world: " + args[0].val(), t); } return new CString(world.getDifficulty().toString(), t); } } @api public static class set_difficulty extends AbstractFunction { @Override public String getName() { return "set_difficulty"; } @Override public Integer[] numArgs() { return new Integer[]{1, 2}; } @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREInvalidWorldException.class, CREFormatException.class}; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public String docs() { return "void {[world], difficulty} Sets the difficulty of the world with the given name, or all worlds if the name is not given." + " difficulty can be " + StringUtils.Join(MCDifficulty.values(), ", ", ", or ", " or ") + "."; } @Override public Version since() { return CHVersion.V3_3_1; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { MCDifficulty difficulty; if (args.length == 1) { try { difficulty = MCDifficulty.valueOf(args[0].val().toUpperCase()); } catch (IllegalArgumentException exception) { throw new CREFormatException("The difficulty \"" + args[0].val() + "\" does not exist.", t); } for (MCWorld world : Static.getServer().getWorlds()) { world.setDifficulty(difficulty); } } else { MCWorld world = Static.getServer().getWorld(args[0].val()); if (world == null) { throw new CREInvalidWorldException("Unknown world: " + args[0].val(), t); } try { difficulty = MCDifficulty.valueOf(args[1].val().toUpperCase()); } catch (IllegalArgumentException exception) { throw new CREFormatException("The difficulty \"" + args[1].val() + "\" does not exist.", t); } world.setDifficulty(difficulty); } return CVoid.VOID; } } @api public static class get_pvp extends AbstractFunction { @Override public String getName() { return "get_pvp"; } @Override public Integer[] numArgs() { return new Integer[]{1}; } @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREInvalidWorldException.class}; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public String docs() { return "boolean {world} Returns if PVP is allowed in the world."; } @Override public Version since() { return CHVersion.V3_3_1; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { MCWorld world = Static.getServer().getWorld(args[0].val()); if (world == null) { throw new CREInvalidWorldException("Unknown world: " + args[0].val(), t); } return CBoolean.get(world.getPVP()); } } @api public static class set_pvp extends AbstractFunction { @Override public String getName() { return "set_pvp"; } @Override public Integer[] numArgs() { return new Integer[]{1, 2}; } @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREInvalidWorldException.class}; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public String docs() { return "void {[world], boolean} Sets if PVP is allowed in the world with the given name, or all worlds if the name is not given."; } @Override public Version since() { return CHVersion.V3_3_1; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { if (args.length == 1) { boolean pvp = Static.getBoolean(args[0]); for (MCWorld world : Static.getServer().getWorlds()) { world.setPVP(pvp); } } else { MCWorld world = Static.getServer().getWorld(args[0].val()); if (world == null) { throw new CREInvalidWorldException("Unknown world: " + args[0].val(), t); } world.setPVP(Static.getBoolean(args[1])); } return CVoid.VOID; } } @api public static class get_gamerule extends AbstractFunction { @Override public String getName() { return "get_gamerule"; } @Override public Integer[] numArgs() { return new Integer[]{1, 2}; } @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREInvalidWorldException.class, CREFormatException.class}; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public String docs() { return "mixed {world, [gameRule]} Returns an associative array containing the values of all existing" + " gamerules for the given world. If gameRule is specified, the function only returns that value." + " gameRule can be " + StringUtils.Join(MCGameRule.values(), ", ", ", or ", " or ") + "."; } @Override public Version since() { return CHVersion.V3_3_1; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { MCWorld world = Static.getServer().getWorld(args[0].val()); if (world == null) { throw new CREInvalidWorldException("Unknown world: " + args[0].val(), t); } if (args.length == 1) { CArray gameRules = CArray.GetAssociativeArray(t); for (String gameRule : world.getGameRules()) { gameRules.set(new CString(gameRule, t), Static.resolveConstruct(world.getGameRuleValue(gameRule), t), t); } return gameRules; } else { try { MCGameRule gameRule = MCGameRule.valueOf(args[1].val().toUpperCase()); String value = world.getGameRuleValue(gameRule.getGameRule()); if(value.equals("")) { throw new CREFormatException("The gamerule \"" + args[1].val() + "\" does not exist in this version.", t); } return Static.resolveConstruct(value, t); } catch (IllegalArgumentException exception) { throw new CREFormatException("The gamerule \"" + args[1].val() + "\" does not exist.", t); } } } } @api public static class set_gamerule extends AbstractFunction { @Override public String getName() { return "set_gamerule"; } @Override public Integer[] numArgs() { return new Integer[]{2, 3}; } @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREInvalidWorldException.class, CREFormatException.class}; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public String docs() { return "void {[world], gameRule, value} Sets the value of the gamerule for the specified world. If world is" + " not given the value is set for all worlds. Returns true if successful. gameRule can be " + StringUtils.Join(MCGameRule.values(), ", ", ", or ", " or ") + "."; } @Override public Version since() { return CHVersion.V3_3_1; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { MCGameRule gameRule; boolean success = false; if (args.length == 2) { try { gameRule = MCGameRule.valueOf(args[0].val().toUpperCase()); } catch (IllegalArgumentException exception) { throw new CREFormatException("The gamerule \"" + args[0].val() + "\" does not exist.", t); } if(!args[1].getCType().equals(gameRule.getRuleType())) { throw new CREFormatException("Wrong value type for \"" + args[0].val() + "\".", t); } String value = args[1].val(); for (MCWorld world : Static.getServer().getWorlds()) { success = world.setGameRuleValue(gameRule, value); } } else { try { gameRule = MCGameRule.valueOf(args[1].val().toUpperCase()); } catch (IllegalArgumentException exception) { throw new CREFormatException("The gamerule \"" + args[1].val() + "\" does not exist.", t); } MCWorld world = Static.getServer().getWorld(args[0].val()); if (world == null) { throw new CREInvalidWorldException("Unknown world: " + args[0].val(), t); } if(!args[2].getCType().equals(gameRule.getRuleType())) { throw new CREFormatException("Wrong value type for \"" + args[1].val() + "\".", t); } success = world.setGameRuleValue(gameRule, args[2].val()); } return CBoolean.get(success); } } @api public static class location_shift extends AbstractFunction { @Override public String getName() { return "location_shift"; } @Override public Integer[] numArgs() { return new Integer[]{3}; } @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREInvalidWorldException.class, CREFormatException.class}; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public String docs() { return "locationArray {location_from, location_to, distance} Returns a location that is the specified" + " distance from the first location along a vector to the second location. The target location's" + " world is ignored."; } @Override public Version since() { return CHVersion.V3_3_1; } @Override public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException { MCPlayer p = env.getEnv(CommandHelperEnvironment.class).GetPlayer(); MCLocation from = ObjectGenerator.GetGenerator().location(args[0], p != null ? p.getWorld() : null, t); MCLocation to = ObjectGenerator.GetGenerator().location(args[1], from.getWorld(), t); double distance = Static.getNumber(args[2], t); Vector3D vector = to.toVector().subtract(from.toVector()).normalize(); MCLocation shifted_from = from.add(vector.multiply(distance)); return ObjectGenerator.GetGenerator().location(shifted_from, false); } } @api public static class get_yaw extends AbstractFunction { @Override public String getName() { return "get_yaw"; } @Override public Integer[] numArgs() { return new Integer[]{2}; } @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREInvalidWorldException.class, CREFormatException.class}; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public String docs() { return "double {location_from, location_to} Calculate yaw from one location to another on the X-Z plane." + " The rotation is measured in degrees (0-359.99...) relative to the (x=0,z=1) vector, which" + " points south. Throws a FormatException if locations have differing worlds."; } @Override public Version since() { return CHVersion.V3_3_1; } @Override public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException { MCPlayer p = env.getEnv(CommandHelperEnvironment.class).GetPlayer(); MCLocation from = ObjectGenerator.GetGenerator().location(args[0], p != null ? p.getWorld() : null, t); MCLocation to = ObjectGenerator.GetGenerator().location(args[1], p != null ? p.getWorld() : null, t); MCLocation subtract; try { subtract = to.subtract(from); } catch(IllegalArgumentException ex) { throw new CREFormatException("Locations are in differing worlds.", t); } double dX = subtract.getX(); double dZ = subtract.getZ(); double yaw = java.lang.Math.atan(dX/dZ) * 180 / java.lang.Math.PI; // In degrees [-90:90]. if(dZ < 0) { // Bottom circle quadrant. yaw += 180; } else if(dX < 0) { // Top left half quadrant. yaw += 360; } return new CDouble(360 - yaw, t); } } @api public static class get_pitch extends AbstractFunction { @Override public String getName() { return "get_pitch"; } @Override public Integer[] numArgs() { return new Integer[]{2}; } @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREInvalidWorldException.class, CREFormatException.class}; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public String docs() { return "double {location_from, location_to} Calculate pitch from one location to another."; } @Override public Version since() { return CHVersion.V3_3_1; } @Override public Construct exec(Target t, Environment env, Construct... args) throws ConfigRuntimeException { MCPlayer p = env.getEnv(CommandHelperEnvironment.class).GetPlayer(); MCLocation from = ObjectGenerator.GetGenerator().location(args[0], p != null ? p.getWorld() : null, t); MCLocation to = ObjectGenerator.GetGenerator().location(args[1], p != null ? p.getWorld() : null, t); MCLocation subtract = to.subtract(from); double dX = subtract.getX(); double dY = subtract.getY(); double dZ = subtract.getZ(); double distanceXZ = java.lang.Math.sqrt(dX * dX + dZ * dZ); double pitch = java.lang.Math.atan(dY/distanceXZ) * -180 / java.lang.Math.PI; return new CDouble(pitch, t); } } @api public static class save_world extends AbstractFunction { @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREInvalidWorldException.class}; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { MCWorld world = Static.getWorld(args[0], t); world.save(); return CVoid.VOID; } @Override public String getName() { return "save_world"; } @Override public Integer[] numArgs() { return new Integer[]{1}; } @Override public String docs() { return "void {world_name} Saves the specified world."; } @Override public Version since() { return CHVersion.V3_3_1; } } @api public static class get_temperature extends AbstractFunction { @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREFormatException.class}; } @Override public boolean isRestricted() { return false; } @Override public Boolean runAsync() { return false; } @Override public Construct exec(Target target, Environment environment, Construct... args) throws ConfigRuntimeException { MCPlayer player = environment.getEnv(CommandHelperEnvironment.class).GetPlayer(); MCWorld world = null; if(player != null) { world = player.getWorld(); } MCLocation loc = ObjectGenerator.GetGenerator().location(args[0], world, target); return new CDouble(loc.getBlock().getTemperature(), target); } @Override public String getName() { return "get_temperature"; } @Override public Integer[] numArgs() { return new Integer[]{1}; } @Override public String docs() { return "double {locationArray} Returns the current temperature of the location given."; } @Override public Version since() { return CHVersion.V3_3_1; } } @api public static class get_world_border extends AbstractFunction { @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CREInvalidWorldException.class}; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { MCWorld w = Static.getServer().getWorld(args[0].val()); if (w == null){ throw new CREInvalidWorldException("Unknown world: " + args[0], t); } if(Static.getServer().getMinecraftVersion().lt(MCVersion.MC1_8)){ return CNull.NULL; } MCWorldBorder wb = w.getWorldBorder(); CArray ret = CArray.GetAssociativeArray(t); ret.set("width", new CDouble(wb.getSize(), t), t); ret.set("center", ObjectGenerator.GetGenerator().location(wb.getCenter(), false), t); ret.set("damagebuffer", new CDouble(wb.getDamageBuffer(), t), t); ret.set("damageamount", new CDouble(wb.getDamageAmount(), t), t); ret.set("warningtime", new CInt(wb.getWarningTime(), t), t); ret.set("warningdistance", new CInt(wb.getWarningDistance(), t), t); return ret; } @Override public String getName() { return "get_world_border"; } @Override public Integer[] numArgs() { return new Integer[]{1}; } @Override public String docs() { return "array {world_name} Returns an associative array of all information about the world's border." + " The keys are width, center, damagebuffer, damageamount, warningtime, warningdistance."; } @Override public Version since() { return CHVersion.V3_3_2; } } @api public static class set_world_border extends AbstractFunction { @Override public Class<? extends CREThrowable>[] thrown() { return new Class[]{CRECastException.class, CREFormatException.class, CREInvalidWorldException.class, CRERangeException.class}; } @Override public boolean isRestricted() { return true; } @Override public Boolean runAsync() { return false; } @Override public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException { MCWorld w = Static.getServer().getWorld(args[0].val()); if (w == null){ throw new CREInvalidWorldException("Unknown world: " + args[0], t); } if(Static.getServer().getMinecraftVersion().lt(MCVersion.MC1_8)){ return CVoid.VOID; } MCWorldBorder wb = w.getWorldBorder(); Construct c = args[1]; if(!(c instanceof CArray)){ throw new CREFormatException("Expected array but given \"" + args[1].val() + "\"", t); } CArray params = (CArray)c; if(params.containsKey("width")){ if(params.containsKey("seconds")){ wb.setSize(ArgumentValidation.getDouble(params.get("width", t), t), ArgumentValidation.getInt32(params.get("seconds", t), t)); } else { wb.setSize(ArgumentValidation.getDouble(params.get("width", t), t)); } } if(params.containsKey("center")){ wb.setCenter(ObjectGenerator.GetGenerator().location(params.get("center", t), w, t)); } if(params.containsKey("damagebuffer")){ wb.setDamageBuffer(ArgumentValidation.getDouble(params.get("damagebuffer", t), t)); } if(params.containsKey("damageamount")){ wb.setDamageAmount(ArgumentValidation.getDouble(params.get("damageamount", t), t)); } if(params.containsKey("warningtime")){ wb.setWarningTime(ArgumentValidation.getInt32(params.get("warningtime", t), t)); } if(params.containsKey("warningdistance")){ wb.setWarningDistance(ArgumentValidation.getInt32(params.get("warningdistance", t), t)); } return CVoid.VOID; } @Override public String getName() { return "set_world_border"; } @Override public Integer[] numArgs() { return new Integer[]{2}; } @Override public String docs() { return "void {world_name, paramArray} Updates the world's border with the given values. In addition to the" + " keys returned by get_world_border(), you can specify the \"seconds\" for which the \"width\"" + " will be applied."; } @Override public Version since() { return CHVersion.V3_3_2; } } }