Merge pull request #4 from Gibstick/DiscoFix2

merge DiscoFix2
This commit is contained in:
Charlie 2014-07-30 17:26:20 -04:00
commit 02f89c330e
15 changed files with 1548 additions and 1146 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target/
*.jar

View File

@ -1,10 +1,13 @@
DiscoSheep 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### ###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/)### ###[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 See BukkitDev, or https://github.com/Gibstick/DiscoSheep/releases
###License### ###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 Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

32
nb-configuration.xml Normal file
View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<netbeans.hint.license>mit</netbeans.hint.license>
<org-netbeans-modules-editor-indent.text.x-fortran.CodeStyle.project.text-limit-width>132</org-netbeans-modules-editor-indent.text.x-fortran.CodeStyle.project.text-limit-width>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.text-line-wrap>none</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.text-line-wrap>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.indent-shift-width>4</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.indent-shift-width>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaces-per-tab>4</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaces-per-tab>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.tab-size>4</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.tab-size>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.text-limit-width>80</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.text-limit-width>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.expand-tabs>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.expand-tabs>
<org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap>none</org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap>
<org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width>4</org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width>
<org-netbeans-modules-editor-indent.CodeStyle.project.spaces-per-tab>4</org-netbeans-modules-editor-indent.CodeStyle.project.spaces-per-tab>
<org-netbeans-modules-editor-indent.CodeStyle.project.tab-size>4</org-netbeans-modules-editor-indent.CodeStyle.project.tab-size>
<org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width>80</org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width>
<org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs>true</org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs>
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
</properties>
</project-shared-configuration>

105
pom.xml Normal file
View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ca.gibstick</groupId>
<artifactId>DiscoSheep</artifactId>
<version>1.1.2</version>
<packaging>jar</packaging>
<repositories>
<repository>
<id>bukkit-repo</id>
<url>http://repo.bukkit.org/content/groups/public/</url>
</repository>
<repository>
<id>repo.oc.tc</id>
<url>http://repo.oc.tc/content/repositories/public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<scope>provided</scope>
<version>1.7.9-R0.2</version>
</dependency>
<dependency>
<groupId>com.sk89q</groupId>
<artifactId>command-framework-bukkit</artifactId>
<version>0.5-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<finalName>DiscoSheep</finalName>
<sourceDirectory>src/main/java</sourceDirectory>
<resources>
<resource>
<targetPath>.</targetPath>
<filtering>true</filtering>
<directory>src/main/resources/</directory>
<includes>
<include>plugin.yml</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<compilerArgs>
<arg>-Xlint:deprecation</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>DiscoSheep</finalName>
<useBaseVersion>true</useBaseVersion>
<shadedClassifierName/>
<outputDirectory>${project.basedir}</outputDirectory>
<artifactSet>
<includes>
<include>com.sk89q:command-framework-bukkit</include>
</includes>
</artifactSet>
<generateUniqueDependencyReducedPom>false</generateUniqueDependencyReducedPom>
<shadedArtifactAttached>true</shadedArtifactAttached> <!-- Makes Netbeans shut up -->
<shadedClassifierName>shaded</shadedClassifierName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<name>DiscoSheep</name>
</project>

View File

@ -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<String, Integer> defaultGuestNumbers = new HashMap<String, Integer>();
private static HashMap<String, Integer> maxGuestNumbers = new HashMap<String, Integer>();
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<Sheep> sheepList = new ArrayList<Sheep>();
private ArrayList<Entity> guestList = new ArrayList<Entity>();
private ArrayList<BlockState> floorBlockCache = new ArrayList<BlockState>();
private ArrayList<Block> floorBlocks = new ArrayList<Block>();
private HashMap<String, Integer> guestNumbers = new HashMap<String, Integer>();
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<String, Integer>(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<Sheep> getSheepList() {
return sheepList;
}
ArrayList<Entity> getGuestList() {
return guestList;
}
ArrayList<BlockState> getFloorCache() {
return this.floorBlockCache;
}
ArrayList<Block> getFloorBlocks() {
return this.floorBlocks;
}
public static HashMap<String, Integer> getDefaultGuestNumbers() {
return defaultGuestNumbers;
}
public HashMap<String, Integer> getGuestNumbers() {
return guestNumbers;
}
public static HashMap<String, Integer> 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<String, Integer>(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();
}
}
}

View File

@ -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<String, DiscoParty> parties = new HashMap<String, DiscoParty>();
@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<String, Integer> 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<String, DiscoParty> getPartyMap() {
return this.parties;
}
public synchronized ArrayList<DiscoParty> getParties() {
return new ArrayList<DiscoParty>(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 <players>: 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 <integer>: set the number of sheep per player that spawn\n"
+ "-t <integer>: set the party duration in seconds\n"
+ "-p <ticks>: set the number of ticks between each disco beat\n"
+ "-r <integer>: set radius of the area in which sheep can spawn\n"
+ "-g <mob> <number>: 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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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 <players>: 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 <integer>: set the number of sheep per player that spawn\n"
+ "-t <seconds>: set the party duration in seconds\n"
+ "-p <ticks>: set the number of ticks between each disco beat\n"
+ "-r <radius>: set radius of the area in which sheep can spawn\n"
+ "-g <mob> <number>: 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");
}
}

View File

@ -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<String, Integer> defaultGuestNumbers = new HashMap<String, Integer>();
private static HashMap<String, Integer> maxGuestNumbers = new HashMap<String, Integer>();
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<Sheep> sheepList = new ArrayList<Sheep>();
private ArrayList<Entity> guestList = new ArrayList<Entity>();
private ArrayList<BlockState> floorBlockCache = new ArrayList<BlockState>();
private ArrayList<Block> floorBlocks = new ArrayList<Block>();
private HashMap<String, Integer> guestNumbers = new HashMap<String, Integer>();
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<String, Integer>(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<Sheep> getSheepList() {
return sheepList;
}
ArrayList<Entity> getGuestList() {
return guestList;
}
ArrayList<BlockState> getFloorCache() {
return this.floorBlockCache;
}
ArrayList<Block> getFloorBlocks() {
return this.floorBlocks;
}
public static HashMap<String, Integer> getDefaultGuestNumbers() {
return defaultGuestNumbers;
}
public HashMap<String, Integer> getGuestNumbers() {
return guestNumbers;
}
public static HashMap<String, Integer> 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<String, Integer>(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();
}
}
}

View File

@ -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<String, DiscoParty> parties = new HashMap<String, DiscoParty>();
private CommandsManager<CommandSender> commands;
public static DiscoSheep getInstance() {
if (instance == null) {
instance = new DiscoSheep();
return instance;
}
return instance;
}
private void setupCommands() {
this.commands = new CommandsManager<CommandSender>() {
@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<String, Integer> 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<String, DiscoParty> getPartyMap() {
return this.parties;
}
public synchronized ArrayList<DiscoParty> getParties() {
return new ArrayList<DiscoParty>(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 <players>: 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 <integer>: set the number of sheep per player that spawn\n"
+ "-t <integer>: set the party duration in seconds\n"
+ "-p <ticks>: set the number of ticks between each disco beat\n"
+ "-r <integer>: set radius of the area in which sheep can spawn\n"
//+ "-g <mob> <number>: 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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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: |
#<command> <subcommand> [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