Updated to v3

Added all the files
This commit is contained in:
Esophose 2016-05-09 09:07:15 -06:00
parent 9f264fe5a5
commit a851ee037d
16 changed files with 2699 additions and 27 deletions

5
.gitattributes vendored
View file

@ -3,6 +3,11 @@
# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
# Standard to msysgit
*.doc diff=astextplain

60
.gitignore vendored
View file

@ -1,35 +1,41 @@
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
# =========================
# Operating System Files
# =========================
# OSX
# =========================
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# =========================
# Operating System Files
# =========================
# OSX
# =========================
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
._*
# Personal stuff
*.project
*.classpath
/bin
/.settings
# Files that might appear on external disk
.Spotlight-V100

View file

@ -0,0 +1,186 @@
/**
* Copyright Esophose 2016
* While using any of the code provided by this plugin
* you must not claim it as your own. This plugin may
* be modified and installed on a server, but may not
* be distributed to any person by any means.
*/
package com.esophose.playerparticles;
import java.io.File;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import com.esophose.playerparticles.libraries.particles.ParticleEffect.ParticleType;
public class ConfigManager {
private static ConfigManager instance = new ConfigManager("effectData");
private static ConfigManager styleInstance = new ConfigManager("styleData");
private File file;
private FileConfiguration config;
public static ConfigManager getInstance() {
return instance;
}
public static ConfigManager getStyleInstance() {
return styleInstance;
}
private ConfigManager(String fileName) {
if (!PlayerParticles.getPlugin().getDataFolder().exists()) PlayerParticles.getPlugin().getDataFolder().mkdir();
file = new File(PlayerParticles.getPlugin().getDataFolder(), fileName + ".yml");
if (!file.exists()) {
try { file.createNewFile(); }
catch (Exception e) { e.printStackTrace(); }
}
config = YamlConfiguration.loadConfiguration(file);
}
public void flushData() {
for(String key : config.getKeys(false)) {
config.set(key, null);
}
try {config.save(file);}
catch (IOException e) {e.printStackTrace();}
}
public static void flushDatabase() {
if(PlayerParticles.useMySQL) {
Statement statement;
try {
statement = PlayerParticles.c.createStatement();
statement.executeUpdate("TRUNCATE playerparticles;");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public void setParticle(ParticleType type, Player player){
if(PlayerParticles.useMySQL) {
Statement statement;
try {
statement = PlayerParticles.c.createStatement();
statement.executeUpdate("UPDATE playerparticles SET particle = '" + type.toString().toLowerCase().replace("_", "") + "' WHERE player_name = '" + player.getName() + "';");
} catch (SQLException e) {
e.printStackTrace();
}
}else{
config.set(player.getName(), type.toString().toLowerCase().replace("_", ""));
try {config.save(file);}
catch (IOException e) {e.printStackTrace();}
}
}
public void resetParticle(Player player){
if(PlayerParticles.useMySQL) {
Statement statement;
try {
statement = PlayerParticles.c.createStatement();
statement.executeUpdate("UPDATE playerparticles SET particle = NULL WHERE player_name = '" + player.getName() + "';");
} catch (SQLException e) {
e.printStackTrace();
}
}else{
config.set(player.getName(), ParticleStyle.NONE.toString().toLowerCase().replace("_", ""));
try {config.save(file);}
catch (IOException e) {e.printStackTrace();}
}
}
public ParticleType getParticle(Player player){
if(PlayerParticles.useMySQL) {
Statement statement;
try {
statement = PlayerParticles.c.createStatement();
ResultSet res = statement.executeQuery("SELECT * FROM playerparticles WHERE player_name = '" + player.getName() + "';");
res.next();
return ParticleCreator.particleFromString(res.getString("particle"));
} catch (SQLException e) {
e.printStackTrace();
}
}else{
String effectToLowerCase = (String) config.getString(player.getName());
return ParticleCreator.particleFromString(effectToLowerCase);
}
return null;
}
public void setStyle(ParticleStyle style, Player player) {
if(PlayerParticles.useMySQL) {
Statement statement;
try {
statement = PlayerParticles.c.createStatement();
statement.executeUpdate("UPDATE playerparticles SET style = '" + style.toString().toLowerCase().replace("_", "") + "' WHERE player_name = '" + player.getName() + "';");
} catch (SQLException e) {
e.printStackTrace();
}
}else{
config.set(player.getName(), style.toString().toLowerCase().replace("_", ""));
try {config.save(file);}
catch (IOException e) {e.printStackTrace();}
}
}
public void resetStyle(Player player) {
if(PlayerParticles.useMySQL) {
Statement statement;
try {
statement = PlayerParticles.c.createStatement();
statement.executeUpdate("UPDATE playerparticles SET style = '" + ParticleStyle.NONE.toString().toLowerCase().replace("_", "") + "' WHERE player_name = '" + player.getName() + "';");
} catch (SQLException e) {
e.printStackTrace();
}
}else{
config.set(player.getName(), ParticleStyle.NONE.toString().toLowerCase().replace("_", ""));
try {config.save(file);}
catch (IOException e) {e.printStackTrace();}
}
}
public ParticleStyle getStyle(Player player) {
if(PlayerParticles.useMySQL) {
Statement statement;
try {
statement = PlayerParticles.c.createStatement();
ResultSet res = statement.executeQuery("SELECT * FROM playerparticles WHERE player_name = '" + player.getName() + "';");
res.next();
return ParticleStyle.styleFromString(res.getString("style"));
} catch (SQLException e) {
e.printStackTrace();
}
}else{
String styleToLowerCase = (String) config.getString(player.getName());
return ParticleStyle.styleFromString(styleToLowerCase);
}
return ParticleStyle.NONE;
}
@SuppressWarnings("unchecked")
public boolean isWorldDisabled(String world) {
if(PlayerParticles.getPlugin().getConfig().get("disabled-worlds") != null && ((ArrayList<String>) PlayerParticles.getPlugin().getConfig().get("disabled-worlds")).contains(world)) {
return true;
}else return false;
}
@SuppressWarnings("unchecked")
public ArrayList<String> getDisabledWorlds() {
if(PlayerParticles.getPlugin().getConfig().get("disabled-worlds") != null) {
return ((ArrayList<String>) PlayerParticles.getPlugin().getConfig().get("disabled-worlds"));
}else return null;
}
}

View file

@ -0,0 +1,54 @@
/**
* Copyright Esophose 2016
* While using any of the code provided by this plugin
* you must not claim it as your own. This plugin may
* be modified and installed on a server, but may not
* be distributed to any person by any means.
*/
package com.esophose.playerparticles;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
public class MessageManager {
private static MessageManager instance = new MessageManager();
private boolean messagesEnabled, prefix, checkForUpdates;
private String messagePrefix;
private MessageManager() {
messagesEnabled = PlayerParticles.getPlugin().getConfig().getBoolean("messages-enabled");
prefix = PlayerParticles.getPlugin().getConfig().getBoolean("use-message-prefix");
messagePrefix = PlayerParticles.getPlugin().getConfig().getString("message-prefix");
messagePrefix = messagePrefix.replace("&", "§");
checkForUpdates = PlayerParticles.getPlugin().getConfig().getBoolean("check-updates");
}
public void reload() {
messagesEnabled = PlayerParticles.getPlugin().getConfig().getBoolean("messages-enabled");
prefix = PlayerParticles.getPlugin().getConfig().getBoolean("use-message-prefix");
messagePrefix = PlayerParticles.getPlugin().getConfig().getString("message-prefix");
messagePrefix = messagePrefix.replace("&", "§");
checkForUpdates = PlayerParticles.getPlugin().getConfig().getBoolean("check-updates");
}
public static MessageManager getInstance() {
return instance;
}
public boolean shouldCheckUpdates() {
return checkForUpdates;
}
public void sendMessage(Player player, String message, ChatColor color) {
if(!messagesEnabled) return;
if(this.prefix){
message = messagePrefix + color + " " + message;
}else{
message = color + message;
}
player.sendMessage(message);
}
}

View file

@ -0,0 +1,50 @@
/**
* Copyright Esophose 2016
* While using any of the code provided by this plugin
* you must not claim it as your own. This plugin may
* be modified and installed on a server, but may not
* be distributed to any person by any means.
*/
package com.esophose.playerparticles;
import java.util.List;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
public class ParticleCommandCompleter implements TabCompleter {
@Override
public List<String> onTabComplete(CommandSender sender, Command cmd, String alias, String[] args) {
if(cmd.getName().equalsIgnoreCase("pp")) {
if(args.length == 1) {
List<String> list = PermissionHandler.getParticlesUserHasPermissionFor((Player)sender);
if(PermissionHandler.canReload((Player)sender)) list.add("reload");
list.add("list");
list.add("styles");
list.add("style");
list.add("version");
list.add("worlds");
list.add("help");
return list;
}
if(args.length == 2) {
return PermissionHandler.getStylesUserHasPermissionFor((Player)sender);
}
}
return null;
}
}

View file

@ -0,0 +1,446 @@
/**
* Copyright Esophose 2016
* While using any of the code provided by this plugin
* you must not claim it as your own. This plugin may
* be modified and installed on a server, but may not
* be distributed to any person by any means.
*/
package com.esophose.playerparticles;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.scheduler.BukkitRunnable;
import com.esophose.playerparticles.libraries.particles.ParticleEffect;
import com.esophose.playerparticles.libraries.particles.ParticleEffect.ParticleType;
public class ParticleCreator extends BukkitRunnable implements Listener {
private static HashMap<String, ParticleType> map = new HashMap<String, ParticleType>();
private static HashMap<String, ParticleStyle> styleMap = new HashMap<String, ParticleStyle>();
private double step = 0;
private double helixStep = 0;
private double helixYStep = 0;
private boolean reverse = false;
private double mysqltimer = 0;
@EventHandler
public void onPlayerJoin(PlayerJoinEvent e){
if(PlayerParticles.useMySQL) {
Statement s = null;
Statement statement = null;
ResultSet res = null;
try {
s = PlayerParticles.c.createStatement();
res = s.executeQuery("SELECT * FROM playerparticles WHERE player_name = '" + e.getPlayer().getName() + "';");
if(!res.next()) {
statement = PlayerParticles.c.createStatement();
statement.executeUpdate("INSERT INTO playerparticles SET player_name = '" + e.getPlayer().getName() + "', particle = NULL, style = 'none';");
System.out.println("New player added to PlayerParticles database: " + e.getPlayer().getName());
}
} catch (SQLException e2) {
e2.printStackTrace();
} finally {
if(s != null) try { s.close(); } catch (SQLException e1) { e1.printStackTrace(); }
if(statement != null) try { statement.close(); } catch (SQLException e1) { e1.printStackTrace(); }
if(res != null) try { res.close(); } catch (SQLException e1) { e1.printStackTrace(); }
}
}
if(ConfigManager.getInstance().getParticle(e.getPlayer()) == null) return;
map.put(e.getPlayer().getName(), ConfigManager.getInstance().getParticle(e.getPlayer()));
styleMap.put(e.getPlayer().getName(), ConfigManager.getStyleInstance().getStyle(e.getPlayer()));
updateMap();
updateStyleMap();
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent e){
if(map.containsKey(e.getPlayer().getName())){
map.remove(e.getPlayer().getName());
}
if(styleMap.containsKey(e.getPlayer().getName())) {
styleMap.remove(e.getPlayer().getName());
}
}
@EventHandler
public void onPlayerMove(PlayerMoveEvent e) {
if(map.containsKey(e.getPlayer().getName()) && styleMap.get(e.getPlayer().getName()) == ParticleStyle.MOVE) {
Location loc = e.getPlayer().getLocation();
loc.setY(loc.getY() + 1);
handleStyleNone(map.get(e.getPlayer().getName()), loc);
}
}
public static void addMap(Player player, ParticleType effect){
map.remove(player.getName());
map.put(player.getName(), effect);
}
public static void removeMap(Player player){
map.remove(player.getName());
}
public static void updateMap(){
map.clear();
for(Player player : Bukkit.getOnlinePlayers()){
if(ConfigManager.getInstance().getParticle(player) == null) continue;
map.put(player.getName(), ConfigManager.getInstance().getParticle(player));
}
}
public static void addStyleMap(Player player, ParticleStyle style) {
styleMap.remove(player.getName());
styleMap.put(player.getName(), style);
}
public static void removeStyleMap(Player player){
styleMap.remove(player.getName());
}
public static void updateStyleMap(){
styleMap.clear();
for(Player player : Bukkit.getOnlinePlayers()){
styleMap.put(player.getName(), ConfigManager.getStyleInstance().getStyle(player));
}
}
public static ParticleType particleFromString(String particle){
for(ParticleType effect : ParticleType.values()){
if(effect.toString().toLowerCase().replace("_", "").equals(particle)) return effect;
}
return null;
}
@Override
public void run() {
step++;
if(step > 30) {
step = 0;
}
helixStep++;
if(helixStep > 90) {
helixStep = 0;
}
if(reverse) {
helixYStep++;
if(helixYStep > 60) reverse = false;
}else{
helixYStep--;
if(helixYStep < -60) reverse = true;
}
if(PlayerParticles.useMySQL) {
mysqltimer++;
if(mysqltimer > 600) {
try {
if(PlayerParticles.c != null && PlayerParticles.c.isClosed()) {
PlayerParticles.c = PlayerParticles.mySQL.openConnection();
if(PlayerParticles.c.isClosed()) {
System.out.println("[PlayerParticles] Cannot connect to database! Is the database available and is your connection information correct?");
}
}
} catch (SQLException | ClassNotFoundException e) {
e.printStackTrace();
}
mysqltimer = 0;
}
}
for(Player player : Bukkit.getOnlinePlayers()){
if(!map.containsKey(player.getName()) || ConfigManager.getInstance().isWorldDisabled(player.getWorld().getName())) continue;
ParticleType effect = map.get(player.getName());
if(PermissionHandler.hasPermission(player, effect)){
Location loc = player.getLocation();
loc.setY(loc.getY() + 1);
displayParticle(effect, styleMap.get(player.getName()), loc);
}
}
}
private void displayParticle(ParticleType effect, ParticleStyle style, Location location){
if(style == null || style == ParticleStyle.NONE) {
handleStyleNone(effect, location);
}else if(style == ParticleStyle.SPIRAL) {
ParticleEffect particle = null;
if(effect == ParticleType.RAINBOW || effect == ParticleType.NOTE) particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 1.0F, 1);
else particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 0.0F, 1);
int points = 16;
double radius = 1;
double slice = 2 * Math.PI / points;
for(int i = 0; i < points; i++) {
double angle = slice * i;
double newX = location.getX() + radius * Math.cos(angle);
double newY = location.getY() + (step / 10) - 1;
double newZ = location.getZ() + radius * Math.sin(angle);
Location newLocation = new Location(location.getWorld(), newX, newY, newZ);
particle.display(newLocation);
}
return;
}else if(style == ParticleStyle.HALO) {
if(step % 2 == 0) return;
ParticleEffect particle = null;
if(effect == ParticleType.RAINBOW || effect == ParticleType.NOTE) particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 1.0F, 1);
else particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 0.0F, 1);
int points = 16;
double radius = .65;
double slice = 2 * Math.PI / points;
for(int i = 0; i < points; i++) {
double angle = slice * i;
double newX = location.getX() + radius * Math.cos(angle);
double newY = location.getY() + 1.5;
double newZ = location.getZ() + radius * Math.sin(angle);
Location newLocation = new Location(location.getWorld(), newX, newY, newZ);
particle.display(newLocation);
}
return;
}else if(style == ParticleStyle.POINT) {
ParticleEffect particle = null;
if(effect == ParticleType.RAINBOW || effect == ParticleType.NOTE) particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 1.0F, 1);
else particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 0.0F, 1);
particle.display(location.add(0.0, 1.5, 0.0));
return;
}else if(style == ParticleStyle.SPIN) {
ParticleEffect particle = null;
if(effect == ParticleType.RAINBOW || effect == ParticleType.NOTE) particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 1.0F, 1);
else particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 0.0F, 1);
int points = 15;
double radius = .5;
double slice = 2 * Math.PI / points;
double angle = slice * (step % 15);
double newX = location.getX() + radius * Math.cos(angle);
double newY = location.getY() + 1.5;
double newZ = location.getZ() + radius * Math.sin(angle);
Location newLocation = new Location(location.getWorld(), newX, newY, newZ);
particle.display(newLocation);
}else if(style == ParticleStyle.QUADHELIX) {
ParticleEffect particle = null;
if(effect == ParticleType.RAINBOW || effect == ParticleType.NOTE) particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 1.0F, 1);
else particle = new ParticleEffect(effect, 0.0F, 0.0F, 0.0F, 0.0F, 1);
for(int i = 0; i < 4; i++) {
double dx = -(Math.cos((helixStep / 90) * (Math.PI * 2) + ((Math.PI / 2) * i))) * ((60 - Math.abs(helixYStep)) / 60);
double dy = ((helixYStep) / 60) * 1.5;
double dz = -(Math.sin((helixStep / 90) * (Math.PI * 2) + ((Math.PI / 2) * i))) * ((60 - Math.abs(helixYStep)) / 60);
particle.display(new Location(location.getWorld(), location.getX() + dx, location.getY() + dy, location.getZ() + dz));
}
return;
}
}
public void handleStyleNone(ParticleType effect, Location location) {
if(effect == null || location == null) return;
if(effect.equals(ParticleType.ANGRY_VILLAGER)){
ParticleEffect particle = new ParticleEffect(effect, 0.6F, 0.6F, 0.6F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.BUBBLE)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.CLOUD)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.CRIT)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.DEPTH_SUSPEND)){
ParticleEffect particle = new ParticleEffect(effect, 0.5F, 0.5F, 0.5F, 0.0F, 5);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.DRIP_LAVA)){
ParticleEffect particle = new ParticleEffect(effect, 0.6F, 0.6F, 0.6F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.DRIP_WATER)){
ParticleEffect particle = new ParticleEffect(effect, 0.6F, 0.6F, 0.6F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.ENCHANTMENT_TABLE)){
ParticleEffect particle = new ParticleEffect(effect, 0.6F, 0.6F, 0.6F, 0.05F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.EXPLODE)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.FIREWORKS_SPARK)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.FLAME)){
ParticleEffect particle = new ParticleEffect(effect, 0.1F, 0.1F, 0.1F, 0.05F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.FOOTSTEP)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.0F, 0.4F, 0.0F, 1);
particle.display(location.subtract(0, 0.98, 0));
return;
}else
if(effect.equals(ParticleType.HAPPY_VILLAGER)){
ParticleEffect particle = new ParticleEffect(effect, 0.5F, 0.5F, 0.5F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.HEART)){
ParticleEffect particle = new ParticleEffect(effect, 0.6F, 0.6F, 0.6F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.HUGE_EXPLOSION)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.INSTANT_SPELL)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.LARGE_EXPLODE)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.LARGE_SMOKE)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.LAVA)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.MAGIC_CRIT)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.MOB_SPELL)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.MOB_SPELL_AMBIENT)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.NOTE)){
ParticleEffect particle = new ParticleEffect(effect, 0.6F, 0.6F, 0.6F, 1.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.PORTAL)){
ParticleEffect particle = new ParticleEffect(effect, 0.5F, 0.5F, 0.5F, 0.05F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.RAINBOW)){
ParticleEffect particle = new ParticleEffect(effect, 0.5F, 0.5F, 0.5F, 1.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.RED_DUST)){
ParticleEffect particle = new ParticleEffect(effect, 0.5F, 0.5F, 0.5F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.SLIME)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.SMOKE)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.SNOW_SHOVEL)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.SNOWBALL_POOF)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.SPELL)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.SUSPENDED)){
ParticleEffect particle = new ParticleEffect(effect, 0.8F, 0.8F, 0.8F, 0.0F, 5);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.WAKE)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 3);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.WITCH_MAGIC)){
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.BARRIER)){
ParticleEffect particle = new ParticleEffect(effect, 1.2F, 1.2F, 1.2F, 0.0F, 1);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.DROPLET)){
ParticleEffect particle = new ParticleEffect(effect, 0.8F, 0.8F, 0.8F, 0.0F, 5);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.DRAGON_BREATH)) {
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 5);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.END_ROD)) {
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 5);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.DAMAGE_INDICATOR)) {
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 5);
particle.display(location);
return;
}else
if(effect.equals(ParticleType.SWEEP_ATTACK)) {
ParticleEffect particle = new ParticleEffect(effect, 0.4F, 0.4F, 0.4F, 0.0F, 5);
particle.display(location);
return;
}
}
}

