diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a25a269 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target/ +*.jar \ No newline at end of file diff --git a/README.md b/README.md index 11ff927..a0c7c53 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,13 @@ DiscoSheep ========== -A plugin for [Bukkit](http://bukkit.org/), the Minecraft server API. This is a from-scratch remake of the fabulous [DiscoSheep plugin](http://forums.bukkit.org/threads/inactive-fun-discosheep-v0-3-uninvited-guesssts-permissions-and-source-code-522.7106/) which spawns a dance party of sheep at your whim. +A plugin for [Bukkit](http://bukkit.org/), the Minecraft server plugin API. This is a from-scratch remake of the fabulous [DiscoSheep plugin](http://forums.bukkit.org/threads/inactive-fun-discosheep-v0-3-uninvited-guesssts-permissions-and-source-code-522.7106/) which spawns a dance party of sheep at your whim. + +###A note on UUIDs### +DiscoSheep doesn't store anything after a party, and disco-party-on-join is handled by a permissions plugin. Thus, we don't need to worry about the migration to UUIDs. ###Versions### -Tested up to CraftBukkit build 2918 (RB for 1.6.4 R2.0); can be built with Java 6. +Tested up to CraftBukkit build #3092 (MC: 1.7.9); can be built with Java 7. ###[BukkitDev](http://dev.bukkit.org/bukkit-plugins/superdiscosheep/)### @@ -12,7 +15,7 @@ Tested up to CraftBukkit build 2918 (RB for 1.6.4 R2.0); can be built with Java See BukkitDev, or https://github.com/Gibstick/DiscoSheep/releases ###License### -Copyright (c) 2013 "Gibstick", "RangerMauve" +Copyright (c) 2013-2014 "Gibstick", "RangerMauve" Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/nb-configuration.xml b/nb-configuration.xml new file mode 100644 index 0000000..8de99a0 --- /dev/null +++ b/nb-configuration.xml @@ -0,0 +1,32 @@ + + + + + + mit + 132 + none + 4 + 4 + 4 + 80 + true + none + 4 + 4 + 4 + 80 + true + project + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..de20afd --- /dev/null +++ b/pom.xml @@ -0,0 +1,105 @@ + + + 4.0.0 + ca.gibstick + DiscoSheep + 1.1.2 + jar + + + bukkit-repo + http://repo.bukkit.org/content/groups/public/ + + + repo.oc.tc + http://repo.oc.tc/content/repositories/public/ + + + + + org.bukkit + bukkit + provided + 1.7.9-R0.2 + + + com.sk89q + command-framework-bukkit + 0.5-SNAPSHOT + + + + DiscoSheep + src/main/java + + + . + true + src/main/resources/ + + plugin.yml + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + + -Xlint:deprecation + + + + + org.apache.maven.plugins + maven-source-plugin + 2.3 + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.1 + + + org.apache.maven.plugins + maven-shade-plugin + 2.3 + + + package + + shade + + + DiscoSheep + true + + ${project.basedir} + + + com.sk89q:command-framework-bukkit + + + false + true + shaded + + + + + + + + UTF-8 + 1.7 + 1.7 + + DiscoSheep + \ No newline at end of file diff --git a/src/ca/gibstick/discosheep/DiscoParty.java b/src/ca/gibstick/discosheep/DiscoParty.java deleted file mode 100644 index 132e4a7..0000000 --- a/src/ca/gibstick/discosheep/DiscoParty.java +++ /dev/null @@ -1,527 +0,0 @@ -package ca.gibstick.discosheep; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.Random; -import org.bukkit.Color; -import org.bukkit.DyeColor; -import org.bukkit.Location; -import org.bukkit.Sound; -import org.bukkit.World; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Firework; -import org.bukkit.entity.Player; -import org.bukkit.entity.Sheep; -import org.bukkit.FireworkEffect; -import org.bukkit.FireworkEffect.Builder; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.block.BlockState; -import org.bukkit.entity.Entity; -import org.bukkit.event.HandlerList; -import org.bukkit.inventory.meta.FireworkMeta; -import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.util.Vector; - -public class DiscoParty { - - // Static properties - static int defaultDuration = 300; // ticks for entire party - static int defaultPeriod = 10; // ticks per state change - static int defaultRadius = 5; - static int defaultSheep = 10; - static float defaultSheepJump = 0.35f; - static int maxDuration = 2400; // 120 seconds - static int maxSheep = 100; - static int maxRadius = 100; - static int minPeriod = 5; // 0.25 seconds - static int maxPeriod = 40; // 2.0 seconds - private static HashMap defaultGuestNumbers = new HashMap(); - private static HashMap maxGuestNumbers = new HashMap(); - private static final DyeColor[] discoColours = { - DyeColor.RED, - DyeColor.ORANGE, - DyeColor.YELLOW, - DyeColor.GREEN, - DyeColor.BLUE, - DyeColor.LIGHT_BLUE, - DyeColor.PINK, - DyeColor.MAGENTA, - DyeColor.LIME, - DyeColor.CYAN, - DyeColor.PURPLE, - DyeColor.BLACK, - DyeColor.WHITE - }; - private static final float[] pentatonicNotes = { - 1.0f, - 1.125f, - 1.25f, - 1.5f, - 1.667f, - 2.0f - }; - // Instance properties - private Random r = new Random(); - private PartyEvents partyEvents; - private DiscoSheep parent; - private Player player; - private ArrayList sheepList = new ArrayList(); - private ArrayList guestList = new ArrayList(); - private ArrayList floorBlockCache = new ArrayList(); - private ArrayList floorBlocks = new ArrayList(); - private HashMap guestNumbers = new HashMap(); - private boolean doFireworks = false; - private boolean doJump = true; - private boolean doLightning = false; - private int duration, period, radius, sheep; - private int state = 0; // basically our own tick system - private DiscoUpdater updater; - - public DiscoParty(DiscoSheep parent, Player player) { - this(parent); - this.player = player; - } - - public DiscoParty(DiscoSheep parent) { - this.parent = parent; - this.duration = DiscoParty.defaultDuration; - this.period = DiscoParty.defaultPeriod; - this.radius = DiscoParty.defaultRadius; - this.sheep = DiscoParty.defaultSheep; - this.guestNumbers = new HashMap(DiscoParty.defaultGuestNumbers); - r = new Random(); - } - - // copy but with new player - // used for /ds other and /ds all - public DiscoParty clone(Player player) { - DiscoParty newParty; - newParty = new DiscoParty(this.parent, player); - newParty.doFireworks = this.doFireworks; - newParty.duration = this.duration; - newParty.period = this.period; - newParty.radius = this.radius; - newParty.sheep = this.sheep; - newParty.doLightning = this.doLightning; - newParty.guestNumbers = this.getGuestNumbers(); - return newParty; - } - - ArrayList getSheepList() { - return sheepList; - } - - ArrayList getGuestList() { - return guestList; - } - - ArrayList getFloorCache() { - return this.floorBlockCache; - } - - ArrayList getFloorBlocks() { - return this.floorBlocks; - } - - public static HashMap getDefaultGuestNumbers() { - return defaultGuestNumbers; - } - - public HashMap getGuestNumbers() { - return guestNumbers; - } - - public static HashMap getMaxGuestNumbers() { - return maxGuestNumbers; - } - - public int getSheep() { - return this.sheep; - } - - public DiscoParty setPlayer(Player player) { - if (player != null) { - this.player = player; - return this; - } else { - throw new NullPointerException(); - } - } - - public DiscoParty setDuration(int duration) throws IllegalArgumentException { - if (duration <= DiscoParty.maxDuration && duration > 0) { - this.duration = duration; - return this; - } else { - throw new IllegalArgumentException(); - } - } - - public DiscoParty setPeriod(int period) throws IllegalArgumentException { - if (period >= DiscoParty.minPeriod && period <= DiscoParty.maxPeriod) { - this.period = period; - return this; - } else { - throw new IllegalArgumentException(); - } - } - - public DiscoParty setRadius(int radius) throws IllegalArgumentException { - if (radius <= DiscoParty.maxRadius && radius > 0) { - this.radius = radius; - return this; - } else { - throw new IllegalArgumentException(); - } - } - - public DiscoParty setDenseRadius(int sheepNo) throws IllegalArgumentException { - Integer rand = (int) Math.floor(Math.sqrt(sheep / Math.PI)); - if (rand > DiscoParty.maxRadius) { - rand = DiscoParty.maxRadius; - } - if (rand < 1) { - rand = 1; - } - - this.setRadius(rand); - return this; - } - - public DiscoParty setSheep(int sheep) throws IllegalArgumentException { - if (sheep <= DiscoParty.maxSheep && sheep > 0) { - this.sheep = sheep; - return this; - } else { - throw new IllegalArgumentException(); - } - } - - public DiscoParty setDoFireworks(boolean doFireworks) { - this.doFireworks = doFireworks; - return this; - } - - public DiscoParty setDoLightning(boolean doLightning) { - this.doLightning = doLightning; - return this; - } - - public DiscoParty setGuestNumber(String key, int n) throws IllegalArgumentException { - if (getMaxGuestNumbers().containsKey(key.toUpperCase())) { - if (n <= getMaxGuestNumbers().get(key.toUpperCase()) && n >= 0) { // so that /ds defaults can take 0 as arg - getGuestNumbers().put(key, n); - - return this; - } - } - throw new IllegalArgumentException(); - } - - // use current settings as new defaults - public DiscoParty setDefaultsFromCurrent() { - DiscoParty.defaultDuration = this.duration; - DiscoParty.defaultPeriod = this.period; - DiscoParty.defaultRadius = this.radius; - DiscoParty.defaultSheep = this.sheep; - DiscoParty.defaultGuestNumbers = new HashMap(this.getGuestNumbers()); - return this; - } - - Location getRandomSpawnLocation(double x, double z, World world, int spawnRadius) { - Location loc; - - double y; - - /* random point on circle with polar coordinates - * random number must be square rooted to obtain uniform distribution - * otherwise the sheep are biased toward the centre */ - double rand = Math.sqrt(r.nextDouble()) * spawnRadius; - double azimuth = r.nextDouble() * 2 * Math.PI; // radians - x += rand * Math.cos(azimuth); - z += rand * Math.sin(azimuth); - y = this.player.getLocation().getY(); - - loc = new Location(world, x, y, z); - loc.setPitch(r.nextFloat() * 360 - 180); - loc.setYaw(0); - - return loc; - } - - // Spawn some number of guests next to given player - void spawnAll(int sheep, int spawnRadius) { - Location loc; - World world = player.getWorld(); - - - double x = player.getLocation().getX(); - double z = player.getLocation().getZ(); - for (int i = 0; i < sheep; i++) { - loc = getRandomSpawnLocation(x, z, world, spawnRadius); - spawnSheep(world, loc); - } - - // loop through hashmap of other guests and spawn accordingly - for (Map.Entry entry : guestNumbers.entrySet()) { - EntityType ent = EntityType.valueOf((String) entry.getKey()); - int num = (Integer) entry.getValue(); - - for (int i = 0; i < num; i++) { - loc = getRandomSpawnLocation(x, z, world, spawnRadius); - spawnGuest(world, loc, ent); - } - } - - loc = player.getLocation(); - this.spawnFloor(world, new Location(world, loc.getBlockX(), loc.getBlockY() - 1, loc.getBlockZ())); - } - - void spawnSheep(World world, Location loc) { - Sheep newSheep = (Sheep) world.spawnEntity(loc, EntityType.SHEEP); - newSheep.setColor(discoColours[(r.nextInt(discoColours.length))]); - newSheep.setBreed(false); // this prevents breeding - no event listener required - newSheep.teleport(loc); // teleport is needed to set orientation - getSheepList().add(newSheep); - if (doLightning) { - world.strikeLightningEffect(loc); - } - } - - void spawnGuest(World world, Location loc, EntityType type) { - Entity newGuest = loc.getWorld().spawnEntity(loc, type); - getGuestList().add(newGuest); - if (doLightning) { - world.strikeLightningEffect(loc); - } - } - - void spawnFloor(World world, Location loc) { - // First we'll save the floor state - for (int x = loc.getBlockX() - this.radius; x < loc.getX() + this.radius; ++x) { - for (int z = loc.getBlockZ() - this.radius; z < loc.getZ() + this.radius; ++z) { - Block block = world.getBlockAt(x, loc.getBlockY(), z); - if (block.getType() != Material.WOOL) { - this.getFloorCache().add(block.getState()); - block.setType(Material.WOOL); - this.getFloorBlocks().add(block); - } - } - } - } - - // Mark all guests for removal, then clear the array - void removeAll() { - for (Sheep sheeple : getSheepList()) { - sheeple.remove(); - } - for (Entity guest : getGuestList()) { - guest.remove(); - } - for (BlockState block : this.floorBlockCache) { - block.update(true); - } - getSheepList().clear(); - getGuestList().clear(); - floorBlockCache.clear(); - } - - // Set a random colour for all sheep in array - void randomizeSheepColour(Sheep sheep) { - sheep.setColor(discoColours[(r.nextInt(discoColours.length))]); - } - - void randomizeFloor(Block block) { - block.setType(Material.WOOL); - block.setData(discoColours[(r.nextInt(discoColours.length))].getData()); - } - - void jump(Entity entity) { - Vector orgVel = entity.getVelocity(); - Vector newVel = (new Vector()).copy(orgVel); - newVel.add(new Vector(0, defaultSheepJump, 0)); - entity.setVelocity(newVel); - } - - // WHY ISN'T THERE A Color.getValue() ?!?!?!?! - private Color getColor(int i) { - Color c = null; - if (i == 1) { - c = Color.AQUA; - } - if (i == 2) { - c = Color.BLACK; - } - if (i == 3) { - c = Color.BLUE; - } - if (i == 4) { - c = Color.FUCHSIA; - } - if (i == 5) { - c = Color.GRAY; - } - if (i == 6) { - c = Color.GREEN; - } - if (i == 7) { - c = Color.LIME; - } - if (i == 8) { - c = Color.MAROON; - } - if (i == 9) { - c = Color.NAVY; - } - if (i == 10) { - c = Color.OLIVE; - } - if (i == 11) { - c = Color.ORANGE; - } - if (i == 12) { - c = Color.PURPLE; - } - if (i == 13) { - c = Color.RED; - } - if (i == 14) { - c = Color.SILVER; - } - if (i == 15) { - c = Color.TEAL; - } - if (i == 16) { - c = Color.WHITE; - } - if (i == 17) { - c = Color.YELLOW; - } - - return c; - } - - void updateAll() { - for (Sheep sheeple : getSheepList()) { - randomizeSheepColour(sheeple); - - if (doFireworks && state % 8 == 0) { - if (r.nextDouble() < 0.50) { - spawnRandomFireworkAtSheep(sheeple); - } - } - - if (doJump) { - if (state % 2 == 0 && r.nextDouble() < 0.5) { - jump(sheeple); - } - } - } - - for (Entity guest : getGuestList()) { - if (doJump) { - if (state % 2 == 0 && r.nextDouble() < 0.5) { - jump(guest); - } - } - } - - for (Block block : this.floorBlocks) { - this.randomizeFloor(block); - } - - } - - private float getPentatonicNote() { - return DiscoParty.pentatonicNotes[r.nextInt(pentatonicNotes.length)]; - } - - void playSounds() { - player.playSound(player.getLocation(), Sound.NOTE_BASS_DRUM, 0.75f, 1.0f); - if (this.state % 2 == 0) { - player.playSound(player.getLocation(), Sound.NOTE_SNARE_DRUM, 0.8f, 1.0f); - } - - if ((this.state + 1) % 8 == 0) { - player.playSound(player.getLocation(), Sound.NOTE_STICKS, 1.0f, 1.0f); - } - } - - void randomizeFirework(Firework firework) { - Builder effect = FireworkEffect.builder(); - FireworkMeta meta = firework.getFireworkMeta(); - - // construct [1, 3] random colours - int numColours = r.nextInt(3) + 1; - Color[] colourArray = new Color[numColours]; - for (int i = 0; i < numColours; i++) { - colourArray[i] = getColor(r.nextInt(17) + 1); - } - - // randomize effects - effect.withColor(colourArray); - effect.flicker(r.nextDouble() < 0.5); - effect.trail(r.nextDouble() < 0.5); - effect.with(FireworkEffect.Type.values()[r.nextInt(FireworkEffect.Type.values().length)]); - - // set random effect and randomize power - meta.addEffect(effect.build()); - meta.setPower(r.nextInt(2) + 1); - - // apply it to the given firework - firework.setFireworkMeta(meta); - } - - void spawnRandomFireworkAtSheep(Sheep sheep) { - Firework firework = (Firework) sheep.getWorld().spawnEntity(sheep.getEyeLocation(), EntityType.FIREWORK); - randomizeFirework(firework); - } - - void update() { - if (duration > 0) { - updateAll(); - playSounds(); - duration -= period; - this.scheduleUpdate(); - this.state = (this.state + 1) % 10000; - } else { - this.stopDisco(); - } - } - - void scheduleUpdate() { - updater = new DiscoUpdater(); - updater.runTaskLater(parent, this.period); - } - - void startDisco() { - this.spawnAll(sheep, radius); - this.scheduleUpdate(); - parent.getPartyMap().put(this.player.getName(), this); - // start listening - this.partyEvents = new PartyEvents(this.parent, this); - parent.getServer().getPluginManager().registerEvents(this.partyEvents, this.parent); - } - - void stopDisco() { - removeAll(); - this.duration = 0; - if (updater != null) { - updater.cancel(); - } - updater = null; - parent.getPartyMap().remove(this.player.getName()); - // stop listening - HandlerList.unregisterAll(this.partyEvents); - } - - class DiscoUpdater extends BukkitRunnable { - - @Override - public void run() { - update(); - } - } -} diff --git a/src/ca/gibstick/discosheep/DiscoSheep.java b/src/ca/gibstick/discosheep/DiscoSheep.java deleted file mode 100644 index 2cfb22c..0000000 --- a/src/ca/gibstick/discosheep/DiscoSheep.java +++ /dev/null @@ -1,311 +0,0 @@ -package ca.gibstick.discosheep; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; -import org.bukkit.plugin.java.JavaPlugin; - -public final class DiscoSheep extends JavaPlugin { - - static final String PERMISSION_PARTY = "discosheep.party.me"; - static final String PERMISSION_ALL = "discosheep.party.all"; - static final String PERMISSION_FIREWORKS = "discosheep.party.fireworks"; - static final String PERMISSION_STOPALL = "discosheep.admin.stopall"; - static final String PERMISSION_RELOAD = "discosheep.admin.reload"; - static final String PERMISSION_OTHER = "discosheep.party.other"; - static final String PERMISSION_CHANGEPERIOD = "discosheep.party.changeperiod"; - static final String PERMISSION_CHANGEDEFAULTS = "discosheep.admin.changedefaults"; - static final String PERMISSION_SAVECONFIG = "discosheep.admin.saveconfig"; - static final String PERMISSION_ONJOIN = "discosheep.party.onjoin"; - static final String PERMISSION_SPAWNGUESTS = "discosheep.party.spawnguests"; - static final String PERMISSION_TOGGLEPARTYONJOIN = "discosheep.admin.toggleonjoin"; - static final String PERMISSION_LIGHTNING = "discosheep.party.lightning"; - static boolean partyOnJoin = true; - Map parties = new HashMap(); - - @Override - public void onEnable() { - getCommand("ds").setExecutor(new DiscoSheepCommandExecutor(this)); - getServer().getPluginManager().registerEvents(new GlobalEvents(this), this); - - getConfig().addDefault("on-join.enabled", partyOnJoin); - getConfig().addDefault("max.sheep", DiscoParty.maxSheep); - getConfig().addDefault("max.radius", DiscoParty.maxRadius); - getConfig().addDefault("max.duration", toSeconds_i(DiscoParty.maxDuration)); - getConfig().addDefault("max.period-ticks", DiscoParty.maxPeriod); - getConfig().addDefault("min.period-ticks", DiscoParty.minPeriod); - getConfig().addDefault("default.sheep", DiscoParty.defaultSheep); - getConfig().addDefault("default.radius", DiscoParty.defaultRadius); - getConfig().addDefault("default.duration", toSeconds_i(DiscoParty.defaultDuration)); - getConfig().addDefault("default.period-ticks", DiscoParty.defaultPeriod); - - /* - * Iterate through all live entities and create default configuration values for them - * excludes bosses and other mobs that throw NPE - */ - for (EntityType ent : EntityType.values()) { - if (ent.isAlive() - && !ent.equals(EntityType.ENDER_DRAGON) - && !ent.equals(EntityType.WITHER) - && !ent.equals(EntityType.PIG_ZOMBIE) - && !ent.equals(EntityType.OCELOT) - && !ent.equals(EntityType.CAVE_SPIDER) - && !ent.equals(EntityType.MAGMA_CUBE) - && !ent.equals(EntityType.MUSHROOM_COW) - && !ent.equals(EntityType.IRON_GOLEM) - && !ent.equals(EntityType.PLAYER)) { - getConfig().addDefault("default.guests." + ent.toString(), 0); - getConfig().addDefault("max.guests." + ent.toString(), 0); - } - } - - loadConfigFromDisk(); - } - - void loadConfigFromDisk() { - getConfig().options().copyDefaults(true); - saveConfig(); - - partyOnJoin = getConfig().getBoolean("on-join.enabled"); - DiscoParty.maxSheep = getConfig().getInt("max.sheep"); - DiscoParty.maxRadius = getConfig().getInt("max.radius"); - DiscoParty.maxDuration = toTicks(getConfig().getInt("max.duration")); - DiscoParty.maxPeriod = getConfig().getInt("max.period-ticks"); - DiscoParty.minPeriod = getConfig().getInt("min.period-ticks"); - DiscoParty.defaultSheep = getConfig().getInt("default.sheep"); - DiscoParty.defaultRadius = getConfig().getInt("default.radius"); - DiscoParty.defaultDuration = toTicks(getConfig().getInt("default.duration")); - DiscoParty.defaultPeriod = getConfig().getInt("default.period-ticks"); - - for (String key : getConfig().getConfigurationSection("default.guests").getKeys(false)) { - DiscoParty.getDefaultGuestNumbers().put(key, getConfig().getInt("default.guests." + key)); - } - - for (String key : getConfig().getConfigurationSection("max.guests").getKeys(false)) { - DiscoParty.getMaxGuestNumbers().put(key, getConfig().getInt("max.guests." + key)); - } - - } - - void reloadConfigFromDisk() { - reloadConfig(); - loadConfigFromDisk(); - } - - void saveConfigToDisk() { - getConfig().set("on-join.enabled", partyOnJoin); - getConfig().set("default.sheep", DiscoParty.defaultSheep); - getConfig().set("default.radius", DiscoParty.defaultRadius); - getConfig().set("default.duration", toSeconds_i(DiscoParty.defaultDuration)); - getConfig().set("default.period-ticks", DiscoParty.defaultPeriod); - - for (Map.Entry entry : DiscoParty.getDefaultGuestNumbers().entrySet()) { - getConfig().set("default.guests." + entry.getKey(), entry.getValue()); - } - - saveConfig(); - } - - @Override - public void onDisable() { - this.stopAllParties(); // or else the parties will continue FOREVER - } - - static int toTicks(double seconds) { - return (int) Math.round(seconds * 20.0); - } - - static double toSeconds(int ticks) { - return (double) Math.round(ticks / 20.0); - } - - static int toSeconds_i(int ticks) { - return (int) Math.round(ticks / 20.0); - } - - public synchronized Map getPartyMap() { - return this.parties; - } - - public synchronized ArrayList getParties() { - return new ArrayList(this.getPartyMap().values()); - } - - public void stopParty(String name) { - if (this.hasParty(name)) { - this.getParty(name).stopDisco(); - } - } - - public void stopAllParties() { - for (DiscoParty party : this.getParties()) { - party.stopDisco(); - } - } - - public boolean hasParty(String name) { - return this.getPartyMap().containsKey(name); - } - - public DiscoParty getParty(String name) { - return this.getPartyMap().get(name); - } - - public void removeParty(String name) { - if (this.hasParty(name)) { - this.getPartyMap().remove(name); - } - } - - /*-- Actual commands begin here --*/ - boolean helpCommand(CommandSender sender) { - sender.sendMessage(ChatColor.YELLOW - + "DiscoSheep Help\n" - + ChatColor.GRAY - + " Subcommands\n" - + ChatColor.WHITE + "me, stop, all, stopall, save, reload, togglejoin\n" - + "other : start a party for the space-delimited list of players\n" - + "defaults: Change the default settings for parties (takes normal arguments)\n" - + ChatColor.GRAY + " Arguments\n" - + ChatColor.WHITE + "-n : set the number of sheep per player that spawn\n" - + "-t : set the party duration in seconds\n" - + "-p : set the number of ticks between each disco beat\n" - + "-r : set radius of the area in which sheep can spawn\n" - + "-g : set spawns for other mobs" - + "-l: enables lightning" - + "-fw: enables fireworks"); - return true; - } - - boolean stopMeCommand(CommandSender sender) { - stopParty(sender.getName()); - return true; - } - - boolean stopAllCommand(CommandSender sender) { - if (sender.hasPermission(PERMISSION_STOPALL)) { - stopAllParties(); - return true; - } else { - return noPermsMessage(sender, PERMISSION_STOPALL); - } - } - - boolean partyCommand(Player player, DiscoParty party) { - if (player.hasPermission(PERMISSION_PARTY)) { - if (!hasParty(player.getName())) { - party.setPlayer(player); - party.startDisco(); - } else { - player.sendMessage(ChatColor.RED + "You already have a party. Are you underground?"); - } - return true; - } else { - return noPermsMessage(player, PERMISSION_PARTY); - } - } - - boolean reloadCommand(CommandSender sender) { - if (sender.hasPermission(PERMISSION_RELOAD)) { - reloadConfigFromDisk(); - sender.sendMessage(ChatColor.GREEN + "DiscoSheep config reloaded from disk"); - return true; - } else { - return noPermsMessage(sender, PERMISSION_RELOAD); - } - } - - boolean partyOtherCommand(String[] players, CommandSender sender, DiscoParty party) { - if (sender.hasPermission(PERMISSION_OTHER)) { - Player p; - for (String playerName : players) { - p = Bukkit.getServer().getPlayer(playerName); - if (p != null) { - if (!hasParty(p.getName())) { - DiscoParty individualParty = party.clone(p); - individualParty.startDisco(); - } - } else { - sender.sendMessage("Invalid player: " + playerName); - } - } - return true; - } else { - return noPermsMessage(sender, PERMISSION_OTHER); - } - } - - boolean partyAllCommand(CommandSender sender, DiscoParty party) { - if (sender.hasPermission(PERMISSION_ALL)) { - for (Player p : Bukkit.getServer().getOnlinePlayers()) { - if (!hasParty(p.getName())) { - DiscoParty individualParty = party.clone(p); - individualParty.startDisco(); - p.sendMessage(ChatColor.RED + "LET'S DISCO!!"); - } - } - return true; - } else { - return noPermsMessage(sender, PERMISSION_ALL); - } - } - - void partyOnJoin(Player player) { - if (!partyOnJoin) { - return; - } - if (player.hasPermission(PERMISSION_ONJOIN)) { - DiscoParty party = new DiscoParty(this, player); - party.startDisco(); - } - } - - boolean togglePartyOnJoinCommand(CommandSender sender) { - if (!sender.hasPermission(PERMISSION_TOGGLEPARTYONJOIN)) { - return noPermsMessage(sender, PERMISSION_TOGGLEPARTYONJOIN); - } - partyOnJoin = !partyOnJoin; - if (partyOnJoin) { - sender.sendMessage(ChatColor.GREEN + "DiscoSheep party on join functionality enabled."); - } else { - sender.sendMessage(ChatColor.GREEN + "DiscoSheep party on join functionality disabled."); - } - return true; - } - - boolean setDefaultsCommand(CommandSender sender, DiscoParty party) { - if (sender.hasPermission(PERMISSION_CHANGEDEFAULTS)) { - party.setDefaultsFromCurrent(); - sender.sendMessage(ChatColor.GREEN + "DiscoSheep configured with new defaults (not saved to disk yet)"); - return true; - } else { - return noPermsMessage(sender, PERMISSION_CHANGEDEFAULTS); - } - } - - boolean saveConfigCommand(CommandSender sender) { - if (sender.hasPermission(PERMISSION_SAVECONFIG)) { - saveConfigToDisk(); - sender.sendMessage(ChatColor.GREEN + "DiscoSheep config saved to disk"); - return true; - } else { - return noPermsMessage(sender, PERMISSION_SAVECONFIG); - } - - } - - boolean clearGuests(DiscoParty party) { - party.getGuestNumbers().clear(); - return true; - } - - boolean noPermsMessage(CommandSender sender, String permission) { - sender.sendMessage(ChatColor.RED + "You do not have the permission node " + ChatColor.GRAY + permission); - return false; - } -} diff --git a/src/ca/gibstick/discosheep/DiscoSheepCommandExecutor.java b/src/ca/gibstick/discosheep/DiscoSheepCommandExecutor.java deleted file mode 100644 index 72bdca7..0000000 --- a/src/ca/gibstick/discosheep/DiscoSheepCommandExecutor.java +++ /dev/null @@ -1,199 +0,0 @@ -package ca.gibstick.discosheep; - -import java.util.Arrays; -import org.bukkit.ChatColor; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -public class DiscoSheepCommandExecutor implements CommandExecutor { - - private DiscoSheep parent; - - public DiscoSheepCommandExecutor(DiscoSheep parent) { - this.parent = parent; - } - - private boolean parseNextArg(String[] args, int i, String compare) { - if (i < args.length - 1) { - return args[i + 1].equalsIgnoreCase(compare); - } - return false; - } - - private String getNextArg(String[] args, int i) { - if (i < args.length - 1) { - return args[i + 1]; - } else { - return null; - } - } - - private int getNextIntArg(String[] args, int i) { - if (i < args.length - 1) { - try { - return Integer.parseInt(args[i + 1]); - } catch (NumberFormatException e) { - return -1; // so that it fails limit checks elsewhere - } - } - return -1; // ibid - } - - private Double getNextDoubleArg(String[] args, int i) { - if (i < args.length - 1) { - try { - return Double.parseDouble(args[i + 1]); - } catch (NumberFormatException e) { - return -1.0d; // so that it fais limit checks elsewhere - } - } - return -1.0d; // ibid - } - - // return portion of the array that contains space-separated args, - // stopping at the end of the array or the next -switch - private String[] getNextArgs(String[] args, int i) { - int j = i; - while (j < args.length && !args[j].startsWith("-")) { - j++; - } - return Arrays.copyOfRange(args, i, j); - } - - @Override - public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) { - - Player player = null; - boolean isPlayer = false; - boolean specialRadius = false; - // flag to determine if we calculate a radius so that the sheep spawn densely in an area - - if (sender instanceof Player) { - player = (Player) sender; - isPlayer = true; - } // check isPlayer before "stop" and "me" commands - - // check for commands that don't need a party - // so that we get them out of the way, and - // prevent needless construction of parties - if (args.length == 1) { - if (args[0].equalsIgnoreCase("stopall")) { - return parent.stopAllCommand(sender); - } else if (args[0].equalsIgnoreCase("stop") && isPlayer) { - return parent.stopMeCommand(sender); - } else if (args[0].equalsIgnoreCase("help")) { - return parent.helpCommand(sender); - } else if (args[0].equalsIgnoreCase("reload")) { - return parent.reloadCommand(sender); - } else if (args[0].equalsIgnoreCase("save") || args[0].equalsIgnoreCase("saveconfig")) { - return parent.saveConfigCommand(sender); - } else if (args[0].equalsIgnoreCase("togglejoin")) { - return parent.togglePartyOnJoinCommand(sender); - } - } - - // construct a main party; all other parties will copy from this - DiscoParty mainParty = new DiscoParty(parent); - - // omg I love argument parsing and I know the best way! - for (int i = 1; i < args.length; i++) { - if (args[i].equalsIgnoreCase("-fw")) { - if (sender.hasPermission(DiscoSheep.PERMISSION_FIREWORKS)) { - mainParty.setDoFireworks(true); - } else { - return parent.noPermsMessage(sender, DiscoSheep.PERMISSION_FIREWORKS); - } - } else if (args[i].equalsIgnoreCase("-r")) { - if (parseNextArg(args, i, "dense")) { - specialRadius = true; - } - if (!specialRadius) { - try { - mainParty.setRadius(getNextIntArg(args, i)); - } catch (IllegalArgumentException e) { - sender.sendMessage("Radius must be an integer within the range [1, " - + DiscoParty.maxRadius + "]"); - return false; - } - } - } else if (args[i].equalsIgnoreCase("-n")) { - try { - mainParty.setSheep(getNextIntArg(args, i)); - } catch (IllegalArgumentException e) { - sender.sendMessage("The number of sheep must be an integer within the range [1, " - + DiscoParty.maxSheep + "]"); - return false; - } - } else if (args[i].equalsIgnoreCase("-t")) { - try { - mainParty.setDuration(parent.toTicks(getNextIntArg(args, i))); - } catch (IllegalArgumentException e) { - sender.sendMessage("The duration in seconds must be an integer within the range [1, " - + parent.toSeconds(DiscoParty.maxDuration) + "]"); - return false; - } - } else if (args[i].equalsIgnoreCase("-p")) { - if (!sender.hasPermission(DiscoSheep.PERMISSION_CHANGEPERIOD)) { - return parent.noPermsMessage(sender, DiscoSheep.PERMISSION_CHANGEPERIOD); - } - try { - mainParty.setPeriod(getNextIntArg(args, i)); - } catch (IllegalArgumentException e) { - sender.sendMessage( - "The period in ticks must be within the range [" - + DiscoParty.minPeriod + ", " - + DiscoParty.maxPeriod + "]"); - return false; - } - } else if (args[i].equalsIgnoreCase("-g")) { - if (!sender.hasPermission(DiscoSheep.PERMISSION_SPAWNGUESTS)) { - return parent.noPermsMessage(sender, DiscoSheep.PERMISSION_SPAWNGUESTS); - } - - if (parseNextArg(args, i, "none")) { - return parent.clearGuests(mainParty); - } - - String[] guests = getNextArgs(args, i + 1); - int j = 0; - while (j < guests.length - 1) { - try { - mainParty.setGuestNumber(guests[j], getNextIntArg(guests, j)); - } catch (IllegalArgumentException e) { - sender.sendMessage(ChatColor.RED + "Invalid arguments: " + ChatColor.WHITE + guests[j] + ", " + guests[j + 1] - + ".\nEither a name typo or a number that is not within limits."); - } - j += 2; // skip over two arguments, since they come in pairs of entity-number - } - } else if (args[i].equalsIgnoreCase("-l")) { - if (!sender.hasPermission(DiscoSheep.PERMISSION_LIGHTNING)) { - return parent.noPermsMessage(sender, DiscoSheep.PERMISSION_LIGHTNING); - } - mainParty.setDoLightning(true); - } - } - - if (specialRadius) { - mainParty.setDenseRadius(mainParty.getSheep()); - } - - if (args.length > 0) { - if (args[0].equalsIgnoreCase("all")) { - return parent.partyAllCommand(sender, mainParty); - } else if (args[0].equalsIgnoreCase("me") && isPlayer) { - return parent.partyCommand(player, mainParty); - } else if (args[0].equalsIgnoreCase("other")) { - return parent.partyOtherCommand(getNextArgs(args, 1), sender, mainParty); - } else if (args[0].equalsIgnoreCase("defaults")) { - return parent.setDefaultsCommand(sender, mainParty); - } else { - sender.sendMessage(ChatColor.RED + "Invalid argument (certain commands do not work from console)."); - return false; - } - } - - return false; - } -} diff --git a/src/ca/gibstick/discosheep/GlobalEvents.java b/src/ca/gibstick/discosheep/GlobalEvents.java deleted file mode 100644 index 74ee35b..0000000 --- a/src/ca/gibstick/discosheep/GlobalEvents.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * BaaBaaBlockSheep have you any wool? - * Nope, event got cancelled. - * Also listens to other events, not just sheep events - */ -package ca.gibstick.discosheep; - -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; - -public class GlobalEvents implements Listener { - - DiscoSheep parent; - - public GlobalEvents(DiscoSheep parent) { - this.parent = parent; - } - - @EventHandler (priority = EventPriority.MONITOR) - public void onPlayerQuitEvent(PlayerQuitEvent e) { - String name = e.getPlayer().getName(); - parent.stopParty(name); - // stop party on player quit or else it will CONTINUE FOR ETERNITY - } - - @EventHandler (priority = EventPriority.MONITOR) - public void onPlayerJoinEvent(PlayerJoinEvent e) { - Player player = e.getPlayer(); - parent.partyOnJoin(player); - } -} diff --git a/src/ca/gibstick/discosheep/PartyEvents.java b/src/ca/gibstick/discosheep/PartyEvents.java deleted file mode 100644 index 1de12b8..0000000 --- a/src/ca/gibstick/discosheep/PartyEvents.java +++ /dev/null @@ -1,71 +0,0 @@ -package ca.gibstick.discosheep; - -import org.bukkit.entity.Sheep; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityDamageEvent; -import org.bukkit.event.entity.EntityTargetEvent; -import org.bukkit.event.player.PlayerShearEntityEvent; - -/** - * - * @author Charlie - */ -public class PartyEvents implements Listener { - - DiscoSheep parent; - DiscoParty party; - /* - * There will be multiple instances of PartyEvents, - * and each instance will only listen for its own party. - * That way, we don't have multiple instances iterating through - * the entire parties hashmap redundantly, yet we can still - * unregister the listeners when no parties are running. - */ - - public PartyEvents(DiscoSheep parent, DiscoParty party) { - this.parent = parent; - this.party = party; - } - - // prevent sheep shearing - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onPlayerShear(PlayerShearEntityEvent e) { - if (e.getEntity() instanceof Sheep) { - - if (party.getSheepList().contains((Sheep) e.getEntity())) { - e.setCancelled(true); - } - - } - } - - // actually make sheep and other guests invincible - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onLivingEntityDamageEvent(EntityDamageEvent e) { - if (e.getEntity() instanceof Sheep) { - if (party.getSheepList().contains((Sheep) e.getEntity())) { - { - party.jump(e.getEntity()); // for kicks - e.setCancelled(true); - } - } - - } - if (party.getGuestList().contains(e.getEntity())) { - party.jump(e.getEntity()); - e.setCancelled(true); - } - } - - // prevent uninvited guests from targetting players - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onEntityTargetLivingEntityEvent(EntityTargetEvent e) { - - if (party.getGuestList().contains(e.getEntity())) { - e.setCancelled(true); - } - - } -} diff --git a/src/main/java/ca/gibstick/discosheep/DiscoCommands.java b/src/main/java/ca/gibstick/discosheep/DiscoCommands.java new file mode 100644 index 0000000..faff3df --- /dev/null +++ b/src/main/java/ca/gibstick/discosheep/DiscoCommands.java @@ -0,0 +1,313 @@ +package ca.gibstick.discosheep; + +import com.sk89q.minecraft.util.commands.Command; +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandPermissions; +import com.sk89q.minecraft.util.commands.NestedCommand; +import java.util.Arrays; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandException; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +/** + * + * @author Charlie + */ +public class DiscoCommands { + + static final String PERMISSION_PARTY = "discosheep.party.me"; + static final String PERMISSION_ALL = "discosheep.party.all"; + static final String PERMISSION_FIREWORKS = "discosheep.party.fireworks"; + static final String PERMISSION_STOPALL = "discosheep.admin.stopall"; + static final String PERMISSION_RELOAD = "discosheep.admin.reload"; + static final String PERMISSION_OTHER = "discosheep.party.other"; + static final String PERMISSION_CHANGEPERIOD = "discosheep.party.changeperiod"; + static final String PERMISSION_CHANGEDEFAULTS = "discosheep.admin.changedefaults"; + static final String PERMISSION_SAVECONFIG = "discosheep.admin.saveconfig"; + static final String PERMISSION_ONJOIN = "discosheep.party.onjoin"; + static final String PERMISSION_SPAWNGUESTS = "discosheep.party.spawnguests"; + static final String PERMISSION_TOGGLEPARTYONJOIN = "discosheep.admin.toggleonjoin"; + static final String PERMISSION_LIGHTNING = "discosheep.party.lightning"; + + static final String FLAGS = "n:t:p:r:lfg"; + + private static final DiscoSheep plugin = DiscoSheep.getInstance(); + + public static class ParentCommand { + + @Command(aliases = {"ds", "discosheep"}, desc = "Main Discosheep Command (see /ds help)", min = 0, max = -1) + @NestedCommand(DiscoCommands.class) + public static void DiscoCommand(final CommandContext args, CommandSender sender) throws CommandException { + } + } + + private static boolean getNextArg(String[] args, int i, String compare) { + if (i < args.length - 1) { + return args[i + 1].equalsIgnoreCase(compare); + } + return false; + } + + private static String getNextArg(String[] args, int i) { + if (i < args.length - 1) { + return args[i + 1]; + } else { + return null; + } + } + + // return portion of the array that contains space-separated args, + // stopping at the end of the array or the next -switch + private static String[] getNextArgs(String[] args, int i) { + int j = i; + while (j < args.length && !args[j].startsWith("-")) { + j++; + } + return Arrays.copyOfRange(args, i, j); + } + + private static int getNextIntArg(String[] args, int i) { + if (i < args.length - 1) { + try { + return Integer.parseInt(args[i + 1]); + } catch (NumberFormatException e) { + return -1; // so that it fails limit checks elsewhere + } + } + return -1; // ibid + } + + private static void parsePartyFlags(DiscoParty party, final CommandContext args, CommandSender sender) throws IllegalArgumentException { + party.setPeriod(args.getFlagInteger('p', DiscoParty.defaultPeriod)); + party.setSheep(args.getFlagInteger('n', DiscoParty.defaultSheep)); + + // handle special case of duration conversion ugh + if (args.hasFlag('t')) { + int duration = args.getFlagInteger('t'); + party.setDuration(plugin.toTicks(duration)); + } + + // handle the special case of radius flag arg "dense" + String radiusArg = args.getFlag('r', Integer.toString(DiscoParty.defaultRadius)); + if ("dense".equals(radiusArg)) { + party.setDenseRadius(party.getSheep()); + } else { + party.setRadius(Integer.parseInt(radiusArg)); + } + + // party will still start if player doesn't have permission for extras + if (sender.hasPermission(PERMISSION_FIREWORKS)) { + party.setDoFireworks(args.hasFlag('f')); + } else { + plugin.noPermsMessage(sender, PERMISSION_FIREWORKS); + } + + if (sender.hasPermission(PERMISSION_LIGHTNING)) { + party.setDoLightning(args.hasFlag('l')); + } else { + plugin.noPermsMessage(sender, PERMISSION_LIGHTNING); + } + + // handle guests + if (args.hasFlag('g')) { + // stop if no permission for spawning guests + if (!sender.hasPermission(PERMISSION_SPAWNGUESTS)) { + plugin.noPermsMessage(sender, PERMISSION_SPAWNGUESTS); + return; + } + + String dirtyArgs[] = args.getParsedSlice(0); + //sender.sendMessage(dirtyArgs); + for (int i = 0; i < dirtyArgs.length; i++) { + if ("none".equals(dirtyArgs[0])) { + plugin.clearGuests(party); + return; + } + + String[] guests = dirtyArgs; + int j = 0; + while (j < guests.length - 1) { + try { + party.setGuestNumber(guests[j].toUpperCase(), getNextIntArg(guests, j)); + } catch (IllegalArgumentException e) { + sender.sendMessage(ChatColor.RED + "Invalid arguments: " + ChatColor.WHITE + guests[j] + ", " + guests[j + 1] + + ".\nEither a name typo or a number that is not within limits."); + } + j += 2; // skip over two arguments, since they come in pairs of entity-number + } + } + + } + + } + + /*-- Actual commands begin here --*/ + @Command(aliases = "help", desc = "DiscoSheep help", usage = "No arguments", min = 0, max = -1) + public static void helpCommand(CommandContext args, CommandSender sender) { + sender.sendMessage(ChatColor.YELLOW + + "DiscoSheep Help\n" + + ChatColor.GRAY + + " Subcommands\n" + + ChatColor.WHITE + "me, stop, all, stopall, save, reload, togglejoin\n" + + "other : start a party for the space-delimited list of players\n" + + "defaults: Change the default settings for parties (takes normal arguments)\n" + + ChatColor.GRAY + " Arguments\n" + + ChatColor.WHITE + "-n : set the number of sheep per player that spawn\n" + + "-t : set the party duration in seconds\n" + + "-p : set the number of ticks between each disco beat\n" + + "-r : set radius of the area in which sheep can spawn\n" + + "-g : set spawns for other mobs" + + "-l: enables lightning" + + "-f: enables fireworks"); + } + + @Command(aliases = {"stop", "stoppls", "wtf"}, desc = "Stop your own disco party", usage = "No arguments", min = 0, max = 0) + public static void stopMeCommand(final CommandContext args, CommandSender sender) throws CommandException { + plugin.stopParty(sender.getName()); + } + + @Command(aliases = {"stopall"}, desc = "Stop all disco parties on the server", usage = "No arguments", min = 0, max = 0) + @CommandPermissions(value = PERMISSION_STOPALL) + public static void stopAllCommand(final CommandContext args, CommandSender sender) throws CommandException { + plugin.stopAllParties(); + } + + @Command(aliases = {"reload"}, desc = "Reload DiscoSheep configuration from file", usage = "No arguments", min = 0, max = 0) + public static void reloadCommand(final CommandContext args, CommandSender sender + ) { + plugin.reloadConfigFromDisk(); + sender.sendMessage(ChatColor.GREEN + "DiscoSheep config reloaded from file."); + } + + @Command( + aliases = {"me", "party", "partay", "turnup"}, + desc = "Start your own private DiscoParty", + usage = "[optional flags]", + min = 0, + max = -1, + flags = FLAGS + ) + @CommandPermissions(value = PERMISSION_PARTY) + public static void partyCommand(final CommandContext args, CommandSender sender + ) { + if (!(sender instanceof Player)) { + sender.sendMessage("You must be a player to have a party"); + return; + } + Player player = (Player) sender; + if (!plugin.hasParty(player.getName())) { + DiscoParty party = new DiscoParty(player); + parsePartyFlags(party, args, sender); + party.startDisco(); + } else { + player.sendMessage(ChatColor.RED + "You already have a party."); + } + } + + @SuppressWarnings("deprecation") + // UUIDs not necessary since DiscoSheep only lasts for one session at most + // and permissions will handle onJoin DiscoSheep + @Command( + aliases = {"other", "yall"}, + desc = "Start a party for other players", + usage = "[optional flags]", + min = 0, + max = -1, + flags = FLAGS + ) + @CommandPermissions(value = PERMISSION_OTHER) + public static void partyOtherCommand(CommandContext args, CommandSender sender + ) { + DiscoParty party = new DiscoParty(); + parsePartyFlags(party, args, sender); + String players[] = args.getParsedSlice(0); + + Player p; + for (String playerName : players) { + p = Bukkit.getServer().getPlayer(playerName); + if (p != null) { + if (!plugin.hasParty(p.getName())) { + DiscoParty individualParty = party.clone(p); + individualParty.startDisco(); + } + } else { + sender.sendMessage("Invalid player: " + playerName); + } + } + } + + @Command( + aliases = {"all", "allturnup"}, + desc = "Start a party for all players on the server", + usage = "[optional flags]", + min = 0, + max = -1, + flags = FLAGS + ) + @CommandPermissions(value = PERMISSION_ALL) + public static void partyAllCommand(final CommandContext args, CommandSender sender + ) { + DiscoParty party = new DiscoParty(); + parsePartyFlags(party, args, sender); + for (Player p : Bukkit.getServer().getOnlinePlayers()) { + if (!plugin.hasParty(p.getName())) { + DiscoParty individualParty = party.clone(p); + individualParty.startDisco(); + p.sendMessage(ChatColor.RED + "LET'S DISCO!!"); + } + } + } + + @Command( + aliases = {"togglejoin", "toggleonjoin"}, + desc = "Start a party for all players on the server", + usage = "[optional flags]", + min = 0, + max = -1, + flags = FLAGS + ) + @CommandPermissions(value = PERMISSION_TOGGLEPARTYONJOIN) + public static void togglePartyOnJoinCommand(final CommandContext args, CommandSender sender + ) { + boolean result = plugin.toggleOnJoin(); + if (result) { + sender.sendMessage(ChatColor.GREEN + "DiscoSheep party on join functionality enabled."); + } else { + sender.sendMessage(ChatColor.GREEN + "DiscoSheep party on join functionality disabled."); + } + } + + @Command( + aliases = {"defaults", "setdefaults"}, + desc = "Change the default party settings", + usage = "[optional flags]", + min = 0, + max = -1, + flags = FLAGS + ) + @CommandPermissions(value = PERMISSION_CHANGEDEFAULTS) + public static void setDefaultsCommand(final CommandContext args, CommandSender sender + ) { + DiscoParty party = new DiscoParty(); + parsePartyFlags(party, args, sender); + party.setDefaultsFromCurrent(); + sender.sendMessage(ChatColor.GREEN + "DiscoSheep configured with new defaults (not saved to disk yet)"); + } + + @Command( + aliases = {"defaults", "setdefaults"}, + desc = "Change the default party settings", + usage = "[optional flags]", + min = 0, + max = -1, + flags = FLAGS + ) + @CommandPermissions(value = PERMISSION_SAVECONFIG) + public static void saveConfigCommand(final CommandContext args, CommandSender sender + ) { + plugin.saveConfigToDisk(); + sender.sendMessage(ChatColor.GREEN + "DiscoSheep config saved to disk"); + } +} diff --git a/src/main/java/ca/gibstick/discosheep/DiscoParty.java b/src/main/java/ca/gibstick/discosheep/DiscoParty.java new file mode 100644 index 0000000..42c4ce2 --- /dev/null +++ b/src/main/java/ca/gibstick/discosheep/DiscoParty.java @@ -0,0 +1,524 @@ +package ca.gibstick.discosheep; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import org.bukkit.Color; +import org.bukkit.DyeColor; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.World; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Firework; +import org.bukkit.entity.Player; +import org.bukkit.entity.Sheep; +import org.bukkit.FireworkEffect; +import org.bukkit.FireworkEffect.Builder; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.entity.Entity; +import org.bukkit.event.HandlerList; +import org.bukkit.inventory.meta.FireworkMeta; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; + +public class DiscoParty { + + // Static properties + static int defaultDuration = 300; // ticks for entire party + static int defaultPeriod = 10; // ticks per state change + static int defaultRadius = 5; + static int defaultSheep = 10; + static float defaultSheepJump = 0.35f; + static int maxDuration = 2400; // 120 seconds + static int maxSheep = 100; + static int maxRadius = 100; + static int minPeriod = 5; // 0.25 seconds + static int maxPeriod = 40; // 2.0 seconds + private static HashMap defaultGuestNumbers = new HashMap(); + private static HashMap maxGuestNumbers = new HashMap(); + private static final DyeColor[] discoColours = { + DyeColor.RED, + DyeColor.ORANGE, + DyeColor.YELLOW, + DyeColor.GREEN, + DyeColor.BLUE, + DyeColor.LIGHT_BLUE, + DyeColor.PINK, + DyeColor.MAGENTA, + DyeColor.LIME, + DyeColor.CYAN, + DyeColor.PURPLE, + DyeColor.BLACK, + DyeColor.WHITE + }; + private static final float[] pentatonicNotes = { + 1.0f, + 1.125f, + 1.25f, + 1.5f, + 1.667f, + 2.0f + }; + // Instance properties + private Random r = new Random(); + private PartyEvents partyEvents; + private final DiscoSheep parent = DiscoSheep.getInstance(); + private Player player; + private ArrayList sheepList = new ArrayList(); + private ArrayList guestList = new ArrayList(); + private ArrayList floorBlockCache = new ArrayList(); + private ArrayList floorBlocks = new ArrayList(); + private HashMap guestNumbers = new HashMap(); + private boolean doFireworks = false; + private boolean doJump = true; + private boolean doLightning = false; + private int duration, period, radius, sheep; + private int state = 0; // basically our own tick system + private DiscoUpdater updater; + + public DiscoParty(Player player) { + this(); + this.player = player; + } + + public DiscoParty() { + this.duration = DiscoParty.defaultDuration; + this.period = DiscoParty.defaultPeriod; + this.radius = DiscoParty.defaultRadius; + this.sheep = DiscoParty.defaultSheep; + this.guestNumbers = new HashMap(DiscoParty.defaultGuestNumbers); + r = new Random(); + } + + // copy but with new player + // used for /ds other and /ds all + public DiscoParty clone(Player player) { + DiscoParty newParty; + newParty = new DiscoParty(player); + newParty.doFireworks = this.doFireworks; + newParty.duration = this.duration; + newParty.period = this.period; + newParty.radius = this.radius; + newParty.sheep = this.sheep; + newParty.doLightning = this.doLightning; + newParty.guestNumbers = this.getGuestNumbers(); + return newParty; + } + + ArrayList getSheepList() { + return sheepList; + } + + ArrayList getGuestList() { + return guestList; + } + + ArrayList getFloorCache() { + return this.floorBlockCache; + } + + ArrayList getFloorBlocks() { + return this.floorBlocks; + } + + public static HashMap getDefaultGuestNumbers() { + return defaultGuestNumbers; + } + + public HashMap getGuestNumbers() { + return guestNumbers; + } + + public static HashMap getMaxGuestNumbers() { + return maxGuestNumbers; + } + + public int getSheep() { + return this.sheep; + } + + public DiscoParty setPlayer(Player player) { + if (player != null) { + this.player = player; + return this; + } else { + throw new NullPointerException(); + } + } + + public DiscoParty setDuration(int duration) throws IllegalArgumentException { + if (duration <= DiscoParty.maxDuration && duration > 0) { + this.duration = duration; + return this; + } else { + throw new IllegalArgumentException(); + } + } + + public DiscoParty setPeriod(int period) throws IllegalArgumentException { + if (period >= DiscoParty.minPeriod && period <= DiscoParty.maxPeriod) { + this.period = period; + return this; + } else { + throw new IllegalArgumentException(); + } + } + + public DiscoParty setRadius(int radius) throws IllegalArgumentException { + if (radius <= DiscoParty.maxRadius && radius > 0) { + this.radius = radius; + return this; + } else { + throw new IllegalArgumentException(); + } + } + + public DiscoParty setDenseRadius(int sheepNo) throws IllegalArgumentException { + Integer rand = (int) Math.floor(Math.sqrt(sheep / Math.PI)); + if (rand > DiscoParty.maxRadius) { + rand = DiscoParty.maxRadius; + } + if (rand < 1) { + rand = 1; + } + + this.setRadius(rand); + return this; + } + + public DiscoParty setSheep(int sheep) throws IllegalArgumentException { + if (sheep <= DiscoParty.maxSheep && sheep > 0) { + this.sheep = sheep; + return this; + } else { + throw new IllegalArgumentException(); + } + } + + public DiscoParty setDoFireworks(boolean doFireworks) { + this.doFireworks = doFireworks; + return this; + } + + public DiscoParty setDoLightning(boolean doLightning) { + this.doLightning = doLightning; + return this; + } + + public DiscoParty setGuestNumber(String key, int n) throws IllegalArgumentException { + if (getMaxGuestNumbers().containsKey(key.toUpperCase())) { + if (n <= getMaxGuestNumbers().get(key.toUpperCase()) && n >= 0) { // so that /ds defaults can take 0 as arg + getGuestNumbers().put(key, n); + + return this; + } + } + throw new IllegalArgumentException(); + } + + // use current settings as new defaults + public DiscoParty setDefaultsFromCurrent() { + DiscoParty.defaultDuration = this.duration; + DiscoParty.defaultPeriod = this.period; + DiscoParty.defaultRadius = this.radius; + DiscoParty.defaultSheep = this.sheep; + DiscoParty.defaultGuestNumbers = new HashMap(this.getGuestNumbers()); + return this; + } + + Location getRandomSpawnLocation(double x, double z, World world, int spawnRadius) { + Location loc; + + double y; + + /* random point on circle with polar coordinates + * random number must be square rooted to obtain uniform distribution + * otherwise the sheep are biased toward the centre */ + double rand = Math.sqrt(r.nextDouble()) * spawnRadius; + double azimuth = r.nextDouble() * 2 * Math.PI; // radians + x += rand * Math.cos(azimuth); + z += rand * Math.sin(azimuth); + y = this.player.getLocation().getY(); + + loc = new Location(world, x, y, z); + loc.setPitch(r.nextFloat() * 360 - 180); + loc.setYaw(0); + + return loc; + } + + // Spawn some number of guests next to given player + void spawnAll(int sheep, int spawnRadius) { + Location loc; + World world = player.getWorld(); + + double x = player.getLocation().getX(); + double z = player.getLocation().getZ(); + for (int i = 0; i < sheep; i++) { + loc = getRandomSpawnLocation(x, z, world, spawnRadius); + spawnSheep(world, loc); + } + + // loop through hashmap of other guests and spawn accordingly + for (Map.Entry entry : guestNumbers.entrySet()) { + EntityType ent = EntityType.valueOf((String) entry.getKey()); + int num = (Integer) entry.getValue(); + + for (int i = 0; i < num; i++) { + loc = getRandomSpawnLocation(x, z, world, spawnRadius); + spawnGuest(world, loc, ent); + } + } + + //loc = player.getLocation(); + //this.spawnFloor(world, new Location(world, loc.getBlockX(), loc.getBlockY() - 1, loc.getBlockZ())); + } + + void spawnSheep(World world, Location loc) { + Sheep newSheep = (Sheep) world.spawnEntity(loc, EntityType.SHEEP); + newSheep.setColor(discoColours[(r.nextInt(discoColours.length))]); + newSheep.setBreed(false); // this prevents breeding - no event listener required + newSheep.teleport(loc); // teleport is needed to set orientation + getSheepList().add(newSheep); + if (doLightning) { + world.strikeLightningEffect(loc); + } + } + + void spawnGuest(World world, Location loc, EntityType type) { + Entity newGuest = loc.getWorld().spawnEntity(loc, type); + getGuestList().add(newGuest); + if (doLightning) { + world.strikeLightningEffect(loc); + } + } + + void spawnFloor(World world, Location loc) { + // First we'll save the floor state + for (int x = loc.getBlockX() - this.radius; x < loc.getX() + this.radius; ++x) { + for (int z = loc.getBlockZ() - this.radius; z < loc.getZ() + this.radius; ++z) { + Block block = world.getBlockAt(x, loc.getBlockY(), z); + if (block.getType() != Material.WOOL) { + this.getFloorCache().add(block.getState()); + block.setType(Material.WOOL); + this.getFloorBlocks().add(block); + } + } + } + } + + // Mark all guests for removal, then clear the array + void removeAll() { + for (Sheep sheeple : getSheepList()) { + sheeple.remove(); + } + for (Entity guest : getGuestList()) { + guest.remove(); + } + for (BlockState block : this.floorBlockCache) { + block.update(true); + } + getSheepList().clear(); + getGuestList().clear(); + floorBlockCache.clear(); + } + + // Set a random colour for all sheep in array + void randomizeSheepColour(Sheep sheep) { + sheep.setColor(discoColours[(r.nextInt(discoColours.length))]); + } + + void randomizeFloor(Block block) { + block.setType(Material.WOOL); + block.setData(discoColours[(r.nextInt(discoColours.length))].getData()); + } + + void jump(Entity entity) { + Vector orgVel = entity.getVelocity(); + Vector newVel = (new Vector()).copy(orgVel); + newVel.add(new Vector(0, defaultSheepJump, 0)); + entity.setVelocity(newVel); + } + + // WHY ISN'T THERE A Color.getValue() ?!?!?!?! + private Color getColor(int i) { + Color c = null; + if (i == 1) { + c = Color.AQUA; + } + if (i == 2) { + c = Color.BLACK; + } + if (i == 3) { + c = Color.BLUE; + } + if (i == 4) { + c = Color.FUCHSIA; + } + if (i == 5) { + c = Color.GRAY; + } + if (i == 6) { + c = Color.GREEN; + } + if (i == 7) { + c = Color.LIME; + } + if (i == 8) { + c = Color.MAROON; + } + if (i == 9) { + c = Color.NAVY; + } + if (i == 10) { + c = Color.OLIVE; + } + if (i == 11) { + c = Color.ORANGE; + } + if (i == 12) { + c = Color.PURPLE; + } + if (i == 13) { + c = Color.RED; + } + if (i == 14) { + c = Color.SILVER; + } + if (i == 15) { + c = Color.TEAL; + } + if (i == 16) { + c = Color.WHITE; + } + if (i == 17) { + c = Color.YELLOW; + } + + return c; + } + + void updateAll() { + for (Sheep sheeple : getSheepList()) { + randomizeSheepColour(sheeple); + + if (doFireworks && state % 8 == 0) { + if (r.nextDouble() < 0.50) { + spawnRandomFireworkAtSheep(sheeple); + } + } + + if (doJump) { + if (state % 2 == 0 && r.nextDouble() < 0.5) { + jump(sheeple); + } + } + } + + for (Entity guest : getGuestList()) { + if (doJump) { + if (state % 2 == 0 && r.nextDouble() < 0.5) { + jump(guest); + } + } + } + + /* for (Block block : this.floorBlocks) { + this.randomizeFloor(block); + }*/ + } + + private float getPentatonicNote() { + return DiscoParty.pentatonicNotes[r.nextInt(pentatonicNotes.length)]; + } + + void playSounds() { + player.playSound(player.getLocation(), Sound.NOTE_BASS_DRUM, 0.75f, 1.0f); + if (this.state % 2 == 0) { + player.playSound(player.getLocation(), Sound.NOTE_SNARE_DRUM, 0.8f, 1.0f); + } + + if ((this.state + 1) % 8 == 0) { + player.playSound(player.getLocation(), Sound.NOTE_STICKS, 1.0f, 1.0f); + } + } + + void randomizeFirework(Firework firework) { + Builder effect = FireworkEffect.builder(); + FireworkMeta meta = firework.getFireworkMeta(); + + // construct [1, 3] random colours + int numColours = r.nextInt(3) + 1; + Color[] colourArray = new Color[numColours]; + for (int i = 0; i < numColours; i++) { + colourArray[i] = getColor(r.nextInt(17) + 1); + } + + // randomize effects + effect.withColor(colourArray); + effect.flicker(r.nextDouble() < 0.5); + effect.trail(r.nextDouble() < 0.5); + effect.with(FireworkEffect.Type.values()[r.nextInt(FireworkEffect.Type.values().length)]); + + // set random effect and randomize power + meta.addEffect(effect.build()); + meta.setPower(r.nextInt(2) + 1); + + // apply it to the given firework + firework.setFireworkMeta(meta); + } + + void spawnRandomFireworkAtSheep(Sheep sheep) { + Firework firework = (Firework) sheep.getWorld().spawnEntity(sheep.getEyeLocation(), EntityType.FIREWORK); + randomizeFirework(firework); + } + + void update() { + if (duration > 0) { + updateAll(); + playSounds(); + duration -= period; + this.scheduleUpdate(); + this.state = (this.state + 1) % 10000; + } else { + this.stopDisco(); + } + } + + void scheduleUpdate() { + updater = new DiscoUpdater(); + updater.runTaskLater(parent, this.period); + } + + void startDisco() { + this.spawnAll(sheep, radius); + this.scheduleUpdate(); + parent.getPartyMap().put(this.player.getName(), this); + // start listening + this.partyEvents = new PartyEvents(this); + parent.getServer().getPluginManager().registerEvents(this.partyEvents, this.parent); + } + + void stopDisco() { + removeAll(); + this.duration = 0; + if (updater != null) { + updater.cancel(); + } + updater = null; + parent.getPartyMap().remove(this.player.getName()); + // stop listening + HandlerList.unregisterAll(this.partyEvents); + } + + class DiscoUpdater extends BukkitRunnable { + + @Override + public void run() { + update(); + } + } +} diff --git a/src/main/java/ca/gibstick/discosheep/DiscoSheep.java b/src/main/java/ca/gibstick/discosheep/DiscoSheep.java new file mode 100644 index 0000000..c3f8b53 --- /dev/null +++ b/src/main/java/ca/gibstick/discosheep/DiscoSheep.java @@ -0,0 +1,360 @@ +package ca.gibstick.discosheep; + +import com.sk89q.bukkit.util.CommandsManagerRegistration; +import com.sk89q.minecraft.util.commands.CommandPermissionsException; +import com.sk89q.minecraft.util.commands.CommandUsageException; +import com.sk89q.minecraft.util.commands.CommandsManager; +import com.sk89q.minecraft.util.commands.MissingNestedCommandException; +import com.sk89q.minecraft.util.commands.WrappedCommandException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandException; +import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; + +public final class DiscoSheep extends JavaPlugin { + + private static DiscoSheep instance; + + static boolean partyOnJoin = false; + Map parties = new HashMap(); + private CommandsManager commands; + + public static DiscoSheep getInstance() { + if (instance == null) { + instance = new DiscoSheep(); + return instance; + } + return instance; + } + + private void setupCommands() { + this.commands = new CommandsManager() { + @Override + public boolean hasPermission(CommandSender sender, String perm) { + return sender instanceof ConsoleCommandSender || sender.hasPermission(perm); + } + }; + CommandsManagerRegistration cmdRegister = new CommandsManagerRegistration(this, this.commands); + cmdRegister.register(DiscoCommands.ParentCommand.class); + } + + @Override + public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { + try { + this.commands.execute(cmd.getName(), args, sender, sender); + } catch (CommandPermissionsException e) { + sender.sendMessage(ChatColor.RED + "You don't have permission."); + } catch (MissingNestedCommandException e) { + sender.sendMessage(ChatColor.RED + e.getUsage()); + } catch (CommandUsageException e) { + sender.sendMessage(ChatColor.RED + e.getMessage()); + sender.sendMessage(ChatColor.RED + e.getUsage()); + } catch (WrappedCommandException e) { + if (e.getCause() instanceof NumberFormatException) { + sender.sendMessage(ChatColor.RED + "Number expected, string received instead."); + } else if (e.getCause() instanceof IllegalArgumentException) { + sender.sendMessage(ChatColor.RED + "Illegal argument (out of bounds or bad format)."); + } else { + sender.sendMessage(ChatColor.RED + "An error has occurred. See console."); + e.printStackTrace(); + } + } catch (CommandException e) { + sender.sendMessage(ChatColor.RED + e.getMessage()); + } catch (com.sk89q.minecraft.util.commands.CommandException ex) { + Logger.getLogger(DiscoSheep.class.getName()).log(Level.SEVERE, null, ex); + } + return true; + } + + @Override + public void onEnable() { + instance = this; + //getCommand("ds").setExecutor(new DiscoSheepCommandExecutor(this)); + setupCommands(); + getServer().getPluginManager().registerEvents(new GlobalEvents(), this); + + getConfig().addDefault("on-join.enabled", partyOnJoin); + getConfig().addDefault("max.sheep", DiscoParty.maxSheep); + getConfig().addDefault("max.radius", DiscoParty.maxRadius); + getConfig().addDefault("max.duration", toSeconds_i(DiscoParty.maxDuration)); + getConfig().addDefault("max.period-ticks", DiscoParty.maxPeriod); + getConfig().addDefault("min.period-ticks", DiscoParty.minPeriod); + getConfig().addDefault("default.sheep", DiscoParty.defaultSheep); + getConfig().addDefault("default.radius", DiscoParty.defaultRadius); + getConfig().addDefault("default.duration", toSeconds_i(DiscoParty.defaultDuration)); + getConfig().addDefault("default.period-ticks", DiscoParty.defaultPeriod); + + /* + * Iterate through all live entities and create default configuration values for them + * excludes bosses and other mobs that throw NPE + */ + for (EntityType ent : EntityType.values()) { + if (ent.isAlive() + && !ent.equals(EntityType.ENDER_DRAGON) + && !ent.equals(EntityType.WITHER) + && !ent.equals(EntityType.PLAYER)) { + getConfig().addDefault("default.guests." + ent.toString(), 0); + getConfig().addDefault("max.guests." + ent.toString(), 5); + } + } + loadConfigFromDisk(); + } + + void loadConfigFromDisk() { + getConfig().options().copyDefaults(true); + saveConfig(); + + partyOnJoin = getConfig().getBoolean("on-join.enabled"); + DiscoParty.maxSheep = getConfig().getInt("max.sheep"); + DiscoParty.maxRadius = getConfig().getInt("max.radius"); + DiscoParty.maxDuration = toTicks(getConfig().getInt("max.duration")); + DiscoParty.maxPeriod = getConfig().getInt("max.period-ticks"); + DiscoParty.minPeriod = getConfig().getInt("min.period-ticks"); + DiscoParty.defaultSheep = getConfig().getInt("default.sheep"); + DiscoParty.defaultRadius = getConfig().getInt("default.radius"); + DiscoParty.defaultDuration = toTicks(getConfig().getInt("default.duration")); + DiscoParty.defaultPeriod = getConfig().getInt("default.period-ticks"); + + for (String key : getConfig().getConfigurationSection("default.guests").getKeys(false)) { + DiscoParty.getDefaultGuestNumbers().put(key, getConfig().getInt("default.guests." + key)); + } + + for (String key : getConfig().getConfigurationSection("max.guests").getKeys(false)) { + DiscoParty.getMaxGuestNumbers().put(key, getConfig().getInt("max.guests." + key)); + } + } + + void reloadConfigFromDisk() { + reloadConfig(); + loadConfigFromDisk(); + } + + void saveConfigToDisk() { + getConfig().set("on-join.enabled", partyOnJoin); + getConfig().set("default.sheep", DiscoParty.defaultSheep); + getConfig().set("default.radius", DiscoParty.defaultRadius); + getConfig().set("default.duration", toSeconds_i(DiscoParty.defaultDuration)); + getConfig().set("default.period-ticks", DiscoParty.defaultPeriod); + + for (Map.Entry entry : DiscoParty.getDefaultGuestNumbers().entrySet()) { + getConfig().set("default.guests." + entry.getKey(), entry.getValue()); + } + saveConfig(); + } + + @Override + public void onDisable() { + this.stopAllParties(); // or else the parties will continue FOREVER + instance = null; + commands = null; + } + + int toTicks(double seconds) { + return (int) Math.round(seconds * 20.0); + } + + double toSeconds(int ticks) { + return (double) Math.round(ticks / 20.0); + } + + int toSeconds_i(int ticks) { + return (int) Math.round(ticks / 20.0); + } + + public synchronized Map getPartyMap() { + return this.parties; + } + + public synchronized ArrayList getParties() { + return new ArrayList(this.getPartyMap().values()); + } + + public void stopParty(String name) { + if (this.hasParty(name)) { + this.getParty(name).stopDisco(); + } + } + + public void stopAllParties() { + for (DiscoParty party : this.getParties()) { + party.stopDisco(); + } + } + + public boolean hasParty(String name) { + return this.getPartyMap().containsKey(name); + } + + public DiscoParty getParty(String name) { + return this.getPartyMap().get(name); + } + + public boolean toggleOnJoin() { + DiscoSheep.partyOnJoin = !DiscoSheep.partyOnJoin; + return DiscoSheep.partyOnJoin; + } + + public void removeParty(String name) { + if (this.hasParty(name)) { + this.getPartyMap().remove(name); + } + } + + /*-- Actual commands begin here --*/ + /*boolean helpCommand(CommandSender sender) { + sender.sendMessage(ChatColor.YELLOW + + "DiscoSheep Help\n" + + ChatColor.GRAY + + " Subcommands\n" + + ChatColor.WHITE + "me, stop, all, stopall, save, reload, togglejoin\n" + + "other : start a party for the space-delimited list of players\n" + + "defaults: Change the default settings for parties (takes normal arguments)\n" + + ChatColor.GRAY + " Arguments\n" + + ChatColor.WHITE + "-n : set the number of sheep per player that spawn\n" + + "-t : set the party duration in seconds\n" + + "-p : set the number of ticks between each disco beat\n" + + "-r : set radius of the area in which sheep can spawn\n" + //+ "-g : set spawns for other mobs\n" + + "-l: enables lightning\n" + + "-fw: enables fireworks"); + return true; + } + + boolean stopMeCommand(CommandSender sender) { + stopParty(sender.getName()); + return true; + } + + boolean stopAllCommand(CommandSender sender) { + if (sender.hasPermission(PERMISSION_STOPALL)) { + stopAllParties(); + return true; + } else { + return noPermsMessage(sender, PERMISSION_STOPALL); + } + } + + boolean partyCommand(Player player, DiscoParty party) { + if (player.hasPermission(PERMISSION_PARTY)) { + if (!hasParty(player.getName())) { + party.setPlayer(player); + party.startDisco(); + } else { + player.sendMessage(ChatColor.RED + "You already have a party. Are you underground?"); + } + return true; + } else { + return noPermsMessage(player, PERMISSION_PARTY); + } + } + + boolean reloadCommand(CommandSender sender) { + if (sender.hasPermission(PERMISSION_RELOAD)) { + reloadConfigFromDisk(); + sender.sendMessage(ChatColor.GREEN + "DiscoSheep config reloaded from disk"); + return true; + } else { + return noPermsMessage(sender, PERMISSION_RELOAD); + } + } + + @SuppressWarnings("deprecation") + // UUIDs not necessary since DiscoSheep only lasts for one session at most + // and permissions will handle onJoin DiscoSheep + boolean partyOtherCommand(String[] players, CommandSender sender, DiscoParty party) { + if (sender.hasPermission(PERMISSION_OTHER)) { + Player p; + for (String playerName : players) { + p = Bukkit.getServer().getPlayer(playerName); + if (p != null) { + if (!hasParty(p.getName())) { + DiscoParty individualParty = party.clone(p); + individualParty.startDisco(); + } + } else { + sender.sendMessage("Invalid player: " + playerName); + } + } + return true; + } else { + return noPermsMessage(sender, PERMISSION_OTHER); + } + } + + boolean partyAllCommand(CommandSender sender, DiscoParty party) { + if (sender.hasPermission(PERMISSION_ALL)) { + for (Player p : Bukkit.getServer().getOnlinePlayers()) { + if (!hasParty(p.getName())) { + DiscoParty individualParty = party.clone(p); + individualParty.startDisco(); + p.sendMessage(ChatColor.RED + "LET'S DISCO!!"); + } + } + return true; + } else { + return noPermsMessage(sender, PERMISSION_ALL); + } + } + + boolean togglePartyOnJoinCommand(CommandSender sender) { + if (!sender.hasPermission(PERMISSION_TOGGLEPARTYONJOIN)) { + return noPermsMessage(sender, PERMISSION_TOGGLEPARTYONJOIN); + } + partyOnJoin = !partyOnJoin; + if (partyOnJoin) { + sender.sendMessage(ChatColor.GREEN + "DiscoSheep party on join functionality enabled."); + } else { + sender.sendMessage(ChatColor.GREEN + "DiscoSheep party on join functionality disabled."); + } + return true; + } + + boolean setDefaultsCommand(CommandSender sender, DiscoParty party) { + if (sender.hasPermission(PERMISSION_CHANGEDEFAULTS)) { + party.setDefaultsFromCurrent(); + sender.sendMessage(ChatColor.GREEN + "DiscoSheep configured with new defaults (not saved to disk yet)"); + return true; + } else { + return noPermsMessage(sender, PERMISSION_CHANGEDEFAULTS); + } + } + + boolean saveConfigCommand(CommandSender sender) { + if (sender.hasPermission(PERMISSION_SAVECONFIG)) { + saveConfigToDisk(); + sender.sendMessage(ChatColor.GREEN + "DiscoSheep config saved to disk"); + return true; + } else { + return noPermsMessage(sender, PERMISSION_SAVECONFIG); + } + + }*/ + void partyOnJoin(Player player) { + if (!partyOnJoin) { + return; + } + if (player.hasPermission(DiscoCommands.PERMISSION_ONJOIN)) { + DiscoParty party = new DiscoParty(player); + party.startDisco(); + } + } + + boolean clearGuests(DiscoParty party) { + party.getGuestNumbers().clear(); + return true; + } + + boolean noPermsMessage(CommandSender sender, String permission) { + sender.sendMessage(ChatColor.RED + "You do not have the permission node " + ChatColor.GRAY + permission); + return false; + } +} diff --git a/src/main/java/ca/gibstick/discosheep/GlobalEvents.java b/src/main/java/ca/gibstick/discosheep/GlobalEvents.java new file mode 100644 index 0000000..aca1959 --- /dev/null +++ b/src/main/java/ca/gibstick/discosheep/GlobalEvents.java @@ -0,0 +1,31 @@ +/* + * BaaBaaBlockSheep have you any wool? + * Nope, event got cancelled. + * Also listens to other events, not just sheep events + */ +package ca.gibstick.discosheep; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +public class GlobalEvents implements Listener { + + DiscoSheep plugin = DiscoSheep.getInstance(); + + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerQuitEvent(PlayerQuitEvent e) { + String name = e.getPlayer().getName(); + plugin.stopParty(name); + // stop party on player quit or else it will CONTINUE FOR ETERNITY + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerJoinEvent(PlayerJoinEvent e) { + Player player = e.getPlayer(); + plugin.partyOnJoin(player); + } +} diff --git a/src/main/java/ca/gibstick/discosheep/PartyEvents.java b/src/main/java/ca/gibstick/discosheep/PartyEvents.java new file mode 100644 index 0000000..5a052e5 --- /dev/null +++ b/src/main/java/ca/gibstick/discosheep/PartyEvents.java @@ -0,0 +1,82 @@ +package ca.gibstick.discosheep; + +import org.bukkit.entity.Sheep; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityPortalEvent; +import org.bukkit.event.entity.EntityTargetEvent; +import org.bukkit.event.player.PlayerInteractEntityEvent; +import org.bukkit.event.player.PlayerShearEntityEvent; + +/** + * + * @author Charlie + */ +public class PartyEvents implements Listener { + + DiscoSheep plugin = DiscoSheep.getInstance(); + DiscoParty party; + /* + * There will be multiple instances of PartyEvents, + * and each instance will only listen for its own party. + * That way, we don't have multiple instances iterating through + * the entire parties hashmap redundantly, yet we can still + * unregister the listeners when no parties are running. + */ + + public PartyEvents(DiscoParty party) { + this.party = party; + } + + // prevent sheep shearing + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onPlayerShear(PlayerShearEntityEvent e) { + if (e.getEntity() instanceof Sheep) { + if (party.getSheepList().contains((Sheep) e.getEntity())) { + e.setCancelled(true); + } + } + } + + // actually make sheep and other guests invincible + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onLivingEntityDamageEvent(EntityDamageEvent e) { + if (e.getEntity() instanceof Sheep) { + if (party.getSheepList().contains((Sheep) e.getEntity())) { + party.jump(e.getEntity()); // for kicks + e.setCancelled(true); + } + } + if (party.getGuestList().contains(e.getEntity())) { + party.jump(e.getEntity()); + e.setCancelled(true); + } + } + + // prevent uninvited guests from targetting players + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onEntityTargetLivingEntityEvent(EntityTargetEvent e) { + if (party.getGuestList().contains(e.getEntity())) { + e.setCancelled(true); + } + } + + // prevent egg breeding + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onPlayerInteractEntityEvent(PlayerInteractEntityEvent e) { + if (party.getSheepList().contains(e.getRightClicked()) || party.getGuestList().contains(e.getRightClicked())) { + e.setCancelled(true); + } + } + + // prevent portal teleport + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onEntityPortalEvent(EntityPortalEvent e) { + if (party.getSheepList().contains(e.getEntity()) || party.getGuestList().contains(e.getEntity())) { + e.setCancelled(true); + } + } + +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..59a2f36 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,93 @@ +name: DiscoSheep +main: ca.gibstick.discosheep.DiscoSheep +authors: [Gibstick, RangerMauve] +version: 1.1.2 +commands: + #ds: + #description: "Main DiscoSheep command" + #usage: | + # [arguments] + #Use /ds help for more information + #To stop your party, use /ds stop. +permissions: + # If default is set to false, console will not have permission! + discosheep.*: + description: Permission node for all DiscoSheep commands + default: op + children: + discosheep.party: true + discosheep.admin: true + discosheep.party.*: + description: All permissions related to parties + defualt: op + children: + discosheep.party.me: true + discosheep.party.all: true + discosheep.party.fireworks: true + discosheep.party.other: true + discosheep.party.changeperiod: true + discosheep.party.spawnguests: true + discosheep.party.lightning: true + discosheep.admin.*: + description: Suggested permissions for administrators + default: op + children: + discosheep.admin.stopall: true + discosheep.admin.reload: true + discosheep.admin.changedefaults: true + discosheep.admin.saveconfig: true + discosheep.admin.toggleonjoin: true + discosheep.party.me: + description: Allows a player to have a party of one + default: op + discosheep.party.all: + description: Allows a player to call a server-wide party + default: op + discosheep.admin.stopall: + description: Allows a player to stop all parties on the server + default: op + discosheep.party.fireworks: + description: Allows a player to enable have parties with fireworks + default: op + discosheep.admin.reload: + description: Allows a player to reload settings from config.yml + default: op + discosheep.party.other: + description: Allows a player to call parties for other people, including themselves. + default: op + children: + discosheep.party.me: true + discosheep.party.changeperiod: + description: Allows a player to use the -p switch + default: op + discosheep.admin.changedefaults: + description: Allows a player to change the default settings + default: op + discosheep.admin.saveconfig: + description: Allows a player to save the config with current values set in memory + default: op + discosheep.party.onjoin: + description: Gives a player a disco party on join + default: false + discosheep.party.spawnguests: + description: Allow a player to spawn other mobs + default: op + discosheep.admin.toggleonjoin: + description: Allow a player to toggle party-on-join functionality (force disable) + default: op + discosheep.party.lightning: + description: Allow a player to use lightning for parties + default: op + # FOR BACKWARDS COMPAT FROM 1.1 TO 1.1.1 + discosheep.party: + children: + discosheep.party.me: true + discosheep.partyall: + children: + discosheep.party.all: true + discosheep.reload: + children: + discoshep.admin.reload: true + discosheep.stopall: + children: + discosheep.admin.stopall: true \ No newline at end of file