| /* Copyright 2015-2020 Rivoreo |
| |
| This Source Code Form is subject to the terms of the Mozilla Public |
| License, v. 2.0. If a copy of the MPL was not distributed with this |
| file, You can obtain one at https://mozilla.org/MPL/2.0/. |
| */ |
| |
| package rivoreo.minecraft.worldmgr; |
| |
| import org.bukkit.plugin.java.JavaPlugin; |
| import org.bukkit.command.Command; |
| import org.bukkit.command.CommandExecutor; |
| import org.bukkit.command.CommandSender; |
| import org.bukkit.event.player.PlayerTeleportEvent; |
| import org.bukkit.entity.Player; |
| import org.bukkit.Location; |
| import org.bukkit.Server; |
| import org.bukkit.World; |
| import org.bukkit.WorldCreator; |
| import org.bukkit.WorldType; |
| import java.util.logging.Logger; |
| import java.util.logging.Level; |
| import java.util.BitSet; |
| import java.util.Collection; |
| import java.util.Hashtable; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.UUID; |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.InvocationTargetException; |
| import java.io.File; |
| import java.io.IOException; |
| |
| public final class BukkitPlugin extends JavaPlugin implements CommandExecutor { |
| public BukkitPlugin() { |
| bukkit_world_environment_ordinal = World.Environment.values().length; |
| } |
| |
| private static boolean try_minecraftforge = true; |
| private static Class<?> forge_world_manager_class; |
| private static Hashtable<Integer, Class<?>> world_providers; |
| private static Hashtable<Integer, Object> forge_loaded_worlds; |
| private static Class<?> mc_world_provider_class; |
| private static Method mc_world_provider_get_name_method; |
| private static Class<?> mc_world_class; |
| private static Field mc_world_provider_field; |
| private static Method craftbukkit_world_get_handle_method; |
| |
| private static BitSet forge_world_id_map; |
| private static Method forge_world_manager_load_world_method; |
| private static Method forge_register_world_provider_type_method; |
| |
| private static Class<?> customworldprovider_class; |
| private static Method customworldprovider_set_world_name_method; |
| |
| private static Constructor<World.Environment> bukkit_world_environment_construtor; |
| private static int bukkit_world_environment_ordinal; |
| private static Field craftbukkit_world_environment_field; |
| |
| private static Field constructor_accessor_field; |
| private static Method acquire_constructor_accessor_method; |
| private static Method constructor_accessor_new_instance_method; |
| |
| private Logger log; |
| private Server server; |
| |
| private static boolean is_minecraftforge_available() { |
| if(!try_minecraftforge) return false; |
| if(forge_world_manager_class == null || world_providers == null || forge_loaded_worlds == null || mc_world_provider_class == null || mc_world_class == null || mc_world_provider_field == null || mc_world_provider_get_name_method == null) try { |
| forge_world_manager_class = Class.forName("net.minecraftforge.common.DimensionManager"); |
| if(world_providers == null) { |
| Field providers_field = forge_world_manager_class.getDeclaredField("providers"); |
| if(providers_field.getType() != Hashtable.class) return false; |
| providers_field.setAccessible(true); |
| world_providers = (Hashtable<Integer, Class<?>>)providers_field.get(null); |
| } |
| if(forge_loaded_worlds == null) { |
| Field worlds_field = forge_world_manager_class.getDeclaredField("worlds"); |
| if(worlds_field.getType() != Hashtable.class) return false; |
| worlds_field.setAccessible(true); |
| forge_loaded_worlds = (Hashtable<Integer, Object>)worlds_field.get(null); |
| } |
| if(mc_world_provider_class == null) { |
| Method get_provider_method = forge_world_manager_class.getDeclaredMethod("getProvider", int.class); |
| mc_world_provider_class = get_provider_method.getReturnType(); |
| } |
| if(mc_world_class == null) { |
| Method get_world_method = forge_world_manager_class.getDeclaredMethod("getWorld", int.class); |
| mc_world_class = get_world_method.getReturnType().getSuperclass(); |
| } |
| if(mc_world_provider_field == null) try { |
| mc_world_provider_field = mc_world_class.getDeclaredField("field_73011_w"); |
| } catch(NoSuchFieldException e) { |
| mc_world_provider_field = mc_world_class.getDeclaredField("provider"); |
| } |
| if(mc_world_provider_get_name_method == null) try { |
| mc_world_provider_get_name_method = mc_world_provider_class.getDeclaredMethod("func_80007_l"); |
| if(mc_world_provider_get_name_method.getReturnType() != String.class) { |
| mc_world_provider_get_name_method = null; |
| throw new NoSuchMethodException("return type mismatch"); |
| } |
| } catch(NoSuchMethodException e) { |
| mc_world_provider_get_name_method = mc_world_provider_class.getDeclaredMethod("getDimensionName"); |
| if(mc_world_provider_get_name_method.getReturnType() != String.class) { |
| mc_world_provider_get_name_method = null; |
| throw new NoSuchMethodException("return type mismatch"); |
| } |
| } |
| } catch(Exception e) { |
| try_minecraftforge = false; |
| return false; |
| } |
| return true; |
| } |
| |
| // Cauldron only |
| private static Object get_world_provider(World world) throws IllegalAccessException, InvocationTargetException { |
| if(craftbukkit_world_get_handle_method == null) try { |
| craftbukkit_world_get_handle_method = world.getClass().getDeclaredMethod("getHandle"); |
| } catch(NoSuchMethodException e) { |
| e.printStackTrace(); |
| return null; |
| } |
| Object mc_world = craftbukkit_world_get_handle_method.invoke(world); |
| return mc_world_provider_field.get(mc_world); |
| } |
| |
| // Cauldron only |
| private static String get_world_provider_name(World world) { |
| try { |
| Object provider = get_world_provider(world); |
| if(provider == null) return null; |
| return (String)mc_world_provider_get_name_method.invoke(provider); |
| } catch(IllegalAccessException e) { |
| e.printStackTrace(); |
| } catch(InvocationTargetException e) { |
| e.printStackTrace(); |
| } |
| return null; |
| } |
| |
| private World get_world_by_provider_name(String name) { |
| if(!is_minecraftforge_available()) return null; |
| for(World world : server.getWorlds()) { |
| String provider_name = get_world_provider_name(world); |
| if(name.equalsIgnoreCase(provider_name)) return world; |
| if(name.equalsIgnoreCase(provider_name.replace(' ', '_'))) return world; |
| } |
| return null; |
| } |
| |
| private World get_world_by_name_or_uuid(String name) { |
| World world; |
| try { |
| UUID uuid = UUID.fromString(name); |
| world = server.getWorld(uuid); |
| if(world == null) { |
| throw new IllegalArgumentException("world not found"); |
| } |
| } catch(IllegalArgumentException e) { |
| world = server.getWorld(name); |
| if(world == null) world = get_world_by_provider_name(name); |
| } |
| return world; |
| } |
| |
| private void list_loaded_worlds(CommandSender sender) { |
| List<World> worlds = server.getWorlds(); |
| switch(worlds.size()) { |
| case 0: |
| sender.sendMessage("No loaded worlds"); |
| return; |
| case 1: |
| sender.sendMessage("Loaded world:"); |
| break; |
| default: |
| sender.sendMessage("Loaded worlds:"); |
| break; |
| } |
| for(World w : worlds) if(is_minecraftforge_available()) { |
| sender.sendMessage(String.format(" %s '%s' (%s)", |
| get_world_provider_name(w).replace(' ', '_'), w.getName(), w.getUID().toString())); |
| } else { |
| sender.sendMessage(String.format(" %s (%s)", w.getName(), w.getUID().toString())); |
| } |
| } |
| |
| private void list_unloaded_worlds(CommandSender sender) { |
| if(!is_minecraftforge_available()) return; |
| List<String> unloaded_world_names = new ArrayList<String>(); |
| for(Map.Entry<Integer, Class<?>> entry : world_providers.entrySet()) try { |
| Class<?> provider_class = entry.getValue(); |
| if(provider_class == customworldprovider_class) continue; |
| Object provider = provider_class.newInstance(); |
| String name = (String)mc_world_provider_get_name_method.invoke(provider); |
| boolean is_loaded = false; |
| for(Object mc_world : forge_loaded_worlds.values()) { |
| String loaded_name = (String)mc_world_provider_get_name_method.invoke(mc_world_provider_field.get(mc_world)); |
| if(name.equals((String)mc_world_provider_get_name_method.invoke(mc_world_provider_field.get(mc_world)))) { |
| is_loaded = true; |
| break; |
| } |
| } |
| if(!is_loaded) unloaded_world_names.add(name.replace(' ', '_')); |
| } catch(Exception e) { |
| e.printStackTrace(); |
| } |
| switch(unloaded_world_names.size()) { |
| case 0: |
| sender.sendMessage("No unloaded worlds"); |
| break; |
| case 1: |
| sender.sendMessage("Unloaded world:\n " + unloaded_world_names.get(0)); |
| break; |
| default: |
| sender.sendMessage("Unloaded worlds:"); |
| for(String name : unloaded_world_names) sender.sendMessage(" " + name); |
| } |
| } |
| |
| // Cauldron only |
| private World load_world(CommandSender sender, String name) { |
| World world = server.getWorld(name); |
| if(world == null) world = get_world_by_provider_name(name); |
| if(world != null) { |
| sender.sendMessage(String.format("World %s is already loaded", name)); |
| return world; |
| } |
| if(forge_world_manager_load_world_method == null) try { |
| forge_world_manager_load_world_method = forge_world_manager_class.getDeclaredMethod("initDimension", int.class); |
| } catch(NoSuchMethodException e) { |
| e.printStackTrace(); |
| sender.sendMessage(String.format("Failed to load world %s: %s: %s", name, e.getClass().getName(), e.getMessage())); |
| return null; |
| } |
| for(Map.Entry<Integer, Class<?>> entry : world_providers.entrySet()) try { |
| Object provider = entry.getValue().newInstance(); |
| String provider_name = (String)mc_world_provider_get_name_method.invoke(provider); |
| if(name.equalsIgnoreCase(provider_name.replace(' ', '_'))) try { |
| forge_world_manager_load_world_method.invoke(null, entry.getKey()); |
| world = get_world_by_provider_name(provider_name); |
| if(world == null) { |
| sender.sendMessage(String.format("Failed to load world %s for unknown reason", name)); |
| } |
| return world; |
| } catch(Exception e) { |
| e.printStackTrace(); |
| if(e instanceof InvocationTargetException) { |
| Throwable cause = ((InvocationTargetException)e).getCause(); |
| if(cause != null && cause instanceof Exception) e = (Exception)cause; |
| } |
| sender.sendMessage(String.format("Failed to load world %s: %s: %s", name, e.getClass().getName(), e.getMessage())); |
| return null; |
| } |
| } catch(Exception e) { |
| e.printStackTrace(); |
| if(e instanceof InvocationTargetException) { |
| Throwable cause = ((InvocationTargetException)e).getCause(); |
| if(cause != null && cause instanceof Exception) e = (Exception)cause; |
| } |
| sender.sendMessage(e.getMessage()); |
| return null; |
| } |
| sender.sendMessage(String.format("World %s not found", name)); |
| return null; |
| } |
| |
| // Cauldron only |
| private static void load_all_worlds(CommandSender sender) { |
| if(forge_world_manager_load_world_method == null) try { |
| forge_world_manager_load_world_method = forge_world_manager_class.getDeclaredMethod("initDimension", int.class); |
| } catch(NoSuchMethodException e) { |
| e.printStackTrace(); |
| sender.sendMessage(String.format("Failed to load worlds: %s: %s", e.getClass().getName(), e.getMessage())); |
| return; |
| } |
| for(Map.Entry<Integer, Class<?>> entry : world_providers.entrySet()) try { |
| Object provider = entry.getValue().newInstance(); |
| String name = (String)mc_world_provider_get_name_method.invoke(provider); |
| boolean is_loaded = false; |
| for(Object mc_world : forge_loaded_worlds.values()) { |
| String loaded_name = (String)mc_world_provider_get_name_method.invoke(mc_world_provider_field.get(mc_world)); |
| if(name.equals((String)mc_world_provider_get_name_method.invoke(mc_world_provider_field.get(mc_world)))) { |
| is_loaded = true; |
| break; |
| } |
| } |
| if(is_loaded) continue; |
| Integer world_id = entry.getKey(); |
| sender.sendMessage(String.format("Loading world %s (%d)...", name, world_id)); |
| try { |
| forge_world_manager_load_world_method.invoke(null, world_id); |
| } catch(Exception e) { |
| e.printStackTrace(); |
| if(e instanceof InvocationTargetException) { |
| Throwable cause = ((InvocationTargetException)e).getCause(); |
| if(cause != null && cause instanceof Exception) e = (Exception)cause; |
| } |
| sender.sendMessage(String.format("Failed to load world %s: %s: %s", name, e.getClass().getName(), e.getMessage())); |
| } |
| } catch(Exception e) { |
| e.printStackTrace(); |
| if(e instanceof InvocationTargetException) { |
| Throwable cause = ((InvocationTargetException)e).getCause(); |
| if(cause != null && cause instanceof Exception) e = (Exception)cause; |
| } |
| sender.sendMessage(e.getMessage()); |
| } |
| } |
| |
| private static Boolean parse_off_on_value(String s) { |
| if(s.equalsIgnoreCase("off")) return Boolean.valueOf(false); |
| if(s.equalsIgnoreCase("on")) return Boolean.valueOf(true); |
| return null; |
| } |
| |
| private static boolean is_valid_world_name(String name) { |
| int i = name.length(); |
| if(i < 1) return false; |
| do { |
| switch(name.charAt(--i)) { |
| case 0x4: |
| case '\b': |
| case ' ': |
| case '\n': |
| case '': |
| case '': |
| case '\r': |
| case ' ': |
| case 0x1b: |
| case '"': |
| case '#': |
| case '\'': |
| case '*': |
| case '/': |
| case ':': |
| case '\\': |
| case 0x7f: |
| return false; |
| } |
| } while(i > 0); |
| return true; |
| } |
| |
| private static boolean is_symbolic_link(File file) throws IOException { |
| String[] args = new String[] { "[", "-h", file.toString(), "]" }; |
| Process p; |
| try { |
| p = Runtime.getRuntime().exec(args); |
| } catch(IOException e) { |
| args[0] = "/usr/bin/["; |
| try { |
| p = Runtime.getRuntime().exec(args); |
| } catch(IOException ee) { |
| throw e; |
| } |
| } |
| try { |
| p.waitFor(); |
| } catch(InterruptedException e) { |
| e.printStackTrace(); |
| } |
| try { |
| return p.exitValue() == 0; |
| } catch(IllegalThreadStateException e) { |
| e.printStackTrace(); |
| return false; |
| } |
| } |
| |
| private static final String LOAD_USAGE = "Usage: world load { -a | <name> }"; |
| private static final String UNLOAD_USAGE = "Usage: world unload [-n] {<name>|<uuid>} [...]"; |
| private static final String CREATE_USAGE = "Usage: world create [-t <type>] [-s <seed-number>] [-S {on|off}] <name>"; |
| |
| @Override |
| public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { |
| //"Usage:\n snapshot take [mc-]<name>\n snapshot drop mc-<name>\n snapshot list" |
| if(args.length < 1) return false; |
| if(args[0].equals("list")) { |
| if(!sender.hasPermission("rivoreo.worldmgr.list")) { |
| sender.sendMessage("Permission denied"); |
| return true; |
| } |
| list_loaded_worlds(sender); |
| list_unloaded_worlds(sender); |
| } else if(args[0].equals("load")) { |
| if(!sender.hasPermission("rivoreo.worldmgr.load_unload")) { |
| sender.sendMessage("Permission denied"); |
| return true; |
| } |
| String world_name; |
| if(args.length > 1 && args[1].charAt(0) == '-') switch(args[1].charAt(1)) { |
| case '-': |
| if(args[1].length() > 2 || args.length != 3) { |
| sender.sendMessage(LOAD_USAGE); |
| return true; |
| } |
| world_name = args[2]; |
| break; |
| case 'a': |
| if(is_minecraftforge_available()) { |
| load_all_worlds(sender); |
| } else { |
| sender.sendMessage("Operation not permitted"); |
| } |
| return true; |
| default: |
| sender.sendMessage(LOAD_USAGE); |
| return true; |
| } else if(args.length != 2) { |
| sender.sendMessage(LOAD_USAGE); |
| return true; |
| } else { |
| world_name = args[1]; |
| } |
| if(is_minecraftforge_available()) { |
| load_world(sender, world_name); |
| } else { |
| sender.sendMessage("Operation not permitted"); |
| } |
| } else if(args[0].equals("unload")) { |
| if(!sender.hasPermission("rivoreo.worldmgr.load_unload")) { |
| sender.sendMessage("Permission denied"); |
| return true; |
| } |
| ArrayList<String> list = new ArrayList<String>(1); |
| boolean no_sync = false; |
| boolean end_of_options = false; |
| for(int i = 1; i < args.length; i++) { |
| if(!end_of_options && args[i].charAt(0) == '-') switch(args[i].charAt(1)) { |
| case '-': |
| if(args[i].length() > 2 || args.length < 3) { |
| sender.sendMessage(LOAD_USAGE); |
| return true; |
| } |
| end_of_options = true; |
| break; |
| case 'n': |
| no_sync = true; |
| break; |
| default: |
| sender.sendMessage(UNLOAD_USAGE); |
| return true; |
| } else list.add(args[i]); |
| } |
| if(list.isEmpty()) { |
| sender.sendMessage(UNLOAD_USAGE); |
| return true; |
| } |
| for(String name : list) { |
| World world = get_world_by_name_or_uuid(name); |
| if(world == null) { |
| sender.sendMessage(String.format("World %s not found", name)); |
| } else if(!server.unloadWorld(world, !no_sync)) { |
| sender.sendMessage("Failed to unload world " + name); |
| } |
| } |
| } else if(args[0].equals("save") || args[0].equals("sync")) { |
| if(!sender.hasPermission("rivoreo.worldmgr.save")) { |
| sender.sendMessage("Permission denied"); |
| return true; |
| } |
| ArrayList<String> list = new ArrayList<String>(1); |
| boolean no_sync = false; |
| boolean end_of_options = false; |
| for(int i = 1; i < args.length; i++) { |
| if(!end_of_options && args[i].charAt(0) == '-') switch(args[i].charAt(1)) { |
| case '-': |
| if(args[i].length() > 2) { |
| sender.sendMessage(String.format("Invalid option '%s'", args[i])); |
| return true; |
| } |
| end_of_options = true; |
| break; |
| case 'a': |
| for(World world : server.getWorlds()) { |
| //sender.sendMessage(String.format("Synchronizing world %s (%s)...", world.getName(), world.getUID().toString())); |
| world.save(); |
| } |
| return true; |
| default: |
| sender.sendMessage(String.format("Invalid option '-%c'", args[i].charAt(1))); |
| return true; |
| } else list.add(args[i]); |
| } |
| if(list.isEmpty()) { |
| sender.sendMessage(String.format("Usage: world %s { -a | {<name>|<uuid>} [...] }", args[0])); |
| return true; |
| } |
| for(String name : list) { |
| World world = get_world_by_name_or_uuid(name); |
| if(world == null) { |
| sender.sendMessage(String.format("World %s not found", name)); |
| } else { |
| world.save(); |
| } |
| } |
| } else if(args[0].equals("switch")) { |
| if(!sender.hasPermission("rivoreo.worldmgr.switch")) { |
| sender.sendMessage("Permission denied"); |
| return true; |
| } |
| if(!(sender instanceof Player)) { |
| sender.sendMessage("switch subcommand may only be used by players"); |
| return true; |
| } |
| if(args.length != 2 && args.length != 5) { |
| sender.sendMessage("Usage: world switch {<name>|<uuid>} [<x> <y> <z>]"); |
| return true; |
| } |
| if(args.length == 5 && !sender.hasPermission("rivoreo.worldmgr.switch_coordinate")) { |
| sender.sendMessage("You don't have permission to specify a coordinate"); |
| return true; |
| } |
| World world = get_world_by_name_or_uuid(args[1]); |
| if(world == null) { |
| if(is_minecraftforge_available()) { |
| world = load_world(sender, args[1]); |
| if(world == null) return true; |
| } else { |
| sender.sendMessage(String.format("World %s not loaded", args[1])); |
| return true; |
| } |
| } |
| Player player = ((Player)sender); |
| if(world == player.getWorld()) { |
| sender.sendMessage("You are already in world " + args[1]); |
| return true; |
| } |
| Location location; |
| if(args.length == 2) { |
| location = world.getSpawnLocation(); |
| } else try { |
| location = new Location(world, Integer.parseInt(args[2]), Integer.parseInt(args[3]), Integer.parseInt(args[4])); |
| } catch(NumberFormatException e) { |
| sender.sendMessage("Invalid coordinate specification"); |
| return true; |
| } |
| player.teleport(location, PlayerTeleportEvent.TeleportCause.COMMAND); |
| } else if(args[0].equals("create")) { |
| if(!sender.hasPermission("rivoreo.worldmgr.create")) { |
| sender.sendMessage("Permission denied"); |
| return true; |
| } |
| String name = null; |
| WorldType type = null; |
| Long seed = null; |
| Boolean should_generate_structures = null; |
| boolean end_of_options = false; |
| for(int i = 1; i < args.length; i++) { |
| if(!end_of_options && args[i].charAt(0) == '-') switch(args[i].charAt(1)) { |
| case '-': |
| if(args[i].length() > 2) { |
| if(args[i].equals("--type")) { |
| if(args.length <= ++i) { |
| sender.sendMessage("Option '--type' requires an argument"); |
| return true; |
| } |
| try { |
| type = WorldType.valueOf(args[i].toUpperCase()); |
| } catch(IllegalArgumentException e) { |
| sender.sendMessage(String.format("Invalid world type '%s'", args[i])); |
| return true; |
| } |
| } else if(args[i].equals("--seed")) { |
| if(args.length <= ++i) { |
| sender.sendMessage("Option '--seed' requires an argument"); |
| return true; |
| } |
| try { |
| seed = Long.decode(args[i]); |
| } catch(NumberFormatException e) { |
| sender.sendMessage("Seed must be a number"); |
| return true; |
| } |
| } else if(args[i].equals("--generate-structures")) { |
| if(args.length <= ++i) { |
| sender.sendMessage("Option '--generate-structures' requires an argument"); |
| return true; |
| } |
| should_generate_structures = parse_off_on_value(args[i]); |
| if(should_generate_structures == null) { |
| sender.sendMessage("Invalid argument to '-S', must be 'off' or 'on'"); |
| return true; |
| } |
| } |
| } else end_of_options = true; |
| break; |
| case 't': |
| if(args.length <= ++i) { |
| sender.sendMessage("Option '-t' requires an argument"); |
| return true; |
| } |
| try { |
| type = WorldType.valueOf(args[i].toUpperCase()); |
| } catch(IllegalArgumentException e) { |
| sender.sendMessage(String.format("Invalid world type '%s'", args[i])); |
| return true; |
| } |
| break; |
| case 's': |
| if(args.length <= ++i) { |
| sender.sendMessage("Option '-s' requires an argument"); |
| return true; |
| } |
| try { |
| seed = Long.decode(args[i]); |
| } catch(NumberFormatException e) { |
| sender.sendMessage("Seed must be a number"); |
| return true; |
| } |
| break; |
| case 'S': |
| if(args.length <= ++i) { |
| sender.sendMessage("Option '-S' requires an argument"); |
| return true; |
| } |
| should_generate_structures = parse_off_on_value(args[i]); |
| if(should_generate_structures == null) { |
| sender.sendMessage("Invalid argument to '-S', must be 'off' or 'on'"); |
| return true; |
| } |
| break; |
| default: |
| sender.sendMessage(String.format("Invalid option '-%c'", args[i].charAt(1))); |
| return true; |
| } else if(name == null) { |
| name = args[i]; |
| if(!is_valid_world_name(name)) { |
| sender.sendMessage("Invalid world name"); |
| return true; |
| } |
| } else { |
| sender.sendMessage(CREATE_USAGE); |
| return true; |
| } |
| } |
| if(name == null) { |
| sender.sendMessage(CREATE_USAGE); |
| return true; |
| } |
| if(get_world_by_name_or_uuid(name) != null) { |
| sender.sendMessage(String.format("World %s is already loaded", name)); |
| return true; |
| } |
| try { |
| File save_dir = new File(server.getWorldContainer().getCanonicalFile(), name); |
| if(is_symbolic_link(save_dir)) { |
| sender.sendMessage(String.format("Failed to create world %s: target save directory '%s' is a symbolic link", name, save_dir)); |
| return true; |
| } |
| } catch(IOException e) { |
| e.printStackTrace(); |
| sender.sendMessage(String.format("Failed to create world %s: %s: %s", name, e.getClass().getName(), e.getMessage())); |
| return true; |
| } |
| WorldCreator creator = new WorldCreator(name); |
| if(type != null) creator.type(type); |
| if(seed != null) creator.seed(seed.longValue()); |
| if(should_generate_structures != null) creator.generateStructures(should_generate_structures.booleanValue()); |
| if(is_minecraftforge_available()) try { |
| if(forge_world_id_map == null) { |
| Field world_id_map_field = forge_world_manager_class.getDeclaredField("dimensionMap"); |
| if(world_id_map_field.getType() != BitSet.class) throw new NoSuchFieldException("type mismatch"); |
| world_id_map_field.setAccessible(true); |
| forge_world_id_map = (BitSet)world_id_map_field.get(null); |
| } |
| Integer world_id = Integer.valueOf(forge_world_id_map.nextClearBit(0)); |
| if(customworldprovider_class == null) { |
| customworldprovider_class = Class.forName("rivoreo.minecraft.worldmgr.CustomWorldProvider"); |
| } |
| if(forge_register_world_provider_type_method == null) { |
| forge_register_world_provider_type_method = forge_world_manager_class.getDeclaredMethod("registerProviderType", int.class, Class.class, boolean.class); |
| } |
| forge_register_world_provider_type_method.invoke(null, world_id, customworldprovider_class, Boolean.valueOf(true)); |
| if(bukkit_world_environment_construtor == null) { |
| bukkit_world_environment_construtor = World.Environment.class.getDeclaredConstructor(String.class, int.class, int.class); |
| bukkit_world_environment_construtor.setAccessible(true); |
| } |
| if(constructor_accessor_field == null) { |
| constructor_accessor_field = Constructor.class.getDeclaredField("constructorAccessor"); |
| constructor_accessor_field.setAccessible(true); |
| } |
| Object constructor_accessor = constructor_accessor_field.get(bukkit_world_environment_construtor); |
| if(constructor_accessor == null) { |
| if(acquire_constructor_accessor_method == null) { |
| acquire_constructor_accessor_method = Constructor.class.getDeclaredMethod("acquireConstructorAccessor"); |
| acquire_constructor_accessor_method.setAccessible(true); |
| } |
| constructor_accessor = acquire_constructor_accessor_method.invoke(bukkit_world_environment_construtor); |
| } |
| Object[] constructor_args = new Object[] { |
| name, Integer.valueOf(bukkit_world_environment_ordinal++), world_id |
| }; |
| if(constructor_accessor_new_instance_method == null) { |
| constructor_accessor_new_instance_method = constructor_accessor.getClass().getDeclaredMethod("newInstance", constructor_args.getClass()); |
| constructor_accessor_new_instance_method.setAccessible(true); |
| } |
| World.Environment environment = (World.Environment)constructor_accessor_new_instance_method.invoke(constructor_accessor, new Object[] { constructor_args }); |
| creator.environment(environment); |
| } catch(Exception e) { |
| e.printStackTrace(); |
| } |
| World world; |
| try { |
| world = creator.createWorld(); |
| } catch(Exception e) { |
| e.printStackTrace(); |
| sender.sendMessage(String.format("Failed to create world %s: %s: %s", name, e.getClass().getName(), e.getMessage())); |
| return true; |
| } |
| if(customworldprovider_class != null) try { |
| Object provider = get_world_provider(world); |
| if(customworldprovider_class.isInstance(provider)) { |
| if(customworldprovider_set_world_name_method == null) { |
| customworldprovider_set_world_name_method = customworldprovider_class.getDeclaredMethod("set_world_name", String.class); |
| } |
| customworldprovider_set_world_name_method.invoke(provider, name); |
| if(craftbukkit_world_environment_field == null) { |
| craftbukkit_world_environment_field = world.getClass().getDeclaredField("environment"); |
| craftbukkit_world_environment_field.setAccessible(true); |
| } |
| /* Need to set environment back to |
| * NORMAL to prevent crashing client |
| * by sending an unknown world |
| * provider type ID. |
| * See Cauldron source file |
| * patches/net/minecraft/server/management/ServerConfigurationManager.java.patch |
| * comment |
| * 'Cauldron start - send DimensionRegisterMessage to client before attempting to login to a Bukkit dimension' |
| * for details. */ |
| craftbukkit_world_environment_field.set(world, World.Environment.NORMAL); |
| } |
| } catch(Exception e) { |
| e.printStackTrace(); |
| } |
| sender.sendMessage(String.format("World %s (%s) loaded", name, world.getUID().toString())); |
| } else { |
| sender.sendMessage("Invalid subcommand"); |
| } |
| return true; |
| } |
| |
| @Override |
| public void onLoad() { |
| log = getLogger(); |
| server = getServer(); |
| } |
| |
| @Override |
| public void onEnable() { |
| getCommand("world").setExecutor(this); |
| } |
| } |