View file

@ -0,0 +1,28 @@
/**
* Copyright Esophose 2016
* While using any of the code provided by this plugin
* you must not claim it as your own. This plugin may
* be modified and installed on a server, but may not
* be distributed to any person by any means.
*/
package com.esophose.playerparticles;
public enum ParticleStyle {
NONE,
SPIRAL,
HALO,
POINT,
MOVE,
SPIN,
QUADHELIX;
public static ParticleStyle styleFromString(String particle){
for(ParticleStyle style : ParticleStyle.values()){
if(style.toString().toLowerCase().replace("_", "").equals(particle)) return style;
}
return ParticleStyle.NONE;
}
}

View file

@ -0,0 +1,77 @@
/**
* Copyright Esophose 2016
* While using any of the code provided by this plugin
* you must not claim it as your own. This plugin may
* be modified and installed on a server, but may not
* be distributed to any person by any means.
*/
package com.esophose.playerparticles;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.entity.Player;
import com.esophose.playerparticles.libraries.particles.ParticleEffect.ParticleType;
public class PermissionHandler {
public static boolean hasPermission(Player player, ParticleType effect) {
if(player.hasPermission("playerparticles.*") || player.hasPermission("playerparticles.particles.*")) return true;
if(effect.equals(ParticleType.RED_DUST) && player.hasPermission("playerparticles.reddust")) {
return true;
}else{
if(effect.equals(ParticleType.RED_DUST)) return false;
}
if(effect.equals(ParticleType.RAINBOW) && player.hasPermission("playerparticles.rainbow")) {
return true;
}else{
if(effect.equals(ParticleType.RAINBOW)) return false;
}
if(player.hasPermission("playerparticles." + effect.getName().toLowerCase().replace("_", ""))) return true;
return false;
}
public static boolean hasStylePermission(Player player, ParticleStyle style) {
if(player.hasPermission("playerparticles.*") || player.hasPermission("playerparticles.styles.*") || style == ParticleStyle.NONE) return true;
if(player.hasPermission("playerparticles.style." + style.toString().toLowerCase().replace("_", ""))) return true;
return false;
}
public static List<String> getParticlesUserHasPermissionFor(Player p) {
List<String> list = new ArrayList<String>();
if(p.hasPermission("playerparticles.*") || p.hasPermission("playerparticles.particles.*")) {
for(ParticleType pt : ParticleType.values()) {
list.add(pt.toString().toLowerCase().replace("_", ""));
}
}else{
for(ParticleType pt : ParticleType.values()) {
if(p.hasPermission("playerparticles." + pt.toString().toLowerCase().replace("_", ""))) list.add(pt.toString().toLowerCase().replace("_", ""));
}
}
return list;
}
public static List<String> getStylesUserHasPermissionFor(Player p) {
List<String> list = new ArrayList<String>();
if(p.hasPermission("playerparticles.*") || p.hasPermission("playerparticles.styles.*")) {
for(ParticleStyle ps : ParticleStyle.values()) {
list.add(ps.toString().toLowerCase());
}
}else{
for(ParticleStyle pt : ParticleStyle.values()) {
if(p.hasPermission("playerparticles.style." + pt.toString().toLowerCase())) list.add(pt.toString().toLowerCase());
}
}
return list;
}
public static boolean canReload(Player p) {
if(p.hasPermission("playerparticles.reload") || p.hasPermission("playerparticles.*")) {
return true;
}
return false;
}
}

