diff --git a/src/ca/gibstick/discosheep/DiscoCommands.java b/src/ca/gibstick/discosheep/DiscoCommands.java index a4391a3..7bfa252 100644 --- a/src/ca/gibstick/discosheep/DiscoCommands.java +++ b/src/ca/gibstick/discosheep/DiscoCommands.java @@ -30,6 +30,7 @@ public class DiscoCommands { 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 PERMISSION_SHARED = "discosheep.party.shared"; static final String FLAGS = "n:t:p:r:lfg"; @@ -190,8 +191,7 @@ public class DiscoCommands { flags = FLAGS ) @CommandPermissions(value = PERMISSION_PARTY) - public static void partyCommand(final CommandContext args, CommandSender sender - ) { + 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; @@ -206,6 +206,32 @@ public class DiscoCommands { } } + @Command( + aliases = {"shared"}, + desc = "Start your own shared DiscoParty (other players can see the party)", + usage = "[optional flags]", + min = 0, + max = -1, + flags = FLAGS + ) + @CommandPermissions(value = PERMISSION_SHARED) + public static void partySharedCommand(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(); + party.setMainPlayer(player); + parsePartyFlags(party, args, sender); + party.getPlayers().addAll(plugin.getPlayersWithin(player, party.getRadius())); + 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 @@ -218,8 +244,7 @@ public class DiscoCommands { flags = FLAGS ) @CommandPermissions(value = PERMISSION_OTHER) - public static void partyOtherCommand(CommandContext args, CommandSender sender - ) { + public static void partyOtherCommand(CommandContext args, CommandSender sender) { DiscoParty party = new DiscoParty(); parsePartyFlags(party, args, sender); String players[] = args.getParsedSlice(0); diff --git a/src/ca/gibstick/discosheep/DiscoParty.java b/src/ca/gibstick/discosheep/DiscoParty.java index efa560b..9b0353c 100644 --- a/src/ca/gibstick/discosheep/DiscoParty.java +++ b/src/ca/gibstick/discosheep/DiscoParty.java @@ -1,12 +1,15 @@ package ca.gibstick.discosheep; import java.util.ArrayList; +import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Random; +import java.util.Set; import org.bukkit.Color; import org.bukkit.DyeColor; -import org.bukkit.Effect; +import org.bukkit.Material; import static org.bukkit.EntityEffect.*; import org.bukkit.FireworkEffect; import org.bukkit.FireworkEffect.Builder; @@ -15,6 +18,7 @@ import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; @@ -41,6 +45,20 @@ public class DiscoParty { static int maxPeriod = 40; // 2.0 seconds private static HashMap defaultGuestNumbers = new HashMap(); private static HashMap maxGuestNumbers = new HashMap(); + private static final EnumSet floorExceptions = EnumSet.of( + Material.STAINED_GLASS, + Material.FURNACE, + Material.CHEST, + Material.ENDER_CHEST, + Material.BURNING_FURNACE, + Material.ENDER_PORTAL, + Material.ENDER_PORTAL_FRAME, + Material.OBSIDIAN, + Material.BED, + Material.BED_BLOCK, + Material.SOIL + ); + private static final DyeColor[] discoColours = { DyeColor.RED, DyeColor.ORANGE, @@ -56,6 +74,7 @@ public class DiscoParty { DyeColor.BLACK, DyeColor.WHITE }; + private static final float[] pentatonicNotes = { 1.0f, 1.125f, @@ -68,9 +87,12 @@ public class DiscoParty { private Random r = new Random(); private PartyEvents partyEvents; private final DiscoSheep parent = DiscoSheep.getInstance(); - private Player player; + private ArrayList players = new ArrayList(); + private Player mainPlayer; private ArrayList sheepList = new ArrayList(); + private HashSet sheepSet = new HashSet(); private ArrayList guestList = new ArrayList(); + private HashSet guestSet = new HashSet(); private ArrayList floorBlockCache = new ArrayList(); private ArrayList floorBlocks = new ArrayList(); private HashMap guestNumbers = new HashMap(); @@ -83,7 +105,8 @@ public class DiscoParty { public DiscoParty(Player player) { this(); - this.player = player; + this.mainPlayer = player; + this.players.add(player); } public DiscoParty() { @@ -110,6 +133,14 @@ public class DiscoParty { return newParty; } + HashSet getSheepSet() { + return sheepSet; + } + + HashSet getGuestSet() { + return guestSet; + } + ArrayList getSheepList() { return sheepList; } @@ -126,6 +157,10 @@ public class DiscoParty { return this.floorBlocks; } + public int getRadius() { + return radius; + } + public static HashMap getDefaultGuestNumbers() { return defaultGuestNumbers; } @@ -142,13 +177,13 @@ public class DiscoParty { return this.sheep; } - public DiscoParty setPlayer(Player player) { - if (player != null) { - this.player = player; - return this; - } else { - throw new NullPointerException(); - } + public DiscoParty setMainPlayer(Player player) { + this.mainPlayer = player; + return this; + } + + public ArrayList getPlayers() { + return players; } public DiscoParty setDuration(int duration) throws IllegalArgumentException { @@ -243,11 +278,11 @@ public class DiscoParty { double azimuth = r.nextDouble() * 2 * Math.PI; // radians x += rand * Math.cos(azimuth); z += rand * Math.sin(azimuth); - y = this.player.getLocation().getY(); + y = this.mainPlayer.getLocation().getY(); loc = new Location(world, x, y, z); loc.setPitch(r.nextFloat() * 360 - 180); - loc.setYaw(0); + loc.setYaw(r.nextFloat() * 360 - 180); return loc; } @@ -255,10 +290,10 @@ public class DiscoParty { // Spawn some number of guests next to given player void spawnAll(int sheep, int spawnRadius) { Location loc; - World world = player.getWorld(); + World world = mainPlayer.getWorld(); - double x = player.getLocation().getX(); - double z = player.getLocation().getZ(); + double x = mainPlayer.getLocation().getX(); + double z = mainPlayer.getLocation().getZ(); for (int i = 0; i < sheep; i++) { loc = getRandomSpawnLocation(x, z, world, spawnRadius); spawnSheep(world, loc); @@ -275,7 +310,7 @@ public class DiscoParty { } } - loc = player.getLocation(); + loc = mainPlayer.getLocation(); this.spawnFloor(world, new Location(world, loc.getBlockX(), loc.getBlockY() - 1, loc.getBlockZ())); } @@ -284,8 +319,9 @@ public class DiscoParty { //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 - newSheep.setTarget(player); + newSheep.setTarget(this.mainPlayer); getSheepList().add(newSheep); + getSheepSet().add(newSheep); if (doLightning) { world.strikeLightningEffect(loc); } @@ -297,6 +333,7 @@ public class DiscoParty { void spawnGuest(World world, Location loc, EntityType type) { Entity newGuest = loc.getWorld().spawnEntity(loc, type); getGuestList().add(newGuest); + getGuestSet().add(newGuest); if (doLightning) { world.strikeLightningEffect(loc); } @@ -307,7 +344,9 @@ public class DiscoParty { for (int x = loc.getBlockX() - Math.min(this.radius, DiscoParty.maxFloorSize); x < loc.getX() + Math.min(this.radius, DiscoParty.maxFloorSize); ++x) { for (int z = loc.getBlockZ() - Math.min(this.radius, DiscoParty.maxFloorSize); z < loc.getZ() + Math.min(this.radius, DiscoParty.maxFloorSize); ++z) { Block block = world.getBlockAt(x, loc.getBlockY(), z); - if (block.getType() != Material.STAINED_GLASS) { + if (!DiscoParty.floorExceptions.contains(block.getType()) + && block.getRelative(BlockFace.UP).getType() == Material.AIR + && (block.getType().isSolid() || block.getType() == Material.AIR)) { this.getFloorCache().add(block.getState()); block.setType(Material.STAINED_GLASS); this.getFloorBlocks().add(block); @@ -324,11 +363,14 @@ public class DiscoParty { for (Entity guest : getGuestList()) { guest.remove(); } + for (BlockState block : this.floorBlockCache) { block.update(true); } getSheepList().clear(); getGuestList().clear(); + getSheepSet().clear(); + getGuestSet().clear(); floorBlockCache.clear(); } @@ -339,7 +381,6 @@ public class DiscoParty { void randomizeFloor(Block block, int index) { int to_color = (index + state) % discoColours.length; - block.setData(discoColours[to_color].getData()); } @@ -350,7 +391,6 @@ public class DiscoParty { entity.setVelocity(newVel); } - // WHY ISN'T THERE A Color.getValue() ?!?!?!?! private Color getColor(int i) { Color c = null; if (i == 1) { @@ -434,23 +474,26 @@ public class DiscoParty { } } } + for (int i = 0; i < this.floorBlocks.size(); i++) { this.randomizeFloor(floorBlocks.get(i), i); } } - private float getPentatonicNote() { + 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); - } + for (Player p : players) { + p.playSound(p.getLocation(), Sound.NOTE_BASS_DRUM, 0.75f, 1.0f); + if (this.state % 2 == 0) { + p.playSound(p.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); + if ((this.state + 1) % 8 == 0) { + p.playSound(p.getLocation(), Sound.NOTE_STICKS, 1.0f, 1.0f); + } } } @@ -504,7 +547,7 @@ public class DiscoParty { void startDisco() { this.spawnAll(sheep, radius); this.scheduleUpdate(); - parent.getPartyMap().put(this.player.getName(), this); + parent.getPartyMap().put(this.mainPlayer.getName(), this); // start listening this.partyEvents = new PartyEvents(this); parent.getServer().getPluginManager().registerEvents(this.partyEvents, this.parent); @@ -517,7 +560,7 @@ public class DiscoParty { updater.cancel(); } updater = null; - parent.getPartyMap().remove(this.player.getName()); + parent.getPartyMap().remove(this.mainPlayer.getName()); // stop listening HandlerList.unregisterAll(this.partyEvents); } diff --git a/src/ca/gibstick/discosheep/DiscoSheep.java b/src/ca/gibstick/discosheep/DiscoSheep.java index a21b251..d6d9077 100644 --- a/src/ca/gibstick/discosheep/DiscoSheep.java +++ b/src/ca/gibstick/discosheep/DiscoSheep.java @@ -7,11 +7,15 @@ 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.EnumSet; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; +import org.bukkit.Bukkit; import org.bukkit.ChatColor; +import org.bukkit.Material; import org.bukkit.command.Command; import org.bukkit.command.CommandException; import org.bukkit.command.CommandSender; @@ -107,6 +111,7 @@ public final class DiscoSheep extends JavaPlugin { getConfig().addDefault("max.guests." + ent.toString(), 5); } } + loadConfigFromDisk(); } @@ -184,6 +189,7 @@ public final class DiscoSheep extends JavaPlugin { if (this.hasParty(name)) { this.getParty(name).stopDisco(); } + } public void stopAllParties() { @@ -230,4 +236,16 @@ public final class DiscoSheep extends JavaPlugin { sender.sendMessage(ChatColor.RED + "You do not have the permission node " + ChatColor.GRAY + permission); return false; } + + // From user "desht" on bukkit forums + public List getPlayersWithin(Player player, int distance) { + List res = new ArrayList(); + int d2 = distance * distance; + for (Player p : Bukkit.getServer().getOnlinePlayers()) { + if (p.getWorld() == player.getWorld() && p.getLocation().distanceSquared(player.getLocation()) <= d2) { + res.add(p); + } + } + return res; + } } diff --git a/src/ca/gibstick/discosheep/PartyEvents.java b/src/ca/gibstick/discosheep/PartyEvents.java index 821fa33..ac807c4 100644 --- a/src/ca/gibstick/discosheep/PartyEvents.java +++ b/src/ca/gibstick/discosheep/PartyEvents.java @@ -1,5 +1,7 @@ package ca.gibstick.discosheep; +import org.bukkit.Instrument; +import org.bukkit.Sound; import org.bukkit.entity.Sheep; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -35,7 +37,7 @@ public class PartyEvents implements Listener { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onPlayerShear(PlayerShearEntityEvent e) { if (e.getEntity() instanceof Sheep) { - if (party.getSheepList().contains((Sheep) e.getEntity())) { + if (party.getSheepSet().contains((Sheep) e.getEntity())) { e.setCancelled(true); } } @@ -45,12 +47,12 @@ public class PartyEvents implements Listener { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onLivingEntityDamageEvent(EntityDamageEvent e) { if (e.getEntity() instanceof Sheep) { - if (party.getSheepList().contains((Sheep) e.getEntity())) { + if (party.getSheepSet().contains((Sheep) e.getEntity())) { party.jump(e.getEntity()); // for kicks e.setCancelled(true); } } - if (party.getGuestList().contains(e.getEntity())) { + if (party.getGuestSet().contains(e.getEntity())) { party.jump(e.getEntity()); e.setCancelled(true); } @@ -59,7 +61,7 @@ public class PartyEvents implements Listener { // prevent uninvited guests from targetting players @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onEntityTargetLivingEntityEvent(EntityTargetEvent e) { - if (party.getGuestList().contains(e.getEntity())) { + if (party.getGuestSet().contains(e.getEntity())) { e.setCancelled(true); } } @@ -67,15 +69,16 @@ public class PartyEvents implements Listener { // 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())) { + if (party.getSheepSet().contains(e.getRightClicked()) || party.getGuestSet().contains(e.getRightClicked())) { e.setCancelled(true); + e.getPlayer().playSound(e.getRightClicked().getLocation(), Sound.NOTE_BASS_GUITAR, 1.0f, party.getPentatonicNote()); } } // 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())) { + if (party.getSheepSet().contains(e.getEntity()) || party.getGuestSet().contains(e.getEntity())) { e.setCancelled(true); } }