mirror of
https://github.com/TotalFreedomMC/PlayerParticles.git
synced 2025-02-11 03:29:53 +00:00
Updated to v3
Added all the files
This commit is contained in:
parent
9f264fe5a5
commit
a851ee037d
16 changed files with 2699 additions and 27 deletions
5
.gitattributes
vendored
5
.gitattributes
vendored
|
@ -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
60
.gitignore
vendored
|
@ -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
|
||||
|
|
186
src/com/esophose/playerparticles/ConfigManager.java
Normal file
186
src/com/esophose/playerparticles/ConfigManager.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
54
src/com/esophose/playerparticles/MessageManager.java
Normal file
54
src/com/esophose/playerparticles/MessageManager.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
446
src/com/esophose/playerparticles/ParticleCreator.java
Normal file
446
src/com/esophose/playerparticles/ParticleCreator.java
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
28
src/com/esophose/playerparticles/ParticleStyle.java
Normal file
28
src/com/esophose/playerparticles/ParticleStyle.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
77
src/com/esophose/playerparticles/PermissionHandler.java
Normal file
77
src/com/esophose/playerparticles/PermissionHandler.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
218
src/com/esophose/playerparticles/PlayerParticles.java
Normal file
218
src/com/esophose/playerparticles/PlayerParticles.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
751
src/com/esophose/playerparticles/updater/Updater.java
Normal file
751
src/com/esophose/playerparticles/updater/Updater.java
Normal 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
178
src/config.yml
Normal 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
7
src/plugin.yml
Normal 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.
|
Loading…
Reference in a new issue