View file

@ -0,0 +1,218 @@
/**
* Copyright Esophose 2016
* While using any of the code provided by this plugin
* you must not claim it as your own. This plugin may
* be modified and installed on a server, but may not
* be distributed to any person by any means.
*/
// Fixed worlds missing from /pp help
// Add style "feet"
package com.esophose.playerparticles;
import java.io.File;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import com.esophose.playerparticles.libraries.databases.MySQL;
import com.esophose.playerparticles.libraries.particles.ParticleEffect.ParticleType;
import com.esophose.playerparticles.updater.PluginUpdateListener;
import com.esophose.playerparticles.updater.Updater;
public class PlayerParticles extends JavaPlugin {
public static String updateVersion = null;
public static MySQL mySQL = null;
public static Connection c = null;
public static boolean useMySQL = false;
public void onEnable(){
saveDefaultConfig();
getCommand("pp").setTabCompleter(new ParticleCommandCompleter());
Bukkit.getPluginManager().registerEvents(new ParticleCreator(), this);
Bukkit.getPluginManager().registerEvents(new PluginUpdateListener(), this);
if(getConfig().getDouble("version") < Double.parseDouble(getDescription().getVersion())){
File configFile = new File(getDataFolder(), "config.yml");
configFile.delete();
saveDefaultConfig();
reloadConfig();
getLogger().warning("config.yml has been updated!");
}
checkDatabase();
ParticleCreator.updateMap();
ParticleCreator.updateStyleMap();
startTasks();
// Check for an update
if(MessageManager.getInstance().shouldCheckUpdates()) {
Updater updater = new Updater(this, 82823, this.getFile(), Updater.UpdateType.NO_DOWNLOAD, false);
if(Double.parseDouble(updater.getLatestName().replaceAll("PlayerParticles v", "")) > Double.parseDouble(getPlugin().getDescription().getVersion())) {
updateVersion = updater.getLatestName().replaceAll("PlayerParticles v", "");
System.out.println("[PlayerParticles] An update (v" + updateVersion + ") is available! You are running v" + getPlugin().getDescription().getVersion());
}
}
}
public static Plugin getPlugin(){
return Bukkit.getPluginManager().getPlugin("PlayerParticles");
}
private void checkDatabase() {
if(getConfig().getBoolean("database-enable")) {
String hostname = getConfig().getString("database-hostname");
String port = getConfig().getString("database-port");
String database = getConfig().getString("database-name");
String user = getConfig().getString("database-user-name");
String pass = getConfig().getString("database-user-password");
mySQL = new MySQL(hostname, port, database, user, pass);
try {
c = mySQL.openConnection();
Statement statement = c.createStatement();
statement.executeUpdate("CREATE TABLE IF NOT EXISTS playerparticles (player_name VARCHAR(32), particle VARCHAR(32), style VARCHAR(32));");
useMySQL = true;
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
System.out.println("Failed to connect to MySQL Database! Check to see if your config is correct!");
useMySQL = false;
}
}else{
useMySQL = false;
}
System.out.println("[PlayerParticles] Using mySQL for data storage: " + useMySQL);
}
private void startTasks() {
double ticks = getConfig().getDouble("ticks-per-particle");
if(ticks == 0.5){
new ParticleCreator().runTaskTimer(this, 20, 1);
new ParticleCreator().runTaskTimer(this, 20, 1);
}else
new ParticleCreator().runTaskTimer(this, 20, (long) ticks);
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
Player p = (Player) sender;
if(args.length == 1 && args[0].equalsIgnoreCase("worlds")) {
String worlds = "";
if(ConfigManager.getInstance().getDisabledWorlds() == null) {
MessageManager.getInstance().sendMessage(p, ((String)getConfig().get("message-disabled-worlds-none")).replace("&", "§"), ChatColor.GREEN);
}
for(String s : ConfigManager.getInstance().getDisabledWorlds()) {
worlds += s + ", ";
}
if(worlds.length() > 2) worlds = worlds.substring(0, worlds.length() - 2);
if(worlds.equals("")) {
worlds = ((String)getConfig().get("message-disabled-worlds-none")).replace("&", "§");
}else{
worlds = ((String)getConfig().get("message-disabled-worlds")).replace("&", "§") + " " + ChatColor.AQUA + worlds;
}
MessageManager.getInstance().sendMessage(p, worlds, ChatColor.GREEN);
return true;
}
if(args.length > 1 && args[0].equalsIgnoreCase("style")) {
String argument = args[1].replace("_", "");
if(ParticleStyle.styleFromString(argument) != null){
ParticleStyle style = ParticleStyle.styleFromString(argument);
if(!PermissionHandler.hasStylePermission(p, style)) {
MessageManager.getInstance().sendMessage(p, ((String)getConfig().get("message-no-permission-style")).replace("{STYLE}", ChatColor.AQUA + style.toString().toLowerCase() + ChatColor.RED).replace("&", "§"), ChatColor.RED);
return true;
}
ConfigManager.getStyleInstance().setStyle(style, p);
ParticleCreator.addStyleMap(p, style);
MessageManager.getInstance().sendMessage(p, ((String)getConfig().get("message-now-using-style")).replace("{STYLE}", ChatColor.AQUA + style.toString().toLowerCase() + ChatColor.GREEN).replace("&", "§"), ChatColor.GREEN);
return true;
}
MessageManager.getInstance().sendMessage(p, ((String)getConfig().get("message-invalid-type-style")).replace("&", "§") + ChatColor.GREEN + " /pp styles", ChatColor.RED);
return true;
}
if(args.length != 1){
MessageManager.getInstance().sendMessage(p, ((String)getConfig().get("message-invalid-arguments")).replace("&", "§") + ChatColor.GREEN + " /pp list", ChatColor.RED);
return true;
}
String argument = args[0].replace("_", "");
if(ParticleCreator.particleFromString(argument) != null){
ParticleType effect = ParticleCreator.particleFromString(argument);
if(!PermissionHandler.hasPermission(p, effect)){
MessageManager.getInstance().sendMessage(p, ((String)getConfig().get("message-no-permission")).replace("{PARTICLE}", ChatColor.AQUA + (effect.equals(ParticleType.RAINBOW) ? "rainbow" : effect.getName().toLowerCase() + ChatColor.RED)).replace("&", "§"), ChatColor.RED);
return true;
}
ConfigManager.getInstance().setParticle(effect, p);
ParticleCreator.addMap(p, effect);
MessageManager.getInstance().sendMessage(p, ((String)getConfig().get("message-now-using")).replace("{PARTICLE}", ChatColor.AQUA + (effect.equals(ParticleType.RAINBOW) ? "rainbow" : effect.getName().toLowerCase() + ChatColor.GREEN)).replace("&", "§"), ChatColor.GREEN);
return true;
}
if(argument.equalsIgnoreCase("clear")) {
ConfigManager.getInstance().resetParticle(p);
ParticleCreator.removeMap(p);
MessageManager.getInstance().sendMessage(p, ((String)getConfig().get("message-cleared-particles")).replace("&", "§"), ChatColor.GREEN);
return true;
}
if(argument.equalsIgnoreCase("version")) {
MessageManager.getInstance().sendMessage(p, "Running PlayerParticles v" + getDescription().getVersion(), ChatColor.GOLD);
MessageManager.getInstance().sendMessage(p, "Plugin created by: Esophose", ChatColor.GOLD);
return true;
}
if(argument.equalsIgnoreCase("help")) {
MessageManager.getInstance().sendMessage(p, ((String)getConfig().get("message-available-commands")).replace("&", "§"), ChatColor.GREEN);
MessageManager.getInstance().sendMessage(p, "list, styles, style, worlds, version, help", ChatColor.AQUA);
MessageManager.getInstance().sendMessage(p, ((String)getConfig().get("message-usage")).replace("&", "§") + ChatColor.AQUA + " /pp <Command>", ChatColor.YELLOW);
return true;
}
if(argument.equalsIgnoreCase("list")) {
String toSend = ((String)getConfig().get("message-use")).replace("&", "§") + " ";
for(ParticleType effect : ParticleType.values()){
if(PermissionHandler.hasPermission(p, effect)){
toSend = toSend + (effect.equals(ParticleType.RAINBOW) ? "rainbow" : effect.getName().toLowerCase()) + ", ";
continue;
}
}
if(toSend.equals(getConfig().get("message-use") + " ")){
MessageManager.getInstance().sendMessage(p, ((String)getConfig().get("message-no-particles")).replace("&", "§"), ChatColor.RED);
return true;
}
toSend = toSend + "clear";
MessageManager.getInstance().sendMessage(p, toSend, ChatColor.GREEN);
MessageManager.getInstance().sendMessage(p, ((String)getConfig().get("message-usage")).replace("&", "§") + ChatColor.AQUA + " /pp <Type>", ChatColor.YELLOW);
return true;
}
if(argument.equalsIgnoreCase("style")) {
MessageManager.getInstance().sendMessage(p, ((String)getConfig().get("message-invalid-type-style")).replace("&", "§") + ChatColor.GREEN + " /pp styles", ChatColor.RED);
return true;
}
if(argument.equalsIgnoreCase("styles")) {
String toSend = ((String)getConfig().get("message-use-style")).replace("&", "§") + " ";
for(ParticleStyle style : ParticleStyle.values()){
if(PermissionHandler.hasStylePermission(p, style)){
toSend = toSend + (style.toString().toLowerCase()) + ", ";
continue;
}
}
if(toSend.equals(((String)getConfig().get("message-use-style")).replace("&", "§") + " ")) {
MessageManager.getInstance().sendMessage(p, ((String)getConfig().get("message-no-styles")).replace("&", "§"), ChatColor.RED);
return true;
}
MessageManager.getInstance().sendMessage(p, toSend, ChatColor.GREEN);
MessageManager.getInstance().sendMessage(p, ((String)getConfig().get("message-usage")).replace("&", "§") + ChatColor.AQUA + " /pp style <Type>", ChatColor.YELLOW);
return true;
}
MessageManager.getInstance().sendMessage(p, ((String)getConfig().get("message-invalid-type")).replace("&", "§") + ChatColor.GREEN + " /pp list", ChatColor.RED);
return true;
}
}

