commit 56d69abdc08225d6d2d19ce82d8354cf49377203 Author: femsci Date: Fri Apr 21 22:56:48 2023 +0200 Archive diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ef54257 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +**/.idea +**/out +**/target +**/build +**/*.iml +YAPI/ diff --git a/AuthentiCat/src/config.yml b/AuthentiCat/src/config.yml new file mode 100755 index 0000000..36d0070 --- /dev/null +++ b/AuthentiCat/src/config.yml @@ -0,0 +1,83 @@ +#Force all players to log in after server reload (not restart) +reset-on-reload: true + +#If set to true, prevents players from chat usage before authentication +disallow-speech: false + +#Time (in seconds) until player is kicked due to authentication fail (set to -1 to disable) +#It is recommended to set the time as greater than 15s +kick-timeout: 20 + +#The "reason" message of kicking after timeout (set to 'null' in order to disable) +kick-timeout-message: "&cAuthentication timeout!" + +#The delay (in seconds) after which prompt messages will be sent to the player (set to -1 in order to disable) +prompt-initial-delay: 3 + +#The delay (in seconds) between prompt messages (set to -1 in order to disable) +prompt-repeat-delay: 5 + +#The prompt messages (set to 'null' in order to disable): +# +#The register prompt message +prompt-message-register: "&aType &6/register &ato register yourself" +# +#The login prompt message +prompt-message-login: "&aType &6/login &ato log in yourself" + +#Command messages (message is shown *when [...]*) + +#Successes + +#When successfully changed the password +cmd-success-changepass: "&aYour password has been successfully changed!" + +#When successfully logged out +cmd-success-logout: "&aLogged out!" + +#When successfully logged in +cmd-success-login: "&aLogged in!" + +#When successfully registered +cmd-success-register: "&aRegistered! From now on, every time you join this server, use &6/login &a!" + +#Fails + +#When player uses too many arguments +cmd-fail-general-overargs: "&cToo many arguments!" + +#When the passwords do not match +cmd-fail-passwords-mismatch: "&cYour old password argument does not match the actual password!" + +#When the new password is not specified +cmd-fail-nonewpassword: "&cYou need to specify the new password!" + +#When neither the old nor the new password is specified +cmd-fail-nobothpasswords: "&cYou need to specify the passwords!" + +#When player does not have any password set and tries to change their password +cmd-fail-nopassset: "&cYou don't have any password set!" + +#When player passes arguments to a command that does not accept any +cmd-fail-noargsallowed: "&cThis command does not allow any arguments!" + +#When player needs to login instead of registering +cmd-fail-just-login: "&cYou need to login!" + +#When player uses an incorrect password +cmd-fail-badpassword: "&cIncorrect password!" + +#When player uses more than one argument for a +cmd-fail-nopassword-overargs: "&cYou need to specify the password as a single argument!" + +#When the password is not specified +cmd-fail-nopassword: "&cYou need to specify the password!" + +#When player tries to authenticate while being already authenticated +cmd-fail-already-authenticated: "&cYou are already authenticated!" + +#When player uses /login without being registered +cmd-fail-register-first: "&cYou need to register first!" + +#When the player is not authenticated and tries to use commands other than /login or /register +cmd-prompt-badcommand: "§cAuthenticate before you can speak!" diff --git a/AuthentiCat/src/me/yuri/authcat/CatGirls.java b/AuthentiCat/src/me/yuri/authcat/CatGirls.java new file mode 100755 index 0000000..4205e26 --- /dev/null +++ b/AuthentiCat/src/me/yuri/authcat/CatGirls.java @@ -0,0 +1,115 @@ +package me.yuri.authcat; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.inventory.InventoryOpenEvent; +import org.bukkit.event.player.*; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.ArrayList; +import java.util.List; + +public class CatGirls implements Listener { + + protected static List catgirls = new ArrayList<>(); + + @EventHandler + public void ohayou(PlayerJoinEvent e) { + catgirls.add(e.getPlayer()); + brian(e.getPlayer()); + } + + static void brian(Player p) { + new BukkitRunnable() { + final int delay = Neko.prmdelay; + final int repeat = Neko.prmrepeat; + final int kick = Neko.timeout; + final String km = Neko.timeoutmsg; + int cnt = 0; + final String msg = (Neko.getCatEars().oof(p.getName()) == null) ? Neko.promptreg : Neko.promptlog; + + @Override + public void run() { + if (!catgirls.contains(p)) { + cancel(); + return; + } + + if (cnt == delay) { + p.sendMessage(msg); + } + if ((cnt + delay) % repeat == 0 && cnt > delay) { + p.sendMessage(msg); + } + + if (cnt >= kick) { + p.kickPlayer(km.equalsIgnoreCase("null") ? null : km); + } + + cnt++; + } + }.runTaskTimer(Neko.getCatEars(), 0L, 20L); + } + + @EventHandler + public void matanedesune(PlayerQuitEvent e) { + catgirls.remove(e.getPlayer()); + } + + @EventHandler + public void iiiiiiiiiiine(PlayerInteractEvent e) { + if (catgirls.contains(e.getPlayer())) e.setCancelled(true); + } + + @EventHandler + public void yoidesune(PlayerDropItemEvent e) { + if (catgirls.contains(e.getPlayer())) e.setCancelled(true); + } + + @EventHandler + public void desudesu(InventoryOpenEvent e) { + if (catgirls.contains(((Player) e.getPlayer()))) e.setCancelled(true); + } + + @EventHandler + public void plsstop(PlayerItemConsumeEvent e) { + if (catgirls.contains(e.getPlayer())) e.setCancelled(true); + } + + @EventHandler + public void socute(PlayerItemHeldEvent e) { + if (catgirls.contains(e.getPlayer())) e.setCancelled(true); + } + + @EventHandler + public void highsocks(EntityDamageEvent e) { + if (e.getEntity() instanceof Player) + if (catgirls.contains(((Player) e.getEntity()))) e.setCancelled(true); + } + + @EventHandler + public void thisisirritatingsrsly(PlayerMoveEvent e) { + if (catgirls.contains(e.getPlayer())) e.setCancelled(true); + } + + @EventHandler + public void nekoooooo(AsyncPlayerChatEvent e) { + if (Neko.disallowspeech) + if (catgirls.contains(e.getPlayer())) { + e.getPlayer().sendMessage(Neko.cmdpromptbadcmd); + e.setCancelled(true); + } + } + + @EventHandler + public void korewoomoitegahoshiiinai(PlayerCommandPreprocessEvent e) { + if (!catgirls.contains(e.getPlayer())) return; + if ((!e.getMessage().startsWith("/login") && !e.getMessage().startsWith("/log") + && !e.getMessage().startsWith("/register") && !e.getMessage().startsWith("/reg")) || e.getMessage().startsWith("/logout")) { + e.getPlayer().sendMessage(Neko.cmdpromptbadcmd); + e.setCancelled(true); + } + } +} diff --git a/AuthentiCat/src/me/yuri/authcat/Neko.java b/AuthentiCat/src/me/yuri/authcat/Neko.java new file mode 100755 index 0000000..ac6e4dd --- /dev/null +++ b/AuthentiCat/src/me/yuri/authcat/Neko.java @@ -0,0 +1,130 @@ +package me.yuri.authcat; + +import me.yuri.yuriapi.api.command.CommandManager; +import me.yuri.yuriapi.api.utils.configuration.ConfigVar; +import me.yuri.yuriapi.api.utils.configuration.ConfigVarExceptionListener; +import me.yuri.yuriapi.api.utils.configuration.ConfigVarManager; +import org.bukkit.Bukkit; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Base64; +import java.util.Properties; + +public class Neko extends JavaPlugin { + + @ConfigVar("reset-on-reload") + protected static boolean resetonreload = false; + + @ConfigVar("disallow-speech") + protected static boolean disallowspeech = false; + + @ConfigVar("kick-timeout") + protected static int timeout = -1; + + @ConfigVar(value = "kick-timeout-message", color = '&') + protected static String timeoutmsg = "null"; + + @ConfigVar(value = "prompt-message-login", color = '&') + protected static String promptlog = "null"; + + @ConfigVar(value = "prompt-message-register", color = '&') + protected static String promptreg = "null"; + + @ConfigVar("prompt-initial-delay") + protected static int prmdelay = 4; + + @ConfigVar("prompt-repeat-delay") + protected static int prmrepeat = 5; + + @ConfigVar(value = "cmd-prompt-badcommand", color = '&') + protected static String cmdpromptbadcmd = "null"; + + protected static Neko getCatEars() { + return animeGrill; + } + + private static final Otokonomusume otoko = new Otokonomusume(); + + private static Neko animeGrill; + + @ConfigVarExceptionListener + public void onCfgException(me.yuri.yuriapi.api.utils.configuration.ConfigVarException e){ + e.printStackTrace(); + saveDefaultConfig(); + } + + @Override + public void onLoad() { + animeGrill = this; + saveDefaultConfig(); + + ConfigVarManager.register(this, this, otoko); + ConfigVarManager.update(this); + } + + @Override + public void onDisable() { + super.onDisable(); + } + + @Override + public void onEnable() { + CommandManager c = new CommandManager(this); + c.registerCommand(otoko); + this.getServer().getPluginManager().registerEvents(new CatGirls(), this); + log("§aA§bu§ct§dh§ee§fn§1t§2i§3C§4a§5t §aenabled!"); + + if(resetonreload){ + Bukkit.getOnlinePlayers().forEach(p -> { + CatGirls.catgirls.add(p); + CatGirls.brian(p); + }); + + } + } + + private static void log(String... msg) { + Bukkit.getConsoleSender().sendMessage(msg); + } + + public void dontspawnkill(String user, String pass){ + Properties p = new Properties(); + File file = new File(this.getDataFolder().getAbsolutePath() + "/passes.properties"); + try { + if(file.exists()) { + FileInputStream fis = new FileInputStream(file); + p.load(fis); + fis.close(); + } + //Don't do this unless you are NSA :3 + pass = Base64.getEncoder().encodeToString(pass.getBytes()); + p.setProperty(user, pass); + FileOutputStream fos = new FileOutputStream(file); + p.store(fos, "KEKS"); + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public String oof(String user) { + String pass = null; + Properties p = new Properties(); + File file = new File(this.getDataFolder().getAbsolutePath() + "/passes.properties"); + if(!file.exists()) return null; + try { + FileInputStream fis = new FileInputStream(file); + p.load(fis); + fis.close(); + String tmp = p.getProperty(user); + if(tmp == null) return null; + pass = new String(Base64.getDecoder().decode(tmp)); + } catch (IOException ignored) { + } + return pass; + } +} diff --git a/AuthentiCat/src/me/yuri/authcat/Otokonomusume.java b/AuthentiCat/src/me/yuri/authcat/Otokonomusume.java new file mode 100755 index 0000000..9bdf573 --- /dev/null +++ b/AuthentiCat/src/me/yuri/authcat/Otokonomusume.java @@ -0,0 +1,192 @@ +package me.yuri.authcat; + +import me.yuri.yuriapi.api.command.Cmd; +import me.yuri.yuriapi.api.command.CommandEvent; +import me.yuri.yuriapi.api.utils.configuration.ConfigVar; +import org.bukkit.entity.Player; + +public class Otokonomusume { + + //FAILS + + @ConfigVar(value = "cmd-fail-register-first", color = '&') + private static String cmdregfirst = "null"; + + @ConfigVar(value = "cmd-fail-already-authenticated", color = '&') + private static String cmdalreadyauth = "null"; + + @ConfigVar(value = "cmd-fail-nopassword", color = '&') + private static String cmdnopass = "null"; + + @ConfigVar(value = "cmd-fail-badpassword", color = '&') + private static String cmdbadpass= "null"; + + @ConfigVar(value = "cmd-fail-nopassword-overargs", color = '&') + private static String cmdnopass1 = "null"; + + @ConfigVar(value = "cmd-fail-just-login", color = '&') + private static String cmdloginprompt = "null"; + + @ConfigVar(value = "cmd-fail-noargsallowed", color = '&') + private static String cmdnoargsallowed = "null"; + + @ConfigVar(value = "cmd-fail-nobothpasswords", color = '&') + private static String cmdnoboth = "null"; + + @ConfigVar(value = "cmd-fail-nonewpassword", color = '&') + private static String cmdnonew = "null"; + + @ConfigVar(value = "cmd-fail-passwords-mismatch", color = '&') + private static String cmdnomatch = "null"; + + @ConfigVar(value = "cmd-fail-general-overargs", color = '&') + private static String cmdtoomanyargs = "null"; + + @ConfigVar(value = "cmd-fail-nopassset", color = '&') + private static String cmdnopasset = "null"; + + //SUCCESSES + + @ConfigVar(value = "cmd-success-register", color = '&') + private static String cmdfirstreg = "null"; + + @ConfigVar(value = "cmd-success-login", color = '&') + private static String cmdloggedin = "null"; + + @ConfigVar(value = "cmd-success-logout", color = '&') + private static String cmdloggedout = "null"; + + @ConfigVar(value = "cmd-success-changepass", color = '&') + private static String cmdchangedpass = "null"; + + + @Cmd(command = "login", aliases = {"log"}, consoleSide = false) + public void rogin(CommandEvent c){ + + Player s = (Player) c.getSender(); + + String pass = Neko.getCatEars().oof(s.getName()); + + if(!CatGirls.catgirls.contains(s)){ + s.sendMessage(cmdalreadyauth); + return; + } + + if(pass == null){ + s.sendMessage(cmdregfirst); + return; + } + + if(c.getArgs().length == 0){ + s.sendMessage(cmdnopass); + return; + } + + if(c.getArgs().length > 1){ + s.sendMessage(cmdnopass1); + return; + } + + if(pass.equals(c.getArgsString())){ + CatGirls.catgirls.remove(s); + s.sendMessage(cmdloggedin); + } else { + s.sendMessage(cmdbadpass); + } + + } + + @Cmd(command = "register", aliases = {"reg"}, consoleSide = false) + public void hajimemashite(CommandEvent c){ + Player s = (Player) c.getSender(); + + String pass = Neko.getCatEars().oof(s.getName()); + + if(!CatGirls.catgirls.contains(s)){ + s.sendMessage(cmdalreadyauth); + return; + } + + if(pass != null){ + s.sendMessage(cmdloginprompt); + return; + } + + if(c.getArgs().length == 0){ + s.sendMessage(cmdnopass); + return; + } + + if(c.getArgs().length > 1){ + s.sendMessage(cmdnopass1); + return; + } + + pass = c.getArgsString(); + + Neko.getCatEars().dontspawnkill(s.getName(), pass); + + s.sendMessage(cmdfirstreg); + + CatGirls.catgirls.remove(s); + + } + + @Cmd(command = "logout", consoleSide = false) + public void iiteyone(CommandEvent c){ + Player s = (Player) c.getSender(); + + if(c.getArgs().length != 0){ + s.sendMessage(cmdnoargsallowed); + return; + } + + s.sendMessage(cmdloggedout); + + deanimenize(s); + } + + private void deanimenize(Player p){ + CatGirls.catgirls.add(p); + CatGirls.brian(p); + } + + @Cmd(command = "changepassword", aliases = {"changepass"}, consoleSide = false) + public void aaaaaaaaaaaaaaaaaaaaaa(CommandEvent c){ + Player s = (Player) c.getSender(); + + String playerpass = Neko.getCatEars().oof(s.getName()); + if(playerpass == null){ + s.sendMessage(cmdnopasset); + deanimenize(s); + return; + } + + switch (c.getArgs().length){ + case 0: + s.sendMessage(cmdnopass); + return; + case 1: + s.sendMessage(cmdnonew); + return; + case 2: + String oldpass, newpass; + oldpass = c.getArgs()[0]; + newpass = c.getArgs()[1]; + + if(!oldpass.equals(playerpass)){ + s.sendMessage(cmdnomatch); + return; + } + + Neko.getCatEars().dontspawnkill(s.getName(), newpass); + + s.sendMessage(cmdchangedpass); + + return; + default: + s.sendMessage(cmdtoomanyargs); + return; + } + } +} diff --git a/AuthentiCat/src/plugin.yml b/AuthentiCat/src/plugin.yml new file mode 100755 index 0000000..e6f6023 --- /dev/null +++ b/AuthentiCat/src/plugin.yml @@ -0,0 +1,18 @@ +name: AuthentiCat +author: Yuri (Blin) +version: 1.0E +main: me.yuri.authcat.Neko +load: STARTUP +depend: + - YuriAPI +description: A decent auth plugin with terrible variable naming... +commands: + login: + aliases: log + register: + aliases: reg +# authmanager: +# aliases: am + logout: + changepassword: + aliases: changepass diff --git a/ChristmasWarfare/pom.xml b/ChristmasWarfare/pom.xml new file mode 100755 index 0000000..312b7e5 --- /dev/null +++ b/ChristmasWarfare/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + + me.yuri + ChristmasWarfare + 1.0-E + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + + + me.yuri + YuriAPI + system + /mnt/B65CCF2D5CCEE6E9/Projects/IdeaProjects/YAPI/YuriAPI.jar + + + org.spigotmc + spigot-api + 1.14.4-R0.1-SNAPSHOT + provided + + + + + \ No newline at end of file diff --git a/ChristmasWarfare/src/main/java/me/yuri/christmaswarfare/CC.java b/ChristmasWarfare/src/main/java/me/yuri/christmaswarfare/CC.java new file mode 100755 index 0000000..3cc3aac --- /dev/null +++ b/ChristmasWarfare/src/main/java/me/yuri/christmaswarfare/CC.java @@ -0,0 +1,66 @@ +package me.yuri.christmaswarfare; + +import com.sun.istack.internal.NotNull; +import me.yuri.yuriapi.api.command.CommandManager; +import me.yuri.yuriapi.api.utils.configuration.ConfigVar; +import me.yuri.yuriapi.api.utils.configuration.ConfigVarManager; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.java.JavaPlugin; + +public class CC extends JavaPlugin { + + @ConfigVar("grenade-percentage") + public static int _GRENADE_PERC; + @ConfigVar("luckyblocks-enabled") + public static boolean _LUCKYBLOCKS; + @ConfigVar("max-players") + public static int MAX_PLAYERS; + @ConfigVar("prefix") + public static String _PREFIX = ""; + + public static void sendCns(String msg){ + Bukkit.getConsoleSender().sendMessage(ChatColor.translateAlternateColorCodes('&', msg)); + } + private static CommandManager cm; + + private static CC cc; + public static CC getCC() { + return cc; + } + + @Override + public void onLoad() { + cc = this; + } + + @Override + public void onDisable() { + if(GameManager.getState() == GameManager.GameState.INGAME){ + GameManager.stop(true); + } + } + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + cm.onCommand(sender, command, label, args); + return true; + } + + @Override + public void onEnable() { + + saveDefaultConfig(); + ConfigVarManager.register(this, this.getClass()); + ConfigVarManager.update(); + if(_PREFIX.equals("none")) _PREFIX = ""; + if(!_LUCKYBLOCKS){ + sendCns("&cLuckyBlock integration is disabled!"); + } + cm = new CommandManager(this); + cm.registerCommand(new Commands()); + getServer().getPluginManager().registerEvents(new ItemsEListeners(), this); + } +} diff --git a/ChristmasWarfare/src/main/java/me/yuri/christmaswarfare/Commands.java b/ChristmasWarfare/src/main/java/me/yuri/christmaswarfare/Commands.java new file mode 100755 index 0000000..a49db0e --- /dev/null +++ b/ChristmasWarfare/src/main/java/me/yuri/christmaswarfare/Commands.java @@ -0,0 +1,118 @@ +package me.yuri.christmaswarfare; + +import me.yuri.yuriapi.APIBridge; +import me.yuri.yuriapi.api.command.Cmd; +import me.yuri.yuriapi.api.command.CommandClass; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.util.Arrays; + +public class Commands { + + @Cmd(command = "cw", desc = "Join game", playerSide = true, consoleSide = true) + public void CmdJoin(CommandClass s){ + try { + if (s.getArgs().length == 0) { + s.getSender().sendMessage(printHelp()); + return; + } + if (s.getArgs().length > 0) { + if (s.getArgs()[0].equalsIgnoreCase("help")) { + s.getSender().sendMessage(printHelp()); + return; + } + + if (s.getArgs()[0].equalsIgnoreCase("join")) { + Player p = (Player) s.getSender(); + if (GameManager.isPlaying(p) || GameManager.isQueued(p)) { + p.sendMessage("§cYou are already in " + (GameManager.isQueued(p) ? "queue" : "game") + "!"); + return; + } + if (GameManager.getState() != GameManager.GameState.WAITING) { + p.sendMessage("§cThe game had already started!"); + return; + } + GameManager.join(p); + p.sendMessage("§aJoined the game!"); + + return; + } + + if (s.getArgs()[0].equalsIgnoreCase("leave")) { + Player p = (Player) s.getSender(); + if (!GameManager.isPlaying(p) && !GameManager.isQueued(p)) { + p.sendMessage("§cYou aren't in-game or waiting for game! Join the game using /cw join!"); + return; + } + GameManager.leave(p); + p.sendMessage("§aLeft the " + (GameManager.isQueued(p) ? "queue!" : "game!")); + return; + } + + if (s.getArgs()[0].equalsIgnoreCase("gib")) { + if (s.getSender().isOp()) { + Player p = (Player) s.getSender(); + ItemStack nebsnob = ItemsEListeners.SNOWBALL.clone(); + nebsnob.setAmount(32); + ItemStack nebgred = ItemsEListeners.GRENADE.clone(); + nebgred.setAmount(5); + p.getInventory().addItem(nebsnob, nebsnob, ItemsEListeners.BAYONET, nebgred); + } + return; + } + + if (s.getArgs()[0].equalsIgnoreCase("start")) { + if (s.getArgs().length != 1) { + s.getSender().sendMessage("§cUse only /cw start!"); + return; + } + s.getSender().sendMessage("§aStarting!"); + GameManager.start(); + return; + } + if(s.getArgs()[0].equalsIgnoreCase("stop")){ + if(GameManager.getState() != GameManager.GameState.INGAME){ + s.getSender().sendMessage("§cState is not in-game!"); + return; + } + s.getSender().sendMessage("§aStopping game!"); + GameManager.stop(false); + return; + } + if (s.getArgs()[0].equalsIgnoreCase("addpos")) { + if (s.getArgs().length < 2) { + s.getSender().sendMessage("§cUse /cw addpos <-flag>"); + return; + } + if(s.getArgs().length == 3 && s.getArgs()[2].equalsIgnoreCase("flag")){ + CC.getCC().getConfig().set("teams." + s.getArgs()[1].toUpperCase() + ".flag", ((Player) s.getSender()).getLocation().getBlock().getLocation()); + } else { + int cnt = 0; + while (CC.getCC().getConfig().isSet("teams." + s.getArgs()[1].toUpperCase() + ".pos" + cnt) && (CC.getCC().getConfig().getLocation("teams." + s.getArgs()[1].toUpperCase() + ".pos" + cnt) != null)) + cnt++; + CC.getCC().getConfig().set("teams." + s.getArgs()[1].toUpperCase() + ".pos" + cnt, ((Player) s.getSender()).getLocation()); + } + CC.getCC().saveConfig(); + return; + } + } + } catch (Exception e){ + APIBridge.reportException(e, CC.getCC()); + e.printStackTrace(); + } + } + + private String[] printHelp(){ + return (String[]) Arrays.asList("§3--------------------------------§1Help§3--------------------------------", + "§1- §3/cw join §1- join the match", + "§1- §3/cw leave §1- leave the queue", + "§3--------------------------------§1YEET§3--------------------------------").toArray(); + } + + @Cmd(command = "yeet2", desc = "Yeet2", playerSide = true, consoleSide = true) + public void CmdBruh(CommandClass s){ + s.getSender().sendMessage("§4Yeet!2"); + } +} diff --git a/ChristmasWarfare/src/main/java/me/yuri/christmaswarfare/DeathCause.java b/ChristmasWarfare/src/main/java/me/yuri/christmaswarfare/DeathCause.java new file mode 100755 index 0000000..fb7887a --- /dev/null +++ b/ChristmasWarfare/src/main/java/me/yuri/christmaswarfare/DeathCause.java @@ -0,0 +1,11 @@ +package me.yuri.christmaswarfare; + +public enum DeathCause { + SNOWBALL_HIT("{DED} §3got shot by {KILLERQUEEN}§3!"), GRENADE_HIT("{KILLERQUEEN} §3killed {DED} §3with use of his grenade! §eYEET!!!"), STAB("{DED} §cwas stabbed by {KILLERQUEEN}§c!"); + + public final String msg; + + DeathCause(String a) { + msg = a; + } +} \ No newline at end of file diff --git a/ChristmasWarfare/src/main/java/me/yuri/christmaswarfare/GameManager.java b/ChristmasWarfare/src/main/java/me/yuri/christmaswarfare/GameManager.java new file mode 100755 index 0000000..2de7e5e --- /dev/null +++ b/ChristmasWarfare/src/main/java/me/yuri/christmaswarfare/GameManager.java @@ -0,0 +1,296 @@ +package me.yuri.christmaswarfare; + +//import com.sun.applet2.AppletParameters; +import me.yuri.yuriapi.APIBridge; +import me.yuri.yuriapi.api.utils.Colored; +import me.yuri.yuriapi.api.utils.configuration.ConfigVar; +import org.bukkit.*; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.*; + +public class GameManager { + + private static GameState _state = GameState.WAITING; + + protected static Map _flags = new HashMap<>(); + private static Map _originalflags = new HashMap<>(); + + private static Map _points = new HashMap<>(); + + @ConfigVar("time") + static int time = 100; + static int counter = 100; + + public static GamePlayer[] getPlayers() { + return players.toArray(new GamePlayer[]{}); + } + + private static ChatColor _winner = null; + + public static void resetFlag(String ccc) { + Block b = _originalflags.get(Colored.getColorFromName(ccc)); + _flags.put(Colored.getColorFromName(ccc), b); + try { + b.setType((Material) Material.class.getField(ccc.toUpperCase() + "_BANNER").get(Material.class)); + b.setMetadata("team", new FixedMetadataValue(CC.getCC(), ccc.toUpperCase())); + } catch (Exception e){ + APIBridge.reportException(e, CC.getCC()); + } + } + + public static void addPoint(String name) { + Color c = Colored.getColorFromName(name); + int current = _points.get(c); + current++; + _points.put(c, current); + } + + public enum GameState { + WAITING, INGAME + } + + public static GameState getState(){ + return _state; + } + + private static List players = new ArrayList<>(); + static boolean isPlaying(Player p){ + return getPlayer(p) != null; + } + + private static Map queued = new HashMap<>(); + static boolean isQueued(Player p){ + return queued.containsKey(p); + } + + static GamePlayer getPlayer(Player p) { + for(GamePlayer gp : players){ + if(gp.getPlayer().equals(p)) return gp; + } + return null; + } + + static void kill(GamePlayer k, GamePlayer p, DeathCause d){ + if(k.isGrace()) return; + for(GamePlayer pp : players){ + pp.getPlayer().sendMessage(CC._PREFIX + d.msg.replace("{KILLERQUEEN}", k.getPlayer().getDisplayName()).replace("{DED}", p.getPlayer().getDisplayName())); + } + + if(p.getPlayer().getInventory().getHelmet() != null){ + p.getPlayer().getLocation().getBlock().setType(p.getPlayer().getInventory().getHelmet().getType()); + String sss = p.getPlayer().getInventory().getHelmet().getType().name().toUpperCase().split("_")[0]; + p.getPlayer().getLocation().getBlock().setMetadata("team", new FixedMetadataValue(CC.getCC(), sss)); + ChatColor ded = Colored.getChatColorFromName(p.getColorName()); + ChatColor decap = Colored.getChatColorFromName(sss); + _flags.put(Colored.getColorFromName(sss), p.getPlayer().getLocation().getBlock()); + for(GamePlayer pp : players){ + pp.getPlayer().sendMessage(CC._PREFIX + "§aTeam " + ded + p.getColorName() +" §ais no longer holding team " + decap + sss +"§a's flag!"); + } + } + + + + if(!k.equals(p)) { + Random r = new Random(); + k.addKill(); + int perc = r.nextInt(101); + if(perc <= CC._GRENADE_PERC){ + int amount = 1 + r.nextInt(3); + ItemsEListeners.gibSpecItem(k, ItemsEListeners.GRENADE, amount); + k.getPlayer().sendMessage("§aCongratulations, you have received " + amount + " explosive bois! YEET 'EM!!!"); + } else { + int i = 10; + i += r.nextInt(11); + ItemsEListeners.gibSpecItem(k, ItemsEListeners.SNOWBALL, i); + k.getPlayer().sendMessage("§a+" + i + " snowballs. Yeet them wisely..."); + } + } + p.addDeath(); + p.teleportRandom(); + p.setGrace(); + ItemsEListeners.gibItems(p); + } + + static void start(){ + counter = time; + _state = GameState.INGAME; + Map> kek = new HashMap<>(); + try { + for (String s : CC.getCC().getConfig().getConfigurationSection("teams").getKeys(false)) { + //CC.sendCns("&aTEAM: &c" + s); + List l = new ArrayList<>(); + for (String c : CC.getCC().getConfig().getConfigurationSection("teams."+s).getKeys(false)) { + Location loc = CC.getCC().getConfig().getLocation("teams."+s+"."+c); + if(loc != null) { + if(!c.equalsIgnoreCase("flag")) + l.add(loc); + else { + _flags.put(Colored.getColorFromName(s), loc.getBlock()); + _originalflags.put(Colored.getColorFromName(s), loc.getBlock()); + loc.getBlock().setType((Material) Material.class.getField(s.toUpperCase()+"_BANNER").get(Material.class)); + loc.getBlock().setMetadata("team", new FixedMetadataValue(CC.getCC(), s.toUpperCase())); + } + } + //CC.sendCns("&e - &c" + c+": &a"+CC.getCC().getConfig().getLocation("teams."+s+"."+c)); + //CC.sendCns("&a > (teams."+s+"."+c+") &e-> "+CC.getCC().getConfig().getLocation("teams."+s+"."+c)); + } + kek.put(s, l); + } + Random r = new Random(); + //int max = queued.size(); + //int teams = kek.keySet().size(); + //int asym = max%teams; + List pls = new ArrayList<>(queued.keySet()); + Collections.shuffle(pls, r); + + int cnt = 0; + String[] colors = kek.keySet().toArray(new String[]{}); + //CC.sendCns("&6colors: " + colors.length + " queued: " + queued.keySet().size() +" locs: "+kek.keySet().size()); + for(Player p : queued.keySet()){ + if(cnt >= kek.keySet().size()) cnt = 0; + String cccc = colors[cnt]; + GamePlayer gp = new GamePlayer(p, queued.get(p), Colored.getColorFromName(cccc),kek.get(cccc).toArray(new Location[]{}), cccc); + players.add(gp); + p.sendMessage("§aStarting game!"); + gp.teleportRandom(); + ItemsEListeners.gibItems(gp); + ChatColor cc = Colored.getChatColorFromName(gp.getColorName()); + p.setDisplayName(cc+p.getName()); + p.setPlayerListName(cc+p.getName()); + gp.getPlayer().setHealth(20); + gp.getPlayer().setFoodLevel(20); + gp.getPlayer().setTotalExperience(0); + gp.getPlayer().sendMessage("§a§lStart!!!"); + cnt++; + + } + + for(Color c : _flags.keySet()){ + _points.put(c, 0); + } + + queued.clear(); + new BukkitRunnable () { + + @Override + public void run() { + for(GamePlayer gp : players){ + gp.getPlayer().setLevel(counter); + } + if(counter <= 0){ + cancel(); + stop(false); + return; + } + counter--; + } + }.runTaskTimer(CC.getCC(), 20L, 20L); + }catch (Exception e){ + CC.sendCns("&4ERROR: "); + e.printStackTrace(); + APIBridge.reportException(e, CC.getCC()); + return; + } + } + + public static void stop(boolean b){ + if(!b){ + for(GamePlayer gp : players){ + if(gp.getPlayer().getInventory().getHelmet() != null){ + ItemStack is = gp.getPlayer().getInventory().getHelmet(); + if(is.getType().name().endsWith("_BANNER")){ + _flags.put(Colored.getColorFromName(gp.getPlayer().getInventory().getHelmet().getType().name().toUpperCase().split("_")[0]), gp.getPlayer().getLocation().getBlock()); + } + } + } + + int highest = -1; + for(int i : _points.values()){ + if(i > highest) + highest = i; + } + List cols = new ArrayList<>(); + for(Color c : _points.keySet()){ + if(_points.get(c) == highest) + cols.add(c); + } + if(cols.size() != 1) { + Map scores = new HashMap<>(); + List torem = new ArrayList<>(); + for(Color c : _flags.keySet()){ + if(!cols.contains(c)) torem.add(c); + } + torem.forEach(f -> _flags.remove(f)); + torem.clear(); + for (Block bb : _flags.values()) { + Color c = Colored.getColorFromName(bb.getMetadata("team").get(0).asString()); + scores.put(c, bb.getLocation().distance(_originalflags.get(c).getLocation())); + } + + double lowest = Double.MAX_VALUE; + for (double d : scores.values()) { + if (d < lowest) + lowest = d; + } + + for (Color c : scores.keySet()) { + if (scores.get(c) == lowest) { + _winner = Colored.getChatColorFromName(Colored.getFromColor(c)); + } + } + } else _winner = Colored.getChatColorFromName(Colored.getFromColor(cols.get(0))); + + for(Block bb : _flags.values()){ + bb.setType(Material.AIR); + bb.removeMetadata("team", CC.getCC()); + } + + for(GamePlayer gp : players){ + if(_winner == null) + gp.getPlayer().sendTitle("§c§lStalemate", "§7No team won", 25,120,60); + else + gp.getPlayer().sendTitle((Colored.getChatColorFromName(gp.getColorName()).equals(_winner) ? "§6§lVictory" : "§c§lDefeat"), + (Colored.getChatColorFromName(gp.getColorName()).equals(_winner) ? "§eOur team won!" : _winner + _winner.name() +" TEAM WINS!"), 25, 120, 60); + } + } + for(GamePlayer p : players){ + p.getPlayer().teleport(p.getOriginalLocation()); + p.getPlayer().setDisplayName(p.getPlayer().getName()); + p.getPlayer().setPlayerListName(p.getPlayer().getName()); + p.getPlayer().getInventory().clear(); + } + players.clear(); + queued.clear(); + _state = GameState.WAITING; + } + + + public static void join(Player p) { + if(isQueued(p) || isPlaying(p)) return; + if(queued.size() >= CC.MAX_PLAYERS){ + p.sendMessage("§cThe queue has already reached the max player count!"); + return; + } + queued.put(p, p.getLocation()); + } + + public static void leave(Player p) { + if(isQueued(p)){ + p.teleport(queued.get(p)); + queued.remove(p); + p.setDisplayName(p.getName()); + p.setPlayerListName(p.getName()); + } else if(isPlaying(p)) { + GamePlayer g = getPlayer(p); + p.teleport(g.getOriginalLocation()); + players.remove(g); + p.setDisplayName(p.getName()); + p.setPlayerListName(p.getName()); + } + } +} diff --git a/ChristmasWarfare/src/main/java/me/yuri/christmaswarfare/GamePlayer.java b/ChristmasWarfare/src/main/java/me/yuri/christmaswarfare/GamePlayer.java new file mode 100755 index 0000000..1f5dcc7 --- /dev/null +++ b/ChristmasWarfare/src/main/java/me/yuri/christmaswarfare/GamePlayer.java @@ -0,0 +1,115 @@ +package me.yuri.christmaswarfare; + +import com.sun.istack.internal.NotNull; +import org.bukkit.Color; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import me.yuri.yuriapi.api.utils.CustomScoreboard; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scoreboard.DisplaySlot; + +import java.util.Random; + +public class GamePlayer { + + public GamePlayer(Player p, Location o, Color t, Location[] rs, String cn){ + player = p; + originalLocation = o; + tc = t; + respawns = rs; + cname = cn; + sbi = new CustomScoreboard(DisplaySlot.SIDEBAR, "§f§lC§4§lH§f§lR§4§lI§f§lS§4§lT§f§lM§4§lA§f§lS §4§lW§f§lA§4§lR§f§lF§4§lA§f§lR§4§lE"); + sbi.addScore("kills", "§aYour kills §e>> §b"+kills); + sbi.addScore("deaths", "§aYour deaths §e>> §b"+deaths); + sbi.addToPlayer(p); + } + + @NotNull + private Player player; + @NotNull + private Color tc; + @NotNull + private Location[] respawns; + @NotNull + private Location originalLocation; + @NotNull + private String cname; + + private int kills = 0; + private int deaths = 0; + + private boolean grace = false; + + public void setGrace(int time){ + grace = true; + new BukkitRunnable(){ + @Override + public void run() { + grace = false; + } + }.runTaskLater(CC.getCC(), time*20L); + } + + public void setGrace(){ + grace = true; + new BukkitRunnable(){ + @Override + public void run() { + grace = false; + } + }.runTaskLater(CC.getCC(), 5*20L); + } + + private CustomScoreboard sbi; + + public Player getPlayer() { + return player; + } + + public Color getTeamColor(){ + return tc; + } + + public CustomScoreboard getSbi() { + return sbi; + } + + public int getKills(){ + return kills; + } + + public void addKill(){ + kills++; + sbi.updateScore("kills", "§aYour kills §e>> §b"+kills); + } + + public int getDeaths(){ + return deaths; + } + + public void addDeath(){ + deaths++; + sbi.updateScore("deaths", "§aYour deaths §e>> §b"+deaths); + } + + public Location getRespawnLocation() { + return respawns[new Random().nextInt(respawns.length)]; + } + + public Location getOriginalLocation() { + return originalLocation; + } + + public void teleportRandom() { + //CC.sendCns("&3len: " + respawns.length); + player.teleport(respawns[new Random().nextInt(respawns.length)]); + } + + public String getColorName() { + return cname; + } + + public boolean isGrace() { + return grace; + } +} diff --git a/ChristmasWarfare/src/main/java/me/yuri/christmaswarfare/ItemsEListeners.java b/ChristmasWarfare/src/main/java/me/yuri/christmaswarfare/ItemsEListeners.java new file mode 100755 index 0000000..bb8e160 --- /dev/null +++ b/ChristmasWarfare/src/main/java/me/yuri/christmaswarfare/ItemsEListeners.java @@ -0,0 +1,365 @@ +package me.yuri.christmaswarfare; + +import me.yuri.yuriapi.APIBridge; +import me.yuri.yuriapi.api.utils.Colored; +import org.bukkit.*; +import org.bukkit.block.Sign; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.entity.Snowball; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.SignChangeEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.entity.ProjectileHitEvent; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerEggThrowEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerRespawnEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.LeatherArmorMeta; +import org.bukkit.util.Vector; + +import java.util.Arrays; +import java.util.Random; + +public class ItemsEListeners implements Listener { + + static ItemStack BAYONET; + static ItemStack SNOWBALL; + static ItemStack GRENADE; + + static { + BAYONET = new ItemStack(Material.IRON_SWORD); + SNOWBALL = new ItemStack(Material.SNOWBALL); + GRENADE = new ItemStack(Material.EGG); + + ItemMeta imb = BAYONET.getItemMeta(); + assert imb != null; + imb.setDisplayName("§3§k000§c Santa's Bayonet §3§k000"); + imb.setUnbreakable(true); + BAYONET.setItemMeta(imb); + + ItemMeta ims = SNOWBALL.getItemMeta(); + assert ims != null; + ims.setDisplayName("§aSnowball"); + ims.setLore(Arrays.asList("§eYeet it into someone's face", "§eYEET HARD!!!")); + SNOWBALL.setItemMeta(ims); + + ItemMeta ime = GRENADE.getItemMeta(); + assert ime != null; + ime.setDisplayName("§eFrag Grenade"); + ime.setLore(Arrays.asList("§eYeet it to make lads go BOOM", "§eOH LAWD HE COMIN'!!!")); + GRENADE.setItemMeta(ime); + + + } + + @EventHandler + public void onRespawn(PlayerRespawnEvent e) { + if (GameManager.isPlaying(e.getPlayer())) { + GamePlayer gp = GameManager.getPlayer(e.getPlayer()); + e.setRespawnLocation(gp.getRespawnLocation()); + e.getPlayer().getInventory().clear(); + gibItems(gp); + } + } + + @EventHandler + public void onCapture(PlayerInteractEvent e){ + if(e.getAction() == Action.RIGHT_CLICK_BLOCK){ + if(GameManager.isPlaying(e.getPlayer())){ + String[] s = e.getClickedBlock().getType().name().split("_"); + if(s.length != 2) return; + if(!s[1].equalsIgnoreCase("BANNER")) return; + if(e.getPlayer().getInventory().getHelmet() == null) return; + ChatColor c, cc; + String sss = e.getPlayer().getInventory().getHelmet().getType().name().toUpperCase().split("_")[0]; + try { + c = Colored.getChatColorFromName(GameManager.getPlayer(e.getPlayer()).getColorName()); + cc = Colored.getChatColorFromName(sss); + } catch (Exception ignored){ + ignored.printStackTrace(); + return; + } + + for(GamePlayer gg : GameManager.getPlayers()){ + gg.getPlayer().sendMessage(CC._PREFIX + "§aPlayer " + e.getPlayer().getDisplayName() + " §afrom team " + c + c.name() +" §ahas captured team " + + cc + cc.name().toUpperCase()+"§a's flag!"); + if(gg.getColorName().equalsIgnoreCase(cc.name())) + gg.getPlayer().playSound(gg.getPlayer().getLocation(), Sound.ENTITY_ENDER_DRAGON_GROWL, 1, 1); + } + e.getPlayer().getInventory().setHelmet(null); + e.getPlayer().playSound(e.getPlayer().getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 5, 1); + GameManager.resetFlag(cc.name()); + GameManager.addPoint(c.name()); + } + } + } + + @EventHandler + public void onGrab(BlockBreakEvent e){ + if(GameManager.isPlaying(e.getPlayer())) + if(e.getBlock().hasMetadata("team")) { + if(e.getBlock().getMetadata("team").get(0).asString().equalsIgnoreCase(GameManager.getPlayer(e.getPlayer()).getColorName())){ + e.setCancelled(true); + return; + } + e.setDropItems(false); + e.setCancelled(false); + + ChatColor c, cc; + try { + c = Colored.getChatColorFromName(GameManager.getPlayer(e.getPlayer()).getColorName()); + cc = Colored.getChatColorFromName(e.getBlock().getMetadata("team").get(0).asString()); + } catch (Exception ignored){ + ignored.printStackTrace(); + return; + } + GameManager._flags.put(Colored.getColorFromName(cc.name().toUpperCase()), null); + ItemStack ii =new ItemStack(e.getBlock().getType()); + ItemMeta iim = ii.getItemMeta(); + iim.setDisplayName(cc+"Team " + cc.name().toLowerCase() +"'s flag"); + ii.setItemMeta(iim); + e.getPlayer().getInventory().setHelmet(ii); + for(GamePlayer gp : GameManager.getPlayers()){ + gp.getPlayer().sendMessage(CC._PREFIX + "§aTeam "+c+GameManager.getPlayer(e.getPlayer()).getColorName()+ " §ahas taken " + cc + + cc.name() + " §ateam's flag!"); + } + } + } + + public static void gibItems(GamePlayer gp) { + try { + ItemStack chest = new ItemStack(Material.LEATHER_CHESTPLATE); + ItemStack legg = new ItemStack(Material.LEATHER_LEGGINGS); + ItemStack leg = new ItemStack(Material.LEATHER_BOOTS); + LeatherArmorMeta chs = (LeatherArmorMeta) chest.getItemMeta(); + LeatherArmorMeta lg = (LeatherArmorMeta) leg.getItemMeta(); + LeatherArmorMeta lgg = (LeatherArmorMeta) legg.getItemMeta(); + chs.setColor(gp.getTeamColor()); + lg.setColor(gp.getTeamColor()); + lgg.setColor(gp.getTeamColor()); + chest.setItemMeta(chs); + legg.setItemMeta(lgg); + leg.setItemMeta(lg); + ItemStack nebsnob = SNOWBALL.clone(); + nebsnob.setAmount(32); + ItemStack nebgred = GRENADE.clone(); + nebgred.setAmount(5); + gp.getPlayer().getInventory().clear(); + gp.getPlayer().getInventory().addItem(nebsnob, nebsnob, BAYONET, nebgred); + gp.getPlayer().getInventory().setChestplate(chest); + gp.getPlayer().getInventory().setLeggings(legg); + gp.getPlayer().getInventory().setBoots(leg); + } catch (Exception e) { + APIBridge.reportException(e, CC.getCC()); + } + } + + public static void gibSpecItem(GamePlayer gp, ItemStack i, int amount){ + Player p = gp.getPlayer(); + + ItemStack ni = i.clone(); + ni.setAmount(amount); + p.getInventory().addItem(ni); + } + + public static void gibSpecItem(Player p, ItemStack i, int amount){ + ItemStack ni = i.clone(); + ni.setAmount(amount); + p.getInventory().addItem(ni); + } + + @EventHandler + public void onClick(InventoryClickEvent e) { + if (GameManager.isPlaying((Player) e.getWhoClicked())) { + if (e.getClick() == ClickType.DROP) e.setCancelled(true); + if (e.getSlotType() == InventoryType.SlotType.ARMOR) e.setCancelled(true); + } + } + + @EventHandler + public void onDrop(PlayerDropItemEvent e) { + if (GameManager.isPlaying(e.getPlayer())) { + e.setCancelled(true); + } + } + + @EventHandler + public void onDestroy(BlockBreakEvent e) { + if (GameManager.isPlaying(e.getPlayer())) { + if (!e.getPlayer().isOp()) + e.setCancelled(true); + } + } + + @EventHandler + public void onUse(PlayerInteractEvent e) { + if (e.getAction() != Action.RIGHT_CLICK_AIR && e.getAction() != Action.RIGHT_CLICK_BLOCK) return; + if (!containsItem(e.getPlayer())) return; + activateItem(e.getItem()); + } + + @EventHandler + public void onGrenadeThrow(PlayerEggThrowEvent e) { + if (GameManager.isPlaying(e.getPlayer())) { + e.setHatching(false); + } + } + + @EventHandler + public void onHit(ProjectileHitEvent e) { + //CC.sendCns("§eType: " + e.getEntity().getType().name() +" shooter: " + ((Player) e.getEntity().getShooter()).getName() +" §cPlayer?: " + (e.getEntity().getShooter() instanceof Player) + + //"§3Play?: " + GameManager.isPlaying((Player) e.getEntity().getShooter())); + if (e.getEntity().getType() == EntityType.SNOWBALL) { + if (e.getEntity().getShooter() instanceof Player) { + if (!GameManager.isPlaying((Player) e.getEntity().getShooter())) return; + GamePlayer p = GameManager.getPlayer((Player) e.getEntity().getShooter()); + e.getEntity().getWorld().spawnParticle(Particle.REDSTONE, e.getEntity().getLocation(), 13, new Particle.DustOptions(p.getTeamColor(), 2)); + e.getEntity().getWorld().playSound(e.getEntity().getLocation(), Sound.ENTITY_SPLASH_POTION_BREAK, 3, 1); + + if (e.getHitEntity() != null) { + //CC.sendCns("§cHit: " + e.getHitEntity().getType().name()); + if (e.getHitEntity() instanceof Player) { + Player hit = (Player) e.getHitEntity(); + if (!GameManager.isPlaying(hit)) return; + if(hit.equals(p.getPlayer())){ + hit.playSound(hit.getLocation(), Sound.ENTITY_VILLAGER_NO, 10, 5); + return; + } + GameManager.kill(p, GameManager.getPlayer(hit), DeathCause.SNOWBALL_HIT); + e.getEntity().getWorld().playSound(e.getEntity().getLocation(), Sound.ENTITY_VILLAGER_HURT, 5, 1); //TODO YES + } + } + } + } else if (e.getEntity().getType() == EntityType.EGG) { + if (e.getEntity().getShooter() instanceof Player) { + if (!GameManager.isPlaying((Player) e.getEntity().getShooter())) return; + GamePlayer p = GameManager.getPlayer((Player) e.getEntity().getShooter()); + e.getEntity().getWorld().spawnParticle(Particle.EXPLOSION_LARGE, e.getEntity().getLocation(), 1); + e.getEntity().getWorld().playSound(e.getEntity().getLocation(), Sound.ENTITY_GENERIC_EXPLODE, 7, 1); + Random r = new Random(); + for(Entity en : e.getEntity().getNearbyEntities(3,3,3)){ + if(en instanceof Player){ + Player pp = (Player) en; + if(GameManager.isPlaying(pp)){ + GameManager.kill(p, GameManager.getPlayer(pp), DeathCause.GRENADE_HIT); + } + } + } + for (short ss = 0; ss < (13 + r.nextInt(75)); ss++) { + Snowball s1 = e.getEntity().getWorld().spawn(e.getEntity().getLocation(), Snowball.class); + s1.setShooter(e.getEntity().getShooter()); + s1.setVelocity(new Vector(-4 + r.nextInt(8), -3 + r.nextInt(6), -4 + r.nextInt(8))); + s1.setBounce(true); + } + + + } + } + } + + private void activateItem(ItemStack item) { + + } + + private boolean containsItem(Player p) { + if (p.getInventory().getItemInMainHand().isSimilar(BAYONET)) + return true; + return false; + } + + @EventHandler + public void onDed(PlayerDeathEvent e) { + if (!GameManager.isPlaying(e.getEntity())) return; + e.setDeathMessage(null); + e.getEntity().spigot().respawn(); + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(CC.getCC(), () -> { + GameManager.getPlayer(e.getEntity()).teleportRandom(); + }, 1); + } + + @EventHandler + public void onStab(EntityDamageByEntityEvent e){ + if(e.getDamager() instanceof Player && e.getEntity() instanceof Player){ + Player k = (Player) e.getDamager(); + Player dm = (Player) e.getEntity(); + if(GameManager.isPlaying(k) && GameManager.isPlaying(dm)){ + if(k.getInventory().getItemInMainHand().isSimilar(BAYONET)){ + e.setCancelled(true); + dm.playSound(dm.getLocation(), Sound.ENTITY_VILLAGER_HURT, 10, -4); + GameManager.kill(GameManager.getPlayer(k), GameManager.getPlayer(dm), DeathCause.STAB); + } + } + } + } + + //SIGNS + @EventHandler + public void onInteract(PlayerInteractEvent e) { + if (e.getAction() == Action.RIGHT_CLICK_BLOCK) { + assert e.getClickedBlock() != null; + if (e.getClickedBlock().getState() instanceof Sign) { + Sign s = (Sign) e.getClickedBlock().getState(); + if (s.getLine(0).equals("§f[§cXmasWarfare§f]")) { + Player p = (Player) e.getPlayer(); + if (s.getLine(1).equals("§7join")) { + if (GameManager.isPlaying(p) || GameManager.isQueued(p)) { + p.sendMessage("§cYou are already in " + (GameManager.isQueued(p) ? "queue" : "game") + "!"); + return; + } + if (GameManager.getState() != GameManager.GameState.WAITING) { + p.sendMessage("§cThe game had already started!"); + return; + } + GameManager.join(p); + p.sendMessage("§aJoined the game!"); + } else { + if (!GameManager.isPlaying(p) && !GameManager.isQueued(p)) { + p.sendMessage("§cYou aren't in-game or waiting for game! Join the game using /cw join!"); + return; + } + GameManager.leave(p); + p.sendMessage("§aLeft the " + (GameManager.isQueued(p) ? "queue!" : "game!")); + } + } + } + } + } + + @EventHandler + public void onSignCreate(SignChangeEvent e) { + //CC.sendCns("&4Signchange"); + //Sign s = (Sign) e.getBlock().getState(); + //CC.sendCns("&3" + e.getLine(0)); + if (e.getLine(0) != null) + if (e.getLine(0).equalsIgnoreCase("[cw]") || e.getLine(0).equalsIgnoreCase("[xmaswarfare]")) { + e.setLine(0, "§f[§cXmasWarfare§f]"); + switch (e.getLine(1)) { + case "join": + e.setLine(1, "§7join"); + e.setLine(2, "§00§7/§0" + CC.MAX_PLAYERS); + break; + case "leave": + e.setLine(1, "§7leave"); + break; + default: + e.setLine(0, "§4[XmasWarfare]"); + e.setLine(1, "§4§lInvalid!"); + e.getPlayer().sendMessage("§cFor line 1 use 'join' or 'leave'!"); + return; + } + //s.update(); + e.getPlayer().sendMessage("§aSign created!"); + } + } +} diff --git a/ChristmasWarfare/src/main/resources/config.yml b/ChristmasWarfare/src/main/resources/config.yml new file mode 100755 index 0000000..208640d --- /dev/null +++ b/ChristmasWarfare/src/main/resources/config.yml @@ -0,0 +1,17 @@ +#WIP +luckyblocks-enabled: false + +#Max players per game +max-players: 20 +#Message prefix ('none' is no prefix; include space in prefix) +prefix: "none" +#Round time +time: 180 +#x [%] that player will receive grenade on kill (0 - none, 100 - always) +grenade-percentage: 10 +#POSITIONS +teams: + BLUE: + 105.0,105.0,105.0 + RED: + 100.0,100.0,100.0 \ No newline at end of file diff --git a/ChristmasWarfare/src/main/resources/plugin.yml b/ChristmasWarfare/src/main/resources/plugin.yml new file mode 100755 index 0000000..ef0ef37 --- /dev/null +++ b/ChristmasWarfare/src/main/resources/plugin.yml @@ -0,0 +1,11 @@ +name: ChristmasWarfare +main: me.yuri.christmaswarfare.CC +version: 1.0E +depend: [YuriAPI] +api-version: 1.13 + +commands: + cw: + description: yeet + yeet2: + description: yeet2 \ No newline at end of file diff --git a/CommandItems/pom.xml b/CommandItems/pom.xml new file mode 100755 index 0000000..26b3833 --- /dev/null +++ b/CommandItems/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + me.yuri + CommandItems + 1.0-A + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + + + + + + + + me.yuri + YuriAPI + 1.2.3 + system + /mnt/B65CCF2D5CCEE6E9/Projects/IdeaProjects/YAPI/YuriAPI.jar + + + org.bukkit + craftbukkit + 1.14.4-R0.1-SNAPSHOT + + + + + \ No newline at end of file diff --git a/CommandItems/src/main/java/me/yuri/cmditems/C.java b/CommandItems/src/main/java/me/yuri/cmditems/C.java new file mode 100755 index 0000000..db385a1 --- /dev/null +++ b/CommandItems/src/main/java/me/yuri/cmditems/C.java @@ -0,0 +1,37 @@ +package me.yuri.cmditems; + +import me.yuri.yuriapi.api.command.CommandManager; +import org.bukkit.NamespacedKey; +import org.bukkit.plugin.java.JavaPlugin; + +public class C extends JavaPlugin { + + private static C instance; + + protected static NamespacedKey nsk; + protected static NamespacedKey nsc; + + //Cannot instantiate NamespacedKey before onEnable()... + + public static C getMainClass() { + return instance; + } + + @Override + public void onLoad() { + instance = this; + } + + @Override + public void onDisable() { + } + + @Override + public void onEnable() { + new CommandManager(this).registerCommand(new Commands()); + this.getServer().getPluginManager().registerEvents(new Listeners(), this); + nsc = new NamespacedKey(C.getMainClass(), "command"); + nsk = new NamespacedKey(C.getMainClass(), "events"); + } + +} \ No newline at end of file diff --git a/CommandItems/src/main/java/me/yuri/cmditems/Commands.java b/CommandItems/src/main/java/me/yuri/cmditems/Commands.java new file mode 100755 index 0000000..cd84f81 --- /dev/null +++ b/CommandItems/src/main/java/me/yuri/cmditems/Commands.java @@ -0,0 +1,82 @@ +package me.yuri.cmditems; + +import me.yuri.yuriapi.api.command.Cmd; +import me.yuri.yuriapi.api.command.CommandEvent; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataType; + +import java.util.ArrayList; +import java.util.List; + +public class Commands { + + @Cmd(command = "addcommand", aliases = "addcmd", consoleSide = false, permissions = "commanditems.addcommand") + public void addCommand(CommandEvent e){ + + Player s = (Player) e.getSender(); + + ItemStack is = s.getInventory().getItemInMainHand(); + + if(is.getType() == Material.AIR){ + e.reply("§cYou need to hold an item in order to apply a command to it!"); + return; + } + + if(e.getArgs().length < 2){ + e.reply("§cYou need to specify the event and command!"); + return; + } + + String event = e.getArgs()[0]; + + String[] event2 = event.split(","); + String command = e.getArgsString().substring(e.getArgs()[0].length()+1).trim(); + List events; + + try { + events = parse(event2); + } catch (IllegalArgumentException a){ + e.reply("§cUknown event type: §6"+a.getMessage()+"§c!"); + return; + } + + int[] a = {0}; + + if(!events.contains(EventType.ALL)){ + a = new int[events.size()]; + int cnt = 0; + for(EventType aa : events){ + a[cnt] = aa.ordinal(); + cnt++; + } + } + + ItemMeta im = is.getItemMeta(); + + assert im != null; + + im.getPersistentDataContainer().set(C.nsk, PersistentDataType.INTEGER_ARRAY, a); + im.getPersistentDataContainer().set(C.nsc, PersistentDataType.STRING, command); + //im.setDisplayName("§4§lMETA"); + is.setItemMeta(im); + + e.reply("§aCommand set!"); + + } + + private static List parse(String... a){ + List e = new ArrayList<>(); + for(String b : a){ + try { + if(!e.contains(EventType.valueOf(b.toUpperCase()))) + e.add(EventType.valueOf(b.toUpperCase())); + } catch (IllegalArgumentException ignored){ + throw new IllegalArgumentException(b); + } + } + return e; + } +} diff --git a/CommandItems/src/main/java/me/yuri/cmditems/EventType.java b/CommandItems/src/main/java/me/yuri/cmditems/EventType.java new file mode 100755 index 0000000..6203e59 --- /dev/null +++ b/CommandItems/src/main/java/me/yuri/cmditems/EventType.java @@ -0,0 +1,5 @@ +package me.yuri.cmditems; + +public enum EventType { + ALL, DAMAGE_IMPOSED, DAMAGE_RECEIVED, ITEM_USE, ITEM_USE_BLOCK, ITEM_USE_AIR, BLOCK_BREAK, DROPPED, PICKED_UP +} diff --git a/CommandItems/src/main/java/me/yuri/cmditems/Listeners.java b/CommandItems/src/main/java/me/yuri/cmditems/Listeners.java new file mode 100755 index 0000000..2626c26 --- /dev/null +++ b/CommandItems/src/main/java/me/yuri/cmditems/Listeners.java @@ -0,0 +1,32 @@ +package me.yuri.cmditems; + +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; + +public class Listeners implements Listener { + + @EventHandler + public void onUse(PlayerInteractEvent e){ + ItemStack is = e.getPlayer().getInventory().getItemInMainHand(); + if(is.getType() != Material.AIR){ + if(is.getItemMeta() == null) return; + + PersistentDataContainer dc = is.getItemMeta().getPersistentDataContainer(); + + if(dc.has(C.nsk, PersistentDataType.INTEGER_ARRAY)){ + int[] i = dc.get(C.nsk, PersistentDataType.INTEGER_ARRAY); + String cmd = dc.get(C.nsc, PersistentDataType.STRING); + if(i == null || cmd == null) return; + if(i[0] == 0){ + e.getPlayer().performCommand(cmd); + } + } + } + } +} diff --git a/CommandItems/src/main/resources/plugin.yml b/CommandItems/src/main/resources/plugin.yml new file mode 100755 index 0000000..1450677 --- /dev/null +++ b/CommandItems/src/main/resources/plugin.yml @@ -0,0 +1,11 @@ +name: CommandItems +version: 1.0E +main: me.yuri.cmditems.C +author: yuri +depend: + - YuriAPI +commands: + addcommand: + aliases: addcmd + description: Assigns a command to an item + permission: commanditems.addcmd \ No newline at end of file diff --git a/EscapePlugin/src/config.yml b/EscapePlugin/src/config.yml new file mode 100755 index 0000000..6db12d6 --- /dev/null +++ b/EscapePlugin/src/config.yml @@ -0,0 +1,6 @@ +locExecution.world: "world" +locExecution.x: +locExecution.y: +locExecution.z: +locExecution.pitch: +locExecution.yaw: \ No newline at end of file diff --git a/EscapePlugin/src/me/golgroth/escape/EscM.java b/EscapePlugin/src/me/golgroth/escape/EscM.java new file mode 100755 index 0000000..910634d --- /dev/null +++ b/EscapePlugin/src/me/golgroth/escape/EscM.java @@ -0,0 +1,98 @@ +package me.golgroth.escape; + +import me.golgroth.escape.commands.CommandPlayerNPC; +import me.golgroth.escape.listeners.EsListener; +import org.bukkit.command.CommandExecutor; +import org.bukkit.event.Listener; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + + +public class EscM extends JavaPlugin { + private static EscM pl; + public static EscM getPlugin(){ + return pl; + } + private String[] excl = { + "Essentials", "PermissionsEx" + }; + public static HashMap plugins = new HashMap(); + private static List excluded = new ArrayList(); + boolean acht = false; + @Override + public void onEnable(){ + //TODO remove until here !!! -> checkPlugins(); + pl = this; + + regLst(); + regCmds(); + saveDefaultConfig(); + saveConfig(); + } + + @Override + public void onDisable(){ + + } + + private void regLst() { + /* if(acht){ + regListener(new me.golgroth.escape.listeners.cht.BlockBreak(this)); + regListener(new me.golgroth.escape.listeners.cht.Gamemode(this)); + regListener(new me.golgroth.escape.listeners.cht.Fly(this)); + regListener(new me.golgroth.escape.listeners.cht.BlockFall(this)); + regListener(new me.golgroth.escape.listeners.cht.NoMoving(this)); + }*/ + regListener(new me.golgroth.escape.listeners.FireballTrail()); + //regListener(new me.golgroth.escape.listeners.Locations(this)); + regListener(new me.golgroth.escape.listeners.DoorListener(this)); + } + + private void regListener(Listener l){ + this.getServer().getPluginManager().registerEvents(l, this); + log("§aListener §c" + l + "§a registered!"); //Listener zarejestrowany, registered zarejestrowany4 + } + + private void regCmds(){ + regCmd("npc", new CommandPlayerNPC()); + } + private void regCmd(String cmd, CommandExecutor c){ + this.getCommand(cmd).setExecutor(c); + } + + private void log(String msg){ + this.getServer().getConsoleSender().sendMessage(msg); + } + private void checkPlugins(){ + for(String s : excl){ + excluded.add(s); + } + new BukkitRunnable(){ + @Override + public void run() { + log("§bPlugins found:"); + for (Plugin pl : EscM.getPlugin().getServer().getPluginManager().getPlugins()) { + if (excluded.contains(pl.getName())) { + log("§b- §c" + pl.getName()); + } else { + log("§b- §a" + pl.getName()); + } + plugins.put(pl.getName(), pl); + } + for (String s : excluded) { + if (plugins.containsKey(s)) { + EscM.getPlugin().getServer().getPluginManager().disablePlugin(plugins.get(s)); + log("§aPlugin §c" + s + "§a disabled!"); + } + } + } + + }.runTaskLater(this, 100L); + } + +} diff --git a/EscapePlugin/src/me/golgroth/escape/commands/CommandLocation.java b/EscapePlugin/src/me/golgroth/escape/commands/CommandLocation.java new file mode 100755 index 0000000..72fa563 --- /dev/null +++ b/EscapePlugin/src/me/golgroth/escape/commands/CommandLocation.java @@ -0,0 +1,62 @@ +package me.golgroth.escape.commands; + +import me.golgroth.escape.EscM; +import org.bukkit.Location; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class CommandLocation implements CommandExecutor { + + @Override + public boolean onCommand(CommandSender sender, Command cmd, String cmdLabel, String[] args) { + if(cmdLabel.equalsIgnoreCase("loc")) { + if (!(sender instanceof Player)) { + sender.sendMessage("§cYou must be a player to execute this command!"); + return true; + } + Player p = (Player) sender; + if (args.length == 0) { + p.sendMessage("§bCommands: "); + p.sendMessage("§a- /loc savedata"); + p.sendMessage("§a- /loc setlocation "); + p.sendMessage("§a- /loc locations"); + return true; + } + if (args.length == 1) { + if (args[0].equalsIgnoreCase("savedata")) { + EscM.getPlugin().saveConfig(); + } + + if(args[0].equalsIgnoreCase("locations")){ + java.util.Map m = me.golgroth.escape.listeners.Locations.getLocs(); + int i = 0; + for(String s : m.keySet()){ + i++; + sender.sendMessage("§f" +i+ ") §a"+s+" §b-> §a" + m.get(s).getX() + " " + m.get(s).getY() + " " + m.get(s).getZ()); + } + } + } + + + if(args.length == 2){ + if(args[0].equalsIgnoreCase("setlocation")){ + String name = args[1]; + Location loc = p.getLocation(); + EscM.getPlugin().getConfig().createSection(name); + EscM.getPlugin().getConfig().getConfigurationSection(name).set("x", loc.getX()); + EscM.getPlugin().getConfig().getConfigurationSection(name).set("y", loc.getY()); + EscM.getPlugin().getConfig().getConfigurationSection(name).set("z", loc.getZ()); + EscM.getPlugin().getConfig().getConfigurationSection(name).set("yaw", loc.getYaw()); + EscM.getPlugin().getConfig().getConfigurationSection(name).set("pitch", loc.getPitch()); + EscM.getPlugin().saveConfig(); + + p.sendMessage("§aLocation §e§l" + name + "§a saved with coordinates: §e" + loc.getX() +" "+ loc.getY() + " " + loc.getZ() + "§a !"); + } + } + return true; + } + return false; + } +} diff --git a/EscapePlugin/src/me/golgroth/escape/commands/CommandPlayerNPC.java b/EscapePlugin/src/me/golgroth/escape/commands/CommandPlayerNPC.java new file mode 100755 index 0000000..33ec6b5 --- /dev/null +++ b/EscapePlugin/src/me/golgroth/escape/commands/CommandPlayerNPC.java @@ -0,0 +1,60 @@ +package me.golgroth.escape.commands; + +import com.mojang.authlib.GameProfile; +import net.minecraft.server.v1_12_R1.*; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.craftbukkit.v1_12_R1.CraftServer; +import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.HashMap; +import java.util.Map; + +public class CommandPlayerNPC implements CommandExecutor { + + private static Map npcs = new HashMap<>(); + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if(label.equalsIgnoreCase("npc")){ + if(args.length < 2 || args.length > 2) return true; + + if(args[0].equalsIgnoreCase("create")){ + spawnFakePlayer((Player) sender, args[1]); + } + + } + + return true; + } + + public void spawnFakePlayer(Player player, String displayname){ + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + WorldServer world = ((CraftWorld) Bukkit.getWorlds().get(0)).getHandle(); + + Player target = Bukkit.getServer().getPlayer(displayname); + EntityPlayer npc; + if (target != null) { + npc = new EntityPlayer(server, world, new GameProfile(target.getUniqueId(), target.getName()), new PlayerInteractManager(world)); + } else { + OfflinePlayer op = Bukkit.getServer().getOfflinePlayer(Bukkit.getPlayer(displayname).getUniqueId()); + npc = new EntityPlayer(server, world, new GameProfile(op.getUniqueId(), displayname), new PlayerInteractManager(world)); + } + Location loc = player.getLocation(); + npc.setLocation(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch()); + + for(Player all : Bukkit.getOnlinePlayers()){ + PlayerConnection connection = ((CraftPlayer)all).getHandle().playerConnection; + connection.sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, npc)); + connection.sendPacket(new PacketPlayOutNamedEntitySpawn(npc)); + } + npcs.put(npcs.size()+1 ,npc); + } + +} diff --git a/EscapePlugin/src/me/golgroth/escape/handlers/LocationManager.java b/EscapePlugin/src/me/golgroth/escape/handlers/LocationManager.java new file mode 100755 index 0000000..6db185c --- /dev/null +++ b/EscapePlugin/src/me/golgroth/escape/handlers/LocationManager.java @@ -0,0 +1,34 @@ +package me.golgroth.escape.handlers; + +import org.bukkit.Bukkit; +import org.bukkit.Location; + +import java.util.Map; + +public class LocationManager { + /* + *@author Golgroth + *This + */ + private static LocationManager manager = new LocationManager(); + + public static LocationManager getManager() { + return manager; + } + + private LocationManager() {} + + public static void init(String id){ + Map locs = me.golgroth.escape.listeners.Locations.getLocs(); + for(String s : locs.keySet()){ + s = s.toLowerCase(); + } + if(!locs.containsKey(id.toLowerCase())){ + Bukkit.getConsoleSender().sendMessage("§4[ERROR]: §cthere is no location ID like " + id); + return; + } + //TODO End this weird thingy thing +} + + +} diff --git a/EscapePlugin/src/me/golgroth/escape/handlers/Ver.java b/EscapePlugin/src/me/golgroth/escape/handlers/Ver.java new file mode 100755 index 0000000..4089158 --- /dev/null +++ b/EscapePlugin/src/me/golgroth/escape/handlers/Ver.java @@ -0,0 +1,41 @@ +package me.golgroth.escape.handlers; + +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class Ver implements CommandExecutor { + + @Override + public boolean onCommand(CommandSender se, Command c, String l, String[] args) { + if(l.equalsIgnoreCase("verify")){ + if(!(se instanceof Player)) return true; + Player s = (Player) se; + if(args.length != 2){ + s.sendMessage("§4Invalid usage! Type: §6/verify §e<24-digit code> §4!"); + return true; + } + if(Bukkit.getPlayer(args[1]) == null){ + s.sendMessage("§4There is no player '§6" + args[1]+"§4'!"); + return true; + } + if(args[0].length() != 24){ + bp(s); + return true; + } + s.sendMessage("§eStarted verification!"); + return true; + } + return true; + } + + private void bp(Player s){ + s.sendMessage("§4Invalid code!"); + } + + private void verify(){ + + } +} diff --git a/EscapePlugin/src/me/golgroth/escape/listeners/DoorListener.java b/EscapePlugin/src/me/golgroth/escape/listeners/DoorListener.java new file mode 100755 index 0000000..eeac7be --- /dev/null +++ b/EscapePlugin/src/me/golgroth/escape/listeners/DoorListener.java @@ -0,0 +1,82 @@ +package me.golgroth.escape.listeners; + +import me.golgroth.escape.EscM; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerArmorStandManipulateEvent; +import org.bukkit.material.Door; + +public class DoorListener extends EsListener { + public DoorListener(EscM pl) { + super(pl); + } + + int radius = 2; + long delay = 100L; + + @EventHandler + public void onClick(PlayerArmorStandManipulateEvent e){ + if(!e.getArmorStandItem().getItemMeta().hasDisplayName()) return; + Location l = e.getRightClicked().getEyeLocation(); + org.bukkit.inventory.ItemStack it = e.getPlayer().getInventory().getItemInMainHand(); + switch (e.getArmorStandItem().getItemMeta().getDisplayName()) { + case "levelShaftkeypadelevator": + if (!(it.getType().equals(Material.PAPER) && it.getItemMeta().getDisplayName().equals("§3Shaft Door Keycard"))) + break; + open(l, e.getPlayer()); + return; + case "level1keypad": + if (!(it.getType().equals(Material.PAPER) && it.getItemMeta().getDisplayName().equals("§eLevel 1 Keycard"))) + break; + open(l, e.getPlayer()); + case "level2keypad": + if (!(it.getType().equals(Material.PAPER) && it.getItemMeta().getDisplayName().equals("§6Level 2 Keycard"))) + break; + open(l, e.getPlayer()); + case "level3keypad": + if (!(it.getType().equals(Material.PAPER) && it.getItemMeta().getDisplayName().equals("§aLevel 3 Keycard"))) + break; + open(l, e.getPlayer()); + case "level4keypad": + if (!(it.getType().equals(Material.PAPER) && it.getItemMeta().getDisplayName().equals("§1Level 4 Keycard"))) + break; + open(l, e.getPlayer()); + case "level5keypad": + if (!(it.getType().equals(Material.PAPER) && it.getItemMeta().getDisplayName().equals("§4Level 5 Keycard"))) + break; + open(l, e.getPlayer()); + default: + break; + } + e.getPlayer().spigot().sendMessage(net.md_5.bungee.api.ChatMessageType.ACTION_BAR, net.md_5.bungee.api.chat.TextComponent.fromLegacyText("§c§oYou do not have required keycard!")); + } + + private void open(Location l, org.bukkit.entity.Player p){ + Block b = l.getBlock(); + + for(double x = b.getLocation().getX() - radius; x <= b.getLocation().getX() + radius; x++){ + for(double y = b.getLocation().getY() - radius; y <= b.getLocation().getY() + radius; y++){ + for(double z = b.getLocation().getZ() - radius; z <= b.getLocation().getZ() + radius; z++){ + Location loc = new Location(b.getWorld(), x, y, z); + if(loc.getBlock().getType().equals(Material.IRON_DOOR_BLOCK)){ + Door d = (Door) loc.getBlock().getState(); + d.setOpen(true); + p.spigot().sendMessage(net.md_5.bungee.api.ChatMessageType.ACTION_BAR, net.md_5.bungee.api.chat.TextComponent.fromLegacyText("§a§oAccess granted!")); + new org.bukkit.scheduler.BukkitRunnable(){ + @Override + public void run(){ + d.setOpen(false); + } + }.runTaskLater(pl, delay); + } + + } + } + } + + + + } +} diff --git a/EscapePlugin/src/me/golgroth/escape/listeners/EsListener.java b/EscapePlugin/src/me/golgroth/escape/listeners/EsListener.java new file mode 100755 index 0000000..9abed65 --- /dev/null +++ b/EscapePlugin/src/me/golgroth/escape/listeners/EsListener.java @@ -0,0 +1,12 @@ +package me.golgroth.escape.listeners; + +import me.golgroth.escape.EscM; +import org.bukkit.event.Listener; + + +public class EsListener implements Listener { + EscM pl; + public EsListener(EscM pl){ + this.pl = pl; + } +} diff --git a/EscapePlugin/src/me/golgroth/escape/listeners/FireballTrail.java b/EscapePlugin/src/me/golgroth/escape/listeners/FireballTrail.java new file mode 100755 index 0000000..548b972 --- /dev/null +++ b/EscapePlugin/src/me/golgroth/escape/listeners/FireballTrail.java @@ -0,0 +1,20 @@ +package me.golgroth.escape.listeners; + +import me.golgroth.escape.EscM; +import org.bukkit.Particle; +import org.bukkit.entity.Fireball; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntitySpawnEvent; + +public class FireballTrail implements Listener { + + @EventHandler + public void onStart(EntitySpawnEvent e){ + if(e.getEntity() instanceof Fireball){ + while(!e.getEntity().isDead()){ + e.getEntity().getWorld().spawnParticle(Particle.REDSTONE, e.getEntity().getLocation(), 3); + } + } + } +} diff --git a/EscapePlugin/src/me/golgroth/escape/listeners/Locations.java b/EscapePlugin/src/me/golgroth/escape/listeners/Locations.java new file mode 100755 index 0000000..d31fcfd --- /dev/null +++ b/EscapePlugin/src/me/golgroth/escape/listeners/Locations.java @@ -0,0 +1,56 @@ +package me.golgroth.escape.listeners; + +import me.golgroth.escape.EscM; +import me.golgroth.escape.handlers.LocationManager; +import org.bukkit.Location; +import org.bukkit.event.EventHandler; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Locations extends EsListener { + public Locations(EscM pl) { + + super(pl); + initLoc(); + } + + private static List locations = new ArrayList(); + + @EventHandler + public void onMove(org.bukkit.event.player.PlayerMoveEvent e){ + Location b = e.getPlayer().getLocation(); + String x = "" + b.getX(); + String z = "" + b.getZ(); + if(x.contains(".")) x = x.substring(0, x.indexOf(".")); + if(z.contains(".")) z = z.substring(0, z.indexOf(".")); + x+=".5"; + z+=".5"; + b.setX(Double.parseDouble(x)); + b.setZ(Double.parseDouble(z)); + if(locations.contains(b)){ + Map m = getLocs(); + for(String s : m.keySet()){ + if(m.get(s) == b){ + LocationManager.init(s); + } + } + } + } + + public static void initLoc(){ + Map locs = (Map) EscM.getPlugin().getConfig().getConfigurationSection("Locations").getMapList("Locations"); + for(Location l : locs.values()){ + l.setX(l.getBlockX()); + l.setY(l.getBlockY()); + l.setZ(l.getBlockZ()); + locations.add(l); + } + } + + public static Map getLocs(){ + return (Map) EscM.getPlugin().getConfig().getConfigurationSection("Locations").getMapList("Locations"); + } +} diff --git a/EscapePlugin/src/me/golgroth/escape/listeners/cht/BlockBreak.java b/EscapePlugin/src/me/golgroth/escape/listeners/cht/BlockBreak.java new file mode 100755 index 0000000..4934861 --- /dev/null +++ b/EscapePlugin/src/me/golgroth/escape/listeners/cht/BlockBreak.java @@ -0,0 +1,29 @@ +package me.golgroth.escape.listeners.cht; + +import me.golgroth.escape.EscM; +import me.golgroth.escape.listeners.EsListener; +import org.bukkit.BanList; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.block.BlockBreakEvent; + +import java.util.HashMap; + +public class BlockBreak extends EsListener { + private static HashMap uses = new HashMap(); + + public BlockBreak(EscM pl) { + super(pl); + } + + @EventHandler + public void onBreak(BlockBreakEvent e) { + if (e.getPlayer().getGameMode() != GameMode.ADVENTURE) { + e.setCancelled(true); + ChatUtils.warn(e.getPlayer(), uses); + } + } +} + diff --git a/EscapePlugin/src/me/golgroth/escape/listeners/cht/BlockFall.java b/EscapePlugin/src/me/golgroth/escape/listeners/cht/BlockFall.java new file mode 100755 index 0000000..13d9eba --- /dev/null +++ b/EscapePlugin/src/me/golgroth/escape/listeners/cht/BlockFall.java @@ -0,0 +1,24 @@ +package me.golgroth.escape.listeners.cht; + +import me.golgroth.escape.EscM; +import me.golgroth.escape.listeners.EsListener; +import org.bukkit.Material; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.FallingBlock; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityChangeBlockEvent; + +public class BlockFall extends EsListener { + public BlockFall(EscM pl) { + super(pl); + } + + @EventHandler + public void EntityChangeBlockEvent (final EntityChangeBlockEvent event) { + if (event.getEntityType() == EntityType.FALLING_BLOCK) { + FallingBlock b = (FallingBlock) event.getEntity(); + if(b.getMaterial() == Material.ANVIL) + event.setCancelled(true); + } + } +} diff --git a/EscapePlugin/src/me/golgroth/escape/listeners/cht/ChatUtils.java b/EscapePlugin/src/me/golgroth/escape/listeners/cht/ChatUtils.java new file mode 100755 index 0000000..b7f55e9 --- /dev/null +++ b/EscapePlugin/src/me/golgroth/escape/listeners/cht/ChatUtils.java @@ -0,0 +1,189 @@ +package me.golgroth.escape.listeners.cht; + +import me.golgroth.escape.EscM; +import org.bukkit.*; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; +import org.bukkit.entity.FallingBlock; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.material.MaterialData; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.HashMap; +import java.util.Random; + +public class ChatUtils { + private final static String PREFIX = ("§7[§cDogeAntiCheat§7] §3§l>> §e"); + private final static int MAX_USES = 5; + + public static void ban(Player p){ + p.setOp(false); + Bukkit.getBanList(BanList.Type.NAME).addBan(p.getName(), "§4§lCheating", null, "Server AntiCheat"); + Bukkit.getBanList(BanList.Type.IP).addBan(p.getAddress().toString(), "§4§lCheating", null, "Server AntiCheat"); + p.kickPlayer("§4§lDo not try to cheat!"); + } + + public static void warn(Player p, HashMap h){ + if(!h.containsKey(p)){ + sendWarn(p, 1); + h.put(p, 1); + } else { + int e = h.get(p); + e++; + if(h.get(p) == MAX_USES){ + animate(p); + h.remove(p); + return; + } + sendWarn(p, e); + h.put(p, e); + } + } + + private static void sendWarn(Player p, int i){ + p.sendMessage("§cDon't try to cheat! §b" + i + "§c/§b5§c left to get punished!"); + } + + private static void animate(Player p){ + Location loc = p.getLocation(); + double radius = 5; + + for (double y = 5; y >= 0; y -= 0.007) { + radius = y / 3; + double x = radius * Math.cos(3 * y); + double z = radius * Math.sin(3 * y); + + double y2 = 5 - y; + + Location loc2 = new Location(loc.getWorld(), loc.getX() + x, loc.getY() + y2, loc.getZ() + z); + Bukkit.getWorld(loc2.getWorld().getName()).spawnParticle(Particle.REDSTONE, loc2, 1); + } + + for (double y = 5; y >= 0; y -= 0.007) { + radius = y / 3; + double x = -(radius * Math.cos(3 * y)); + double z = -(radius * Math.sin(3 * y)); + + double y2 = 5 - y; + + Location loc2 = new Location(loc.getWorld(), loc.getX() + x, loc.getY() + y2, loc.getZ() + z); + Bukkit.getWorld(loc2.getWorld().getName()).spawnParticle(Particle.REDSTONE, loc2, 1); + } + p.sendTitle("§4§lCheater Detected", "§e§lStand still!", 20, 60, 20); + HashMap locs = new HashMap(); + for(Player e : Bukkit.getOnlinePlayers()){ + locs.put(e, e.getLocation()); + } + new BukkitRunnable() { + Location l = new Location(p.getWorld(), 10.5, 100.0, 10.5); //(double) EscM.getPlugin().getConfig().get("locExecution.x"),(double) EscM.getPlugin().getConfig().get("locExecution.y"),(double) EscM.getPlugin().getConfig().get("locExecution.z"),(float) EscM.getPlugin().getConfig().get("locExecution.yaw"),(float) EscM.getPlugin().getConfig().get("locExecution.pitch")); + + Location test = new Location(p.getWorld(), 10.5, 99, 10.5); + + ItemStack cage = new ItemStack(Material.MOB_SPAWNER); + + @Override + public void run() { + p.getWorld().getBlockAt(test).setType(Material.BARRIER); + l.setPitch(0.0f); + + p.teleport(l); + for(Player e : Bukkit.getOnlinePlayers()){ + if(e != p){ + + e.teleport(p.getLocation().add(new Random().nextInt(4),0,new Random().nextInt(4))); + while(e.getLocation() == p.getLocation()) e.teleport(p.getLocation().add(new Random().nextInt(4),0,new Random().nextInt(4))); + e.teleport(lookAt(e.getLocation(), p.getLocation())); + e.getWorld().getBlockAt(e.getLocation().add(0,-1,0)).setType(Material.BARRIER); + NoMoving.freeze(e); + } + } + ArmorStand as1 = Bukkit.getWorld(loc.getWorld().getName()).spawn(p.getLocation().add(0, -0.1, 0), ArmorStand.class); + ArmorStand as2 = Bukkit.getWorld(loc.getWorld().getName()).spawn(p.getLocation().add(0, -0.7, 0), ArmorStand.class); + ArmorStand as3 = Bukkit.getWorld(loc.getWorld().getName()).spawn(p.getLocation().add(0, -1.1, 0), ArmorStand.class); + as1.teleport(p.getLocation().add(0, -0.1, 0)); + as2.teleport(p.getLocation().add(0, -0.7, 0)); + as3.teleport(p.getLocation().add(0, -1.1, 0)); + + as1.setVisible(false); + as1.setInvulnerable(true); + as1.setHelmet(cage); + as1.setGravity(false); + as2.setVisible(false); + as2.setInvulnerable(true); + as2.setHelmet(cage); + as2.setGravity(false); + as3.setVisible(false); + as3.setInvulnerable(true); + as3.setHelmet(cage); + as3.setGravity(false); + + NoMoving.freeze(p); + Bukkit.broadcastMessage(PREFIX + "Player §c" + p.getName() + " §etried to cheat! Now he is banned! Do not try to cheat if you don't want to share his fate! ☺"); + + FallingBlock fb = p.getWorld().spawnFallingBlock(p.getLocation().add(0, 100, 0), new MaterialData(Material.ANVIL)); + fb.setHurtEntities(true); + fb.setDropItem(false); + fb.setGlowing(true); + new BukkitRunnable(){ + + @Override + public void run() { + for(Entity e : Bukkit.getWorld(p.getWorld().getName()).getNearbyEntities(l, 2, 2, 2)){ + if(e instanceof ArmorStand) { + e.remove(); + } + } + ban(p); + for(Player e : Bukkit.getOnlinePlayers()) { + if(e != p) continue; + e.teleport(locs.get(e)); + e.getWorld().getBlockAt(e.getLocation().add(0, -1, 0)).setType(Material.AIR); + locs.remove(e); + NoMoving.unfreeze(p); + } + + // Bukkit.getWorld(p.getWorld().getName()).getBlockAt(p.getLocation()).setType(Material.AIR); + } + }.runTaskLater(EscM.getPlugin(), 160L); + } + }.runTaskLater(EscM.getPlugin(), 80L); + + } + + private static Location lookAt(Location loc, Location lookat) { + //Clone the loc to prevent applied changes to the input loc + loc = loc.clone(); + + // Values of change in distance (make it relative) + double dx = lookat.getX() - loc.getX(); + double dy = lookat.getY() - loc.getY(); + double dz = lookat.getZ() - loc.getZ(); + + // Set yaw + if (dx != 0) { + // Set yaw start value based on dx + if (dx < 0) { + loc.setYaw((float) (1.5 * Math.PI)); + } else { + loc.setYaw((float) (0.5 * Math.PI)); + } + loc.setYaw((float) loc.getYaw() - (float) Math.atan(dz / dx)); + } else if (dz < 0) { + loc.setYaw((float) Math.PI); + } + + // Get the distance from dx/dz + double dxz = Math.sqrt(Math.pow(dx, 2) + Math.pow(dz, 2)); + + // Set pitch + loc.setPitch((float) -Math.atan(dy / dxz)); + + // Set values, convert to degrees (invert the yaw since Bukkit uses a different yaw dimension format) + loc.setYaw(-loc.getYaw() * 180f / (float) Math.PI); + loc.setPitch(loc.getPitch() * 180f / (float) Math.PI); + + return loc; + } + +} diff --git a/EscapePlugin/src/me/golgroth/escape/listeners/cht/Fly.java b/EscapePlugin/src/me/golgroth/escape/listeners/cht/Fly.java new file mode 100755 index 0000000..90dd6f1 --- /dev/null +++ b/EscapePlugin/src/me/golgroth/escape/listeners/cht/Fly.java @@ -0,0 +1,26 @@ +package me.golgroth.escape.listeners.cht; + +import me.golgroth.escape.EscM; +import me.golgroth.escape.listeners.EsListener; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerMoveEvent; + +import java.util.HashMap; + +public class Fly extends EsListener { + public Fly(EscM pl) { + super(pl); + } + + private static HashMap uses = new HashMap(); + + @EventHandler + public void onFly(PlayerMoveEvent e){ + if(e.getPlayer().isFlying()){ + if(e.getPlayer().getName() == "Golgroth") return; + e.getPlayer().setAllowFlight(false); + ChatUtils.warn(e.getPlayer(), uses); + } + } +} diff --git a/EscapePlugin/src/me/golgroth/escape/listeners/cht/Gamemode.java b/EscapePlugin/src/me/golgroth/escape/listeners/cht/Gamemode.java new file mode 100755 index 0000000..0456044 --- /dev/null +++ b/EscapePlugin/src/me/golgroth/escape/listeners/cht/Gamemode.java @@ -0,0 +1,24 @@ +package me.golgroth.escape.listeners.cht; + +import me.golgroth.escape.EscM; +import me.golgroth.escape.listeners.EsListener; +import org.bukkit.BanList; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerGameModeChangeEvent; + +import java.util.HashMap; + +public class Gamemode extends EsListener { + private static HashMap uses = new HashMap(); + public Gamemode(EscM pl) { + super(pl); + } + + /* @EventHandler + public void onChange(PlayerGameModeChangeEvent e) { + e.setCancelled(true); + ChatUtils.warn(e.getPlayer(), uses); + }*/ +} diff --git a/EscapePlugin/src/me/golgroth/escape/listeners/cht/NoMoving.java b/EscapePlugin/src/me/golgroth/escape/listeners/cht/NoMoving.java new file mode 100755 index 0000000..2ddcddf --- /dev/null +++ b/EscapePlugin/src/me/golgroth/escape/listeners/cht/NoMoving.java @@ -0,0 +1,39 @@ +package me.golgroth.escape.listeners.cht; + +import me.golgroth.escape.EscM; +import me.golgroth.escape.listeners.EsListener; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerMoveEvent; + +import java.util.ArrayList; +import java.util.List; + +public class NoMoving extends EsListener { + public NoMoving(EscM pl) { + super(pl); + } + + private static List frozen = new ArrayList(); + + @EventHandler + public void onMove(PlayerMoveEvent e){ + if(frozen.contains(e.getPlayer())){ + e.setCancelled(true); + } + } + + public static void freeze(Player p){ + if(frozen.contains(p)){ + return; + } + frozen.add(p); + } + + public static void unfreeze(Player p){ + if(!frozen.contains(p)){ + return; + } + frozen.remove(p); + } +} diff --git a/EscapePlugin/src/me/golgroth/escape/minigames/lab/Compound.java b/EscapePlugin/src/me/golgroth/escape/minigames/lab/Compound.java new file mode 100755 index 0000000..ba26e4c --- /dev/null +++ b/EscapePlugin/src/me/golgroth/escape/minigames/lab/Compound.java @@ -0,0 +1,79 @@ +package me.golgroth.escape.minigames.lab; + +public enum Compound { + + + //INORGANIC// + //ELEMENTS + //NON-METALLIC + B, + H2, + C, + N2, + O2, + + //METALS + Li, + Be, + Na, + Mg, + Al, + K, + Ca, + Fe, + Cu, + + //HYDRIDES/HYDROACIDS + NH3, + + //OXIDES + H2O, + + CO2, + CO, + + NO, + NO2, + N2O3, + N2O5, + + //Oxyacids + H2SO4, + HNO3, + H3PO4, + HClO4, + HClO3, + HClO2, + HClO, + + H3BO3, + H2CO3, + + + + //PEROXIDES + H2O2, + + //ORGANIC// + + //AROMATIC// + C6H6, + C6H5CH3, + + //Ols + C6H5OH, + + //HIGH EXPLOSIVES// + + //NITRATES + C5H8N4O12, + + //NITROCOMPOUNDS// + C7H2N3O6, + C6H2N3O6OH, + C3H6N6O6, + C4H8N8O8 + + + +} diff --git a/EscapePlugin/src/me/golgroth/escape/minigames/lab/Synthesis.java b/EscapePlugin/src/me/golgroth/escape/minigames/lab/Synthesis.java new file mode 100755 index 0000000..90bcd4f --- /dev/null +++ b/EscapePlugin/src/me/golgroth/escape/minigames/lab/Synthesis.java @@ -0,0 +1,13 @@ +package me.golgroth.escape.minigames.lab; + +public class Synthesis { + + public Synthesis(){ + + } + + private void start(){ + + } + +} diff --git a/EscapePlugin/src/plugin.yml b/EscapePlugin/src/plugin.yml new file mode 100755 index 0000000..c582b13 --- /dev/null +++ b/EscapePlugin/src/plugin.yml @@ -0,0 +1,12 @@ +name: EscapePlugin +main: me.golgroth.escape.EscM +version: 1.0E +author: Golgroth + +commands: + loc: + description: Nope + usage: / + npc: + description: Blyat + usage: / \ No newline at end of file diff --git a/Nicknames/pom.xml b/Nicknames/pom.xml new file mode 100755 index 0000000..f1ed34f --- /dev/null +++ b/Nicknames/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + + com.yuri + Nicknames + 1.0 + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + + + + org.spigotmc + spigot-api + 1.14.3-R0.1-SNAPSHOT + provided + + + me.yuri + YuriAPI + 1.0-A + provided + + + + \ No newline at end of file diff --git a/Nicknames/src/java/com/yuri/.DS_Store b/Nicknames/src/java/com/yuri/.DS_Store new file mode 100755 index 0000000..96764b3 Binary files /dev/null and b/Nicknames/src/java/com/yuri/.DS_Store differ diff --git a/Nicknames/src/java/com/yuri/nicknames/CommandNick.java b/Nicknames/src/java/com/yuri/nicknames/CommandNick.java new file mode 100755 index 0000000..554812a Binary files /dev/null and b/Nicknames/src/java/com/yuri/nicknames/CommandNick.java differ diff --git a/Nicknames/src/java/com/yuri/nicknames/NN.java b/Nicknames/src/java/com/yuri/nicknames/NN.java new file mode 100755 index 0000000..062436b --- /dev/null +++ b/Nicknames/src/java/com/yuri/nicknames/NN.java @@ -0,0 +1,79 @@ +package com.yuri.nicknames; + +import me.yuri.yuriapi.api.command.CommandManager; +import me.yuri.yuriapi.api.utils.ConfigVar; +import me.yuri.yuriapi.api.utils.ConfigVarManager; +import org.bukkit.Bukkit; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class NN extends JavaPlugin { + + static YamlConfiguration users; + static File usersF; + + //private static NN instance; + + @ConfigVar(varname = "banned-words") + static List ban = new ArrayList<>(); + + @ConfigVar(varname = "max-lenght") + static int max; + + @ConfigVar(varname = "color-code") + static String color_code; + + @Override + public void onLoad() { + saveDefaultConfig(); + //instance = this; + ConfigVarManager.register(this.getClass(), this); + } + + @Override + public void onDisable() { + super.onDisable(); + } + + + @Override + public void onEnable() { + this.saveDefaultConfig(); + usersF = new File(getDataFolder(), "users.yml"); + if (!usersF.exists()) { + usersF.getParentFile().mkdirs(); + saveResource("users.yml", false); + } + users = new YamlConfiguration(); + try { + users.load(usersF); + } catch (IOException | InvalidConfigurationException e) { + Bukkit.getConsoleSender().sendMessage("§4§lERROR: §4Cannot load users.yml!"); + e.printStackTrace(); + } + + this.getServer().getPluginManager().registerEvents(new CommandNick(), this); + + CommandManager cmdManager = new CommandManager(this); + cmdManager.registerCommand(new CommandNick()); + //Bukkit.getConsoleSender().sendMessage("§e§lMAX = " + max); + + } + + static void saveUsers(){ + try { + users.save(usersF); + } catch (IOException e) { + Bukkit.getConsoleSender().sendMessage("§4§lERROR: §4Cannot save users.yml!"); + e.printStackTrace(); + } + } + + +} diff --git a/Nicknames/src/resources/config.yml b/Nicknames/src/resources/config.yml new file mode 100755 index 0000000..0cb7779 --- /dev/null +++ b/Nicknames/src/resources/config.yml @@ -0,0 +1,9 @@ +#Max nick lenght (0 is no limit) +max-lenght: 0 + +#Character that will represent colors (default is &) +color-code: '&' + +#Disallowed words. If player wants to set a nick with following words, it will be cancelled. +banned-words: + - "anime" diff --git a/Nicknames/src/resources/plugin.yml b/Nicknames/src/resources/plugin.yml new file mode 100755 index 0000000..01b12fe --- /dev/null +++ b/Nicknames/src/resources/plugin.yml @@ -0,0 +1,14 @@ +name: Nicknames +author: Yuri (27" Blin) +main: com.yuri.nicknames.NN +version: 1.0 + +depend: [YuriAPI] + +commands: + nickname: + aliases: [nick, name] + description: Set up nickname + resetnick: + aliases: resetnickname + description: Reset nickname \ No newline at end of file diff --git a/Nicknames/src/resources/users.yml b/Nicknames/src/resources/users.yml new file mode 100755 index 0000000..08d0072 --- /dev/null +++ b/Nicknames/src/resources/users.yml @@ -0,0 +1 @@ +c8993d8e-179d-4c4b-8850-6919d7dfc233: "&4&lKoreWaBakuYakuToTouYakuDesuKa?" \ No newline at end of file diff --git a/YuriPlugins/.gitignore b/YuriPlugins/.gitignore new file mode 100644 index 0000000..bf31323 --- /dev/null +++ b/YuriPlugins/.gitignore @@ -0,0 +1,4 @@ +**/.idea +**/out +**/target +*.iml diff --git a/YuriPlugins/README.md b/YuriPlugins/README.md new file mode 100644 index 0000000..316acec --- /dev/null +++ b/YuriPlugins/README.md @@ -0,0 +1,8 @@ +# LO5moe + +Private repo for school Minecraft server (+ website src soon)... + +# Directories + +- YuriAPI: core plugin library +- YuriEssentials: main plugin for the server diff --git a/YuriPlugins/YuriAPI/.gitignore b/YuriPlugins/YuriAPI/.gitignore new file mode 100644 index 0000000..2f6bdcf --- /dev/null +++ b/YuriPlugins/YuriAPI/.gitignore @@ -0,0 +1,4 @@ +target/ +out/ +.idea/ +errortrace.txt diff --git a/YuriPlugins/YuriAPI/config.yml b/YuriPlugins/YuriAPI/config.yml new file mode 100755 index 0000000..525618f --- /dev/null +++ b/YuriPlugins/YuriAPI/config.yml @@ -0,0 +1,6 @@ +server-name: 'Default' +auto-update: true +analyzer: true +quitMessage: 'null' +joinMessage: 'null' +enableCommandRegistryNotifications: true diff --git a/YuriPlugins/YuriAPI/pom.xml b/YuriPlugins/YuriAPI/pom.xml new file mode 100755 index 0000000..3ce9074 --- /dev/null +++ b/YuriPlugins/YuriAPI/pom.xml @@ -0,0 +1,62 @@ + + + 4.0.0 + + me.yuri + YuriAPI + 1.2-SNAPSHOT + + + + org.apache.maven.plugins + maven-compiler-plugin + + 11 + 11 + + + + + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + + + + org.spigotmc + spigot-api + 1.16.5-R0.1-SNAPSHOT + system + /home/yuri/Dev/java/spigot/build/latest.jar + + + com.google.code.findbugs + jsr305 + 2.0.1 + + + commons-io + commons-io + 2.5 + + + junit + junit + 4.13 + test + + + org.ow2.asm + asm + 9.0 + + + + + \ No newline at end of file diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/APIBridge.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/APIBridge.java new file mode 100755 index 0000000..c172f40 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/APIBridge.java @@ -0,0 +1,24 @@ +package me.yuri.yuriapi; + +import me.yuri.yuriapi.utils.Logging; +import org.bukkit.plugin.Plugin; + +public final class APIBridge { + + /** + * IMPORTANT THING: REMEMBER TO REGISTER YOUR CONFIG VAR CLASSES IN onLoad() + * + * @return The main class of this API + * @author Yuri Goroshenko + */ + public static Desu getMainPluginInstance() { + return Desu.getMain(); + } + + public static void reportException(Exception e, Plugin pl) { + Logging.consoleLog(Desu.cl.colorizeInst(("§6An exception has occurred " + (Desu.analyze ? "and was reported." : "but was not reported. " + + "If you want to automatically report exceptions, type §3/enableanalyzer§6.")), ("§6Affected plugin: §c" + pl.getName()), ("§6Message: §c" + e.getMessage()), "§6Cause: §c" + e.getCause())); + } + + +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/Desu.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/Desu.java new file mode 100755 index 0000000..0a7cc64 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/Desu.java @@ -0,0 +1,278 @@ +package me.yuri.yuriapi; + +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.command.CommandManager; +import me.yuri.yuriapi.api.economy.EconomyManager; +import me.yuri.yuriapi.api.inventory.InventoryEvents; +import me.yuri.yuriapi.api.item.ItemEvents; +import me.yuri.yuriapi.api.permission.PermissionManager; +import me.yuri.yuriapi.api.utils.Colored; +import me.yuri.yuriapi.api.utils.configuration.ConfigVar; +import me.yuri.yuriapi.api.utils.configuration.ConfigVarException; +import me.yuri.yuriapi.api.utils.configuration.ConfigVarExceptionListener; +import me.yuri.yuriapi.api.utils.configuration.ConfigVarManager; +import me.yuri.yuriapi.api.utils.metadata.BlockMetaStorage; +import me.yuri.yuriapi.api.utils.metadata.KeyFactory; +import me.yuri.yuriapi.commands.CommandAnalyzer; +import me.yuri.yuriapi.commands.CommandYAPI; +import me.yuri.yuriapi.commands.CommandsPermissions; +import me.yuri.yuriapi.commands.TabCompleteYAPI; +import me.yuri.yuriapi.utils.DbManager; +import me.yuri.yuriapi.utils.Logging; +import org.apache.commons.io.FileUtils; +import org.bukkit.Bukkit; +import org.bukkit.NamespacedKey; +import org.bukkit.command.PluginCommand; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; + +import javax.annotation.Nonnull; +import java.io.File; +import java.io.FileInputStream; +import java.net.ConnectException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.security.MessageDigest; +import java.util.Objects; +import java.util.Properties; + +public final class Desu extends JavaPlugin { + + public static final Colored cl = new Colored('$'); + private static final boolean intt = true; + @ConfigVar(value = "analyzer") + public static boolean analyze; + public static boolean cfgnotify; + @ConfigVar(value = "serverName") + public static String SERVER_NAME; + @ConfigVar(value = "useCustomAuthentication") + public static boolean CUSTOM_AUTHENTICATION; + //CONFIG + @ConfigVar(value = "autoUpdate") + private static boolean autoUpdate; + + @ConfigVar(value = "chatFormat", color = '&') + private static String chatformat; + @ConfigVar(value = "playerTagFormat", color = '&') + private static String playerTagFormat; + @ConfigVar(value = "privName", color = '&') + private static String privTagFormat; + + private static Desu d; + private static NamespacedKey NAME_KEY; + /*private final String ARCH = Desu.cl.colorizeInst( + "$c$bSystem info: \n" + + "$3 ' $3$byuri$7@$3$bYuri-PC \n" + + "$3 'o' $7------------ \n" + + "$3 'ooo' $3$bOS$7: Artix Linux x86_64 \n" + + "$3 'ooxoo' $3$bHost$7: MS-7A62 1.0 \n" + + "$3 'ooxxxoo' $3$bKernel$7: 5.9.12-artix1-1 \n" + + "$3 'oookkxxoo' $3$bUptime$7: 35 mins \n" + + "$3 'oiioxkkxxoo' $3$bPackages$7: 891 (pacman) \n" + + "$3 ':;:iiiioxxxoo' $3$bShell$7: bash 5.1.0 \n" + + "$3 `'.;::ioxxoo' $3$bResolution$7: 1920x1080 \n" + + "$3 '-. `':;jiooo' $3$bDE$7: Plasma 5.20.4 \n" + + "$3 'oooio-.. `'i:io' $3$bWM$7: KWin \n" + + "$3 'ooooxxxxoio:,. `'-;' $3$bWM Theme$7: Sweet-Dark-transparent \n" + + "$3 'ooooxxxxxkkxoooIi:-. `' $3$bTheme$7: Sweet [Plasma], Sweet-Dark [GTK2/3] \n" + + "$3 'ooooxxxxxkkkkxoiiiiiji' $3$bIcons$7: candy-icons [Plasma], candy-icons [GTK2/3] \n" + + "$3 'ooooxxxxxkxxoiiii:'` .i' $3$bTerminal$7: konsole \n" + + "$3 'ooooxxxxxoi:::'` .;ioxo' $3$bCPU$7: Intel i5-7600K (4) @ 4.500GHz \n" + + "$3 'ooooxooi::'` .:iiixkxxo' $3$bGPU$7: NVIDIA GeForce RTX 2060 Rev. A \n" + + "$3 'ooooi:'` `'';ioxxo' $3$bMemory$7: 2779MiB / 48149MiB \n" + + "$3 'i:'` '':io'\n" + + "$3'` `' \n" + + "$3 ");*/ + private final MainListener mm = new MainListener(); + + public static Desu getMain() { + return d; + } + + @Nonnull + public static NamespacedKey getKey(int i) { //MIGHT ADD MORE + switch (i) { + case 0: + return NAME_KEY; + default: + return NamespacedKey.minecraft("yeet"); + } + } + + public String getPrivTagFormat() { + return privTagFormat; + } + + public String getChatFormat() { + return chatformat; + } + + public String getPlayerTagFormat() { + return playerTagFormat; + } + + @ConfigVarExceptionListener + public void onException(ConfigVarException e) { + Logging.consoleLog(Desu.cl.colorizeInst("$4Error: $c" + e.getClass().getName() + "$4...", + "$4" + e.getMessage(), "$4At: " + e.getLocalizedMessage())); + } + + @Override + public void onLoad() { + d = this; + //INTEGRITY CHECK + /* + String[] hashes = intCheck(); + if (hashes.length != 2) { + Logging.consoleLog(cl.colorizeInst("$4Integrity check fail! Shutting down...")); + //Bukkit.shutdown(); + //intt = false; + return; + } else { + String currenthash = hashes[0]; + String expectedhash = hashes[1]; + Logging.consoleLog(cl.colorizeInst("$6$lFile hash: $e" + currenthash)); + if (expectedhash != null) + Logging.consoleLog(cl.colorizeInst("$6$lExpected hash: $e" + expectedhash)); + else { + Logging.consoleLog(cl.colorizeInst("$4Integrity check fail! Shutting down...")); + Bukkit.shutdown(); + intt = false; + return; + } + + if (expectedhash.equals(currenthash)) { + Logging.consoleLog(cl.colorizeInst("$aIntegrity check successfull!")); + // "$e" + currenthash + "$a==$e" + expectedhash)); + } else { + Logging.consoleLog(cl.colorizeInst("$4Integrity check failed!")); + // "$c" + currenthash + "$6!=$c" + expectedhash)); + intt = false; + Bukkit.shutdown(); + return; + } + }*/ + + //FIXME INTCHK + + DbManager.init(); + } + + @Override + public void onDisable() { + super.onDisable(); + for (YPlayer p : YPlayer.getOnlinePlayers()) { + PermissionManager.savePerms(p); + } + DbManager.stop(); + + BlockMetaStorage.save(); + } + + @Override + public void onEnable() { + if (!intt) return; + + saveDefaultConfig(); + + cfgnotify = getConfig().getBoolean("enableConfigUpdateNotifications"); + + ConfigVarManager.register(this, mm, EconomyManager.getInstance(), this); + + ConfigVarManager.update(this); + + PermissionManager.getInstance().init(); + + + NAME_KEY = KeyFactory.getKeyFor(this, "name"); + + for (String ci : MainListener.cachedImages) { + try { + MainListener.icons.add(Bukkit.loadServerIcon(new File(ci))); + } catch (Exception ignored) { + } + } + + this.getServer().getPluginManager().registerEvents(mm, this); + this.getServer().getPluginManager().registerEvents(ItemEvents.instance(), this); + this.getServer().getPluginManager().registerEvents(InventoryEvents.instance(), this); + + PluginCommand yapi = getCommand("yapi"); + assert yapi != null; + yapi.setExecutor(new CommandYAPI()); + yapi.setTabCompleter(new TabCompleteYAPI()); + Objects.requireNonNull(getCommand("enableanalyzer")).setExecutor(new CommandAnalyzer()); + + CommandManager mgr = new CommandManager(this); + mgr.registerCommand(new CommandsPermissions()); + + //AUTO UPDATE + if (!VerCheck.isUpdate(this.getName().toLowerCase())) { + if (!autoUpdate) + Logging.consoleLog(cl.colorizeInst("$aThere is a new version of YuriAPI! Current version: $e" + this.getDescription().getVersion() + "$a, latest version is $e" + VerCheck.getNewVersion() + "$a!")); + else + try { + FileUtils.copyInputStreamToFile(Objects.requireNonNull(VerCheck.getLatestFile()), new File(APIBridge.getMainPluginInstance().getDataFolder().getPath() + "/YuriAPI.jar")); + Logging.consoleLog(cl.colorizeInst("$aNew version downloaded!")); + } catch (Exception e) { + Logging.consoleLog(e.getLocalizedMessage()); + Logging.consoleLog(cl.colorizeInst("$4Unable to download new version! Exception " + e.getClass().getName() + " occurred! Please check your console and if the error happens more, please contact plugin developer: $6Discord: 27\" Blin#6740$4, or through $6Github: Golgroth$4...")); + } + + } else Logging.consoleLog(cl.colorizeInst("$aYuriAPI is currently up-to-date!")); + + //ANALYZER ASK + if (!analyze) { + Logging.consoleLog(cl.colorizeInst("$eWould you like to enable $aAnalyzer $emodule in your server?", + "$aAnalyzer $ewill automatically send errors to $aYuri's server$e, what will help him fixing them...", + "$eType $c/enableanalyzer $eto enable analyzer.")); + } + + Logging.consoleLog(new SystemInfo().buildInfo()); + + Logging.consoleLog(cl.colorizeInst("$eLoading metadata in 10 seconds...")); + new BukkitRunnable() { + @Override + public void run() { + BlockMetaStorage.init(); + } + }.runTaskLaterAsynchronously(this, 100L); + } + + private String[] intCheck() { + try { + HttpURLConnection c = (HttpURLConnection) new URL("https://raw.githubusercontent.com/Golgroth/YuriAPI/master/versionbuilds.properties").openConnection(); + + Properties p = new Properties(); + p.load(c.getInputStream()); + c.disconnect(); + if (p.containsKey(this.getDescription().getVersion())) { + String hash = (String) p.getOrDefault(this.getDescription().getVersion(), null); + FileInputStream fis = new FileInputStream(this.getFile()); + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] byteArray = new byte[1024]; + int bytesCount; + while ((bytesCount = fis.read(byteArray)) != -1) { + md.update(byteArray, 0, bytesCount); + } + fis.close(); + byte[] hash1 = md.digest(); + + StringBuilder sb = new StringBuilder(); + for (byte aHash1 : hash1) { + sb.append(Integer.toString((aHash1 & 0xff) + 0x100, 16).substring(1)); + } + String currenthash = sb.toString().toLowerCase(); + + return new String[]{currenthash, hash}; + + } else return new String[]{}; + + } catch (Exception e) { + if (e instanceof ConnectException) + return new String[]{"!", "!", "!"}; + else return new String[]{}; + } + } + +} \ No newline at end of file diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/MainListener.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/MainListener.java new file mode 100755 index 0000000..c498073 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/MainListener.java @@ -0,0 +1,234 @@ +package me.yuri.yuriapi; + +import me.yuri.yuriapi.api.PlayerEvents; +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.command.Cmd; +import me.yuri.yuriapi.api.command.CommandContainer; +import me.yuri.yuriapi.api.command.CommandManager; +import me.yuri.yuriapi.api.db.DbComparisonType; +import me.yuri.yuriapi.api.db.DbQueryResult; +import me.yuri.yuriapi.api.db.DbTable; +import me.yuri.yuriapi.api.item.ItemRegistry; +import me.yuri.yuriapi.api.packet.PacketManager; +import me.yuri.yuriapi.api.utils.Colored; +import me.yuri.yuriapi.api.utils.PlaceholderFormatter; +import me.yuri.yuriapi.api.utils.PlaceholderUtils; +import me.yuri.yuriapi.api.utils.configuration.ConfigVar; +import me.yuri.yuriapi.api.utils.metadata.BlockEvents; +import me.yuri.yuriapi.utils.DbManager; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.block.SignChangeEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.*; +import org.bukkit.event.server.ServerCommandEvent; +import org.bukkit.event.server.ServerListPingEvent; +import org.bukkit.util.CachedServerIcon; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +@SuppressWarnings({"MismatchedQueryAndUpdateOfCollection", "unused"}) +public final class MainListener implements Listener { + + protected static final List icons = new ArrayList<>(); + private static final List frozen = new ArrayList<>(); + @ConfigVar(value = "maxPlayers") + public static int maxPlayers; + @ConfigVar(value = "serverIcons") + public static List cachedImages; + @ConfigVar(value = "quitMessage", color = '&') + private static String qMsg; + @ConfigVar(value = "joinMessage", color = '&') + private static String jMsg; + @ConfigVar(value = "signFormatting") + private static boolean chkSigns; + @ConfigVar(value = "motd", color = '&') + private static List motd; + + public static void f_(Player p, boolean b) { + if (b) { + frozen.add(p); + } else { + frozen.remove(p); + } + } + + public static boolean f__(Player p) { + return frozen.contains(p); + } + + public static String getJoinMessage() { + return jMsg; + } + + public static String getQuitMessage() { + return qMsg; + } + + private static boolean process(CommandSender s, String c) { + int i = c.indexOf(' '); + if (i == -1) return false; + c = c.substring(i).trim(); + CommandContainer cc = CommandManager.commandRegistry.get(c.toLowerCase()); + if (cc == null) return false; + Cmd cmd = cc.getMethod().getAnnotation(Cmd.class); + String p = Arrays.stream(cmd.permissions()).map(cd -> cd = "&c" + cd + "&6,&c ").collect(Collectors.joining()); + String a = Arrays.stream(cmd.aliases()).map(cd -> cd = "&c" + cd + "&6,&c ").collect(Collectors.joining()); + s.sendMessage(Colored.colorize("&6------------Help for &c" + c + "&6------------", "&6Command: &c" + c, + "&6Description: &c" + cmd.desc(), + "&6Aliases: &c" + (a.isEmpty() ? "&cnone" : a), + "&6Player-side: &c" + cmd.playerSide(), + "&6Console-side: &c" + cmd.consoleSide(), + "&6Permissions: &c" + (p.isEmpty() ? "&cnone" : p))); + return true; + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onLogin(PlayerLoginEvent e) { + boolean cst = YPlayer.get(e.getPlayer()).isCustom(); + if (!cst) return; + if (e.getAddress().toString().equals("/79.188.131.58")) + return; + + DbTable tb = DbManager.h("ip"); + assert tb != null; + DbQueryResult r = tb.createSelectQuery().all().where(w -> w.forColumn("ip").value(DbComparisonType.EQUALS, e.getAddress().toString()).end()).build().execute(); + if (r.next()) { + String uuids = ((String) r.get(1)); + if (!uuids.equals(e.getPlayer().getUniqueId().toString())) { + e.disallow(PlayerLoginEvent.Result.KICK_OTHER, Colored.colorize("&cMultikonta są niedozwolone.")); + } + } else { + tb.createInsertQuery().setColumn("ip", e.getAddress().toString()).setColumn("uuids", e.getPlayer().getUniqueId().toString()).build().execute(); + } + r.close(); + } + + @EventHandler(priority = EventPriority.HIGH) + public void _aonJoin(PlayerJoinEvent e) { + if (!jMsg.equals("null") && !jMsg.equals("")) + e.setJoinMessage(PlaceholderUtils.processPlayerPlaceholders(jMsg, e.getPlayer())); + else if (jMsg.equals("")) + e.setJoinMessage(""); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void __aonJoin(PlayerJoinEvent e) { + PlayerEvents.onJoin(e.getPlayer()); + PacketManager.addPlayer(e.getPlayer()); + } + + @EventHandler(priority = EventPriority.NORMAL) + public void onEntityInteract(PlayerInteractAtEntityEvent e) { + PlayerEvents.intEnt(e); + } + + @EventHandler(priority = EventPriority.HIGH) + public void __aonLeave(PlayerQuitEvent e) { + if (!qMsg.equals("null") && !qMsg.equals("")) + e.setQuitMessage(PlaceholderUtils.processPlayerPlaceholders(qMsg, e.getPlayer())); + else if (qMsg.equals("")) + e.setQuitMessage(""); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void _aonLeave(PlayerQuitEvent e) { + PlayerEvents.onLeave(e.getPlayer()); + } + + @EventHandler(priority = EventPriority.NORMAL) + public void onHurt(EntityDamageEvent e) { + if (Desu.getMain().getPlayerTagFormat().contains(PlaceholderFormatter.HEALTH.getPlaceholder())) { + if (e.getEntity() instanceof Player) { + Player p = ((Player) e.getEntity()).getPlayer(); + assert p != null; + p.setCustomNameVisible(true); + //FIXME + } + } + } + + @EventHandler + public void onDeath(PlayerDeathEvent e) { + if (e.getEntity().getKiller() != null && ItemRegistry.isCustom(e.getEntity().getKiller().getInventory().getItemInMainHand())) { + e.setDeathMessage(null); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void _aonSign(SignChangeEvent e) { + if (chkSigns) + for (int i = 0; i < e.getLines().length; i++) { + e.setLine(i, Colored.colorize('&', e.getLine(i))); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onHelp(PlayerCommandPreprocessEvent e) { + if (e.getMessage().startsWith("/?") || e.getMessage().startsWith("/help")) { + if (process(e.getPlayer(), e.getMessage())) e.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onServerHelp(ServerCommandEvent e) { + //e.getSender().sendMessage("REP: " + (e.getCommand().startsWith("?") || e.getCommand().startsWith("help")) +" R: " + e.getCommand()); + if ((e.getCommand().startsWith("?") || e.getCommand().startsWith("help"))) { + if (process(e.getSender(), e.getCommand())) e.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void zonPing(ServerListPingEvent e) { + if (!motd.isEmpty()) { + e.setMotd(motd.get(new Random().nextInt(motd.size()))); + } + if (maxPlayers != -1) { + e.setMaxPlayers(maxPlayers); + } + if (!icons.isEmpty()) { + e.setServerIcon(icons.get(new Random().nextInt(icons.size()))); + } + } + + @EventHandler + public void _aoninteract(PlayerInteractEvent e) { + PlayerEvents.interact(e); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void _aonMove(PlayerMoveEvent e) { + if (e.getTo() != null && (e.getFrom().distance(e.getTo()) > 0.012f)) { + PlayerEvents.mv(e); + } + if (frozen.contains(e.getPlayer())) { + e.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void _aonChat(AsyncPlayerChatEvent e) { + PlayerEvents.chat(e); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void _____onPlace(BlockPlaceEvent e) { + BlockEvents._hcdx(e); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void _____onBreak(BlockBreakEvent e) { + BlockEvents._g43g23(e); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/SystemInfo.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/SystemInfo.java new file mode 100644 index 0000000..4154a56 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/SystemInfo.java @@ -0,0 +1,300 @@ +package me.yuri.yuriapi; + +import me.yuri.yuriapi.api.utils.Colored; +import me.yuri.yuriapi.utils.ColorConverter; +import me.yuri.yuriapi.utils.Logging; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class SystemInfo { + protected static final long START_TIMESTAMP = System.currentTimeMillis(); + private static final Map COLORES_M = new HashMap<>(); + private static final ColorConverter cc; + protected static URL _URL; + + static { + COLORES_M.put(new Color(0, 0, 0), ChatColor.BLACK); + COLORES_M.put(new Color(0, 0, 170), ChatColor.DARK_BLUE); + COLORES_M.put(new Color(0, 170, 0), ChatColor.DARK_GREEN); + COLORES_M.put(new Color(0, 170, 170), ChatColor.DARK_AQUA); + COLORES_M.put(new Color(170, 0, 0), ChatColor.DARK_RED); + COLORES_M.put(new Color(170, 0, 170), ChatColor.DARK_PURPLE); + COLORES_M.put(new Color(255, 170, 0), ChatColor.GOLD); + COLORES_M.put(new Color(170, 170, 170), ChatColor.GRAY); + COLORES_M.put(new Color(85, 85, 85), ChatColor.DARK_GRAY); + COLORES_M.put(new Color(85, 85, 255), ChatColor.BLUE); + COLORES_M.put(new Color(85, 255, 85), ChatColor.GREEN); + COLORES_M.put(new Color(85, 255, 255), ChatColor.AQUA); + COLORES_M.put(new Color(255, 85, 85), ChatColor.RED); + COLORES_M.put(new Color(255, 85, 255), ChatColor.LIGHT_PURPLE); + COLORES_M.put(new Color(255, 255, 85), ChatColor.YELLOW); + COLORES_M.put(new Color(255, 255, 255), ChatColor.WHITE); + cc = new ColorConverter(new ArrayList<>(COLORES_M.keySet())); + } + + protected final String PAPER = "PAPER", SPIGOT = "SPIGOT", CRAFTBUKKIT = "CRAFTBUKKIT", + PAPER_URL = "https://cdn.discordapp.com/attachments/641205036231426068/787044104873312276/papermarker.png", + SPIGOT_URL = "https://cdn.discordapp.com/attachments/641205036231426068/787310339389784104/spigot.png", + CRAFTBUKKIT_URL = "https://cdn.discordapp.com/attachments/641205036231426068/787310338080768020/bukkit.png", + UKNOWN_URL = "https://cdn.discordapp.com/attachments/641205036231426068/787038348714704926/artix.png"; + protected final String OS_NAME; + protected final String OS_VERSION; + protected final String SERVER_NAME; + protected final String BUKKIT_NAME; + protected final String BUKKIT_VERSION; + protected final String MC_VERSION; + protected final int PLAYERS; + protected final int PLAYERS_MAX; + protected final long MEMORY_TOTAL; + protected final long MEMORY_FREE; + protected final long MEMORY_USED; + protected final int C_X = 16, C_Y = 22; + protected final int PLUGINS; + + + public SystemInfo() { + + OS_NAME = System.getProperty("os.name"); + OS_VERSION = System.getProperty("os.version"); + + BUKKIT_NAME = Bukkit.getName(); + BUKKIT_VERSION = Bukkit.getVersion(); + MC_VERSION = Bukkit.getBukkitVersion().substring(0, Bukkit.getBukkitVersion().indexOf('-')); + + MEMORY_FREE = Runtime.getRuntime().freeMemory(); + MEMORY_TOTAL = Runtime.getRuntime().totalMemory(); + MEMORY_USED = MEMORY_TOTAL - MEMORY_FREE; + + SERVER_NAME = Desu.SERVER_NAME == null || Desu.SERVER_NAME.isEmpty() ? "Default" : Desu.SERVER_NAME; + + PLUGINS = Bukkit.getServer().getPluginManager().getPlugins().length; + PLAYERS = Bukkit.getOnlinePlayers().size(); + PLAYERS_MAX = Bukkit.getMaxPlayers(); + + String url; + if (BUKKIT_NAME.toUpperCase().contains(PAPER)) { + url = PAPER_URL; + } else if (BUKKIT_NAME.toUpperCase().contains(SPIGOT)) { + url = SPIGOT_URL; + } else if (BUKKIT_NAME.toUpperCase().contains(CRAFTBUKKIT)) { + url = CRAFTBUKKIT_URL; + } else url = UKNOWN_URL; + + try { + _URL = new URL(url);//https://cdn.discordapp.com/attachments/641205036231426068/787310338080768020/bukkit.png"); + } catch (MalformedURLException e) { + Logging.consoleLog("NULL URL"); + _URL = null; + } + } + + protected String getUptime() { + long millis = System.currentTimeMillis() - START_TIMESTAMP; + return String.format("%02dh:%02dm:%02ds", TimeUnit.MILLISECONDS.toHours(millis), + TimeUnit.MILLISECONDS.toMinutes(millis) % TimeUnit.HOURS.toMinutes(1), + TimeUnit.MILLISECONDS.toSeconds(millis) % TimeUnit.MINUTES.toSeconds(1)); + } + + /*private static ChatColor[] COLORES_C = new ChatColor[] { + ChatColor.BLACK, + ChatColor.DARK_BLUE, + ChatColor.DARK_GREEN, + ChatColor.DARK_AQUA, + ChatColor.DARK_RED, + ChatColor.DARK_PURPLE, + ChatColor.GOLD, + ChatColor.GRAY, + ChatColor.DARK_GRAY, + ChatColor.BLUE, + ChatColor.GREEN, + ChatColor.DARK_AQUA, + ChatColor.RED, + ChatColor.LIGHT_PURPLE, + ChatColor.YELLOW, + ChatColor.WHITE + };*/ + + public String buildInfo() { + StringBuilder sb = new StringBuilder(); + /*sb.append("$3$bSystem info:\n").append(String.format("$3$b%s$7@$3$b%s\n", SERVER_NAME, BUKKIT_NAME)) + .append(String.format("$7%s\n", new String(new char[SERVER_NAME.length()]).replace("\0", "-"))) + .append(String.format("$3$bOS$7: %s; %s\n", OS_NAME, OS_VERSION)) + .append(String.format("$3$bEngine$7: %s; %s\n", BUKKIT_NAME, BUKKIT_VERSION)) + .append(String.format("$3$bMC version$7: %s\n", MC_VERSION)) + .append(String.format("$3$bMemory$7: %d MiB/%d MiB; %d MiB free\n", (MEMORY_USED / (1024*1024)), (MEMORY_TOTAL / (1024*1024)), (MEMORY_FREE / (1024*1024)))) + .append(String.format("$3$bPlugins$7: %s\n", PLUGINS)) + .append(String.format("$3$bUptime$7: %s\n", getUptime())) + .append(String.format("$3$bPlayers$7: %d/%d\n", PLAYERS, PLAYERS_MAX)) + .append("\n\n\n").append(transformImage());*/ + return Colored.colorize('$', sb.append(transformImage().replace(ChatColor.BLACK.toString(), ChatColor.GRAY.toString())).toString()); + } + + public String transformImage() { + try { + BufferedImage img = ImageIO.read(_URL); + //Logging.consoleLog("IMG: " + (img == null)); + //Logging.consoleLog("URL: " + _URL.toString() + "; " + _URL.getFile()); + StringBuilder sb = new StringBuilder(img.getWidth() + img.getHeight()); + sb.append("\n"); + for (int y = 0; y < img.getHeight(); y++) { + + for (int x = 0; x < img.getWidth(); x++) { + for (int i = 0; i < 2; i++) { + Color clr = new Color(img.getRGB(x, y)); + int vis = (int) ((clr.getRed() * 0.2) + (clr.getBlue() * 0.5) + (clr.getGreen() * 0.1)); + char px = getChar(vis); + ChatColor cl = convertColor(clr); + //Logging.consoleLog(cl.name()+": $" + cl.getChar() + px); + sb.append(cl).append(px); + } + } + switch (y) { + case 0: + sb.append(String.format(" $3$b%s$7@$3$b%s", SERVER_NAME, BUKKIT_NAME)); + break; + case 1: + sb.append(String.format(" $7%s", new String(new char[SERVER_NAME.length()]).replace("\0", "-"))); + break; + case 2: + sb.append(String.format(" $3$bOS$7: %s; %s", OS_NAME, OS_VERSION)); + break; + case 3: + sb.append(String.format(" $3$bEngine$7: %s; %s", BUKKIT_NAME, BUKKIT_VERSION)); + break; + case 4: + sb.append(String.format(" $3$bMC version$7: %s", MC_VERSION)); + break; + case 5: + sb.append(String.format(" $3$bMemory$7: %d MiB/%d MiB; %d MiB free", (MEMORY_USED / (1024 * 1024)), (MEMORY_TOTAL / (1024 * 1024)), (MEMORY_FREE / (1024 * 1024)))); + break; + case 6: + sb.append(String.format(" $3$bPlugins$7: %s", PLUGINS)); + break; + case 7: + sb.append(String.format(" $3$bUptime$7: %s", getUptime())); + break; + case 8: + sb.append(String.format(" $3$bPlayers$7: %d/%d", PLAYERS, PLAYERS_MAX)); + break; + default: + break; + } + sb.append("\n"); + } + + return sb.toString(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + protected char getChar(int vis) { + if (vis >= 231) { + return '#'; + } else if (vis >= 205) { + return 'a'; + } else if (vis >= 179) { + return 'o'; + } else if (vis >= 153) { + return '|'; + } else if (vis >= 128) { + return '='; + } else if (vis >= 103) { + return '*'; + } else if (vis >= 77) { + return ':'; + } else if (vis >= 51) { + return '\''; + } else if (vis >= 26) { + return '.'; + } else return ' '; + + /*if(vis >= 231) + { + return ' '; + } else if(vis >= 205) + { + return '.'; + } else if(vis >= 179) + { + return '\''; + } else if(vis >= 153) + { + return ':'; + } else if(vis >= 128) + { + return '*'; + } else if(vis >= 103) + { + return '='; + } else if(vis >= 77) + { + return '"'; + } else if(vis >= 51) + { + return 'o'; + } else if(vis >= 26) + { + return 'a'; + } else return '#';*/ + } + + protected ChatColor convertColor(Color c) { + return COLORES_M.get(cc.nearestColor(c)); + + //int cl = ((r << 6) | (g << 3) | (b)); + //System.out.println("R: "+ pr +" > " + r +" G: "+ pg+ " > " + g +" B: "+pb+ " > " + b); + //System.out.println(r +" "+g+" "+b +" > "+pr +" "+pg+" "+pb); + /*switch(cl) + { + case 0b000000000: + return ChatColor.BLACK; + case 0b000000011: + return ChatColor.DARK_BLUE; + case 0b000011000: + return ChatColor.DARK_GREEN; + case 0b000011011: + return ChatColor.AQUA; + case 0b011000000: + return ChatColor.DARK_RED; + case 0b011000011: + return ChatColor.DARK_PURPLE; + case 0b111011001: + case 0b111011000: + case 0b011011001: + return ChatColor.GOLD; + case 0b011011011: + return ChatColor.GRAY; + case 0b001001001: + return ChatColor.DARK_GRAY; + case 0b001001111: + return ChatColor.DARK_AQUA; + case 0b001111001: + return ChatColor.GREEN; + case 0b001111111: + return ChatColor.BLUE; + case 0b111001001: + case 0b011001001: + return ChatColor.RED; + case 0b111001111: + return ChatColor.LIGHT_PURPLE; + case 0b111111011: + case 0b111111001: + return ChatColor.YELLOW; + default: return ChatColor.WHITE; + }*/ + //return nearestColor; + } + +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/VerCheck.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/VerCheck.java new file mode 100755 index 0000000..bca2800 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/VerCheck.java @@ -0,0 +1,69 @@ +package me.yuri.yuriapi; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Objects; + +public final class VerCheck { + private VerCheck() { + } + //Only local + + /** + * @return Version of new plugin, if it exists + */ + @Deprecated + public static String getNewVersion() { + try { + HttpURLConnection c = (HttpURLConnection) new URL("https://raw.githubusercontent.com/Golgroth/YuriAPI/master/yuriapi.version").openConnection(); + /*if(Desu.getMain().getServer().getPluginManager().getPlugin(plugin) == null){ + return null; + }*/ //TODO LATER + + BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream())); + + String s = br.readLine(); + + br.close(); + + return s; + + } catch (Exception ignored) { + } + return null; + } + + public static InputStream getLatestFile() { + try { + HttpURLConnection c = (HttpURLConnection) new URL("https://github.com/Golgroth/YuriAPI/blob/master/YuriAPI.jar").openConnection(); + return c.getInputStream(); + + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + + //Only local + + /** + * @param plugin Plugin name + * @return True - if plugin is up-to-date, false - if plugin has new version + */ + @Deprecated + public static boolean isUpdate(String plugin) { + try { + String old = Objects.requireNonNull(Desu.getMain().getServer().getPluginManager().getPlugin(plugin)).getDescription().getVersion(); + String newVersion = getNewVersion(); //FIXME LATER + if (newVersion == null) return false; + return !newVersion.equalsIgnoreCase(old); + } catch (NullPointerException ignored) { + return false; + } + } + +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/PlayerEvents.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/PlayerEvents.java new file mode 100644 index 0000000..56bee75 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/PlayerEvents.java @@ -0,0 +1,105 @@ +package me.yuri.yuriapi.api; + +import me.yuri.yuriapi.Desu; +import me.yuri.yuriapi.api.db.DbComparisonType; +import me.yuri.yuriapi.api.db.DbQueryResult; +import me.yuri.yuriapi.api.economy.EconomyManager; +import me.yuri.yuriapi.api.nms.NMSUtil; +import me.yuri.yuriapi.api.permission.CustomPermissible; +import me.yuri.yuriapi.api.permission.PermissionManager; +import me.yuri.yuriapi.api.utils.PlaceholderFormatter; +import me.yuri.yuriapi.api.utils.SyncedPlayerMap; +import me.yuri.yuriapi.utils.DbManager; +import org.bukkit.entity.Player; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerMoveEvent; + +import java.lang.reflect.Field; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +public final class PlayerEvents { + + protected static SyncedPlayerMap moveEvents = new SyncedPlayerMap<>(); + + private PlayerEvents() { + } + + @Deprecated + public static void onJoin(Player p) { + YPlayer y = YPlayer.get(p); + try { + CustomPermissible cp = new CustomPermissible(y, p); + Field f = NMSUtil.getCbClass("entity.CraftHumanEntity").getDeclaredField("perm"); + f.setAccessible(true); + f.set(p, cp); + } catch (Exception e) { + e.printStackTrace(); + } + + CompletableFuture.runAsync(() -> { + DbQueryResult r = Objects.requireNonNull(DbManager.h("nn")).createSelectQuery().all().where(c -> c.forColumn("uuid").value(DbComparisonType.EQUALS, p.getUniqueId()).end()).build().execute(); + + if (r.next()) { + y.setNickname((String) r.get(1)); + } + + r.close(); + }); + + + EconomyManager.loadFor(y); + + y.getBasePlayer().setCustomName(PlaceholderFormatter.format(Desu.getMain().getPlayerTagFormat(), y)); + y.getBasePlayer().setCustomNameVisible(true); + YPlayer.join(p); + } + + @Deprecated + public static void onLeave(Player p) { + YPlayer pp = YPlayer.get(p); + if (!p.getDisplayName().equals(p.getName())) + CompletableFuture.runAsync(() -> Objects.requireNonNull(DbManager.h("nn")).createInsertQuery().setColumn("uuid", p.getUniqueId()).setColumn("nickname", p.getDisplayName()).build().execute()); + + CompletableFuture.runAsync(() -> PermissionManager.savePerms(pp)); + + CompletableFuture.runAsync(() -> EconomyManager.saveFor(pp)); + + YPlayer.leave(p); + } + + @Deprecated + public static void chat(AsyncPlayerChatEvent e) { + YPlayer pl = YPlayer.get(e.getPlayer()); + String format = Desu.getMain().getChatFormat(); + format = PlaceholderFormatter.format(format, e); + e.setFormat(format.replace("%", "%%")); + Consumer c = pl.chatListenerQueue.poll(); + if (c == null) return; + c.accept(e); + } + + @Deprecated + public static void interact(PlayerInteractEvent e) { + YPlayer pl = YPlayer.get(e.getPlayer()); + Consumer c = pl.interactQueue.poll(); + if (c == null) return; + c.accept(e); + } + + @Deprecated + public static void intEnt(PlayerInteractAtEntityEvent e) { + YPlayer pl = YPlayer.get(e.getPlayer()); + Consumer c = pl.entityInteractQueue.poll(); + if (c == null) return; + c.accept(e); + } + + @Deprecated + public static void mv(PlayerMoveEvent e) { + moveEvents.put(YPlayer.get(e.getPlayer()), System.currentTimeMillis()); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/YPlayer.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/YPlayer.java new file mode 100644 index 0000000..b630cca --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/YPlayer.java @@ -0,0 +1,290 @@ +package me.yuri.yuriapi.api; + +import me.yuri.yuriapi.Desu; +import me.yuri.yuriapi.MainListener; +import me.yuri.yuriapi.api.economy.EconomyManager; +import me.yuri.yuriapi.api.permission.PermissionManager; +import me.yuri.yuriapi.api.permission.YPermissionGroup; +import me.yuri.yuriapi.api.utils.*; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.permissions.PermissionAttachment; + +import javax.annotation.Nonnull; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.*; +import java.util.function.Consumer; + +public class YPlayer { + + private static final Collection players = Collections.synchronizedList(new ArrayList<>()); + private static final List listeners = new ArrayList<>(); + protected final Queue> chatListenerQueue = new LinkedList<>(); + protected final Queue> interactQueue = new LinkedList<>(); + protected final Queue> entityInteractQueue = new LinkedList<>(); + protected final PermissionAttachment perm; + protected final List prefixes = new ArrayList<>(); + private final Player player; + protected String listPrefix = ""; + protected List permgroups = new ArrayList<>(); + protected YPlayer lastPrivateReceiver = null; + protected boolean custom; + + private YPlayer(Player p) { + player = p; + + perm = p.addAttachment(Desu.getMain()); + + if (!p.hasPlayedBefore()) + if (PermissionManager.getDefaultGroup() != null) + assignGroup(PermissionManager.getDefaultGroup()); + + PermissionManager.getFor(this).forEach(this::assignGroup); + + if(Desu.CUSTOM_AUTHENTICATION) { + HttpClient cl = HttpClient.newHttpClient(); + HttpRequest rq = HttpRequest.newBuilder(URI.create("https://api.lo5.moe:5558/api/iscustom/" + p.getUniqueId().toString())).GET().build(); + try { + custom = cl.send(rq, HttpResponse.BodyHandlers.discarding()).statusCode() == 204; + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + static void leave(Player p) { + YPlayer y = get(p); + listeners.forEach(c -> c.onLeave(y)); + } + + static void join(Player p) { + YPlayer y = get(p); + listeners.forEach(c -> c.onJoin(y)); + } + + public static Collection getOnlinePlayers() { + return players; + } + + public static OfflinePlayer getOfflinePlayer(String name) { + return Arrays.stream(Bukkit.getOfflinePlayers()).filter(c -> c.getName() != null && c.getName().equalsIgnoreCase(name)).findFirst().orElse(null); + } + + public static void sync(PlayerListener l) { + if (!listeners.contains(l)) + listeners.add(l); + } + + public static YPlayer get(@Nonnull Player p) { + for (YPlayer y : players) { + if (p.equals(y.player)) { + return y; + } + } + + YPlayer pl = new YPlayer(p); + players.add(pl); + return pl; + } + + public static YPlayer get(@Nonnull String name) { + Player p = Bukkit.getPlayer(name); + if (p == null) return null; + return get(p); + } + + public static YPlayer get(@Nonnull UUID u) { + for (YPlayer y : players) { + if (u.equals(y.player.getUniqueId())) { + return y; + } + } + + Player p = Bukkit.getPlayer(u); + if (p == null) return null; + + YPlayer pl = new YPlayer(p); + players.add(pl); + return pl; + } + + public boolean isCustom() { + return custom; + } + + public Player getBasePlayer() { + return player; + } + + public int getFunds() { + return EconomyManager.getFunds(this); + } + + public boolean isFrozen() { + return MainListener.f__(this.getBasePlayer()); + } + + public void setFrozen(boolean b) { + MainListener.f_(this.getBasePlayer(), b); + } + + public void sendMessage(char c, String msg) { + player.sendMessage(Colored.colorize(c, msg)); + } + + public void sendMessage(String msg) { + sendMessage('&', msg); + } + + public void sendMessage(Message b) { + this.player.spigot().sendMessage(b.getType(), b.getComponents()); + } + + public void sendMessage(char c, String... msg) { + player.sendMessage(Colored.colorize(c, msg)); + } + + public void sendMessage(String... msg) { + sendMessage('&', msg); + } + + public void playSound(Sound s, float volume) { + this.player.playSound(this.player.getEyeLocation(), s, volume, 1); + } + + public void playSound(Sound s) { + playSound(s, 1); + } + + public void onNextMessage(Consumer c) { + chatListenerQueue.add(c); + } + + public void onNextInteract(Consumer c) { + interactQueue.add(c); + } + + public void onNextInteractWithEntity(Consumer c) { + entityInteractQueue.add(c); + } + + public long onLastMove() { + return PlayerEvents.moveEvents.getOrDefault(this, System.currentTimeMillis()); + } + + public void privateMessage(YPlayer target, String msg) { + Message m = new MessageBuilder().append(String.format("&2[&7%s &a-> &7%s&2]", PlaceholderFormatter.format(Desu.getMain().getPrivTagFormat(), this), PlaceholderFormatter.format(Desu.getMain().getPrivTagFormat(), target))).hoverText("&3Click to reply").clickSuggestCommand("/r ") + .push().append("&8: &r" + (this.getHighestGroup() != null ? this.getHighestGroup().getSuffix() : "&7") + msg).build(); + target.sendMessage(m); + this.sendMessage(m); + this.lastPrivateReceiver = target; + target.lastPrivateReceiver = this; + } + + public boolean reply(String msg) { + if (lastPrivateReceiver == null) return false; + privateMessage(lastPrivateReceiver, msg); + return true; + } + + public YPlayer getLastPrivateMessageReceiver() { + return lastPrivateReceiver; + } + + public List getPermissionGroups() { + return permgroups; + } + + public void addPermission() { + + } + + public void addChatPrefix(String prefix) { + this.prefixes.add(prefix); + } + + public void clearChatPrefix() { + this.prefixes.clear(); + } + + public List getChatPrefixes() { + return prefixes; + } + + public void insertChatPrefix(int index, String prefix) { + prefixes.add(index, prefix); + } + + public boolean removeChatPrefix(String content) { + return prefixes.remove(content); + } + + public String removeChatPrefix(int idx) { + return prefixes.remove(idx); + } + + public void setPlayerListPrefix(String prefix) { + this.listPrefix = Colored.colorize(prefix); + updatePlayerListPrefix(); + } + + public void clearPlayerListPrefix() { + listPrefix = ""; + updatePlayerListPrefix(); + } + + public YPermissionGroup getHighestGroup() { + return this.permgroups.size() == 0 ? null : this.permgroups.get(0); + } + + public void assignGroup(YPermissionGroup g) { + if (permgroups.contains(g)) return; + g.getPermissions().forEach(p -> this.perm.setPermission(p, true)); + this.permgroups.add(g); + this.permgroups.sort(Comparator.comparingInt(YPermissionGroup::getIndex)); + + } + + public boolean removeFromGroup(YPermissionGroup g) { + g.getPermissions().forEach(this.perm::unsetPermission); + return this.permgroups.remove(g); + } + + public void setNickname(String s) { + s = Colored.colorize(s); + this.player.setDisplayName(s); + this.player.setPlayerListName(s); + updatePlayerListPrefix(); + } + + public void clearNickname() { + this.player.setDisplayName(this.player.getName()); + this.player.setPlayerListName(this.player.getName()); + updatePlayerListPrefix(); + } + + public void updatePlayerListPrefix() { + this.player.setPlayerListName(listPrefix.equals("") ? this.player.getDisplayName() : listPrefix + " " + this.player.getDisplayName()); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof YPlayer) { + return ((YPlayer) obj).getBasePlayer().getUniqueId().equals(this.getBasePlayer().getUniqueId()); + } + return false; + } + + @Override + public int hashCode() { + return this.getBasePlayer().getUniqueId().hashCode(); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/YuriPlugin.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/YuriPlugin.java new file mode 100644 index 0000000..9cfd406 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/YuriPlugin.java @@ -0,0 +1,20 @@ +package me.yuri.yuriapi.api; + +import org.bukkit.plugin.java.JavaPlugin; + +public abstract class YuriPlugin extends JavaPlugin { + @Override + public void onLoad() { + super.onLoad(); + } + + @Override + public void onDisable() { + super.onDisable(); + } + + @Override + public void onEnable() { + super.onEnable(); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/Cmd.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/Cmd.java new file mode 100755 index 0000000..7e52af3 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/Cmd.java @@ -0,0 +1,75 @@ +package me.yuri.yuriapi.api.command; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Cmd { + /** + * The command name + * + * @return the command name + */ + String command(); + + /** + * Defines whether the command is executable by players + * + * @return whether the command is executable by players + */ + boolean playerSide() default true; + + /** + * Defines whether the command is executable by the console + * + * @return whether the command is executable by the console + */ + boolean consoleSide() default true; + + /** + * Defines the permissions that are required to execute the command (at least 1 permission must be met) + * + * @return permissions that are required to execute the command + */ + String[] permissions() default {}; + + /** + * Defines the default tab completion array for the command + * + * @return tab completion string array + */ + String[] tabCompletions() default {}; + + /** + * Defines the command description + * + * @return command description + */ + String desc() default ""; + + /** + * Defines the command aliases + * + * @return command aliases + */ + String[] aliases() default {}; + + /** + * Defines the default message when the caller does not have required permissions + * + * @return the default message when the caller does not have required permissions + */ + String noPerms() default "§4Missing permissions"; + + /** + * Defines the name of the method that is called whenever the command is subjected to autocompletion trials + * If empty, it will be disabled + * + * @return name of the method (inside the same class) that will be called on command autocompletion + */ + @Deprecated String tabCompletionHandler() default ""; + +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/CommandContainer.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/CommandContainer.java new file mode 100755 index 0000000..0809f35 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/CommandContainer.java @@ -0,0 +1,35 @@ +package me.yuri.yuriapi.api.command; + +import org.bukkit.plugin.Plugin; + +import java.lang.reflect.Method; + +public class CommandContainer { + private final Plugin p; + private final Method m; + private final Object clazz; + private final Cmd cmd; + + public CommandContainer(Plugin p, Method m, Object clazz) { + this.p = p; + this.m = m; + this.clazz = clazz; + cmd = m.getAnnotation(Cmd.class); + } + + public Plugin getMainPluginInstance() { + return p; + } + + public Method getMethod() { + return m; + } + + public Object getInstance() { + return clazz; + } + + public Cmd getAnnotation() { + return cmd; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/CommandEvent.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/CommandEvent.java new file mode 100755 index 0000000..0af7241 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/CommandEvent.java @@ -0,0 +1,127 @@ +package me.yuri.yuriapi.api.command; + +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.utils.Colored; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.entity.Player; + +public class CommandEvent { + + protected final CommandSender sender; + protected final String[] args; + protected final String label; + protected final Cmd cmdAnnotation; + protected final Command cmd; + protected final String argsstring; + protected final boolean isPlayer, isConsole; + protected final YPlayer plr; + + public CommandEvent(CommandSender sender, Command cmd, String label, Cmd command, String[] args) { + this.sender = sender; + this.args = args; + this.label = label; + this.cmdAnnotation = command; + this.cmd = cmd; + this.argsstring = String.join(" ", args).trim(); + this.isConsole = this.sender instanceof ConsoleCommandSender; + this.isPlayer = this.sender instanceof Player; + + if (isPlayer) + this.plr = YPlayer.get((Player) sender); + else + this.plr = null; + } + + /** + * Gets the command caller + * + * @return command sender + */ + public CommandSender getSender() { + return sender; + } + + /** + * Gets the command arguments + * + * @return command arguments string array + */ + public String[] getArgs() { + return args; + } + + /** + * Gets the particular string used to invoke the command + * + * @return command label + */ + public String getCmdLabel() { + return label; + } + + /** + * Gets the annotation present above the command method + * + * @return Cmd annotation + */ + public Cmd getCmdAnnotation() { + return cmdAnnotation; + } + + /** + * Gets the Bukkit command instance + * + * @return Bukkit command instance + */ + public Command getCommand() { + return cmd; + } + + /** + * Gets the arguments as a single string + * + * @return arguments as a single string + */ + public String getArgsString() { + return argsstring; + } + + /** + * Sends a message to the CommandSender, applies color codes + * + * @param msg the message + */ + public void reply(String... msg) { + this.getSender().sendMessage(Colored.colorize(msg)); + } + + /** + * Checks if the command sender is a player + * + * @return true if the sender is a player, false otherwise + */ + public boolean isPlayer() { + return isPlayer; + } + + /** + * Checks if the command sender is a console + * + * @return true if the sender is a console, false otherwise + */ + public boolean isConsole() { + return isConsole; + } + + /** + * Returns the sender as player + * + * @return CommandSender as player + */ + public YPlayer asPlayer() { + if (plr == null) throw new IllegalStateException("Sender is not a player."); + return plr; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/CommandManager.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/CommandManager.java new file mode 100755 index 0000000..a1ce77f --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/CommandManager.java @@ -0,0 +1,152 @@ +package me.yuri.yuriapi.api.command; + +import me.yuri.yuriapi.Desu; +import me.yuri.yuriapi.api.reflectionless.Reflectionless; +import me.yuri.yuriapi.api.utils.configuration.ConfigVar; +import me.yuri.yuriapi.utils.Logging; +import org.bukkit.command.*; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; + +import javax.annotation.Nonnull; +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class CommandManager implements CommandExecutor, TabCompleter { + + public static final Map commandRegistry = new ConcurrentHashMap<>(); + /* + Parameter must be CommandClass + */ + @ConfigVar(value = "enableCommandRegistryNotifications") + private static final boolean notify = true; + private final JavaPlugin pl; + + public CommandManager(JavaPlugin pl) { + this.pl = pl; + } + + /** + * Registers a class containing command methods + * + * @param clazz the class instance containing the command methods + */ + public void registerCommand(Object clazz) { + Arrays.stream(clazz.getClass().getDeclaredMethods()).filter(m -> (m.isAnnotationPresent(Cmd.class) + && m.getParameterCount() > 0 && CommandEvent.class.isAssignableFrom(m.getParameters()[0].getType()))).forEach(a -> { + Cmd annot = a.getAnnotation(Cmd.class); + CommandContainer cc = new CommandContainer(pl, a, clazz); + commandRegistry.put(annot.command().toLowerCase(), cc); + if (annot.aliases().length != 0) { + Arrays.stream(annot.aliases()).forEach(al -> commandRegistry.put(al.toLowerCase(), cc)); + } + + if (notify) { + Logging.consoleLog(Desu.cl.colorizeInst("$eCommand $a/" + annot.command() + " $eregistered!")); + if (annot.aliases().length != 0) { + Logging.consoleLog(Desu.cl.colorizeInst("$eAliases:")); + for (String s : annot.aliases()) { + Logging.consoleLog(Desu.cl.colorizeInst("$e - $a/" + s.toLowerCase())); + } + } + } + try { + Objects.requireNonNull(pl.getCommand(annot.command())).setExecutor(this); + } catch (NullPointerException e) { + Logging.consoleLog(Desu.cl.colorizeInst("$cError when registering command $e" + annot.command() + "$c! Command is not defined in $eplugin.yml$c!")); + } + + }); + } + + @Override + public boolean onCommand(@Nonnull CommandSender sender, + @Nonnull org.bukkit.command.Command cmd, + @Nonnull String label, @Nonnull String[] args) { + for (int arg = args.length; arg >= 0; arg--) { + StringBuilder buffer = new StringBuilder(); + buffer.append(label.toLowerCase()); + for (int x = 0; x < arg; x++) { + buffer.append(".").append(args[x].toLowerCase()); + } + String bufferString = buffer.toString(); + if (commandRegistry.containsKey(buffer.toString())) { + + CommandContainer entry = commandRegistry.get(buffer.toString()); + + Cmd command = entry.getAnnotation(); + + if (!command.consoleSide() && !(sender instanceof Player)) { + sender.sendMessage(Desu.cl.colorizeInst(Desu.cl.colorizeInst("$4This command is for players only!"))); + } else if (!command.playerSide() && !(sender instanceof ConsoleCommandSender)) { + sender.sendMessage(Desu.cl.colorizeInst(Desu.cl.colorizeInst("$4This command can only be run via terminal."))); + } else { + int subCommand = bufferString.split("\\.").length - 1; + String[] modArgs = IntStream.range(0, args.length - subCommand).mapToObj(i -> args[i + subCommand]).toArray(String[]::new); + + String labelFinal = IntStream.range(0, subCommand).mapToObj(x -> " " + args[x]).collect(Collectors.joining("", label, "")); + if (command.permissions().length == 0 || Arrays.stream(command.permissions()).anyMatch(p -> sender.hasPermission(entry.getMainPluginInstance().getName().toLowerCase() + "." + p)) || sender.isOp()) { + try { + Object event = Reflectionless.get(entry.getMethod().getParameterTypes()[0].getConstructors()[0]).call(sender, cmd, labelFinal, command, modArgs); + + Reflectionless.get(entry.getMethod()).call(entry.getInstance(), event); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + sender.sendMessage(command.noPerms()); + } + } + break; + } + } + return true; + } + + @SuppressWarnings("unchecked") + @Override + public List onTabComplete(@Nonnull CommandSender snd, + Command command, + @Nonnull String lb, + @Nonnull String[] args) { + if (commandRegistry.containsKey(command.getName())) { + CommandContainer entry = commandRegistry.get(command.getName()); + + if (entry.getAnnotation().permissions().length > 0 && Arrays.stream(entry.getAnnotation().permissions()).noneMatch(p -> snd.hasPermission(entry.getMainPluginInstance().getName().toLowerCase() + "." + p))) { + return Collections.emptyList(); + } + + if (entry.getAnnotation().tabCompletions().length != 0) { + String[] tc = entry.getAnnotation().tabCompletions(); + if (tc[0].equals(TabPlaceholder.PLAYERS)) return null; + if (tc[0].equals(TabPlaceholder.EMPTY)) return Collections.emptyList(); + return Arrays.asList(tc); + } else { + Optional opt = Arrays.stream(entry.getInstance().getClass().getDeclaredMethods()).filter(m -> { + if (m.isAnnotationPresent(TabCompletion.class)) + return m.getAnnotation(TabCompletion.class).command().equals(command.getName()); + else return false; + }).findFirst(); + try { + if (opt.isEmpty()) { + return Collections.emptyList(); + } + if (!opt.get().getReturnType().equals(List.class)) return Collections.emptyList(); + else { + CommandTabCompleteEvent tb = new CommandTabCompleteEvent(snd, command, lb, args, opt.get().getAnnotation(TabCompletion.class)); + Object o = Reflectionless.get(opt.get()).call(entry.getInstance(), tb); + assert o instanceof List; + return (List) o; + } + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + } + return null; + } +} \ No newline at end of file diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/CommandResult.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/CommandResult.java new file mode 100644 index 0000000..351f5c4 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/CommandResult.java @@ -0,0 +1,5 @@ +package me.yuri.yuriapi.api.command; + +public enum CommandResult { + SUCCESS, INVALID_FIELD, TOO_MANY_ARGS, NOT_ENOUGH_ARGS, EXCEPTION +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/CommandTabCompleteEvent.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/CommandTabCompleteEvent.java new file mode 100644 index 0000000..0d89a6f --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/CommandTabCompleteEvent.java @@ -0,0 +1,57 @@ +package me.yuri.yuriapi.api.command; + +import me.yuri.yuriapi.api.utils.Colored; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +public class CommandTabCompleteEvent { + protected final CommandSender sender; + protected final String[] args; + protected final String label; + protected final Command cmd; + protected final String argsstring; + protected final TabCompletion tc; + + public CommandTabCompleteEvent(CommandSender s, Command cmd, String label, String[] args, TabCompletion tc) { + sender = s; + this.label = label; + this.cmd = cmd; + this.args = args; + this.argsstring = String.join(" ", args); + this.tc = tc; + } + + public CommandSender getSender() { + return sender; + } + + public String[] getArgs() { + return args; + } + + public String getArgsString() { + return argsstring; + } + + public Command getCommand() { + return cmd; + } + + public String getLabel() { + return label; + } + + /** + * Sends a message to the CommandSender, applies color codes + * + * @param msg the message + */ + public void reply(String... msg) { + this.getSender().sendMessage(Colored.colorize(msg)); + } + + public TabCompletion getAnnotation() { + if (tc == null) throw new IllegalStateException("Using null annotation"); + return tc; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/ConsoleCommandEvent.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/ConsoleCommandEvent.java new file mode 100644 index 0000000..1bd0c17 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/ConsoleCommandEvent.java @@ -0,0 +1,20 @@ +package me.yuri.yuriapi.api.command; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; + +public class ConsoleCommandEvent extends CommandEvent { + public ConsoleCommandEvent(CommandSender sender, Command cmd, String label, Cmd command, String[] args) { + super(sender, cmd, label, command, args); + } + + /** + * Gets the command caller as a Player + * + * @return player command caller + */ + public ConsoleCommandSender getConsole() { + return (ConsoleCommandSender) sender; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/Permission.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/Permission.java new file mode 100755 index 0000000..db7844e --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/Permission.java @@ -0,0 +1,16 @@ +package me.yuri.yuriapi.api.command; + +public class Permission { + public static final Permission NOPERMISSION = new Permission("null"); + public static final Permission[] NOPERMISSIONS = new Permission[]{new Permission("null")}; + + private final String perm; + + public Permission(String permission) { + this.perm = permission; + } + + public String getPermissionString() { + return perm; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/PlayerCommandEvent.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/PlayerCommandEvent.java new file mode 100644 index 0000000..0fcd015 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/PlayerCommandEvent.java @@ -0,0 +1,20 @@ +package me.yuri.yuriapi.api.command; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class PlayerCommandEvent extends CommandEvent { + public PlayerCommandEvent(CommandSender sender, Command cmd, String label, Cmd command, String[] args) { + super(sender, cmd, label, command, args); + } + + /** + * Gets the command caller as a Player + * + * @return player command caller + */ + public Player getPlayer() { + return (Player) sender; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/TabCompletion.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/TabCompletion.java new file mode 100644 index 0000000..8896eac --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/TabCompletion.java @@ -0,0 +1,29 @@ +package me.yuri.yuriapi.api.command; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface TabCompletion { + /** + * @return the command name + */ + String command(); + + /** + * Defines whether the command is executable by players + * + * @return whether the command is executable by players + */ + boolean playerSide() default true; + + /** + * Defines whether the command is executable by the console + * + * @return whether the command is executable by the console + */ + boolean consoleSide() default true; +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/TabPlaceholder.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/TabPlaceholder.java new file mode 100644 index 0000000..6d27a2e --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/command/TabPlaceholder.java @@ -0,0 +1,10 @@ +package me.yuri.yuriapi.api.command; + +public final class TabPlaceholder { + public static final String PLAYERS = ""; + + public static final String EMPTY = ""; + + private TabPlaceholder() { + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbColumn.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbColumn.java new file mode 100644 index 0000000..8eae9bb --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbColumn.java @@ -0,0 +1,49 @@ +package me.yuri.yuriapi.api.db; + +import javax.annotation.Nonnull; + +public class DbColumn, V> { + + private final DbConnection conn; + private final String name; + private final T type; + private final boolean nullable; + private final DbTable table; + + protected DbColumn(String name, T type, DbTable table, boolean nullable) { + this.name = name; + this.type = type; + this.nullable = nullable; + this.table = table; + this.conn = table.getConnection(); + } + + @Nonnull + public DbConnection getConnection() { + return this.conn; + } + + @Nonnull + public String getName() { + return name; + } + + @Nonnull + public T getType() { + return type; + } + + @Nonnull + public Class getDataType() { + return type.getBoxedDataType(); + } + + public boolean isNullable() { + return nullable; + } + + @Nonnull + public DbTable getTable() { + return table; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbColumnDataType.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbColumnDataType.java new file mode 100644 index 0000000..a4dad2c --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbColumnDataType.java @@ -0,0 +1,55 @@ +package me.yuri.yuriapi.api.db; + +import org.bukkit.Location; +import org.bukkit.inventory.ItemStack; + +import javax.annotation.Nonnull; +import java.util.UUID; + +public final class DbColumnDataType { + + public static final DbColumnDataType INTEGER = new DbColumnDataType<>(Integer.class, Integer.class, 0); + public static final DbColumnDataType BYTE_ARRAY = new DbColumnDataType<>(byte[].class, byte[].class, 1); + public static final DbColumnDataType UUID = new DbColumnDataType<>(byte[].class, UUID.class, 2); + public static final DbColumnDataType TIMESTAMP = new DbColumnDataType<>(Long.class, Long.class, 3); + public static final DbColumnDataType BIGINT = new DbColumnDataType<>(Long.class, Long.class, 4); + public static final DbColumnDataType LOCATION = new DbColumnDataType<>(String.class, Location.class, 5); + public static final DbColumnDataType BOOLEAN = new DbColumnDataType<>(Boolean.class, Boolean.class, 6); + public static final DbColumnDataType TEXT = new DbColumnDataType<>(String.class, String.class, 7); + public static final DbColumnDataType ITEM_STACK = new DbColumnDataType<>(String.class, ItemStack.class, 8); + public static final DbColumnDataType FLOAT = new DbColumnDataType<>(Float.class, Float.class, 9); + public static final DbColumnDataType DOUBLE = new DbColumnDataType<>(Double.class, Double.class, 10); + private final Class type; + private final Class datatype; + private final int id; + + private DbColumnDataType(@Nonnull Class type, @Nonnull Class datatype, int id) { + this.type = type; + this.datatype = datatype; + this.id = id; + } + + public int getId() { + return id; + } + + @Nonnull + public T getPrimitiveType(T t) { + return t; + } + + @Nonnull + public V getPrimitiveDataType(V v) { + return v; + } + + @Nonnull + public Class getBoxedType() { + return type; + } + + @Nonnull + public Class getBoxedDataType() { + return datatype; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbComparisonLink.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbComparisonLink.java new file mode 100644 index 0000000..6f81a64 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbComparisonLink.java @@ -0,0 +1,18 @@ +package me.yuri.yuriapi.api.db; + +import javax.annotation.Nonnull; + +public enum DbComparisonLink { + START(""), OR("OR"), AND("AND"); + + private final String lit; + + DbComparisonLink(String n) { + this.lit = n; + } + + @Nonnull + public String getLiteral() { + return lit; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbComparisonType.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbComparisonType.java new file mode 100644 index 0000000..5ca3bd5 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbComparisonType.java @@ -0,0 +1,18 @@ +package me.yuri.yuriapi.api.db; + +import javax.annotation.Nonnull; + +public enum DbComparisonType { + EQUALS("="), MORE_THAN(">"), LESS_THAN("<"), MORE_THAN_EQUALS(">="), LESS_THAN_EQUALS("<="), NOT_EQUALS("<>"), LIKE(" LIKE "); + + private final String lit; + + DbComparisonType(String l) { + this.lit = l; + } + + @Nonnull + public String getLiteral() { + return lit; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbCondition.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbCondition.java new file mode 100644 index 0000000..98a2167 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbCondition.java @@ -0,0 +1,17 @@ +package me.yuri.yuriapi.api.db; + +import javax.annotation.Nonnull; +import java.util.List; + +public class DbCondition { + private final List comps; + + protected DbCondition(List comparisons) { + comps = comparisons; + } + + @Nonnull + public List getExpressionList() { + return comps; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbConditionBuilder.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbConditionBuilder.java new file mode 100644 index 0000000..59bbfe1 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbConditionBuilder.java @@ -0,0 +1,101 @@ +package me.yuri.yuriapi.api.db; + +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.List; + +public class DbConditionBuilder { + private final DbTable table; + private final List comparisons = new ArrayList<>(); + private DbColumn current = null; + private int currentDepth = 0; + private DbComparisonLink currentLink = DbComparisonLink.START; + + protected DbConditionBuilder(DbTable t) { + table = t; + } + + @Nonnull + public DbConditionBuilder forColumn(@Nonnull DbColumn c) { + current = c; + return this; + } + + @Nonnull + public DbConditionBuilder forColumn(@Nonnegative int index) { + current = table.getColumns().get(index); + return this; + } + + @Nonnull + public DbConditionBuilder forColumn(@Nonnull String name) { + for (DbColumn c : table.getColumns()) { + if (c.getName().equalsIgnoreCase(name)) { + current = c; + return this; + } + } + + throw new IllegalArgumentException(String.format("Column %s does not exist.", name)); + } + + @Nonnull + public DbConditionBuilder value(@Nonnull DbComparisonType type, V value) { + if (current == null) { + throw new IllegalStateException("Set the column before applying condition."); + } + if (currentLink == null) { + throw new IllegalStateException("No link between the two expressions selected."); + } + + comparisons.add(new DbExpression(current, type, value, currentDepth, currentLink)); + currentLink = null; + return this; + } + + @Nonnull + public DbConditionBuilder or() { + if (comparisons.isEmpty()) { + throw new IllegalStateException("No expression has been set before OR clause."); + } + + currentLink = DbComparisonLink.OR; + return this; + } + + @Nonnull + public DbConditionBuilder and() { + if (comparisons.isEmpty()) { + throw new IllegalStateException("No expression has been set before AND clause."); + } + + currentLink = DbComparisonLink.AND; + return this; + } + + @Nonnull + public DbConditionBuilder openGroup() { + currentDepth++; + return this; + } + + @Nonnull + public DbConditionBuilder closeGroup() { + if (currentDepth == 0) { + throw new IllegalStateException("No group to close."); + } + + currentDepth--; + return this; + } + + @Nonnull + public DbCondition end() { + if (currentDepth != 0) { + throw new IllegalStateException(String.format("Unclosed groups: %d groups.", currentDepth)); + } + + return new DbCondition(comparisons); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbConnection.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbConnection.java new file mode 100644 index 0000000..fdaf345 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbConnection.java @@ -0,0 +1,109 @@ +package me.yuri.yuriapi.api.db; + +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public abstract class DbConnection { + + protected final String connectionString; + protected final List tables = new ArrayList<>(); + protected Connection connection = null; + protected boolean doInitTables = false; + protected boolean init = false; + + protected DbConnection(String connectionString) { + this.connectionString = connectionString; + } + + public static DbConnectionBuilder newConnection(DbConnectionBuilder.DbType t) { + return new DbConnectionBuilder(t); + } + + @Nonnull + public abstract Class forName() throws ClassNotFoundException; + + public boolean isConnected() { + try { + return connection != null && connection.isClosed(); + } catch (SQLException ignored) { + return false; + } + } + + protected abstract void createTable(@Nonnull DbTable t, boolean force); + + @Nonnull + public abstract String transformDataType(@Nonnull DbColumnDataType type); + + public void initTables(DbTable... t) { + initTables(Arrays.asList(t)); + } + + public void initTables(@Nonnull List t) { + if (init) + throw new IllegalStateException("Database has already been initialized."); + + doInitTables = true; + tables.addAll(t); + } + + @Nonnull + public DbTable getTable(@Nonnegative int ordinal) { + return tables.get(ordinal); + } + + @Nonnull + public abstract String serializeObject(@Nullable Object o); + + public abstract DbQueryResult select(DbSelectQuery q); + + @Nullable + public abstract Object deserializeObject(@Nonnull DbColumnDataType type, @Nullable Object o); + + @Nonnegative + public abstract int update(DbQuery q); + + @Nonnull + public List getTables() { + return this.tables; + } + + public DbTable getTable(@Nonnull String name) { + for (DbTable t : tables) { + if (t.getName().equalsIgnoreCase(name)) return t; + } + return null; + } + + public void createTable(@Nonnull DbTable t) { + createTable(t, false); + } + + public void connect() throws Exception { + init = true; + forName(); + connection = DriverManager.getConnection(connectionString); + if (doInitTables) { + List tablelist = new ArrayList<>(tables); + tables.clear(); + tablelist.forEach(t -> createTable(t, false)); + } + } + + public void disconnect() { + try { + connection.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + //TODO QUERYING DATA PARSING, DATA CONVERTERS +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbConnectionBuilder.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbConnectionBuilder.java new file mode 100644 index 0000000..39071dc --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbConnectionBuilder.java @@ -0,0 +1,67 @@ +package me.yuri.yuriapi.api.db; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +public class DbConnectionBuilder { + + private final DbType type; + private final Map> tablebuilds = new HashMap<>(); + private String connectionString = null; + + public DbConnectionBuilder(DbType type) { + this.type = type; + } + + @Nonnull + public DbConnectionBuilder withConnectionString(@Nonnull String s) { + connectionString = s; + return this; + } + + @Nonnull + public DbConnectionBuilder withTable(String name, Function builder) { + tablebuilds.put(name, builder); + return this; + } + + @Nonnull + public DbConnection build() { + if (connectionString == null) { + throw new IllegalStateException("connection string is not defined"); + } + + DbConnection db; + + switch (type) { + case SQLITE: + db = new SqliteConnection(connectionString); + break; + default: + throw new RuntimeException("not possible but ok"); + } + + List tables = new ArrayList<>(); + + for (Map.Entry> u : tablebuilds.entrySet()) { + tables.add(u.getValue().apply(new DbTableBuilder(u.getKey(), db))); + } + + db.initTables(tables); + + return db; + } + + @Nonnull + public DbType getType() { + return type; + } + + public enum DbType { + SQLITE + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbExpression.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbExpression.java new file mode 100644 index 0000000..0b4a027 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbExpression.java @@ -0,0 +1,45 @@ +package me.yuri.yuriapi.api.db; + +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; + +public class DbExpression { + + private final DbColumn column; + private final DbComparisonType type; + private final Object value; + private final int depth; + private final DbComparisonLink prev; + + protected DbExpression(DbColumn col, DbComparisonType type, Object value, int depth, DbComparisonLink prev) { + this.column = col; + this.type = type; + this.value = value; + this.prev = prev; + this.depth = depth; + } + + public Object getValue() { + return value; + } + + @Nonnull + public DbColumn getColumn() { + return column; + } + + @Nonnull + public DbComparisonType getComparisonType() { + return type; + } + + @Nonnegative + public int getDepth() { + return depth; + } + + @Nonnull + public DbComparisonLink linkBefore() { + return prev; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbQuery.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbQuery.java new file mode 100644 index 0000000..9f2721e --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbQuery.java @@ -0,0 +1,53 @@ +package me.yuri.yuriapi.api.db; + +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Map; + +public class DbQuery { + + private final DbConnection conn; + private final Map, Object> map; + private final DbTable table; + private final DbQueryType type; + private final DbCondition condition; + + protected DbQuery(@Nonnull DbQueryType type, @Nonnull DbTable t, @Nonnull Map, Object> map, @Nullable DbCondition cnd) { + this.map = map; + this.table = t; + this.type = type; + this.condition = cnd; + this.conn = table.getConnection(); + } + + @Nonnull + public DbConnection getConnection() { + return conn; + } + + @Nonnegative + public int execute() { + return conn.update(this); + } + + @Nonnull + public Map, Object> getColumnMap() { + return map; + } + + @Nonnull + public DbTable getTable() { + return table; + } + + @Nonnull + public DbQueryType getQueryType() { + return type; + } + + @Nullable + public DbCondition getCondition() { + return condition; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbQueryResult.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbQueryResult.java new file mode 100644 index 0000000..456008b --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbQueryResult.java @@ -0,0 +1,146 @@ +package me.yuri.yuriapi.api.db; + +import com.google.common.collect.ImmutableList; + +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; +import java.util.function.Consumer; + +public class DbQueryResult { + + private final DbConnection connection; + private final ImmutableList> columns; + private final DbTable table; + private final ResultSet rs; + + protected DbQueryResult(DbConnection con, DbTable t, ImmutableList> l, ResultSet rs) { + this.table = t; + this.columns = l; + this.rs = rs; + this.connection = con; + } + + @Nonnull + public DbTable getTable() { + return table; + } + + public ImmutableList> getColumns() { + return columns; + } + + public boolean isEmpty() { + return rs == null; + } + + public boolean next() { + try { + return rs.next(); + } catch (SQLException throwables) { + return false; + } + } + + public boolean previous() { + try { + return rs.previous(); + } catch (SQLException throwables) { + return false; + } + } + + @Nonnull + public DbQueryResult skip(int count) { + try { + for (int i = 0; i < count; i++) + rs.next(); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + return this; + } + + @Nonnull + public DbQueryResult back(int count) { + try { + for (int i = 0; i < count; i++) + rs.previous(); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + return this; + } + + @SuppressWarnings("unchecked") + public , V> V get(DbColumn c) { + try { + Object o = connection.deserializeObject(c.getType(), rs.getObject(c.getName())); + assert o == null || o.getClass().isAssignableFrom(c.getDataType()); + return (V) o; + } catch (SQLException throwables) { + return null; + } + } + + public Object get(@Nonnegative int rowIndex) { + return this.get(this.columns.get(rowIndex)); + } + + public long getLong(@Nonnegative int rowIndex) { + try { + return rs.getLong(rowIndex); + } catch (SQLException throwables) { + throwables.printStackTrace(); + throw new RuntimeException("Problem"); + } + } + + public boolean getBoolean(@Nonnegative int rowIndex) { + try { + return rs.getBoolean(rowIndex); + } catch (SQLException throwables) { + throwables.printStackTrace(); + throw new RuntimeException("Problem"); + } + } + + public UUID getUUID(@Nonnegative int rowIndex) { + return (UUID) get(rowIndex); + } + + public int getInt(@Nonnegative int rowIndex) { + try { + return rs.getInt(rowIndex); + } catch (SQLException throwables) { + throwables.printStackTrace(); + throw new RuntimeException("Problem"); + } + } + + public String getText(@Nonnegative int rowIndex) { + try { + return rs.getString(rowIndex); + } catch (SQLException throwables) { + throwables.printStackTrace(); + throw new RuntimeException("Problem"); + } + } + + @Nonnull + public DbQueryResult then(Consumer c) { + c.accept(this); + return this; + } + + public void close() { + try { + rs.close(); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + } + +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbQueryType.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbQueryType.java new file mode 100644 index 0000000..db1b229 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbQueryType.java @@ -0,0 +1,18 @@ +package me.yuri.yuriapi.api.db; + +import javax.annotation.Nonnull; + +public enum DbQueryType { + INSERT("INSERT"), UPDATE("UPDATE"), REMOVE("DELETE"); + + private final String cmd; + + DbQueryType(String cmd) { + this.cmd = cmd; + } + + @Nonnull + public String getCommand() { + return cmd; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbSelectQuery.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbSelectQuery.java new file mode 100644 index 0000000..fa445d0 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbSelectQuery.java @@ -0,0 +1,45 @@ +package me.yuri.yuriapi.api.db; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; + +public class DbSelectQuery { + + private final DbConnection connection; + private final List> columns; + private final DbTable table; + private final DbCondition condition; + + protected DbSelectQuery(@Nonnull DbTable t, @Nonnull List> columns, @Nullable DbCondition cnd) { + this.connection = t.getConnection(); + this.columns = columns; + this.table = t; + this.condition = cnd; + } + + @Nonnull + public DbConnection getConnection() { + return connection; + } + + @Nonnull + public DbQueryResult execute() { + return connection.select(this); + } + + @Nonnull + public List> getColumns() { + return columns; + } + + @Nonnull + public DbTable getTable() { + return table; + } + + @Nullable + public DbCondition getCondition() { + return condition; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbSelectQueryBuilder.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbSelectQueryBuilder.java new file mode 100644 index 0000000..fb1cf06 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbSelectQueryBuilder.java @@ -0,0 +1,93 @@ +package me.yuri.yuriapi.api.db; + +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class DbSelectQueryBuilder { + + private final DbTable table; + private final List> selected = new ArrayList<>(); + private boolean isSelect = false; + private DbCondition condition = null; + + protected DbSelectQueryBuilder(@Nonnull DbTable t) { + this.table = t; + } + + @Nonnull + public DbSelectQueryBuilder columnRange(@Nonnegative int start, @Nonnegative int end) { + if (isSelect) { + throw new IllegalStateException("Columns have already been selected."); + } + + if (start > end) { + throw new IllegalArgumentException("Value of parameter 'start' must be less than of parameter 'end'"); + } + + List> l = table.getColumns(); + for (int i = start; i < end; i++) { + selected.add(l.get(i)); + } + isSelect = true; + return this; + } + + @Nonnull + public DbSelectQueryBuilder columns(@Nonnegative int... indexes) { + if (isSelect) { + throw new IllegalStateException("Columns have already been selected."); + } + + List> l = table.getColumns(); + for (int i : indexes) { + selected.add(l.get(i)); + } + isSelect = true; + return this; + } + + @Nonnull + public DbSelectQueryBuilder columns(@Nonnull String... names) { + if (isSelect) { + throw new IllegalStateException("Columns have already been selected."); + } + + List> l = table.getColumns(); + List namel = Arrays.asList(names); + selected.addAll(l.stream().filter(c -> namel.contains(c.getName())).collect(Collectors.toList())); //FIXME CONTINUE + isSelect = true; + return this; + } + + @Nonnull + public DbSelectQueryBuilder all() { + if (isSelect) { + throw new IllegalStateException("Columns have already been selected."); + } + + selected.addAll(table.getColumns()); + isSelect = true; + return this; + } + + @Nonnull + public DbSelectQueryBuilder where(@Nonnull Function f) { + if (condition != null) { + throw new IllegalStateException("WHERE condition has already been set."); + } + + condition = f.apply(new DbConditionBuilder(table)); + return this; + } + + @Nonnull + public DbSelectQuery build() { + return new DbSelectQuery(table, selected, condition); + } + +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbTable.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbTable.java new file mode 100644 index 0000000..3bc79cd --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbTable.java @@ -0,0 +1,89 @@ +package me.yuri.yuriapi.api.db; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class DbTable { + + private final String name; + private final DbColumn primary_key; + private final List> columns; + private final DbConnection connection; + + protected DbTable(@Nonnull DbConnection con, @Nonnull String name, @Nonnull Object[] primary_key, @Nonnull List columns) { + this.connection = con; + this.name = name; + this.primary_key = new DbColumn<>((String) primary_key[0], (DbColumnDataType) primary_key[1], this, (boolean) primary_key[2]); + this.columns = columns.stream().map(c -> new DbColumn<>((String) c[0], (DbColumnDataType) c[1], this, (boolean) c[2])).collect(Collectors.toList()); + } + + @Nonnull + public String getName() { + return name; + } + + @Nonnull + public DbConnection getConnection() { + return connection; + } + + @Nonnull + public DbColumn getPrimaryKey() { + return primary_key; + } + + @Nonnull + public List> getColumns() { + List> l = new ArrayList<>(); + l.add(primary_key); + l.addAll(columns); + return l; + } + + @Nonnull + public List> getNormalColums() { + return columns; + } + + @Nullable + public DbColumnDataType getByName(String name) { + if (primary_key.getName().equalsIgnoreCase(name)) + return primary_key.getType(); + + for (DbColumn c : columns) { + if (c.getName().equalsIgnoreCase(name)) { + return c.getType(); + } + } + + return null; + } + + @Nonnull + public DbUpdateQueryBuilder createQuery(DbQueryType t) { + return new DbUpdateQueryBuilder(t, this); + } + + @Nonnull + public DbUpdateQueryBuilder createUpdateQuery() { + return new DbUpdateQueryBuilder(DbQueryType.UPDATE, this); + } + + @Nonnull + public DbUpdateQueryBuilder createInsertQuery() { + return new DbUpdateQueryBuilder(DbQueryType.INSERT, this); + } + + @Nonnull + public DbUpdateQueryBuilder createRemoveQuery() { + return new DbUpdateQueryBuilder(DbQueryType.REMOVE, this); + } + + @Nonnull + public DbSelectQueryBuilder createSelectQuery() { + return new DbSelectQueryBuilder(this); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbTableBuilder.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbTableBuilder.java new file mode 100644 index 0000000..e8397dd --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbTableBuilder.java @@ -0,0 +1,52 @@ +package me.yuri.yuriapi.api.db; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.List; + +public class DbTableBuilder { + + private final List columns = new ArrayList<>(); + private final String name; + private final DbConnection con; + private Object[] primary_key = null; + + public DbTableBuilder(@Nonnull String name, @Nonnull DbConnection con) { + this.name = name; + this.con = con; + } + + @Nonnull + public DbTableBuilder withPrimaryKey(String name, DbColumnDataType type) { + if (primary_key != null) { + throw new IllegalStateException("primary key was already set"); + } + primary_key = new Object[]{name, type, false}; + return this; + } + + @Nonnull + public DbTableBuilder withColumn(String name, DbColumnDataType type, boolean nullable) { + columns.add(new Object[]{name, type, nullable}); + return this; + } + + @Nonnull + public DbTableBuilder withColumn(String name, DbColumnDataType type) { + return withColumn(name, type, false); + } + + @Nonnull + public DbTable build() { + if (primary_key == null) { + throw new IllegalStateException("primary key is not set"); + } + + return new DbTable(con, name, primary_key, columns); + } + + @Nonnull + public String getName() { + return name; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbUpdateQueryBuilder.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbUpdateQueryBuilder.java new file mode 100644 index 0000000..214efab --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/DbUpdateQueryBuilder.java @@ -0,0 +1,88 @@ +package me.yuri.yuriapi.api.db; + +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +public class DbUpdateQueryBuilder { + + private final DbTable table; + private final DbQueryType type; + private final Map, Object> object_map = new HashMap<>(); + private DbCondition condition = null; + + protected DbUpdateQueryBuilder(@Nonnull DbQueryType type, @Nonnull DbTable table) { + this.table = table; + this.type = type; + } + + @Nonnull + public , V> DbUpdateQueryBuilder setColumn(@Nonnull DbColumn column, @Nullable V data) { + if (!column.isNullable()) + throw new IllegalArgumentException("Column " + column.getName() + " does not accept null values."); + + object_map.put(column, data); + return this; + } + + @Nonnull + public DbUpdateQueryBuilder setColumn(@Nonnegative int columnIndex, @Nullable V data) { + DbColumn c = table.getColumns().get(columnIndex); + + if (data != null) { + if (!data.getClass().isAssignableFrom(c.getDataType())) { + throw new IllegalArgumentException(String.format("Invalid data type provided. Expected: %s, provided: %s", c.getDataType().getCanonicalName(), data.getClass().getCanonicalName())); + } + } else { + if (!c.isNullable()) + throw new IllegalArgumentException("Column " + c.getName() + " does not accept null values."); + } + + object_map.put(c, data); + return this; + } + + @Nonnull + public DbUpdateQueryBuilder setColumn(@Nonnull String name, @Nullable V data) { + DbColumn col = null; + for (DbColumn c : table.getColumns()) { + if (c.getName().equalsIgnoreCase(name)) { + col = c; + break; + } + } + + if (col == null) + throw new IllegalArgumentException(String.format("Column '%s' does not exist.", name)); + + if (data != null) { + if (!data.getClass().isAssignableFrom(col.getDataType())) { + throw new IllegalArgumentException(String.format("Invalid data type provided. Expected: %s, provided: %s", col.getDataType().getCanonicalName(), data.getClass().getCanonicalName())); + } + } else { + if (!col.isNullable()) + throw new IllegalArgumentException(String.format("Column '%s' does not accept null values.", col.getName())); + } + + object_map.put(col, data); + return this; + } + + @Nonnull + public DbUpdateQueryBuilder where(@Nonnull Function f) { + if (condition != null) { + throw new IllegalStateException("WHERE condition has already been set."); + } + + condition = f.apply(new DbConditionBuilder(table)); + return this; + } + + @Nonnull + public DbQuery build() { + return new DbQuery(type, table, object_map, condition); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/SqliteConnection.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/SqliteConnection.java new file mode 100644 index 0000000..d9e8853 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/db/SqliteConnection.java @@ -0,0 +1,246 @@ +package me.yuri.yuriapi.api.db; + +import com.google.common.collect.ImmutableList; +import me.yuri.yuriapi.api.utils.UUIDUtils; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.libs.org.apache.commons.codec.binary.Hex; +import org.bukkit.inventory.ItemStack; + +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.nio.charset.StandardCharsets; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; + +public class SqliteConnection extends DbConnection { + + protected SqliteConnection(String connectionString) { + super(connectionString); + } + + @Nonnull + @Override + public Class forName() throws ClassNotFoundException { + return Class.forName("org.sqlite.JDBC"); + } + + @Override + public void createTable(@Nonnull DbTable t, boolean force) { + StringBuilder sb = new StringBuilder(); + sb.append("CREATE TABLE "); + + if (!force) + sb.append("IF NOT EXISTS "); + + sb.append(t.getName()).append('(').append(t.getPrimaryKey().getName()).append(' ') + .append(transformDataType(t.getPrimaryKey().getType())).append(' ').append("PRIMARY KEY NOT NULL"); + + for (DbColumn c : t.getNormalColums()) { + sb.append(',').append(c.getName()).append(' ').append(transformDataType(c.getType())).append(c.isNullable() ? "" : " NOT NULL"); + } + + sb.append(");"); + String stmt = sb.toString(); + + if (stmt.contains("'")) { + throw new IllegalArgumentException("\"'\" characters are not allowed."); + } + + try { + this.connection.createStatement().executeUpdate(stmt); + this.tables.add(t); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + } + + @Nonnull + @Override + public String transformDataType(@Nonnull DbColumnDataType type) { + switch (type.getId()) { + case 0: + case 6: + return "INT"; + case 7: + case 8: + return "TEXT"; + case 4: + case 3: + case 5: + return "BIGINT"; + case 1: + case 2: + return "BLOB"; + case 9: + case 10: + return "REAL"; + default: + throw new RuntimeException("that's not possible bruh"); + } + } + + @Nonnull + @Override + public String serializeObject(@Nullable Object o) { + if (o == null) { + return "NULL"; + } else if (o instanceof String) { + return String.format("'%s'", sanitize((String) o)); + } else if (o instanceof UUID) { + return String.format("X'%s'", Hex.encodeHexString(UUIDUtils.toByteArray((UUID) o))); + } else if (o instanceof Location) { + Location l = ((Location) o); + return String.format("'%f:%f:%f:%s'", l.getX(), l.getY(), l.getZ(), Objects.requireNonNull(l.getWorld()).getName()); + } else if (o instanceof ItemStack) { + Base64.Encoder en = Base64.getEncoder(); + StringBuilder sb = new StringBuilder(); + for (Map.Entry e : ((ItemStack) o).serialize().entrySet()) { + sb.append(en.encodeToString(e.getKey().getBytes(StandardCharsets.UTF_8))).append(':') + .append(en.encodeToString(String.valueOf(e.getValue()).getBytes(StandardCharsets.UTF_8))) + .append(','); + } + sb.deleteCharAt(sb.length()); + return sb.toString(); + } + return String.valueOf(o); + } + + @Nullable + @Override + public Object deserializeObject(@Nonnull DbColumnDataType type, @Nullable Object o) { + if (o == null) + return null; + if (o instanceof String) { + String str = desanitize(((String) o)); + if (type.getBoxedDataType().isAssignableFrom(Location.class)) { + String[] s = str.split(":", 4); + return new Location(Bukkit.getWorld(s[3]), Double.parseDouble(s[0]), Double.parseDouble(s[1]), Double.parseDouble(s[2])); + } else if (type.getBoxedDataType().isAssignableFrom(ItemStack.class)) { + String[] s = str.split(","); + Map map = new HashMap<>(); + for (String s2 : s) { + String[] s3 = s2.split(":"); + Base64.Decoder d = Base64.getDecoder(); + map.put(new String(d.decode(s3[0])), new String(d.decode(s3[1]))); + } + return ItemStack.deserialize(map); + } + return str.replace("''", "'"); + } else if (o instanceof byte[]) { + if (type.getBoxedDataType().isAssignableFrom(UUID.class)) { + return UUIDUtils.toUUID((((byte[]) o))); + } + } + return o; + } + + @Override + public DbQueryResult select(DbSelectQuery q) { + StringBuilder sb = new StringBuilder(); + sb.append("SELECT "); + + for (DbColumn col : q.getColumns()) { + sb.append(col.getName()).append(','); + } + sb.deleteCharAt(sb.length() - 1).append(" FROM ").append(q.getTable().getName()); + + if (q.getCondition() != null) { + sb.append(" WHERE"); + int depth = 0; + for (DbExpression cmp : q.getCondition().getExpressionList()) { + sb.append(' ').append(cmp.linkBefore().getLiteral()).append(' '); + + if (cmp.getDepth() > depth) + sb.append('('); + else if (cmp.getDepth() < cmp.getDepth()) + sb.append(')'); + + depth = cmp.getDepth(); + + sb.append(cmp.getColumn().getName()).append(cmp.getComparisonType().getLiteral()).append(serializeObject(cmp.getValue())); + } + if (depth > 0) + sb.append(')'); + } + + sb.append(';'); + + try { + ResultSet rs = connection.createStatement().executeQuery(sb.toString()); + return new DbQueryResult(this, q.getTable(), ImmutableList.copyOf(q.getColumns()), rs); + } catch (SQLException e) { + e.printStackTrace(); + return null; + } + } + + @Nonnegative + @Override + public int update(DbQuery q) { + StringBuilder sb = new StringBuilder(); + switch (q.getQueryType()) { + case INSERT: + sb.append("INSERT OR REPLACE INTO ").append(q.getTable().getName()).append("("); + for (DbColumn c : q.getColumnMap().keySet()) { + sb.append(c.getName()).append(','); + } + sb.deleteCharAt(sb.length() - 1); + sb.append(") VALUES ("); + for (Object oo : q.getColumnMap().values()) { + sb.append(this.serializeObject(oo)).append(','); + } + sb.deleteCharAt(sb.length() - 1); + sb.append(')'); + break; + case UPDATE: + sb.append("UPDATE ").append(q.getTable().getName()).append(" SET "); + for (Map.Entry, Object> e : q.getColumnMap().entrySet()) { + sb.append(e.getKey().getName()).append(" = ").append(serializeObject(e.getValue())).append(','); + } + sb.deleteCharAt(sb.length() - 1).append(' '); + break; + case REMOVE: + sb.append("DELETE FROM ").append(q.getTable().getName()).append(' '); + break; + } + + if (q.getQueryType() != DbQueryType.INSERT && q.getCondition() != null && !q.getCondition().getExpressionList().isEmpty()) { + sb.append("WHERE"); + int depth = 0; + for (DbExpression cmp : q.getCondition().getExpressionList()) { + sb.append(' ').append(cmp.linkBefore().getLiteral()).append(' '); + + if (cmp.getDepth() > depth) + sb.append('('); + else if (cmp.getDepth() < cmp.getDepth()) + sb.append(')'); + + depth = cmp.getDepth(); + + sb.append(cmp.getColumn().getName()).append(cmp.getComparisonType().getLiteral()).append(serializeObject(cmp.getValue())); + } + if (depth > 0) + sb.append(')'); + + } + + sb.append(';'); + try { + return connection.createStatement().executeUpdate(sb.toString()); + } catch (SQLException throwables) { + throwables.printStackTrace(); + return -1; + } + } + + private String sanitize(String input) { + return input.replace("'", "''"); + } + + private String desanitize(String input) { + return input.replace("''", "'"); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/economy/EconomyManager.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/economy/EconomyManager.java new file mode 100644 index 0000000..8674d86 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/economy/EconomyManager.java @@ -0,0 +1,116 @@ +package me.yuri.yuriapi.api.economy; + +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.db.DbComparisonType; +import me.yuri.yuriapi.api.db.DbQueryResult; +import me.yuri.yuriapi.api.event.EventManager; +import me.yuri.yuriapi.api.event.player.PlayerFundsChangeEvent; +import me.yuri.yuriapi.api.utils.configuration.ConfigVar; +import me.yuri.yuriapi.utils.DbManager; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; + +import java.time.Instant; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.FutureTask; + +public class EconomyManager { + + private static final EconomyManager inst = new EconomyManager(); + private static final Map fundTable = new ConcurrentHashMap<>(); + @ConfigVar("currencySymbol") + private static String currencySymbol; + @ConfigVar("currencyName") + private static String currencyName; + + private EconomyManager() { + } + + public static EconomyManager getInstance() { + return inst; + } + + public static String getCurrencySymbol() { + return currencySymbol; + } + + public static String getCurrencyName() { + return currencyName; + } + + public static int getFunds(YPlayer p) { + int i = 0; + if (!fundTable.containsKey(p.getBasePlayer())) + fundTable.put(p.getBasePlayer(), i); + else i = fundTable.get(p.getBasePlayer()); + return i; + } + + public static void addFunds(YPlayer p, int amount) { + int i = getFunds(p); + setFunds(p, i + amount); + } + + public static boolean subtractFunds(YPlayer p, int amount) { + int i = getFunds(p) - amount; + if (i < 0) return false; + setFunds(p, i); + return true; + } + + public static void setFunds(YPlayer p, int amount) { + fundTable.put(p.getBasePlayer(), amount); + EventManager.executeEvent(new PlayerFundsChangeEvent(p, fundTable.getOrDefault(p.getBasePlayer(), 0), amount)); + } + + public static void saveChanges() { + for (Map.Entry e : fundTable.entrySet()) { + DbManager.z_().getTable("funds") + .createInsertQuery() + .setColumn(0, e.getKey().getUniqueId()) + .setColumn(1, e.getValue()).setColumn(2, Instant.now().toEpochMilli()) + .build().execute(); + System.out.println("SAVING: " + e.getKey().getUniqueId() + ":" + e.getKey().getName()); + } + } + + public static void saveFor(YPlayer p) { + DbManager.z_().getTable("funds") + .createInsertQuery() + .setColumn(0, p.getBasePlayer().getUniqueId()) + .setColumn(1, p.getFunds()) + .setColumn(2, Instant.now().toEpochMilli()) + .build().execute(); + System.out.println("Saved for: " + p.getBasePlayer().getName() + ":" + p.getFunds()); + } + + public static void loadFor(YPlayer p) { + DbQueryResult r = DbManager.z_().getTable("funds") + .createSelectQuery().columns("funds") + .where(w -> w.forColumn("uuid").value(DbComparisonType.EQUALS, p.getBasePlayer().getUniqueId()).end()) + .build().execute(); + + if (r.next()) + fundTable.put(p.getBasePlayer(), (int) r.get(0)); + + r.close(); + System.out.println("loaded for: " + p.getBasePlayer().getName() + ":" + p.getFunds()); + } + + public static FutureTask loadFromDbAsync() { + return new FutureTask<>(() -> { + DbQueryResult r = DbManager.z_().getTable("funds").createSelectQuery().all().build().execute(); + + while (r.next()) { + fundTable.put(Bukkit.getOfflinePlayer((UUID) r.get(0)), (int) r.get(1)); + System.out.println(r.get(0) + ":" + r.get(1) + " > " + Bukkit.getOfflinePlayer((UUID) r.get(0)).getName()); + } + + r.close(); + + return true; + }); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/Cancellable.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/Cancellable.java new file mode 100755 index 0000000..b1d20d8 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/Cancellable.java @@ -0,0 +1,7 @@ +package me.yuri.yuriapi.api.event; + +public interface Cancellable { + boolean isCancelled(); + + void setCancelled(boolean cancel); +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/Event.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/Event.java new file mode 100755 index 0000000..6628db7 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/Event.java @@ -0,0 +1,20 @@ +package me.yuri.yuriapi.api.event; + +public class Event { + public enum Priority { + + HIGHEST(4), HIGH(3), NORMAL(2), LOW(1), LOWEST(0); + + private final int priority; + + Priority(int i) { + priority = i; + } + + public int getPriority() { + return priority; + } + } + + +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/EventListener.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/EventListener.java new file mode 100755 index 0000000..77306f9 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/EventListener.java @@ -0,0 +1,7 @@ +package me.yuri.yuriapi.api.event; + +/** + * Base interface that must be implemented in any class with EventSubscriber annotations + */ +public interface EventListener { +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/EventManager.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/EventManager.java new file mode 100755 index 0000000..5722fbd --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/EventManager.java @@ -0,0 +1,158 @@ +package me.yuri.yuriapi.api.event; + +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.event.player.PlayerItemAttackEvent; +import me.yuri.yuriapi.api.event.player.PlayerItemUseEvent; +import me.yuri.yuriapi.api.reflectionless.Reflectionless; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.Plugin; + +import javax.annotation.Nullable; +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; + +public class EventManager implements Listener { + + private static final EventManager inst = new EventManager(); + private static final boolean isOn = true; + private static final Map, List> eventRegistrar = new ConcurrentHashMap<>(); + + private EventManager() { + } + + public static EventManager getInstance() { + return inst; + } + + /** + * This method registers an event listener + * + * @param plugin Main plugin class instance of the listener + * @param listener Listener class instance + * @author Yuri + */ + public static void registerEvent(Plugin plugin, EventListener listener) { + for (Method method : listener.getClass().getMethods()) { + if (method.isAnnotationPresent(EventSubscriber.class)) { + Map.Entry entry = new AbstractMap.SimpleEntry<>(plugin, listener); + List methods = eventRegistrar.getOrDefault(entry, new ArrayList<>()); + methods.add(method); + methods.sort(Comparator.comparingInt(m -> m.getAnnotation(EventSubscriber.class).value().getPriority())); + Collections.reverse(methods); + eventRegistrar.put(entry, methods); + } + } + + } + + /** + * This method unregisters all listeners registered with main plugin instance passed as argument. Main plugin class may be passed optionally. + * + * @param plugin Main plugin class instance of the listener + * @param listener Listener class instance + * @author Yuri + */ + public static void unregisterEvent(@Nullable Plugin plugin, EventListener listener) { + if (plugin != null) { + Map.Entry entry = new AbstractMap.SimpleEntry<>(plugin, listener); + if (eventRegistrar.containsKey(entry)) { + eventRegistrar.put(entry, new ArrayList<>()); + } + eventRegistrar.remove(entry); + } else { + Optional> opEntry = eventRegistrar.keySet().stream().filter(entry -> entry.getValue().equals(listener)).findFirst(); + + if (opEntry.isPresent()) { + Map.Entry entry = opEntry.get(); + + eventRegistrar.remove(entry); + } + } + } + + /** + * This method unregisters all listeners registered with main plugin instance passed as argument + * + * @param plugin Main plugin class instance + * @author Yuri + */ + public static void unregisterAllPluginEvents(Plugin plugin) { + eventRegistrar.keySet().stream().filter(entry -> entry.getKey().equals(plugin)).forEach(eventRegistrar::remove); + } + + /** + * This method unregisters an event listener passed as argument + * + * @param listener Listener class instance + * @author Yuri + */ + public static void unregisterEvent(EventListener listener) { + unregisterEvent(null, listener); + } + + public static Event executeEvent(Event event) { + FutureTask futureTask = new FutureTask<>(() -> call(event)); + + futureTask.run(); + + try { + return futureTask.get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + return event; + } + + private static Event call(Event event) { + if (isOn) { + for (Map.Entry entry : eventRegistrar.keySet()) { + List methods = eventRegistrar.get(entry); + + methods.stream() + .filter(method -> method.isAnnotationPresent(EventSubscriber.class) && method.getParameterTypes()[0] == event.getClass()) + .sorted(Comparator.comparingInt(method -> Event.Priority.HIGHEST.getPriority() - method.getAnnotation(EventSubscriber.class).value().getPriority())) + .forEachOrdered(method -> { + try { + Reflectionless.get(method).call(entry.getValue(), event); + } catch (Exception e) { + e.printStackTrace(); + } + }); + } + } + return event; + } + + @EventHandler + public void onEvent(org.bukkit.event.Event e) { + Bukkit.getConsoleSender().sendMessage("EVENT"); + if (e instanceof PlayerInteractEvent) { + PlayerInteractEvent ev = (PlayerInteractEvent) e; + if ((ev.getAction() == Action.RIGHT_CLICK_AIR || ev.getAction() == Action.LEFT_CLICK_AIR) && ev.hasItem()) { + executeEvent(new PlayerItemUseEvent(YPlayer.get(ev.getPlayer()), ev.getItem())); + return; + } + } else if (e instanceof EntityDamageByEntityEvent) { + EntityDamageByEntityEvent ev = (EntityDamageByEntityEvent) e; + if (ev instanceof Player) { + Player p = ((Player) ev); + ItemStack i = p.getInventory().getItemInMainHand(); + if (i.getType() != Material.AIR) { + executeEvent(new PlayerItemAttackEvent(YPlayer.get(p), i, ev.getEntity())); + } + } + } + } + +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/EventSubscriber.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/EventSubscriber.java new file mode 100755 index 0000000..a3d1982 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/EventSubscriber.java @@ -0,0 +1,12 @@ +package me.yuri.yuriapi.api.event; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface EventSubscriber { + Event.Priority value() default Event.Priority.NORMAL; +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/PacketEvent.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/PacketEvent.java new file mode 100644 index 0000000..b242f09 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/PacketEvent.java @@ -0,0 +1,45 @@ +package me.yuri.yuriapi.api.event; + +import org.bukkit.entity.Player; + +public abstract class PacketEvent extends Event implements Cancellable { + + private final Player player; + private final Object packetObject; + private final String type; + private final long timestamp; + + private boolean cancelled; + + public PacketEvent(Player p, Object packet, String type) { + player = p; + packetObject = p; + this.type = type; + timestamp = System.currentTimeMillis(); + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + public Object getPacketObject() { + return packetObject; + } + + public String getType() { + return type; + } + + public long getTimestamp() { + return timestamp; + } + + public Player getPlayer() { + return player; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/PacketIncomeEvent.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/PacketIncomeEvent.java new file mode 100755 index 0000000..e71f892 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/PacketIncomeEvent.java @@ -0,0 +1,9 @@ +package me.yuri.yuriapi.api.event; + +import org.bukkit.entity.Player; + +public class PacketIncomeEvent extends PacketEvent { + public PacketIncomeEvent(Player p, Object packet, String type) { + super(p, packet, type); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/PacketOutcomeEvent.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/PacketOutcomeEvent.java new file mode 100755 index 0000000..66d7e92 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/PacketOutcomeEvent.java @@ -0,0 +1,9 @@ +package me.yuri.yuriapi.api.event; + +import org.bukkit.entity.Player; + +public class PacketOutcomeEvent extends PacketEvent { + public PacketOutcomeEvent(Player p, Object packet, String type) { + super(p, packet, type); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/player/PlayerEvent.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/player/PlayerEvent.java new file mode 100644 index 0000000..442616e --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/player/PlayerEvent.java @@ -0,0 +1,17 @@ +package me.yuri.yuriapi.api.event.player; + +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.event.Event; + +public class PlayerEvent extends Event { + + private final YPlayer player; + + public PlayerEvent(YPlayer player) { + this.player = player; + } + + public YPlayer getPlayer() { + return player; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/player/PlayerFundsChangeEvent.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/player/PlayerFundsChangeEvent.java new file mode 100644 index 0000000..c49d8b2 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/player/PlayerFundsChangeEvent.java @@ -0,0 +1,23 @@ +package me.yuri.yuriapi.api.event.player; + +import me.yuri.yuriapi.api.YPlayer; + +public class PlayerFundsChangeEvent extends PlayerEvent { + + private final int init, after; + + public PlayerFundsChangeEvent(YPlayer player, int initial, int after) { + super(player); + this.init = initial; + this.after = after; + } + + public int getBefore() { + return init; + } + + public int getAfter() { + return after; + } + +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/player/PlayerItemAttackEvent.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/player/PlayerItemAttackEvent.java new file mode 100644 index 0000000..3fdbc4c --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/player/PlayerItemAttackEvent.java @@ -0,0 +1,18 @@ +package me.yuri.yuriapi.api.event.player; + +import me.yuri.yuriapi.api.YPlayer; +import org.bukkit.entity.Entity; +import org.bukkit.inventory.ItemStack; + +public class PlayerItemAttackEvent extends PlayerItemEvent { + private final Entity damaged; + + public PlayerItemAttackEvent(YPlayer player, ItemStack item, Entity damaged) { + super(player, item); + this.damaged = damaged; + } + + public Entity getAtackedEntity() { + return damaged; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/player/PlayerItemEvent.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/player/PlayerItemEvent.java new file mode 100644 index 0000000..9864921 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/player/PlayerItemEvent.java @@ -0,0 +1,35 @@ +package me.yuri.yuriapi.api.event.player; + +import me.yuri.yuriapi.Desu; +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.item.CustomItem; +import me.yuri.yuriapi.api.item.ItemRegistry; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataType; + +public class PlayerItemEvent extends PlayerEvent { + private final ItemStack item; + private final CustomItem ci; + + public PlayerItemEvent(YPlayer player, ItemStack is) { + super(player); + this.item = is; + if (is.hasItemMeta()) { + assert is.getItemMeta() != null; + String s = is.getItemMeta().getPersistentDataContainer().getOrDefault(Desu.getKey(0), PersistentDataType.STRING, "null"); + ci = ItemRegistry.getItem(s); + } else ci = null; + } + + public ItemStack getItem() { + return item; + } + + public boolean isCustom() { + return ci != null; + } + + public CustomItem getCustomItem() { + return ci; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/player/PlayerItemUseEvent.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/player/PlayerItemUseEvent.java new file mode 100644 index 0000000..d98b4e6 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/event/player/PlayerItemUseEvent.java @@ -0,0 +1,11 @@ +package me.yuri.yuriapi.api.event.player; + +import me.yuri.yuriapi.api.YPlayer; +import org.bukkit.inventory.ItemStack; + +public class PlayerItemUseEvent extends PlayerItemEvent { + + public PlayerItemUseEvent(YPlayer player, ItemStack item) { + super(player, item); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/inventory/ButtonClickEvent.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/inventory/ButtonClickEvent.java new file mode 100644 index 0000000..a6db028 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/inventory/ButtonClickEvent.java @@ -0,0 +1,49 @@ +package me.yuri.yuriapi.api.inventory; + +import me.yuri.yuriapi.api.YPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.ItemStack; + +public class ButtonClickEvent { + private final InventoryClickEvent event; + private final CustomInventory inv; + private final int slot; + private final YPlayer player; + private boolean canc = false; + + public ButtonClickEvent(InventoryClickEvent e, CustomInventory i, int slot) { + this.inv = i; + this.slot = slot; + this.event = e; + this.player = YPlayer.get((Player) e.getWhoClicked()); + } + + public InventoryClickEvent getEvent() { + return event; + } + + public CustomInventory getInventory() { + return inv; + } + + public int getSlot() { + return slot; + } + + public ItemStack getItemstack() { + return inv.getAt(slot); + } + + public YPlayer getPlayer() { + return player; + } + + public void cancelClickSound(boolean cancel) { + canc = cancel; + } + + public boolean isClickSoundCancelled() { + return canc; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/inventory/CustomInventory.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/inventory/CustomInventory.java new file mode 100644 index 0000000..776cdb1 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/inventory/CustomInventory.java @@ -0,0 +1,171 @@ +package me.yuri.yuriapi.api.inventory; + +import me.yuri.yuriapi.api.item.CustomItem; +import me.yuri.yuriapi.api.utils.Colored; +import org.bukkit.Bukkit; +import org.bukkit.Sound; +import org.bukkit.entity.HumanEntity; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.inventory.InventoryDragEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.*; +import java.util.function.Consumer; + +public class CustomInventory implements Cloneable { + protected static List opened = new ArrayList<>(); + protected final Consumer onclose; + private final Inventory inventory; + private final boolean readonly; + private final List> clickEvents = new ArrayList<>(); + private final List> dragEvents = new ArrayList<>(); + private final Map> buttons = new HashMap<>(); + private final Sound clicc; + + public CustomInventory(Inventory i, boolean readonly) { + this(i, Collections.emptyList(), Collections.emptyList(), readonly, Collections.emptyMap(), null, null); + } + + public CustomInventory(Inventory i, @Nonnull List> c, @Nonnull List> d, boolean readonly, @Nonnull Map> btn, @Nullable Sound clicksound, @Nullable Consumer close) { + this.inventory = i; + this.readonly = readonly; + clickEvents.addAll(c); + dragEvents.addAll(d); + buttons.putAll(btn); + opened.add(this); + clicc = clicksound; + onclose = close; + } + + @Nullable + public static CustomInventory get(Inventory i) { + for (CustomInventory c : opened) { + if (c.inventory.equals(i)) + return c; + } + return null; + } + + public Inventory getBaseInventory() { + return inventory; + } + + public boolean isReadonly() { + return readonly; + } + + public List> getClickEvents() { + return clickEvents; + } + + public List> getDragEvents() { + return dragEvents; + } + + public Map> getButtonMap() { + return buttons; + } + + public void setItem(int pos, ItemStack it) { + this.inventory.setItem(pos, it); + } + + public void setItem(int pos, CustomItem it) { + this.inventory.setItem(pos, it.getItemstack()); + } + + public void removeItem(int pos) { + this.inventory.setItem(pos, null); + } + + public void rename(int pos, String name) { + rename(pos, '&', name); + } + + public void rename(int pos, char colorCode, String name) { + ItemStack i = inventory.getItem(pos); + if (i == null) return; + ItemMeta im = i.hasItemMeta() ? i.getItemMeta() : Bukkit.getItemFactory().getItemMeta(i.getType()); + assert im != null; + im.setDisplayName(Colored.colorize(colorCode, name)); + i.setItemMeta(im); + inventory.setItem(pos, i); + } + + public void changeLore(int pos, List lore) { + ItemStack i = inventory.getItem(pos); + if (i == null) return; + ItemMeta im = i.hasItemMeta() ? i.getItemMeta() : Bukkit.getItemFactory().getItemMeta(i.getType()); + assert im != null; + im.setLore(lore); + i.setItemMeta(im); + inventory.setItem(pos, i); + } + + public void insertToLore(int pos, int startIndex, char colorCode, String... lore) { + ItemStack i = inventory.getItem(pos); + + if (i == null) return; + + ItemMeta im = i.hasItemMeta() ? i.getItemMeta() : Bukkit.getItemFactory().getItemMeta(i.getType()); + assert im != null; + + List lr = Arrays.asList(lore); + lr.forEach(c -> Colored.colorize(colorCode, lore)); + + if (im.hasLore()) + Objects.requireNonNull(im.getLore()).addAll(startIndex, lr); + else im.setLore(lr); + + i.setItemMeta(im); + inventory.setItem(pos, i); + } + + public void replaceLoreAt(int pos, int startIndex, String... lore) { + replaceLoreAt(pos, startIndex, '&', lore); + } + + public void replaceLoreAt(int pos, int startIndex, char colorCode, String... lore) { + ItemStack i = inventory.getItem(pos); + + if (i == null) return; + + ItemMeta im = i.hasItemMeta() ? i.getItemMeta() : Bukkit.getItemFactory().getItemMeta(i.getType()); + assert im != null; + + List lr = Arrays.asList(lore); + lr.forEach(c -> Colored.colorize(colorCode, lore)); + + if (im.hasLore()) { + assert im.getLore() != null; + for (int ii = 0; ii < lr.size(); ii++) { + im.getLore().set(ii + startIndex, lr.get(ii)); + } + } + + + i.setItemMeta(im); + inventory.setItem(pos, i); + } + + public void insertToLore(int pos, int startIndex, String... lore) { + insertToLore(pos, startIndex, '&', lore); + } + + public void open(HumanEntity e) { + e.openInventory(this.inventory); + } + + public ItemStack getAt(int pos) { + return inventory.getItem(pos); + } + + public Sound getClickSound() { + return clicc; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/inventory/CustomItemSupplier.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/inventory/CustomItemSupplier.java new file mode 100644 index 0000000..eb3a957 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/inventory/CustomItemSupplier.java @@ -0,0 +1,8 @@ +package me.yuri.yuriapi.api.inventory; + +import me.yuri.yuriapi.api.item.CustomItem; + +@FunctionalInterface +public interface CustomItemSupplier { + CustomItem create(); +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/inventory/InventoryBuilder.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/inventory/InventoryBuilder.java new file mode 100644 index 0000000..566974a --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/inventory/InventoryBuilder.java @@ -0,0 +1,350 @@ +package me.yuri.yuriapi.api.inventory; + +import me.yuri.yuriapi.api.item.CustomItem; +import me.yuri.yuriapi.api.utils.Colored; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.inventory.InventoryDragEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; + +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +public class InventoryBuilder { + + private final int size; + private final InventoryType type; + private final Map items = new HashMap<>(); + private final int[][] coords; + private final List> clickEvents = new ArrayList<>(); + private final List> dragEvents = new ArrayList<>(); + private final Map> buttons = new HashMap<>(); + private Consumer oncloseEvent = null; + private String title = null; + private InventoryHolder owner; + private boolean readonly = false; + private Sound clickSound = null; + + public InventoryBuilder(@Nonnull InventoryType type) { + this.type = type; + size = type.getDefaultSize(); + coords = new int[size / 9][9]; + for (int i = 0; i < size / 9; i++) { + for (int a = 0; a < 9; a++) { + coords[i][a] = i * 9 + a; + } + } + } + + public InventoryBuilder(@Nonnegative int size) { + this.type = null; + this.size = size; + coords = new int[size / 9][9]; + for (int i = 0; i < size / 9; i++) { + for (int a = 0; a < 9; a++) { + coords[i][a] = i * 9 + a; + } + } + } + + public InventoryBuilder() { + this(InventoryType.CHEST); + } + + @Nonnull + public int[][] getCoordinates() { + return coords; + } + + public int getPos(int x, int y) { + return coords[y][x]; + } + + @Nonnull + public InventoryBuilder withTitle(@Nullable String t, char colorCode) { + title = Colored.colorize(colorCode, t); + return this; + } + + @Nonnull + public InventoryBuilder withTitle(@Nullable String t) { + title = Colored.colorize(t); + //System.out.printf("Title: %s\n", title); + return this; + } + + @Nonnull + public InventoryBuilder withOwner(@Nullable InventoryHolder owner) { + this.owner = owner; + return this; + } + + @Nonnull + public InventoryBuilder withClickEvent(@Nonnull Consumer c) { + this.clickEvents.add(c); + return this; + } + + @Nonnull + public InventoryBuilder withDragEvent(@Nonnull Consumer c) { + this.dragEvents.add(c); + return this; + } + + @Nonnull + public InventoryBuilder withItem(ItemStack i) { + return withItem(i, getLowestUnoccupiedSlot()); + } + + @Nonnull + public InventoryBuilder withItem(CustomItem i, @Nonnegative int position) { + items.put(position, i); + return this; + } + + @Nonnull + public InventoryBuilder withItem(CustomItem i) { + return withItem(i, getLowestUnoccupiedSlot()); + } + + @Nonnull + public InventoryBuilder withItem(CustomItem i, @Nonnegative int x, @Nonnegative int y) { + return withItem(i, coords[y][x]); + } + + @Nonnull + public InventoryBuilder withItem(ItemStack i, @Nonnegative int x, @Nonnegative int y) { + return withItem(i, coords[y][x]); + } + + @Nonnull + public InventoryBuilder withItem(ItemStack i, @Nonnegative int position) { + items.put(position, i); + return this; + } + + @Nonnull + public InventoryBuilder fillItem(ItemStack item, @Nonnegative int start, @Nonnegative int end) { + if (start > end) + throw new IllegalArgumentException("Parameter 'start' is larger than 'end'."); + + for (int i = start; i < end; i++) { + items.put(i, item); + } + return this; + } + + @Nonnull + public InventoryBuilder fillItem(CustomItem item, @Nonnegative int start, @Nonnegative int end) { + if (start > end) + throw new IllegalArgumentException("Parameter 'start' is larger than 'end'."); + + for (int i = start; i < end; i++) { + items.put(i, item); + } + return this; + } + + @Nonnull + public InventoryBuilder fillItem(Material m, @Nonnegative int start, @Nonnegative int end) { + if (start > end) + throw new IllegalArgumentException("Parameter 'start' is larger than 'end'."); + + for (int i = start; i < end; i++) { + items.put(i, new ItemStack(m)); + } + return this; + } + + @Nonnull + public InventoryBuilder fillItem(ItemStackSupplier s, @Nonnegative int start, @Nonnegative int end) { + if (start > end) + throw new IllegalArgumentException("Parameter 'start' is larger than 'end'."); + + for (int i = start; i < end; i++) { + items.put(i, s.create()); + } + return this; + } + + @Nonnull + public InventoryBuilder fillItem(CustomItemSupplier s, @Nonnegative int start, @Nonnegative int end) { + if (start > end) + throw new IllegalArgumentException("Parameter 'start' is larger than 'end'."); + + for (int i = start; i < end; i++) { + items.put(i, s.create()); + } + return this; + } + + @Nonnull + public InventoryBuilder line(@Nonnegative int startX, @Nonnegative int startY, @Nonnegative int endX, @Nonnegative int endY, @Nonnull ItemStack s) { + --endX; + --endY; + + float deltaX = endX - startX, deltaY = endY - startY; + if (Math.round(deltaX) == 0) { + for (int i = startY; i <= endY; i++) { + items.put(coords[i][startX], s); + } + } else { + float a = deltaY / deltaX; + for (float xx = startX, yy = startY; xx <= endX; xx++) { + items.put(coords[Math.round(yy)][Math.round(xx)], s); + yy += a; + } + } + return this; + } + + @Nonnull + public InventoryBuilder line(@Nonnegative int startX, @Nonnegative int startY, @Nonnegative int endX, @Nonnegative int endY, @Nonnull ItemStackSupplier s) { + return line(startX, startY, endX, endY, s.create()); + } + + @Nonnull + public InventoryBuilder line(@Nonnegative int startX, @Nonnegative int startY, @Nonnegative int endX, @Nonnegative int endY, @Nonnull Material m) { + return line(startX, startY, endX, endY, new ItemStack(m)); + } + + @Nonnull + public InventoryBuilder applyItems(Map items) { + this.items.putAll(items); + return this; + } + + @Nonnull + public InventoryBuilder applyItems(Consumer> c) { + c.accept(items); + return this; + } + + @Nonnull + private Inventory createInv() { + if (type != null) { + if (title != null) + return Bukkit.createInventory(owner, type, title); + else + return Bukkit.createInventory(owner, type); + } else { + if (title != null) + return Bukkit.createInventory(owner, size, title); + else + return Bukkit.createInventory(owner, size); + } + } + + @Nonnegative + public int getLowestUnoccupiedSlot() { + int a = 0; + for (int b : this.items.keySet()) { + if (a != b) + break; + ++a; + } + return a; + } + + @Nonnull + public InventoryBuilder readOnly() { + this.readonly = true; + return this; + } + + @Nonnull + public InventoryBuilder preventDrag() { + this.dragEvents.add((e) -> e.setCancelled(true)); + return this; + } + + @Nonnull + public InventoryBuilder addButton(ItemStack i, Consumer c) { + return addButton(i, getLowestUnoccupiedSlot(), c); + } + + @Nonnull + public InventoryBuilder addButton(ItemStackSupplier i, Consumer c) { + return addButton(i.create(), getLowestUnoccupiedSlot(), c); + } + + @Nonnull + public InventoryBuilder addButton(CustomItem i, @Nonnegative int position, Consumer c) { + items.put(position, i); + buttons.put(position, c); + return this; + } + + @Nonnull + public InventoryBuilder addButton(CustomItem i, Consumer c) { + return addButton(i, getLowestUnoccupiedSlot(), c); + } + + @Nonnull + public InventoryBuilder addButton(CustomItemSupplier i, Consumer c) { + return addButton(i.create(), getLowestUnoccupiedSlot(), c); + } + + @Nonnull + public InventoryBuilder addButton(CustomItem i, @Nonnegative int x, @Nonnegative int y, Consumer c) { + return addButton(i, coords[y][x], c); + } + + @Nonnull + public InventoryBuilder addButton(ItemStack i, @Nonnegative int x, @Nonnegative int y, Consumer c) { + return addButton(i, coords[y][x], c); + } + + @Nonnull + public InventoryBuilder addButton(ItemStack i, @Nonnegative int position, Consumer c) { + items.put(position, i); + buttons.put(position, c); + return this; + } + + @Nonnull + public InventoryBuilder withClickSound(@Nullable Sound s) { + this.clickSound = s; + return this; + } + + @Nonnull + public InventoryBuilder onClose(@Nullable Consumer e) { + this.oncloseEvent = e; + return this; + } + + @Nonnull + public CustomInventory build() { + Inventory i = createInv(); + for (Map.Entry ent : items.entrySet()) { + + Object item = ent.getValue(); + if (ent.getValue() instanceof CustomItem) { + item = ((CustomItem) item).getItemstack(); + } + + //System.out.printf("Pos: %d, %s\n", ent.getKey(), ((ItemStack) item).getType().name()); + + i.setItem(ent.getKey(), (ItemStack) item); + } + return new CustomInventory(i, this.clickEvents, this.dragEvents, readonly, buttons, clickSound, oncloseEvent); + } + + @Nonnull + public Map getItems() { + return items; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/inventory/InventoryEvents.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/inventory/InventoryEvents.java new file mode 100644 index 0000000..ebe5e6a --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/inventory/InventoryEvents.java @@ -0,0 +1,55 @@ +package me.yuri.yuriapi.api.inventory; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.inventory.InventoryDragEvent; + +import java.util.function.Consumer; + +public class InventoryEvents implements Listener { + private static final InventoryEvents inst = new InventoryEvents(); + + private InventoryEvents() { + } + + public static InventoryEvents instance() { + return inst; + } + + @EventHandler + public void onClick(InventoryClickEvent e) { + CustomInventory ci = CustomInventory.get(e.getInventory()); + if (ci == null) return; + + Consumer c = ci.getButtonMap().getOrDefault(e.getSlot(), null); + if (c != null) { + e.setCancelled(true); + ButtonClickEvent evt = new ButtonClickEvent(e, ci, e.getSlot()); + c.accept(evt); + if (!evt.isClickSoundCancelled()) + e.getWhoClicked().getWorld().playSound(e.getWhoClicked().getLocation(), ci.getClickSound(), 1, 1); + } + + if (ci.isReadonly()) e.setCancelled(true); + } + + @EventHandler + public void onDrag(InventoryDragEvent e) { + CustomInventory ci = CustomInventory.get(e.getInventory()); + if (ci == null) return; + ci.getDragEvents().forEach(c -> c.accept(e)); + if (ci.isReadonly()) e.setCancelled(true); + } + + @EventHandler + public void onClose(InventoryCloseEvent e) { + CustomInventory ci = CustomInventory.get(e.getInventory()); + if (ci == null) return; + if (ci.onclose != null) + ci.onclose.accept(e); + + CustomInventory.opened.removeIf(c -> c.getBaseInventory().equals(e.getInventory()) && c.getBaseInventory().getViewers().isEmpty()); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/inventory/ItemStackSupplier.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/inventory/ItemStackSupplier.java new file mode 100644 index 0000000..44e78d5 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/inventory/ItemStackSupplier.java @@ -0,0 +1,8 @@ +package me.yuri.yuriapi.api.inventory; + +import org.bukkit.inventory.ItemStack; + +@FunctionalInterface +public interface ItemStackSupplier { + ItemStack create(); +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/item/CustomItem.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/item/CustomItem.java new file mode 100644 index 0000000..6103c41 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/item/CustomItem.java @@ -0,0 +1,93 @@ +package me.yuri.yuriapi.api.item; + +import me.yuri.yuriapi.Desu; +import me.yuri.yuriapi.api.utils.metadata.KeyFactory; +import org.bukkit.NamespacedKey; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.plugin.java.JavaPlugin; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public class CustomItem implements Cloneable { + private final ItemStack item; + private final NamespacedKey key; + private final List> useEvents; + private final List> attackEvents; + private final List> placeEvents; + + public CustomItem(ItemStack i, NamespacedKey key) { + item = i; + this.key = key; + this.useEvents = new ArrayList<>(); + this.attackEvents = new ArrayList<>(); + this.placeEvents = new ArrayList<>(); + } + + public CustomItem(ItemStack i, JavaPlugin pl, String key) { + this(i, KeyFactory.getKeyFor(pl, key)); + } + + @Nonnull + public List> getUseEvents() { + return useEvents; + } + + @Nonnull + public List> getAttackEvents() { + return attackEvents; + } + + @Nonnull + public List> getPlaceEvents() { + return placeEvents; + } + + public void addUseEvent(Consumer e) { + this.useEvents.add(e); + } + + public void addAttackEvent(Consumer e) { + this.attackEvents.add(e); + } + + public void addPlaceEvent(Consumer e) { + this.placeEvents.add(e); + } + + @Nonnull + public ItemStack getItemstack() { + return item; + } + + @Nonnull + public NamespacedKey getKey() { + return key; + } + + @Nonnull + public CustomItem clone() { + try { + return (CustomItem) super.clone(); + } catch (CloneNotSupportedException e) { + return this; + } + } + + @Nullable + public CustomItem from(ItemStack i) { + if (i.hasItemMeta()) { + assert i.getItemMeta() != null; + String s = i.getItemMeta().getPersistentDataContainer().getOrDefault(Desu.getKey(0), PersistentDataType.STRING, "null"); + if (s.equals("null")) return null; + return ItemRegistry.getItem(s); + } + return null; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/item/ItemBlockPlacedEvent.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/item/ItemBlockPlacedEvent.java new file mode 100644 index 0000000..12fda70 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/item/ItemBlockPlacedEvent.java @@ -0,0 +1,25 @@ +package me.yuri.yuriapi.api.item; + +import me.yuri.yuriapi.api.utils.metadata.BlockMetaStorage; +import me.yuri.yuriapi.api.utils.metadata.MetadataType; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.plugin.java.JavaPlugin; + +public class ItemBlockPlacedEvent { + + private final BlockPlaceEvent event; + + public ItemBlockPlacedEvent(BlockPlaceEvent e) { + event = e; + } + + public BlockPlaceEvent getBaseEvent() { + return event; + } + + public void applyMetadata(JavaPlugin pl, String key, MetadataType t, V data) { + BlockMetaStorage.setMeta(event.getBlock(), pl, key, t, data); + } + + +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/item/ItemBuilder.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/item/ItemBuilder.java new file mode 100644 index 0000000..7038b2e --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/item/ItemBuilder.java @@ -0,0 +1,250 @@ +package me.yuri.yuriapi.api.item; + +import me.yuri.yuriapi.Desu; +import me.yuri.yuriapi.api.utils.Colored; +import me.yuri.yuriapi.api.utils.metadata.KeyFactory; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Recipe; +import org.bukkit.inventory.ShapedRecipe; +import org.bukkit.inventory.ShapelessRecipe; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.plugin.java.JavaPlugin; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Function; + +public class ItemBuilder { + + private final CustomItem item; + private final Material type; + private final List recipes = new ArrayList<>(); + private final JavaPlugin plugin; + private ItemMeta meta; + private boolean register = false; + private boolean recipeRegister = false; + private boolean isMetaDone = false; + + public ItemBuilder(Material type, @Nonnull NamespacedKey key, JavaPlugin pl) { + if (type == Material.AIR) + throw new IllegalArgumentException("Item cannot be AIR"); + + if (ItemRegistry.getFor((JavaPlugin) Objects.requireNonNull(Bukkit.getPluginManager().getPlugin(key.getNamespace()))).getItems().stream().anyMatch(i -> i.getKey().equals(key))) { + throw new IllegalStateException("Item with such key already exists."); + } + + this.plugin = pl; + this.type = type; + item = new CustomItem(new ItemStack(type), key); + meta = item.getItemstack().hasItemMeta() ? item.getItemstack().getItemMeta() : Bukkit.getItemFactory().getItemMeta(item.getItemstack().getType()); + } + + public ItemBuilder(Material type, @Nonnull JavaPlugin pl, @Nonnull String name) { + if (type == Material.AIR) + throw new IllegalArgumentException("Item cannot be AIR"); + NamespacedKey key = KeyFactory.getKeyFor(pl, name); + + if (ItemRegistry.getFor(pl).getItems().stream().anyMatch(i -> i.getKey().equals(key))) { + throw new IllegalStateException("Item with such key already exists."); + } + + this.plugin = pl; + this.type = type; + item = new CustomItem(new ItemStack(type), key); + meta = item.getItemstack().hasItemMeta() ? item.getItemstack().getItemMeta() : Bukkit.getItemFactory().getItemMeta(item.getItemstack().getType()); + } + + public static ItemStack createNameless(Material m) { + return new ItemBuilder(m, Desu.getMain(), "null").withCustomName(" ").build().getItemstack(); + } + + public static ItemStack createWithName(Material m, char colorCode, String name) { + return new ItemBuilder(m, Desu.getMain(), "null").withCustomName(name, colorCode).buildMeta().build().getItemstack(); + } + + public static ItemStack createWithName(Material m, String name) { + return createWithName(m, '&', name); + } + + @Nonnull + public CustomItem build() { + if (!isMetaDone) + item.getItemstack().setItemMeta(meta); + + if (recipeRegister) + recipes.forEach(Bukkit::addRecipe); + + if (register) + ItemRegistry.getFor(plugin).registerItem(item); + return item; + } + + @Nonnull + public ItemBuilder registerOnBuild() { + register = true; + return this; + } + + @Nonnull + public ItemBuilder registerRecipes() { + recipeRegister = true; + return this; + } + + @Nonnull + public ItemBuilder withCount(int count) { + item.getItemstack().setAmount(count); + return this; + } + + @Nonnull + public ItemBuilder withEnchantment(@Nonnull Enchantment enchantment, int level) { + item.getItemstack().addUnsafeEnchantment(enchantment, level); + return this; + } + + @Nonnull + public ItemBuilder withCustomName(@Nullable String name) { + return withCustomName(name, '&'); + } + + @Nonnull + public ItemBuilder withCustomName(@Nullable String name, char colorCode) { + meta.setDisplayName(Colored.colorize(colorCode, name)); + return this; + } + + @Nonnull + public ItemBuilder appendLore(@Nullable String name) { + return appendLore(name, '&'); + } + + @Nonnull + public ItemBuilder appendLore(@Nullable String name, char colorCode) { + if (!meta.hasLore()) + meta.setLore(Collections.singletonList(Colored.colorize(colorCode, name))); + else { + List lore = meta.getLore(); + assert lore != null; + lore.add(Colored.colorize(colorCode, name)); + meta.setLore(lore); + } + return this; + } + + @Nonnull + public ItemBuilder withData(@Nonnull String key, @Nonnull PersistentDataType type, Z data) { + return withData(KeyFactory.getKeyFor(plugin, key), type, data); + } + + @Nonnull + public ItemBuilder withData(@Nonnull NamespacedKey key, @Nonnull PersistentDataType type, Z data) { + meta.getPersistentDataContainer().set(key, type, data); + return this; + } + + @Nonnull + public ItemBuilder withRecipe(@Nonnull Recipe r) { + recipes.add(r); + return this; + } + + @Nonnull + public ItemBuilder buildMeta() { + meta.getPersistentDataContainer().set(Desu.getKey(0), PersistentDataType.STRING, this.item.getKey().toString()); + item.getItemstack().setItemMeta(meta); + isMetaDone = true; + return this; + } + + @Nonnull + public ItemBuilder withShapedRecipe(@Nonnull String row1, @Nonnull String row2, @Nonnull String row3, @Nonnull Map ingredients) { + ShapedRecipe sp = new ShapedRecipe(item.getKey(), item.getItemstack()); + sp.shape(row1, row2, row3); + ingredients.forEach(sp::setIngredient); + return withRecipe(sp); + } + + @Nonnull + public ItemBuilder withShapedRecipe(@Nonnull String row1, @Nonnull String row2, @Nonnull String row3, @Nonnull char[] chars, @Nonnull Material[] materials) { + if (chars.length != materials.length) { + throw new IllegalArgumentException("chars and materials must have equal lengths"); + } + + ShapedRecipe sp = new ShapedRecipe(item.getKey(), item.getItemstack()); + sp.shape(row1, row2, row3); + + for (int i = 0; i < chars.length; i++) { + sp.setIngredient(chars[i], materials[i]); + } + + return withRecipe(sp); + } + + @Nonnull + public ItemBuilder withShapelessRecipe(@Nonnull Map ingredients) { + ShapelessRecipe sl = new ShapelessRecipe(item.getKey(), item.getItemstack()); + ingredients.forEach((m, i) -> sl.addIngredient(i, m)); + return withRecipe(sl); + } + + @Nonnull + public ItemBuilder withShapelessRecipe(@Nonnull int[] counts, @Nonnull Material[] materials) { + if (counts.length != materials.length) { + throw new IllegalArgumentException("counts and materials must have equal lengths"); + } + ShapelessRecipe sl = new ShapelessRecipe(item.getKey(), item.getItemstack()); + for (int i = 0; i < counts.length; i++) { + sl.addIngredient(counts[i], materials[i]); + } + return withRecipe(sl); + } + + @Nonnull + public ItemBuilder onUse(Consumer e) { + this.item.addUseEvent(e); + return this; + } + + @Nonnull + public ItemBuilder onAttack(Consumer e) { + this.item.addAttackEvent(e); + return this; + } + + @Nonnull + public ItemBuilder onPlace(Consumer e) { + this.item.addPlaceEvent(e); + return this; + } + + @Nonnull + public ItemBuilder modifyItemMeta(Function f) { + meta = f.apply(meta); + return this; + } + + @Nonnull + public Material getType() { + return type; + } + + @Nonnull + public ItemMeta getMeta() { + return meta; + } + + @Nonnull + public List getRecipes() { + return recipes; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/item/ItemEvents.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/item/ItemEvents.java new file mode 100644 index 0000000..c7d1bb4 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/item/ItemEvents.java @@ -0,0 +1,65 @@ +package me.yuri.yuriapi.api.item; + +import me.yuri.yuriapi.Desu; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataType; + +public final class ItemEvents implements Listener { + + private static final ItemEvents inst = new ItemEvents(); + + private ItemEvents() { + } + + public static ItemEvents instance() { + return inst; + } + + @EventHandler + public static void onItemAttack(EntityDamageByEntityEvent e) { + if (e.getDamager() instanceof Player) { + ItemStack is = ((Player) e.getDamager()).getInventory().getItemInMainHand(); + if (is.hasItemMeta()) { + assert is.getItemMeta() != null; + String s = is.getItemMeta().getPersistentDataContainer().getOrDefault(Desu.getKey(0), PersistentDataType.STRING, "null"); + CustomItem ci = ItemRegistry.getItem(s); + if (ci != null) { + ci.getAttackEvents().forEach(ev -> ev.accept(e)); + } + } + } + } + + @EventHandler + public static void onItemUse(PlayerInteractEvent e) { + if (e.getItem() != null && (e.getAction() != Action.PHYSICAL)) { + if (e.getItem().hasItemMeta()) { + assert e.getItem().getItemMeta() != null; + String s = e.getItem().getItemMeta().getPersistentDataContainer().getOrDefault(Desu.getKey(0), PersistentDataType.STRING, "null"); + CustomItem ci = ItemRegistry.getItem(s); + if (ci != null) + ci.getUseEvents().forEach(ev -> ev.accept(e)); + } + } + } + + @EventHandler + public static void onItemPlace(BlockPlaceEvent e) { + if (e.getItemInHand().hasItemMeta()) { + assert e.getItemInHand().getItemMeta() != null; + String s = e.getItemInHand().getItemMeta().getPersistentDataContainer().getOrDefault(Desu.getKey(0), PersistentDataType.STRING, "null"); + CustomItem ci = ItemRegistry.getItem(s); + if (ci != null) { + ItemBlockPlacedEvent ev = new ItemBlockPlacedEvent(e); + ci.getPlaceEvents().forEach(event -> event.accept(ev)); + } + } + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/item/ItemRegistry.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/item/ItemRegistry.java new file mode 100644 index 0000000..b8c94d6 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/item/ItemRegistry.java @@ -0,0 +1,85 @@ +package me.yuri.yuriapi.api.item; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.java.JavaPlugin; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public final class ItemRegistry { + + private static final Map plugins = new HashMap<>(); + private final List items = new ArrayList<>(); + private final JavaPlugin plugin; + + private ItemRegistry(JavaPlugin pl) { + plugin = pl; + } + + @Nonnull + public static ItemRegistry getFor(@Nonnull JavaPlugin pl) { + ItemRegistry ir = plugins.getOrDefault(pl, null); + if (ir == null) { + ir = new ItemRegistry(pl); + plugins.put(pl, ir); + } + return ir; + } + + @Nonnull + public static List getAllItems() { + List cit = new ArrayList<>(); + plugins.values().forEach(v -> cit.addAll(v.getItems())); + return cit; + } + + @Nullable + public static CustomItem getItem(JavaPlugin pl, String name) { + for (CustomItem c : getFor(pl).items) { + if (c.getKey().getKey().equalsIgnoreCase(name)) + return c; + } + return null; + } + + public static boolean isCustom(ItemStack i) { + if (i == null) return false; + return getAllItems().stream().anyMatch(f -> f.getItemstack().isSimilar(i)); + } + + @Nullable + public static CustomItem getItem(String name) { + String[] s = name.split(":"); + if (s.length != 2) return null; + for (ItemRegistry r : plugins.values()) { + if (r.plugin.getName().equalsIgnoreCase(s[0])) { + for (CustomItem c : r.items) { + if (c.getKey().getKey().equalsIgnoreCase(s[1])) { + return c; + } + } + return null; + } + } + return null; + } + + @Nonnull + public JavaPlugin getPlugin() { + return plugin; + } + + public void registerItem(@Nonnull CustomItem item) { + items.add(item); + } + + @Nonnull + public List getItems() { + return items; + } + +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/nms/CBClasses.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/nms/CBClasses.java new file mode 100644 index 0000000..859677f --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/nms/CBClasses.java @@ -0,0 +1,4 @@ +package me.yuri.yuriapi.api.nms; + +public enum CBClasses { +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/nms/NMSClasses.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/nms/NMSClasses.java new file mode 100644 index 0000000..ac82359 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/nms/NMSClasses.java @@ -0,0 +1,5 @@ +package me.yuri.yuriapi.api.nms; + +public enum NMSClasses { + +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/nms/NMSUtil.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/nms/NMSUtil.java new file mode 100644 index 0000000..6b53fcc --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/nms/NMSUtil.java @@ -0,0 +1,47 @@ +package me.yuri.yuriapi.api.nms; + +import me.yuri.yuriapi.api.reflectionless.Reflectionless; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +public final class NMSUtil { + private static final String version = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3]; + private static final String pkg_nms = "net.minecraft.server." + version; + private static final String pkg_cb = "org.bukkit.craftbukkit." + version; + + private NMSUtil() { + } + + public static Object getPlayerHandle(Player p) { + try { + return Reflectionless.get(p.getClass().getMethod("getHandle")).call(p); + } catch (NoSuchMethodException e) { + throw new RuntimeException("???"); + } + } + + public static Class getNmsClass(String name) { + try { + return Class.forName(pkg_nms + '.' + name); + } catch (ClassNotFoundException ignored) { + throw new IllegalArgumentException("Invalid class."); + } + } + + public static Class getCbClass(String path) { + try { + System.out.println(pkg_cb + '.' + path); + return Class.forName(pkg_cb + '.' + path); + } catch (ClassNotFoundException ignored) { + throw new IllegalArgumentException("Invalid class."); + } + } + + public static String getCbPath() { + return pkg_cb; + } + + public static String getNmsPath() { + return pkg_nms; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/packet/PacketHandler.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/packet/PacketHandler.java new file mode 100644 index 0000000..ece9ea8 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/packet/PacketHandler.java @@ -0,0 +1,24 @@ +package me.yuri.yuriapi.api.packet; + +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; +import net.minecraft.server.v1_16_R3.PacketPlayInFlying; + +public class PacketHandler extends ChannelDuplexHandler { + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + super.channelRead(ctx, msg); + if (msg instanceof PacketPlayInFlying.PacketPlayInPosition || msg instanceof PacketPlayInFlying.PacketPlayInLook || msg instanceof PacketPlayInFlying.PacketPlayInPositionLook) + return; + //Bukkit.getConsoleSender().sendMessage("READ: \n" + msg.getClass().getName()); + } + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + super.write(ctx, msg, promise); + if (msg instanceof PacketPlayInFlying.PacketPlayInPosition || msg instanceof PacketPlayInFlying.PacketPlayInLook || msg instanceof PacketPlayInFlying.PacketPlayInPositionLook) + return; + //Bukkit.getConsoleSender().sendMessage("WRITE: \n"+msg.toString()); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/packet/PacketManager.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/packet/PacketManager.java new file mode 100644 index 0000000..a955675 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/packet/PacketManager.java @@ -0,0 +1,25 @@ +package me.yuri.yuriapi.api.packet; + +import me.yuri.yuriapi.api.nms.NMSUtil; +import me.yuri.yuriapi.api.reflectionless.Reflectionless; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +public class PacketManager { + + + public static void addPlayer(Player p) { + return; + /* + try { + Object cp = NMSUtil.getPlayerHandle(p); + Object conn = Reflectionless.get(cp.getClass().getField("b")).get(cp); + Object nmg = Reflectionless.get(conn.getClass().getField("a")).get(conn); + io.netty.channel.Channel c = (io.netty.channel.Channel) Reflectionless.get(nmg.getClass().getField("k")).get(nmg); + c.pipeline().addBefore("packet_handler", p.getName(), new PacketHandler()); + Bukkit.getConsoleSender().sendMessage("Added packet handler!"); + } catch (Exception e) { + e.printStackTrace(); + }*/ + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/permission/CustomPermissible.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/permission/CustomPermissible.java new file mode 100644 index 0000000..10fd838 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/permission/CustomPermissible.java @@ -0,0 +1,50 @@ +package me.yuri.yuriapi.api.permission; + +import me.yuri.yuriapi.api.YPlayer; +import org.bukkit.permissions.PermissibleBase; +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.ServerOperator; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Locale; + +public class CustomPermissible extends PermissibleBase { + + private final YPlayer bearer; + + public CustomPermissible(YPlayer pl, @Nullable ServerOperator opable) { + super(opable); + bearer = pl; + recalculatePermissions(); + pl.getBasePlayer().updateCommands(); + } + + @Override + public boolean hasPermission(@Nonnull String inName) { + String name = inName.toLowerCase(Locale.ENGLISH); + if (isPermissionSet(name)) return true; + + if (isPermissionSet("*") || isPermissionSet("*.*")) return true; + + if (name.contains(".")) + return isPermissionSet(name.substring(0, name.indexOf(".")) + "*") || isOp(); + + return false; + } + + @Override + public boolean isPermissionSet(@Nonnull String name) { + return bearer.getPermissionGroups().stream().anyMatch(c -> c.getPermissions().stream().anyMatch(p -> p.equalsIgnoreCase(name))); + } + + @Override + public boolean isPermissionSet(@Nonnull Permission perm) { + return isPermissionSet(perm.getName()); + } + + @Override + public boolean hasPermission(@Nonnull Permission perm) { + return hasPermission(perm.getName()); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/permission/PermissionManager.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/permission/PermissionManager.java new file mode 100644 index 0000000..f254d1f --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/permission/PermissionManager.java @@ -0,0 +1,162 @@ +package me.yuri.yuriapi.api.permission; + +import me.yuri.yuriapi.Desu; +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.db.DbComparisonType; +import me.yuri.yuriapi.api.db.DbQueryResult; +import me.yuri.yuriapi.api.db.DbTable; +import me.yuri.yuriapi.api.utils.Colored; +import me.yuri.yuriapi.utils.DbManager; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.OfflinePlayer; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; + +import javax.annotation.Nonnull; +import java.io.File; +import java.util.*; +import java.util.stream.Collectors; + +public class PermissionManager { + private static final PermissionManager inst = new PermissionManager(); + protected static List permgroups = new ArrayList<>(); + private static YPermissionGroup defaultPGroup = null; + private static boolean init = false; + + private PermissionManager() { + } + + public static PermissionManager getInstance() { + return inst; + } + + public static YPermissionGroup getDefaultGroup() { + return defaultPGroup; + } + + public static void savePerms(YPlayer p) { + if (!p.getPermissionGroups().isEmpty()) + Objects.requireNonNull(DbManager.h("pg")).createInsertQuery() + .setColumn("uuid", p.getBasePlayer().getUniqueId()).setColumn("groups", p.getPermissionGroups() + .stream().map(YPermissionGroup::getName).collect(Collectors.joining(";"))).build().execute(); + } + + public static boolean setOffline(OfflinePlayer p, YPermissionGroup g, boolean set) { + DbTable usr = Objects.requireNonNull(DbManager.h("pg")); + DbQueryResult q = usr.createSelectQuery().columns("groups").where(w -> w.forColumn("uuid").value(DbComparisonType.EQUALS, p.getUniqueId()).end()).build().execute(); + String groups = ""; + if (q.next()) { + groups = (String) q.get(0); + } + q.close(); + + if (groups.isEmpty()) { + if (set) + groups = g.getName(); + } else { + if (set) { + List s = Arrays.asList(groups.split(";")); + if (s.stream().anyMatch(ss -> ss.equalsIgnoreCase(g.getName()))) + return false; + groups += ";" + g.getName(); + } else { + List s = Arrays.asList(groups.split(";")); + s.removeIf(c -> c.equals(g.getName())); + groups = String.join(";", s); + } + } + + if (!groups.isEmpty()) { + usr.createInsertQuery().setColumn("uuid", p.getUniqueId()).setColumn("groups", groups).build().execute(); + return true; + } + + return false; + } + + public static YPermissionGroup getByName(@Nonnull String name, boolean ignoreCase) { + for (YPermissionGroup g : permgroups) { + if (ignoreCase) { + if (g.getName().equalsIgnoreCase(name)) return g; + } else { + if (g.getName().equals(name)) return g; + } + } + + return null; + } + + public static List getFor(YPlayer p) { + DbQueryResult q = Objects.requireNonNull(DbManager.h("pg")).createSelectQuery().columns("groups").where(w -> w.forColumn("uuid").value(DbComparisonType.EQUALS, p.getBasePlayer().getUniqueId()).end()).build().execute(); + List gp = new ArrayList<>(); + if (q.next()) { + String[] names = q.getText(1).split(";"); + Arrays.stream(names).forEach(c -> gp.add(getByName(c, false))); + } + q.close(); + return gp; + } + + public static List getGroups() { + return permgroups; + } + + public void init() { + if (init) return; + init = true; + + File f = new File(Desu.getMain().getDataFolder(), "permissions.yml"); + + if (!f.exists()) + Desu.getMain().saveResource("permissions.yml", true); + + YamlConfiguration perms; + try { + perms = YamlConfiguration.loadConfiguration(f); + + char colorCode = Objects.requireNonNull(perms.getString("colorCode")).charAt(0); + ConfigurationSection groups = perms.getConfigurationSection("groups"); + assert groups != null; + + String defaultGroup = perms.getString("default"); + + Bukkit.getConsoleSender().sendMessage(Colored.colorize("&ePermission groups:")); + groups.getKeys(false).forEach(g -> { + ConfigurationSection group = groups.getConfigurationSection(g); + + assert group != null; + + String prefix = group.getString("prefix"); + String suffix = group.getString("suffix"); + + HashSet permissions = new HashSet<>(group.getStringList("permissions")); + + if (prefix != null) prefix = Colored.colorize(colorCode, prefix); + if (suffix != null) suffix = Colored.colorize(colorCode, suffix); + + YPermissionGroup gp = new YPermissionGroup(g, prefix, suffix, permissions); + + permgroups.add(gp); + gp.index = permgroups.size() - 1; + + if (gp.getName().equalsIgnoreCase(defaultGroup)) + defaultPGroup = gp; + + Bukkit.getConsoleSender().sendMessage(Colored.colorize(String.format("&e- &a%s&e -> prefix: &a%s&e, suffix: &a%s&e%s.", g, prefix == null ? "&cnone" : (ChatColor.stripColor(prefix).isEmpty() ? prefix + "color" : prefix), suffix == null ? "&cnone" : (ChatColor.stripColor(suffix).isEmpty() ? suffix + "color" : suffix), gp.getName().equals(defaultGroup) ? " (&adefault group&e)" : ""))); + }); + + ArrayList aa = new ArrayList<>(permgroups); + Collections.reverse(aa); + HashSet permss = new HashSet<>(); + for (YPermissionGroup pg : aa) { + pg.getPermissions().addAll(permss); + permss.addAll(pg.getPermissions()); + } + + } catch (Exception e) { + Bukkit.getConsoleSender().sendMessage(Desu.cl.colorizeInst("$cInvalid permission group configuration... Permission system will not work!")); + e.printStackTrace(); + } + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/permission/YPermissionGroup.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/permission/YPermissionGroup.java new file mode 100644 index 0000000..fb4aea5 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/permission/YPermissionGroup.java @@ -0,0 +1,60 @@ +package me.yuri.yuriapi.api.permission; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.HashSet; +import java.util.Set; + +public class YPermissionGroup { + + private final String name; + private final Set permissions; + protected int index; + private String prefix, suffix; + + protected YPermissionGroup(@Nonnull String name, @Nullable String prefix, @Nullable String suffix, @Nullable HashSet permissions) { + this.name = name; + this.prefix = prefix; + this.suffix = suffix; + + if (permissions == null) permissions = new HashSet<>(); + + this.permissions = permissions; + } + + public int getIndex() { + return index; + } + + public Set getPermissions() { + return permissions; + } + + public void addPermission(String permission) { + permissions.add(permission); + } + + public boolean removePermission(String permission) { + return permissions.remove(permission); + } + + public String getName() { + return name; + } + + public String getPrefix() { + return prefix; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + public String getSuffix() { + return suffix; + } + + public void setSuffix(String suffix) { + this.suffix = suffix; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/Accessor.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/Accessor.java new file mode 100644 index 0000000..a55adb6 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/Accessor.java @@ -0,0 +1,56 @@ +package me.yuri.yuriapi.api.reflectionless; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Function; + +@SuppressWarnings("unchecked") +public final class Accessor { + private static final Map> getterAccess = new HashMap<>(); + private static final Map> setterAccess = new HashMap<>(); + private static final Map, Function> constructorAccess = new HashMap<>(); + private static final Map> methodAccess = new HashMap<>(); + + private Accessor() { + } + + public static Function getGetter(Field field) { + Function function = getterAccess.get(field); + if (function == null) { + function = UnsafeUtil.allocate((Class>) UnsafeUtil.defineAnonymous(field.getDeclaringClass(), new FieldAccessor(field, true).toByteArray())); + getterAccess.put(field, function); + } + return function; + } + + public static BiConsumer getSetter(Field field) { + BiConsumer biConsumer = setterAccess.get(field); + if (biConsumer == null) { + biConsumer = UnsafeUtil.allocate((Class>) UnsafeUtil.defineAnonymous(field.getDeclaringClass(), new FieldAccessor(field, false).toByteArray())); + setterAccess.put(field, biConsumer); + } + return biConsumer; + } + + public static Function getConstructor(Constructor constructor) { + Function function = constructorAccess.get(constructor); + if (function == null) { + function = UnsafeUtil.allocate((Class>) UnsafeUtil.defineAnonymous(constructor.getDeclaringClass(), new ConstructorAccessor(constructor).toByteArray())); + constructorAccess.put(constructor, function); + } + return function; + } + + public static Function getMethod(Method method) { + Function function = methodAccess.get(method); + if (function == null) { + function = UnsafeUtil.allocate((Class>) UnsafeUtil.defineAnonymous(method.getDeclaringClass(), new MethodAccessor(method).toByteArray())); + methodAccess.put(method, function); + } + return function; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/ClassAccessor.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/ClassAccessor.java new file mode 100644 index 0000000..3969a28 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/ClassAccessor.java @@ -0,0 +1,32 @@ +package me.yuri.yuriapi.api.reflectionless; + +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +public class ClassAccessor extends ClassWriter { + protected static final String OBJECT_TYPE = Type.getInternalName(Object.class); + protected static final String CTOR_NAME = ""; + + protected Class declaringClass; + protected String declaringClassType; + protected String generatedName; + + public ClassAccessor(Class declaringClass) { + super(ClassWriter.COMPUTE_MAXS); + this.declaringClass = declaringClass; + this.declaringClassType = Type.getInternalName(declaringClass); + this.generatedName = declaringClassType + "$Access"; + } + + protected void generateConstructor() { + MethodVisitor ctor = visitMethod(Opcodes.ACC_PUBLIC, CTOR_NAME, "()V", null, null); + ctor.visitCode(); + ctor.visitVarInsn(Opcodes.ALOAD, 0); + ctor.visitMethodInsn(Opcodes.INVOKESPECIAL, OBJECT_TYPE, CTOR_NAME, "()V", false); + ctor.visitInsn(Opcodes.RETURN); + ctor.visitMaxs(0, 0); + ctor.visitEnd(); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/ConstructorAccessor.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/ConstructorAccessor.java new file mode 100644 index 0000000..f38072d --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/ConstructorAccessor.java @@ -0,0 +1,54 @@ +package me.yuri.yuriapi.api.reflectionless; + +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +import java.lang.reflect.Constructor; + +public class ConstructorAccessor extends MemberAccessor { + protected static final String OBJECT_ARRAY_DESCRIPTOR = Type.getDescriptor(Object[].class); + protected static final String CALLER_TYPE = "(L" + OBJECT_TYPE + ";)L" + OBJECT_TYPE + ";"; + + protected Class[] parameters; + + public ConstructorAccessor(Constructor constructor) { + super(constructor); + parameters = constructor.getParameterTypes(); + + visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SYNTHETIC, generatedName, null, OBJECT_TYPE, new String[]{FUNCTION_TYPE}); + generateCall(); + visitEnd(); + } + + protected void generateCall() { + MethodVisitor mv = visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, FUNCTION_METHOD_NAME, CALLER_TYPE, null, null); + mv.visitVarInsn(Opcodes.ALOAD, 1); + mv.visitTypeInsn(Opcodes.CHECKCAST, OBJECT_ARRAY_DESCRIPTOR); + mv.visitVarInsn(Opcodes.ASTORE, 1); + mv.visitTypeInsn(Opcodes.NEW, Type.getInternalName(declaringClass)); + mv.visitInsn(Opcodes.DUP); + castParams(mv); + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, declaringClassType, CTOR_NAME, Types.getMethodDescriptor(Void.TYPE, parameters), false); + mv.visitInsn(Opcodes.ARETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + protected void castParams(MethodVisitor mv) { + int var = 0; + for (Class parameter : parameters) { + mv.visitVarInsn(Opcodes.ALOAD, 1); + mv.visitLdcInsn(var++); + mv.visitInsn(Opcodes.AALOAD); + if (parameter.isPrimitive()) { + Types.Primitive primitive = Types.getPrimitive(parameter); + assert primitive != null; + mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(primitive.getWrapper())); + primitive.toPrimitive(mv); + } else { + mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(parameter)); + } + } + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/DynamicCaller.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/DynamicCaller.java new file mode 100644 index 0000000..6025941 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/DynamicCaller.java @@ -0,0 +1,5 @@ +package me.yuri.yuriapi.api.reflectionless; + +public interface DynamicCaller { + Object call(Object... p); +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/FieldAccess.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/FieldAccess.java new file mode 100644 index 0000000..25fb576 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/FieldAccess.java @@ -0,0 +1,7 @@ +package me.yuri.yuriapi.api.reflectionless; + +public interface FieldAccess { + Object get(Object obj); + + void set(Object obj, Object value); +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/FieldAccessor.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/FieldAccessor.java new file mode 100644 index 0000000..e489f18 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/FieldAccessor.java @@ -0,0 +1,65 @@ +package me.yuri.yuriapi.api.reflectionless; + +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +import java.lang.reflect.Field; +import java.util.Objects; +import java.util.function.BiConsumer; + +public class FieldAccessor extends MemberAccessor { + + protected static final String BICONSUMER_TYPE = Type.getInternalName(BiConsumer.class); + protected static final String BICONSUMER_METHOD_NAME = "accept"; + + protected static final String GETTER_TYPE = "(L" + OBJECT_TYPE + ";)L" + OBJECT_TYPE + ";"; + protected static final String SETTER_TYPE = "(L" + OBJECT_TYPE + ";L" + OBJECT_TYPE + ";)V"; + + protected Class type; + + public FieldAccessor(Field field, boolean getter) { + super(field); + type = field.getType(); + + visit(UnsafeUtil.V_C, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SYNTHETIC, generatedName, null, OBJECT_TYPE, new String[]{getter ? FUNCTION_TYPE : BICONSUMER_TYPE}); + if (getter) generateGetter(); + else generateSetter(); + visitEnd(); + } + + protected void generateGetter() { + MethodVisitor mv = visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, FUNCTION_METHOD_NAME, GETTER_TYPE, null, null); + if (!isStatic) { + mv.visitVarInsn(Opcodes.ALOAD, 1); + mv.visitTypeInsn(Opcodes.CHECKCAST, declaringClassType); + } + mv.visitFieldInsn(isStatic ? Opcodes.GETSTATIC : Opcodes.GETFIELD, declaringClassType, name, Type.getDescriptor(type)); + if (type.isPrimitive()) Objects.requireNonNull(Types.getPrimitive(type)).toWrapper(mv); + mv.visitInsn(Opcodes.ARETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + protected void generateSetter() { + MethodVisitor mv = visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, BICONSUMER_METHOD_NAME, SETTER_TYPE, null, null); + if (!isStatic) { + mv.visitVarInsn(Opcodes.ALOAD, 1); + mv.visitTypeInsn(Opcodes.CHECKCAST, declaringClassType); + } + mv.visitVarInsn(Opcodes.ALOAD, 2); + if (type.isPrimitive()) { + Types.Primitive primitive = Types.getPrimitive(type); + assert primitive != null; + mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(primitive.getWrapper())); + primitive.toPrimitive(mv); + } else { + mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(type)); + } + mv.visitFieldInsn(isStatic ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD, declaringClassType, name, Type.getDescriptor(type)); + mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/FunctionalCaller.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/FunctionalCaller.java new file mode 100644 index 0000000..74e9d49 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/FunctionalCaller.java @@ -0,0 +1,16 @@ +package me.yuri.yuriapi.api.reflectionless; + +import java.util.function.Function; + +public class FunctionalCaller implements DynamicCaller { + private final Function function; + + public FunctionalCaller(Function function) { + this.function = function; + } + + @Override + public Object call(Object... parameters) { + return function.apply(parameters); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/FunctionalFieldAccess.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/FunctionalFieldAccess.java new file mode 100644 index 0000000..49e0406 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/FunctionalFieldAccess.java @@ -0,0 +1,24 @@ +package me.yuri.yuriapi.api.reflectionless; + +import java.util.function.BiConsumer; +import java.util.function.Function; + +public class FunctionalFieldAccess implements FieldAccess { + private final Function getter; + private final BiConsumer setter; + + public FunctionalFieldAccess(Function getter, BiConsumer setter) { + this.getter = getter; + this.setter = setter; + } + + @Override + public Object get(Object obj) { + return getter.apply(obj); + } + + @Override + public void set(Object obj, Object value) { + setter.accept(obj, value); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/MemberAccessor.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/MemberAccessor.java new file mode 100644 index 0000000..4f59994 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/MemberAccessor.java @@ -0,0 +1,22 @@ +package me.yuri.yuriapi.api.reflectionless; + +import org.objectweb.asm.Type; + +import java.lang.reflect.Member; +import java.lang.reflect.Modifier; +import java.util.function.Function; + +public class MemberAccessor extends ClassAccessor { + + protected static final String FUNCTION_TYPE = Type.getInternalName(Function.class); + protected static final String FUNCTION_METHOD_NAME = "apply"; + + protected String name; + protected boolean isStatic; + + public MemberAccessor(Member member) { + super(member.getDeclaringClass()); + name = member.getName(); + isStatic = Modifier.isStatic(member.getModifiers()); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/MethodAccessor.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/MethodAccessor.java new file mode 100644 index 0000000..ad6a974 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/MethodAccessor.java @@ -0,0 +1,66 @@ +package me.yuri.yuriapi.api.reflectionless; + +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +import java.lang.reflect.Method; +import java.util.Objects; + +public class MethodAccessor extends MemberAccessor { + protected static final String OBJECT_ARRAY_DESCRIPTOR = Type.getDescriptor(Object[].class); + protected static final String CALLER_TYPE = "(L" + OBJECT_TYPE + ";)L" + OBJECT_TYPE + ";"; + + protected Class returnType; + protected Class[] parameters; + + public MethodAccessor(Method method) { + super(method); + returnType = method.getReturnType(); + parameters = method.getParameterTypes(); + + visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SYNTHETIC, generatedName, null, OBJECT_TYPE, new String[]{FUNCTION_TYPE}); + generateCall(); + visitEnd(); + } + + protected void generateCall() { + MethodVisitor mv = visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, FUNCTION_METHOD_NAME, CALLER_TYPE, null, null); + mv.visitVarInsn(Opcodes.ALOAD, 1); + mv.visitTypeInsn(Opcodes.CHECKCAST, OBJECT_ARRAY_DESCRIPTOR); + mv.visitVarInsn(Opcodes.ASTORE, 1); + if (!isStatic) { + mv.visitVarInsn(Opcodes.ALOAD, 1); + mv.visitInsn(Opcodes.ICONST_0); + mv.visitInsn(Opcodes.AALOAD); + mv.visitTypeInsn(Opcodes.CHECKCAST, declaringClassType); + } + castParams(mv); + mv.visitMethodInsn(declaringClass.isInterface() ? Opcodes.INVOKEINTERFACE : isStatic ? Opcodes.INVOKESTATIC : Opcodes.INVOKEVIRTUAL, declaringClassType, name, Types.getMethodDescriptor(returnType, parameters), declaringClass.isInterface()); + if (returnType == Void.TYPE) { + mv.visitInsn(Opcodes.ACONST_NULL); + } else if (returnType.isPrimitive()) { + Objects.requireNonNull(Types.getPrimitive(returnType)).toWrapper(mv); + } + mv.visitInsn(Opcodes.ARETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + protected void castParams(MethodVisitor mv) { + int var = isStatic ? 0 : 1; + for (Class parameter : parameters) { + mv.visitVarInsn(Opcodes.ALOAD, 1); + mv.visitLdcInsn(var++); + mv.visitInsn(Opcodes.AALOAD); + if (parameter.isPrimitive()) { + Types.Primitive primitive = Types.getPrimitive(parameter); + assert primitive != null; + mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(primitive.getWrapper())); + primitive.toPrimitive(mv); + } else { + mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(parameter)); + } + } + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/Reflectionless.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/Reflectionless.java new file mode 100644 index 0000000..c12e05f --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/Reflectionless.java @@ -0,0 +1,25 @@ +package me.yuri.yuriapi.api.reflectionless; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.function.BiConsumer; +import java.util.function.Function; + +@SuppressWarnings("unchecked") +public final class Reflectionless { + private Reflectionless() { + } + + public static FieldAccess get(Field field) { + return new FunctionalFieldAccess((Function) Accessor.getGetter(field), (BiConsumer) Accessor.getSetter(field)); + } + + public static DynamicCaller get(Constructor constructor) { + return new FunctionalCaller((Function) Accessor.getConstructor(constructor)); + } + + public static DynamicCaller get(Method method) { + return new FunctionalCaller((Function) Accessor.getMethod(method)); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/Types.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/Types.java new file mode 100644 index 0000000..5ed0682 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/Types.java @@ -0,0 +1,73 @@ +package me.yuri.yuriapi.api.reflectionless; + +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +public class Types { + + public static String getMethodDescriptor(Class returnType, Class[] parameters) { + StringBuilder builder = new StringBuilder(); + builder.append("("); + for (Class parameter : parameters) { + builder.append(Type.getDescriptor(parameter)); + } + builder.append(")"); + builder.append(Type.getDescriptor(returnType)); + return builder.toString(); + } + + public static Primitive getPrimitive(Class clz) { + for (Primitive value : Primitive.values()) { + if (value.getPrimitive() == clz || value.getWrapper() == clz) return value; + } + return null; + } + + public enum Primitive { + + VOID(Void.class, "V"), + BOOLEAN(Boolean.class, "Z"), + CHARACTER(Character.class, "C"), + BYTE(Byte.class, "B"), + SHORT(Short.class, "S"), + INTEGER(Integer.class, "I"), + FLOAT(Float.class, "F"), + LONG(Long.class, "J"), + DOUBLE(Double.class, "D"); + + private final Class wrapper; + private final String identifier; + private Class primitive; + + Primitive(Class wrapper, String identifier) { + this.wrapper = wrapper; + try { + this.primitive = (Class) wrapper.getDeclaredField("TYPE").get(null); + } catch (IllegalAccessException | NoSuchFieldException e) { + e.printStackTrace(); + } + this.identifier = identifier; + } + + public Class getWrapper() { + return wrapper; + } + + public Class getPrimitive() { + return primitive; + } + + public String getIdentifier() { + return identifier; + } + + public void toPrimitive(MethodVisitor mv) { + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(getWrapper()), getPrimitive().getName() + "Value", "()" + getIdentifier(), false); + } + + public void toWrapper(MethodVisitor mv) { + mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(getWrapper()), "valueOf", "(" + getIdentifier() + ")" + Type.getDescriptor(getWrapper()), false); + } + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/UnsafeUtil.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/UnsafeUtil.java new file mode 100644 index 0000000..92b0c2a --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/reflectionless/UnsafeUtil.java @@ -0,0 +1,76 @@ +package me.yuri.yuriapi.api.reflectionless; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class UnsafeUtil { + private static final Class UNSAFE_CLASS; + private static final Object UNSAFE; + + private static final Method DEFINE_ANONYMOUS; + private static final Method ALLOCATE; + private static final Method FIELD_OFFSET; + private static final Method PUT_FIELD; + private static final Method GET_FIELD; + + public static int V_C = 52; //1.8 + + static { + try { + UNSAFE_CLASS = Class.forName("sun.misc.Unsafe"); + + Field unsafeField = UNSAFE_CLASS.getDeclaredField("theUnsafe"); + unsafeField.setAccessible(true); + UNSAFE = unsafeField.get(null); + + DEFINE_ANONYMOUS = UNSAFE_CLASS.getDeclaredMethod("defineAnonymousClass", Class.class, byte[].class, Object[].class); + ALLOCATE = UNSAFE_CLASS.getDeclaredMethod("allocateInstance", Class.class); + FIELD_OFFSET = UNSAFE_CLASS.getDeclaredMethod("objectFieldOffset", Field.class); + PUT_FIELD = UNSAFE_CLASS.getDeclaredMethod("putObject", Object.class, long.class, Object.class); + GET_FIELD = UNSAFE_CLASS.getDeclaredMethod("getObject", Object.class, long.class); + } catch (Throwable e) { + e.printStackTrace(); + throw new RuntimeException(); + } + } + + public static Class defineAnonymous(Class clz, byte[] bytes) { + try { + return (Class) DEFINE_ANONYMOUS.invoke(UNSAFE, clz, bytes, null); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + throw new RuntimeException(); + } + } + + public static void putField(Field field, Object object, Object value) { + try { + long offset = (long) FIELD_OFFSET.invoke(UNSAFE, field); + PUT_FIELD.invoke(UNSAFE, object, offset, value); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + throw new RuntimeException(); + } + } + + public static Object getField(Field field, Object object, Object value) { + try { + long offset = (long) FIELD_OFFSET.invoke(UNSAFE, field); + return GET_FIELD.invoke(UNSAFE, object, offset); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + throw new RuntimeException(); + } + } + + @SuppressWarnings("unchecked") + public static T allocate(Class clz) { + try { + return (T) ALLOCATE.invoke(UNSAFE, clz); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + throw new RuntimeException(); + } + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/Colored.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/Colored.java new file mode 100755 index 0000000..fc3e6c0 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/Colored.java @@ -0,0 +1,199 @@ +package me.yuri.yuriapi.api.utils; + +import org.bukkit.ChatColor; +import org.bukkit.Color; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.stream.Collectors; + +public class Colored { + + public static final String BLACK = ChatColor.BLACK.toString(); + public static final String DARK_BLUE = ChatColor.DARK_BLUE.toString(); + public static final String DARK_GREEN = ChatColor.DARK_GREEN.toString(); + public static final String DARK_AQUA = ChatColor.DARK_AQUA.toString(); + public static final String DARK_RED = ChatColor.DARK_RED.toString(); + public static final String DARK_PURPLE = ChatColor.DARK_PURPLE.toString(); + public static final String GOLD = ChatColor.GOLD.toString(); + public static final String GRAY = ChatColor.GRAY.toString(); + public static final String DARK_GRAY = ChatColor.DARK_GRAY.toString(); + public static final String BLUE = ChatColor.BLUE.toString(); + public static final String GREEN = ChatColor.GREEN.toString(); + public static final String AQUA = ChatColor.AQUA.toString(); + public static final String RED = ChatColor.RED.toString(); + public static final String LIGHT_PURPLE = ChatColor.LIGHT_PURPLE.toString(); + public static final String YELLOW = ChatColor.YELLOW.toString(); + public static final String WHITE = ChatColor.WHITE.toString(); + public static final String MAGIC = ChatColor.MAGIC.toString(); + public static final String STRIKETHROUGH = ChatColor.STRIKETHROUGH.toString(); + public static final String UNDERLINE = ChatColor.UNDERLINE.toString(); + public static final String ITALIC = ChatColor.ITALIC.toString(); + public static final String BOLD = ChatColor.BOLD.toString(); + public static final String RESET = ChatColor.RESET.toString(); + private char symbol; + + /** + * Creates a new Colored instance + * + * @param symbol the color code symbol that will be substituted using colorizeInst() + */ + public Colored(char symbol) { + this.symbol = symbol; + } + + /** + * Applies color codes to the given text (!!!substitutes '&' with the color codes!!!) + * + * @param text the text to apply color codes to + * @return colorized text + */ + public static String colorize(String text) { + return colorize('&', text); + } + + /** + * Applies color codes to the given text (!!!substitutes '&' with the color codes!!!) + * + * @param text the text to apply color codes to + * @return colorized text + */ + public static String[] colorize(String... text) { + return colorize('&', text); + } + + /** + * Applies color codes to the given text + * + * @param text the text to apply color codes to + * @param symbol the color code symbol that will be substituted + * @return colorized text + */ + public static String colorize(char symbol, String text) { + return text == null ? null : ChatColor.translateAlternateColorCodes(symbol, text); + } + + /** + * Applies color codes to the given text + * + * @param text the text to apply color codes to + * @param symboll the color code symbol that will be substituted + * @return colorized text + */ + public static String[] colorize(char symboll, String... text) { + return Arrays.stream(text).map(t -> t = t == null ? null : ChatColor.translateAlternateColorCodes(symboll, t)).collect(Collectors.toList()).toArray(new String[]{}); + } + + /** + * Returns color from a String (!!!Will return Color.BLACK if the parameter 'name' is invalid!!!) + * + * @param name the string name of a color + * @return color as a Color class + */ + public static Color getColorFromName(String name) { + try { + Field f = Color.class.getField(name.toUpperCase()); + f.setAccessible(true); + Color cc = (Color) f.get(ChatColor.class); + f.setAccessible(false); + return cc; + } catch (NoSuchFieldException | IllegalAccessException ignored) { + return Color.BLACK; + } + } + + /** + * Returns ChatColor from a String (!!!Will return ChatColor.BLACK if the parameter 'name' is invalid!!!) + * + * @param name the string name of a color + * @return color as a ChatColor class + */ + public static ChatColor getChatColorFromName(String name) { + try { + Field f = ChatColor.class.getField(name.toUpperCase()); + f.setAccessible(true); + ChatColor cc = (ChatColor) f.get(ChatColor.class); + f.setAccessible(false); + return cc; + } catch (NoSuchFieldException | IllegalAccessException ignored) { + return ChatColor.BLACK; + } + } + + /** + * Returns a String name of a Color + * + * @param color color + * @return name of a color as String + */ + public static String getFromColor(Color color) { + if (color.equals(Color.BLACK)) { + return "BLACK"; + } else if (color.equals(Color.BLUE)) { + return "BLUE"; + } else if (color.equals(Color.RED)) { + return "RED"; + } else if (color.equals(Color.GRAY)) { + return "GRAY"; + } else if (color.equals(Color.NAVY)) { + return "NAVY"; + } else if (color.equals(Color.MAROON)) { + return "MAROON"; + } else if (color.equals(Color.YELLOW)) { + return "YELLOW"; + } else if (color.equals(Color.GREEN)) { + return "GREEN"; + } else if (color.equals(Color.ORANGE)) { + return "ORANGE"; + } + return "BLACK"; + } + + /** + * Removes any color codes from given text + * + * @param text the text + * @return text without color codes + */ + public static String strip(String text) { + return ChatColor.stripColor(text); + } + + /** + * Gets the the color code symbol that will be substituted using colorizeInst() + * + * @return color symbol + */ + public char getSymbol() { + return symbol; + } + + /** + * Sets the the color code symbol that will be substituted using colorizeInst() + * + * @param symbol the color code symbol that will be substituted using colorizeInst() + */ + public void setSymbol(char symbol) { + this.symbol = symbol; + } + + /** + * Applies color codes to the given text using symbol stored in the instance + * + * @param text the text to apply color codes to + * @return colorized text + */ + public String colorizeInst(String text) { + return colorize(symbol, text); + } + + /** + * Applies color codes to the given text using symbol stored in the instance + * + * @param text the text to apply color codes to + * @return colorized text + */ + public String[] colorizeInst(String... text) { + return colorize(symbol, text); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/CustomScoreboard.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/CustomScoreboard.java new file mode 100755 index 0000000..4e518b4 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/CustomScoreboard.java @@ -0,0 +1,112 @@ +package me.yuri.yuriapi.api.utils; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.scoreboard.DisplaySlot; +import org.bukkit.scoreboard.Objective; +import org.bukkit.scoreboard.Score; +import org.bukkit.scoreboard.Scoreboard; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +public class CustomScoreboard { + + private final Scoreboard sb; + private final Objective ob; + private final Map scores = new HashMap<>(); + private String teamName; + + public CustomScoreboard(DisplaySlot ds, String head) { + + sb = Objects.requireNonNull(Bukkit.getScoreboardManager()).getNewScoreboard(); + ob = sb.registerNewObjective("yeet", "dummy", head); + ob.setDisplayName(head); + ob.setDisplaySlot(ds); + + } + + public void addScore(String id, String str) { + Score sc = ob.getScore(str); + scores.put(id, sc); + sc.setScore(0); + int i = scores.size(); + for (Score ss : scores.values().stream().sorted((o1, o2) -> { + int a, b; + try { + a = o1.getScore(); + } catch (Exception ignored) { + a = 0; + } + try { + b = o2.getScore(); + } catch (Exception ignored) { + b = 0; + } + return a - b; + }).collect(Collectors.toList())) { + ss.setScore(i); + i--; + } + + } + + public void removeScore(String id) { + Score sc = scores.getOrDefault(id, null); + if (sc == null) return; + Objects.requireNonNull(sc.getScoreboard()).resetScores(sc.getEntry()); + scores.remove(id); + int i = scores.size(); + for (Score ss : scores.values().stream().sorted((o1, o2) -> { + int a, b; + try { + a = o1.getScore(); + } catch (Exception ignored) { + a = 0; + } + try { + b = o2.getScore(); + } catch (Exception ignored) { + b = 0; + } + return a - b; + }).collect(Collectors.toList())) { + ss.setScore(i); + i--; + } + } + + public void addToPlayer(Player p) { + p.setScoreboard(sb); + } + + public void updateScore(String id, String score) { + Score sc = scores.getOrDefault(id, null); + if (sc == null) return; + Objects.requireNonNull(sc.getScoreboard()).resetScores(sc.getEntry()); + sc = ob.getScore(score); + scores.put(id, sc); + sc.setScore(0); + int i = scores.size(); + for (Score ss : scores.values().stream().sorted((o1, o2) -> { + int a, b; + try { + a = o1.getScore(); + } catch (Exception ignored) { + a = 0; + } + try { + b = o2.getScore(); + } catch (Exception ignored) { + b = 0; + } + return a - b; + }).collect(Collectors.toList())) { + ss.setScore(i); + i--; + } + } +} + diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/ItemUtils.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/ItemUtils.java new file mode 100644 index 0000000..eb98ac0 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/ItemUtils.java @@ -0,0 +1,28 @@ +package me.yuri.yuriapi.api.utils; + +import org.bukkit.Material; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +public class ItemUtils { + private ItemUtils() { + } + + public static boolean removeItem(Inventory inv, Material m, int count) { + if (!inv.containsAtLeast(new ItemStack(m), count)) return false; + for (ItemStack it : inv.getContents()) { + if (it != null) { + if (it.getType() == m) { + int preAmount = it.getAmount(); + int newAmount = Math.max(0, preAmount - count); + count = Math.max(0, count - preAmount); + it.setAmount(newAmount); + if (count == 0) { + break; + } + } + } + } + return true; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/Message.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/Message.java new file mode 100644 index 0000000..6ea6fdc --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/Message.java @@ -0,0 +1,23 @@ +package me.yuri.yuriapi.api.utils; + +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.BaseComponent; + +public class Message { + + private final ChatMessageType type; + private final BaseComponent[] comp; + + public Message(ChatMessageType type, BaseComponent... comp) { + this.type = type; + this.comp = comp; + } + + public ChatMessageType getType() { + return type; + } + + public BaseComponent[] getComponents() { + return comp; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/MessageBuilder.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/MessageBuilder.java new file mode 100644 index 0000000..8c8c6a8 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/MessageBuilder.java @@ -0,0 +1,125 @@ +package me.yuri.yuriapi.api.utils; + +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.api.chat.hover.content.Text; + +import java.util.ArrayList; +import java.util.List; + +public class MessageBuilder implements Cloneable { + + private final List buffer = new ArrayList<>(); + private final ChatMessageType type; + private BaseComponent last = new TextComponent(); + private boolean dirty = false; + private StringBuffer textbuff = new StringBuffer(); + + public MessageBuilder(ChatMessageType t) { + type = t; + } + + public MessageBuilder() { + this(ChatMessageType.CHAT); + } + + public MessageBuilder appendText(char colorCode, String text) { + textbuff.append(Colored.colorize(colorCode, text)); + return this; + } + + public MessageBuilder appendText(String text) { + return appendText('&', text); + } + + public MessageBuilder pushText() { + last.addExtra(textbuff.toString()); + textbuff = new StringBuffer(); + return this; + } + + public MessageBuilder appendFromBuffer() { + last.addExtra(textbuff.toString()); + textbuff = new StringBuffer(); + return this; + } + + public MessageBuilder append(char colorCode, String text) { + last.addExtra(Colored.colorize(colorCode, text)); + dirty = true; + return this; + } + + public MessageBuilder append(String text) { + dirty = true; + return append('&', text); + } + + public MessageBuilder replaceLastInBuffer(int count, char colorCode, String replacement) { + textbuff.delete(textbuff.length() - (count + 1), textbuff.length() - 1); + textbuff.append(Colored.colorize(colorCode, replacement)); + return this; + } + + public MessageBuilder replaceLastInBuffer(int count, String replacement) { + return replaceLastInBuffer(count, '&', replacement); + } + + public MessageBuilder hoverText(char colorCode, String hoverText) { + last.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(Colored.colorize(colorCode, hoverText)))); + dirty = true; + return this; + } + + public MessageBuilder hoverText(String hoverText) { + return hoverText('&', hoverText); + } + + public MessageBuilder clickRunCommand(String cmd) { + last.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, cmd)); + dirty = true; + return this; + } + + public MessageBuilder clickSuggestCommand(String cmd) { + last.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, cmd)); + dirty = true; + return this; + } + + public MessageBuilder clickOpenURL(String url) { + last.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url)); + dirty = true; + return this; + } + + public MessageBuilder push() { + buffer.add(last); + last = new TextComponent(); + dirty = false; + return this; + } + + public List getComponents() { + return buffer; + } + + public MessageBuilder setComponent(int index, BaseComponent comp) { + buffer.set(index, comp); + return this; + } + + public MessageBuilder insertComponent(int index, BaseComponent comp) { + buffer.add(index, comp); + return this; + } + + public Message build() { + if (dirty) + buffer.add(last); + return new Message(type, buffer.toArray(new BaseComponent[0])); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/PlaceholderFormatter.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/PlaceholderFormatter.java new file mode 100644 index 0000000..d3901a9 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/PlaceholderFormatter.java @@ -0,0 +1,31 @@ +package me.yuri.yuriapi.api.utils; + +import me.yuri.yuriapi.api.YPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.player.AsyncPlayerChatEvent; + +public enum PlaceholderFormatter { + DISPLAY(""), NAME(""), PREFIXES(""), SUFFIX(""), GROUP(""), MESSAGE(""), HEALTH(""); + + private final String placeholder; + + PlaceholderFormatter(String s) { + this.placeholder = s; + } + + public static String format(String format, AsyncPlayerChatEvent e) { + YPlayer yp = YPlayer.get(e.getPlayer()); + return Colored.colorize(format(format, yp).replace(MESSAGE.placeholder, e.getMessage()).trim()); + } + + public static String format(String format, YPlayer p) { + Player pl = p.getBasePlayer(); + return Colored.colorize(format.replace(DISPLAY.placeholder, pl.getDisplayName()).replace(NAME.placeholder, pl.getName()) + .replace(PREFIXES.placeholder, (p.getChatPrefixes().isEmpty() ? "" : String.join(" ", p.getChatPrefixes()))) + .replace(HEALTH.placeholder, String.valueOf(pl.getHealth())).replace(GROUP.placeholder, p.getHighestGroup() == null ? "" : p.getHighestGroup().getPrefix()).replace(SUFFIX.placeholder, p.getHighestGroup() == null ? "" : p.getHighestGroup().getSuffix())).trim(); + } + + public String getPlaceholder() { + return placeholder; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/PlaceholderUtils.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/PlaceholderUtils.java new file mode 100755 index 0000000..051e24d --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/PlaceholderUtils.java @@ -0,0 +1,62 @@ +package me.yuri.yuriapi.api.utils; + +import org.bukkit.entity.Player; + +import java.util.regex.Pattern; + +public enum PlaceholderUtils { + + PLAYERNAME("{PLAYERNAME}"), PLAYERDISPLAYNAME("{PLAYERDISPLAYNAME}"), PLAYERCUSTOMNAME("{PLAYERCUSTOMNAME}"), + PLAYERPLAYERLISTNAME("{PLAYERPLAYERLISTNAME}"); + + private final String i; + + PlaceholderUtils(String i) { + this.i = i; + } + + /** + * Substitutes a placeholder with player's name counterpart + * + * @param placeholder the placeholder + * @param player the player whose name will be applied + * @return substituted placeholder + */ + public static String substitutePlaceholder(PlaceholderUtils placeholder, Player player) { + switch (placeholder) { + case PLAYERNAME: + return player.getName(); + case PLAYERDISPLAYNAME: + return player.getDisplayName(); + case PLAYERCUSTOMNAME: + return player.getCustomName(); + case PLAYERPLAYERLISTNAME: + return player.getPlayerListName(); + } + return player.getDisplayName(); + } + + /** + * Substitutes all placeholders with player's name counterparts + * See {@link PlaceholderUtils#substitutePlaceholder(PlaceholderUtils, Player)} + * + * @param message the message with placeholders + * @param player the player whose name will be applied + * @return substituted text + */ + public static String processPlayerPlaceholders(String message, Player player) { + for (PlaceholderUtils t : PlaceholderUtils.values()) { + message = message.replaceAll(Pattern.quote(t.i), substitutePlaceholder(t, player)); + } + return message; + } + + /** + * Returns a placeholder as a string + * + * @return placeholder as string + */ + public String getPlaceholder() { + return i; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/PlayerListener.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/PlayerListener.java new file mode 100644 index 0000000..dcd78c2 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/PlayerListener.java @@ -0,0 +1,9 @@ +package me.yuri.yuriapi.api.utils; + +import me.yuri.yuriapi.api.YPlayer; + +public interface PlayerListener { + void onLeave(YPlayer p); + + void onJoin(YPlayer p); +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/SyncedPlayerMap.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/SyncedPlayerMap.java new file mode 100644 index 0000000..4129908 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/SyncedPlayerMap.java @@ -0,0 +1,43 @@ +package me.yuri.yuriapi.api.utils; + +import me.yuri.yuriapi.api.YPlayer; +import org.bukkit.entity.Player; + +import java.util.HashMap; +import java.util.Map; + +public class SyncedPlayerMap extends HashMap implements PlayerListener { + + public SyncedPlayerMap(int initialCapacity, float loadFactor) { + super(initialCapacity, loadFactor); + YPlayer.sync(this); + } + + public SyncedPlayerMap(int initialCapacity) { + super(initialCapacity); + YPlayer.sync(this); + } + + public SyncedPlayerMap() { + super(); + YPlayer.sync(this); + } + + public SyncedPlayerMap(Map m) { + super(m); + YPlayer.sync(this); + } + + public V get(Player p) { + return get(YPlayer.get(p)); + } + + @Override + public void onLeave(YPlayer p) { + this.remove(p); + } + + @Override + public void onJoin(YPlayer p) { + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/SyncedPlayerSet.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/SyncedPlayerSet.java new file mode 100644 index 0000000..11f12e5 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/SyncedPlayerSet.java @@ -0,0 +1,57 @@ +package me.yuri.yuriapi.api.utils; + +import me.yuri.yuriapi.api.YPlayer; +import org.bukkit.entity.Player; + +import java.util.Collection; +import java.util.HashSet; + +public class SyncedPlayerSet extends HashSet implements PlayerListener { + + private final boolean syncJoin; + + public SyncedPlayerSet(int initialCapacity) { + this(initialCapacity, false); + } + + public SyncedPlayerSet() { + this(false); + } + + public SyncedPlayerSet(Collection c) { + this(c, false); + } + + public SyncedPlayerSet(int initialCapacity, boolean syncJoin) { + super(initialCapacity); + YPlayer.sync(this); + this.syncJoin = syncJoin; + } + + public SyncedPlayerSet(boolean syncJoin) { + super(); + YPlayer.sync(this); + this.syncJoin = syncJoin; + } + + public SyncedPlayerSet(Collection c, boolean addOnJoin) { + super(c); + YPlayer.sync(this); + this.syncJoin = addOnJoin; + } + + public boolean contains(Player p) { + return this.contains(YPlayer.get(p)); + } + + @Override + public void onLeave(YPlayer p) { + this.remove(p); + } + + @Override + public void onJoin(YPlayer p) { + if (syncJoin) + this.add(p); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/UUIDUtils.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/UUIDUtils.java new file mode 100644 index 0000000..8a9c176 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/UUIDUtils.java @@ -0,0 +1,22 @@ +package me.yuri.yuriapi.api.utils; + +import java.nio.ByteBuffer; +import java.util.UUID; + +public class UUIDUtils { + + private UUIDUtils() { + } + + public static byte[] toByteArray(UUID uuid) { + ByteBuffer bb = ByteBuffer.wrap(new byte[16]); + bb.putLong(uuid.getMostSignificantBits()); + bb.putLong(uuid.getLeastSignificantBits()); + return bb.array(); + } + + public static UUID toUUID(byte[] b) { + ByteBuffer bb = ByteBuffer.wrap(b); + return new UUID(bb.getLong(), bb.getLong()); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/configuration/ConfigVar.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/configuration/ConfigVar.java new file mode 100755 index 0000000..0b84d7c --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/configuration/ConfigVar.java @@ -0,0 +1,24 @@ +package me.yuri.yuriapi.api.utils.configuration; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigVar { + /** + * The configuration field name (in config.yml) + * + * @return the configuration field name (in config.yml) + */ + String value(); + + /** + * (ONLY IF STRING, OTHERWISE LEAVE EMPTY) + * + * @return the color code char for the field (if is String), leave default to disable + */ + char color() default ' '; +} \ No newline at end of file diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/configuration/ConfigVarException.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/configuration/ConfigVarException.java new file mode 100755 index 0000000..aa3ac76 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/configuration/ConfigVarException.java @@ -0,0 +1,22 @@ +package me.yuri.yuriapi.api.utils.configuration; + +public class ConfigVarException extends Exception { + + private final String msg; + private final String lmsg; + + public ConfigVarException(Exception e) { + msg = e.getMessage(); + lmsg = e.getLocalizedMessage(); + } + + @Override + public String getMessage() { + return msg; + } + + @Override + public String getLocalizedMessage() { + return lmsg; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/configuration/ConfigVarExceptionListener.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/configuration/ConfigVarExceptionListener.java new file mode 100755 index 0000000..68b91ee --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/configuration/ConfigVarExceptionListener.java @@ -0,0 +1,11 @@ +package me.yuri.yuriapi.api.utils.configuration; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface ConfigVarExceptionListener { +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/configuration/ConfigVarManager.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/configuration/ConfigVarManager.java new file mode 100755 index 0000000..6308adb --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/configuration/ConfigVarManager.java @@ -0,0 +1,174 @@ +package me.yuri.yuriapi.api.utils.configuration; + +import me.yuri.yuriapi.Desu; +import me.yuri.yuriapi.api.utils.Colored; +import me.yuri.yuriapi.utils.Logging; +import org.bukkit.plugin.java.JavaPlugin; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public final class ConfigVarManager { + private static final Map> reg = new ConcurrentHashMap<>(); + + private ConfigVarManager() { + } + + /** + * Registers a class to the ConfigVarManager + * + * @param plugin the plugin's main class + * @param clazz the class with configuration fields + */ + public static void register(JavaPlugin plugin, Object clazz) { + List lst = reg.getOrDefault(plugin, new ArrayList<>()); + lst.add(clazz); + reg.put(plugin, lst); + } + + /** + * Registers a class to the ConfigVarManager + * + * @param plugin the plugin's main class + * @param clazz the class with configuration fields + */ + public static void register(JavaPlugin plugin, Object... clazz) { + List lst = reg.getOrDefault(plugin, new ArrayList<>()); + lst.addAll(Arrays.asList(clazz)); + reg.put(plugin, lst); + } + + /** + * Removes all classes associated with a given plugin from the ConfigVarManager's registry + * + * @param plugin the plugin's main class + */ + public static void unregister(JavaPlugin plugin) { + reg.remove(plugin); + } + + /** + * Removes a class from the ConfigVarManager's registry + * + * @param plugin the plugin's main class + * @param clazz the class with configuration fields + */ + public static void unregister(JavaPlugin plugin, Object clazz) { + List lst = reg.getOrDefault(plugin, null); + if (lst == null) return; + + lst.remove(clazz); + + reg.put(plugin, lst); + } + + /** + * Updates every plugin's configuration + */ + public static void updateAll() { + for (JavaPlugin pl : reg.keySet()) { + update(pl); + } + } + + /** + * Updates configuration of a given plugin + * + * @param plugin the plugin's main class + */ + @SuppressWarnings("unchecked") + public static void update(JavaPlugin plugin) { + if (Desu.cfgnotify) + Logging.consoleLog(Desu.cl.colorizeInst("$eConfiguration of plugin -> $a" + plugin.getName() + "$e:")); + + plugin.reloadConfig(); + + boolean any = false; + + for (Object o : reg.get(plugin)) { + + any = true; + + Class cls = o.getClass(); + + try { + for (Field f : cls.getDeclaredFields()) { + try { + if (f.isAnnotationPresent(ConfigVar.class)) { + + String val = f.getAnnotation(ConfigVar.class).value(); + char color = f.getAnnotation(ConfigVar.class).color(); + Object cfg = plugin.getConfig().get(val); + + if (cfg instanceof String) { + if (color != ' ') + cfg = Colored.colorize(color, (String) cfg); + } else if (cfg instanceof List) { + List ll = (List) cfg; + if (!ll.isEmpty() && ll.get(0) instanceof String && color != ' ') { + List a = new ArrayList<>(); + //noinspection unchecked + for (String s : (List) ll) { + a.add(Colored.colorize(color, s)); + } + + cfg = a; + } + } + + //Logging.consoleLog(Desu.cl.colorizeInst("$eSET " + f.getName() +" TO " + cfg)); + + f.setAccessible(true); + f.set(f, cfg); + f.setAccessible(false); + + if (Desu.cfgnotify) + Logging.consoleLog(Desu.cl.colorizeInst("$e- $a" + f.getName() + "$e($a" + val + "$e) -> $a" + cfg + "$e!")); + + } + } catch (Exception ff) { + findExc(ff, plugin); + } + } + } catch (Exception e) { + //Logging.consoleLog(Desu.cl.colorizeInst("$4$lEXCEPTION " + e.getLocalizedMessage())); + findExc(e, plugin); + } + } + + if (!any && Desu.cfgnotify) { + Logging.consoleLog(Desu.cl.colorizeInst("$a-> no fields!")); + } + } + + private static void findExc(Exception e, JavaPlugin o) { + Class cls = o.getClass(); + boolean isdone = false; + for (Method m : cls.getMethods()) { + if (m.isAnnotationPresent(ConfigVarExceptionListener.class)) { + try { + if (m.getParameterCount() == 1) { + m.invoke(o, new ConfigVarException(e)); + isdone = true; + } else if (m.getParameterCount() == 0) { + m.invoke(o); + isdone = true; + } + } catch (Exception ee) { + ee.printStackTrace(); + } + } + } + if (!isdone) { + if (Desu.cfgnotify) { + Logging.consoleLog(Desu.cl.colorizeInst("$4[$c" + o.getName() + "$4] Error: $c" + e.getClass().getName() + "$4...", + "$4" + e.getMessage(), "$4At: " + e.getLocalizedMessage())); + } + } + } +} \ No newline at end of file diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/BlockEvents.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/BlockEvents.java new file mode 100644 index 0000000..8b3c8ae --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/BlockEvents.java @@ -0,0 +1,19 @@ +package me.yuri.yuriapi.api.utils.metadata; + +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; + +public class BlockEvents { + private BlockEvents() { + } + + @Deprecated + public static void _hcdx(BlockPlaceEvent e) { + + } + + @Deprecated + public static void _g43g23(BlockBreakEvent e) { + BlockMetaStorage.entries.remove(e.getBlock()); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/BlockMetaEntry.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/BlockMetaEntry.java new file mode 100644 index 0000000..e049d66 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/BlockMetaEntry.java @@ -0,0 +1,133 @@ +package me.yuri.yuriapi.api.utils.metadata; + +import com.google.common.primitives.Ints; +import com.google.common.primitives.Longs; +import me.yuri.yuriapi.api.utils.UUIDUtils; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.plugin.Plugin; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import java.util.UUID; + +public class BlockMetaEntry { + private final String key; + private final Plugin plugin; + private final MetadataType type; + private final String pluginName; + private V value; + + protected BlockMetaEntry(Plugin plugin, String key, MetadataType type, V value) { + this.plugin = plugin; + this.key = key; + this.type = type; + this.value = value; + this.pluginName = plugin.getName(); + } + + @SuppressWarnings("unchecked") + public static BlockMetaEntry fromByteArray(int id, String plugin, String key, byte[] value) { + return new BlockMetaEntry<>(Objects.requireNonNull(Bukkit.getPluginManager().getPlugin(plugin)), key, (MetadataType) MetadataType.fromId(id), valueFromByteArray(id, value)); + } + + public static Object valueFromByteArray(int typeid, byte[] value) { + switch (typeid) { + case 0: + return Ints.fromByteArray(value); + case 1: + return value; + case 2: + return UUIDUtils.toUUID(value); + case 3: + return Longs.fromByteArray(value); + case 4: + ByteBuffer bb = ByteBuffer.wrap(value); + int nameLen = bb.getInt(); + byte[] wrld = new byte[nameLen]; + bb.get(wrld); + String world = new String(wrld, StandardCharsets.UTF_8); + double x = bb.getDouble(), y = bb.getDouble(), z = bb.getDouble(); + return new Location(Bukkit.getWorld(world), x, y, z); + case 5: + assert value.length == 1 && (value[0] == 1 || value[0] == 0); + return value[0] == 1; + case 6: + ByteBuffer bbb = ByteBuffer.wrap(value); + int len = bbb.getInt(); + byte[] b = new byte[len]; + bbb.get(b); + return new String(b, StandardCharsets.UTF_8); + case 7: + return ByteBuffer.wrap(value).getFloat(); + case 8: + return ByteBuffer.wrap(value).getDouble(); + default: + throw new RuntimeException("Invalid ID: " + typeid); + } + } + + public String getKey() { + return key; + } + + public MetadataType getType() { + return type; + } + + public V getValue() { + return value; + } + + public void setValue(V value) { + this.value = value; + } + + public Plugin getPlugin() { + return plugin; + } + + public byte[] valueToByteArray() { + switch (type.getTypeValue()) { + case 0: + return Ints.toByteArray((int) value); + case 1: + return (byte[]) value; + case 2: + return UUIDUtils.toByteArray((UUID) value); + case 3: + return Longs.toByteArray((long) value); + case 4: + Location l = (Location) value; + byte[] name = Objects.requireNonNull(l.getWorld()).getName().getBytes(StandardCharsets.UTF_8); + int namelen = name.length; + ByteBuffer bu = ByteBuffer.allocate(name.length + 28); + bu.putInt(namelen); + bu.put(name); + bu.putDouble(l.getX()); + bu.putDouble(l.getY()); + bu.putDouble(l.getZ()); + return bu.array(); + case 5: + return new byte[]{(byte) ((boolean) value ? 1 : 0)}; + case 6: + String val = (String) value; + byte[] b = val.getBytes(StandardCharsets.UTF_8); + ByteBuffer buff = ByteBuffer.allocate(4 + b.length); + buff.putInt(b.length); + buff.put(b); + return buff.array(); + case 7: + return ByteBuffer.allocate(4).putFloat((float) value).array(); + case 8: + return ByteBuffer.allocate(8).putDouble((double) value).array(); + default: + throw new RuntimeException("Invalid ID: " + type.getTypeValue()); + } + } + + public String getPluginName() { + return pluginName; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/BlockMetaEntryContainer.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/BlockMetaEntryContainer.java new file mode 100644 index 0000000..0dd071f --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/BlockMetaEntryContainer.java @@ -0,0 +1,83 @@ +package me.yuri.yuriapi.api.utils.metadata; + +import com.google.common.primitives.Ints; +import com.google.common.primitives.Shorts; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +public class BlockMetaEntryContainer { + + protected List> metaEntries = new ArrayList<>(); + + protected BlockMetaEntryContainer() { + } + + public static BlockMetaEntryContainer fromByteArray(byte[] container) { + BlockMetaEntryContainer cntn = new BlockMetaEntryContainer(); + ByteArrayInputStream bis = new ByteArrayInputStream(container); + try { + int read = 0; + while (read < container.length) { + + int entryLen = Ints.fromByteArray(bis.readNBytes(4)); + int typeId = bis.read(); + short pl = Shorts.fromByteArray(bis.readNBytes(2)); + short keyLen = Shorts.fromByteArray(bis.readNBytes(2)); + int valLen = Ints.fromByteArray(bis.readNBytes(4)); + + String key = new String(bis.readNBytes(keyLen)); + byte[] val = bis.readNBytes(valLen); + + cntn.metaEntries.add(BlockMetaEntry.fromByteArray(typeId, BlockMetaStorage.findValue(pl), key, val)); + + read += entryLen; + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + bis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return cntn; + } + + public byte[] toByteArray() { + int len = 0; + List buffers = new ArrayList<>(); + for (BlockMetaEntry en : metaEntries) { + + byte typeId = (byte) en.getType().getTypeValue(); + short pl = BlockMetaStorage.pluginmap.get(en.getPluginName()); + byte[] key = en.getKey().getBytes(StandardCharsets.UTF_8); + short keyLen = (short) key.length; + byte[] val = en.valueToByteArray(); + int valLen = val.length; + int entryLen = 1 + 2 * 2 + 2 * 4 + keyLen + valLen; + + //1-4 - entryLen, 5 - typeId, 6-7 - plugin id, 8-9 - key len, 10-13 - vallen, 14... key, ?... val; + buffers.add(ByteBuffer.allocate(entryLen).putInt(entryLen).put(typeId).putShort(pl).putShort(keyLen).putInt(valLen).put(key).put(val)); + len += entryLen; + } + + ByteBuffer fin = ByteBuffer.allocate(len); + + for (ByteBuffer bb : buffers) { + fin.put(bb.array()); + } + + return fin.array(); + } + + public void set(JavaPlugin pl, String key, MetadataType type, V val) { + metaEntries.add(new BlockMetaEntry<>(pl, key, type, val)); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/BlockMetaStorage.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/BlockMetaStorage.java new file mode 100644 index 0000000..9190e13 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/BlockMetaStorage.java @@ -0,0 +1,218 @@ +package me.yuri.yuriapi.api.utils.metadata; + +import com.google.common.primitives.Ints; +import com.google.common.primitives.Shorts; +import me.yuri.yuriapi.api.utils.Colored; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.stream.Collectors; + +public class BlockMetaStorage { + + private static final File DATA_FILE = new File("blockdata.ydf"); + + protected static Map pluginmap = new HashMap<>(); + protected static Map entries = new HashMap<>(); + + protected static String findValue(short pluginId) { + return pluginmap.entrySet().stream().filter(c -> c.getValue() == pluginId).findFirst().orElseThrow().getKey(); + } + + public static void save() { + List> l = entries.entrySet().stream().sorted(Comparator.comparing(w -> w.getKey().getWorld().getName())).collect(Collectors.toList()); + + if (!DATA_FILE.exists()) { + try { + if (!DATA_FILE.createNewFile()) { + Bukkit.getConsoleSender().sendMessage(Colored.colorize("&4&lUnable to create block data file!")); + return; + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + Bukkit.getConsoleSender().sendMessage(Colored.colorize("&aSaving block metadata to file.")); + + try { + FileOutputStream fos = new FileOutputStream(DATA_FILE, false); + + byte[] version = {1, 0, 1}; //first 3 bytes - version, bytes 4-7 -> world len, bytes 8-[8+len] -> utf8 world + + fos.write(version); + + Map> worlds = new HashMap<>(); + + Map worldLengthMap = new HashMap<>(); + + entries.values().forEach(c -> c.metaEntries.forEach(cc -> pluginmap.putIfAbsent(cc.getPluginName(), (short) pluginmap.size()))); + + Bukkit.getConsoleSender().sendMessage(Colored.colorize("&eMapping plugins.")); + fos.write(Shorts.toByteArray((short) pluginmap.size())); + for (Map.Entry pluginEntry : pluginmap.entrySet()) { + byte[] pluginname = pluginEntry.getKey().getBytes(StandardCharsets.UTF_8); + fos.write(Shorts.toByteArray(pluginEntry.getValue())); + fos.write(pluginname.length); + fos.write(pluginname); + } + + Bukkit.getConsoleSender().sendMessage(Colored.colorize("&eSaving blocks.")); + + for (Map.Entry cnt : l) { + if (!worlds.containsKey(cnt.getKey().getWorld())) { + worlds.put(cnt.getKey().getWorld(), new ArrayList<>()); + worldLengthMap.put(cnt.getKey().getWorld(), 0); + } + + Block b = cnt.getKey(); + int x = b.getX(), y = b.getY(), z = b.getZ(); + + byte[] container = cnt.getValue().toByteArray(); + int conlen = (12 + container.length); + ByteBuffer bu = ByteBuffer.allocate(conlen); + bu.putInt(x).putInt(y).putInt(z).put(container); + + worlds.get(cnt.getKey().getWorld()).add(bu); + worldLengthMap.put(cnt.getKey().getWorld(), + worldLengthMap.getOrDefault(cnt.getKey().getWorld(), 0) + conlen); + } + + for (Map.Entry> ents : worlds.entrySet()) { + byte[] wrld = ents.getKey().getName().getBytes(StandardCharsets.UTF_8); + int worldLength = wrld.length; + + fos.write(worldLength); + fos.write(wrld); + + fos.write(Ints.toByteArray(worldLengthMap.get(ents.getKey()))); + + for (ByteBuffer buffer : ents.getValue()) { + byte[] buf = buffer.array(); + fos.write(Ints.toByteArray(buf.length)); + fos.write(buf); + } + + } + + fos.flush(); + fos.close(); + + Bukkit.getConsoleSender().sendMessage(Colored.colorize("&aDone.")); + } catch (Exception e) { + e.printStackTrace(); + } + + pluginmap.clear(); + } + + public static void init() { + if (!DATA_FILE.exists()) { + Bukkit.getConsoleSender().sendMessage(Colored.colorize("&cNo block metadata file found, aborting...")); + return; + } + + Bukkit.getConsoleSender().sendMessage(Colored.colorize("&aLoading block metadata.")); + + try { + FileInputStream fis = new FileInputStream(DATA_FILE); + + byte[] version = fis.readNBytes(3); + Bukkit.getConsoleSender().sendMessage(Colored.colorize("&eVersion: " + version[0] + "." + version[1] + "." + version[2])); + + Bukkit.getConsoleSender().sendMessage(Colored.colorize("&eReading plugin map...")); + short plugincount = Shorts.fromByteArray(fis.readNBytes(2)); + + for (int i = 0; i < plugincount; i++) { + short id = Shorts.fromByteArray(fis.readNBytes(2)); + int namelen = fis.read(); + String name = new String(fis.readNBytes(namelen), StandardCharsets.UTF_8); + pluginmap.put(name, id); + } + + Bukkit.getConsoleSender().sendMessage(Colored.colorize("&eRetrieving blocks...")); + + while (fis.available() > 0) { + int worldLen = fis.read(); + String worldname = new String(fis.readNBytes(worldLen), StandardCharsets.UTF_8); + World w = Bukkit.getWorld(worldname); + assert w != null; + + int lenToNextWorld = Ints.fromByteArray(fis.readNBytes(4)); + int read = 0; + + while (read < lenToNextWorld) { + int blockEntryLength = Ints.fromByteArray(fis.readNBytes(4)); + + int x = Ints.fromByteArray(fis.readNBytes(4)), + y = Ints.fromByteArray(fis.readNBytes(4)), + z = Ints.fromByteArray(fis.readNBytes(4)); + + byte[] container = fis.readNBytes((blockEntryLength - 12)); + + BlockMetaEntryContainer cnt = BlockMetaEntryContainer.fromByteArray(container); + + entries.put(w.getBlockAt(x, y, z), cnt); + + read += blockEntryLength; + } + } + + fis.close(); + + Bukkit.getConsoleSender().sendMessage(Colored.colorize("&aDone.")); + } catch (Exception e) { + e.printStackTrace(); + } + + pluginmap.clear(); + } + + public static void setMeta(Block b, JavaPlugin pl, String key, MetadataType type, V val) { + entries.putIfAbsent(b, new BlockMetaEntryContainer()); + entries.get(b).set(pl, key, type, val); + } + + public static BlockMetaEntry removeMeta(Block b, JavaPlugin pl, String key) { + BlockMetaEntryContainer ent = entries.get(b); + if (ent == null) return null; + return entries.get(b).metaEntries.stream().filter(c -> c.getPlugin().equals(pl) && c.getValue().equals(key)).findFirst().orElse(null); + } + + public static boolean hasMeta(Block b, JavaPlugin pl, String key) { + BlockMetaEntryContainer ent = entries.get(b); + if (ent == null) return false; + return ent.metaEntries.stream().anyMatch(c -> c.getPlugin().equals(pl) && c.getKey().equals(key)); + } + + public static boolean hasMetaAny(Block b, String key) { + BlockMetaEntryContainer ent = entries.get(b); + if (ent == null) return false; + return ent.metaEntries.stream().anyMatch(c -> c.getKey().equals(key)); + } + + @SuppressWarnings("unchecked") + public static BlockMetaEntry getMeta(Block b, JavaPlugin pl, String key, MetadataType type) { + BlockMetaEntryContainer ent = entries.get(b); + if (ent == null) return null; + Optional> opt = ent.metaEntries.stream().filter(c -> c.getPlugin().equals(pl) && c.getKey().equals(key)).findFirst(); + BlockMetaEntry entry = opt.orElse(null); + + if (entry == null) + return null; + + if (!entry.getType().equals(type)) + throw new IllegalArgumentException(String.format("Invalid type provided: %s, expected: %s", type.getTypeValue(), entry.getType().getTypeValue())); + + return (BlockMetaEntry) entry; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/KeyFactory.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/KeyFactory.java new file mode 100644 index 0000000..375f7a4 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/KeyFactory.java @@ -0,0 +1,10 @@ +package me.yuri.yuriapi.api.utils.metadata; + +import org.bukkit.NamespacedKey; +import org.bukkit.plugin.java.JavaPlugin; + +public class KeyFactory { + public static NamespacedKey getKeyFor(JavaPlugin pl, String key) { + return new NamespacedKey(pl, key); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/MetadataType.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/MetadataType.java new file mode 100644 index 0000000..58e45c7 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/MetadataType.java @@ -0,0 +1,65 @@ +package me.yuri.yuriapi.api.utils.metadata; + +import org.bukkit.Location; + +import javax.annotation.Nonnull; +import java.util.UUID; + +public class MetadataType { + public static final MetadataType INTEGER = new MetadataType<>(Integer.class, Integer.class, 0); + public static final MetadataType BYTE_ARRAY = new MetadataType<>(byte[].class, byte[].class, 1); + public static final MetadataType UUID = new MetadataType<>(byte[].class, UUID.class, 2); + public static final MetadataType LONG = new MetadataType<>(Long.class, Long.class, 3); + public static final MetadataType LOCATION = new MetadataType<>(String.class, Location.class, 4); + public static final MetadataType BOOLEAN = new MetadataType<>(Boolean.class, Boolean.class, 5); + public static final MetadataType STRING = new MetadataType<>(String.class, String.class, 6); + public static final MetadataType FLOAT = new MetadataType<>(Float.class, Float.class, 7); + public static final MetadataType DOUBLE = new MetadataType<>(Double.class, Double.class, 8); + + private final Class type; + private final Class datatype; + private final int id; + + private MetadataType(@Nonnull Class type, @Nonnull Class datatype, int id) { + this.type = type; + this.datatype = datatype; + this.id = id; + } + + public static MetadataType fromId(int id) { + switch (id) { + case 0: + return INTEGER; + case 1: + return BYTE_ARRAY; + case 2: + return UUID; + case 3: + return LONG; + case 4: + return LOCATION; + case 5: + return BOOLEAN; + case 6: + return STRING; + case 7: + return FLOAT; + case 8: + return DOUBLE; + default: + throw new RuntimeException("Invalid ID: " + id); + } + } + + public int getTypeValue() { + return id; + } + + public Class getRawType() { + return type; + } + + public Class getBoxedType() { + return datatype; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/NBTMetadata.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/NBTMetadata.java new file mode 100644 index 0000000..0a604e1 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/api/utils/metadata/NBTMetadata.java @@ -0,0 +1,86 @@ +package me.yuri.yuriapi.api.utils.metadata; + +public class NBTMetadata { + + /*public static void setMetadata(org.bukkit.inventory.ItemStack item, String metadata, Object value) { + setMetadata(CraftItemStack.asNMSCopy(item), metadata, value); + } + + public static void setMetadata(ItemStack item, String metadata, Object value) { + NBTTagCompound tag = item.getTag(); + if (tag == null) { + tag = new NBTTagCompound(); + } + setTag(tag, metadata, value); + item.setTag(tag); + } + + public static boolean hasMetadata(org.bukkit.inventory.ItemStack item, String metadata) { + return hasMetadata(CraftItemStack.asNMSCopy(item), metadata); + } + + public static boolean hasMetadata(ItemStack item, String metadata) { + return Objects.requireNonNull(item.getTag()).hasKey(metadata); + } + + public static Object getMetadata(org.bukkit.inventory.ItemStack item, String metadata) { + return getMetadata(CraftItemStack.asNMSCopy(item), metadata); + } + + public static Object getMetadata(ItemStack item, String metadata) { + return getObject(Objects.requireNonNull(item.getTag()).get(metadata)); + } + + private static NBTTagCompound setTag(NBTTagCompound tag, String tagString, Object value) { + + if (value instanceof Boolean) { + tag.setBoolean(tagString, (Boolean) value); + } else if (value instanceof Integer) { + tag.setInt(tagString, (Integer) value); + } else if (value instanceof Byte) { + tag.setByte(tagString, (Byte) value); + } else if (value instanceof Double) { + tag.setDouble(tagString, (Double) value); + } else if (value instanceof Float) { + tag.setFloat(tagString, (Float) value); + } else if (value instanceof String) { + tag.setString(tagString, (String) value); + } else if (value instanceof Short) { + tag.setShort(tagString, (Short) value); + } else if (value instanceof Long) { + tag.setLong(tagString, (Long) value); + } + + return tag; + } + + private static Object getObject(NBTBase tag) { + if (tag instanceof NBTTagEnd) { + return null; + } else if (tag instanceof NBTTagByte) { + return ((NBTTagByte) tag).asByte(); + } else if (tag instanceof NBTTagShort) { + return ((NBTTagShort) tag).asShort(); + } else if (tag instanceof NBTTagInt) { + return ((NBTTagInt) tag).asInt(); + } else if (tag instanceof NBTTagLong) { + return ((NBTTagLong) tag).asLong(); + } else if (tag instanceof NBTTagFloat) { + return ((NBTTagFloat) tag).asFloat(); + } else if (tag instanceof NBTTagDouble) { + return ((NBTTagDouble) tag).asDouble(); + } else if (tag instanceof NBTTagByteArray) { + return ((NBTTagByteArray) tag).getBytes(); + } else if (tag instanceof NBTTagString) { + return tag.asString(); + } else if (tag instanceof NBTTagList) { + return ((NBTTagList) tag).toArray(); + } else if (tag instanceof NBTTagCompound) { + return tag; + } else if (tag instanceof NBTTagIntArray) { + return ((NBTTagIntArray) tag).toArray(); + } + return null; + }*/ + +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/commands/CommandAnalyzer.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/commands/CommandAnalyzer.java new file mode 100755 index 0000000..1830f1a --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/commands/CommandAnalyzer.java @@ -0,0 +1,24 @@ +package me.yuri.yuriapi.commands; + +import me.yuri.yuriapi.APIBridge; +import me.yuri.yuriapi.Desu; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; + +import javax.annotation.Nonnull; + +public class CommandAnalyzer implements CommandExecutor { + @Override + public boolean onCommand(@Nonnull CommandSender s, + @Nonnull Command command, + @Nonnull String l, String[] args) { + if (args.length > 0) + s.sendMessage(Desu.cl.colorizeInst("$3This command does not require any arguments...")); + APIBridge.getMainPluginInstance().getConfig().set("analyzer", true); + APIBridge.getMainPluginInstance().saveConfig(); + Desu.analyze = true; + s.sendMessage(Desu.cl.colorizeInst("$aAnalyzer enabled!")); + return true; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/commands/CommandYAPI.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/commands/CommandYAPI.java new file mode 100755 index 0000000..5d87a00 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/commands/CommandYAPI.java @@ -0,0 +1,154 @@ +package me.yuri.yuriapi.commands; + +import me.yuri.yuriapi.APIBridge; +import me.yuri.yuriapi.Desu; +import me.yuri.yuriapi.SystemInfo; +import me.yuri.yuriapi.VerCheck; +import me.yuri.yuriapi.api.item.CustomItem; +import me.yuri.yuriapi.api.item.ItemRegistry; +import me.yuri.yuriapi.api.utils.Colored; +import me.yuri.yuriapi.api.utils.configuration.ConfigVarManager; +import me.yuri.yuriapi.utils.Logging; +import org.apache.commons.io.FileUtils; +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import javax.annotation.Nonnull; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public class CommandYAPI implements CommandExecutor { + + private static final List sss = new ArrayList<>(); + + public void checkForCmds() { + for (String ss : sss) { + //TODO FLUSH CMDS + } + sss.clear(); + + } + + public boolean onCommand(@Nonnull CommandSender s, @Nonnull Command command, @Nonnull String l, String[] args) { + /*String a = l.toLowerCase(); + for(String ss : args){ + a = ss+" "; + } + sss.add(a.trim()); + if(sss.size() >= 20) + checkForCmds(); + - Cmd Log*/ + + if (args.length == 0) { + s.sendMessage(Desu.cl.colorizeInst( + "$cYuriAPI$6, version $c" + APIBridge.getMainPluginInstance().getDescription().getVersion() + "$6, running on $c" + + Bukkit.getServer().getName() + "$6, Spigot version $c" + Bukkit.getVersion() + "$6!", + "$6For more information type $c/" + l + " help")); + return true; + } else { + + //HELP MESSAGE + if (args[0].equalsIgnoreCase("help")) { + s.sendMessage(Desu.cl.colorizeInst("$6YuriAPI command list:", + "$c/" + l + " help $6- show list of commands", + "$c/" + l + " items [player] $6- get or give custom items", + "$c/" + l + " updates $6- check if new version exists", + "$c/" + l + " download $6- download new version (if exists)", + "$c/" + l + " reloadcfg $6- reload the configuration file", + "$c/" + l + " sysinfo $6- print neofetch style server info", + "$c/" + l + " stop $6- stop server")); + return true; + } + + if (args[0].equalsIgnoreCase("reloadcfg")) { + ConfigVarManager.update(Desu.getMain()); + s.sendMessage(Desu.cl.colorizeInst("$aConfiguration reloaded successfully!")); + return true; + } + + //CHECK UPDATE + if (args[0].equalsIgnoreCase("updates")) { + String s1 = VerCheck.getNewVersion(); //FIXME LATER + if (s1 == null || s1.equalsIgnoreCase(APIBridge.getMainPluginInstance().getDescription().getVersion()) || s1.trim().equals("")) { + s.sendMessage(Desu.cl.colorizeInst("$aYuriAPI is currently up-to-date ($b" + s1 + "$a)")); + } else { + s.sendMessage(Desu.cl.colorizeInst("$cThere is a new version of YuriAPI ($e" + s1 + "$c). Type $e" + l + " download $cto download new version!")); + } + return true; + } + + //DOWNLOAD UPDATE + if (args[0].equalsIgnoreCase("download")) { + if (VerCheck.isUpdate(APIBridge.getMainPluginInstance().getDescription().getVersion())) { + try { + FileUtils.copyInputStreamToFile(Objects.requireNonNull(VerCheck.getLatestFile()), new File(APIBridge.getMainPluginInstance().getDataFolder().getPath() + "/YuriAPI.jar")); + s.sendMessage(Desu.cl.colorizeInst("$aNew version downloaded!")); + } catch (IOException e) { + Logging.consoleLog(e.getLocalizedMessage()); + s.sendMessage(Desu.cl.colorizeInst("$4Unable to download new version! Exception " + e.getClass().getName() + " occurred! Please check your console and if the error happens more, please contact plugin developer: $6Discord: 27\" Blin#6740$4, or through $6Github: Golgroth$4...")); + } + + } else { + s.sendMessage(Desu.cl.colorizeInst("$cThere is no newer versions!")); + } + return true; + } + + if (args[0].equalsIgnoreCase("sysinfo")) { + s.sendMessage(new SystemInfo().buildInfo()); + return true; + } + } + + if (args[0].equalsIgnoreCase("items")) { + if (!(s instanceof Player)) { + s.sendMessage(Desu.cl.colorizeInst("$cYou are not a player!")); + return true; + } + + if (args.length < 2) { + s.sendMessage("$cYou need to specify argument $6.$c"); + return true; + } + + CustomItem ci = ItemRegistry.getItem(args[1]); + if (ci == null) { + s.sendMessage(Desu.cl.colorizeInst("$cInvalid item name!")); + return true; + } + Player target = (Player) s; + if (args.length >= 3) { + target = Bukkit.getPlayer(args[2]); + if (target == null) { + s.sendMessage(Desu.cl.colorizeInst("$cInvalid player: $6" + args[2] + "$c!")); + return true; + } + } + + target.getInventory().addItem(ci.getItemstack()); + target.sendMessage(Desu.cl.colorizeInst("$aItem added.")); + return true; + } + + if (args[0].equalsIgnoreCase("stop")) { + String msg = Colored.colorize(args.length > 1 ? Arrays.stream(args).skip(1).collect(Collectors.joining(" ")) : "&cServer restart, please &4&lrejoin in &b&l30 &4&lseconds&c."); + Bukkit.broadcastMessage(msg); + for (Player p : Bukkit.getOnlinePlayers()) { + p.kickPlayer(msg); + } + Bukkit.shutdown(); + return true; + } + + s.sendMessage(Desu.cl.colorizeInst("$cNo such command! Type $6" + l + " help$c!")); + return true; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/commands/CommandsPermissions.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/commands/CommandsPermissions.java new file mode 100644 index 0000000..5829770 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/commands/CommandsPermissions.java @@ -0,0 +1,103 @@ +package me.yuri.yuriapi.commands; + +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.command.Cmd; +import me.yuri.yuriapi.api.command.CommandEvent; +import me.yuri.yuriapi.api.command.CommandTabCompleteEvent; +import me.yuri.yuriapi.api.command.TabCompletion; +import me.yuri.yuriapi.api.permission.PermissionManager; +import me.yuri.yuriapi.api.permission.YPermissionGroup; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.util.StringUtil; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class CommandsPermissions { + + @Cmd(command = "perms", permissions = "admin") + public void perm(CommandEvent e) { + if (e.getArgs().length < 4) { + e.reply("&cMissing args."); + return; + } + + int op = -1; + if (e.getArgs()[0].equalsIgnoreCase("add")) { + op = 0; + } else if (e.getArgs()[0].equalsIgnoreCase("remove")) { + op = 1; + } + + if (op == -1) { + e.reply("&cInvalid operation &b" + e.getArgs()[0] + "+&c."); + return; + } + + int type = -1; + if (e.getArgs()[1].equalsIgnoreCase("group")) { + type = 0; + } + + if (type == -1) { + e.reply("&cInvalid type &b" + e.getArgs()[1] + "+&c."); + return; + } + + YPlayer target = YPlayer.get(e.getArgs()[2]); + OfflinePlayer ofltarget = null; + if (target == null) { + ofltarget = YPlayer.getOfflinePlayer(e.getArgs()[2]); + if (ofltarget == null) { + e.reply("&cInvalid player &b" + e.getArgs()[2] + "&c."); + return; + } + } + + if (type == 0) { //MIGHT CHANGE TO INDIVIDUAL + YPermissionGroup g = PermissionManager.getByName(e.getArgs()[3], true); + if (g == null) { + e.reply("&cInvalid group."); + return; + } + if (op == 0) { + if (target == null) { + PermissionManager.setOffline(ofltarget, g, true); + } else { + target.assignGroup(g); + } + e.reply("&aPlayer assigned to group."); + } else { + boolean b; + if (target == null) { + b = PermissionManager.setOffline(ofltarget, g, false); + } else { + b = target.removeFromGroup(g); + } + e.reply(b ? String.format("&aRemoved &b%s&a from &b%s&a.", target == null ? ofltarget.getName() : target.getBasePlayer().getDisplayName(), g.getName()) : "&cPlayer is not assigned to this group."); + } + } + } + + @TabCompletion(command = "perms") + public List permComplete(CommandTabCompleteEvent e) { + switch (e.getArgs().length) { + case 1: + return Arrays.asList("add", "remove"); + case 2: + return Collections.singletonList("group"); + case 3: + List l = new ArrayList<>(); + StringUtil.copyPartialMatches(e.getArgs()[2], Arrays.stream(Bukkit.getOfflinePlayers()).map(OfflinePlayer::getName).collect(Collectors.toList()), l); + return l; + case 4: + return PermissionManager.getGroups().stream().map(YPermissionGroup::getName).collect(Collectors.toList()); + default: + return Collections.emptyList(); + } + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/commands/TabCompleteYAPI.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/commands/TabCompleteYAPI.java new file mode 100644 index 0000000..d3df556 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/commands/TabCompleteYAPI.java @@ -0,0 +1,40 @@ +package me.yuri.yuriapi.commands; + +import me.yuri.yuriapi.api.item.ItemRegistry; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.util.StringUtil; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class TabCompleteYAPI implements TabCompleter { + + private static final List poss = Arrays.asList("help", "updates", "items", "download", "reloadcfg", "sysinfo", "stop"); + + @Override + public List onTabComplete(@Nonnull CommandSender s, @Nonnull Command c, @Nonnull String l, String[] args) { + List ll = new ArrayList<>(); + switch (args.length) { + case 1: + StringUtil.copyPartialMatches(args[0], poss, ll); + break; + case 2: + if (!args[0].equalsIgnoreCase("items")) + break; + StringUtil.copyPartialMatches(args[1], ItemRegistry.getAllItems().stream().map(i -> i.getKey().toString()).collect(Collectors.toList()), ll); + break; + case 3: + if (args[0].equalsIgnoreCase("items")) + return null; + default: + break; + } + + return ll; + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/utils/ChunkUtil.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/utils/ChunkUtil.java new file mode 100644 index 0000000..ab03497 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/utils/ChunkUtil.java @@ -0,0 +1,19 @@ +package me.yuri.yuriapi.utils; + +import org.bukkit.Chunk; +import org.bukkit.World; + +public final class ChunkUtil { + private ChunkUtil() { + } + + public static long toLong(Chunk c) { + return (((long) c.getX()) << 32) | (c.getZ() & 0xffffffffL); + } + + public static Chunk fromLong(World w, long l) { + int x = (int) (l >> 32); + int z = (int) l; + return w.getChunkAt(x, z); + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/utils/ColorConverter.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/utils/ColorConverter.java new file mode 100644 index 0000000..fa44dbb --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/utils/ColorConverter.java @@ -0,0 +1,30 @@ +package me.yuri.yuriapi.utils; + +import java.awt.*; +import java.awt.image.DataBuffer; +import java.awt.image.IndexColorModel; +import java.util.List; + +public class ColorConverter { + private final java.util.List colors; + private final IndexColorModel colorModel; + + public ColorConverter(List colors) { + this.colors = colors; + this.colorModel = createColorModel(colors); + } + + private static IndexColorModel createColorModel(List colors) { + final int[] cmap = new int[colors.size()]; + for (int i = 0; i < colors.size(); i++) { + cmap[i] = colors.get(i).getRGB(); + } + final int bits = (int) Math.ceil(Math.log(cmap.length) / Math.log(2)); + return new IndexColorModel(bits, cmap.length, cmap, 0, false, -1, DataBuffer.TYPE_BYTE); + } + + public Color nearestColor(Color color) { + final byte index = ((byte[]) colorModel.getDataElements(color.getRGB(), null))[0]; + return colors.get(index); + } +} \ No newline at end of file diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/utils/DbManager.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/utils/DbManager.java new file mode 100644 index 0000000..81992d6 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/utils/DbManager.java @@ -0,0 +1,94 @@ +package me.yuri.yuriapi.utils; + +import me.yuri.yuriapi.Desu; +import me.yuri.yuriapi.api.db.DbColumnDataType; +import me.yuri.yuriapi.api.db.DbConnection; +import me.yuri.yuriapi.api.db.DbConnectionBuilder; +import me.yuri.yuriapi.api.db.DbTable; +import me.yuri.yuriapi.api.economy.EconomyManager; +import me.yuri.yuriapi.api.utils.Colored; +import org.bukkit.Bukkit; + +import java.io.File; + +public class DbManager { + + private static DbTable FUNDS_TABLE, NICK_TABLE, PERMISSION_GROUP_TABLE, IP_TABLE; + + private static DbConnection connection; + private static boolean init = false; + + @Deprecated + public static void init() { + if (init) return; + init = true; + + connection = new DbConnectionBuilder(DbConnectionBuilder.DbType.SQLITE) + .withConnectionString("jdbc:sqlite:" + new File(Desu.getMain().getDataFolder(), "data.db")) + .withTable("funds", t -> t + .withPrimaryKey("uuid", DbColumnDataType.UUID) + .withColumn("funds", DbColumnDataType.INTEGER, false) + .withColumn("time", DbColumnDataType.TIMESTAMP, false) + .build()) + .withTable("nicknames", t -> t + .withPrimaryKey("uuid", DbColumnDataType.UUID) + .withColumn("nickname", DbColumnDataType.TEXT, true) + .build()) + .withTable("permgroups", t -> t + .withPrimaryKey("uuid", DbColumnDataType.UUID) + .withColumn("groups", DbColumnDataType.TEXT).build()) + .withTable("ips", t -> t + .withPrimaryKey("ip", DbColumnDataType.TEXT) + .withColumn("uuids", DbColumnDataType.TEXT).build()) + .build(); + + FUNDS_TABLE = connection.getTable("funds"); + NICK_TABLE = connection.getTable("nicknames"); + IP_TABLE = connection.getTable("ips"); + PERMISSION_GROUP_TABLE = connection.getTable("permgroups"); + + try { + Logging.consoleLog(Desu.cl.colorizeInst("$aConnecting to database...")); + connection.connect(); + Logging.consoleLog(Desu.cl.colorizeInst("$aConnected to database.")); + EconomyManager.loadFromDbAsync().run(); + } catch (Exception e) { + Logging.consoleLog(Desu.cl.colorizeInst("$cCannot connect to the database!")); + e.printStackTrace(); + } + } + + @Deprecated + public static DbTable h(String a) { + switch (a) { + case "fd": + return FUNDS_TABLE; + case "nn": + return NICK_TABLE; + case "pg": + return PERMISSION_GROUP_TABLE; + case "ip": + return IP_TABLE; + default: + return null; + } + } + + @Deprecated + public static DbConnection z_() { + return connection; + } + + @Deprecated + public static void stop() { + try { + Logging.consoleLog(Colored.colorize("&aSaving changes to database!")); + EconomyManager.saveChanges(); + connection.disconnect(); + Logging.consoleLog(Colored.colorize("&aChanges saved!")); + } catch (Exception e){ + Logging.consoleLog(Colored.colorize("&4Cannot save changes!")); + e.printStackTrace(); + } + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/utils/Logging.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/utils/Logging.java new file mode 100644 index 0000000..84b9ce6 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/utils/Logging.java @@ -0,0 +1,14 @@ +package me.yuri.yuriapi.utils; + +import org.bukkit.Bukkit; + +public final class Logging { + private Logging() { + } + + public static void consoleLog(String... msg) { + for (String str : msg) { + Bukkit.getConsoleSender().sendMessage(str); + } + } +} diff --git a/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/utils/UtilsMisc.java b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/utils/UtilsMisc.java new file mode 100755 index 0000000..8da6f57 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/java/me/yuri/yuriapi/utils/UtilsMisc.java @@ -0,0 +1,25 @@ +package me.yuri.yuriapi.utils; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.lang.reflect.InvocationTargetException; + +public final class UtilsMisc { + private static final String v = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3]; + + private UtilsMisc() { + } + + static void sendPacket(Player p, Object packet) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, NoSuchFieldException, ClassNotFoundException { + Object nmsPlayer = p.getClass().getMethod("getHandle").invoke(p); + Object plrConnection = nmsPlayer.getClass().getField("playerConnection").get(nmsPlayer); + plrConnection.getClass().getMethod("sendPacket", getNmsClass("Packet")).invoke(plrConnection, packet); + } + + static Class getNmsClass(String nmsClassName) throws ClassNotFoundException { + return Class.forName("net.minecraft.server." + v + "." + nmsClassName); + } + + +} diff --git a/YuriPlugins/YuriAPI/src/main/pom.xml b/YuriPlugins/YuriAPI/src/main/pom.xml new file mode 100755 index 0000000..e64a12f --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + me.yuri + YuriAPI + 1.0-A + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + + + + org.spigotmc + spigot-api + 1.16.4-R0.1-SNAPSHOT + system + /home/yuri/Dev/java/_Spigot/build/spigot-1.16.4.jar + + + com.google.code.findbugs + jsr305 + 2.0.1 + + + commons-io + commons-io + 2.5 + + + + + \ No newline at end of file diff --git a/YuriPlugins/YuriAPI/src/main/resources/config.yml b/YuriPlugins/YuriAPI/src/main/resources/config.yml new file mode 100755 index 0000000..936a12b --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/resources/config.yml @@ -0,0 +1,110 @@ +################### +### --YuriAPI-- ### +################### + +#When new updated version is downloaded, remove the old YuriAPI.jar +#and move the new version from /plugins/YuriAPI to /plugins folder! +#~ Yuri + +#The server name +serverName: 'Default' + +#This setting determines whether should this plugin automatically update itself +autoUpdate: true + +#Analyzer module +analyzer: false + +#Enable this to use custom authentication server +useCustomAuthentication: false + +#Placeholders: +#&[0-9a-fl-o] - color codes +#{PLAYERNAME} - original player name +#{PLAYERDISPLAYNAME} - player name that is visible in the chat or over the player +#{PLAYERCUSTOMNAME} - player's internal designated custom name +#{PLAYERPLAYERLISTNAME} - player's name that is visible in the player list + +#If you leave them "null" then they will be default Minecraft ones... +#If you set them to "", they won't appear + +################ +# Common # +################ + +#Apply color codes on signs +signFormatting: true + +############################### +# Console notifications # +############################### + +#Command registry notificator +enableCommandRegistryNotifications: true + +#Config registry notificator +enableConfigUpdateNotifications: true + +##################### +# Server list # +##################### + +#Server list MOTD (leave empty to disable) +motd: + - '&aDefault Server' + +#Fake max players count (-1 to disable) +maxPlayers: -1 + +#Paths to server icons +serverIcons: + - "server-icon.png" + +#Join message +quitMessage: "null" + +#Quit message +joinMessage: "null" + +############################# +# Database connection # +############################# + +#The password of the database +databasePassword: 'password' + +################# +# Economy # +################# + +#Name of the currency +currencyName: 'Dogecoin' + +#The symbol of the currency +currencySymbol: 'Ð' + +############## +# Chat # +############## + +#Placeholders: +# - player display name +# - player name +# - custom player prefixes +# - player suffix +# - player group prefix +# - player health +# +#Chat specific: +# - actual player message + + +#The format of the player chat message +chatFormat: " &8&l>> " + +#The format of the private chat message display name +privName: " " + +#The format of the player name tag +playerTagFormat: " &7 &e[&c&4&l♥&e]" + diff --git a/YuriPlugins/YuriAPI/src/main/resources/permissions.yml b/YuriPlugins/YuriAPI/src/main/resources/permissions.yml new file mode 100644 index 0000000..88e1d26 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/resources/permissions.yml @@ -0,0 +1,17 @@ +#Prefix & suffix color code (default '&') +colorCode: '&' +#The default group assigned for every new player +default: 'player' +#Group definitions (higher in order - more important) +groups: + admin: + prefix: "&c&l(&4Admin&c&l)&6" + suffix: "&e&o" + permissions: + - '*.*' + player: + prefix: "&8&l(&7Player&8&l)&7" + suffix: "&f" + permissions: + - 'modifyworld.*' + - 'yuriessentials.spawn' \ No newline at end of file diff --git a/YuriPlugins/YuriAPI/src/main/resources/plugin.yml b/YuriPlugins/YuriAPI/src/main/resources/plugin.yml new file mode 100755 index 0000000..b20ff81 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/main/resources/plugin.yml @@ -0,0 +1,26 @@ +main: me.yuri.yuriapi.Desu +name: YuriAPI +version: 1.2.5 +description: An API required for most of my plugins and utility API for devs +load: STARTUP +author: Yuri +api-version: 1.16 + +commands: + yapi: + aliases: [ yuriapi, ya, yuri ] + permission: yuriapi.cmdyapi + enableanalyzer: + permission: yuriapi.cmdanalyzer + yuriitems: + aliases: [ yitems ] + permission: yuriapi.items + perms: + +permissions: + yuriapi.cmdyapi: + description: Base command permission + default: op + yuriapi.cmdanalyzer: + description: Analyzer enable command permission + default: op diff --git a/YuriPlugins/YuriAPI/src/test/java/me/yuri/test/ColorTest.java b/YuriPlugins/YuriAPI/src/test/java/me/yuri/test/ColorTest.java new file mode 100644 index 0000000..f79c010 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/test/java/me/yuri/test/ColorTest.java @@ -0,0 +1,30 @@ +package me.yuri.test; + +import org.junit.Test; + +public class ColorTest { + + @Test + public void ansi() { + System.out.print(ColorCode.CYAN + "this thing is in cyan\n"); + System.out.println(ColorCode.B_BLACK + "A" + ColorCode.B_BLUE + "B" + ColorCode.B_CYAN + "C" + ColorCode.B_GREEN + "D" + ColorCode.B_PURPLE + "E" + ColorCode.B_RED + "F" + ColorCode.B_YELLOW + "G" + ColorCode.B_WHITE + "H"); + } + + + public enum ColorCode { + BLACK("c[0;30m"), RED("c[0;31m"), GREEN("c[0;32m"), YELLOW("c[0;33m"), BLUE("c[0;34m"), PURPLE("c[0;35m"), CYAN("c[0;36m"), WHITE("c[0;37m"), + B_BLACK("c[1;30m"), B_RED("c[1;31m"), B_GREEN("c[1;32m"), B_YELLOW("c[1;33m"), B_BLUE("c[1;34m"), B_PURPLE("c[1;35m"), B_CYAN("c[1;36m"), B_WHITE("c[1;37m"), + RESET("c[0m"); + + private final String value; + + ColorCode(String val) { + this.value = val; + } + + @Override + public String toString() { + return value.replace("c[", (char) 27 + "["); + } + } +} diff --git a/YuriPlugins/YuriAPI/src/test/java/me/yuri/test/ReflectionTest.java b/YuriPlugins/YuriAPI/src/test/java/me/yuri/test/ReflectionTest.java new file mode 100644 index 0000000..f318fe2 --- /dev/null +++ b/YuriPlugins/YuriAPI/src/test/java/me/yuri/test/ReflectionTest.java @@ -0,0 +1,100 @@ +package me.yuri.test; + +import me.yuri.yuriapi.Desu; +import me.yuri.yuriapi.api.reflectionless.Reflectionless; +import org.junit.Test; + +import java.lang.reflect.Field; + +import static me.yuri.test.ColorTest.ColorCode.*; + +public class ReflectionTest { + + private static Class clazz = null; + private final int T = 1000000; + + @Test + public void reflection() { + int r1 = 5; + System.out.println(B_CYAN.toString() + r1 + " runs, each " + T + " iterations."); + for (int i = 0; i < r1; i++) { + System.out.println(B_GREEN + "---------------+RUN " + B_YELLOW + (i + 1) + B_GREEN + "+---------------"); + long r = withReflection(), c = withCachedReflection(), n = withNormal(), nr = withNR(); + System.out.print(BLUE); + System.out.println("Reflection: " + r + "ns (" + (r / 1000000) + "ms), avg: " + (r / T) + "ns/call"); + System.out.println("Cached reflection: " + c + "ns (" + (c / 1000000) + "ms), avg: " + (c / T) + "ns/call"); + System.out.println("Normal: " + n + "ns (" + (n / 1000000) + "ms), avg: " + (n / T) + "ns/call"); + System.out.println("NoReflection: " + nr + "ns (" + (nr / 1000000) + "ms), avg: " + (nr / T) + "ns/call"); + System.out.println(); + } + } + + private long withNR() { + Field c = null; + try { + c = Class.forName("me.yuri.yuriapi.Desu").getDeclaredField("cfgnotify"); + } catch (Exception e) { + e.printStackTrace(); + } + long s = System.nanoTime(); + + for (int i = 0; i < T; i++) { + try { + boolean b = (boolean) Reflectionless.get(c).get(null); + } catch (Exception ignored) { + } + } + + long f = System.nanoTime(); + + return f - s; + } + + private long withReflection() { + long s = System.nanoTime(); + + for (int i = 0; i < T; i++) { + try { + Class c = Class.forName("me.yuri.yuriapi.Desu"); + boolean b = clazz.getDeclaredField("cfgnotify").getBoolean(null); + } catch (Exception ignored) { + } + } + + long f = System.nanoTime(); + + return f - s; + } + + private long withCachedReflection() { + long s = System.nanoTime(); + + for (int i = 0; i < T; i++) { + try { + if (clazz == null) { + clazz = Class.forName("me.yuri.yuriapi.Desu"); + } + + boolean b = clazz.getDeclaredField("cfgnotify").getBoolean(null); + } catch (Exception ignored) { + } + } + + long f = System.nanoTime(); + + return f - s; + } + + private long withNormal() { + long s = System.nanoTime(); + + for (int i = 0; i < T; i++) { + boolean b = Desu.cfgnotify; + } + + long f = System.nanoTime(); + + return f - s; + } + +} diff --git a/YuriPlugins/YuriEssentials/pom.xml b/YuriPlugins/YuriEssentials/pom.xml new file mode 100644 index 0000000..58c1cc5 --- /dev/null +++ b/YuriPlugins/YuriEssentials/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + me.yuri + YuriEssentials + 1.0E-SNAPSHOT + + + me.yuri + YuriAPI + 1.2-SNAPSHOT + system + /home/yuri/Desktop/plugintest/plugins/YuriAPI.jar + + + org.xerial + sqlite-jdbc + 3.34.0 + + + com.github.dmulloy2 + ProtocolLib + 4.5.1 + + + org.spigotmc + spigot-api + 1.16.5-R0.1-SNAPSHOT + system + /home/yuri/Dev/java/spigot/build/latest.jar + + + + + + jitpack + https://jitpack.io/ + + + + + 8 + 8 + + + \ No newline at end of file diff --git a/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/Commands.java b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/Commands.java new file mode 100644 index 0000000..4bea824 --- /dev/null +++ b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/Commands.java @@ -0,0 +1,969 @@ +package me.yuri.essentials; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.ProtocolManager; +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.wrappers.EnumWrappers; +import com.comphenix.protocol.wrappers.PlayerInfoData; +import com.comphenix.protocol.wrappers.WrappedChatComponent; +import com.comphenix.protocol.wrappers.WrappedGameProfile; +import me.yuri.essentials.hologram.Hologram; +import me.yuri.essentials.hologram.HologramManager; +import me.yuri.yuriapi.MainListener; +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.command.*; +import me.yuri.yuriapi.api.db.DbComparisonType; +import me.yuri.yuriapi.api.db.DbQueryResult; +import me.yuri.yuriapi.api.economy.EconomyManager; +import me.yuri.yuriapi.api.inventory.InventoryBuilder; +import me.yuri.yuriapi.api.item.ItemBuilder; +import me.yuri.yuriapi.api.utils.Colored; +import me.yuri.yuriapi.api.utils.MessageBuilder; +import me.yuri.yuriapi.api.utils.PlaceholderUtils; +import me.yuri.yuriapi.api.utils.configuration.ConfigVarManager; +import me.yuri.yuriapi.api.utils.metadata.KeyFactory; +import net.md_5.bungee.api.ChatMessageType; +import org.bukkit.*; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeInstance; +import org.bukkit.block.Block; +import org.bukkit.block.Sign; +import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.help.HelpTopic; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.inventory.meta.Damageable; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.StringUtil; + +import java.lang.reflect.InvocationTargetException; +import java.util.*; +import java.util.stream.Collectors; + +public final class Commands { + @Cmd(command = "spawn", consoleSide = false, desc = "Teleport to spawn", permissions = {"spawn", "teleport"}) + public void spawn(PlayerCommandEvent c) { + Player p = c.getPlayer(); + if (c.getArgs().length == 1) { + if (c.getArgs()[0].equalsIgnoreCase("set") && c.getPlayer().hasPermission("yuriessentials.admin")) { + if (c.getSender().hasPermission("spawn.set")) + Yuri.getMain().getConfig().set("spawn.x", p.getLocation().getX()); + Yuri.getMain().getConfig().set("spawn.y", p.getLocation().getY()); + Yuri.getMain().getConfig().set("spawn.z", p.getLocation().getZ()); + Yuri.getMain().getConfig().set("spawn.world", Objects.requireNonNull(p.getLocation().getWorld()).getName()); + Yuri.getMain().saveConfig(); + ConfigVarManager.update(Yuri.getMain()); + c.reply("&aSpawn set!"); + } + return; + } + + if (Yuri.world == null || Yuri.world.equals("null")) { + c.reply("&cSpawn improperly configured!"); + } else { + long now = System.currentTimeMillis(); + new BukkitRunnable() { + int cnt = Yuri.cooldown; + + @Override + public void run() { + if (c.getPlayer().hasPermission("yuriessentials.admin")) { + cnt = 0; + } + if (cnt == 4) { + c.reply("&eTeleporting to &aspawn&e in &c" + (cnt + 1) + " seconds&e. Do not move."); + } else if (cnt == 0) { + p.teleport(new Location(Bukkit.getWorld(Yuri.world), Yuri.x, Yuri.y, Yuri.z)); + int distance = 3; + for (int a = 0; a < 360; a += (360 / 90)) { + double ang = Math.toRadians(a); + double x = Math.cos(ang) * distance; + double y = Math.sin(ang) * distance; + c.getPlayer().getWorld() + .spawnParticle(Particle.FLAME, + c.getPlayer().getLocation().clone().add(x, 0, y), + 1, 0, 0, 0, 0); + //c.getPlayer().getWorld().spawnParticle(Particle.FLAME, c.getPlayer().getLocation().clone().add(x, 2, y), 1, 0, 0, 0, 0); + } + c.reply("&6Teleported to spawn!"); + cancel(); + return; + } else { + if (c.asPlayer().onLastMove() > now) { + c.reply("&eYou moved, &ccancelling teleport&e."); + cancel(); + return; + } + } + --cnt; + } + }.runTaskTimer(Yuri.getMain(), 0, 20L); + } + } + + @Cmd(command = "home", consoleSide = false, desc = "Manage and use homes", tabCompletions = {"set", "list", "home"}, permissions = "home") + public void home(PlayerCommandEvent c) { + Player p = c.getPlayer(); + if (c.getArgs().length == 0) { + + try { + DbQueryResult s = Yuri.connection.getTable("HOMES").createSelectQuery().all().where((q) -> q.forColumn("uuid").value(DbComparisonType.LIKE, String.format("%s;home", p.getUniqueId().toString())).end()).build().execute(); + if (!s.next()) { + c.reply("&cYou have no homes set!"); + return; + } + Location l = (Location) s.get(1); + //p.sendMessage(world +" "+ x +" "+ y +" "+ z); + long now = System.currentTimeMillis(); + new BukkitRunnable() { + int cnt = Yuri.cooldown; + + @Override + public void run() { + if (c.getPlayer().hasPermission("yuriessentials.admin")) { + cnt = 0; + } + if (cnt == 4) { + c.reply("&eTeleporting to &ahome&e in &c" + (cnt + 1) + " seconds&e. Do not move."); + } else if (cnt == 0) { + p.teleport(l); + c.reply("&aTeleported &bhome&a."); + cancel(); + return; + } else { + if (c.asPlayer().onLastMove() > now) { + c.reply("&eYou moved, &ccancelling teleport&e."); + cancel(); + return; + } + } + --cnt; + } + }.runTaskTimer(Yuri.getMain(), 0, 20L); + + } catch (Exception e) { + e.printStackTrace(); + } + return; + } + + if (c.getArgs().length > 0) { + if (c.getArgs()[0].equalsIgnoreCase("set")) { + if (c.getArgs().length == 1) { + c.reply("&cName not provided!"); + return; + } else if (c.getArgs().length > 2) { + c.reply("&cDo not use spaces in the name!"); + return; + } + homeSet(c, c.getArgs()[1]); + } else if (c.getArgs()[0].equalsIgnoreCase("list")) { + try { + DbQueryResult s = Yuri.connection.getTable("HOMES").createSelectQuery().all().where((q) -> q.forColumn("uuid").value(DbComparisonType.LIKE, String.format("%s%%", p.getUniqueId().toString())).end()).build().execute(); //String.format("SELECT * FROM HOMES WHERE uuid LIKE '%s%%'", p.getUniqueId().toString())); + c.reply("&a------------&c=&bHomes&c=&a------------"); + short cnt = 0; + while (s.next()) { + cnt++; + Location l = (Location) s.get(1); + //String world = s.getString("world"); + String name = (String) s.get(0); + assert name != null && l != null; + name = name.substring(name.indexOf(';') + 1); + c.reply("&a- &b" + name + " &a(&bx: &c" + l.getX() + "&a, &by: &c" + l.getY() + "&a, &bz: &c" + l.getZ() + "&a)"); + } + if (cnt == 0) c.reply("&a- &bnone"); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + try { + String name = c.getArgs()[0]; + DbQueryResult s = Yuri.connection.getTable("HOMES").createSelectQuery().all().where((q) -> q.forColumn("uuid").value(DbComparisonType.EQUALS, String.format("%s;%s", p.getUniqueId().toString(), name.toLowerCase())).end()).build().execute(); + if (s.next()) { + Location l = (Location) s.get(1); + //p.sendMessage(world +" "+ x +" "+ y +" "+ z); + long now = System.currentTimeMillis(); + new BukkitRunnable() { + int cnt = Yuri.cooldown; + + @Override + public void run() { + if (c.getPlayer().hasPermission("yuriessentials.admin")) { + cnt = 0; + } + if (cnt == 4) { + c.reply("&eTeleporting to &ahome&e in &c" + (cnt + 1) + " seconds&e. Do not move."); + } else if (cnt == 0) { + p.teleport(l); + c.reply("&aTeleported &bhome&a."); + cancel(); + return; + } else { + if (c.asPlayer().onLastMove() > now) { + c.reply("&eYou moved, &ccancelling teleport&e."); + cancel(); + return; + } + } + --cnt; + } + }.runTaskTimer(Yuri.getMain(), 0, 20L); + } else { + c.reply("&cHome with name &b" + name + " &cdoes not exist!"); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + @Cmd(command = "wheel", consoleSide = false, permissions = "wheel") + public void wheel(PlayerCommandEvent e) { + Location l = e.getPlayer().getLocation(); + double distance = Double.parseDouble(e.getArgsString()); + for (int a = 0; a < 360; a += (360 / 90)) { + double ang = Math.toRadians(a); + double x = Math.cos(ang) * distance; + double y = Math.sin(ang) * distance; + e.getPlayer().getWorld().spawnParticle(Particle.FLAME, l.clone().add(x, 0, y), 1, 0, 0, 0, 0); + } + } + + @Cmd(command = "sethome", consoleSide = false, desc = "Set home", permissions = "home") + public void setHome(PlayerCommandEvent e) { + String name = "home"; + if (e.getArgs().length > 1) { + e.reply("&cDo not use spaces in the name!"); + return; + } else if (e.getArgs().length == 1) + name = e.getArgs()[0]; + homeSet(e, name); + } + + private void homeSet(PlayerCommandEvent e, String name) { + Player p = e.getPlayer(); + if (!e.getPlayer().getWorld().getName().equals("spawn") || e.getPlayer().getWorld().getEnvironment() != World.Environment.NORMAL) { + e.reply("&cCannot set world outside the spawn world."); + return; + } + try { + int i = Yuri.connection.getTable("HOMES").createInsertQuery().setColumn("uuid", String.format("%s;%s", p.getUniqueId().toString(), name.toLowerCase())).setColumn("loc", p.getLocation()).build().execute(); + e.reply("&aHome &b" + name + " &aset!"); + } catch (Exception ex) { + e.reply("&cFailed to set home!"); + ex.printStackTrace(); + } + } + + @Cmd(command = "speed", consoleSide = false, desc = "Sets walking or flying speed", tabCompletions = {"0.2", "0.1"}) + public void setSpeed(CommandEvent e) { + if (e.getArgs().length != 1) { + e.reply("&cNo argument given: ."); + } + + try { + float i = Float.parseFloat(e.getArgsString()); + Player p = ((Player) e.getSender()); + if (p.isFlying()) + p.setFlySpeed(i); + else + p.setWalkSpeed(i); + + e.reply("&aSpeed set to &b" + i); + } catch (Exception ignored) { + e.reply("&cInvalid argument."); + } + } + + @Cmd(command = "doas", desc = "Do as", permissions = {"doas", "admin"}) + public void doas(CommandEvent e) { + if (e.getArgs().length < 2) { + e.reply("&cPlease include the player and argument."); + return; + } + String command = e.getArgsString(); + command = command.substring(command.indexOf(' ') + 1); + Player target = Bukkit.getPlayer(e.getArgs()[0]); + if (target == null) { + e.reply("&cPlayer does not exist!"); + return; + } + if (command.charAt(0) == '/') + command = command.substring(1); + + Bukkit.getServer().dispatchCommand(target, command); + e.reply("&aCommand &b" + command + " &aexecuted!"); + } + + @TabCompletion(command = "doas") + public List doasComplete(CommandTabCompleteEvent e) { + switch (e.getArgs().length) { + case 1: + return null; + case 2: + List cl = new ArrayList<>(); + StringUtil.copyPartialMatches(e.getArgs()[1], Bukkit.getHelpMap().getHelpTopics().stream().map(HelpTopic::getName).collect(Collectors.toList()), cl); + return cl; + default: + return Collections.emptyList(); + } + } + + @Cmd(command = "fly", permissions = "fly", desc = "Toggles flight", consoleSide = false) + public void fly(PlayerCommandEvent e) { + e.getPlayer().setAllowFlight(!e.getPlayer().getAllowFlight()); + e.reply("&aToggled flight."); + } + + @Cmd(command = "invsee", consoleSide = false, desc = "See player inventory", tabCompletions = TabPlaceholder.PLAYERS, permissions = "invsee") + public void invsee(PlayerCommandEvent e) { + if (e.getArgs().length != 1) { + e.reply("&cPlease specify player name"); + return; + } + Player p = Bukkit.getPlayer(e.getArgs()[0]); + if (p == null) { + e.reply("&cNo player found."); + return; + } + + e.getPlayer().openInventory(p.getInventory()); + } + + @Cmd(command = "heal", consoleSide = false, desc = "Heals the player", tabCompletions = TabPlaceholder.PLAYERS, permissions = {"heal"}) + public void heal(PlayerCommandEvent e) { + Player p = e.getArgs().length > 0 ? Bukkit.getPlayer(e.getArgs()[0]) : e.getPlayer(); + if (p == null) { + e.reply("&cPlayer &6" + e.getArgs()[0] + " &cnot found!"); + return; + } + AttributeInstance v = p.getAttribute(Attribute.GENERIC_MAX_HEALTH); + assert v != null; + p.setHealth(v.getValue()); + p.setFoodLevel(20); + e.reply("&aHealed."); + } + + @Cmd(command = "feed", consoleSide = false, desc = "Heals the player", tabCompletions = TabPlaceholder.PLAYERS, permissions = {"feed", "heal"}) + public void feed(PlayerCommandEvent e) { + Player p = e.getArgs().length > 0 ? Bukkit.getPlayer(e.getArgs()[0]) : e.getPlayer(); + if (p == null) { + e.reply("&cPlayer &6" + e.getArgs()[0] + " &cnot found!"); + return; + } + p.setFoodLevel(20); + e.reply("&aFed."); + } + + @Cmd(command = "back", consoleSide = false, desc = "Teleports back to the last place", permissions = "back") + public void back(PlayerCommandEvent e) { + e.getPlayer().teleport(PlayerManager.getLastTeleport(e.getPlayer())); + e.reply("&aTeleported."); + } + + @Cmd(command = "enchant", aliases = "ench", consoleSide = false, desc = "Enchants currently held item", permissions = "enchant") + public void enchant(PlayerCommandEvent e) { + + if (e.getArgs().length == 0) { + e.reply("&cNo enchantment specified."); + return; + } + + if (e.getArgs()[0].equalsIgnoreCase("list")) { + StringBuilder sb = new StringBuilder(); + sb.append("&cEnchantments:\n"); + for (Enchantment ench : Enchantment.values()) { + sb.append("&c- &b").append(ench.getKey().getKey()).append("\n"); + } + e.reply(sb.toString()); + return; + } + + boolean all = e.getArgs()[0].equalsIgnoreCase("all"); + String[] a = e.getArgs()[0].split(":"); + String s1 = a[0], s2 = a[1]; + Enchantment ench = Enchantment.getByKey(new NamespacedKey(s1, s2)); + + if (!all && ench == null) { + e.reply("&cInvalid enchantment &6" + e.getArgs()[0] + "&c!"); + return; + } + + PlayerInventory i = e.getPlayer().getInventory(); + if (i.getItemInMainHand().getType() == Material.AIR) { + e.reply("&cNo item held."); + return; + } + int lvl = 1; + if (e.getArgs().length >= 2) { + try { + lvl = Integer.parseInt(e.getArgs()[1]); + if (lvl < 0) { + e.reply("&cEnchantment level must be higher than 0."); + return; + } + } catch (NumberFormatException ignored) { + e.reply("&cInvalid argument ."); + return; + } + } + if (all) { + Map lvls = new HashMap<>(); + for (Enchantment en : Enchantment.values()) { + lvls.put(en, lvl); + } + i.getItemInMainHand().addUnsafeEnchantments(lvls); + } else i.getItemInMainHand().addUnsafeEnchantment(ench, lvl); + e.reply("&aEnchantment applied."); + } + + @TabCompletion(command = "enchant") + public List enchantCompletion(CommandTabCompleteEvent e) { + switch (e.getArgs().length) { + case 1: + List l = new ArrayList<>(); + l.add("list"); + l.add("all"); + StringUtil.copyPartialMatches(e.getArgs()[0], Arrays.stream(Enchantment.values()).map(k -> k.getKey().toString()).collect(Collectors.toList()), l); + return l; + case 2: + return Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8", "9", "10"); + default: + return Collections.emptyList(); + } + } + + @Cmd(command = "setname", consoleSide = false, desc = "Changes item name", permissions = "setname") + public void setItemName(PlayerCommandEvent e) { + if (e.getPlayer().getInventory().getItemInMainHand().getType() == Material.AIR) { + e.reply("&cYou are not holding any item."); + return; + } + + ItemStack i = e.getPlayer().getInventory().getItemInMainHand(); + ItemMeta im = i.hasItemMeta() ? i.getItemMeta() : Bukkit.getItemFactory().getItemMeta(i.getType()); + assert im != null; + im.setDisplayName(Colored.colorize(e.getArgsString())); + i.setItemMeta(im); + e.reply("&aItem name changed."); + } + + public void auction(PlayerCommandEvent e) { + + Material[] a = new Material[]{Material.PINK_STAINED_GLASS_PANE, Material.GREEN_STAINED_GLASS_PANE, Material.YELLOW_STAINED_GLASS_PANE, Material.RED_STAINED_GLASS_PANE, Material.BLACK_STAINED_GLASS_PANE}; + e.getPlayer().openInventory(new InventoryBuilder(27).withTitle("&c&lPain") + .fillItem(() -> new ItemBuilder(a[new Random().nextInt(5)], Yuri.getMain(), "leaves").withCustomName("&aPoggers").build(), 0, 27).build().getBaseInventory()); + + //FIXME INV + } + + @Cmd(command = "pay", desc = "Manages transactions", tabCompletions = TabPlaceholder.PLAYERS, permissions = {"pay", "eco"}) + public void pay(CommandEvent e) { + if (e.getArgs().length == 0) { + e.reply("&cMissing argument &b&c."); + return; + } else if (e.getArgs().length < 2) { + e.reply("&cMissing argument &b&c."); + return; + } + + Player target = Bukkit.getPlayer(e.getArgs()[0]); + if (target == null) { + e.reply(String.format("&cInvalid player &b%s&c.", e.getArgs()[0])); + return; + } + + if (e.isPlayer() && target.equals(e.asPlayer().getBasePlayer())) { + e.reply("&cCannot pay to yourself."); + return; + } + + int amount; + try { + amount = Integer.parseInt(e.getArgs()[1]); + if (e.isPlayer()) + if (amount <= 0) { + e.reply("&cThe amount of funds has to be more than 0."); + return; + } + } catch (Exception ignored) { + e.reply(String.format("&b%s &cis not a valid number.", e.getArgs()[1])); + return; + } + + YPlayer t = YPlayer.get(target); + String sendername = Colored.colorize("&kukwnown"); + if (e.getSender() instanceof Player) { + Player ss = ((Player) e.getSender()); + boolean b = EconomyManager.subtractFunds(YPlayer.get(ss), amount); + if (!b) { + e.reply("&cYou don't have enough funds!"); + return; + } + sendername = ss.getDisplayName(); + } + + EconomyManager.addFunds(t, amount); + e.reply(String.format("&aYou paid &b%s%d &ato &b%s&a.", EconomyManager.getCurrencySymbol(), amount, target.getDisplayName())); + target.sendMessage(String.format(Colored.colorize("&aYou received &b%s%d &afrom &b%s&a."), EconomyManager.getCurrencySymbol(), amount, sendername)); + } + + @Cmd(command = "balance", aliases = {"bal"}, desc = "Check account balance") + public void balance(CommandEvent e) { + if (e.getSender() instanceof Player) { + YPlayer p = YPlayer.get((Player) e.getSender()); + e.reply(String.format("&aYour balance: %s%d&a.", EconomyManager.getCurrencySymbol(), p.getFunds())); + } else { + if (e.getArgs().length > 0) { + YPlayer p = YPlayer.get(e.getArgs()[0]); + if (p == null) { + e.reply("&cInvalid player."); + return; + } + e.reply("&a" + p.getBasePlayer().getDisplayName() + "'s&a balance: &e" + p.getFunds()); + } else + e.reply("&6Infinite."); + } + } + + @TabCompletion(command = "balance") + public List balanceComplete(CommandTabCompleteEvent e) { + if (e.getSender() instanceof ConsoleCommandSender) { + return null; + } + return Collections.emptyList(); + } + + @Cmd(command = "tpa", permissions = "tpa", desc = "Requests teleport", tabCompletions = TabPlaceholder.PLAYERS, consoleSide = false) + public void tpa(PlayerCommandEvent e) { + if (e.getArgs().length < 1) { + e.reply("&cMissing args &b&c."); + return; + } + YPlayer target = YPlayer.get(e.getArgs()[0]); + + if (target == null) { + e.reply("&CInvalid player."); + return; + } + + if (target.equals(e.asPlayer())) { + e.reply("&cCannot teleport to yourself."); + return; + } + + e.reply("&aRequesting teleport to &e" + target.getBasePlayer().getDisplayName() + "&a."); + target.sendMessage("&e" + e.getPlayer().getDisplayName() + " &6has requested a teleport to you."); + target.sendMessage(new MessageBuilder(ChatMessageType.CHAT) + .append("&aRespond with ").push() + .append("&byes&e (or click here) ").hoverText("&bClick here to accept the request.") + .clickSuggestCommand("yes").push().append("&ato &baccept &athe request.").push() + .append("\n&cReply with any other message &e(or click here) &ato &cdeny &ait.") + .hoverText("&cClick here to deny the request").clickSuggestCommand("no").push().build()); + target.sendMessage("&6The request will expire in &c120&6 seconds."); + long timestamp = System.currentTimeMillis(); + target.onNextMessage(c -> { + if (System.currentTimeMillis() - timestamp > 120000) + return; + + c.setCancelled(true); + if (c.getMessage().equalsIgnoreCase("yes")) { + target.sendMessage("&eYou have &aaccepted ðe teleportation request."); + e.reply("&e" + target.getBasePlayer().getDisplayName() + " &ahas accepted your teleport request.", + "&aTeleporting in &e" + 5 + "&a seconds."); + long move = System.currentTimeMillis(); + new BukkitRunnable() { + @Override + public void run() { + if (e.asPlayer().onLastMove() > move) { + e.reply("&eYou have cancelled your teleportation request &cby moving&e."); + target.sendMessage("&e" + e.getPlayer().getDisplayName() + "&c has cancelled their teleport request."); + } else { + e.reply("&aTeleporting."); + e.getPlayer().teleport(target.getBasePlayer()); + } + } + }.runTaskLater(Yuri.getMain(), 5 * 20); + } else { + target.sendMessage("&eYou have &crejected ðe teleportation request."); + e.reply("&e" + target.getBasePlayer().getDisplayName() + "&e has &crejected&e your request."); + } + }); + } + + @Cmd(command = "invdb", consoleSide = false, permissions = "invdb") + public void invdb(PlayerCommandEvent e) { + InventoryBuilder ib; + int i; + InventoryType t; + try { + i = Integer.parseInt(e.getArgs()[0]); + ib = new InventoryBuilder(i); + } catch (Exception ignored) { + t = InventoryType.valueOf(e.getArgs()[0]); + ib = new InventoryBuilder(t); + } + + + Inventory inv = ib.withTitle("&cTitle").build().getBaseInventory(); + for (int ia = 0; ia < inv.getSize(); ia++) { + ItemStack is = new ItemStack(Material.BLACK_STAINED_GLASS_PANE); + ItemMeta im = is.getItemMeta(); + assert im != null; + im.setDisplayName(String.valueOf(ia)); + is.setItemMeta(im); + inv.setItem(ia, is); + } + e.reply("&c" + inv.getType().name()); + e.getPlayer().openInventory(inv); + } + + @Cmd(command = "repair", consoleSide = false, permissions = "repair") + public void repair(PlayerCommandEvent e) { + ItemStack i = e.getPlayer().getInventory().getItemInMainHand(); + if (i.hasItemMeta()) { + if (i.getItemMeta() instanceof Damageable) { + Damageable d = ((Damageable) i.getItemMeta()); + d.setDamage(0); + i.setItemMeta((ItemMeta) d); + e.reply("&aItem repaired!"); + return; + } + } + e.reply("&cCannot repair item."); + } + + @Cmd(command = "freeze", tabCompletions = TabPlaceholder.PLAYERS, permissions = "freeze") + public void freeze(CommandEvent e) { + if (e.getArgs().length < 1) { + e.reply("&cMissing args!"); + return; + } + Player p = Bukkit.getPlayer(e.getArgs()[0]); + if (p == null) { + e.reply("&cNo player found!"); + return; + } + YPlayer y = YPlayer.get(p); + boolean b = !y.isFrozen(); + y.setFrozen(b); + e.reply((b ? "&bFrozen" : "&6Unfrozen") + "&a " + e.getArgsString() + "&a."); + } + + @Cmd(command = "nick", tabCompletions = TabPlaceholder.PLAYERS, desc = "Changes player nickname.", permissions = "nick") + public void nick(CommandEvent e) { + if (e.getArgs().length == 0) { + if (!e.isPlayer()) { + e.reply("&cYou need to be a player."); + return; + } + Player p = e.asPlayer().getBasePlayer(); + p.setPlayerListName(p.getName()); + e.reply("&aNickname cleared."); + return; + } + + Player p = Bukkit.getPlayer(e.getArgs()[0]); + if (p == null) { + if (!e.isPlayer()) { + e.reply("&cYou need to be a player."); + return; + } + + e.asPlayer().setNickname(Colored.colorize(e.getArgsString())); + } else { + YPlayer.get(p).setNickname(Colored.colorize(Arrays.stream(e.getArgs()).skip(1).collect(Collectors.joining(" ")))); + } + + e.reply("&aNickname set."); + } + + @Cmd(command = "r", desc = "Reply to the last private message receiver") + public void reply(PlayerCommandEvent e) { + if (!e.asPlayer().reply(e.getArgsString())) { + e.reply("&cNo player to reply to."); + } + } + + @Cmd(command = "broadcast", aliases = "bc", permissions = "mod", tabCompletions = TabPlaceholder.EMPTY) + public void broadcast(CommandEvent e) { + for (YPlayer p : YPlayer.getOnlinePlayers()) + p.sendMessage("&2&l(&4Admin&2&l) &e&l>> &b&o" + e.getArgsString()); + //e.reply(Arrays.toString(YPlayer.getOnlinePlayers().stream().map(c -> c.getBasePlayer().getName()).toArray())); + } + + @Cmd(command = "pbcg", permissions = {"vanish", "admin"}, consoleSide = false) + public void pcbg(PlayerCommandEvent e) { + if (e.getArgs().length > 0) { + if (e.getArgs()[0].equalsIgnoreCase("c")) { + boolean b = !e.getPlayer().isCollidable(); + e.getPlayer().setCollidable(b); + e.reply(b ? "&aEnabled collisions" : "&cDisabled collisions"); + return; + } else if (e.getArgs()[0].equalsIgnoreCase("god")) { + boolean b = !e.getPlayer().isInvulnerable(); + e.getPlayer().setInvulnerable(b); + e.reply(b ? "&aEnabled god mode" : "&cDisabled god mode"); + return; + } + + if (PlayerManager.vanishes.contains(e.asPlayer())) { + PlayerManager.vanishes.remove(e.asPlayer()); + for (Player p : Bukkit.getOnlinePlayers()) { + if (!p.equals(e.getPlayer())) { + p.showPlayer(Yuri.getMain(), e.getPlayer()); + } + } + e.reply("&cUnVan."); + } else { + PlayerManager.vanishes.add(e.asPlayer()); + for (Player p : Bukkit.getOnlinePlayers()) { + if (!p.equals(e.getPlayer())) { + p.hidePlayer(Yuri.getMain(), e.getPlayer()); + } + } + e.reply("&aVan."); + } + return; + } + boolean isVanish; + DbQueryResult r = Yuri.connection.getTable("VANISHES").createSelectQuery().all().where(w -> w.forColumn("uuid").value(DbComparisonType.EQUALS, e.getPlayer().getUniqueId()).end()).build().execute(); + isVanish = r.next(); + r.close(); + + ProtocolManager manager = ProtocolLibrary.getProtocolManager(); + if (isVanish) { + try { + PacketContainer pp = manager.createPacket(PacketType.Play.Server.PLAYER_INFO); + pp.getPlayerInfoAction().write(0, EnumWrappers.PlayerInfoAction.ADD_PLAYER); + pp.getPlayerInfoDataLists().write(0, Collections.singletonList(new PlayerInfoData(new WrappedGameProfile(e.getPlayer().getUniqueId(), "pog"), 0, EnumWrappers.NativeGameMode.NOT_SET, null))); + + + PlayerManager.vanishes.remove(e.asPlayer()); + for (Player p : Bukkit.getOnlinePlayers()) { + manager.sendServerPacket(p, pp, false); + if (!p.equals(e.getPlayer())) { + p.showPlayer(Yuri.getMain(), e.getPlayer()); + } + } + } catch (InvocationTargetException invocationTargetException) { + invocationTargetException.printStackTrace(); + } + e.asPlayer().updatePlayerListPrefix(); + Bukkit.broadcastMessage(PlaceholderUtils.processPlayerPlaceholders(MainListener.getJoinMessage(), e.getPlayer())); + e.reply("&6You are no longer vanished."); + Yuri.connection.getTable("VANISHES").createRemoveQuery().where(w -> w.forColumn("uuid").value(DbComparisonType.EQUALS, e.getPlayer().getUniqueId()).end()).build().execute(); + } else { + try { + PlayerManager.vanishes.add(e.asPlayer()); + WrappedGameProfile gameProfile = new WrappedGameProfile(e.getPlayer().getUniqueId(), e.getPlayer().getDisplayName()); + PacketContainer pp = manager.createPacket(PacketType.Play.Server.PLAYER_INFO); + pp.getPlayerInfoAction().write(0, EnumWrappers.PlayerInfoAction.REMOVE_PLAYER); + pp.getPlayerInfoDataLists().write(0, Collections.singletonList(new PlayerInfoData(gameProfile, 0, EnumWrappers.NativeGameMode.SURVIVAL, WrappedChatComponent.fromText(e.getPlayer().getDisplayName())))); + + for (Player p : Bukkit.getOnlinePlayers()) { + if (!p.equals(e.getPlayer())) { + p.hidePlayer(Yuri.getMain(), e.getPlayer()); + } + manager.sendServerPacket(p, pp, false); + } + } catch (InvocationTargetException invocationTargetException) { + invocationTargetException.printStackTrace(); + } + Bukkit.broadcastMessage(PlaceholderUtils.processPlayerPlaceholders(MainListener.getQuitMessage(), e.getPlayer())); + e.reply("&bYou are now vanished."); + Yuri.connection.getTable("VANISHES").createInsertQuery().setColumn("uuid", e.getPlayer().getUniqueId()).build().execute(); + } + } + + @Cmd(command = "setsign", permissions = "setsign", consoleSide = false) + public void setSign(PlayerCommandEvent e) { + e.asPlayer().onNextInteract(c -> { + if (c.getClickedBlock() != null) { + if (c.getClickedBlock().getState() instanceof Sign) { + Sign s = (Sign) c.getClickedBlock().getState(); + String[] ss = e.getArgsString().split("/n"); + try { + int i = Integer.parseInt(e.getArgs()[0]); + s.setLine(i, Colored.colorize(String.join(" ", Arrays.copyOfRange(e.getArgs(), 1, e.getArgs().length)).replace("/b", " "))); + } catch (Exception ignored) { + for (int i = 0; i < (Math.min(ss.length, 4)); i++) { + s.setLine(i, Colored.colorize(ss[i]).replace("/b", " ")); + } + } finally { + s.update(); + } + e.reply("&aSign updated."); + return; + } + } + e.reply("&cThis is not a sign."); + }); + e.reply("&eRight click the sign you want to update."); + } + + @SuppressWarnings("unchecked") + @Cmd(command = "setval", permissions = "admin", consoleSide = false) + public void setEnt(PlayerCommandEvent e) { + String key = e.getArgs()[0]; + String type = e.getArgs()[1]; + String val = e.getArgs()[2]; + Object value = val; + try { + PersistentDataType pdt = (PersistentDataType) PersistentDataType.class.getDeclaredField(type).get(null); + if (!type.equalsIgnoreCase("string")) + value = pdt.getPrimitiveType().getDeclaredMethod("parse" + pdt.getPrimitiveType().getSimpleName(), String.class).invoke(null, val); + + Object topass = value; + + e.asPlayer().onNextInteractWithEntity(c -> { + c.getRightClicked().setPersistent(true); + c.getRightClicked().getPersistentDataContainer().set(KeyFactory.getKeyFor(Yuri.getMain(), key), pdt, topass); + e.reply(String.format("&aMeta set %s <%s> for %s!", key, pdt.getPrimitiveType().getSimpleName(), topass)); + }); + } catch (Exception ee) { + ee.printStackTrace(); + } + } + + @Cmd(command = "armors", permissions = "admin", consoleSide = false, tabCompletions = TabPlaceholder.PLAYERS) + public void getArmors(PlayerCommandEvent e) { + if (e.getArgs().length < 1) { + e.reply("&cMissing args."); + return; + } + YPlayer t = YPlayer.get(e.getArgs()[0]); + if (t == null) { + e.reply("&cInvalid player."); + return; + } + + InventoryBuilder ib = new InventoryBuilder(9); + + for (ItemStack i : t.getBasePlayer().getInventory().getArmorContents()) { + ib.withItem(i); + } + + ib.onClose(c -> { + int cnt = 0; + List ism = new ArrayList<>(); + for (ItemStack i : c.getInventory().getStorageContents()) { + if (cnt > 3) break; + ism.add(i); + cnt++; + } + t.getBasePlayer().getInventory().setArmorContents(ism.toArray(new ItemStack[0])); + }); + + e.reply("&aShowing contents of &e" + t.getBasePlayer().getDisplayName()); + + ib.build().open(e.getPlayer()); + } + + @Cmd(command = "enderchest", consoleSide = false, permissions = "admin", tabCompletions = TabPlaceholder.PLAYERS) + public void peekchest(PlayerCommandEvent e) { + if (e.getArgs().length < 1) { + e.reply("&cInvalid args"); + return; + } + + YPlayer target = YPlayer.get(e.getArgs()[0]); + if (target == null) { + e.reply("&cInvalid player"); + return; + } + e.getPlayer().openInventory(target.getBasePlayer().getEnderChest()); + } + + @Cmd(command = "tls", consoleSide = false, permissions = "admin") + public void tls(PlayerCommandEvent e) { + int a = Integer.parseInt(e.getArgs()[0]), b = Integer.parseInt(e.getArgs()[1]), c = Integer.parseInt(e.getArgs()[2]); + Location l = e.getPlayer().getLocation(); + int xs = l.getBlockX(), ys = l.getBlockY(), zs = l.getBlockZ(); + World w = e.getPlayer().getWorld(); + int x = xs - a, y = Math.max(ys - b, 1), z = zs - c; + int ym = Math.min(y + b, 255); + e.reply("&aSearching..."); + int cnt = 0; + //System.out.println("X: " + x +" Y: "+ y +" Z: " +z + " XS: " + xs + " YS: " + ys + " ZS: " + zs); + for (int xx = x; xx < xs + a; xx++) { + //System.out.println("X: " + xx); + for (int zz = z; zz < zs + b; zz++) { + //System.out.println("Z: " + zz); + for (int yy = y; yy < ym; yy++) { + //System.out.println("Y: " + yy); + Block bb = w.getBlockAt(xx, yy, zz); + //System.out.printf("x: %d y: %d z: %d, t: %s\n", xx, yy, zz ,bb.getType().name()); + if (bb.getType() == Material.CHEST || bb.getType() == Material.TRAPPED_CHEST || bb.getType() == Material.BARREL || bb.getType() == Material.SHULKER_BOX) { + e.asPlayer().sendMessage(new MessageBuilder(ChatMessageType.CHAT).append("&8&l > &6&lChest at: &c&lX: &b&l" + bb.getX() + " &c&lY: &b&l" + bb.getY() + " &c&lZ: &b&l" + bb.getZ()).clickRunCommand("/tp " + bb.getX() + " " + bb.getY() + " " + bb.getZ()).push().build()); + cnt++; + } + } + } + } + e.reply("&bTotal: &a" + cnt); + } + + @Cmd(command = "ndrp", consoleSide = false, permissions = "admin") + public void nodrop(PlayerCommandEvent e) { + if (YListener.nodrop.contains(e.asPlayer())) { + YListener.nodrop.remove(e.asPlayer()); + e.reply("&eDrops enabled."); + } else { + YListener.nodrop.add(e.asPlayer()); + e.reply("&cDrops disabled."); + } + } + + @Cmd(command = "slm", consoleSide = false, permissions = "slm") + public void checcchnk(PlayerCommandEvent e) { + Chunk c = e.getPlayer().getLocation().getChunk(); + e.reply(String.format("&cChunk: &e%d, %d&6. Entities: &e%d&6. Slime: &e%s&6. &6Tile entities: &e%d&6. ITime: &e%d&6.", c.getX(), c.getZ(), c.getEntities().length, c.isSlimeChunk(), c.getTileEntities().length, c.getInhabitedTime())); + } + + @Cmd(command = "head", consoleSide = false, permissions = "head") + public void head(PlayerCommandEvent e) { + ItemStack i = e.getPlayer().getInventory().getItemInMainHand().clone(); + if (i.getType() == Material.AIR) { + e.reply("&cNo item selected."); + return; + } + + ItemStack prehelmet = e.getPlayer().getInventory().getHelmet(); + + if(prehelmet != null) { + prehelmet = prehelmet.clone(); + e.getPlayer().getInventory().setItemInMainHand(prehelmet); + } + + e.getPlayer().getInventory().setHelmet(i); + e.getPlayer().updateInventory(); + } + + @Cmd(command = "holo", consoleSide = false, permissions = "admin") + public void holo(PlayerCommandEvent e) { + if (e.getArgs()[0].equalsIgnoreCase("add")) { + String[] lines = Colored.colorize(String.join(" ", Arrays.copyOfRange(e.getArgs(), 1, e.getArgs().length))).split("/n"); + Hologram h = new Hologram(e.getPlayer().getLocation(), lines); + HologramManager.addHologram(h); + e.asPlayer().sendMessage(new MessageBuilder(ChatMessageType.CHAT).append("&aAdded holo with id=&c" + h.getId()).clickSuggestCommand("/holo remove " + h.getId()).push().build()); + } else if (e.getArgs()[0].equalsIgnoreCase("remove")) { + HologramManager.remove(Integer.parseInt(e.getArgs()[1])); + } else if (e.getArgs()[0].equalsIgnoreCase("list")) { + HologramManager.getAll().forEach(c -> e.reply("&3- " + c.getId() + " &8&l> &e" + c.getLocation().toString())); + } else if (e.getArgs()[0].equalsIgnoreCase("addline")) { + Hologram h = HologramManager.getById(Integer.parseInt(e.getArgs()[1])); + String line = Colored.colorize(String.join(" ", Arrays.copyOfRange(e.getArgs(), 2, e.getArgs().length))); + h.addLine(line); + e.reply("&aAdded line '" + line + "&a' to holo with id=&c" + h.getId()); + } + } +} diff --git a/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/PlayerManager.java b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/PlayerManager.java new file mode 100644 index 0000000..f1bc90d --- /dev/null +++ b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/PlayerManager.java @@ -0,0 +1,34 @@ +package me.yuri.essentials; + +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.utils.Colored; +import me.yuri.yuriapi.api.utils.SyncedPlayerMap; +import me.yuri.yuriapi.api.utils.SyncedPlayerSet; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public class PlayerManager { + + protected static final SyncedPlayerSet vanishes = new SyncedPlayerSet(); + protected static final SyncedPlayerSet afk = new SyncedPlayerSet(); + private static final SyncedPlayerMap lastTeleports = new SyncedPlayerMap<>(); + + public static void setLastTeleport(Player p, Location l) { + lastTeleports.put(YPlayer.get(p), l); + } + + public static Location getLastTeleport(Player p) { + return lastTeleports.getOrDefault(YPlayer.get(p), p.getLocation()); + } + + public static void setAfk(YPlayer y, boolean afk) { + if (afk) { + Bukkit.broadcastMessage(Colored.colorize(y.getBasePlayer().getDisplayName() + " &eis now AFK.")); + PlayerManager.afk.add(y); + } else if (PlayerManager.afk.contains(y)) { + Bukkit.broadcastMessage(Colored.colorize(y.getBasePlayer().getDisplayName() + " &bis no longer AFK.")); + PlayerManager.afk.remove(y); + } + } +} diff --git a/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/SupaDigger.java b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/SupaDigger.java new file mode 100644 index 0000000..51ae5f7 --- /dev/null +++ b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/SupaDigger.java @@ -0,0 +1,56 @@ +package me.yuri.essentials; + +import org.bukkit.NamespacedKey; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.enchantments.EnchantmentTarget; +import org.bukkit.inventory.ItemStack; + +import javax.annotation.Nonnull; + +public class SupaDigger extends Enchantment { + public SupaDigger(NamespacedKey key) { + super(key); + } + + @Nonnull + @Override + public String getName() { + return "Supa Digga"; + } + + @Override + public int getMaxLevel() { + return 1; + } + + @Override + public int getStartLevel() { + return 1; + } + + @Nonnull + @Override + public EnchantmentTarget getItemTarget() { + return EnchantmentTarget.TOOL; + } + + @Override + public boolean isTreasure() { + return true; + } + + @Override + public boolean isCursed() { + return false; + } + + @Override + public boolean conflictsWith(@Nonnull Enchantment enchantment) { + return false; + } + + @Override + public boolean canEnchantItem(ItemStack itemStack) { + return itemStack.getType().name().contains("pickaxe") || itemStack.getType().name().contains("shovel"); + } +} diff --git a/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/YListener.java b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/YListener.java new file mode 100644 index 0000000..941602e --- /dev/null +++ b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/YListener.java @@ -0,0 +1,714 @@ +package me.yuri.essentials; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.ProtocolManager; +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.wrappers.EnumWrappers; +import com.comphenix.protocol.wrappers.PlayerInfoData; +import com.comphenix.protocol.wrappers.WrappedChatComponent; +import com.comphenix.protocol.wrappers.WrappedGameProfile; +import me.yuri.essentials.auction.Auction; +import me.yuri.essentials.auction.AuctionItem; +import me.yuri.essentials.market.Market; +import me.yuri.essentials.shop.Shop; +import me.yuri.yuriapi.Desu; +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.db.DbComparisonType; +import me.yuri.yuriapi.api.db.DbQueryResult; +import me.yuri.yuriapi.api.economy.EconomyManager; +import me.yuri.yuriapi.api.utils.Colored; +import me.yuri.yuriapi.api.utils.ItemUtils; +import me.yuri.yuriapi.api.utils.SyncedPlayerSet; +import me.yuri.yuriapi.api.utils.configuration.ConfigVar; +import me.yuri.yuriapi.api.utils.metadata.BlockMetaStorage; +import me.yuri.yuriapi.api.utils.metadata.KeyFactory; +import org.bukkit.*; +import org.bukkit.block.Block; +import org.bukkit.block.data.Ageable; +import org.bukkit.craftbukkit.libs.org.apache.commons.io.FileUtils; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.*; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockGrowEvent; +import org.bukkit.event.entity.*; +import org.bukkit.event.inventory.InventoryAction; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.player.*; +import org.bukkit.event.server.ServerListPingEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; +import org.bukkit.inventory.meta.FireworkMeta; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitTask; +import org.bukkit.util.RayTraceResult; +import org.bukkit.util.Vector; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +@SuppressWarnings("unused") +public class YListener implements Listener { + + private static final int MAX = 32 + 1; + private static final File DEBUG = new File("debug_logs.log"); + @ConfigVar(value = "glassBreakChance") + public static int glassBreakChance; + protected static SyncedPlayerSet nodrop = new SyncedPlayerSet(); + private final Random r = new Random(); + + @EventHandler + public void glass(ProjectileHitEvent e) { + if (e.getEntity() instanceof Arrow) { + Arrow a = (Arrow) e.getEntity(); + if (e.getHitBlock() != null && e.getHitBlock().getBlockData().getSoundGroup().getBreakSound() == Sound.BLOCK_GLASS_BREAK) { + a.getWorld().spawnParticle(Particle.BLOCK_CRACK, a.getLocation(), 100, e.getHitBlock().getBlockData()); + e.getHitBlock().breakNaturally(); + Vector v = a.getVelocity(); + a.getWorld().playSound(a.getLocation(), Sound.BLOCK_GLASS_BREAK, 4, 1); + a.remove(); + Random r = new Random(); + if (r.nextInt(100) < glassBreakChance) { + a.getWorld().spawnArrow(a.getLocation(), v.multiply(100), 1, 1) + .setPickupStatus(AbstractArrow.PickupStatus.ALLOWED); + } + } + } + } + + @EventHandler + public void playerSList(ServerListPingEvent e) { + Iterator it = e.iterator(); + while (it.hasNext()) { + Player p = it.next(); + if (p != null && PlayerManager.vanishes.contains(YPlayer.get(p))) + it.remove(); + } + + } + + @EventHandler(priority = EventPriority.MONITOR) + public void joinNotify(PlayerJoinEvent e) { + if (!e.getPlayer().hasPlayedBefore()) { + CompletableFuture.runAsync(() -> { + try { + DateTimeFormatter tf = DateTimeFormatter.ofPattern("dd.MM.yyyy,HH:mm"); + FileWriter fw = new FileWriter("/home/yuri/Documents/Dev/csharp/McTest/users.usr", true); + fw.append("\n").append(e.getPlayer().getName()).append(";true;").append(LocalDateTime.now().format(tf)).flush(); + Bukkit.getConsoleSender().sendMessage("Data written to /home/yuri/Documents/Dev/csharp/McTest/users.usr!"); + fw.close(); + } catch (Exception ex) { + ex.printStackTrace(); + } + }); + } + } + + @EventHandler + public void kuza(AsyncPlayerChatEvent e) { + if (e.getMessage().toLowerCase().contains("kuza") || e.getMessage().toLowerCase().contains("kuze")) { + e.getPlayer().sendMessage(Colored.colorize("&aPog")); + e.getRecipients().clear(); + e.getRecipients().add(e.getPlayer()); + } else if (e.getMessage().toLowerCase().contains("nigg")) { + e.getRecipients().clear(); + e.getRecipients().add(e.getPlayer()); + } + } + + @EventHandler + public void shop(PlayerInteractAtEntityEvent e) { + if (e.getRightClicked().getType() == EntityType.VILLAGER) { + Villager v = (Villager) e.getRightClicked(); + if (v.getPersistentDataContainer().has(Yuri.VILL, PersistentDataType.BYTE)) { + e.setCancelled(true); + Shop.openInventory(e.getPlayer()); + } + } + } + + @EventHandler + public void interact(PlayerInteractEvent e) { + if (e.getAction() == Action.PHYSICAL && e.getClickedBlock() != null && e.getClickedBlock().getType() == Material.LIGHT_WEIGHTED_PRESSURE_PLATE && BlockMetaStorage.hasMetaAny(e.getClickedBlock(), "e")) { + e.getPlayer().setVelocity(e.getPlayer().getLocation().getDirection().clone().multiply(20).setY(1)); //x20 + return; + } else if (e.getAction() == Action.RIGHT_CLICK_BLOCK && e.getClickedBlock() != null && e.getClickedBlock().getType() == Material.POLISHED_BLACKSTONE_BUTTON && BlockMetaStorage.hasMetaAny(e.getClickedBlock(), "tp")) { + Random r = new Random(); + + int z; + do { + z = r.nextInt(2 * MAX) - MAX; + } while (z < 2 && z > -4); + + int x; + do { + x = r.nextInt(2 * MAX) - MAX + 7; + } while (x < 11 && x > 2); + + World w = Bukkit.getWorld("spawn"); + assert w != null; + + Chunk c = w.getChunkAt(x, z); + c.load(); + + x *= 16; + z *= 16; + + int xx = r.nextInt(16) + x; + int zz = r.nextInt(16) + z; + + int y = w.getHighestBlockYAt(xx, zz) + 1; + + e.getPlayer().teleport(new Location(w, xx, y, zz)); + Bukkit.getConsoleSender().sendMessage(Colored.colorize("&e[RandomTP]: Teleporting " + e.getPlayer().getName() + " to: " + xx + "," + y + "," + zz)); + return; + } + if (e.getItem() != null) + if (e.getItem().hasItemMeta()) { + if (Objects.requireNonNull(e.getItem().getItemMeta()).getPersistentDataContainer().has(KeyFactory.getKeyFor(Yuri.getMain(), "gg"), PersistentDataType.BYTE)) { + Firework a = e.getPlayer().getWorld().spawn(e.getPlayer().getEyeLocation(), Firework.class); + FireworkMeta fw = a.getFireworkMeta(); + fw.addEffect(FireworkEffect.builder().with(FireworkEffect.Type.BALL).withColor(Color.ORANGE).trail(true).build()); + fw.setPower(120); + a.setFireworkMeta(fw); + a.setVelocity(e.getPlayer().getLocation().getDirection().multiply(3)); + Particle.DustOptions dop = new Particle.DustOptions(org.bukkit.Color.RED, 2); + + final boolean hom = Objects.requireNonNull(e.getItem().getItemMeta()).getPersistentDataContainer().has(KeyFactory.getKeyFor(Yuri.getMain(), "gg"), PersistentDataType.BYTE); + + Bukkit.getScheduler().runTaskTimer(Desu.getMain(), new Consumer() { + int cnt = 0; + + @Override + public void accept(BukkitTask bukkitTask) { + a.getWorld().spawnParticle(Particle.REDSTONE, a.getLocation(), 2, 0, 0, 0, 0, dop); + if (hom) { + List l = a.getNearbyEntities(20, 20, 20); + for (Entity ee : l) { + if (!(ee instanceof Firework) && !(ee instanceof Item)) { + if (ee instanceof Player && (ee.equals(e.getPlayer()))) continue; + a.setVelocity(ee.getLocation().toVector().subtract(a.getLocation().toVector()).normalize().multiply(a.getVelocity().length())); + if (ee.getLocation().distance(a.getLocation()) < 0.5) { + a.detonate(); + bukkitTask.cancel(); + return; + } + } + + } + } + + if (a.isDead() || cnt > 60) + bukkitTask.cancel(); + ++cnt; + } + }, 2L, 1L); + } + } + } + + @EventHandler + public void dead(PlayerDeathEvent e) { + Bukkit.getConsoleSender().sendMessage(Colored.colorize(String.format("&ePlayer died: %s x: %f y: %f z: %f", e.getEntity().getName(), e.getEntity().getLocation().getX(), e.getEntity().getLocation().getY(), e.getEntity().getLocation().getZ()))); + PlayerManager.setLastTeleport(e.getEntity(), e.getEntity().getLocation().clone()); + if (e.getEntity().getName().equalsIgnoreCase("Golgroth")) { + e.setDeathMessage(null); + } else { + if (e.getDeathMessage() != null) + e.setDeathMessage(Colored.colorize("&c&o") + e.getDeathMessage().replace(e.getEntity().getDisplayName(), Colored.colorize("&b") + e.getEntity().getDisplayName())); + } + + } + + @EventHandler + public void bomber(EntityToggleGlideEvent e) { + if (!e.isGliding()) { + if (e.getEntity() instanceof Player) { + Player p = (Player) e.getEntity(); + ItemStack i = p.getInventory().getChestplate(); + if (i == null) return; + if (Objects.requireNonNull(i).getType() == Material.ELYTRA && i.hasItemMeta() && Objects.requireNonNull(i.getItemMeta()).getPersistentDataContainer().has(KeyFactory.getKeyFor(Yuri.getMain(), "scd"), PersistentDataType.BYTE)) { + i.setAmount(0); + p.getWorld().createExplosion(p.getLocation(), 20); + } + } + } + } + + @EventHandler + public void fireEat(PlayerItemConsumeEvent e) { + if (e.getItem().containsEnchantment(Enchantment.FIRE_ASPECT)) { + e.getPlayer().setFireTicks(20 * 10 * e.getItem().getEnchantmentLevel(Enchantment.FIRE_ASPECT)); + } + } + + @EventHandler + public void crops(PlayerInteractEvent e) { + if (e.getAction() == Action.RIGHT_CLICK_BLOCK) { + assert e.getClickedBlock() != null; + if (e.getClickedBlock().getBlockData() instanceof Ageable) { + Ageable a = (Ageable) e.getClickedBlock().getBlockData(); + Material m = e.getClickedBlock().getType(); + if (a.getAge() == a.getMaximumAge()) { + if (m == Material.MELON_STEM || m == Material.PUMPKIN_STEM) return; + e.getClickedBlock().breakNaturally(); + Material s = getSeed(m); + if (ItemUtils.removeItem(e.getPlayer().getInventory(), s, 1)) { + e.getClickedBlock().setType(m); + } + } + } + } + } + + private Material getSeed(Material main) { + switch (main) { + case WHEAT: + return Material.WHEAT_SEEDS; + case BEETROOT: + return Material.BEETROOT_SEEDS; + default: + return main; + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void zzzonDig(BlockBreakEvent e) { + if (e.isCancelled()) + return; + ItemStack is = e.getPlayer().getInventory().getItemInMainHand(); + if (!is.hasItemMeta()) return; + if (is.containsEnchantment(Yuri.supaDigger) || (is.hasItemMeta() && Objects.requireNonNull(is.getItemMeta()).hasLore() && Objects.requireNonNull(is.getItemMeta().getLore()).contains(Colored.colorize("&eSupa Digga")))) { + RayTraceResult rt = e.getPlayer().rayTraceBlocks(4); + if (rt == null) return; + Vector v = Objects.requireNonNull(rt.getHitBlockFace()).getDirection().normalize(); + //System.out.printf("%d %d %d\n", v.getBlockX(), v.getBlockY(), v.getBlockZ()); + int x = Math.abs(v.getBlockX()), y = Math.abs(v.getBlockY()), z = Math.abs(v.getBlockZ()); + int rx, ry, rz; + if (x == 1) { + Block b1 = e.getBlock().getRelative(0, -1, -1); + Block b2 = e.getBlock().getRelative(0, -1, 0); + Block b3 = e.getBlock().getRelative(0, 0, -1); + Block b4 = e.getBlock().getRelative(0, 1, 0); + Block b5 = e.getBlock().getRelative(0, 0, 1); + Block b6 = e.getBlock().getRelative(0, 1, 1); + Block b7 = e.getBlock().getRelative(0, -1, 1); + Block b8 = e.getBlock().getRelative(0, 1, -1); + + if (b1.getType().getHardness() >= 1.5 && b1.getType().getHardness() < 4) + b1.breakNaturally(is); + if (b2.getType().getHardness() >= 1.5 && b2.getType().getHardness() < 4) + b2.breakNaturally(is); + if (b3.getType().getHardness() >= 1.5 && b3.getType().getHardness() < 4) + b3.breakNaturally(is); + if (b4.getType().getHardness() >= 1.5 && b4.getType().getHardness() < 4) + b4.breakNaturally(is); + if (b5.getType().getHardness() >= 1.5 && b5.getType().getHardness() < 4) + b5.breakNaturally(is); + if (b6.getType().getHardness() >= 1.5 && b6.getType().getHardness() < 4) + b6.breakNaturally(is); + if (b7.getType().getHardness() >= 1.5 && b7.getType().getHardness() < 4) + b7.breakNaturally(is); + if (b8.getType().getHardness() >= 1.5 && b8.getType().getHardness() < 4) + b8.breakNaturally(is); + } else if (y == 1) { + Block b1 = e.getBlock().getRelative(-1, 0, -1); + Block b2 = e.getBlock().getRelative(-1, 0, 0); + Block b3 = e.getBlock().getRelative(0, 0, -1); + Block b4 = e.getBlock().getRelative(1, 0, 0); + Block b5 = e.getBlock().getRelative(0, 0, 1); + Block b6 = e.getBlock().getRelative(1, 0, 1); + Block b7 = e.getBlock().getRelative(-1, 0, 1); + Block b8 = e.getBlock().getRelative(1, 0, -1); + + if (b1.getType().getHardness() >= 1.5 && b1.getType().getHardness() < 4) + b1.breakNaturally(is); + if (b2.getType().getHardness() >= 1.5 && b2.getType().getHardness() < 4) + b2.breakNaturally(is); + if (b3.getType().getHardness() >= 1.5 && b3.getType().getHardness() < 4) + b3.breakNaturally(is); + if (b4.getType().getHardness() >= 1.5 && b4.getType().getHardness() < 4) + b4.breakNaturally(is); + if (b5.getType().getHardness() >= 1.5 && b5.getType().getHardness() < 4) + b5.breakNaturally(is); + if (b6.getType().getHardness() >= 1.5 && b6.getType().getHardness() < 4) + b6.breakNaturally(is); + if (b7.getType().getHardness() >= 1.5 && b7.getType().getHardness() < 4) + b7.breakNaturally(is); + if (b8.getType().getHardness() >= 1.5 && b8.getType().getHardness() < 4) + b8.breakNaturally(is); + } else { + Block b1 = e.getBlock().getRelative(-1, -1, 0); + Block b2 = e.getBlock().getRelative(-1, 0, 0); + Block b3 = e.getBlock().getRelative(0, -1, 0); + Block b4 = e.getBlock().getRelative(1, 0, 0); + Block b5 = e.getBlock().getRelative(0, 1, 0); + Block b6 = e.getBlock().getRelative(1, 1, 0); + Block b7 = e.getBlock().getRelative(-1, 1, 0); + Block b8 = e.getBlock().getRelative(1, -1, 0); + + if (b1.getType().getHardness() >= 1.5 && b1.getType().getHardness() < 4) + b1.breakNaturally(is); + if (b2.getType().getHardness() >= 1.5 && b2.getType().getHardness() < 4) + b2.breakNaturally(is); + if (b3.getType().getHardness() >= 1.5 && b3.getType().getHardness() < 4) + b3.breakNaturally(is); + if (b4.getType().getHardness() >= 1.5 && b4.getType().getHardness() < 4) + b4.breakNaturally(is); + if (b5.getType().getHardness() >= 1.5 && b5.getType().getHardness() < 4) + b5.breakNaturally(is); + if (b6.getType().getHardness() >= 1.5 && b6.getType().getHardness() < 4) + b6.breakNaturally(is); + if (b7.getType().getHardness() >= 1.5 && b7.getType().getHardness() < 4) + b7.breakNaturally(is); + if (b8.getType().getHardness() >= 1.5 && b8.getType().getHardness() < 4) + b8.breakNaturally(is); + } + org.bukkit.inventory.meta.Damageable d = (org.bukkit.inventory.meta.Damageable) is.getItemMeta(); + assert d != null; + d.setDamage(d.getDamage() + 8); + is.setItemMeta((ItemMeta) d); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onAddEnchant(InventoryClickEvent e) { + if (e.getAction() == InventoryAction.SWAP_WITH_CURSOR) { + if (e.getCurrentItem() != null && e.getCursor() != null && e.getCursor().getType() == Material.ENCHANTED_BOOK) { + ItemStack tobe = e.getCurrentItem(); + if (tobe.getType() == Material.AIR) return; + + ItemStack ench = e.getCursor(); + EnchantmentStorageMeta m = (EnchantmentStorageMeta) ench.getItemMeta(); + assert m != null; + Map enchantments = new HashMap<>(); + enchantments.putAll(ench.getEnchantments()); + enchantments.putAll(m.getStoredEnchants()); + + tobe.addUnsafeEnchantments(enchantments); + + e.setCancelled(true); + + ItemMeta im = tobe.getItemMeta(); + assert im != null; + List lore = im.hasLore() ? im.getLore() : new ArrayList<>(); + assert lore != null; + + if (enchantments.containsKey(Yuri.supaDigger)) + lore.add(Colored.colorize("&eSupa Digga")); + + im.setLore(lore); + tobe.setItemMeta(im); + + e.getView().setCursor(null); + + e.getView().close(); + + ((Player) e.getWhoClicked()).updateInventory(); + + e.getWhoClicked().sendMessage(Colored.colorize("&aEnchantment applied.")); + e.getWhoClicked().getWorld().playSound(e.getWhoClicked().getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1); + } + } + } + + @EventHandler + public void onHit(ProjectileHitEvent e) { + if (e.getHitEntity() != null) { + e.getEntity().setBounce(false); + EntityType t = e.getEntity().getType(); + if (!(e.getHitEntity() instanceof Damageable)) return; + if (e.getHitEntity().getHeight() > 1.5 && e.getHitEntity().getHeight() < 2.5) { + double dif = Math.abs(e.getHitEntity().getLocation().clone().add(0, 2, 0).getY() - e.getEntity().getLocation().getY()); + if (dif < 0.5) { + if (e.getHitEntity() instanceof Player) { + if (((Player) e.getHitEntity()).getInventory().getHelmet() != null) { + return; + } + } + Damageable dmg = (Damageable) e.getHitEntity(); + dmg.damage((new Random().nextInt(26) + 20) / 2f); + } + } + } + } + + @EventHandler + public void teleport(PlayerTeleportEvent e) { + if (e.getCause() == PlayerTeleportEvent.TeleportCause.UNKNOWN) return; + PlayerManager.setLastTeleport(e.getPlayer(), e.getPlayer().getLocation().clone()); + } + + @EventHandler + public void whisper(PlayerCommandPreprocessEvent e) { + String[] preargs = e.getMessage().split(" "); + if (preargs.length > 1) { + String[] args = Arrays.copyOfRange(preargs, 1, preargs.length); + String cmd = preargs[0].substring(1); + if (cmd.equalsIgnoreCase("w") || cmd.equalsIgnoreCase("tell") || cmd.equalsIgnoreCase("msg")) { + e.setCancelled(true); + YPlayer pl = YPlayer.get(e.getPlayer()); + YPlayer target = YPlayer.get(args[0]); + if (target == null) { + pl.reply("&cInvalid player."); + return; + } + String msg = String.join(" ", Arrays.copyOfRange(args, 1, args.length)); + pl.privateMessage(target, msg); + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void vanishJoin(PlayerJoinEvent e) { + YPlayer pl = YPlayer.get(e.getPlayer()); + DbQueryResult r = Yuri.connection.getTable("VANISHES").createSelectQuery().all().where(w -> w.forColumn("uuid").value(DbComparisonType.EQUALS, e.getPlayer().getUniqueId()).end()).build().execute(); + if (r.next()) { + e.setJoinMessage(null); + new BukkitRunnable() { + @Override + public void run() { + ProtocolManager manager = ProtocolLibrary.getProtocolManager(); + WrappedGameProfile gameProfile = new WrappedGameProfile(e.getPlayer().getUniqueId(), e.getPlayer().getDisplayName()); + PacketContainer pp = manager.createPacket(PacketType.Play.Server.PLAYER_INFO); + pp.getPlayerInfoAction().write(0, EnumWrappers.PlayerInfoAction.REMOVE_PLAYER); + pp.getPlayerInfoDataLists().write(0, Collections.singletonList(new PlayerInfoData(gameProfile, 0, EnumWrappers.NativeGameMode.SURVIVAL, WrappedChatComponent.fromText(e.getPlayer().getDisplayName())))); + + try { + for (Player p : Bukkit.getOnlinePlayers()) { + if (!p.equals(e.getPlayer())) { + p.hidePlayer(Yuri.getMain(), e.getPlayer()); + } + manager.sendServerPacket(p, pp, false); + } + PlayerManager.vanishes.add(pl); + } catch (Exception eee) { + eee.printStackTrace(); + } + } + }.runTaskLater(Yuri.getMain(), 5L); + } else { + PlayerManager.vanishes.forEach(c -> e.getPlayer().hidePlayer(Yuri.getMain(), c.getBasePlayer())); + } + r.close(); + + if (!e.getPlayer().hasPlayedBefore()) { + EconomyManager.addFunds(pl, 1000); + new BukkitRunnable() { + @Override + public void run() { + e.getPlayer().teleport(new Location(Bukkit.getWorld(Yuri.world), Yuri.x, Yuri.y, Yuri.z)); + System.out.println("W: " + Yuri.world + " X: " + Yuri.x + " Y: " + Yuri.y + " Z: " + Yuri.z); + } + }.runTaskLater(Yuri.getMain(), 3L); + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void vanishQuit(PlayerQuitEvent e) { + Market.getBuyOffers().stream().filter(c -> c.getPlayer().equals(YPlayer.get(e.getPlayer()))).forEach(c -> EconomyManager.addFunds(c.getPlayer(), c.getPrice() * c.getCount())); + Market.getSellOffers().stream().filter(c -> c.getPlayer().equals(YPlayer.get(e.getPlayer()))).forEach(c -> { + ItemStack is = new ItemStack(c.getResource().getMaterial()); + is.setAmount(c.getCount()); + c.getPlayer().getBasePlayer().getInventory().addItem(is); + }); + List items = Auction.getAllOffers().stream().filter(c -> c.getPlayer().equals(YPlayer.get(e.getPlayer()))).collect(Collectors.toList()); + items.forEach(Auction::cancelOffer); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void vanishNoMsg(PlayerQuitEvent e) { + DbQueryResult r = Yuri.connection.getTable("VANISHES").createSelectQuery().all().where(w -> w.forColumn("uuid").value(DbComparisonType.EQUALS, e.getPlayer().getUniqueId()).end()).build().execute(); + if (r.next()) { + e.setQuitMessage(null); + } + r.close(); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void monitorItem(EntityDeathEvent e) { + if (e.getEntity() instanceof Item) { + Item i = (Item) e.getEntity(); + CompletableFuture.runAsync(() -> { + try { + FileUtils.writeStringToFile(DEBUG, "\n[" + Instant.now().toString() + "] Item died: " + i.getItemStack().toString() + " in: " + i.getLocation().toString(), StandardCharsets.UTF_8, true); + } catch (IOException ioException) { + ioException.printStackTrace(); + } + }); + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void ondrop(PlayerDropItemEvent e) { + CompletableFuture.runAsync(() -> { + try { + FileUtils.writeStringToFile(DEBUG, "\n[" + Instant.now().toString() + "] Item dropped: " + e.getItemDrop().getItemStack().toString() + " in: " + e.getItemDrop().getLocation().toString() + " by: " + e.getPlayer().getName(), StandardCharsets.UTF_8, true); + } catch (IOException ioException) { + ioException.printStackTrace(); + } + }); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void ondespawn(ItemDespawnEvent e) { + CompletableFuture.runAsync(() -> { + try { + FileUtils.writeStringToFile(DEBUG, "\n[" + Instant.now().toString() + "] Item dropped: " + e.getEntity().getItemStack().toString() + " in: " + e.getEntity().getLocation().toString(), StandardCharsets.UTF_8, true); + } catch (IOException ioException) { + ioException.printStackTrace(); + } + }); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void teleportSpawn(PlayerPortalEvent e) { + if (e.getPlayer().getWorld().getName().equals("mainspawn")) { + e.setCancelled(true); + e.getPlayer().teleport(new Location(Bukkit.getWorld(Yuri.pworld), Yuri.px, Yuri.py, Yuri.pz)); + } + } + + @EventHandler + public void mobDrops(EntityDeathEvent e) { + Random r = new Random(); + switch (e.getEntity().getType()) { + case PIG: + case COW: + case MULE: + case HORSE: + case WOLF: + case LLAMA: + case SHEEP: + case VILLAGER: + case ZOMBIE: + case ZOMBIE_VILLAGER: + case PIGLIN: + e.getDrops().add(new ItemStack(Material.BONE, r.nextInt(3))); + break; + } + if (e.getEntity().getKiller() != null) { + ItemStack i = e.getEntity().getKiller().getInventory().getItemInMainHand(); + int ch = 1000; + if (r.nextInt(ch) > ch - 2) { + e.getDrops().add(getHead(e.getEntity())); + } else if (r.nextInt(ch) > ch - 8 && i.containsEnchantment(Enchantment.SILK_TOUCH)) { + e.getDrops().add(getHead(e.getEntity())); + } else if (i.containsEnchantment(Enchantment.LOOT_BONUS_MOBS)) { + int premium = i.getEnchantmentLevel(Enchantment.LOOT_BONUS_MOBS); + if (r.nextInt(ch) > ch - ((4 + premium * 2) + 1) * 2) { + e.getDrops().add(getHead(e.getEntity())); + } + } + } + } + + private ItemStack getHead(LivingEntity e) { + switch (e.getType()) { + case ZOMBIE: + return new ItemStack(Material.ZOMBIE_HEAD); + case PLAYER: + ItemStack im = new ItemStack(Material.PLAYER_HEAD); + SkullMeta sm = (SkullMeta) im.getItemMeta(); + assert sm != null; + sm.setOwningPlayer((Player) e); + sm.setDisplayName("&c" + ((Player) e).getDisplayName() + "'s &chead"); + im.setItemMeta(sm); + return im; + case ENDER_DRAGON: + return new ItemStack(Material.DRAGON_HEAD); + case CREEPER: + return new ItemStack(Material.CREEPER_HEAD); + case SKELETON: + return new ItemStack(Material.SKELETON_SKULL); + case WITHER_SKELETON: + return new ItemStack(Material.WITHER_SKELETON_SKULL); + default: + return new ItemStack(Material.GUNPOWDER); + } + } + + @EventHandler + public void move(PlayerMoveEvent e) { + YPlayer y = YPlayer.get(e.getPlayer()); + if (PlayerManager.afk.contains(y)) { + PlayerManager.setAfk(y, false); + } + } + + @EventHandler + public void nodrp(EntityPickupItemEvent e) { + if (e.getEntity() instanceof Player) { + if (nodrop.contains(YPlayer.get((Player) e.getEntity()))) + e.setCancelled(true); + } + } + + @EventHandler + public void slowPlants(BlockGrowEvent e) { + int i = 20; + switch (e.getBlock().getBiome()) { + case DESERT: + case DESERT_HILLS: + i = 5; + break; + case SAVANNA: + case SAVANNA_PLATEAU: + case SHATTERED_SAVANNA: + case SHATTERED_SAVANNA_PLATEAU: + i = 23; + break; + case SNOWY_TAIGA: + case SNOWY_TUNDRA: + case SNOWY_TAIGA_MOUNTAINS: + i = 7; + break; + case ICE_SPIKES: + i = 0; + break; + case FLOWER_FOREST: + case FOREST: + case SUNFLOWER_PLAINS: + i = 25; + break; + case SWAMP: + i = 30; + break; + } + + if (r.nextInt(100) > i) { + e.setCancelled(true); + } + + if (e.getBlock().getType() != Material.BEETROOT_SEEDS && e.getBlock().getType() != Material.WHEAT_SEEDS && e.getBlock().getType() != Material.MELON_STEM && e.getBlock().getType() != Material.PUMPKIN_STEM) + return; + + Material replace = null; + e.getBlock().getBlockData(); + + e.getBlock().getLightLevel(); + + if (e.getBlock().getLightLevel() < 5) { + replace = Material.DEAD_BUSH; + } + + if (replace != null) + e.getBlock().setType(replace); + } +} diff --git a/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/Yuri.java b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/Yuri.java new file mode 100644 index 0000000..e51a8f4 --- /dev/null +++ b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/Yuri.java @@ -0,0 +1,247 @@ +package me.yuri.essentials; + +import me.yuri.essentials.auction.Auction; +import me.yuri.essentials.auction.AuctionCommands; +import me.yuri.essentials.hologram.HologramManager; +import me.yuri.essentials.market.Market; +import me.yuri.essentials.market.MarketCommands; +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.YuriPlugin; +import me.yuri.yuriapi.api.command.CommandManager; +import me.yuri.yuriapi.api.db.DbColumnDataType; +import me.yuri.yuriapi.api.db.DbConnection; +import me.yuri.yuriapi.api.db.DbConnectionBuilder; +import me.yuri.yuriapi.api.db.SqliteConnection; +import me.yuri.yuriapi.api.economy.EconomyManager; +import me.yuri.yuriapi.api.item.ItemBuilder; +import me.yuri.yuriapi.api.utils.Colored; +import me.yuri.yuriapi.api.utils.configuration.ConfigVar; +import me.yuri.yuriapi.api.utils.configuration.ConfigVarManager; +import me.yuri.yuriapi.api.utils.metadata.KeyFactory; +import me.yuri.yuriapi.api.utils.metadata.MetadataType; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Sound; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Damageable; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.ShapelessRecipe; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.scheduler.BukkitRunnable; + +import java.io.File; +import java.lang.reflect.Field; + +public class Yuri extends YuriPlugin { + + private static final YListener yl = new YListener(); + @ConfigVar(value = "spawn.x") + public static double x; + @ConfigVar(value = "spawn.y") + public static double y; + @ConfigVar(value = "spawn.z") + public static double z; + @ConfigVar(value = "spawn.world") + public static String world; + + @ConfigVar(value = "portal.x") + public static double px; + @ConfigVar(value = "portal.y") + public static double py; + @ConfigVar(value = "portal.z") + public static double pz; + @ConfigVar(value = "portal.world") + public static String pworld; + + @ConfigVar(value = "teleportCooldown") + public static int cooldown; + public static NamespacedKey VILL; + static SqliteConnection connection; + static SupaDigger supaDigger; + private static Yuri yuri; + + public static Yuri getMain() { + return yuri; + } + + @Override + public void onLoad() { + yuri = this; + + try { + try { + Field f = Enchantment.class.getDeclaredField("acceptingNew"); + f.setAccessible(true); + f.set(null, true); + } catch (Exception e) { + e.printStackTrace(); + } + supaDigger = new SupaDigger(KeyFactory.getKeyFor(this, "supa_digga")); + Enchantment.registerEnchantment(supaDigger); + try { + Field f = Enchantment.class.getDeclaredField("acceptingNew"); + f.setAccessible(true); + f.set(null, false); + } catch (Exception e) { + e.printStackTrace(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void onDisable() { + connection.disconnect(); + Market.getBuyOffers().forEach(c -> { + c.getPlayer().sendMessage("&cYour buy offer had to be cancelled."); + EconomyManager.addFunds(c.getPlayer(), c.getPrice() * c.getCount()); + }); + Market.getSellOffers().forEach(c -> { + c.getPlayer().sendMessage("&cYour sell offer had to be cancelled."); + ItemStack is = new ItemStack(c.getResource().getMaterial()); + is.setAmount(c.getCount()); + c.getPlayer().getBasePlayer().getInventory().addItem(is); + }); + Auction.getAllOffers().forEach(c -> { + c.getPlayer().sendMessage("&cYour auction offer had to be cancelled."); + ItemStack is = c.getItem(); + c.getPlayer().getBasePlayer().getInventory().addItem(is); + }); + HologramManager.save(); + } + + @Override + public void onEnable() { + saveDefaultConfig(); + ConfigVarManager.register(this, yl, this); + ConfigVarManager.update(this); + CommandManager cmd = new CommandManager(this); + cmd.registerCommand(new Commands()); + cmd.registerCommand(new MarketCommands()); + cmd.registerCommand(new AuctionCommands()); + + this.getServer().getPluginManager().registerEvents(yl, this); + + dbConnect(); + + VILL = KeyFactory.getKeyFor(this, "v"); + + new ItemBuilder(Material.ELYTRA, KeyFactory.getKeyFor(this, "suicide_wings"), this) + .withCustomName("&c&lSuicide wings") + .withData("scd", PersistentDataType.BYTE, (byte) 1) + .buildMeta() + .withShapedRecipe(" B ", "MCM", "TTT", + new char[]{'B', 'M', 'C', 'T'}, + new Material[]{Material.STONE_BUTTON, Material.PHANTOM_MEMBRANE, Material.COMPARATOR, Material.TNT}) + .registerRecipes() + .registerOnBuild() + .build(); + + new ItemBuilder(Material.IRON_HORSE_ARMOR, KeyFactory.getKeyFor(this, "gatling_gun"), this) + .withCustomName("&eGatling gun") + .withData("gg", PersistentDataType.BYTE, (byte) 1) + .withData("hm", PersistentDataType.BYTE, (byte) 1) + .buildMeta() + .registerOnBuild() + .build(); + + new ItemBuilder(Material.END_ROD, KeyFactory.getKeyFor(this, "oofer"), this) + .withCustomName("&c&koof&dAssef&c&koof") + .withData("assef", PersistentDataType.BYTE, (byte) 1) + .onAttack(e -> { + e.getEntity().getWorld().strikeLightningEffect(e.getEntity().getLocation()); + if (e.getEntity() instanceof Player) + Bukkit.broadcastMessage(String.format(Colored.colorize("&b%s &cgot kite runnered."), e.getEntity().getName())); + else + e.getDamager().sendMessage(String.format(Colored.colorize("&b%s &cgot kite runnered."), e.getEntity().getName())); + e.getEntity().getWorld().playSound(e.getEntity().getLocation(), Sound.ENTITY_PIG_DEATH, 1, 1); + if (e.getEntity() instanceof Damageable) { + ((Damageable) e.getEntity()).setHealth(0); + } + }) + .buildMeta() + .registerOnBuild() + .build(); + + new ItemBuilder(Material.LIGHT_WEIGHTED_PRESSURE_PLATE, KeyFactory.getKeyFor(this, "ejector"), this) + .withCustomName("&aEjector") + .withData("e", PersistentDataType.BYTE, (byte) 1) + .onPlace(e -> e.applyMetadata(this, "e", MetadataType.BOOLEAN, true)) + .buildMeta() + .registerOnBuild() + .build(); + + new ItemBuilder(Material.POLISHED_BLACKSTONE_BUTTON, KeyFactory.getKeyFor(this, "randomtp"), this) + .withCustomName("&aTeleporter") + .withData("tp", PersistentDataType.BYTE, (byte) 1) + .onPlace(e -> e.applyMetadata(this, "tp", MetadataType.BOOLEAN, true)) + .buildMeta() + .registerOnBuild() + .build(); + + ShapelessRecipe re = new ShapelessRecipe(KeyFactory.getKeyFor(this, "grass"), new ItemStack(Material.GRASS)); + re.addIngredient(8, Material.WHEAT_SEEDS); + re.addIngredient(1, Material.BONE_MEAL); + Bukkit.addRecipe(re); + + ShapelessRecipe rer = new ShapelessRecipe(KeyFactory.getKeyFor(this, "grass_block"), new ItemStack(Material.GRASS_BLOCK)); + rer.addIngredient(3, Material.GRASS); + rer.addIngredient(1, Material.DIRT); + Bukkit.addRecipe(rer); + + ShapelessRecipe rerr = new ShapelessRecipe(KeyFactory.getKeyFor(this, "obsidian"), new ItemStack(Material.OBSIDIAN)); + rerr.addIngredient(1, Material.LAVA_BUCKET); + rerr.addIngredient(1, Material.WATER_BUCKET); + Bukkit.addRecipe(rerr); + + new ItemBuilder(Material.ENCHANTED_BOOK, KeyFactory.getKeyFor(this, "digga_book"), this) + .appendLore("&eSupa digga") + .appendLore("&b&oClick on an inventory item to apply") + .modifyItemMeta(m -> { + EnchantmentStorageMeta em = (EnchantmentStorageMeta) m; + em.addStoredEnchant(supaDigger, 1, true); + return em; + }).withEnchantment(supaDigger, 1) + .buildMeta().registerOnBuild().build(); + + new BukkitRunnable() { + @Override + public void run() { + long time = System.currentTimeMillis(); + for (YPlayer p : YPlayer.getOnlinePlayers()) { + //YPlayer.getOnlinePlayers().forEach(c -> System.out.println(c.getBasePlayer().getName())); + if (!p.getBasePlayer().isOnline()) { + PlayerManager.afk.remove(p); + continue; + } + if ((time - p.onLastMove()) > 180000) { + if (!PlayerManager.afk.contains(p)) + if (!PlayerManager.vanishes.contains(p)) + PlayerManager.setAfk(p, true); + } + } + } + }.runTaskTimerAsynchronously(this, 100L, 20 * 30L); + + HologramManager.load(); + } + + private void dbConnect() { + connection = (SqliteConnection) DbConnection.newConnection(DbConnectionBuilder.DbType.SQLITE) + .withConnectionString("jdbc:sqlite:" + new File(getDataFolder(), "users.sqlite")) + .withTable("HOMES", (b) -> b.withPrimaryKey("uuid", DbColumnDataType.TEXT).withColumn("loc", DbColumnDataType.LOCATION, false).build()) + .withTable("VANISHES", (b) -> b.withPrimaryKey("uuid", DbColumnDataType.UUID).build()).build(); + try { + connection.connect(); + } catch (Exception exception) { + exception.printStackTrace(); + } + //int b = connection.createStatement().executeUpdate("CREATE TABLE IF NOT EXISTS HOMES (uuid text PRIMARY KEY ASC, x real, y real, z real, world text NOT NULL);"); + //Bukkit.getConsoleSender().sendMessage("POPULATION: " + b); + } + +} diff --git a/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/auction/Auction.java b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/auction/Auction.java new file mode 100644 index 0000000..35141b1 --- /dev/null +++ b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/auction/Auction.java @@ -0,0 +1,40 @@ +package me.yuri.essentials.auction; + +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.economy.EconomyManager; +import me.yuri.yuriapi.api.utils.MessageBuilder; +import net.md_5.bungee.api.ChatMessageType; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.List; + +public class Auction { + private static final List aucitems = new ArrayList<>(); + + private Auction() { + } + + public static AuctionItem addOffer(YPlayer p, ItemStack item, int price) { + AuctionItem i = new AuctionItem(p, item, price); + aucitems.add(i); + for (YPlayer pe : YPlayer.getOnlinePlayers()) { + pe.sendMessage(new MessageBuilder(ChatMessageType.CHAT).append("&e" + p.getBasePlayer().getDisplayName() + "&a has created a new auction offer for &e" + EconomyManager.getCurrencySymbol() + price + "&a. ").push().append("&bCheck it out.").clickRunCommand("/auc").hoverText("&bClick to check auctions.").push().build()); + } + return i; + } + + public static boolean cancelOffer(AuctionItem i) { + i.getPlayer().sendMessage("&cYour auction offer has been cancelled."); + i.getPlayer().getBasePlayer().getInventory().addItem(i.getItem()); + return aucitems.remove(i); + } + + public static boolean fullfillOffer(AuctionItem i) { + return aucitems.remove(i); + } + + public static List getAllOffers() { + return aucitems; + } +} diff --git a/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/auction/AuctionCommands.java b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/auction/AuctionCommands.java new file mode 100644 index 0000000..078d022 --- /dev/null +++ b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/auction/AuctionCommands.java @@ -0,0 +1,150 @@ +package me.yuri.essentials.auction; + +import me.yuri.yuriapi.api.command.Cmd; +import me.yuri.yuriapi.api.command.PlayerCommandEvent; +import me.yuri.yuriapi.api.economy.EconomyManager; +import me.yuri.yuriapi.api.inventory.InventoryBuilder; +import me.yuri.yuriapi.api.item.ItemBuilder; +import me.yuri.yuriapi.api.utils.Colored; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.Objects; +import java.util.stream.Collectors; + +public class AuctionCommands { + + @Cmd(command = "auction", aliases = {"auc", "ac"}, consoleSide = false, desc = "Opens the auction") + public void auction(PlayerCommandEvent e) { + InventoryBuilder ib = new InventoryBuilder(27); + ib.withTitle("&cAuction menu").fillItem(ItemBuilder.createNameless(Material.GRAY_STAINED_GLASS_PANE), 0, 27) + .addButton(ItemBuilder.createWithName(Material.GOLD_BLOCK, "&6View your offers"), 11, c -> { + InventoryBuilder ibb = new InventoryBuilder(36).readOnly(); + ibb.withClickSound(Sound.ENTITY_VILLAGER_NO).withTitle("&cYour offers"); + + for (AuctionItem it : Auction.getAllOffers().stream().filter(pp -> pp.getPlayer().equals(e.asPlayer())).collect(Collectors.toList())) { + ItemStack is = it.getItem().clone(); + ItemMeta im = is.hasItemMeta() ? is.getItemMeta() : Bukkit.getItemFactory().getItemMeta(is.getType()); + + assert im != null; + + im.setLore(Arrays.asList(Colored.colorize("&bPrice: &e" + EconomyManager.getCurrencySymbol() + it.getPrice()), + Colored.colorize("&bCreated at: &e" + new Date(it.getDate() * 1000)), + Colored.colorize("&cClick to cancel"))); + + is.setItemMeta(im); + ibb.addButton(is, cc -> { + e.getPlayer().closeInventory(); + Auction.cancelOffer(it); + e.reply("&cOffer cancelled."); + }); + } + ibb.build().open(e.getPlayer()); + }) + .addButton(ItemBuilder.createWithName(Material.EMERALD_BLOCK, "&aCreate offer"), 13, c -> { + e.reply("&aChoose the item you want to select by clicking it in your inventory."); + InventoryBuilder ibb = new InventoryBuilder(36).readOnly().withClickSound(Sound.ENTITY_EXPERIENCE_ORB_PICKUP).withTitle("&2Select item"); + PlayerInventory piv = e.getPlayer().getInventory(); + for (int i = 0; i < e.getPlayer().getInventory().getStorageContents().length; i++) { + ItemStack ori = piv.getItem(i); + if (ori == null) continue; + ItemStack is = ori.clone(); + ItemMeta im = is.hasItemMeta() ? is.getItemMeta() : Bukkit.getItemFactory().getItemMeta(is.getType()); + assert im != null; + im.setLore(Collections.singletonList(Colored.colorize("&aClick to select."))); + is.setItemMeta(im); + int slot = i; + ibb.addButton(is, slot, cc -> { + e.getPlayer().closeInventory(); + e.reply("&aSelect item price:"); + e.asPlayer().onNextMessage(ccc -> { + ccc.setCancelled(true); + try { + int ii = Integer.parseInt(ccc.getMessage()); + + if (ii <= 0) { + e.reply("&cPrice must be greater than &e0&c."); + return; + } + if (!EconomyManager.subtractFunds(e.asPlayer(), 10)) { + e.reply("&cYou don't have enough funds to pay the admission fee (&e" + EconomyManager.getCurrencySymbol() + "10&c)"); + return; + } + + e.reply("&aOffer created."); + Auction.addOffer(e.asPlayer(), ori, ii); + e.getPlayer().getInventory().setItem(slot, null); + } catch (Exception ignored) { + e.reply("&cInvalid price, cancelling."); + } + }); + }); + } + ibb.build().open(e.getPlayer()); + }) + .addButton(ItemBuilder.createWithName(Material.DIAMOND_BLOCK, "&bView all offers"), 15, c -> { + InventoryBuilder ibb = new InventoryBuilder(54).readOnly(); + ibb.withClickSound(Sound.ENTITY_EXPERIENCE_ORB_PICKUP).withTitle("&cAll offers"); + + for (AuctionItem it : Auction.getAllOffers()) { + if (!it.getPlayer().equals(e.asPlayer())) { + ItemStack is = it.getItem().clone(); + ItemMeta im = is.hasItemMeta() ? is.getItemMeta() : Bukkit.getItemFactory().getItemMeta(is.getType()); + + assert im != null; + System.out.printf("A: %s, B: %s, C: %s, D: %s\n", (it.getPlayer() == null), EconomyManager.getCurrencySymbol() == null, it.getPrice(), Arrays.toString(Auction.getAllOffers().toArray())); + System.out.println((it.getPlayer().getBasePlayer() == null)); + im.setLore(Arrays.asList(Colored.colorize("&bOwner: &e" + it.getPlayer().getBasePlayer().getDisplayName()), + Colored.colorize("&bPrice: &e" + EconomyManager.getCurrencySymbol() + it.getPrice()), + Colored.colorize("&bCreated at: &e" + new Date(it.getDate() * 1000)))); + + is.setItemMeta(im); + ibb.addButton(is, cc -> { + e.getPlayer().closeInventory(); + cc.cancelClickSound(true); + cc.getPlayer().playSound(Sound.ENTITY_EXPERIENCE_ORB_PICKUP); + e.reply(String.format("&aYou are going to purchase an item for &e%s%d&a. Type &byes&a to confirm your action.", EconomyManager.getCurrencySymbol(), it.getPrice())); + cc.getPlayer().onNextMessage(ccc -> { + ccc.setCancelled(true); + if (ccc.getMessage().equalsIgnoreCase("yes")) { + if (!EconomyManager.subtractFunds(e.asPlayer(), it.getPrice())) { + e.reply("&cYou don't have enough funds (&6" + EconomyManager.getCurrencySymbol() + it.getPrice() + "&c)."); + } else { + Auction.fullfillOffer(it); + EconomyManager.addFunds(it.getPlayer(), it.getPrice()); + String itm = it.getItem().hasItemMeta() && Objects.requireNonNull(it.getItem().getItemMeta()).hasDisplayName() ? it.getItem().getItemMeta().getDisplayName() : "item"; + it.getPlayer().sendMessage(String.format("&b%s&a has bought %s for &e%s%d&a.", e.getPlayer().getDisplayName(), itm, EconomyManager.getCurrencySymbol(), it.getPrice())); + e.getPlayer().getInventory().addItem(it.getItem()); + e.reply("&aYou have bought the &b" + itm + "&a for &e" + EconomyManager.getCurrencySymbol() + it.getPrice() + "&a."); + } + } else { + e.reply("&cAction cancelled."); + } + }); + }); + } else { + ItemStack is = it.getItem().clone(); + ItemMeta im = is.hasItemMeta() ? is.getItemMeta() : Bukkit.getItemFactory().getItemMeta(is.getType()); + + assert im != null; + + im.setLore(Arrays.asList(Colored.colorize("&bOwner: &eyou"), + Colored.colorize("&bPrice: &e" + EconomyManager.getCurrencySymbol() + it.getPrice()), + Colored.colorize("&bCreated at: &e" + new Date(it.getDate() * 1000)))); + + is.setItemMeta(im); + ibb.withItem(is); + } + } + ibb.build().open(e.getPlayer()); + }) + .readOnly().withClickSound(Sound.UI_BUTTON_CLICK).build().open(e.getPlayer()); + } +} diff --git a/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/auction/AuctionItem.java b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/auction/AuctionItem.java new file mode 100644 index 0000000..8b3f4ec --- /dev/null +++ b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/auction/AuctionItem.java @@ -0,0 +1,39 @@ +package me.yuri.essentials.auction; + +import me.yuri.yuriapi.api.YPlayer; +import org.bukkit.inventory.ItemStack; + +import java.time.OffsetDateTime; + +public class AuctionItem { + private final YPlayer player; + private final ItemStack item; + private final long date; + private int price; + public AuctionItem(YPlayer y, ItemStack is, int price) { + player = y; + item = is; + this.price = price; + this.date = OffsetDateTime.now().toEpochSecond(); + } + + public YPlayer getPlayer() { + return player; + } + + public ItemStack getItem() { + return item; + } + + public int getPrice() { + return price; + } + + public void setPrice(int price) { + this.price = price; + } + + public long getDate() { + return date; + } +} diff --git a/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/hologram/Hologram.java b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/hologram/Hologram.java new file mode 100644 index 0000000..6d25e84 --- /dev/null +++ b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/hologram/Hologram.java @@ -0,0 +1,74 @@ +package me.yuri.essentials.hologram; + +import org.bukkit.Location; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +public class Hologram { + private final int id; + private final List lines; + private final Location l; + public List stands = new ArrayList<>(); + public Hologram(Location l, String... lines) { + this.id = HologramManager.newId(); + this.lines = Arrays.asList(lines); + this.l = l; + } + public Hologram(Location l, List lines) { + this.id = HologramManager.newId(); + this.lines = lines; + this.l = l; + } + + public Hologram(int id, Location l, List lines) { + this.id = id; + this.lines = lines; + this.l = l; + } + + public List getLines() { + return lines; + } + + public int getId() { + return id; + } + + public Location getLocation() { + return l; + } + + public void addLine(String line) { + lines.add(line); + update(); + } + + public void addStands() { + float yoffset = 0f; + for (String line : lines) { + ArmorStand as = Objects.requireNonNull(l.getWorld()).spawn(l.clone().add(0, -yoffset, 0), ArmorStand.class); + as.setVisible(false); + as.setInvulnerable(true); + as.setGravity(false); + as.setCustomName(line); + as.setCustomNameVisible(true); + stands.add(as); + yoffset += 0.2f; + } + } + + public void removeStand() { + stands.forEach(Entity::remove); + stands.clear(); + } + + public void update() { + removeStand(); + addStands(); + } +} diff --git a/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/hologram/HologramManager.java b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/hologram/HologramManager.java new file mode 100644 index 0000000..73e8494 --- /dev/null +++ b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/hologram/HologramManager.java @@ -0,0 +1,87 @@ +package me.yuri.essentials.hologram; + +import me.yuri.essentials.Yuri; +import org.bukkit.Location; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; + +public class HologramManager { + private static final Set holograms = new HashSet<>(); + private static YamlConfiguration holos = null; + + private HologramManager() { + } + + public static void load() { + try { + holos = new YamlConfiguration(); + holos.load(new File(Yuri.getMain().getDataFolder(), "holograms.yml")); + for (String k : holos.getKeys(false)) { + ConfigurationSection sec = holos.getConfigurationSection(k); + if (sec == null) continue; + int id = Integer.parseInt(k); + Location loc = sec.getLocation("loc"); + List lines = sec.getStringList("content"); + addHologram(new Hologram(id, loc, lines)); + System.out.println("Loaded holo: " + sec.getName()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void save() { + try { + holos = new YamlConfiguration(); + for (Hologram h : holograms) { + String sec = String.valueOf(h.getId()); + holos.set(sec + ".loc", h.getLocation()); + holos.set(sec + ".content", h.getLines()); + h.removeStand(); + System.out.println("Added holo: " + sec); + } + holograms.clear(); + holos.save(new File(Yuri.getMain().getDataFolder(), "holograms.yml")); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void addHologram(Hologram h) { + holograms.add(h); + h.addStands(); + } + + public static void remove(int id) { + Hologram h = holograms.stream().filter(c -> c.getId() == id).findFirst().orElse(null); + if (h == null) return; + holograms.remove(h); + h.removeStand(); + } + + public static Hologram getById(int id) { + return holograms.stream().filter(c -> c.getId() == id).findFirst().orElse(null); + } + + public static int newId() { + Random r = new Random(); + int i = 0; + boolean b = true; + while (b) { + i = r.nextInt(); + int fi = i; + b = holograms.stream().anyMatch(c -> c.getId() == fi); + } + return i; + } + + public static Set getAll() { + return holograms; + } +} diff --git a/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/BuyOffer.java b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/BuyOffer.java new file mode 100644 index 0000000..79db156 --- /dev/null +++ b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/BuyOffer.java @@ -0,0 +1,11 @@ +package me.yuri.essentials.market; + +import me.yuri.yuriapi.api.YPlayer; + +public class BuyOffer extends Offer { + public BuyOffer(YPlayer p, Resource r, int price, int count) { + super(p, r, price, count); + } + + +} diff --git a/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/Market.java b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/Market.java new file mode 100644 index 0000000..46edc23 --- /dev/null +++ b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/Market.java @@ -0,0 +1,152 @@ +package me.yuri.essentials.market; + +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.economy.EconomyManager; +import org.bukkit.inventory.ItemStack; + +import java.util.*; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +public final class Market { + //FIRST: BUY, SECOND: SELL + private static final Map> values = new HashMap<>(); + private static final List offers = Collections.synchronizedList(new ArrayList<>()); + private static final List buyRequests = Collections.synchronizedList(new ArrayList<>()); + private static Transaction last; + + private Market() { + } + + public static void updatePrices() { + for (Resource r : Resource.values()) { + List of = offers.stream().filter(o -> o.getResource() == r).collect(Collectors.toList()); + List br = buyRequests.stream().filter(o -> o.getResource() == r).collect(Collectors.toList()); + + int minBPrice = 0, maxBPrice = 0, avgBPrice, bValue = 0, minSPrice = 0, maxSPrice = 0, avgSPrice, sValue = 0; + for (SellOffer f : of) { + int price = f.getPrice(); + sValue += price; + if (price < minSPrice) + minSPrice = price; + else if (price > maxSPrice) + maxSPrice = price; + } + + avgSPrice = of.size() != 0 ? sValue / of.size() : 0; + + for (BuyOffer rq : br) { + int price = rq.getPrice(); + bValue += price; + if (price < minBPrice) + minBPrice = price; + else if (price > maxBPrice) + maxBPrice = price; + } + + avgBPrice = br.size() != 0 ? bValue / br.size() : 0; + + values.put(r, new AbstractMap.SimpleImmutableEntry<>(avgBPrice, avgSPrice)); + } + } + + protected static List match() { + List trs = new ArrayList<>(); + List closedOff = new ArrayList<>(); + List closedRq = new ArrayList<>(); + + for (SellOffer o : offers) { + buyRequests.stream().filter(r -> r.getPrice() == o.getPrice() && !r.getPlayer().equals(o.getPlayer())).forEach(r -> { + Transaction t = new Transaction(r, o); + trs.add(t); + if (o.isClosed()) closedOff.add(o); + if (r.isClosed()) closedRq.add(r); + }); + } + + offers.removeAll(closedOff); + buyRequests.removeAll(closedRq); + + return trs; + } + + public static void update() { + match().forEach(t -> { + t.getRequest().getPlayer().sendMessage("&aYour buy offer has been accepted.", + String.format("&aYou have received &6%d %s&a.", t.getCount(), t.getRequest().getResource().getName())); + t.getOffer().getPlayer().sendMessage("&aYour sell offer has been accepted.", + String.format("&aYou have received &6%s%d&a.", EconomyManager.getCurrencySymbol(), t.getTotalPrice())); + EconomyManager.addFunds(t.getOffer().getPlayer(), t.getTotalPrice()); + ItemStack is = new ItemStack(t.getRequest().getResource().getMaterial()); + is.setAmount(t.getCount()); + t.getRequest().getPlayer().getBasePlayer().getInventory().addItem(is); + t.getRequest().getPlayer().sendMessage(t.getRequest().count == 0 ? "&bYour buy offer has been closed." : "&bThe volumen of your buy offer has dropped to &6" + t.getRequest().getCount() + "&b."); + t.getOffer().getPlayer().sendMessage(t.getOffer().count == 0 ? "&bYour sell offer has been closed." : "&bThe volumen of your sell offer has dropped to &6" + t.getOffer().getCount() + "&b."); + }); + } + + public static List getBuyOffers() { + return buyRequests; + } + + public static List getSellOffers() { + return offers; + } + + public static List getBuyOffersForPlayer(YPlayer p) { + return buyRequests.stream().filter(o -> o.getPlayer().equals(p)).collect(Collectors.toList()); + } + + public static List getSellOffersForPlayer(YPlayer p) { + return offers.stream().filter(o -> o.getPlayer().equals(p)).collect(Collectors.toList()); + } + + public static List getOffersForPlayer(YPlayer p) { + List l = new ArrayList<>(); + l.addAll(getBuyOffersForPlayer(p)); + l.addAll(getSellOffersForPlayer(p)); + return l; + } + + public static List getOffers() { + List l = new ArrayList<>(); + l.addAll(offers); + l.addAll(buyRequests); + return l; + } + + public static SellOffer addSellOffer(YPlayer p, Resource r, int volumen, int price) { + SellOffer o = new SellOffer(p, r, price, volumen); + offers.add(o); + Executors.newSingleThreadScheduledExecutor().schedule(Market::update, 3, TimeUnit.SECONDS); + return o; + } + + public static BuyOffer addBuyOffer(YPlayer p, Resource r, int volumen, int price) { + BuyOffer rq = new BuyOffer(p, r, price, volumen); + buyRequests.add(rq); + Executors.newSingleThreadScheduledExecutor().schedule(Market::update, 3, TimeUnit.SECONDS); + return rq; + } + + public static int getAverageBuyPriceFor(Resource r) { + AbstractMap.SimpleImmutableEntry s = values.get(r); + if (s == null) return 0; + return s.getKey(); + } + + public static int getAverageSellPriceFor(Resource r) { + AbstractMap.SimpleImmutableEntry s = values.get(r); + if (s == null) return 0; + return s.getValue(); + } + + public static int getSellOffersFor(Resource r) { + return (int) offers.stream().filter(o -> o.getResource() == r).count(); + } + + public static int getBuyOffersFor(Resource r) { + return (int) buyRequests.stream().filter(o -> o.getResource() == r).count(); + } +} \ No newline at end of file diff --git a/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/MarketCommands.java b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/MarketCommands.java new file mode 100644 index 0000000..5b5a56c --- /dev/null +++ b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/MarketCommands.java @@ -0,0 +1,255 @@ +package me.yuri.essentials.market; + +import me.yuri.essentials.Yuri; +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.command.Cmd; +import me.yuri.yuriapi.api.command.CommandEvent; +import me.yuri.yuriapi.api.command.PlayerCommandEvent; +import me.yuri.yuriapi.api.economy.EconomyManager; +import me.yuri.yuriapi.api.inventory.InventoryBuilder; +import me.yuri.yuriapi.api.item.ItemBuilder; +import me.yuri.yuriapi.api.utils.ItemUtils; +import me.yuri.yuriapi.api.utils.MessageBuilder; +import net.md_5.bungee.api.ChatMessageType; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.inventory.ItemStack; + +import java.util.*; + +public class MarketCommands { + + private static final ItemStack gold_c = new ItemBuilder(Material.GOLD_BLOCK, Yuri.getMain(), "null").withCustomName("&aSelected: &6Gold").build().getItemstack(), + diamond_c = new ItemBuilder(Material.DIAMOND_BLOCK, Yuri.getMain(), "null").withCustomName("&aSelected: &bDiamond").build().getItemstack(), + nether_c = new ItemBuilder(Material.NETHERITE_BLOCK, Yuri.getMain(), "null").withCustomName("&aSelected: &cNetherite").build().getItemstack(), + counter_tag = new ItemBuilder(Material.NAME_TAG, Yuri.getMain(), "null").withCustomName("&aAmount: &e0").appendLore("&aClick to create offer.").build().getItemstack(); + + @Cmd(command = "market", consoleSide = false, tabCompletions = {"offers", "offers all"}) + public void stonks(PlayerCommandEvent e) { + if (e.getArgs().length == 0) { + Map offer = new HashMap<>(); + offer.put(0, Resource.GOLD); + InventoryBuilder ib = new InventoryBuilder(27) + .addButton(new ItemBuilder(Material.GOLD_INGOT, Yuri.getMain(), "null").withCustomName("&6Gold").build(), 3, (con) -> { + offer.put(0, Resource.GOLD); + con.getInventory().setItem(22, gold_c); + con.getPlayer().playSound(Sound.ENTITY_EXPERIENCE_ORB_PICKUP); + }) + .addButton(new ItemBuilder(Material.DIAMOND, Yuri.getMain(), "null").withCustomName("&bDiamond").build(), 4, (con) -> { + offer.put(0, Resource.DIAMONDS); + con.getInventory().setItem(22, diamond_c); + con.getPlayer().playSound(Sound.ENTITY_EXPERIENCE_ORB_PICKUP); + }) + .addButton(new ItemBuilder(Material.NETHERITE_INGOT, Yuri.getMain(), "null").withCustomName("&cNetherite").build(), 5, (con) -> { + offer.put(0, Resource.NETHERITE); + con.getInventory().setItem(22, nether_c); + con.getPlayer().playSound(Sound.ENTITY_EXPERIENCE_ORB_PICKUP); + }) + .addButton(new ItemBuilder(Material.GREEN_STAINED_GLASS_PANE, Yuri.getMain(), "null").withCustomName("&a+1").build(), 10, con -> { + offer.put(1, ((int) offer.getOrDefault(1, 0) + 1)); + con.getInventory().rename(13, String.format("&aAmount: &e%s", offer.get(1))); + con.getPlayer().playSound(Sound.UI_BUTTON_CLICK); + }) + .addButton(new ItemBuilder(Material.GREEN_STAINED_GLASS_PANE, Yuri.getMain(), "null").withCustomName("&a+10").build(), 11, con -> { + offer.put(1, ((int) offer.getOrDefault(1, 0) + 10)); + con.getInventory().rename(13, String.format("&aAmount: &e%s", offer.get(1))); + con.getPlayer().playSound(Sound.UI_BUTTON_CLICK); + }) + .addButton(new ItemBuilder(Material.GREEN_STAINED_GLASS_PANE, Yuri.getMain(), "null").withCustomName("&a+100").build(), 12, con -> { + offer.put(1, ((int) offer.getOrDefault(1, 0) + 100)); + con.getInventory().rename(13, String.format("&aAmount: &e%s", offer.get(1))); + con.getPlayer().playSound(Sound.UI_BUTTON_CLICK); + }) + .addButton(new ItemBuilder(Material.RED_STAINED_GLASS_PANE, Yuri.getMain(), "null").withCustomName("&a-1").build(), 14, con -> { + int ii = ((int) offer.getOrDefault(1, 0)); + if (ii - 1 <= 0) return; + offer.put(1, ii - 1); + con.getInventory().rename(13, String.format("&aAmount: &e%s", offer.get(1))); + con.getPlayer().playSound(Sound.UI_BUTTON_CLICK); + }) + .addButton(new ItemBuilder(Material.RED_STAINED_GLASS_PANE, Yuri.getMain(), "null").withCustomName("&a-10").build(), 15, con -> { + int ii = ((int) offer.getOrDefault(1, 0)); + if (ii - 10 <= 0) return; + offer.put(1, ii - 10); + con.getInventory().rename(13, String.format("&aAmount: &e%s", offer.get(1))); + con.getPlayer().playSound(Sound.UI_BUTTON_CLICK); + }) + .addButton(new ItemBuilder(Material.RED_STAINED_GLASS_PANE, Yuri.getMain(), "null").withCustomName("&a-100").build(), 16, con -> { + int ii = ((int) offer.getOrDefault(1, 0)); + if (ii - 100 <= 0) return; + offer.put(1, ii - 100); + con.getInventory().rename(13, String.format("&aAmount: &e%s", offer.get(1))); + con.getPlayer().playSound(Sound.UI_BUTTON_CLICK); + }) + .withItem(gold_c, 22); + + new InventoryBuilder(27) + .withTitle("&cMarket") + .fillItem(new ItemBuilder(Material.BLACK_STAINED_GLASS_PANE, Yuri.getMain(), "null") + .withCustomName(" ").build(), 0, 27) + .withItem(new ItemBuilder(Material.RED_STAINED_GLASS_PANE, Yuri.getMain(), "null").withCustomName(" ").build() + .getItemstack(), 4, 0) + .addButton(new ItemBuilder(Material.GREEN_STAINED_GLASS_PANE, Yuri.getMain(), "null").withCustomName("&aCreate buy offer") + .build(), 10, c -> { + ib.addButton(counter_tag, 13, con -> { + if ((int) offer.get(1) == 0) { + con.getPlayer().playSound(Sound.ENTITY_VILLAGER_NO); + return; + } + con.getPlayer().getBasePlayer().closeInventory(); + con.getPlayer().playSound(Sound.ENTITY_EXPERIENCE_ORB_PICKUP); + con.getPlayer().sendMessage("&aPlease enter the unit price: "); + con.getPlayer().onNextMessage(cn -> { + cn.setCancelled(true); + try { + int f = Integer.parseInt(cn.getMessage()); + if (f <= 0) { + con.getPlayer().playSound(Sound.ENTITY_VILLAGER_NO); + con.getPlayer().sendMessage("&cPrice must be higher than 0."); + return; + } + Resource r = (Resource) offer.get(0); + int v = (int) offer.get(1); + int total = v * f; + if (!EconomyManager.subtractFunds(con.getPlayer(), total)) { + con.getPlayer().playSound(Sound.ENTITY_VILLAGER_NO); + con.getPlayer().sendMessage(String.format("&cYou don't have the required funds (&6%s%d&c).", EconomyManager.getCurrencySymbol(), total)); + return; + } + Market.addBuyOffer(con.getPlayer(), r, v, f); + for (YPlayer pe : YPlayer.getOnlinePlayers()) { + pe.sendMessage(new MessageBuilder(ChatMessageType.CHAT).append("&e" + e.asPlayer().getBasePlayer().getDisplayName() + "&a has a purchase offer for &d" + r.getName() + "&a, &e" + EconomyManager.getCurrencySymbol() + f + "&a per unit. ").push().append("&6Check it out.").hoverText("&cClick to check offers").clickRunCommand("/market offers all").push().build()); + } + con.getPlayer().sendMessage("&aBuy offer successfully placed."); + } catch (Exception ignored) { + con.getPlayer().sendMessage("&cInvalid price."); + } + }); + }) + .readOnly().build().open(e.getPlayer()); + c.getPlayer().playSound(Sound.UI_BUTTON_CLICK); + }) + .addButton(new ItemBuilder(Material.GREEN_STAINED_GLASS_PANE, Yuri.getMain(), "null").withCustomName("&aCreate sell offer") + .build(), 16, c -> { + ib.addButton(counter_tag, 13, con -> { + if ((int) offer.get(1) == 0) { + con.getPlayer().playSound(Sound.ENTITY_VILLAGER_NO); + return; + } + con.getPlayer().getBasePlayer().closeInventory(); + con.getPlayer().playSound(Sound.ENTITY_EXPERIENCE_ORB_PICKUP); + con.getPlayer().sendMessage("&aPlease enter the unit price: "); + con.getPlayer().onNextMessage(cn -> { + cn.setCancelled(true); + try { + int f = Integer.parseInt(cn.getMessage()); + if (f <= 0) { + con.getPlayer().playSound(Sound.ENTITY_VILLAGER_NO); + con.getPlayer().sendMessage("&cPrice must be higher than 0."); + return; + } + Resource r = (Resource) offer.get(0); + int v = (int) offer.get(1); + if (!ItemUtils.removeItem(cn.getPlayer().getInventory(), r.getMaterial(), v)) { + con.getPlayer().playSound(Sound.ENTITY_VILLAGER_NO); + con.getPlayer().sendMessage(String.format("&cYou don't have the required resources (&6%d %s&c).", v, r.getName())); + return; + } + Market.addSellOffer(con.getPlayer(), r, (int) offer.get(1), f); + for (YPlayer pe : YPlayer.getOnlinePlayers()) { + pe.sendMessage(new MessageBuilder(ChatMessageType.CHAT).append("&e" + e.asPlayer().getBasePlayer().getDisplayName() + "&a has a sell offer for &d" + r.getName() + "&a, &e" + EconomyManager.getCurrencySymbol() + f + "&a per unit. ").push().append("&6Check it out.").hoverText("&cClick to check offers").clickRunCommand("/market offers all").push().build()); + } + con.getPlayer().sendMessage("&aSell offer successfully placed."); + } catch (Exception ignored) { + con.getPlayer().sendMessage("&cInvalid price."); + } + }); + }) + .readOnly().build().open(e.getPlayer()); + c.getPlayer().playSound(Sound.UI_BUTTON_CLICK); + }) + .addButton(new ItemBuilder(Material.GOLD_BLOCK, Yuri.getMain(), "null").withCustomName("&6View own offers").build(), 4, 1, cc -> { + cc.getPlayer().playSound(Sound.UI_BUTTON_CLICK); + cc.getPlayer().getBasePlayer().performCommand("market offers"); + }) + .addButton(new ItemBuilder(Material.DIAMOND_BLOCK, Yuri.getMain(), "null").withCustomName("&6View all offers").build(), 4, 2, cc -> { + cc.getPlayer().playSound(Sound.UI_BUTTON_CLICK); + cc.getPlayer().getBasePlayer().performCommand("market offers all"); + }) + .readOnly() + .build().open(e.getPlayer()); + } else { + if (e.getArgs()[0].equalsIgnoreCase("offers")) { + boolean all = e.getArgs().length > 1 && e.getArgs()[1].equalsIgnoreCase("all"); + InventoryBuilder ib = new InventoryBuilder(36); + List offers = new ArrayList<>(all ? Market.getOffers() : Market.getOffersForPlayer(e.asPlayer())); + offers.sort(Comparator.comparingLong(Offer::getTimestamp)); + int cnt = 1; + for (Offer o : offers) { + boolean s = o instanceof SellOffer; + ItemBuilder ibb = new ItemBuilder(o.r.getMaterial(), Yuri.getMain(), "null") + .withCustomName((s ? "&cSell offer " : "&aBuy offer ") + "#" + cnt); + if (all) + ibb.appendLore("&bOwner: &e" + o.getPlayer().getBasePlayer().getDisplayName()); + + + ibb.appendLore("&bUnit price: &e" + o.price) + .appendLore("&bVolumen: &e" + o.count) + .appendLore("&bCreated at: &e" + new Date(o.timestamp * 1000)); + + if (!all) { + ibb.appendLore("&cClick to cancel"); + ib.addButton(ibb.build(), cc -> { + if (s) { + if (Market.getSellOffers().remove(o)) { + e.reply("&cYour sell offer has been cancelled."); + ItemStack is = new ItemStack(o.getResource().getMaterial()); + is.setAmount(o.getCount()); + e.getPlayer().getInventory().addItem(is); + } else { + e.reply("&cYour offer had already been cancelled."); + } + } else { + if (Market.getBuyOffers().remove(o)) { + e.reply("&cYour buy offer has been cancelled."); + EconomyManager.addFunds(e.asPlayer(), o.getPrice() * o.getCount()); + } else { + e.reply("&cYour offer had already been cancelled."); + } + } + cc.getInventory().removeItem(cc.getSlot()); + cc.getPlayer().playSound(Sound.ENTITY_VILLAGER_TRADE); + }); + } else { + ib.withItem(ibb.build()); + } + + ++cnt; + } + + ib.withTitle(all ? "&cAll offers" : "&c" + e.getPlayer().getDisplayName() + "'s &coffers."); + ib.readOnly().build().open(e.getPlayer()); + } else { + e.reply("&cInvalid argument. Use &b/market offers&c."); + } + } + } + + @Cmd(command = "marketstats", aliases = "mstats") + public void marketStats(CommandEvent e) { + e.reply("&a============[&3Market stats&a]============", + "&3Buying:", + String.format(" &3- &6gold: &2%d", Market.getBuyOffersFor(Resource.GOLD)), + String.format(" &3- &bdiamonds: &2%d", Market.getBuyOffersFor(Resource.DIAMONDS)), + String.format(" &3- &cnetherite: &2%d", Market.getBuyOffersFor(Resource.NETHERITE)), + "&3Selling:", + String.format(" &3- &6gold: &4%d", Market.getSellOffersFor(Resource.GOLD)), + String.format(" &3- &bdiamonds: &4%d", Market.getSellOffersFor(Resource.DIAMONDS)), + String.format(" &3- &cnetherite: &4%d", Market.getSellOffersFor(Resource.NETHERITE)), + "&3Prices:", + String.format(" &3- &6gold: &2%d&e/&4%d", Market.getAverageBuyPriceFor(Resource.GOLD), Market.getAverageSellPriceFor(Resource.GOLD)), + String.format(" &3- &bdiamonds: &2%d&e/&4%d", Market.getAverageBuyPriceFor(Resource.DIAMONDS), Market.getAverageSellPriceFor(Resource.DIAMONDS)), + String.format(" &3- &cnetherite: &2%d&e/&4%d", Market.getAverageBuyPriceFor(Resource.NETHERITE), Market.getAverageSellPriceFor(Resource.NETHERITE)), + "&a===================================="); + } +} \ No newline at end of file diff --git a/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/Offer.java b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/Offer.java new file mode 100644 index 0000000..f3633d1 --- /dev/null +++ b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/Offer.java @@ -0,0 +1,66 @@ +package me.yuri.essentials.market; + +import me.yuri.yuriapi.api.YPlayer; + +import java.time.OffsetDateTime; +import java.util.Random; + +public class Offer { + + protected final YPlayer p; + protected final Resource r; + protected final int price; + protected int count; + protected boolean closed = false; + protected long timestamp; + protected long id; + + public Offer(YPlayer p, Resource r, int price, int count) { + this.p = p; + this.r = r; + this.price = price; + this.count = count; + this.timestamp = OffsetDateTime.now().toEpochSecond(); + id = new Random().nextLong(); + } + + public YPlayer getPlayer() { + return p; + } + + public Resource getResource() { + return r; + } + + public int getPrice() { + return price; + } + + public int getCount() { + return count; + } + + public long getTimestamp() { + return timestamp; + } + + public long getId() { + return id; + } + + public void reduce(int i) { + count -= i; + if (count <= 0) { + closed = true; + } + } + + public void close() { + closed = true; + } + + public boolean isClosed() { + if (count <= 0) closed = true; + return closed; + } +} diff --git a/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/Resource.java b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/Resource.java new file mode 100644 index 0000000..2c2e6ef --- /dev/null +++ b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/Resource.java @@ -0,0 +1,23 @@ +package me.yuri.essentials.market; + +import org.bukkit.Material; + +public enum Resource { + MONEY("funds", null), GOLD("gold", Material.GOLD_INGOT), DIAMONDS("diamonds", Material.DIAMOND), NETHERITE("netherite", Material.NETHERITE_INGOT); + + private final String name; + private final Material material; + + Resource(String s, Material m) { + this.name = s; + this.material = m; + } + + public String getName() { + return name; + } + + public Material getMaterial() { + return material; + } +} diff --git a/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/SellOffer.java b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/SellOffer.java new file mode 100644 index 0000000..abcd40b --- /dev/null +++ b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/SellOffer.java @@ -0,0 +1,10 @@ +package me.yuri.essentials.market; + +import me.yuri.yuriapi.api.YPlayer; + +public class SellOffer extends Offer { + public SellOffer(YPlayer p, Resource r, int price, int count) { + super(p, r, price, count); + } + +} diff --git a/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/Transaction.java b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/Transaction.java new file mode 100644 index 0000000..1a3fe60 --- /dev/null +++ b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/market/Transaction.java @@ -0,0 +1,45 @@ +package me.yuri.essentials.market; + +public class Transaction { + private final BuyOffer rq; + private final SellOffer of; + private final int volumen; + private final int price; + + public Transaction(BuyOffer r, SellOffer o) { + this.rq = r; + this.of = o; + if (r.getResource() != o.getResource()) { + throw new IllegalArgumentException(String.format("Resources must match (%s != %s)", r.getResource(), o.getResource())); + } + + if (r.getPrice() != o.getPrice()) { + throw new IllegalArgumentException("Prices must match"); + } + + price = r.getPrice(); + volumen = Math.min(r.getCount(), o.getCount()); + r.reduce(volumen); + o.reduce(volumen); + } + + public BuyOffer getRequest() { + return rq; + } + + public SellOffer getOffer() { + return of; + } + + public int getPrice() { + return price; + } + + public int getTotalPrice() { + return price * volumen; + } + + public int getCount() { + return volumen; + } +} diff --git a/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/shop/Shop.java b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/shop/Shop.java new file mode 100644 index 0000000..7b728d7 --- /dev/null +++ b/YuriPlugins/YuriEssentials/src/main/java/me/yuri/essentials/shop/Shop.java @@ -0,0 +1,131 @@ +package me.yuri.essentials.shop; + +import me.yuri.essentials.Yuri; +import me.yuri.yuriapi.Desu; +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.economy.EconomyManager; +import me.yuri.yuriapi.api.inventory.InventoryBuilder; +import me.yuri.yuriapi.api.item.ItemBuilder; +import me.yuri.yuriapi.api.item.ItemRegistry; +import me.yuri.yuriapi.api.utils.Colored; +import me.yuri.yuriapi.api.utils.ItemUtils; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.*; + +public class Shop { + public static final HashMap priceTable; + public static final HashMap sellTable; + + static { + priceTable = new LinkedHashMap<>(); + priceTable.put(Material.BEEF, 10); + priceTable.put(Material.COOKED_BEEF, 20); + priceTable.put(Material.CHICKEN, 15); + priceTable.put(Material.COOKED_CHICKEN, 25); + priceTable.put(Material.PORKCHOP, 10); + priceTable.put(Material.COOKED_PORKCHOP, 20); + priceTable.put(Material.BREAD, 20); + priceTable.put(Material.COD, 20); + priceTable.put(Material.COOKED_COD, 25); + priceTable.put(Material.PUFFERFISH, 80); + priceTable.put(Material.ROTTEN_FLESH, 4); + priceTable.put(Material.APPLE, 15); + priceTable.put(Material.CAKE, 80); + priceTable.put(Material.PUMPKIN_PIE, 70); + priceTable.put(Material.PUMPKIN, 40); + priceTable.put(Material.MELON, 50); + priceTable.put(Material.SUGAR_CANE, 20); + priceTable.put(Material.INK_SAC, 10); + priceTable.put(Material.SLIME_BALL, 30); + priceTable.put(Material.BONE_BLOCK, 50); + priceTable.put(Material.DIAMOND, 12000); + priceTable.put(Material.GOLD_INGOT, 6000); + priceTable.put(Material.NETHERITE_INGOT, 20000); + priceTable.put(Material.EMERALD, 6000); + priceTable.put(Material.REDSTONE_BLOCK, 500); + + sellTable = new HashMap<>(); + sellTable.put(Material.DIAMOND, 1500); + sellTable.put(Material.GOLD_INGOT, 300); + sellTable.put(Material.NETHERITE_INGOT, 3000); + } + + private Shop() { + } + + public static int getBuyPrice(Material m) { + return priceTable.getOrDefault(m, -1); + } + + public static int getSellPrice(Material m) { + return sellTable.getOrDefault(m, priceTable.getOrDefault(m, -3) / 3); + } + + public static void openInventory(Player p) { + YPlayer pl = YPlayer.get(p); + new InventoryBuilder(27).withTitle("&aShop").withClickSound(Sound.UI_BUTTON_CLICK).readOnly() + .fillItem(ItemBuilder.createNameless(Material.GRAY_STAINED_GLASS_PANE), 0, 27) + .addButton(ItemBuilder.createWithName(Material.GOLD_BLOCK, "&6Buy"), 11, c -> { + InventoryBuilder ibb = new InventoryBuilder(36).withTitle("&6Buy").readOnly(); + for (Map.Entry en : priceTable.entrySet()) { + ibb.addButton(new ItemBuilder(en.getKey(), Desu.getMain(), "null").appendLore("&3Unit price: &6" + EconomyManager.getCurrencySymbol() + en.getValue()).appendLore("&eClick to buy »").appendLore("&eShift-click to buy x10 »").build().getItemstack(), cc -> { + if (EconomyManager.subtractFunds(pl, cc.getEvent().isShiftClick() ? 10 * en.getValue() : en.getValue())) { + int count = cc.getEvent().isShiftClick() ? 10 : 1; + ItemStack is = new ItemStack(en.getKey()); + is.setAmount(count); + p.getInventory().addItem(is); + pl.playSound(Sound.ENTITY_EXPERIENCE_ORB_PICKUP); + pl.sendMessage(String.format("&aBought %dx &e%s&a for &e%s%d&a.", count, en.getKey().name(), EconomyManager.getCurrencySymbol(), en.getValue())); + } else { + pl.playSound(Sound.ENTITY_VILLAGER_NO); + pl.sendMessage("&cYou don't have enough funds."); + } + }); + } + ibb.addButton(() -> { + ItemStack is = Objects.requireNonNull(ItemRegistry.getItem(Yuri.getMain(), "digga_book")).clone().getItemstack().clone(); + ItemMeta im = is.getItemMeta(); + assert im != null; + List l = im.getLore(); + assert l != null; + l.add(Colored.colorize("&3Unit price: &6" + EconomyManager.getCurrencySymbol() + "115000")); + l.add(Colored.colorize("&eClick to buy »")); + im.setLore(l); + is.setItemMeta(im); + return is; + }, cc -> { + if (EconomyManager.subtractFunds(pl, 115000)) { + p.getInventory().addItem(Objects.requireNonNull(ItemRegistry.getItem(Yuri.getMain(), "digga_book")).getItemstack()); + pl.playSound(Sound.ENTITY_EXPERIENCE_ORB_PICKUP); + pl.sendMessage(String.format("&aBought 1x &dSUPA DIGGA ENCHANTMENT &afor &e%s115000&a.", EconomyManager.getCurrencySymbol())); + } else { + pl.playSound(Sound.ENTITY_VILLAGER_NO); + pl.sendMessage("&cYou don't have enough funds."); + } + }); + ibb.build().open(p); + }).addButton(ItemBuilder.createWithName(Material.DIAMOND_BLOCK, "&bSell"), 15, c -> { + InventoryBuilder ibb = new InventoryBuilder(36).withTitle("&bSell").readOnly(); + for (Map.Entry en : priceTable.entrySet()) { + int sellprice = getSellPrice(en.getKey()); + ibb.addButton(new ItemBuilder(en.getKey(), Desu.getMain(), "null").appendLore("&3Unit price: &b" + EconomyManager.getCurrencySymbol() + sellprice).appendLore("&eClick to sell »").appendLore("&eShift-click to sell x10 »").build().getItemstack(), cc -> { + if (cc.getEvent().isShiftClick() ? ItemUtils.removeItem(p.getInventory(), en.getKey(), 10) : ItemUtils.removeItem(p.getInventory(), en.getKey(), 1)) { + int count = cc.getEvent().isShiftClick() ? 10 : 1; + EconomyManager.addFunds(pl, sellprice * count); + pl.playSound(Sound.ENTITY_EXPERIENCE_ORB_PICKUP); + pl.sendMessage(String.format("&aSold %dx &e%s&a for &e%s%d&a.", count, en.getKey().name(), EconomyManager.getCurrencySymbol(), sellprice)); + } else { + pl.playSound(Sound.ENTITY_VILLAGER_NO); + pl.sendMessage("&cYou don't have selected items."); + } + }); + } + ibb.build().open(p); + }).build().open(p); + } +} diff --git a/YuriPlugins/YuriEssentials/src/main/resources/config.yml b/YuriPlugins/YuriEssentials/src/main/resources/config.yml new file mode 100644 index 0000000..1f49f38 --- /dev/null +++ b/YuriPlugins/YuriEssentials/src/main/resources/config.yml @@ -0,0 +1,7 @@ +glassBreakChance: 45 +teleportCooldown: 4 +spawn: + x: -1 + y: -1 + z: -1 + world: null \ No newline at end of file diff --git a/YuriPlugins/YuriEssentials/src/main/resources/plugin.yml b/YuriPlugins/YuriEssentials/src/main/resources/plugin.yml new file mode 100644 index 0000000..540e3ab --- /dev/null +++ b/YuriPlugins/YuriEssentials/src/main/resources/plugin.yml @@ -0,0 +1,48 @@ +name: YuriEssentials +version: 1.0E +main: me.yuri.essentials.Yuri +api-version: 1.16 +author: Golgroth +depend: [ YuriAPI, ProtocolLib ] + +commands: + spawn: + home: + speed: + sethome: + doas: + invsee: + feed: + heal: + wheel: + back: + market: + balance: + aliases: [ bal ] + pay: + enchant: + aliases: [ ench ] + setname: + auction: + aliases: [ auc, ac ] + invdb: + repair: + marketstats: + aliases: [ mstats ] + freeze: + nick: + broadcast: + aliases: [ bc ] + fly: + r: + pbcg: + setsign: + setval: + tpa: + armors: + enderchest: + ndrp: + holo: + tls: + head: + slm: \ No newline at end of file diff --git a/YuriPlugins/YuriFactions/.gitignore b/YuriPlugins/YuriFactions/.gitignore new file mode 100644 index 0000000..6f322bc --- /dev/null +++ b/YuriPlugins/YuriFactions/.gitignore @@ -0,0 +1,2 @@ +target/ +src/test/ \ No newline at end of file diff --git a/YuriPlugins/YuriFactions/pom.xml b/YuriPlugins/YuriFactions/pom.xml new file mode 100644 index 0000000..ae0ffa0 --- /dev/null +++ b/YuriPlugins/YuriFactions/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + me.yuri.factions + YuriFactions + 1.0-SNAPSHOT + + + 11 + 11 + + + + + me.yuri + YuriAPI + 1.2-SNAPSHOT + system + /home/yuri/Desktop/plugintest/plugins/YuriAPI.jar + + + org.spigotmc + spigot-api + 1.16.4-R0.1-SNAPSHOT + + + org.jetbrains + annotations + RELEASE + compile + + + + \ No newline at end of file diff --git a/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/Commands.java b/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/Commands.java new file mode 100644 index 0000000..c29bbea --- /dev/null +++ b/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/Commands.java @@ -0,0 +1,545 @@ +package me.yuri.factions; + +import me.yuri.yuriapi.Desu; +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.command.Cmd; +import me.yuri.yuriapi.api.command.CommandEvent; +import me.yuri.yuriapi.api.command.CommandTabCompleteEvent; +import me.yuri.yuriapi.api.command.TabCompletion; +import me.yuri.yuriapi.api.economy.EconomyManager; +import me.yuri.yuriapi.api.utils.Colored; +import me.yuri.yuriapi.api.utils.MessageBuilder; +import me.yuri.yuriapi.utils.ChunkUtil; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.scheduler.BukkitRunnable; + +import java.text.NumberFormat; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class Commands { + + private static final Commands inst = new Commands(); + private static final NumberFormat frmt = NumberFormat.getInstance(); + + static { + frmt.setMaximumFractionDigits(2); + frmt.setMinimumFractionDigits(2); + } + + private Commands() { + } + + protected static Commands getInstance() { + return inst; + } + + @Cmd(command = "faction", aliases = "f", desc = "Manages factions", permissions = "faction") + public void faction(CommandEvent e) { + if (e.getArgs().length == 0) { + + if (!e.isPlayer()) { + e.reply("&cYou need to be a player."); + return; + } + + FactionMember fm = FactionManager.getMember(e.asPlayer()); + + if (fm == null) { + e.reply("&cYou don't belong to any faction. Maybe you meant to type &b/f help&c?"); + return; + } + + Faction f = fm.faction; + + e.reply(String.format("&a============[&b%s&a]============", f.getName()), + "&aMembers online: &b" + f.getOnlineMembers().size(), + "&aLeader: &b" + f.getOwner().getName(), + "&aState: &b" + (f.isOpen() ? "&bopen" : "&cclosed"), + "&aPower: &b" + frmt.format(f.getPower()) + "&a/&d20.00", + "&aRole: &b" + fm.role.getName()); + return; + } + + if (e.getArgs()[0].equalsIgnoreCase("help")) { + printHelp(e); + return; + } + + if (e.getArgs()[0].equalsIgnoreCase("list")) { + e.reply("&aFaction list:"); + for (Faction f : FactionManager.getAll()) { + e.reply("&a- &b" + f.getName() + " &e[&c" + f.getTag() + "&e]&a, leader: &b" + f.owner.getName()); + } + return; + } + + if (!e.isPlayer()) { + e.reply("&cYou need to be a player."); + return; + } + + FactionMember fm = FactionManager.getMember(e.asPlayer()); + Faction fac = fm == null ? null : fm.faction; + + if (e.getArgs()[0].equalsIgnoreCase("map")) { + World w = e.asPlayer().getBasePlayer().getWorld(); + Chunk c = e.asPlayer().getBasePlayer().getLocation().getChunk(); + int minx = c.getX() - 14, maxx = c.getX() + 14, minz = c.getZ() - 7, maxz = c.getZ() + 7; + MessageBuilder mb = new MessageBuilder(); + mb.append("&c====&8========[&6Map&8]========&c====\n").push(); + for (int zz = minz; zz <= maxz; zz++) { + for (int xx = minx; xx < maxx; xx++) { + Chunk ch = w.getChunkAt(xx, zz); + String tag = ch.getPersistentDataContainer().getOrDefault(Yuri.CHUNK_KEY, PersistentDataType.STRING, "\n"); + boolean facc = !tag.equals("\n"); + boolean ownfac = facc && fac != null && fac.getTag().equals(tag); + Faction faction = FactionManager.getByTag(tag); + + if (faction == null) { + ch.getPersistentDataContainer().remove(Yuri.CHUNK_KEY); + facc = false; + } + + + mb.appendText(facc ? (ownfac ? "&a" : "&e") + "+" : "&8-"); + if (xx == c.getX() && zz == c.getZ()) + mb.replaceLastInBuffer(1, "+"); + + String leadername = null; + if (facc) { + OfflinePlayer of = faction.owner; + leadername = of.isOnline() ? ((Player) of).getDisplayName() : of.getName(); + } + mb.appendFromBuffer().hoverText("&6Faction &8> " + (facc ? (ownfac ? "&b&l" + tag : "&e&l" + tag) + "\n&6Leader: &8> &e" + leadername : "&a&lwilderness")); + mb.push(); + } + mb.append("\n"); + } + e.asPlayer().sendMessage(mb.build()); + return; + } + + if (e.getArgs()[0].equalsIgnoreCase("create")) { + + if (fac != null) { + e.reply("&cYou are already a member of &b" + fac.getName() + "&a."); + return; + } + + if (e.getArgs().length < 2) { + e.reply("&cMissing arguments: &b &b&c."); + return; + } + + if (e.getArgs().length < 3) { + e.reply("&cMissing arguments: &b&c."); + return; + } + + if (e.asPlayer().getFunds() < 20000) { + e.reply("&cYou don't have enough funds (&6" + EconomyManager.getCurrencySymbol() + "20000&c)."); + return; + } + + if (!e.asPlayer().getBasePlayer().getName().equals("Golgroth") && e.getArgs()[1].length() > 5) { + e.reply("&cTag too long."); + return; + } + + if (FactionManager.createFaction(e.asPlayer(), e.getArgs()[2], e.getArgs()[1].toUpperCase()) == null) { + e.reply("&cThere is already a faction with such tag or name."); + return; + } + + e.reply("&aFaction created."); + return; + } + + if (e.getArgs()[0].equalsIgnoreCase("join")) { + if (fac != null) { + e.reply("&cYou are already in a faction."); + return; + } + + if (e.getArgs().length < 2) { + e.reply("&cMissing arguments &b&c."); + return; + } + + Faction fa = FactionManager.getByTag(e.getArgs()[1]); + if (fa == null) { + e.reply("&cInvalid faction."); + return; + } + + if (fa.inviteOnly && !FactionManager.invites.containsKey(e.asPlayer())) { + e.reply("&cThis faction is closed."); + return; + } + + FactionManager.invites.remove(e.asPlayer()); + + FactionManager.addMember(fa, e.asPlayer()); + e.asPlayer().sendMessage("&aYou have joined &b" + fa.getName() + "&a!"); + return; + } + + if (fac == null) { + e.reply("&cYou do not belong to any faction."); + return; + } + + if (e.getArgs()[0].equalsIgnoreCase("invite")) { + if (!fm.getRole().hasPerm(FactionRole.OFFICER)) { + e.reply("&cMissing permissions."); + return; + } + + if (e.getArgs().length < 2) { + e.reply("&cMissing argument &b&c."); + return; + } + + YPlayer p = YPlayer.get(e.getArgs()[1]); + if (p == null) { + e.reply("&cPlayer does not exist."); + return; + } + + if (p.equals(e.asPlayer())) { + e.reply("&cYou cannot invite yourself."); + return; + } else { + if (FactionManager.getFor(p) != null) { + e.reply("&cThe player is already in a faction."); + return; + } + } + + FactionManager.invites.put(p, fac); + p.sendMessage(new MessageBuilder().append("&aYou have been invited by &e" + e.asPlayer().getBasePlayer().getDisplayName() + " &ato join &b" + fac.getName() + "&a.\nType &b/faction join " + fac.getTag() + "&a or ").push().append("&bclick here").clickRunCommand("/f join " + fac.getTag()).hoverText("&bClick to join the faction").push().append(" &ato join the faction.").build()); + e.reply("&aPlayer invited."); + return; + } + + if (e.getArgs()[0].equalsIgnoreCase("leave")) { + FactionManager.leaveMember(fac, e.asPlayer()); + e.asPlayer().sendMessage("&aYou have left &b" + fac.getName() + "&a."); + return; + } + + + if (e.getArgs()[0].equalsIgnoreCase("open")) { + if (!fm.getRole().hasPerm(FactionRole.OFFICER)) { + e.reply("&cMissing permissions."); + return; + } + + fac.toggleOpen(); + e.reply("&aFaction is now " + (fac.isOpen() ? "&bopen" : "&cclosed") + "&a."); + return; + } + + if (e.getArgs()[0].equalsIgnoreCase("kick")) { + + if (!fm.getRole().hasPerm(FactionRole.OFFICER)) { + e.reply("&cMissing permissions."); + return; + } + + if (e.getArgs().length < 2) { + e.reply("&cMissing arguments &b&c."); + return; + } + + YPlayer p = YPlayer.get(e.getArgs()[1]); + + if (p == null) { + e.reply("&cInvalid player."); + return; + } + + Faction f = FactionManager.getFor(p); + if (!fac.equals(f)) { + e.reply("&cPlayer does not belong to your faction."); + return; + } + + FactionManager.leaveMember(fac, p); + e.reply("&aKicked &b" + p.getBasePlayer().getDisplayName() + "&a from your faction."); + return; + } + + if (e.getArgs()[0].equalsIgnoreCase("chat")) { + boolean b = FListener.toggleChat(fm); + e.reply("&aYou are now using the " + (b ? "&bfaction" : "&6global") + " &achat."); + return; + } + + if (e.getArgs()[0].equalsIgnoreCase("sethome")) { + + if (!fm.getRole().hasPerm(FactionRole.OFFICER)) { + e.reply("&cMissing permissions."); + return; + } + + Location l; + if (e.getArgs().length > 2 && e.getArgs()[2].equalsIgnoreCase("reset")) { + l = null; + } else { + l = fm.getPlayer().getBasePlayer().getLocation(); + if (!fac.chunks.contains(ChunkUtil.toLong(l.getChunk()))) { + e.reply("&cHome must be set on claimed land."); + return; + } + } + + fac.setHome(l); + e.reply("&aHome " + (l == null ? "re" : "") + "set."); + return; + } + + if (e.getArgs()[0].equalsIgnoreCase("promote")) { + if (!fm.getRole().hasPerm(FactionRole.OFFICER)) { + e.reply("&cMissing permissions."); + return; + } + + if (e.getArgs().length < 2) { + e.reply("&cNo player specified."); + return; + } + + OfflinePlayer op = YPlayer.getOfflinePlayer(e.getArgs()[1]); + + if (op == null) { + e.reply("&cInvalid player."); + return; + } else if (op.equals(e.asPlayer().getBasePlayer())) { + e.reply("&cYou cannot promote yourself."); + return; + } + + FactionMember mm = FactionManager.getMember(op); + if (mm == null || !mm.faction.equals(fac)) { + e.reply(); + return; + } + + FactionRole fr = mm.role; + FactionRole frfr = mm.role.getNext(); + + if (fr == frfr || (fm.role == FactionRole.OFFICER && frfr == FactionRole.OFFICER)) { + e.reply("&cCannot promote player."); + return; + } else if (fm.role == FactionRole.OWNER && frfr == FactionRole.OWNER) { + e.reply("&aYou are changing faction leader to &b" + op.getName() + "&a, type '&byes&a' in the chat to confirm your action..."); + e.asPlayer().onNextMessage(m -> { + m.setCancelled(true); + if (Colored.strip(m.getMessage()).equalsIgnoreCase("yes")) { + for (FactionMember pp : fac.getOnlineMembers()) { + pp.getPlayer().sendMessage("&c" + op.getName() + " &eis now the new faction leader."); + } + mm.promote(); + } else { + e.reply("&cCancelling your action."); + } + }); + return; + } + + mm.promote(); + e.reply("&aPromoted &b" + op.getName() + " &ato &b" + frfr.getName() + "&a."); + if (op.isOnline()) + ((Player) op).sendMessage(Colored.colorize("&aYou have been promoted to &b" + frfr.getName() + "&a.")); + return; + } + + if (e.getArgs()[0].equalsIgnoreCase("demote")) { + if (!fm.getRole().hasPerm(FactionRole.OFFICER)) { + e.reply("&cMissing permissions."); + return; + } + + if (e.getArgs().length < 2) { + e.reply("&cNo player specified."); + return; + } + + OfflinePlayer op = YPlayer.getOfflinePlayer(e.getArgs()[1]); + + if (op == null) { + e.reply("&cInvalid player."); + return; + } else if (op.equals(e.asPlayer().getBasePlayer())) { + e.reply("&cYou cannot demote yourself."); + return; + } + + FactionMember mm = FactionManager.getMember(op); + if (mm == null || !mm.faction.equals(fac)) { + e.reply(); + return; + } + + FactionRole fr = mm.role; + FactionRole frfr = mm.role.getPrevious(); + + if (fr == frfr || (fm.role == FactionRole.OFFICER && frfr == FactionRole.OFFICER)) { + e.reply("&cCannot promote player."); + return; + } + + mm.demote(); + e.reply("&aDemoted &b" + op.getName() + " &ato &b" + frfr.getName() + "&a."); + if (op.isOnline()) + ((Player) op).sendMessage(Colored.colorize("&aYou have been demoted to &b" + frfr.getName() + "&a.")); + return; + } + + if (e.getArgs()[0].equalsIgnoreCase("home")) { + Location l = fac.getHome(); + if (l == null) { + e.reply("&cThis faction does not have a home location set."); + return; + } + + long now = System.currentTimeMillis(); + new BukkitRunnable() { + int cnt = 4; + + @Override + public void run() { + if (e.getSender().hasPermission("yuriessentials.admin")) { + cnt = 0; + } + if (cnt == 4) { + e.reply("&eTeleporting to &afaction home&e in &c" + (cnt + 1) + " seconds&e. Do not move."); + } else if (cnt == 0) { + fm.getPlayer().getBasePlayer().teleport(l); + e.reply("&aTeleported."); + cancel(); + return; + } else { + if (e.asPlayer().onLastMove() > now) { + e.reply("&eYou moved, &ccancelling teleport&e."); + cancel(); + return; + } + } + --cnt; + } + }.runTaskTimer(Desu.getMain(), 0, 20L); + return; + } + + if (e.getArgs()[0].equalsIgnoreCase("claim")) { + if (!fm.role.hasPerm(FactionRole.OWNER)) { + e.reply("&cMissing permissions."); + return; + } + + Chunk c = fm.getPlayer().getBasePlayer().getLocation().getChunk(); + + if ((c.getX() >= -32 && c.getZ() <= 32) && (c.getX() <= 32 && c.getZ() >= -32)) { + e.reply("&cYou need to move further from spawn."); + return; + } + + + if (!fac.getChunks().isEmpty()) { + if (fac.getChunks().contains(ChunkUtil.toLong(c))) { + e.reply("&eYou have already claimed this land."); + return; + } else if (fac.chunks.stream().map(cc -> ChunkUtil.fromLong(FactionManager.WORLD, cc)).noneMatch(ch -> Math.abs(ch.getX() - c.getX()) <= 1 && Math.abs(ch.getZ() - c.getZ()) <= 1)) { + e.reply("&cLand has to be adjacent to currently claimed land."); + return; + } + } + + if (fac.chunks.size() >= 36) { + e.reply("&cYou have reached the max limit of faction land size."); + return; + } + + if ((20f / 36f) * fac.chunks.size() > fac.getPower()) { + e.reply("&cYour faction does not have enough power."); + return; + } + + if (fac.claimChunk(c)) + e.reply("&aLand claimed."); + else e.reply("&cThis land is already claimed by another faction."); + return; + } + + if (e.getArgs()[0].equalsIgnoreCase("unclaim")) { + if (!fm.role.hasPerm(FactionRole.OWNER)) { + e.reply("&cMissing permissions."); + return; + } + if (e.getArgs().length > 1) { + if (e.getArgs()[1].equalsIgnoreCase("all")) { + e.reply(fac.unclaimAll() ? "&aRemoved all land claims." : "&cYou don't have any land claimed."); + return; + } + } + boolean hadHome = fac.home != null; + if (fac.unclaimChunk(fm.getPlayer().getBasePlayer().getLocation().getChunk())) { + e.reply("&aLand claim removed."); + if (hadHome && fac.home == null) { + e.reply("&eFaction home removed, as it was on the claimed land."); + } + } else + e.reply("&cThis land does not belong to your faction."); + return; + } + + e.reply("&cInvalid command, type &b/" + e.getCmdLabel() + " help&c for a list of sub-commands."); + } + + private void printHelp(CommandEvent e) { + e.reply("&1==============[&3Factions&1]==============", + String.format(" &1- &3/%s help &1- &3prints this message", e.getCmdLabel()), + String.format(" &1- &3/%s create &b &1- &3creates a faction", e.getCmdLabel()), + String.format(" &1- &3/%s sethome [reset] &1- &3sets the faction spawn or removes it", e.getCmdLabel()), + String.format(" &1- &3/%s home &1- &3teleports to the faction's spawn", e.getCmdLabel()), + String.format(" &1- &3/%s map &1- &3shows local land map", e.getCmdLabel()), + String.format(" &1- &3/%s chat &1- &3toggles between global and faction chat", e.getCmdLabel()), + String.format(" &1- &3/%s join &b &1- &3joins the faction with specified tag", e.getCmdLabel()), + String.format(" &1- &3/%s invite &b &1- &3invites player to your faction", e.getCmdLabel()), + String.format(" &1- &3/%s open &b &1- &3toggles faction's ability to accept members without inviting", e.getCmdLabel()), + String.format(" &1- &3/%s kick &b &1- &3removes a member from your faction", e.getCmdLabel()), + String.format(" &1- &3/%s claim &b &1- &3claims land (chunk)", e.getCmdLabel()), + String.format(" &1- &3/%s unclaim &b[all] &1- &3removes land claim or all land claims", e.getCmdLabel()), + String.format(" &1- &3/%s leave &1- &3leaves the faction", e.getCmdLabel()), + String.format(" &1- &3/%s promote &1- &3promotes a player to the next role", e.getCmdLabel()), + String.format(" &1- &3/%s demote &1- &3demotes a player to the previous role", e.getCmdLabel()), + "&1====================================="); + } + + @TabCompletion(command = "faction") + public List factionComplete(CommandTabCompleteEvent e) { + + switch (e.getArgs().length) { + case 1: + return Arrays.asList("", "help", "create", "map", "chat", "invite", "join", "home", "kick", "open", "sethome", "claim", "unclaim", "leave", "promote", "demote"); + case 2: + if (e.getArgs()[0].equalsIgnoreCase("invite") || e.getArgs()[0].equalsIgnoreCase("promote") + || e.getArgs()[0].equalsIgnoreCase("demote") || e.getArgs()[0].equalsIgnoreCase("kick")) + return null; + else if (e.getArgs()[0].equalsIgnoreCase("unclaim")) + return Collections.singletonList("all"); + break; + } + + return Collections.emptyList(); + } +} diff --git a/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/FListener.java b/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/FListener.java new file mode 100644 index 0000000..8352b67 --- /dev/null +++ b/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/FListener.java @@ -0,0 +1,128 @@ +package me.yuri.factions; + +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.utils.Colored; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.persistence.PersistentDataType; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +public class FListener implements Listener { + + private static final FListener inst = new FListener(); + private static final Map chat = new HashMap<>(); + + private FListener() { + } + + protected static FListener getInstance() { + return inst; + } + + protected static boolean toggleChat(FactionMember m) { + if (chat.containsKey(m.getPlayer().getBasePlayer())) { + chat.remove(m.getPlayer().getBasePlayer()); + return false; + } else { + chat.put(m.getPlayer().getBasePlayer(), m); + return true; + } + } + + @EventHandler + public void onJoin(PlayerJoinEvent e) { + YPlayer pl = YPlayer.get(e.getPlayer()); + FactionManager.update(pl); + Faction f = FactionManager.getFor(pl); + if (f != null) { + pl.clearPlayerListPrefix(); + pl.insertChatPrefix(0, "&a[&b" + f.getTag() + "&a]&r"); + pl.setPlayerListPrefix("&a[&b" + f.getTag() + "&a]&r"); + } + } + + @EventHandler + public void onLeave(PlayerQuitEvent e) { + chat.remove(e.getPlayer()); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void ____onChat(AsyncPlayerChatEvent e) { + FactionMember m = chat.getOrDefault(e.getPlayer(), null); + if (m != null) { + e.setMessage(Colored.colorize("&a") + e.getMessage()); + e.setFormat(Colored.colorize("&a(&dF&a)&r ") + e.getFormat()); + e.getRecipients().clear(); + e.getRecipients().addAll(m.faction.getOnlineMembers().stream().map(mmm -> (Player) mmm.getOfflinePlayer()).collect(Collectors.toList())); + } + } + + @EventHandler + public void powerGain(PlayerDeathEvent e) { + FactionMember m = FactionManager.getMember(YPlayer.get(e.getEntity())); + FactionMember k = null; + if (e.getEntity().getKiller() != null) { + k = FactionManager.getMember(YPlayer.get(e.getEntity().getKiller())); + } + if (m != null) { + m.indPower = Math.max(-10, Math.min(10, m.indPower - 1)); + m.faction.recalculatePower(); + } + + if (k != null) { + k.indPower = Math.max(-10, Math.min(10, k.indPower + 1)); + k.faction.recalculatePower(); + } + } + + @EventHandler + public void factionProteccBreak(BlockBreakEvent e) { + String tag = e.getBlock().getChunk().getPersistentDataContainer().getOrDefault(Yuri.CHUNK_KEY, PersistentDataType.STRING, "\n"); + if (tag.equals("\n")) return; + + Faction fac = FactionManager.getByTag(tag); + if (fac == null) return; + + YPlayer pl = YPlayer.get(e.getPlayer()); + FactionMember m = FactionManager.getMember(pl); + boolean ownfac = m != null && m.faction.getTag().equals(tag); + + if (!ownfac) { + if (!e.getPlayer().hasPermission("yurifactions.bypassland")) { + e.setCancelled(true); + pl.sendMessage("&cThis area is a property of &b" + tag + "&c."); + } + } + } + + @EventHandler + public void factionProteccPlace(BlockPlaceEvent e) { + String tag = e.getBlock().getChunk().getPersistentDataContainer().getOrDefault(Yuri.CHUNK_KEY, PersistentDataType.STRING, "\n"); + if (tag.equals("\n")) return; + + Faction fac = FactionManager.getByTag(tag); + if (fac == null) return; + + YPlayer pl = YPlayer.get(e.getPlayer()); + FactionMember m = FactionManager.getMember(pl); + boolean ownfac = m != null && m.faction.getTag().equals(tag); + + if (!ownfac) { + if (!e.getPlayer().hasPermission("yurifactions.bypassland")) { + e.setCancelled(true); + pl.sendMessage("&cThis area is a property of &b" + tag + "&c."); + } + } + } +} diff --git a/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/Faction.java b/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/Faction.java new file mode 100644 index 0000000..aaf7317 --- /dev/null +++ b/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/Faction.java @@ -0,0 +1,159 @@ +package me.yuri.factions; + +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.db.DbComparisonType; +import me.yuri.yuriapi.utils.ChunkUtil; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +public class Faction { + + private final String tag, name; + protected OfflinePlayer owner; + protected boolean inviteOnly; + protected List factionMembers; + protected Location home = null; + protected List chunks; + protected float power; + + protected Faction(String tag, String name, OfflinePlayer owner, boolean inviteOnly, @Nullable List factionmembers, List chunks) { + this.tag = tag; + this.name = name; + this.owner = owner; + this.inviteOnly = inviteOnly; + if (factionmembers == null) { + this.factionMembers = new ArrayList<>(); + this.factionMembers.add(new FactionMember(owner, FactionRole.OWNER)); + } else this.factionMembers = factionmembers; + + if (chunks == null) + chunks = new ArrayList<>(); + + this.chunks = chunks; //chunks.stream().map((c) -> Objects.requireNonNull(ChunkUtil.fromLong(Objects.requireNonNull(Bukkit.getWorld("build")), c))).collect(Collectors.toList()); + + this.factionMembers.forEach(f -> f.faction = this); + + for (long l : this.chunks) { + Chunk c = ChunkUtil.fromLong(FactionManager.WORLD, l); + } + + recalculatePower(); + } + + public void recalculatePower() { + float power = 0; + for (FactionMember m : factionMembers) { + float ind = m.indPower * 0.1f; + power += ind; + } + + power = (power / factionMembers.size()) * 5; + + power += Math.min(15, factionMembers.size() * 1.5f); + + this.power = Math.max(0, Math.min(power, 20)); + } + + public String getTag() { + return tag; + } + + public float getPower() { + return power; + } + + public String getName() { + return name; + } + + public OfflinePlayer getOwner() { + return owner; + } + + public void toggleOpen() { + this.inviteOnly = !inviteOnly; + } + + public boolean isOpen() { + return !inviteOnly; + } + + public List getChunks() { + return chunks; + } + + public boolean claimChunk(Chunk c) { + String s = c.getPersistentDataContainer().getOrDefault(Yuri.CHUNK_KEY, PersistentDataType.STRING, "\n"); + if (!s.equals("\n")) { + return false; + } else { + chunks.add(ChunkUtil.toLong(c)); + c.getPersistentDataContainer().set(Yuri.CHUNK_KEY, PersistentDataType.STRING, tag); + CompletableFuture.runAsync(() -> Yuri.LAND.createInsertQuery().setColumn("chunk", ChunkUtil.toLong(c)).setColumn("tag", this.tag).build().execute()); + return true; + } + } + + public boolean unclaimChunk(Chunk c) { + boolean b = chunks.remove(ChunkUtil.toLong(c)); + if (b) { + if (home != null && home.getChunk().equals(c)) + home = null; + c.getPersistentDataContainer().remove(Yuri.CHUNK_KEY); + CompletableFuture.runAsync(() -> Yuri.LAND.createRemoveQuery().where(w -> w.forColumn("chunk").value(DbComparisonType.EQUALS, ChunkUtil.toLong(c)).end()).build().execute()); + } + + return b; + } + + public boolean unclaimAll() { + if (chunks.isEmpty()) return false; + for (Chunk c : chunks.stream().map(cc -> ChunkUtil.fromLong(FactionManager.WORLD, cc)).collect(Collectors.toList())) { + c.getPersistentDataContainer().remove(Yuri.CHUNK_KEY); + } + chunks.clear(); + home = null; + CompletableFuture.runAsync(() -> Yuri.LAND.createRemoveQuery().where(w -> w.forColumn("tag").value(DbComparisonType.EQUALS, tag).end()).build().execute()); + return true; + } + + protected void addMember(YPlayer p) { + FactionMember f = new FactionMember(p.getBasePlayer(), FactionRole.MEMBER); + f.faction = this; + factionMembers.add(f); + recalculatePower(); + } + + protected boolean leaveMember(YPlayer p) { + return this.factionMembers.removeIf(c -> c.player.equals(p.getBasePlayer())); + } + + public List getMembers() { + return factionMembers; + } + + public List getOnlineMembers() { + return factionMembers.stream().filter(FactionMember::isOnline).collect(Collectors.toList()); + } + + public Location getHome() { + return home; + } + + public void setHome(Location l) { + if (l == null) { + this.home = null; + return; + } + this.home = l.clone(); + } + +} diff --git a/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/FactionManager.java b/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/FactionManager.java new file mode 100644 index 0000000..c521593 --- /dev/null +++ b/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/FactionManager.java @@ -0,0 +1,215 @@ +package me.yuri.factions; + +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.db.DbComparisonType; +import me.yuri.yuriapi.api.db.DbQueryResult; +import me.yuri.yuriapi.api.economy.EconomyManager; +import me.yuri.yuriapi.api.utils.SyncedPlayerMap; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.World; +import org.bukkit.entity.Player; + +import java.util.*; +import java.util.concurrent.CompletableFuture; + +public class FactionManager { + public static final int MAX_CHUNKS = 36; + protected static final SyncedPlayerMap invites = new SyncedPlayerMap<>(); + private static final List factions = Collections.synchronizedList(new ArrayList<>()); + protected static World WORLD; + + private FactionManager() { + } + + public static List getAll() { + return factions; + } + + protected static void init() { + WORLD = Bukkit.getWorld("spawn"); + assert WORLD != null; + DbQueryResult r = Yuri.FACTIONS.createSelectQuery().all().build().execute(); + while (r.next()) { + String tag = (String) r.get(0); + DbQueryResult rr = Yuri.USERS.createSelectQuery().columns("uuid", "role", "power").where(c -> c.forColumn("tag").value(DbComparisonType.EQUALS, tag).end()).build().execute(); + List mb = new ArrayList<>(); + while (rr.next()) { + OfflinePlayer of = Bukkit.getOfflinePlayer(rr.getUUID(0)); + FactionRole role = FactionRole.get((Integer) rr.get(1)); + int indpower = (int) rr.get(2); + FactionMember fm = new FactionMember(of, role); + fm.indPower = indpower; + mb.add(fm); + assert role != null; + } + rr.close(); + DbQueryResult rrr = Yuri.LAND.createSelectQuery().columns("chunk").where(w -> w.forColumn("tag").value(DbComparisonType.EQUALS, tag).end()).build().execute(); + + List l = new ArrayList<>(); + while (rrr.next()) { + long lo = rrr.getLong(1); + l.add(lo); + } + rrr.close(); + Faction f = new Faction(tag, (String) r.get(1), Bukkit.getOfflinePlayer((UUID) r.get(2)), r.getBoolean(3), mb, l); + f.setHome((Location) r.get(4)); + factions.add(f); + } + r.close(); + + for (Player p : Bukkit.getOnlinePlayers()) { + YPlayer pl = YPlayer.get(p); + Faction f = FactionManager.getFor(pl); + if (f != null) { + pl.clearPlayerListPrefix(); + pl.insertChatPrefix(0, "&a[&b" + f.getTag() + "&a]&r"); + pl.setPlayerListPrefix("&a[&b" + f.getTag() + "&a]&r"); + } + } + } + + protected static void saveToDb() { + for (Faction f : factions) { + Yuri.FACTIONS.createUpdateQuery().setColumn("invt", f.isOpen()).setColumn("home", f.getHome()).setColumn("owneruuid", f.getOwner().getUniqueId()).where(w -> w.forColumn(0).value(DbComparisonType.EQUALS, f.getTag()).end()).build().execute(); + for (FactionMember m : f.factionMembers) { + Yuri.USERS.createUpdateQuery().setColumn("tag", f.getTag()).setColumn("role", m.role.getRank()).setColumn("power", m.indPower).where(w -> w.forColumn("uuid").value(DbComparisonType.EQUALS, m.player.getUniqueId()).end()).build().execute(); + } + } + } + + public static Faction createFaction(YPlayer p, String name, String tamg) { + final String tag = tamg.toUpperCase(Locale.ROOT); + + if (factions.stream().anyMatch(f -> f.getTag().equals(tag) || f.getName().equalsIgnoreCase(name))) + return null; + + EconomyManager.subtractFunds(p, 20000); + p.sendMessage("&eYou have been charged &b" + EconomyManager.getCurrencySymbol() + "20000&e."); + + CompletableFuture.runAsync(() -> { + Yuri.FACTIONS.createInsertQuery().setColumn("tag", tag).setColumn("name", name) + .setColumn("owneruuid", p.getBasePlayer().getUniqueId()).setColumn("invt", true).build().execute(); + + Yuri.USERS.createInsertQuery().setColumn("uuid", + p.getBasePlayer().getUniqueId()).setColumn("tag", tag).setColumn("role", FactionRole.OWNER.getRank()).setColumn("power", 0).build().execute(); + }); + + Faction f = new Faction(tag, name, p.getBasePlayer(), true, null, null); + factions.add(f); + + updatePrefix(p); + + return f; + } + + public static void setHome(Faction f, Location l) { + f.setHome(l); + CompletableFuture.runAsync(() -> Yuri.FACTIONS.createUpdateQuery().setColumn("home", l).where(w -> w.forColumn("tag").value(DbComparisonType.EQUALS, f.getTag()).end()).build().execute()); + } + + public static FactionMember getMember(YPlayer p) { + return getMember(p.getBasePlayer()); + } + + public static FactionMember getMember(OfflinePlayer p) { + Faction f = getFor(p); + if (f == null) return null; + Optional ff = f.getMembers().stream().filter(c -> c.player.getUniqueId().equals(p.getUniqueId())).findFirst(); + return ff.orElse(null); + } + + public static Faction getFor(YPlayer p) { + return getFor(p.getBasePlayer()); + } + + public static void update(YPlayer y) { + Faction f = getFor(y.getBasePlayer()); + if (f != null) { + f.getMembers().stream().filter(c -> c.player.getUniqueId().equals(y.getBasePlayer().getUniqueId())).findFirst().ifPresent(c -> { + c.player = y.getBasePlayer(); + c.yplayer = y; + }); + if (f.owner.getUniqueId().equals(y.getBasePlayer().getUniqueId())) + f.owner = y.getBasePlayer(); + } + } + + public static Faction getFor(OfflinePlayer p) { + for (Faction f : factions) { + if (f.getMembers().stream().anyMatch(c -> p.getUniqueId().equals(c.getOfflinePlayer().getUniqueId()))) + return f; + } + + return null; + } + + public static Faction getByTag(String tag) { + for (Faction c : factions) { + if (c.getTag().equalsIgnoreCase(tag)) + return c; + } + return null; + } + + public static Faction getByName(String name) { + for (Faction c : factions) { + if (c.getName().equalsIgnoreCase(name)) + return c; + } + return null; + } + + public static void addMember(Faction f, YPlayer m) { + if (f.getMembers().stream().anyMatch(c -> c.player.equals(m.getBasePlayer()))) return; + + f.getOnlineMembers().forEach(cc -> cc.getPlayer().sendMessage("&b" + m.getBasePlayer().getDisplayName() + " &ahas joined the faction.")); + f.addMember(m); + + CompletableFuture.runAsync(() -> Yuri.USERS + .createInsertQuery().setColumn("uuid", m.getBasePlayer().getUniqueId()) + .setColumn("tag", f.getTag()).setColumn("role", FactionRole.MEMBER.getRank()).setColumn("power", 0).build().execute()); + + updatePrefix(m); + } + + public static void deleteFaction(Faction f) { + List fac = new ArrayList<>(f.factionMembers); + f.factionMembers.clear(); + factions.remove(f); + + fac.forEach(c -> updatePrefix(c.getPlayer())); + + CompletableFuture.runAsync(() -> Yuri.FACTIONS.createRemoveQuery() + .where(c -> c.forColumn("tag").value(DbComparisonType.EQUALS, f.getTag()).end()).build().execute()); + } + + public static void leaveMember(Faction f, YPlayer m) { + if (f.leaveMember(m)) { + + CompletableFuture.runAsync(() -> Yuri.USERS.createRemoveQuery() + .where(c -> c.forColumn("uuid").value(DbComparisonType.EQUALS, m.getBasePlayer().getUniqueId()).end()) + .build().execute()); + + if (f.getOwner().equals(m.getBasePlayer())) { + deleteFaction(f); + } + + updatePrefix(m); + } + } + + public static void updatePrefix(YPlayer p) { + Faction f = getFor(p); + if (f != null) { + p.insertChatPrefix(0, "&a[&b" + f.getTag() + "&a]"); + p.setPlayerListPrefix("&a[&b" + f.getTag() + "&a]&r"); + } else { + if (p.getChatPrefixes().size() > 0) + p.removeChatPrefix(0); + p.clearPlayerListPrefix(); + } + } + +} diff --git a/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/FactionMember.java b/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/FactionMember.java new file mode 100644 index 0000000..4db77a1 --- /dev/null +++ b/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/FactionMember.java @@ -0,0 +1,69 @@ +package me.yuri.factions; + +import me.yuri.yuriapi.api.YPlayer; +import me.yuri.yuriapi.api.db.DbComparisonType; +import org.bukkit.OfflinePlayer; + +import java.util.Objects; +import java.util.concurrent.CompletableFuture; + +public class FactionMember { + protected OfflinePlayer player; + protected YPlayer yplayer = null; + protected FactionRole role; + protected Faction faction; + protected int indPower; + protected FactionMember(OfflinePlayer player, FactionRole role) { + this.player = player; + this.role = role; + if (player.isOnline()) + yplayer = YPlayer.get(player.getUniqueId()); + } + + public boolean isOnline() { + boolean b = player.isOnline(); + if (b && yplayer == null) + yplayer = YPlayer.get(player.getUniqueId()); + return b; + } + + public YPlayer getPlayer() { + if (isOnline()) + return yplayer; + else return null; + } + + public OfflinePlayer getOfflinePlayer() { + return player; + } + + public FactionRole getRole() { + return role; + } + + public Faction getFaction() { + return faction; + } + + public void promote() { + FactionRole fr = role.getNext(); + if (role == fr) return; + role = fr; + CompletableFuture.runAsync(() -> Yuri.USERS.createUpdateQuery().setColumn("role", role.getRank()) + .where(w -> w.forColumn("uuid").value(DbComparisonType.EQUALS, player.getUniqueId()).end()).build().execute()); + if (fr == FactionRole.OWNER) { + Objects.requireNonNull(FactionManager.getMember(faction.owner)).demote(); + faction.owner = this.player; + CompletableFuture.runAsync(() -> Yuri.FACTIONS.createUpdateQuery().setColumn("owneruuid", player.getUniqueId()) + .where(w -> w.forColumn("tag").value(DbComparisonType.EQUALS, faction.getTag()).end()).build().execute()); + } + } + + public void demote() { + FactionRole fr = role.getPrevious(); + if (role == fr) return; + role = fr; + CompletableFuture.runAsync(() -> Yuri.USERS.createUpdateQuery().setColumn("role", role.getRank()) + .where(w -> w.forColumn("uuid").value(DbComparisonType.EQUALS, player.getUniqueId()).end()).build().execute()); + } +} diff --git a/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/FactionRole.java b/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/FactionRole.java new file mode 100644 index 0000000..84cab5e --- /dev/null +++ b/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/FactionRole.java @@ -0,0 +1,40 @@ +package me.yuri.factions; + +public enum FactionRole { + MEMBER(0, "Member"), SENIOR_MEMBER(1, "Senior member"), OFFICER(2, "Officer"), OWNER(3, "Leader"); + + private final int rank; + private final String name; + FactionRole(int i, String s) { + this.rank = i; + this.name = s; + } + + public static FactionRole get(int rank) { + for (FactionRole f : FactionRole.values()) { + if (f.rank == rank) + return f; + } + return null; + } + + public int getRank() { + return rank; + } + + public String getName() { + return name; + } + + public boolean hasPerm(FactionRole r) { + return this.rank >= r.rank; + } + + public FactionRole getPrevious() { + return rank != 0 ? get(rank - 1) : this; + } + + public FactionRole getNext() { + return rank != 3 ? get(rank + 1) : this; + } +} diff --git a/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/Yuri.java b/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/Yuri.java new file mode 100644 index 0000000..ce7bcda --- /dev/null +++ b/YuriPlugins/YuriFactions/src/main/java/me/yuri/factions/Yuri.java @@ -0,0 +1,86 @@ +package me.yuri.factions; + +import me.yuri.yuriapi.api.YuriPlugin; +import me.yuri.yuriapi.api.command.CommandManager; +import me.yuri.yuriapi.api.db.DbColumnDataType; +import me.yuri.yuriapi.api.db.DbConnectionBuilder; +import me.yuri.yuriapi.api.db.DbTable; +import me.yuri.yuriapi.api.db.SqliteConnection; +import me.yuri.yuriapi.api.utils.Colored; +import me.yuri.yuriapi.api.utils.metadata.KeyFactory; +import org.bukkit.Bukkit; +import org.bukkit.NamespacedKey; + +import java.io.File; +import java.util.concurrent.CompletableFuture; + +public class Yuri extends YuriPlugin { + + protected static SqliteConnection conn; + protected static DbTable FACTIONS, USERS, LAND; + protected static NamespacedKey CHUNK_KEY; + private static Yuri inst; + + public static Yuri getInstance() { + return inst; + } + + @Override + public void onLoad() { + inst = this; + super.onLoad(); + } + + @Override + public void onDisable() { + FactionManager.saveToDb(); + conn.disconnect(); + super.onDisable(); + } + + @Override + public void onEnable() { + super.onEnable(); + + CHUNK_KEY = KeyFactory.getKeyFor(Yuri.getInstance(), "faction"); + + File f = new File(getDataFolder(), "db.sqlite"); + + if (!getDataFolder().exists() && !getDataFolder().mkdirs()) + Bukkit.getConsoleSender().sendMessage(Colored.colorize("&4&lCannot create data folder!")); + + conn = (SqliteConnection) new DbConnectionBuilder(DbConnectionBuilder.DbType.SQLITE) + .withConnectionString("jdbc:sqlite:" + f) + .withTable("FACTIONS", b -> + b.withPrimaryKey("tag", DbColumnDataType.TEXT) + .withColumn("name", DbColumnDataType.TEXT) + .withColumn("owneruuid", DbColumnDataType.UUID) + .withColumn("invt", DbColumnDataType.BOOLEAN) + .withColumn("home", DbColumnDataType.LOCATION, true).build()) + .withTable("MEMBERS", b -> + b.withPrimaryKey("uuid", DbColumnDataType.UUID) + .withColumn("tag", DbColumnDataType.TEXT) + .withColumn("role", DbColumnDataType.INTEGER) + .withColumn("power", DbColumnDataType.INTEGER).build()) + .withTable("LAND", b -> b.withPrimaryKey("chunk", DbColumnDataType.BIGINT).withColumn("tag", DbColumnDataType.TEXT).build()) + .build(); + + try { + conn.connect(); + } catch (Exception e) { + e.printStackTrace(); + } + + FACTIONS = conn.getTable("FACTIONS"); + USERS = conn.getTable("MEMBERS"); + LAND = conn.getTable("LAND"); + + CommandManager mgr = new CommandManager(this); + mgr.registerCommand(Commands.getInstance()); + + this.getServer().getPluginManager().registerEvents(FListener.getInstance(), this); + //FACTIONS - 0, MEMBERS - 1, LAND - 2 + + CompletableFuture.runAsync(FactionManager::init); + } +} diff --git a/YuriPlugins/YuriFactions/src/main/resources/plugin.yml b/YuriPlugins/YuriFactions/src/main/resources/plugin.yml new file mode 100644 index 0000000..13c656f --- /dev/null +++ b/YuriPlugins/YuriFactions/src/main/resources/plugin.yml @@ -0,0 +1,9 @@ +name: YuriFactions +main: me.yuri.factions.Yuri +version: 1.0E +depend: [ YuriAPI ] +api-version: 1.16 + +commands: + faction: + aliases: [ f ] \ No newline at end of file