diff --git a/src/com/onarandombox/MultiVerseCore/MVPlayerSession.java b/src/com/onarandombox/MultiVerseCore/MVPlayerSession.java index d6cd73f1..d440a843 100644 --- a/src/com/onarandombox/MultiVerseCore/MVPlayerSession.java +++ b/src/com/onarandombox/MultiVerseCore/MVPlayerSession.java @@ -1,11 +1,53 @@ package com.onarandombox.MultiVerseCore; +import java.util.Date; + +import org.bukkit.Location; import org.bukkit.entity.Player; +import org.bukkit.util.config.Configuration; public class MVPlayerSession { - public MVPlayerSession(Player player, MultiVerseCore multiVerseCore) { - // TODO Auto-generated constructor stub + private Player player; // Player holder, may be unnecessary. + public Location loc; // Contain the Players Location so on player move we can compare this and check if they've moved a block. + + public String portal = null; // Allow a player to target a portal to prevent them typing its name every command. + + public Location coord1 = null; // Coordinate 1 (Left Click) + public Location coord2 = null; // Coordinate 2 (Right Click) + + private Long teleportLast = 0L; // Timestamp for the Players last Portal Teleportation. + private Long messageLast = 0L; // Timestamp for the Players last Alert Message. + + private Configuration config; // Configuration file to find out Cooldown Timers. + + public MVPlayerSession(Player player, Configuration config, MultiVerseCore multiVerseCore) { + this.player = player; + this.loc = player.getLocation(); + this.config = config; + } + + /** + * Teleport the Player to the destination as long as enough time has passed since the last teleport. + * @param location + */ + public void teleport(Location location){ + Long time = (new Date()).getTime(); + if ((time - this.teleportLast) > config.getInt("portalcooldown", 5000)){ + this.player.teleportTo(location); + this.teleportLast = time; + } + } + + /** + * Send a Message to the Player as long as enough time has passed since the last message. + * @param msg + */ + public void message(String msg){ + Long time = (new Date()).getTime(); + if((time - this.messageLast) > config.getInt("messagecooldown", 2000)){ + this.player.sendMessage(msg); + this.messageLast = time; + } } - } diff --git a/src/com/onarandombox/MultiVerseCore/MVWorldListener.java b/src/com/onarandombox/MultiVerseCore/MVWorldListener.java new file mode 100644 index 00000000..60a0d236 --- /dev/null +++ b/src/com/onarandombox/MultiVerseCore/MVWorldListener.java @@ -0,0 +1,18 @@ +package com.onarandombox.MultiVerseCore; + +import org.bukkit.World; +import org.bukkit.event.Listener; +import org.bukkit.event.world.WorldEvent; + +public class MVWorldListener implements Listener { + + MultiVerseCore plugin; + + public MVWorldListener(MultiVerseCore plugin){ + this.plugin = plugin; + } + + public void onWorldLoad(WorldEvent event){ + World world = event.getWorld(); + } +} diff --git a/src/com/onarandombox/MultiVerseCore/MultiVerseCore.java b/src/com/onarandombox/MultiVerseCore/MultiVerseCore.java index c3c9c42b..4f818ccf 100644 --- a/src/com/onarandombox/MultiVerseCore/MultiVerseCore.java +++ b/src/com/onarandombox/MultiVerseCore/MultiVerseCore.java @@ -2,12 +2,16 @@ package com.onarandombox.MultiVerseCore; import java.io.File; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.logging.Logger; import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.World.Environment; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; +import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginDescriptionFile; @@ -30,11 +34,11 @@ public class MultiVerseCore extends JavaPlugin { private Map commands = new HashMap(); // Variable to state whether we are displaying Debug Messages or not. - public boolean debug = true; + public static boolean debug = true; // Useless stuff to keep us going. - private final Logger log = Logger.getLogger("Minecraft"); - public final String logPrefix = "[MultiVerse-Core] "; + public static final Logger log = Logger.getLogger("Minecraft"); + public static final String logPrefix = "[MultiVerse-Core] "; public static Plugin instance; public static Server server; public static PluginDescriptionFile description; @@ -43,19 +47,21 @@ public class MultiVerseCore extends JavaPlugin { public static PermissionHandler Permissions = null; // Configurations - public static Configuration configMV; - public static Configuration configWorlds; + public static Configuration configMV = null; + public static Configuration configWorlds = null; // Setup the block/player/entity listener. private MVPlayerListener playerListener = new MVPlayerListener(this);; private MVBlockListener blockListener = new MVBlockListener(this); private MVEntityListener entityListener = new MVEntityListener(this); private MVPluginListener pluginListener = new MVPluginListener(this); + private MVWorldListener worldListener = new MVWorldListener(this); // HashMap to contain all the Worlds which this Plugin will manage. - public HashMap mvWorlds = new HashMap(); + public static HashMap worlds = new HashMap(); + // HashMap to contain information relating to the Players. - public HashMap playerSessions = new HashMap(); + public static HashMap playerSessions = new HashMap(); /** * Constructor... Perform the Necessary tasks here. @@ -68,70 +74,63 @@ public class MultiVerseCore extends JavaPlugin { * What happens when the plugin gets around to be enabled... */ public void onEnable() { + // Create the Plugin Data folder. this.getDataFolder().mkdir(); - /** - * Output a little snippet to state that the plugin is now enabled. - */ + + // Output a little snippet to show it's enabled. log.info(logPrefix + "- Version " + this.getDescription().getVersion() + " Enabled"); - /** - * Quick check for the Permissions Plugin, if we don't find it here - * we'll have to check Plugin onEnable Events. - */ + + // Quick check for the Permissions Plugin, if we don't find it here then we'll check the plugin onEnable event. if(getServer().getPluginManager().getPlugin("Permissions")==null){ - log.info(logPrefix + "Commands have been DISABLED until Permissions has been found."); + log.info(logPrefix + "- Commands have been DISABLED until Permissions has been found."); } else { Permissions = com.nijikokun.bukkit.Permissions.Permissions.Security; } - /** - * If the Configuration Files don't exist then create them. - */ - if(!(new File(this.getDataFolder(), "MultiVerse.yml").exists())){ - new defaultConfiguration().setupMultiVerseConfig(new File(this.getDataFolder(), "MultiVerse.yml")); - } - if(!(new File(this.getDataFolder(), "Worlds.yml").exists())){ - new defaultConfiguration().setupMultiVerseConfig(new File(this.getDataFolder(), "Worlds.yml")); - } - /** - * Grab the Configuration Files & Load them. - */ - configMV = new Configuration(new File(this.getDataFolder(), "MultiVerse.yml")); - configMV.load(); - configWorlds = new Configuration(new File(this.getDataFolder(), "Worlds.yml")); - configWorlds.load(); - /** - * Setup all the events which we will be listening. - */ - /* + + // Call the defaultConfiguration class to create the config files if they don't already exist. + new defaultConfiguration(this.getDataFolder(), "config.yml"); + new defaultConfiguration(this.getDataFolder(), "worlds.yml"); + + // Now grab the Configuration Files. + configMV = new Configuration(new File(this.getDataFolder(), "config.yml")); + configWorlds = new Configuration(new File(this.getDataFolder(), "worlds.yml")); + + // Now attempt to Load the configurations. + try{ configMV.load(); } catch (Exception e){ log.info(MultiVerseCore.logPrefix + "- Failed to load config.yml"); } + try{ configWorlds.load(); } catch (Exception e){ log.info(MultiVerseCore.logPrefix + "- Failed to load worlds.yml"); } + + // Setup all the Events the plugin needs to Monitor. PluginManager pm = getServer().getPluginManager(); - pm.registerEvent(Event.Type.PLAYER_MOVE, playerListener, Priority.Low,this); // Low so it acts above any other. - pm.registerEvent(Event.Type.PLAYER_CHAT, playerListener, Priority.Normal, this); - pm.registerEvent(Event.Type.PLAYER_RESPAWN, playerListener, Priority.Normal, this); - pm.registerEvent(Event.Type.PLAYER_JOIN, playerListener,Priority.Normal, this); - pm.registerEvent(Event.Type.PLAYER_QUIT, playerListener,Priority.Normal, this); + pm.registerEvent(Event.Type.PLAYER_MOVE, playerListener, Priority.Low, this); // Low so it acts above any other. + pm.registerEvent(Event.Type.PLAYER_CHAT, playerListener, Priority.High, this); // To Add World Prefixing to Chat. + pm.registerEvent(Event.Type.PLAYER_RESPAWN, playerListener, Priority.Normal, this); // Respawn Players at the right point. + + pm.registerEvent(Event.Type.PLAYER_QUIT, playerListener,Priority.Normal, this); // To remove Player Sessions + + // These 3 events should only be required in the Portals module. + //pm.registerEvent(Event.Type.BLOCK_DAMAGED, blockListener,Priority.Normal, this); // For Set Coord 1 & Info Wand etc... + //pm.registerEvent(Event.Type.BLOCK_RIGHTCLICKED, blockListener,Priority.Normal, this); // For Set Coord 2 + //pm.registerEvent(Event.Type.BLOCK_FLOW, blockListener, Priority.High,this); // To create Water/Lava Portals - pm.registerEvent(Event.Type.BLOCK_RIGHTCLICKED, blockListener,Priority.Normal, this); - pm.registerEvent(Event.Type.BLOCK_DAMAGED, blockListener,Priority.Normal, this); - pm.registerEvent(Event.Type.BLOCK_FLOW, blockListener, Priority.High,this); - pm.registerEvent(Event.Type.BLOCK_PLACED, blockListener, Priority.High,this); + pm.registerEvent(Event.Type.BLOCK_BREAK, blockListener, Priority.Normal, this); // To prevent Blocks being destroyed. + pm.registerEvent(Event.Type.BLOCK_PLACED, blockListener, Priority.High, this); // To prevent Blocks being placed. - pm.registerEvent(Event.Type.ENTITY_DAMAGED, entityListener, Priority.High,this); - */ - /** - * In case of a /reload we need to make sure every player online gets - * setup with a player session. - */ - Player[] p = this.getServer().getOnlinePlayers(); - for (int i = 0; i < p.length; i++) { - debugMsg("Player Sessions - Player " + i + " Out of " + p.length + " Name - " + p[i].getName(), null); - this.playerSessions.put(p[i].getName(), new MVPlayerSession(p[i],this)); - } - /** - * Load up the Worlds & their Settings. - */ + pm.registerEvent(Event.Type.ENTITY_DAMAGED, entityListener, Priority.High, this); // To Allow/Disallow PVP. + + pm.registerEvent(Event.Type.WORLD_LOADED, worldListener, Priority.Highest, this); // Setup the Worlds config when a World is created. + + pm.registerEvent(Event.Type.PLUGIN_ENABLE, pluginListener, Priority.Normal, this); // Monitor for Permissions Plugin etc. + + // Call the Function to load all the Worlds and setup the HashMap loadWorlds(); + + // Call the Function to assign all the Commands to their Class. setupCommands(); } + /** + * + */ private void setupCommands() { commands.put("mvcreate", new MVCreate(this)); commands.put("mvimport", new MVImport(this)); @@ -148,18 +147,91 @@ public class MultiVerseCore extends JavaPlugin { * Load the Worlds & Settings from the configuration file. */ private void loadWorlds() { - // TODO Auto-generated method stub + // Basic Counter to count how many Worlds we are loading. + int count = 0; - } + // Grab all the Worlds that already exist. + List worlds = getServer().getWorlds(); + + // You never know these days... bloody NPE's. + if(worlds != null && worlds.size()>0){ + for (World world : worlds){ + log.info(logPrefix + "Loading existing World - '" + world.getName() + "' - " + world.getEnvironment().toString()); // Output to the Log that wea re loading a world, specify the name and environment type. + + MultiVerseCore.worlds.put(world.getName(), new MVWorld(world, MultiVerseCore.configWorlds, this)); // Place the World into the HashMap. + count++; // Increment the World Count. + } + } + + log.info(logPrefix + count + " - existing World(s) found."); + + List worldKeys = MultiVerseCore.configWorlds.getKeys("worlds"); // Grab all the Worlds from the Config. + count = 0; + if(worldKeys != null){ + for (String worldKey : worldKeys){ + // If this World already exists within the HashMap then we don't need to process it. + if(MultiVerseCore.worlds.containsKey(worldKey)){ + continue; + } + + String wEnvironment = MultiVerseCore.configWorlds.getString("worlds." + worldKey + ".environment", "NORMAL"); // Grab the Environment as a String. + + Boolean monsters = MultiVerseCore.configWorlds.getBoolean("worlds." + worldKey + ".monsters", true); // Grab whether we want to spawn Monsters. + Boolean animals = MultiVerseCore.configWorlds.getBoolean("worlds." + worldKey + ".animals", true); // Grab whether we want to spawn Animals. + + Environment env; + if(wEnvironment.equalsIgnoreCase("NETHER")) // Check if the selected Environment is NETHER, otherwise we just default to NORMAL. + env = Environment.NETHER; + else + env = Environment.NORMAL; + + log.info(logPrefix + "Loading World & Settings - '" + worldKey + "' - " + wEnvironment); // Output to the Log that wea re loading a world, specify the name and environment type. + + World world = getServer().createWorld(worldKey, env); + + // Beta 1.3 = + // D = Monsters + // E = Animals + ((CraftWorld) world).getHandle().D = monsters; + ((CraftWorld) world).getHandle().E = animals; + //((CraftWorld) world).getHandle().q.a(i, j, k); + //Spawn Crap + + // The following will be used once they accept the pull request. + //world.setMonsterSpawn = monsters; + //world.setAnimalSpawn = animals; + + //MultiVerseCore.worlds.put(worldKey, new MVWorld(world, MultiVerseCore.configWorlds, this)); // Place the World into the HashMap. + + count++; // Increment the World Count. + } + } + log.info(logPrefix + count + " - World(s) loaded."); + + } + /** * What happens when the plugin gets disabled... */ public void onDisable() { - log.info(logPrefix + "- Disabled"); } + /** + * Grab the players session if one exists, otherwise create a session then return it. + * @param player + * @return + */ + public MVPlayerSession getPlayerSession(Player player){ + if(playerSessions.containsKey(player.getName())){ + return playerSessions.get(player.getName()); + } else { + playerSessions.put(player.getName(), new MVPlayerSession(player, MultiVerseCore.configMV, this)); + return playerSessions.get(player.getName()); + } + } + /** * onCommand */ diff --git a/src/com/onarandombox/MultiVerseCore/configuration/defaultConfiguration.java b/src/com/onarandombox/MultiVerseCore/configuration/defaultConfiguration.java index 88f5eab7..2016a0ce 100644 --- a/src/com/onarandombox/MultiVerseCore/configuration/defaultConfiguration.java +++ b/src/com/onarandombox/MultiVerseCore/configuration/defaultConfiguration.java @@ -1,98 +1,51 @@ package com.onarandombox.MultiVerseCore.configuration; import java.io.File; -import java.io.BufferedWriter; -import java.io.FileWriter; -import java.io.IOException; +import java.io.FileOutputStream; +import java.io.InputStream; +import com.onarandombox.MultiVerseCore.MultiVerseCore; + +/** + * https://github.com/Nijikokun/iConomy3/blob/master/com/nijiko/coelho/iConomy/iConomy.java + * @author Nijikokun & Coelho + */ public class defaultConfiguration { - public void setupMultiVerseConfig(File config) { - try { - config.createNewFile(); - FileWriter fstream = new FileWriter(config); - BufferedWriter out = new BufferedWriter(fstream); + public defaultConfiguration(File folder, String name){ - // TODO: Format Layout, remove unnecessary crap etc... + File actual = new File(folder, name); + if (!actual.exists()) { + + InputStream input = this.getClass().getResourceAsStream("/default/" + name); + if (input != null) { + FileOutputStream output = null; - out.write("#Prefix Chat with World Name.\n"); - out.write("prefix: true\n"); - out.write("\n"); - out.write("#Choose whether or not Players have to pay to use the portals.\n"); - out.write("iconomy: false\n"); - out.write("\n"); - out.write("#True/False - Whether MultiVerse should handle all respawns on every World including the Default.\n"); - out.write("#Disable this if you have a form of Respawn Teleportation plugin.\n"); - out.write("globalrespawn: false\n"); - out.write("#True/False - Whether MultiVerse should handle all respawns on the MultiVerse Worlds.\n"); - out.write("#If 'globalrespawn:true' then this will have no effect.\n"); - out.write("alternaterespawn: true\n"); - out.write("\n"); - out.write("#How long a player has to wait before using another portal.\n"); - out.write("#In Milliseconds - Default is '5000' which is 5 Seconds.\n"); - out.write("tpcooldown: 5000\n"); - out.write("#How long to leave in between sending an alert to the player.\n"); - out.write("#In Milliseconds - Default is '5000' which is 5 Seconds.\n"); - out.write("alertcooldown: 5000\n"); - out.write("#How long the player has to wait before they can get more information from a portal.\n"); - out.write("#In Milliseconds - Default is '5000' which is 5 Seconds.\n"); - out.write("infocooldown: 5000\n"); - out.write("\n"); - out.write("#The Item a player has to use to get information from a portal.\n"); - out.write("#Default is 49 - Obsidian\n"); - out.write("infowand: 49\n"); - out.write("\n"); - out.write("#The Item a player has to use to set the coordinates to create a portal\n"); - out.write("#Default is 270 - Wood Pickaxe\n"); - out.write("setwand: 270\n"); - out.write("\n"); - out.write("#SinglePlayer Styled Nether - You still have to \"/mvimport\" the World for Nether.\n"); - out.write("#The settings below only affect the SPLike portals.\n"); - out.write("#SPLike - True/False - Portals without a Destination or Sign will act like a SinglePlayer portal.\n"); - out.write("#AutoBuild - True/False - AutoBuild a destination portal if none are found nearby?\n"); - out.write("#Nether - Folder/WorldName of the Nether world.\n"); - out.write("#Default - Folder/WorldName of the default world setup in server.properties.\n"); - out.write("#RespawnToDefault - True/False - When a player dies do we respawn them back to the default world.\n"); - out.write("splike: false\n"); - out.write("autobuild: false\n"); - out.write("nether: nether\n"); - out.write("default: world\n"); - out.write("respawntodefault: false\n"); - - - out.close(); - fstream.close(); - } catch (IOException ex) { - System.out.print("Error creating MultiVerse.yml"); - } - } - - public void setupWorldConfig(File config){ - if (!config.exists()) { - try { - config.createNewFile(); - FileWriter fstream = new FileWriter(config); - BufferedWriter out = new BufferedWriter(fstream); + try { + output = new FileOutputStream(actual); + byte[] buf = new byte[8192]; + int length = 0; + + while ((length = input.read(buf)) > 0) { + output.write(buf, 0, length); + } + + System.out.println(MultiVerseCore.logPrefix + "Default setup file written: " + name); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (input != null) + input.close(); + } catch (Exception e) {} - // TODO: Implement an Example. - - // out.write("\n"); - // out.write("###############################\n"); - // out.write("########### Example ###########\n"); - // out.write("###############################\n"); - // out.write("# worlds:\n"); - // out.write("# hellworld:\n"); - // out.write("# environment: NETHER\n"); - // out.write("# creative:\n"); - // out.write("# environment: NORMAL\n"); - // out.write("###############################\n"); - // out.write("\n"); - out.write("worlds:\n"); - - out.close(); - fstream.close(); - } catch (IOException ex) { - System.out.print("Error creating Worlds.yml"); + try { + if (output != null) + output.close(); + } catch (Exception e) { + + } + } } } } diff --git a/src/com/onarandombox/utils/blockSafety.java b/src/com/onarandombox/utils/blockSafety.java new file mode 100644 index 00000000..352402c5 --- /dev/null +++ b/src/com/onarandombox/utils/blockSafety.java @@ -0,0 +1,53 @@ +package com.onarandombox.utils; + +import org.bukkit.Material; +import org.bukkit.World; + +public class blockSafety { + /** + * This function checks whether the block at the given coordinates are above + * air or not. + * + * @param world + * @param x + * @param y + * @param z + * @return + */ + private boolean blockIsAboveAir(World world, double x, double y, double z) { + return (world.getBlockAt((int) Math.floor(x), (int) Math.floor(y - 1), + (int) Math.floor(z)).getType() == Material.AIR); + } + + /** + * This function checks whether the block at the coordinates given is safe + * or not by checking for Laval/Fire/Air etc. + * + * @param world + * @param x + * @param y + * @param z + * @return + */ + public boolean blockIsNotSafe(World world, double x, double y, double z) { + if ((world.getBlockAt((int) Math.floor(x), (int) Math.floor(y - 1), + (int) Math.floor(z)).getType() == Material.LAVA)) + return true; + if ((world.getBlockAt((int) Math.floor(x), (int) Math.floor(y - 1), + (int) Math.floor(z)).getType() == Material.STATIONARY_LAVA)) + return true; + if ((world.getBlockAt((int) Math.floor(x), (int) Math.floor(y - 1), + (int) Math.floor(z)).getType() == Material.FIRE)) + return true; + if (world.getBlockAt((int) Math.floor(x), (int) Math.floor(y), + (int) Math.floor(z)).getType() != Material.AIR + || world.getBlockAt((int) Math.floor(x), + (int) Math.floor(y + 1), (int) Math.floor(z)).getType() != Material.AIR) + return true; + if (blockIsAboveAir(world, x, y, z)) + return true; + + return false; + } + +} diff --git a/src/defaults/config.yml b/src/defaults/config.yml new file mode 100644 index 00000000..17a40fc1 --- /dev/null +++ b/src/defaults/config.yml @@ -0,0 +1,15 @@ +#True/False - Whether MultiVerse should handle all respawns on every World including the Default. +#Disable this if you have a form of Respawn Teleportation plugin. +globalrespawn: false + +#True/False - Whether MultiVerse should handle all respawns on the MultiVerse Worlds. +#If 'globalrespawn:true' then this will have no effect. +alternaterespawn: true + +#How long to leave in between sending a message to the player. +#In Milliseconds - Default is '5000' which is 5 Seconds. +messagecooldown: 5000 + +#Portal Cooldown, only affects MultiVerse portals. +#In Milliseconds - Default is '5000' which is 5 Seconds. +portalcooldown: 5000 \ No newline at end of file diff --git a/src/defaults/worlds.yml b/src/defaults/worlds.yml new file mode 100644 index 00000000..f2207c41 --- /dev/null +++ b/src/defaults/worlds.yml @@ -0,0 +1 @@ +worlds: \ No newline at end of file