View file

@ -0,0 +1,126 @@
package com.esophose.playerparticles.libraries.databases;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* Abstract Database class, serves as a base for any connection method (MySQL,
* SQLite, etc.)
*
* @author -_Husky_-
* @author tips48
*/
public abstract class Database {
protected Connection connection;
/**
* Creates a new Database
*
*/
protected Database() {
this.connection = null;
}
/**
* Opens a connection with the database
*
* @return Opened connection
* @throws SQLException
* if the connection can not be opened
* @throws ClassNotFoundException
* if the driver cannot be found
*/
public abstract Connection openConnection() throws SQLException,
ClassNotFoundException;
/**
* Checks if a connection is open with the database
*
* @return true if the connection is open
* @throws SQLException
* if the connection cannot be checked
*/
public boolean checkConnection() throws SQLException {
return connection != null && !connection.isClosed();
}
/**
* Gets the connection with the database
*
* @return Connection with the database, null if none
*/
public Connection getConnection() {
return connection;
}
/**
* Closes the connection with the database
*
* @return true if successful
* @throws SQLException
* if the connection cannot be closed
*/
public boolean closeConnection() throws SQLException {
if (connection == null) {
return false;
}
connection.close();
return true;
}
/**
* Executes a SQL Query<br>
*
* If the connection is closed, it will be opened
*
* @param query
* Query to be run
* @return the results of the query
* @throws SQLException
* If the query cannot be executed
* @throws ClassNotFoundException
* If the driver cannot be found; see {@link #openConnection()}
*/
public ResultSet querySQL(String query) throws SQLException,
ClassNotFoundException {
if (!checkConnection()) {
openConnection();
}
Statement statement = connection.createStatement();
ResultSet result = statement.executeQuery(query);
return result;
}
/**
* Executes an Update SQL Query<br>
* See {@link java.sql.Statement#executeUpdate(String)}<br>
* If the connection is closed, it will be opened
*
* @param query
* Query to be run
* @return Result Code, see {@link java.sql.Statement#executeUpdate(String)}
* @throws SQLException
* If the query cannot be executed
* @throws ClassNotFoundException
* If the driver cannot be found; see {@link #openConnection()}
*/
public int updateSQL(String query) throws SQLException,
ClassNotFoundException {
if (!checkConnection()) {
openConnection();
}
Statement statement = connection.createStatement();
int result = statement.executeUpdate(query);
return result;
}
}

View file

@ -0,0 +1,78 @@
package com.esophose.playerparticles.libraries.databases;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* Connects to and uses a MySQL database
*
* @author -_Husky_-
* @author tips48
*/
public class MySQL extends Database {
private final String user;
private final String database;
private final String password;
private final String port;
private final String hostname;
/**
* Creates a new MySQL instance
*
* @param hostname
* Name of the host
* @param port
* Port number
* @param username
* Username
* @param password
* Password
*/
public MySQL(String hostname, String port, String username,
String password) {
this(hostname, port, null, username, password);
}
/**
* Creates a new MySQL instance for a specific database
*
* @param hostname
* Name of the host
* @param port
* Port number
* @param database
* Database name
* @param username
* Username
* @param password
* Password
*/
public MySQL(String hostname, String port, String database,
String username, String password) {
this.hostname = hostname;
this.port = port;
this.database = database;
this.user = username;
this.password = password;
}
@Override
public Connection openConnection() throws SQLException,
ClassNotFoundException {
if (checkConnection()) {
return connection;
}
String connectionURL = "jdbc:mysql://"
+ this.hostname + ":" + this.port;
if (database != null) {
connectionURL = connectionURL + "/" + this.database;
}
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(connectionURL,
this.user, this.password);
return connection;
}
}

View file

@ -0,0 +1,439 @@
/**
* The MIT License (MIT)
*
* Copyright (c) 2014 Maxim Roncace
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.esophose.playerparticles.libraries.particles;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
/**
* Particle effects utility library
* @author Maxim Roncace
* @version 0.1.0
*/
/**
* Slightly modified to suit the needs
* of the plugin
* @author Esophose
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public class ParticleEffect {
private static Class<?> packetClass = null;
private static Constructor<?> packetConstructor = null;
private static Field[] fields = null;
private static boolean netty = true;
private static Field player_connection = null;
private static Method player_sendPacket = null;
private static HashMap<Class<? extends Entity>, Method> handles = new HashMap<Class<? extends Entity>, Method>();
private static boolean newParticlePacketConstructor = false;
private static Class<Enum> enumParticle = null;
private ParticleType type;
private double speed;
private int count;
private double offsetX, offsetY, offsetZ;
private static boolean compatible = true;
static {
String vString = getVersion().replace("v", "");
double v = 0;
if (!vString.isEmpty()){
String[] array = vString.split("_");
v = Double.parseDouble(array[0] + "." + array[1]);
}
try {
if (v < 1.7) {
netty = false;
packetClass = getNmsClass("Packet63WorldParticles");
packetConstructor = packetClass.getConstructor();
fields = packetClass.getDeclaredFields();
}
else {
packetClass = getNmsClass("PacketPlayOutWorldParticles");
if (v < 1.8){
Bukkit.getLogger().info("[PlayerParticles] Server is < 1.8 - Falling back to old version");
packetConstructor = packetClass.getConstructor(String.class, float.class, float.class, float.class,
float.class, float.class, float.class, float.class, int.class);
}
else { // use the new constructor for 1.8
Bukkit.getLogger().info("[PlayerParticles] Server is >= 1.8 - Using new version");
newParticlePacketConstructor = true;
enumParticle = (Class<Enum>)getNmsClass("EnumParticle");
packetConstructor = packetClass.getDeclaredConstructor(enumParticle, boolean.class, float.class,
float.class, float.class, float.class, float.class, float.class, float.class, int.class,
int[].class);
}
}
}
catch (Exception ex){
ex.printStackTrace();
Bukkit.getLogger().severe("[ParticleLib] Failed to initialize NMS components!");
compatible = false;
}
}
/**
* Constructs a new particle effect for use.
* <p>
* Note: different values for speed and radius may hav;e different effects
* depending on the particle's type.
* </p>
* @param type the particle type
* @param speed the speed of the particles
* @param count the number of particles to spawn
* @param radius the radius of the particles
*/
public ParticleEffect(ParticleType type, double offsetX, double offsetY, double offsetZ, double speed, int count){
this.type = type;
this.speed = speed;
this.count = count;
this.offsetX = offsetX;
this.offsetY = offsetY;
this.offsetZ = offsetZ;
}
/**
* Gets the name of this effect
* @return The name of this effect
*/
public String getName() {
return type.name;
}
/**
* Gets the speed of the particles in this effect
* @return The speed of the particles in this effect
*/
public double getSpeed(){
return speed;
}
/**
* Retrieves the number of particles spawned by the effect
* @return The number of particles spawned by the effect
*/
public int getCount(){
return count;
}
/**
* Gets the offsetX of the particle effect
* @return The offsetX of the particle effect
*/
public double getOffsetX(){
return offsetX;
}
/**
* Gets the offsetY of the particle effect
* @return The offsetY of the particle effect
*/
public double getOffsetY(){
return offsetY;
}
/**
* Gets the offsetZ of the particle effect
* @return The offsetZ of the particle effect
*/
public double getOffsetZ(){
return offsetZ;
}
/**
* Send a particle effect to all players
* @param location The location to send the effect to
*/
public void display(Location location){
try {
Object packet = createPacket(location);
for (Player player : Bukkit.getOnlinePlayers()){
if(player.getLocation().getWorld().getName().equals(location.getWorld().getName())) // Patch a bug where particles will be shown in all worlds
sendPacket(player, packet);
}
}
catch (Exception e){
e.printStackTrace();
}
}
/**
* Constructs a new particle packet.
* @param location the location to spawn the particle effect at
* @return the constructed packet
*/
private Object createPacket(Location location){
try {
if (this.count <= 0){
this.count = 1;
}
Object packet;
if (netty){
if (newParticlePacketConstructor){
Object particleType = enumParticle.getEnumConstants()[type.getId()];
packet = packetConstructor.newInstance(particleType,
true, (float)location.getX(), (float)location.getY(), (float)location.getZ(),
(float)this.offsetX, (float)this.offsetY, (float)this.offsetZ,
(float)this.speed, this.count, new int[0]);
}
else {
packet = packetConstructor.newInstance(type.getName(),
(float)location.getX(), (float)location.getY(), (float)location.getZ(),
(float)this.offsetX, (float)this.offsetY, (float)this.offsetZ,
(float)this.speed, this.count);
}
}
else {
packet = packetConstructor.newInstance();
for (Field f : fields){
f.setAccessible(true);
if (f.getName().equals("a"))
f.set(packet, type.getName());
else if (f.getName().equals("b"))
f.set(packet, (float)location.getX());
else if (f.getName().equals("c"))
f.set(packet, (float)location.getY());
else if (f.getName().equals("d"))
f.set(packet, (float)location.getZ());
else if (f.getName().equals("e"))
f.set(packet, this.offsetX);
else if (f.getName().equals("f"))
f.set(packet, this.offsetY);
else if (f.getName().equals("g"))
f.set(packet, this.offsetZ);
else if (f.getName().equals("h"))
f.set(packet, this.speed);
else if (f.getName().equals("i"))
f.set(packet, this.count);
}
}
return packet;
}
catch (IllegalAccessException ex){
ex.printStackTrace();
Bukkit.getLogger().severe("[ParticleLib] Failed to construct particle effect packet!");
}
catch (InstantiationException ex){
ex.printStackTrace();
Bukkit.getLogger().severe("[ParticleLib] Failed to construct particle effect packet!");
}
catch (InvocationTargetException ex){
ex.printStackTrace();
Bukkit.getLogger().severe("[ParticleLib] Failed to construct particle effect packet!");
}
return null;
}
/**
* Sends a packet to a player.
* <p>
* Note: this method is <strong>not typesafe</strong>!
* </p>
* @param p the player to send a packet to
* @param packet the packet to send
* @throws IllegalArgumentException if <code>packet</code> is not of a proper type
*/
private static void sendPacket(Player p, Object packet) throws IllegalArgumentException {
try {
if (player_connection == null){
player_connection = getHandle(p).getClass().getField("playerConnection");
for (Method m : player_connection.get(getHandle(p)).getClass().getMethods()){
if (m.getName().equalsIgnoreCase("sendPacket")){
player_sendPacket = m;
}
}
}
player_sendPacket.invoke(player_connection.get(getHandle(p)), packet);
}
catch (IllegalAccessException ex){
ex.printStackTrace();
Bukkit.getLogger().severe("[ParticleLib] Failed to send packet!");
}
catch (InvocationTargetException ex){
ex.printStackTrace();
Bukkit.getLogger().severe("[ParticleLib] Failed to send packet!");
}
catch (NoSuchFieldException ex){
ex.printStackTrace();
Bukkit.getLogger().severe("[ParticleLib] Failed to send packet!");
}
}
/**
* Gets the NMS handle of the given {@link Entity}.
* @param entity the entity get the handle of
* @return the entity's NMS handle
*/
private static Object getHandle(Entity entity){
try {
if (handles.get(entity.getClass()) != null)
return handles.get(entity.getClass()).invoke(entity);
else {
Method entity_getHandle = entity.getClass().getMethod("getHandle");
handles.put(entity.getClass(), entity_getHandle);
return entity_getHandle.invoke(entity);
}
}
catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
/**
* Gets the NMS class by the given name.
* @param name the name of the NMS class to get
* @return the NMS class of the given name
*/
private static Class<?> getNmsClass(String name){
String version = getVersion();
String className = "net.minecraft.server." + version + name;
Class<?> clazz = null;
try {
clazz = Class.forName(className);
}
catch (ClassNotFoundException ex){
ex.printStackTrace();
Bukkit.getLogger().severe("[ParticleLib] Failed to load NMS class " + name + "!");
}
return clazz;
}
/**
* Determines the version string used by Craftbukkit's safeguard (e.g. 1_7_R4).
* @return the version string used by Craftbukkit's safeguard
*/
private static String getVersion(){
String[] array = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",");
if (array.length == 4)
return array[3] + ".";
return "";
}
/**
* Gets whether ParticleLib is compatible with the server software.
* @return whether ParticleLib is compatible with the server software.
*/
public static boolean isCompatible(){
return compatible;
}
/**
* Enum representing valid particle types in Minecraft 1.8
*/
public enum ParticleType {
EXPLODE("explode", 0, 17),
LARGE_EXPLODE("largeexplode", 1, 1),
HUGE_EXPLOSION("hugeexplosion", 2, 0),
FIREWORKS_SPARK("fireworksSpark", 3, 2),
BUBBLE("bubble", 4, 3),
WAKE("wake", 6, -1),
SUSPENDED("suspended", 7, 4),
DEPTH_SUSPEND("depthsuspend", 8, 5),
CRIT("crit", 9, 7),
MAGIC_CRIT("magicCrit", 10, 8),
SMOKE("smoke", 11, -1),
LARGE_SMOKE("largesmoke", 12, 22),
SPELL("spell", 13, 11),
INSTANT_SPELL("instantSpell", 14, 12),
MOB_SPELL("mobSpell", 15, 9),
MOB_SPELL_AMBIENT("mobSpellAmbient", 16, 10),
WITCH_MAGIC("witchMagic", 17, 13),
DRIP_WATER("dripWater", 18, 27),
DRIP_LAVA("dripLava", 19, 28),
ANGRY_VILLAGER("angryVillager", 20, 31),
HAPPY_VILLAGER("happyVillager", 21, 32),
NOTE("note", 23, 24),
PORTAL("portal", 24, 15),
ENCHANTMENT_TABLE("enchantmenttable", 25, 16),
FLAME("flame", 26, 18),
LAVA("lava", 27, 19),
FOOTSTEP("footstep", 28, 20),
CLOUD("cloud", 29, 23),
RED_DUST("reddust", 30, 24),
SNOWBALL_POOF("snowballpoof", 31, 25),
SNOW_SHOVEL("snowshovel", 32, 28),
SLIME("slime", 33, 29),
HEART("heart", 34, 30),
BARRIER("barrier", 35, -1),
DROPLET("droplet", 39, -1),
DRAGON_BREATH("dragonbreath", 42, -1),
END_ROD("endRod", 43, -1),
DAMAGE_INDICATOR("damageIndicator", 44, -1),
SWEEP_ATTACK("sweepAttack", 45, -1),
RAINBOW("rainbow", 30, -1);
private String name;
private int id;
private int legacyId;
ParticleType(String name, int id, int legacyId){
this.name = name;
this.id = id;
this.legacyId = legacyId;
}
/**
* Gets the name of the particle effect
*
* @return The name of the particle effect
*/
public String getName(){
return name;
}
/**
* Gets the ID of the particle effect
*
* @return The ID of the particle effect
*/
int getId(){
return id;
}
/**
* Gets the legacy ID (pre-1.8) of the particle effect
*
* @return the legacy ID of the particle effect (or -1 if introduced after 1.7)
*/
int getLegacyId(){
return legacyId;
}
}
}

View file

@ -0,0 +1,23 @@
package com.esophose.playerparticles.updater;
import org.bukkit.ChatColor;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import com.esophose.playerparticles.MessageManager;
import com.esophose.playerparticles.PlayerParticles;
public class PluginUpdateListener implements Listener {
@EventHandler
public void onPlayerJoin(PlayerJoinEvent e) {
if(e.getPlayer().isOp()) {
if(PlayerParticles.updateVersion != null) {
MessageManager.getInstance().sendMessage(e.getPlayer(), "An update (" + ChatColor.AQUA + "v" + PlayerParticles.updateVersion + ChatColor.YELLOW + ") is available! You are running " + ChatColor.AQUA + "v" + PlayerParticles.getPlugin().getDescription().getVersion(), ChatColor.YELLOW);
MessageManager.getInstance().sendMessage(e.getPlayer(), "Download from: http://dev.bukkit.org/bukkit-plugins/playerparticles/", ChatColor.YELLOW);
}
}
}
}

View file

@ -0,0 +1,751 @@
package com.esophose.playerparticles.updater;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
/**
* Check for updates on BukkitDev for a given plugin, and download the updates if needed.
* <p>
* <b>VERY, VERY IMPORTANT</b>: Because there are no standards for adding auto-update toggles in your plugin's config, this system provides NO CHECK WITH YOUR CONFIG to make sure the user has allowed auto-updating.
* <br>
* It is a <b>BUKKIT POLICY</b> that you include a boolean value in your config that prevents the auto-updater from running <b>AT ALL</b>.
* <br>
* If you fail to include this option in your config, your plugin will be <b>REJECTED</b> when you attempt to submit it to dev.bukkit.org.
* </p>
* An example of a good configuration option would be something similar to 'auto-update: true' - if this value is set to false you may NOT run the auto-updater.
* <br>
* If you are unsure about these rules, please read the plugin submission guidelines: http://goo.gl/8iU5l
*
* @author Gravity
* @version 2.3
*/
public class Updater {
/* Constants */
// Remote file's title
private static final String TITLE_VALUE = "name";
// Remote file's download link
private static final String LINK_VALUE = "downloadUrl";
// Remote file's release type
private static final String TYPE_VALUE = "releaseType";
// Remote file's build version
private static final String VERSION_VALUE = "gameVersion";
// Path to GET
private static final String QUERY = "/servermods/files?projectIds=";
// Slugs will be appended to this to get to the project's RSS feed
private static final String HOST = "https://api.curseforge.com";
// User-agent when querying Curse
private static final String USER_AGENT = "Updater (by Gravity)";
// Used for locating version numbers in file names
private static final String DELIMETER = "^v|[\\s_-]v";
// If the version number contains one of these, don't update.
private static final String[] NO_UPDATE_TAG = { "-DEV", "-PRE", "-SNAPSHOT" };
// Used for downloading files
private static final int BYTE_SIZE = 1024;
// Config key for api key
private static final String API_KEY_CONFIG_KEY = "api-key";
// Config key for disabling Updater
private static final String DISABLE_CONFIG_KEY = "disable";
// Default api key value in config
private static final String API_KEY_DEFAULT = "PUT_API_KEY_HERE";
// Default disable value in config
private static final boolean DISABLE_DEFAULT = false;
/* User-provided variables */
// Plugin running Updater
private final Plugin plugin;
// Type of update check to run
private final UpdateType type;
// Whether to announce file downloads
private final boolean announce;
// The plugin file (jar)
private final File file;
// The folder that downloads will be placed in
private final File updateFolder;
// The provided callback (if any)
private final UpdateCallback callback;
// Project's Curse ID
private int id = -1;
// BukkitDev ServerMods API key
private String apiKey = null;
/* Collected from Curse API */
private String versionName;
private String versionLink;
private String versionType;
private String versionGameVersion;
/* Update process variables */
// Connection to RSS
private URL url;
// Updater thread
private Thread thread;
// Used for determining the outcome of the update process
private Updater.UpdateResult result = Updater.UpdateResult.SUCCESS;
/**
* Gives the developer the result of the update process. Can be obtained by called {@link #getResult()}
*/
public enum UpdateResult {
/**
* The updater found an update, and has readied it to be loaded the next time the server restarts/reloads.
*/
SUCCESS,
/**
* The updater did not find an update, and nothing was downloaded.
*/
NO_UPDATE,
/**
* The server administrator has disabled the updating system.
*/
DISABLED,
/**
* The updater found an update, but was unable to download it.
*/
FAIL_DOWNLOAD,
/**
* For some reason, the updater was unable to contact dev.bukkit.org to download the file.
*/
FAIL_DBO,
/**
* When running the version check, the file on DBO did not contain a recognizable version.
*/
FAIL_NOVERSION,
/**
* The id provided by the plugin running the updater was invalid and doesn't exist on DBO.
*/
FAIL_BADID,
/**
* The server administrator has improperly configured their API key in the configuration.
*/
FAIL_APIKEY,
/**
* The updater found an update, but because of the UpdateType being set to NO_DOWNLOAD, it wasn't downloaded.
*/
UPDATE_AVAILABLE
}
/**
* Allows the developer to specify the type of update that will be run.
*/
public enum UpdateType {
/**
* Run a version check, and then if the file is out of date, download the newest version.
*/
DEFAULT,
/**
* Don't run a version check, just find the latest update and download it.
*/
NO_VERSION_CHECK,
/**
* Get information about the version and the download size, but don't actually download anything.
*/
NO_DOWNLOAD
}
/**
* Represents the various release types of a file on BukkitDev.
*/
public enum ReleaseType {
/**
* An "alpha" file.
*/
ALPHA,
/**
* A "beta" file.
*/
BETA,
/**
* A "release" file.
*/
RELEASE
}
/**
* Initialize the updater.
*
* @param plugin The plugin that is checking for an update.
* @param id The dev.bukkit.org id of the project.
* @param file The file that the plugin is running from, get this by doing this.getFile() from within your main class.
* @param type Specify the type of update this will be. See {@link UpdateType}
* @param announce True if the program should announce the progress of new updates in console.
*/
public Updater(Plugin plugin, int id, File file, UpdateType type, boolean announce) {
this(plugin, id, file, type, null, announce);
}
/**
* Initialize the updater with the provided callback.
*
* @param plugin The plugin that is checking for an update.
* @param id The dev.bukkit.org id of the project.
* @param file The file that the plugin is running from, get this by doing this.getFile() from within your main class.
* @param type Specify the type of update this will be. See {@link UpdateType}
* @param callback The callback instance to notify when the Updater has finished
*/
public Updater(Plugin plugin, int id, File file, UpdateType type, UpdateCallback callback) {
this(plugin, id, file, type, callback, false);
}
/**
* Initialize the updater with the provided callback.
*
* @param plugin The plugin that is checking for an update.
* @param id The dev.bukkit.org id of the project.
* @param file The file that the plugin is running from, get this by doing this.getFile() from within your main class.
* @param type Specify the type of update this will be. See {@link UpdateType}
* @param callback The callback instance to notify when the Updater has finished
* @param announce True if the program should announce the progress of new updates in console.
*/
public Updater(Plugin plugin, int id, File file, UpdateType type, UpdateCallback callback, boolean announce) {
this.plugin = plugin;
this.type = type;
this.announce = announce;
this.file = file;
this.id = id;
this.updateFolder = this.plugin.getServer().getUpdateFolderFile();
this.callback = callback;
final File pluginFile = this.plugin.getDataFolder().getParentFile();
final File updaterFile = new File(pluginFile, "Updater");
final File updaterConfigFile = new File(updaterFile, "config.yml");
YamlConfiguration config = new YamlConfiguration();
config.options().header("This configuration file affects all plugins using the Updater system (version 2+ - http://forums.bukkit.org/threads/96681/ )" + '\n'
+ "If you wish to use your API key, read http://wiki.bukkit.org/ServerMods_API and place it below." + '\n'
+ "Some updating systems will not adhere to the disabled value, but these may be turned off in their plugin's configuration.");
config.addDefault(API_KEY_CONFIG_KEY, API_KEY_DEFAULT);
config.addDefault(DISABLE_CONFIG_KEY, DISABLE_DEFAULT);
if (!updaterFile.exists()) {
this.fileIOOrError(updaterFile, updaterFile.mkdir(), true);
}
boolean createFile = !updaterConfigFile.exists();
try {
if (createFile) {
this.fileIOOrError(updaterConfigFile, updaterConfigFile.createNewFile(), true);
config.options().copyDefaults(true);
config.save(updaterConfigFile);
} else {
config.load(updaterConfigFile);
}
} catch (final Exception e) {
final String message;
if (createFile) {
message = "The updater could not create configuration at " + updaterFile.getAbsolutePath();
} else {
message = "The updater could not load configuration at " + updaterFile.getAbsolutePath();
}
this.plugin.getLogger().log(Level.SEVERE, message, e);
}
if (config.getBoolean(DISABLE_CONFIG_KEY)) {
this.result = UpdateResult.DISABLED;
return;
}
String key = config.getString(API_KEY_CONFIG_KEY);
if (API_KEY_DEFAULT.equalsIgnoreCase(key) || "".equals(key)) {
key = null;
}
this.apiKey = key;
try {
this.url = new URL(Updater.HOST + Updater.QUERY + this.id);
} catch (final MalformedURLException e) {
this.plugin.getLogger().log(Level.SEVERE, "The project ID provided for updating, " + this.id + " is invalid.", e);
this.result = UpdateResult.FAIL_BADID;
}
if (this.result != UpdateResult.FAIL_BADID) {
this.thread = new Thread(new UpdateRunnable());
this.thread.start();
} else {
runUpdater();
}
}
/**
* Get the result of the update process.
*
* @return result of the update process.
* @see UpdateResult
*/
public Updater.UpdateResult getResult() {
this.waitForThread();
return this.result;
}
/**
* Get the latest version's release type.
*
* @return latest version's release type.
* @see ReleaseType
*/
public ReleaseType getLatestType() {
this.waitForThread();
if (this.versionType != null) {
for (ReleaseType type : ReleaseType.values()) {
if (this.versionType.equalsIgnoreCase(type.name())) {
return type;
}
}
}
return null;
}
/**
* Get the latest version's game version (such as "CB 1.2.5-R1.0").
*
* @return latest version's game version.
*/
public String getLatestGameVersion() {
this.waitForThread();
return this.versionGameVersion;
}
/**
* Get the latest version's name (such as "Project v1.0").
*
* @return latest version's name.
*/
public String getLatestName() {
this.waitForThread();
return this.versionName;
}
/**
* Get the latest version's direct file link.
*
* @return latest version's file link.
*/
public String getLatestFileLink() {
this.waitForThread();
return this.versionLink;
}
/**
* As the result of Updater output depends on the thread's completion, it is necessary to wait for the thread to finish
* before allowing anyone to check the result.
*/
private void waitForThread() {
if ((this.thread != null) && this.thread.isAlive()) {
try {
this.thread.join();
} catch (final InterruptedException e) {
this.plugin.getLogger().log(Level.SEVERE, null, e);
}
}
}
/**
* Save an update from dev.bukkit.org into the server's update folder.
*
* @param file the name of the file to save it as.
*/
private void saveFile(String file) {
final File folder = this.updateFolder;
deleteOldFiles();
if (!folder.exists()) {
this.fileIOOrError(folder, folder.mkdir(), true);
}
downloadFile();
// Check to see if it's a zip file, if it is, unzip it.
final File dFile = new File(folder.getAbsolutePath(), file);
if (dFile.getName().endsWith(".zip")) {
// Unzip
this.unzip(dFile.getAbsolutePath());
}
if (this.announce) {
this.plugin.getLogger().info("Finished updating.");
}
}
/**
* Download a file and save it to the specified folder.
*/
private void downloadFile() {
BufferedInputStream in = null;
FileOutputStream fout = null;
try {
URL fileUrl = new URL(this.versionLink);
final int fileLength = fileUrl.openConnection().getContentLength();
in = new BufferedInputStream(fileUrl.openStream());
fout = new FileOutputStream(new File(this.updateFolder, file.getName()));
final byte[] data = new byte[Updater.BYTE_SIZE];
int count;
if (this.announce) {
this.plugin.getLogger().info("About to download a new update: " + this.versionName);
}
long downloaded = 0;
while ((count = in.read(data, 0, Updater.BYTE_SIZE)) != -1) {
downloaded += count;
fout.write(data, 0, count);
final int percent = (int) ((downloaded * 100) / fileLength);
if (this.announce && ((percent % 10) == 0)) {
this.plugin.getLogger().info("Downloading update: " + percent + "% of " + fileLength + " bytes.");
}
}
} catch (Exception ex) {
this.plugin.getLogger().log(Level.WARNING, "The auto-updater tried to download a new update, but was unsuccessful.", ex);
this.result = Updater.UpdateResult.FAIL_DOWNLOAD;
} finally {
try {
if (in != null) {
in.close();
}
} catch (final IOException ex) {
this.plugin.getLogger().log(Level.SEVERE, null, ex);
}
try {
if (fout != null) {
fout.close();
}
} catch (final IOException ex) {
this.plugin.getLogger().log(Level.SEVERE, null, ex);
}
}
}
/**
* Remove possibly leftover files from the update folder.
*/
private void deleteOldFiles() {
//Just a quick check to make sure we didn't leave any files from last time...
File[] list = listFilesOrError(this.updateFolder);
for (final File xFile : list) {
if (xFile.getName().endsWith(".zip")) {
this.fileIOOrError(xFile, xFile.mkdir(), true);
}
}
}
/**
* Part of Zip-File-Extractor, modified by Gravity for use with Updater.
*
* @param file the location of the file to extract.
*/
private void unzip(String file) {
final File fSourceZip = new File(file);
try {
final String zipPath = file.substring(0, file.length() - 4);
ZipFile zipFile = new ZipFile(fSourceZip);
Enumeration<? extends ZipEntry> e = zipFile.entries();
while (e.hasMoreElements()) {
ZipEntry entry = e.nextElement();
File destinationFilePath = new File(zipPath, entry.getName());
this.fileIOOrError(destinationFilePath.getParentFile(), destinationFilePath.getParentFile().mkdirs(), true);
if (!entry.isDirectory()) {
final BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry));
int b;
final byte[] buffer = new byte[Updater.BYTE_SIZE];
final FileOutputStream fos = new FileOutputStream(destinationFilePath);
final BufferedOutputStream bos = new BufferedOutputStream(fos, Updater.BYTE_SIZE);
while ((b = bis.read(buffer, 0, Updater.BYTE_SIZE)) != -1) {
bos.write(buffer, 0, b);
}
bos.flush();
bos.close();
bis.close();
final String name = destinationFilePath.getName();
if (name.endsWith(".jar") && this.pluginExists(name)) {
File output = new File(this.updateFolder, name);
this.fileIOOrError(output, destinationFilePath.renameTo(output), true);
}
}
}
zipFile.close();
// Move any plugin data folders that were included to the right place, Bukkit won't do this for us.
moveNewZipFiles(zipPath);
} catch (final IOException e) {
this.plugin.getLogger().log(Level.SEVERE, "The auto-updater tried to unzip a new update file, but was unsuccessful.", e);
this.result = Updater.UpdateResult.FAIL_DOWNLOAD;
} finally {
this.fileIOOrError(fSourceZip, fSourceZip.delete(), false);
}
}
/**
* Find any new files extracted from an update into the plugin's data directory.
* @param zipPath path of extracted files.
*/
private void moveNewZipFiles(String zipPath) {
File[] list = listFilesOrError(new File(zipPath));
for (final File dFile : list) {
if (dFile.isDirectory() && this.pluginExists(dFile.getName())) {
// Current dir
final File oFile = new File(this.plugin.getDataFolder().getParent(), dFile.getName());
// List of existing files in the new dir
final File[] dList = listFilesOrError(dFile);
// List of existing files in the current dir
final File[] oList = listFilesOrError(oFile);
for (File cFile : dList) {
// Loop through all the files in the new dir
boolean found = false;
for (final File xFile : oList) {
// Loop through all the contents in the current dir to see if it exists
if (xFile.getName().equals(cFile.getName())) {
found = true;
break;
}
}
if (!found) {
// Move the new file into the current dir
File output = new File(oFile, cFile.getName());
this.fileIOOrError(output, cFile.renameTo(output), true);
} else {
// This file already exists, so we don't need it anymore.
this.fileIOOrError(cFile, cFile.delete(), false);
}
}
}
this.fileIOOrError(dFile, dFile.delete(), false);
}
File zip = new File(zipPath);
this.fileIOOrError(zip, zip.delete(), false);
}
/**
* Check if the name of a jar is one of the plugins currently installed, used for extracting the correct files out of a zip.
*
* @param name a name to check for inside the plugins folder.
* @return true if a file inside the plugins folder is named this.
*/
private boolean pluginExists(String name) {
File[] plugins = listFilesOrError(new File("plugins"));
for (final File file : plugins) {
if (file.getName().equals(name)) {
return true;
}
}
return false;
}
/**
* Check to see if the program should continue by evaluating whether the plugin is already updated, or shouldn't be updated.
*
* @return true if the version was located and is not the same as the remote's newest.
*/
private boolean versionCheck() {
final String title = this.versionName;
if (this.type != UpdateType.NO_VERSION_CHECK) {
final String localVersion = this.plugin.getDescription().getVersion();
if (title.split(DELIMETER).length >= 2) {
// Get the newest file's version number
final String remoteVersion = title.split(DELIMETER)[title.split(DELIMETER).length - 1].split(" ")[0];
if (this.hasTag(localVersion) || !this.shouldUpdate(localVersion, remoteVersion)) {
// We already have the latest version, or this build is tagged for no-update
this.result = Updater.UpdateResult.NO_UPDATE;
return false;
}
} else {
// The file's name did not contain the string 'vVersion'
final String authorInfo = this.plugin.getDescription().getAuthors().isEmpty() ? "" : " (" + this.plugin.getDescription().getAuthors().get(0) + ")";
this.plugin.getLogger().warning("The author of this plugin" + authorInfo + " has misconfigured their Auto Update system");
this.plugin.getLogger().warning("File versions should follow the format 'PluginName vVERSION'");
this.plugin.getLogger().warning("Please notify the author of this error.");
this.result = Updater.UpdateResult.FAIL_NOVERSION;
return false;
}
}
return true;
}
/**
* <b>If you wish to run mathematical versioning checks, edit this method.</b>
* <p>
* With default behavior, Updater will NOT verify that a remote version available on BukkitDev
* which is not this version is indeed an "update".
* If a version is present on BukkitDev that is not the version that is currently running,
* Updater will assume that it is a newer version.
* This is because there is no standard versioning scheme, and creating a calculation that can
* determine whether a new update is actually an update is sometimes extremely complicated.
* </p>
* <p>
* Updater will call this method from {@link #versionCheck()} before deciding whether
* the remote version is actually an update.
* If you have a specific versioning scheme with which a mathematical determination can
* be reliably made to decide whether one version is higher than another, you may
* revise this method, using the local and remote version parameters, to execute the
* appropriate check.
* </p>
* <p>
* Returning a value of <b>false</b> will tell the update process that this is NOT a new version.
* Without revision, this method will always consider a remote version at all different from
* that of the local version a new update.
* </p>
* @param localVersion the current version
* @param remoteVersion the remote version
* @return true if Updater should consider the remote version an update, false if not.
*/
public boolean shouldUpdate(String localVersion, String remoteVersion) {
return !localVersion.equalsIgnoreCase(remoteVersion);
}
/**
* Evaluate whether the version number is marked showing that it should not be updated by this program.
*
* @param version a version number to check for tags in.
* @return true if updating should be disabled.
*/
private boolean hasTag(String version) {
for (final String string : Updater.NO_UPDATE_TAG) {
if (version.contains(string)) {
return true;
}
}
return false;
}
/**
* Make a connection to the BukkitDev API and request the newest file's details.
*
* @return true if successful.
*/
private boolean read() {
try {
final URLConnection conn = this.url.openConnection();
conn.setConnectTimeout(5000);
if (this.apiKey != null) {
conn.addRequestProperty("X-API-Key", this.apiKey);
}
conn.addRequestProperty("User-Agent", Updater.USER_AGENT);
conn.setDoOutput(true);
final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
final String response = reader.readLine();
final JSONArray array = (JSONArray) JSONValue.parse(response);
if (array.isEmpty()) {
this.plugin.getLogger().warning("The updater could not find any files for the project id " + this.id);
this.result = UpdateResult.FAIL_BADID;
return false;
}
JSONObject latestUpdate = (JSONObject) array.get(array.size() - 1);
this.versionName = (String) latestUpdate.get(Updater.TITLE_VALUE);
this.versionLink = (String) latestUpdate.get(Updater.LINK_VALUE);
this.versionType = (String) latestUpdate.get(Updater.TYPE_VALUE);
this.versionGameVersion = (String) latestUpdate.get(Updater.VERSION_VALUE);
return true;
} catch (final IOException e) {
if (e.getMessage().contains("HTTP response code: 403")) {
this.plugin.getLogger().severe("dev.bukkit.org rejected the API key provided in plugins/Updater/config.yml");
this.plugin.getLogger().severe("Please double-check your configuration to ensure it is correct.");
this.result = UpdateResult.FAIL_APIKEY;
} else {
this.plugin.getLogger().severe("The updater could not contact dev.bukkit.org for updating.");
this.plugin.getLogger().severe("If you have not recently modified your configuration and this is the first time you are seeing this message, the site may be experiencing temporary downtime.");
this.result = UpdateResult.FAIL_DBO;
}
this.plugin.getLogger().log(Level.SEVERE, null, e);
return false;
}
}
/**
* Perform a file operation and log any errors if it fails.
* @param file file operation is performed on.
* @param result result of file operation.
* @param create true if a file is being created, false if deleted.
*/
private void fileIOOrError(File file, boolean result, boolean create) {
if (!result) {
this.plugin.getLogger().severe("The updater could not " + (create ? "create" : "delete") + " file at: " + file.getAbsolutePath());
}
}
private File[] listFilesOrError(File folder) {
File[] contents = folder.listFiles();
if (contents == null) {
this.plugin.getLogger().severe("The updater could not access files at: " + this.updateFolder.getAbsolutePath());
return new File[0];
} else {
return contents;
}
}
/**
* Called on main thread when the Updater has finished working, regardless
* of result.
*/
public interface UpdateCallback {
/**
* Called when the updater has finished working.
* @param updater The updater instance
*/
void onFinish(Updater updater);
}
private class UpdateRunnable implements Runnable {
@Override
public void run() {
runUpdater();
}
}
private void runUpdater() {
if (this.url != null && (this.read() && this.versionCheck())) {
// Obtain the results of the project's file feed
if ((this.versionLink != null) && (this.type != UpdateType.NO_DOWNLOAD)) {
String name = this.file.getName();
// If it's a zip file, it shouldn't be downloaded as the plugin's name
if (this.versionLink.endsWith(".zip")) {
name = this.versionLink.substring(this.versionLink.lastIndexOf("/") + 1);
}
this.saveFile(name);
} else {
this.result = UpdateResult.UPDATE_AVAILABLE;
}
}
if (this.callback != null) {
new BukkitRunnable() {
@Override
public void run() {
runCallback();
}
}.runTask(this.plugin);
}
}
private void runCallback() {
this.callback.onFinish(this);
}
}

178
src/config.yml Normal file
View file

@ -0,0 +1,178 @@
# __________.__ __________ __ .__ .__ ________
# \______ \ | _____ ___.__. __________\______ \_____ ________/ |_|__| ____ | | ____ ______ ___ _\_____ \
# | ___/ | \__ \< | |/ __ \_ __ \ ___/\__ \\_ __ \ __\ |/ ___\| | _/ __ \ / ___/ \ \/ / _(__ <
# | | | |__/ __ \\___ \ ___/| | \/ | / __ \| | \/| | | \ \___| |_\ ___/ \___ \ \ / / \
# |____| |____(____ / ____|\___ >__| |____| (____ /__| |__| |__|\___ >____/\___ >____ > \_/ /______ /
# \/\/ \/ \/ \/ \/ \/ \/
# ====================================================#
# PlayerParticles Config #
# DO NOT DELETE OR EDIT THE FIELD "version"! #
# ====================================================#
# DO NOT CHANGE THIS UNDER ANY CIRCUMSTANCE (Will reset your config)
version: 3.7
# There are 20 minecraft ticks per second
# The default value of 20 means a particle will be displayed every tick
# That means 20 particles will be displayed per second
# If ticks-per-particle was set to 5, then 4 particles would be displayed per second since 20/5 is 4
# If your server is experiencing lag after installing this plugin, raising this value should help
# Setting this value to 0.5 will cause 40 particles to appear per second. Be warned this could cause strain on the server.
# Changing this 'may' cause style timing to get messed up
# Only use integer values, excluding 0.5
# Default: 1
ticks-per-particle: 1
# Check for new versions of the plugin
# Default: true
check-updates: true
# The worlds which this plugin is disabled in
# Default: []
disabled-worlds: []
# - your_world_name_here
# - add_more_under_these
# If you're using other plugins to execute commands you may wish to turn off messages
# Default: true
messages-enabled: true
# Whether or not to use the message-prefix field when displaying messages
# Default: true
use-message-prefix: true
# The prefix to use for all PlayerParticle messages
# Use & to set color / format
# This is useless if use-message-prefix is set to false
# Default: '&c[&ePlayerParticles&c]'
message-prefix: '&7[&3PlayerParticles&7]'
# ================================================================ #
# MESSAGE CONFIGURATION #
# Important Notes: #
# * {PARTICLE} displays the particle argument used in the command #
# * {STYLE} displays the style argument used in the command #
# * You can not use the apostrophe character! ( ' ) #
# ================================================================ #
#################
# Particles #
#################
# No Particle Permission
# Default: 'You do not have permission to use type {PARTICLE} particles!'
message-no-permission: 'You do not have permission to use type {PARTICLE} particles!'
# /pp list No Particles
# Default: 'You do not have permission to use any particles!'
message-no-particles: 'You do not have permission to use any particles!'
# Now Using Particles
# Default: 'Now using type {PARTICLE} particles!'
message-now-using: 'Now using type {PARTICLE} particles!'
# Cleared Particles
# Default: 'Cleared your particles!'
message-cleared-particles: 'Cleared your particles!'
# You Can Use Particles
# Default: 'You can use:'
message-use: 'You can use:'
# Invalid Particle Type
# Default: 'Invalid particle type!'
message-invalid-type: 'Invalid particle type!'
##################
# Styles #
##################
# No Style Permission
# Default: 'You do not have permission to use the style type {STYLE}!'
message-no-permission-style: 'You do not have permission to use the style type {STYLE}!'
# /pp styles No Styles
# Default: 'You do not have permission to use any particles!'
message-no-styles: 'You do not have permission to use any styles!'
# Now Using Style
# Default: 'Now using style type {STYLE}!'
message-now-using-style: 'Now using style type {STYLE}!'
# Cleared Style
# Default: 'Cleared your particles!'
message-cleared-style: 'Cleared your style!'
# You Can Use Styles
# Default: 'You can use:'
message-use-style: 'You can use:'
# Invalid Style Type
# Default: 'Invalid style type!'
message-invalid-type-style: 'Invalid style type!'
#################
# Other #
#################
# Usage
# Default: 'Usage:'
message-usage: 'Usage:'
# Invalid Arguments
# Default: 'Invalid arguments!'
message-invalid-arguments: 'Invalid Arguments!'
# Reload
# Default: 'Reloaded Config!'
message-reload: 'Reloaded Config!'
# Available Commands
# Default: 'Available Commands:'
message-available-commands: 'Available Commands:'
# Disabled Worlds None
# Default: 'Particles are not disabled in any worlds!'
message-disabled-worlds-none: 'Particles are not disabled in any worlds!'
# Disabled Worlds
# Default: 'Particles are disabled in these worlds:'
message-disabled-worlds: 'Particles are disabled in these worlds:'
# ================================================================ #
# DATABASE CONFIGURATION #
# Information: #
# * This is meant for people who have multiple servers connected #
# together through BungeeCord. Unless you have multiple servers, #
# it is recommended to keep the database storage disabled for #
# the best performance! #
# ================================================================ #
# Enable Database
# Default: false
database-enable: false
# =================================================================== #
# The following are only required if database-enable is set to 'true' #
# =================================================================== #
# Database Hostname
# Default: ''
database-hostname: ''
# Database Port
# Default: 3306
database-port: 3306
# Database Name
# Default: ''
database-name: ''
# Database User Name
# Default: ''
database-user-name: ''
# Database User Password
# Default: ''
database-user-password: ''

7
src/plugin.yml Normal file
View file

@ -0,0 +1,7 @@
name: PlayerParticles
main: com.esophose.playerparticles.PlayerParticles
version: 3.7
description: Make Particles Around Players
commands:
pp:
description: Particles Command.