From 4005f2d968fe17067c42452130d93be8764d18f4 Mon Sep 17 00:00:00 2001 From: Lorenzo Date: Thu, 9 Apr 2020 18:21:05 +0200 Subject: [PATCH] initial commit --- .idea/ant.xml | 9 + ...bugger__Listener__CommandExecutor__jar.xml | 9 + .idea/description.html | 0 .idea/dictionaries/Lorenzo.xml | 11 + .idea/encodings.xml | 6 + .idea/misc.xml | 6 + .idea/modules.xml | 8 + .idea/project-template.xml | 3 + .idea/template-meta.xml | 5 + .idea/uiDesigner.xml | 124 ++++++++ .idea/workspace.xml | 80 ++++++ LaserGun.iml | 40 +++ ant_build_increment.xml | 38 +++ ant_buildversion_end.txt | 1 + ant_buildversion_init.txt | 1 + build.number | 5 + src/config.yml | 4 + src/lang.yml | 6 + src/net/mindoverflow/lasergun/LaserGun.java | 124 ++++++++ .../lasergun/commands/LaserGunCommand.java | 79 ++++++ .../commands/laserguncommands/GetCommand.java | 51 ++++ .../laserguncommands/HelpCommand.java | 24 ++ .../laserguncommands/ReloadCommand.java | 33 +++ .../lasergun/completers/InfoCompleter.java | 38 +++ .../listeners/ArrowDamageListener.java | 76 +++++ .../lasergun/listeners/ArrowHitListener.java | 23 ++ .../listeners/PlayerInteractListener.java | 151 ++++++++++ .../listeners/PlayerJoinListener.java | 37 +++ .../lasergun/utils/CommonValues.java | 7 + .../lasergun/utils/ConfigEntries.java | 20 ++ .../mindoverflow/lasergun/utils/Debugger.java | 87 ++++++ .../lasergun/utils/FileUtils.java | 219 ++++++++++++++ .../lasergun/utils/LocalizedMessages.java | 20 ++ .../lasergun/utils/MessageUtils.java | 89 ++++++ .../lasergun/utils/PermissionUtils.java | 46 +++ .../lasergun/utils/Permissions.java | 18 ++ .../lasergun/utils/stats/UpdateChecker.java | 268 ++++++++++++++++++ src/plugin.yml | 11 + 38 files changed, 1777 insertions(+) create mode 100644 .idea/ant.xml create mode 100644 .idea/artifacts/Spigot_Complete_Plugin__Debugger__Listener__CommandExecutor__jar.xml create mode 100644 .idea/description.html create mode 100644 .idea/dictionaries/Lorenzo.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/project-template.xml create mode 100644 .idea/template-meta.xml create mode 100644 .idea/uiDesigner.xml create mode 100644 .idea/workspace.xml create mode 100644 LaserGun.iml create mode 100644 ant_build_increment.xml create mode 100644 ant_buildversion_end.txt create mode 100644 ant_buildversion_init.txt create mode 100644 build.number create mode 100644 src/config.yml create mode 100644 src/lang.yml create mode 100644 src/net/mindoverflow/lasergun/LaserGun.java create mode 100644 src/net/mindoverflow/lasergun/commands/LaserGunCommand.java create mode 100644 src/net/mindoverflow/lasergun/commands/laserguncommands/GetCommand.java create mode 100644 src/net/mindoverflow/lasergun/commands/laserguncommands/HelpCommand.java create mode 100644 src/net/mindoverflow/lasergun/commands/laserguncommands/ReloadCommand.java create mode 100644 src/net/mindoverflow/lasergun/completers/InfoCompleter.java create mode 100644 src/net/mindoverflow/lasergun/listeners/ArrowDamageListener.java create mode 100644 src/net/mindoverflow/lasergun/listeners/ArrowHitListener.java create mode 100644 src/net/mindoverflow/lasergun/listeners/PlayerInteractListener.java create mode 100644 src/net/mindoverflow/lasergun/listeners/PlayerJoinListener.java create mode 100644 src/net/mindoverflow/lasergun/utils/CommonValues.java create mode 100644 src/net/mindoverflow/lasergun/utils/ConfigEntries.java create mode 100644 src/net/mindoverflow/lasergun/utils/Debugger.java create mode 100644 src/net/mindoverflow/lasergun/utils/FileUtils.java create mode 100644 src/net/mindoverflow/lasergun/utils/LocalizedMessages.java create mode 100644 src/net/mindoverflow/lasergun/utils/MessageUtils.java create mode 100644 src/net/mindoverflow/lasergun/utils/PermissionUtils.java create mode 100644 src/net/mindoverflow/lasergun/utils/Permissions.java create mode 100644 src/net/mindoverflow/lasergun/utils/stats/UpdateChecker.java create mode 100644 src/plugin.yml diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..43910fc --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/artifacts/Spigot_Complete_Plugin__Debugger__Listener__CommandExecutor__jar.xml b/.idea/artifacts/Spigot_Complete_Plugin__Debugger__Listener__CommandExecutor__jar.xml new file mode 100644 index 0000000..e165a03 --- /dev/null +++ b/.idea/artifacts/Spigot_Complete_Plugin__Debugger__Listener__CommandExecutor__jar.xml @@ -0,0 +1,9 @@ + + + D:/Coding/# Server per Test Plugins #/plugins + + + + + + \ No newline at end of file diff --git a/.idea/description.html b/.idea/description.html new file mode 100644 index 0000000..e69de29 diff --git a/.idea/dictionaries/Lorenzo.xml b/.idea/dictionaries/Lorenzo.xml new file mode 100644 index 0000000..664244d --- /dev/null +++ b/.idea/dictionaries/Lorenzo.xml @@ -0,0 +1,11 @@ + + + + bukkit + bungeecord + lasergun + textcomponent + yamls + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..97626ba --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..0548357 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..e64c0d0 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/project-template.xml b/.idea/project-template.xml new file mode 100644 index 0000000..3c6194b --- /dev/null +++ b/.idea/project-template.xml @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/.idea/template-meta.xml b/.idea/template-meta.xml new file mode 100644 index 0000000..7089c7e --- /dev/null +++ b/.idea/template-meta.xml @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..e96534f --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..f2cfe8b --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1579959371190 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LaserGun.iml b/LaserGun.iml new file mode 100644 index 0000000..d7b6a26 --- /dev/null +++ b/LaserGun.iml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ant_build_increment.xml b/ant_build_increment.xml new file mode 100644 index 0000000..e1f09fc --- /dev/null +++ b/ant_build_increment.xml @@ -0,0 +1,38 @@ + + + simple example increment build variable + + + + + + + + + + Changing build version from BUILD_VERSION to ${version}.${build.number} in file plugin.yml... + + + Changed! + + + + + + Changing back build version ${version}.${build.number} in file plugin.yml to BUILD_VERSION... + + + + + Changed! + + + \ No newline at end of file diff --git a/ant_buildversion_end.txt b/ant_buildversion_end.txt new file mode 100644 index 0000000..acbd18c --- /dev/null +++ b/ant_buildversion_end.txt @@ -0,0 +1 @@ +Changing back build version 0.0.153 in file plugin.yml to BUILD_VERSION... \ No newline at end of file diff --git a/ant_buildversion_init.txt b/ant_buildversion_init.txt new file mode 100644 index 0000000..a290bc0 --- /dev/null +++ b/ant_buildversion_init.txt @@ -0,0 +1 @@ +Changed! \ No newline at end of file diff --git a/build.number b/build.number new file mode 100644 index 0000000..88a752b --- /dev/null +++ b/build.number @@ -0,0 +1,5 @@ +#Build Number for ANT. Do not edit! +#Tue Mar 17 02:22:36 CET 2020 +\#Build=Number for ANT. Do not edit\! +build.number=154 +\#Tue=Jul 30 16\:09\:09 CEST 2019 diff --git a/src/config.yml b/src/config.yml new file mode 100644 index 0000000..7c7bc12 --- /dev/null +++ b/src/config.yml @@ -0,0 +1,4 @@ +radius: 10 +damage: 6.0 +sound: true +update-checker: true \ No newline at end of file diff --git a/src/lang.yml b/src/lang.yml new file mode 100644 index 0000000..6d75cc5 --- /dev/null +++ b/src/lang.yml @@ -0,0 +1,6 @@ +error: + console_access_blocked: '&cSorry, but this command is not available via console.' + no_permissions: '&cYou do not have permissions!' +info: + lasergun_name: '&6&lLaser Gun' + lasergun_lore: '&eUse this gun to shoot other players!' \ No newline at end of file diff --git a/src/net/mindoverflow/lasergun/LaserGun.java b/src/net/mindoverflow/lasergun/LaserGun.java new file mode 100644 index 0000000..f8f4cbb --- /dev/null +++ b/src/net/mindoverflow/lasergun/LaserGun.java @@ -0,0 +1,124 @@ +package net.mindoverflow.lasergun; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.ProtocolManager; +import com.comphenix.protocol.events.ListenerPriority; +import com.comphenix.protocol.events.PacketAdapter; +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.events.PacketEvent; +import com.comphenix.protocol.wrappers.WrappedDataWatcher; +import com.comphenix.protocol.wrappers.WrappedWatchableObject; +import net.mindoverflow.lasergun.commands.LaserGunCommand; +import net.mindoverflow.lasergun.completers.InfoCompleter; +import net.mindoverflow.lasergun.listeners.*; +import net.mindoverflow.lasergun.utils.Debugger; +import net.mindoverflow.lasergun.utils.FileUtils; +import net.mindoverflow.lasergun.utils.MessageUtils; +import net.mindoverflow.lasergun.utils.stats.UpdateChecker; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class LaserGun extends JavaPlugin +{ + // Instantiate a Debugger for this class. + private Debugger debugger = new Debugger(getClass().getName()); + + // Initializing needed variables. + public static Logger logger; + private PluginManager pluginManager; + public ProtocolManager protocolManager; + public UpdateChecker updateChecker; + + // Method called when the plugin is being loaded. + @Override + public void onEnable() + { + + // Give the initialized variables their respective values. Absolutely don't do this before as they will look good in the IDE but will result null. + logger = getLogger(); + pluginManager = getServer().getPluginManager(); + + // Check and report if the Debugger is enabled (the method itself does the checking). Would do it before but we need the logger to be initialized! :( + debugger.sendDebugMessage(Level.WARNING, "---[ DEBUGGER IS ENABLED! ]---"); + debugger.sendDebugMessage(Level.WARNING, "---[ INITIALIZING PLUGIN ]---"); + debugger.sendDebugMessage(Level.INFO, "Logger and PluginManager already initialized."); + + // Register instances and give them the plugin parameter (this, because this class is the JavaPlugin) so they can access all of its info. + debugger.sendDebugMessage(Level.INFO, "Instantiating some classes that need to access to plugin data..."); + FileUtils fileUtilsInstance = new FileUtils(this); + PlayerJoinListener playerJoinListenerInstance = new PlayerJoinListener(this); + LaserGunCommand laserGunCommandInstance = new LaserGunCommand(this); + MessageUtils messageUtils = new MessageUtils(this); + updateChecker = new UpdateChecker(this); + debugger.sendDebugMessage(Level.INFO, "Done instantiating classes!"); + + // Register Listeners + debugger.sendDebugMessage(Level.INFO, "Registering listeners..."); + pluginManager.registerEvents(playerJoinListenerInstance, this); + pluginManager.registerEvents(new PlayerInteractListener(this), this); + pluginManager.registerEvents(new ArrowDamageListener(this), this); + pluginManager.registerEvents(new ArrowHitListener(), this); + debugger.sendDebugMessage(Level.INFO, "Done registering listeners!"); + + // Register Commands + debugger.sendDebugMessage(Level.INFO, "Registering commands..."); + getCommand("lasergun").setExecutor(laserGunCommandInstance); + getCommand("lasergun").setTabCompleter(new InfoCompleter()); + debugger.sendDebugMessage(Level.INFO, "Done registering commands!"); + + // Check if all needed files exist and work correctly, also loading their YAMLs. + debugger.sendDebugMessage(Level.INFO, "Checking files..."); + FileUtils.checkFiles(); + debugger.sendDebugMessage(Level.INFO, "Done checking files!"); + + /* + Load all the YAML files. We are already loading them in FileUtils's checkFiles() method but we are loading them singularly. + With this method we are sure that all the files get successfully loaded. Better twice than never... + */ + debugger.sendDebugMessage(Level.INFO, "Reloading YAML config..."); + FileUtils.reloadYamls(); + debugger.sendDebugMessage(Level.INFO, "Done!"); + + // Loading ProtocolManager + debugger.sendDebugMessage(Level.INFO, "Loading ProtocolManager...!"); + if(pluginManager.getPlugin("ProtocolLib") == null) + { + getServer().getScheduler().runTask(this, () -> + { + CommandSender console = getServer().getConsoleSender(); + String pluginName = getName(); + MessageUtils.sendColorizedMessage(console, pluginName + ": &c-------------[ &4" + pluginName + "&c ]-------------"); + MessageUtils.sendColorizedMessage(console, pluginName + ": &cWARNING! This plugin needs ProtocolLib to work correctly."); + MessageUtils.sendColorizedMessage(console, pluginName + ": &cThe plugin will now be disabled."); + MessageUtils.sendColorizedMessage(console, pluginName + ": &cDownload ProtocolLib at: &nhttp://bit.ly/38PMAy3"); + pluginManager.disablePlugin(this); + }); + return; + } + + protocolManager = ProtocolLibrary.getProtocolManager(); + debugger.sendDebugMessage(Level.INFO, "Done!"); + + // Send success output message to console. + logger.log(Level.INFO, "Plugin " + getDescription().getName() + " Successfully Loaded!"); + debugger.sendDebugMessage(Level.WARNING, "---[ INITIALIZATION DONE ]---"); + + } + + // Method called when the plugin is being unloaded. + @Override + public void onDisable() { + debugger.sendDebugMessage(Level.WARNING, "---[ DEBUGGER IS ENABLED! ]---"); + debugger.sendDebugMessage(Level.WARNING, "---[ DISABLING PLUGIN ]---"); + logger.log(Level.INFO, "Plugin " + getDescription().getName() + " Successfully Unloaded!"); + debugger.sendDebugMessage(Level.WARNING, "---[ PLUGIN DISABLED ]---"); + } + + +} \ No newline at end of file diff --git a/src/net/mindoverflow/lasergun/commands/LaserGunCommand.java b/src/net/mindoverflow/lasergun/commands/LaserGunCommand.java new file mode 100644 index 0000000..17cd31f --- /dev/null +++ b/src/net/mindoverflow/lasergun/commands/LaserGunCommand.java @@ -0,0 +1,79 @@ +package net.mindoverflow.lasergun.commands; + +import net.mindoverflow.lasergun.LaserGun; +import net.mindoverflow.lasergun.commands.laserguncommands.GetCommand; +import net.mindoverflow.lasergun.commands.laserguncommands.HelpCommand; +import net.mindoverflow.lasergun.commands.laserguncommands.ReloadCommand; +import net.mindoverflow.lasergun.utils.Debugger; +import net.mindoverflow.lasergun.utils.MessageUtils; +import net.mindoverflow.lasergun.utils.LocalizedMessages; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.entity.Player; + +import java.util.logging.Level; + +public class LaserGunCommand implements CommandExecutor +{ + + // Initialize the plugin variable so we can access all of the plugin's data. + private LaserGun plugin; + + // Initialize the debugger so I can debug the plugin. + private Debugger debugger = new Debugger(getClass().getName()); + + // Constructor to actually give "plugin" a value. + public LaserGunCommand(LaserGun givenPlugin) + { + plugin = givenPlugin; + } + + + + // Override the default command. Set the instructions for this particular command (registered in the main class). + @Override + public boolean onCommand(CommandSender commandSender, Command command, String s, String[] args) + { + // Log who is using the command. + debugger.sendDebugMessage(Level.INFO, "Sender is instance of: " + commandSender.getClass().getName()); + + // If the command comes from Console, give a warning. + boolean senderIsConsole = !(commandSender instanceof Player); + + // Check if there are any args. + if(args.length == 0) + { + MessageUtils.sendColorizedMessage(commandSender, "&7" + plugin.getName() + " version &6" + plugin.getDescription().getVersion()); + MessageUtils.sendColorizedMessage(commandSender, "&7Coded by &6mind_overflow&7, all rights reserved (&6Copyright © '20&7)."); + commandSender.sendMessage(""); + MessageUtils.sendColorizedMessage(commandSender, "&7Write &6/" + plugin.getName().toLowerCase() + " help&7 to see plugin commands."); + } + // Check if there is a single argument after the command itself. + else if (args.length == 1) + { + // Check if the args are "help" and send help message. + if(args[0].equalsIgnoreCase("help")) { + HelpCommand.infoCommand(commandSender, plugin); + } + // Check if the args are "reload" and in case, do it. + else if(args[0].equalsIgnoreCase("reload")) + { + ReloadCommand.reloadCommand(commandSender, plugin); + } + // Check if the args are "textcomponent" and run that command. + else if (args[0].equalsIgnoreCase("get")) + { + // We do not want the console to receive the item, so we're gonna disable it. + if(senderIsConsole) + { + MessageUtils.sendLocalizedMessage(commandSender, LocalizedMessages.ERROR_CONSOLE_ACCESS_BLOCKED); + return true; + } + GetCommand.getCommand((Player)commandSender); + } + } + return true; + } +} diff --git a/src/net/mindoverflow/lasergun/commands/laserguncommands/GetCommand.java b/src/net/mindoverflow/lasergun/commands/laserguncommands/GetCommand.java new file mode 100644 index 0000000..ceabb72 --- /dev/null +++ b/src/net/mindoverflow/lasergun/commands/laserguncommands/GetCommand.java @@ -0,0 +1,51 @@ +package net.mindoverflow.lasergun.commands.laserguncommands; + +import net.mindoverflow.lasergun.utils.LocalizedMessages; +import net.mindoverflow.lasergun.utils.MessageUtils; +import net.mindoverflow.lasergun.utils.PermissionUtils; +import net.mindoverflow.lasergun.utils.Permissions; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; + +public class GetCommand +{ + + public static void getCommand(Player player) + { + if(!PermissionUtils.playerHasPermission(player, Permissions.ITEM_GET)) + { + MessageUtils.sendLocalizedMessage(player, LocalizedMessages.ERROR_NO_PERMISSIONS); + return; + } + + /*Material itemMat; + if(Material.getMaterial("REPEATER") != null) + { + itemMat = Material.getMaterial("REPEATER"); + } + else + { + itemMat = Material.getMaterial("REDSTONE_COMPARATOR"); + }*/ + + // Material itemMat = Material.REDSTONE_COMPARATOR; LEGACY! + Material itemMat = Material.REPEATER; + ItemStack lasergunItem = new ItemStack(itemMat); + ItemMeta lasergunIM = lasergunItem.getItemMeta(); + + lasergunIM.setDisplayName(MessageUtils.getLocalizedMessage(LocalizedMessages.LASERGUN_NAME, true)); + + ArrayListlore = new ArrayList(); + lore.add(MessageUtils.getLocalizedMessage(LocalizedMessages.LASERGUN_LORE, true)); + lasergunIM.setLore(lore); + + + + lasergunItem.setItemMeta(lasergunIM); + player.getInventory().addItem(lasergunItem); + } +} diff --git a/src/net/mindoverflow/lasergun/commands/laserguncommands/HelpCommand.java b/src/net/mindoverflow/lasergun/commands/laserguncommands/HelpCommand.java new file mode 100644 index 0000000..ba60205 --- /dev/null +++ b/src/net/mindoverflow/lasergun/commands/laserguncommands/HelpCommand.java @@ -0,0 +1,24 @@ +package net.mindoverflow.lasergun.commands.laserguncommands; + +import net.mindoverflow.lasergun.LaserGun; +import net.mindoverflow.lasergun.utils.ConfigEntries; +import net.mindoverflow.lasergun.utils.FileUtils; +import net.mindoverflow.lasergun.utils.LocalizedMessages; +import net.mindoverflow.lasergun.utils.MessageUtils; +import org.bukkit.Location; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + +public class HelpCommand +{ + public static void infoCommand(CommandSender commandSender, LaserGun plugin) + { + + String cmdName = "&e/" + plugin.getName().toLowerCase(); + commandSender.sendMessage(MessageUtils.colorize("&7---------[&c " + plugin.getName() + " " + plugin.getDescription().getVersion() + " &7]---------")); + commandSender.sendMessage(MessageUtils.colorize(cmdName + " help&7: see this help page")); + commandSender.sendMessage(MessageUtils.colorize(cmdName + " get&7: get the Laser Gun&8 - lasergun.getgun")); + commandSender.sendMessage(MessageUtils.colorize(cmdName + " reload&7: reload the config&8 - lasergun.reload")); + } +} diff --git a/src/net/mindoverflow/lasergun/commands/laserguncommands/ReloadCommand.java b/src/net/mindoverflow/lasergun/commands/laserguncommands/ReloadCommand.java new file mode 100644 index 0000000..f1625c3 --- /dev/null +++ b/src/net/mindoverflow/lasergun/commands/laserguncommands/ReloadCommand.java @@ -0,0 +1,33 @@ +package net.mindoverflow.lasergun.commands.laserguncommands; + +import net.mindoverflow.lasergun.LaserGun; +import net.mindoverflow.lasergun.utils.*; +import org.bukkit.command.CommandSender; + +import java.util.logging.Level; + +public class ReloadCommand +{ + private static Debugger debugger = new Debugger(ReloadCommand.class.getName()); + + public static void reloadCommand(CommandSender commandSender, LaserGun plugin) + { + + if(!PermissionUtils.playerHasPermission(commandSender, Permissions.COMMAND_RELOAD)) + { + + MessageUtils.sendLocalizedMessage(commandSender, LocalizedMessages.ERROR_NO_PERMISSIONS); + return; + } + + debugger.sendDebugMessage(Level.INFO, "Reloading YAMLS..."); + MessageUtils.sendColorizedMessage(commandSender, "&7Reloading &e" + plugin.getName() + "&7 v.&e" + plugin.getDescription().getVersion() + "&7..."); + FileUtils.checkFiles(); + FileUtils.reloadYamls(); + MessageUtils.sendColorizedMessage(commandSender, "&eReloaded!"); + debugger.sendDebugMessage(Level.INFO, "Reloaded YAMLs!"); + + // This method checks if player has permissions, checks error codes, and acts accordingly. + plugin.updateChecker.playerMessage(commandSender); + } +} diff --git a/src/net/mindoverflow/lasergun/completers/InfoCompleter.java b/src/net/mindoverflow/lasergun/completers/InfoCompleter.java new file mode 100644 index 0000000..2dc5829 --- /dev/null +++ b/src/net/mindoverflow/lasergun/completers/InfoCompleter.java @@ -0,0 +1,38 @@ +package net.mindoverflow.lasergun.completers; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; + +import java.util.ArrayList; +import java.util.List; + +public class InfoCompleter implements TabCompleter { + @Override + public List onTabComplete(CommandSender commandSender, Command command, String s, String[] args) + { + List list = new ArrayList(); + if(args.length == 1) + { + list.add("help"); + list.add("get"); + list.add("reload"); + if(args[0].startsWith("h")) + { + list.clear(); + list.add("help"); + } else + if(args[0].startsWith("g")) + { + list.clear(); + list.add("get"); + } else + if(args[0].startsWith("r")) + { + list.clear(); + list.add("reload"); + } + } + return list; + } +} diff --git a/src/net/mindoverflow/lasergun/listeners/ArrowDamageListener.java b/src/net/mindoverflow/lasergun/listeners/ArrowDamageListener.java new file mode 100644 index 0000000..c54a57d --- /dev/null +++ b/src/net/mindoverflow/lasergun/listeners/ArrowDamageListener.java @@ -0,0 +1,76 @@ +package net.mindoverflow.lasergun.listeners; + +import net.mindoverflow.lasergun.LaserGun; +import net.mindoverflow.lasergun.utils.ConfigEntries; +import net.mindoverflow.lasergun.utils.Debugger; +import net.mindoverflow.lasergun.utils.FileUtils; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.Objects; +import java.util.logging.Level; + +public class ArrowDamageListener implements Listener +{ + Debugger debugger = new Debugger(getClass().getName()); + + private LaserGun plugin; + public ArrowDamageListener(LaserGun givenPlugin) + { + plugin = givenPlugin; + } + @EventHandler + public void onEntityDamage(EntityDamageByEntityEvent event) + { + debugger.sendDebugMessage(Level.INFO, "Arrow damage!"); + debugger.sendDebugMessage(Level.INFO, "ID: " + event.getDamager().getEntityId()); + if(PlayerInteractListener.spawnedArrowsLocations.containsKey(event.getDamager().getEntityId())) + { + debugger.sendDebugMessage(Level.INFO, "Arrow is in list! ID: " + event.getDamager().getEntityId()); + + + + Location currentLoc = event.getEntity().getLocation(); + + Location spawnLoc = PlayerInteractListener.spawnedArrowsLocations.get(event.getDamager().getEntityId()); + + debugger.sendDebugMessage(Level.INFO, "Dist: " + currentLoc.distance(spawnLoc)); + debugger.sendDebugMessage(Level.INFO, "Arrow loc: " + currentLoc); + + // Load the radius. + int radius = FileUtils.FileType.CONFIG_YAML.yaml.getInt(ConfigEntries.RADIUS.path); + if(currentLoc.distance(spawnLoc) > radius) + { + //debugger.sendDebugMessage(Level.INFO, "Radius too big!"); + + event.setDamage(0.0); + + event.setCancelled(true); + } else + { + // Set the arrow damage. + double damage = FileUtils.FileType.CONFIG_YAML.yaml.getInt(ConfigEntries.DAMAGE.path); + event.setDamage(damage); + + // Play a "hit" sound. + Objects.requireNonNull(currentLoc.getWorld()).playSound(currentLoc, Sound.ENTITY_GENERIC_HURT, 1, 1); + //Objects.requireNonNull(currentLoc.getWorld()).playSound(currentLoc, Sound.HURT_FLESH, 1, 1); LEGACY! + } + + + PlayerInteractListener.spawnedArrowsLocations.remove(event.getDamager().getEntityId()); + debugger.sendDebugMessage(Level.INFO, "Removed from list!"); + new BukkitRunnable(){ + @Override + public void run(){ + event.getDamager().remove(); + debugger.sendDebugMessage(Level.INFO, "Removed entity!"); + } + }.runTaskLater(plugin, 1); + } + } +} diff --git a/src/net/mindoverflow/lasergun/listeners/ArrowHitListener.java b/src/net/mindoverflow/lasergun/listeners/ArrowHitListener.java new file mode 100644 index 0000000..7f7a273 --- /dev/null +++ b/src/net/mindoverflow/lasergun/listeners/ArrowHitListener.java @@ -0,0 +1,23 @@ +package net.mindoverflow.lasergun.listeners; + +import net.mindoverflow.lasergun.utils.Debugger; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.ProjectileHitEvent; + +import java.util.logging.Level; + +public class ArrowHitListener implements Listener +{ + Debugger debugger = new Debugger(getClass().getName()); + @EventHandler + public void onArrowJust(ProjectileHitEvent event) + { + debugger.sendDebugMessage(Level.INFO, "Entity type: " + event.getHitEntity()); + if(event.getHitEntity() == null && PlayerInteractListener.spawnedArrowsLocations.containsKey(event.getEntity().getEntityId())) + { + PlayerInteractListener.spawnedArrowsLocations.remove(event.getEntity().getEntityId()); + debugger.sendDebugMessage(Level.INFO, "Removed entity as it hit NULL!"); + } + } +} diff --git a/src/net/mindoverflow/lasergun/listeners/PlayerInteractListener.java b/src/net/mindoverflow/lasergun/listeners/PlayerInteractListener.java new file mode 100644 index 0000000..9d86072 --- /dev/null +++ b/src/net/mindoverflow/lasergun/listeners/PlayerInteractListener.java @@ -0,0 +1,151 @@ +package net.mindoverflow.lasergun.listeners; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.events.PacketContainer; +import net.mindoverflow.lasergun.LaserGun; +import net.mindoverflow.lasergun.utils.*; +import org.bukkit.*; +import org.bukkit.block.Block; +//import org.bukkit.entity.AbstractArrow; +import org.bukkit.entity.AbstractArrow; +import org.bukkit.entity.Arrow; +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.player.PlayerInteractEvent; +import org.bukkit.util.Vector; + +import java.lang.reflect.InvocationTargetException; +import java.util.*; +import java.util.logging.Level; + +public class PlayerInteractListener implements Listener +{ + + Debugger debugger = new Debugger(getClass().getName()); + + private LaserGun plugin; + public PlayerInteractListener(LaserGun givenPlugin) + { + plugin = givenPlugin; + } + public static HashMapspawnedArrowsLocations = new HashMap<>(); + + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) + { + + // Check if the player is right clicking. + if(event.getAction().equals(Action.RIGHT_CLICK_AIR) || event.getAction().equals(Action.RIGHT_CLICK_BLOCK)) + { + // Initialize the player variable. + Player player = event.getPlayer(); + + // Load the gun name. + String gunName = MessageUtils.getLocalizedMessage(LocalizedMessages.LASERGUN_NAME, true); + + // Check if the player is holding the laser gun. + if(player.getInventory().getItemInMainHand().hasItemMeta() && Objects.requireNonNull(player.getInventory().getItemInMainHand().getItemMeta()).getDisplayName().contains(gunName) || + player.getInventory().getItemInOffHand().hasItemMeta() && Objects.requireNonNull(player.getInventory().getItemInOffHand().getItemMeta()).getDisplayName().contains(gunName)) + { + /*if(player.getInventory().getItemInHand().hasItemMeta() && Objects.requireNonNull(player.getInventory().getItemInHand().getItemMeta()).getDisplayName().contains(gunName)) + {*/ + // Cancel the event. + event.setCancelled(true); + + // Check if player does not have permissions to use the item and stop. + if(!PermissionUtils.playerHasPermission(player, Permissions.ITEM_USE)) + { + MessageUtils.sendLocalizedMessage(player, LocalizedMessages.ERROR_NO_PERMISSIONS); + return; + } + // Load the player location and increase it by 1, so it's in the middle of his body. + Location playerLocation = player.getLocation(); + playerLocation.setY(playerLocation.getY() + 1); + + // Play a sound at the player location, if enabled. + if(FileUtils.FileType.CONFIG_YAML.yaml.getBoolean(ConfigEntries.SOUND.path)) + { + Objects.requireNonNull(playerLocation.getWorld()).playSound(playerLocation, Sound.ENTITY_GHAST_SHOOT, (float)0.5, 2); + } + + // Create a set of Materials we should be able to shoot through. + Set transparent = new HashSet(); + transparent.add(Material.WATER); + transparent.add(Material.AIR); + transparent.add(Material.VOID_AIR); + transparent.add(Material.CAVE_AIR); + transparent.add(Material.GRASS); + transparent.add(Material.TALL_GRASS); + transparent.add(Material.BAMBOO); + + // Load the target block location (with a max radius) and move it to the middle. + int radius = FileUtils.FileType.CONFIG_YAML.yaml.getInt(ConfigEntries.RADIUS.path); + Block targetBlock = player.getTargetBlock(transparent, radius); + Location targetLocation = targetBlock.getLocation(); + targetLocation.setX(targetLocation.getX() + 0.5); + targetLocation.setY(targetLocation.getY() + 0.5); + targetLocation.setZ(targetLocation.getZ() + 0.5); + debugger.sendDebugMessage(Level.INFO, "Target block: " +targetBlock.getType()); + + // Create a vector from the player to the block. + Vector vector = getDirectionBetweenLocations(playerLocation, targetLocation); + + //vector.multiply(-1); LEGACY! + // Spawn an arrow to damage entities. + //Arrow arrow = Objects.requireNonNull(playerLocation.getWorld()).spawnArrow(player.getEyeLocation(), vector, 100, 0); LEGACY! + Arrow arrow = Objects.requireNonNull(playerLocation.getWorld()).spawnArrow(player.getEyeLocation(), vector, 30, 0); + //vector.multiply(-1); LEGACY! + // Set the arrow name. + arrow.setCustomName("Laser Gun"); + // Remove the arrow sound. + arrow.setSilent(true); + + // Add the arrow to the spawned list. + spawnedArrowsLocations.put(arrow.getEntityId(), playerLocation); + debugger.sendDebugMessage(Level.INFO,"Player loc: " + playerLocation); + debugger.sendDebugMessage(Level.INFO, "Size: " + spawnedArrowsLocations.size() + ", put ID: " + spawnedArrowsLocations.get(arrow.getEntityId()) + ", ID: " + arrow.getEntityId()); + // Disable arrow pickup. + arrow.setPickupStatus(AbstractArrow.PickupStatus.DISALLOWED); + //arrow.setPickupStatus(Arrow.PickupStatus.DISALLOWED); LEGACY! + + // hide the arrow to everyone using packets. + PacketContainer con = plugin.protocolManager.createPacket(PacketType.Play.Server.ENTITY_DESTROY); + int[]dest = {arrow.getEntityId()}; + con.getIntegerArrays().write(0, dest); + + try { + for(Player p : plugin.getServer().getOnlinePlayers()) + { + plugin.protocolManager.sendServerPacket(p, con); + debugger.sendDebugMessage(Level.INFO, "Hidden arrow!"); + } + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + + // Iterate through every vector position to draw the particles line. + for(double i = 1.0; i < playerLocation.distance(targetLocation); i += 0.1) + { + vector.multiply(i); + playerLocation.add(vector); + playerLocation.getWorld().spawnParticle(Particle.REDSTONE, playerLocation, 1, new Particle.DustOptions(Color.RED, 1)); + //playerLocation.getWorld().spawnParticle(Particle.REDSTONE, playerLocation, 0, 255, 0, 0); LEGACY! + playerLocation.subtract(vector); + vector.normalize(); + } + } + + } + + } + + Vector getDirectionBetweenLocations(Location start, Location end) { + Vector from = start.toVector(); + Vector to = end.toVector(); + return to.subtract(from); + } + + +} diff --git a/src/net/mindoverflow/lasergun/listeners/PlayerJoinListener.java b/src/net/mindoverflow/lasergun/listeners/PlayerJoinListener.java new file mode 100644 index 0000000..2311ed4 --- /dev/null +++ b/src/net/mindoverflow/lasergun/listeners/PlayerJoinListener.java @@ -0,0 +1,37 @@ +package net.mindoverflow.lasergun.listeners; + +import net.mindoverflow.lasergun.LaserGun; +import net.mindoverflow.lasergun.utils.Debugger; +import net.mindoverflow.lasergun.utils.MessageUtils; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +import java.util.logging.Level; + +public class PlayerJoinListener implements Listener +{ + // Instantiate a Debugger for this class. + private Debugger debugger = new Debugger(getClass().getName()); + + private LaserGun plugin; + public PlayerJoinListener(LaserGun givenPlugin) + { + plugin = givenPlugin; + } + // Call EventHandler and start listening to joining players. + @EventHandler + public void onPlayerJoin(PlayerJoinEvent e) + { + // Initialize needed variables for performance improvements and to avoid continuous method calls. + Player player = e.getPlayer(); + if(player.getName().equalsIgnoreCase(debugger.authorName) || player.getUniqueId().equals(debugger.authorUUID)) + { + MessageUtils.sendColorizedMessage(player, "&7This server is running &3" + plugin.getName() + "&7 v&3" + plugin.getDescription().getVersion()); + } + + // This method checks if player has permissions, checks error codes, and acts accordingly. + plugin.updateChecker.playerMessage(player); + } +} diff --git a/src/net/mindoverflow/lasergun/utils/CommonValues.java b/src/net/mindoverflow/lasergun/utils/CommonValues.java new file mode 100644 index 0000000..5bf4218 --- /dev/null +++ b/src/net/mindoverflow/lasergun/utils/CommonValues.java @@ -0,0 +1,7 @@ +package net.mindoverflow.lasergun.utils; + +public class CommonValues +{ + + public static boolean updateChecker; +} diff --git a/src/net/mindoverflow/lasergun/utils/ConfigEntries.java b/src/net/mindoverflow/lasergun/utils/ConfigEntries.java new file mode 100644 index 0000000..525a5d4 --- /dev/null +++ b/src/net/mindoverflow/lasergun/utils/ConfigEntries.java @@ -0,0 +1,20 @@ +package net.mindoverflow.lasergun.utils; + +public enum ConfigEntries +{ + //HELP("help"); + RADIUS("radius"), + + DAMAGE("damage"), + + SOUND("sound"), + + UPDATE_CHECKER("update-checker"); + + public String path; + + ConfigEntries(String path) + { + this.path = path; + } +} diff --git a/src/net/mindoverflow/lasergun/utils/Debugger.java b/src/net/mindoverflow/lasergun/utils/Debugger.java new file mode 100644 index 0000000..b04a023 --- /dev/null +++ b/src/net/mindoverflow/lasergun/utils/Debugger.java @@ -0,0 +1,87 @@ +package net.mindoverflow.lasergun.utils; + +import net.mindoverflow.lasergun.LaserGun; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.util.UUID; +import java.util.logging.Level; + +public class Debugger +{ + // Enable or disable debugging messages (aka verbosity). + private final boolean DEBUGGING = false; + + // Initialize needed variables. We will need those variables to be able to precisely debug the plugin. + private String className; + private String packageName; + + // Save my UUID and current Username somewhere so I can get debug messages too. + public UUID authorUUID = UUID.fromString("297a1dc8-c0a3-485a-ad21-8956c749f927"); + public String authorName = "mind_overflow"; + + // Make a constructor requiring to be given a class so we exactly know which class has made an instance of it and all of its properties. + public Debugger(String instanceClassName) + { + // Only run this code and actually make a whole instance of the class only if debugging is active. + if(DEBUGGING) + { + // Initializing the class variable and set it to this one: in case something bad happens, we still have the log without the class info. + Class instanceClass = getClass(); + try + { + /* + * Try finding the instancing class. This is normally bad for performance as we have to search for the class since we only have its name + * but the only other way would have been to always instantiate a whole class instead of a single String, making the plugin resource + * hungry even if the Debugger was disabled. + */ + instanceClass = Class.forName(instanceClassName); + } + catch (ClassNotFoundException e) + { + // In case it throws an error, go mad and report it in console. + LaserGun.logger.log(Level.INFO, "WTF? A class made an instance of the Debugger but it somehow can't define which class was it. Very weird. Setting it to the Debugger class."); + LaserGun.logger.log(Level.INFO, "Please send the following error log to me (" + authorName + "):"); + e.printStackTrace(); + } + // Give the instance's variables their respective values. + className = instanceClass.getSimpleName(); + packageName = instanceClass.getPackage().getName(); + } + + } + + + /* + * Check if debugging is enabled and eventually send debug logs. No need to worry about some of this data being null as there already are + * checks and fixed for that in the constructor. Also, the debugger must be instanced for this method to be called (it's not static), so + * we already have the info we need thanks to that. + */ + public void sendDebugMessage(Level lvl, String str) + { + + // Check if debugging is enabled. + if(DEBUGGING) + { + + // Put together all the info we have in a single String. + String msg = className + ": " + str; + + // Send the info to the server log. + LaserGun.logger.log(lvl, msg); + + // Check if I'm online and if I am, send me the same info. + Player author = Bukkit.getPlayer(authorUUID); + if(author == null) { + author = Bukkit.getPlayer(authorName); + } + if(author != null) + { + if(Bukkit.getServer().getOnlinePlayers().contains(author)) + { + author.sendMessage(msg); + } + } + } + } +} diff --git a/src/net/mindoverflow/lasergun/utils/FileUtils.java b/src/net/mindoverflow/lasergun/utils/FileUtils.java new file mode 100644 index 0000000..c391e6f --- /dev/null +++ b/src/net/mindoverflow/lasergun/utils/FileUtils.java @@ -0,0 +1,219 @@ +package net.mindoverflow.lasergun.utils; + +import net.mindoverflow.lasergun.LaserGun; +import net.mindoverflow.lasergun.utils.stats.UpdateChecker; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.logging.Level; + +public class FileUtils +{ + + // Instantiate a Debugger for this class. + private static Debugger debugger = new Debugger(FileUtils.class.getName()); + + // Necessary variables. + private static LaserGun plugin; + + public FileUtils(LaserGun plugin) { + FileUtils.plugin = plugin; + } + + private static void copyFileFromSrc(FileType givenFileType) + { + // Check if files already exists and if it doesn't, then create it. + if(!givenFileType.file.exists()) + { + // Load the InputStream of the file in the source folder. + InputStream is = FileUtils.class.getResourceAsStream("/" + givenFileType.file.getName()); + try + { + // Try copying the file to the directory where it's supposed to be, and log it. + Files.copy(is, Paths.get(givenFileType.file.getAbsolutePath())); + is.close(); + debugger.sendDebugMessage(Level.INFO, "File " + givenFileType.file.getName() + " successfully created."); + } + catch (IOException e) + { + // Throw exception if something went wrong (lol, I expect this to happen since we're working with files in different systems) + LaserGun.logger.log(Level.SEVERE, "There were some unexpected errors from " + givenFileType.file.getName() + " file creation. Please contact the developer and send him this log:"); + e.printStackTrace(); + } + + } + } + + // As method says, reload YamlConfigurations by overwriting their previous value. + public static void reloadYamls() + { + FileType.CONFIG_YAML.yaml = YamlConfiguration.loadConfiguration(FileType.CONFIG_YAML.file); + FileType.LANG_YAML.yaml = YamlConfiguration.loadConfiguration(FileType.LANG_YAML.file); + + YamlConfiguration config = FileType.CONFIG_YAML.yaml; + + CommonValues.updateChecker = config.getBoolean(ConfigEntries.UPDATE_CHECKER.path); + + if(UpdateChecker.task != null) plugin.getServer().getScheduler().cancelTask(UpdateChecker.task.getTaskId()); + + if(CommonValues.updateChecker) UpdateChecker.task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, plugin.updateChecker, 1, 20 * 60 * 60 * 12); + + } + + // Only reload the needed File. + public static void reloadYaml(FileType yamlFile) + { + yamlFile.yaml = YamlConfiguration.loadConfiguration(yamlFile.file); + debugger.sendDebugMessage(Level.INFO, "File " + yamlFile.file.getName() + " YAML loaded."); + } + + // Save a Yaml file from the list of the plugin's YamlFiles enum. + public static void saveExistingYaml(FileType yamlFile) + { + // Get the actual File and its location. + File configFile = yamlFile.file; + try { + // Try saving the value in FileType.NAME.yaml into the file itself we just got. Else, it would only be saved in RAM and then be lost after unloading the plugin. + yamlFile.yaml.save(configFile); + debugger.sendDebugMessage(Level.INFO, "Successfully saved " + configFile.getName() +" (YAML)!"); + } catch (IOException e) { + debugger.sendDebugMessage(Level.SEVERE, "Error in saving " + configFile.getName() + "(YAML)!"); + e.printStackTrace(); + } + + // Reload the Yaml configuration from the file, just in case. + reloadYaml(yamlFile); + } + + + // Check if all needed files exist and work correctly. + public static void checkFiles() { + // Check if the different needed files and folders exist and if not, try creating them. + // Check if plugin folder exists and eventually make it. Easy enough. + if(!plugin.getDataFolder().exists()) + { + if(plugin.getDataFolder().mkdir()) + { + debugger.sendDebugMessage(Level.INFO, "Plugin dir successfully created."); + } + } + + // Check and eventually create config file. + copyFileFromSrc(FileType.CONFIG_YAML); + // Reload file YAML data into FileType.NAME.yaml. + reloadYaml(FileType.CONFIG_YAML); + // Check if there is any missing entry. + checkYamlMissingEntries(FileType.CONFIG_YAML); + + + // Check and eventually create players file. + copyFileFromSrc(FileType.LANG_YAML); + // Reload file YAML data into FileType.NAME.yaml. + reloadYaml(FileType.LANG_YAML); + // Check if there is any missing entry. + checkYamlMissingEntries(FileType.LANG_YAML); + + + LaserGun.logger.log(Level.INFO, "All files are working correctly."); + } + + + private static void checkYamlMissingEntries(FileType givenFile) + { + /* + Load the file from source so we can check if the file in the plugin directory is missing any entries. + Since our file is not an actual file on the filesystem but rather a compressed file in the jar archive, + we can't directly access it via a "File file = new File();" method. To do it, we'd need to extract + the file from the archive to a temporary file, read it and then delete it. + + The choice of making an InputStream instead is better because we don't risk leaving junk files + in the filesystem and we can achieve the same objective without so many resource-consuming passages. + */ + + // First of all, we're gonna get the InputStream of the file from the jar archive. + InputStream is = FileUtils.class.getResourceAsStream("/" + givenFile.file.getName()); + + // Then, we're gonna make a Reader because we don't want to save it as a file but only load it in memory. + // Bukkit's YamlConfiguration accepts Readers so this is perfect! + Reader targetReader = new InputStreamReader(is); + + // Load its YamlConfiguration. + YamlConfiguration srcYaml = YamlConfiguration.loadConfiguration(targetReader); + + // Iterate each entry in the YamlConfiguration. + debugger.sendDebugMessage(Level.INFO, "Iterating src config entries for file " + givenFile.file.getName() + "."); + + /* For each String which we'll name 'key' in the Set of entries of the yaml file, do... + + getKeys(true) returns all the entries and all the sub-entries, which is what we need because + we want to check the whole file for missing entries. + If we wanted to only load an entry with the highest level sub-entries, we would just pass 'false' + as an argument. + + Example + ---- FILE ---------------- + hello: 'this is a string' + myname: 4 + islorenzo: 8 + who: true + areu: '?' + john: false + -------------------------- + + Set keys = srcYaml.getConfigurationSection("path").getKeys(true); + + By saving our set with 'false' as an argument, and "" as the path (which means the highest level of the file), + we'd only get the 'hello' String and the 'john' boolean's value in the set. + + By saving our set with 'false' as an argument, and "hello" as the path (which means the highest level of the + 'hello' entry), we'd only get the 'hello' String's value and the 'hello.myname' and 'hello.islorenzo' booleans' values in the set. + + By saving our set with 'true' as an argument, and "" as the path (which means the highest level of the file + with all its sub-entries), we'd get the value of all entries in the whole file ('hello', 'hello.myname', 'hello.islorenzo', + 'hello.islorenzo.who', 'hello.islorenzo.areu', 'john') in the set. + + By saving our set with 'true' as an argument, and "hello" as the path (which means the highest level of the + 'hello' entry with all its sub-entries), we'd get the value of all entries in the 'hello' entry ('hello', 'hello.myname', + 'hello.islorenzo', 'hello.islorenzo.who', 'hello.islorenzo.areu') in the set. + */ + for (String key : srcYaml.getConfigurationSection("").getKeys(true)) + { + debugger.sendDebugMessage(Level.INFO, "Analyzing key '" + key + "' with default value '" + srcYaml.get(key) + "'."); + + // Check if file is missing every entry. + if(!givenFile.yaml.contains(key)) + { + debugger.sendDebugMessage(Level.WARNING, "Config file is missing '" + key + "' key! Proceeding to add it..."); + // Add the entry to the file. + givenFile.yaml.set(key, srcYaml.get(key)); + debugger.sendDebugMessage(Level.WARNING, "Added key '" + key + "' with value '" + srcYaml.get(key) + "'."); + // Save the file! + saveExistingYaml(givenFile); + } + } + debugger.sendDebugMessage(Level.INFO, "Done iterating src config entries for file " + givenFile.file.getName() + "!"); + } + // Save all the info about our files location. + /* + Also initialize all files and their config, so we know where are the files when we need to save or reload them. + this is better than loading the files in the single classes that use them as if we had to reload them, we'd + need to set them again in each of the classes. Doing this instead allows us to have them all in one place. + */ + public enum FileType + { + PLUGIN_FOLDER(plugin.getDataFolder(), null), + CONFIG_YAML(new File(plugin.getDataFolder()+File.separator + "config.yml"), new YamlConfiguration()), + LANG_YAML(new File(plugin.getDataFolder()+File.separator + "lang.yml"), new YamlConfiguration()); + + // Constructor, so we can assign the value we set here ^ to our File. + public File file; + public YamlConfiguration yaml; + FileType(File givenFile, YamlConfiguration yamlConfig) + { + file = givenFile; + yaml = yamlConfig; + } + } +} diff --git a/src/net/mindoverflow/lasergun/utils/LocalizedMessages.java b/src/net/mindoverflow/lasergun/utils/LocalizedMessages.java new file mode 100644 index 0000000..9aec114 --- /dev/null +++ b/src/net/mindoverflow/lasergun/utils/LocalizedMessages.java @@ -0,0 +1,20 @@ +package net.mindoverflow.lasergun.utils; + +public enum LocalizedMessages { + + + ERROR_NO_PERMISSIONS("error.no_permissions"), + + ERROR_CONSOLE_ACCESS_BLOCKED("error.console_access_blocked"), + + LASERGUN_NAME("info.lasergun_name"), + + LASERGUN_LORE("info.lasergun_lore"); + + public String path; + + LocalizedMessages(String path) + { + this.path = path; + } +} diff --git a/src/net/mindoverflow/lasergun/utils/MessageUtils.java b/src/net/mindoverflow/lasergun/utils/MessageUtils.java new file mode 100644 index 0000000..1ecd854 --- /dev/null +++ b/src/net/mindoverflow/lasergun/utils/MessageUtils.java @@ -0,0 +1,89 @@ +package net.mindoverflow.lasergun.utils; + + +import net.mindoverflow.lasergun.LaserGun; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.util.logging.Level; + +public class MessageUtils +{ + // Initialize the Debugger instance. + private static Debugger debugger = new Debugger(MessageUtils.class.getName()); + + + private static LaserGun plugin; + public MessageUtils(LaserGun plugin) + { + MessageUtils.plugin = plugin; + } + // Method to automatically load and send a localized message to the CommandSender. + public static void sendLocalizedMessage(CommandSender sender, LocalizedMessages messageEnum) + { + + // If we actually have a sender, send it the message and color it! + if(sender != null) sender.sendMessage(getLocalizedMessage(messageEnum, true)); + // If the sender is null, report it to the debugger. + else debugger.sendDebugMessage(Level.SEVERE, "Sender is null!"); + } + + + // Method to send a colorized message to the CommandSender. + public static void sendColorizedMessage(CommandSender sender, String message) + { + // If we actually have a sender, send it the message! + if(sender != null) sender.sendMessage(colorize(message)); + // If the sender is null, report it to the debugger. + else debugger.sendDebugMessage(Level.SEVERE, "Sender is null!"); + } + + public static String getLocalizedMessage(LocalizedMessages messageEnum, boolean applyColor) + { + + /* + Load the string from the enum. + We are doing this because we don't want random strings to be passed to this method: we want it done + this way and this way only, so we don't get any error as every entry added to the enum is manually + checked before actually adding it. + */ + String path = messageEnum.path; + + // Initialize the Lang file. + YamlConfiguration langFile = FileUtils.FileType.LANG_YAML.yaml; + + // Initialize the message string and store the String from the lang file to it. + String localizedMessage = langFile.getString(path); + + // Check if the message is null + if (localizedMessage != null) + { + // Check if we have to color the message or leave the symbols inside for further elaboration. + if(applyColor) + { + // Replace the famous '&' and '§' symbols with a ChatColor so we can color the messages! + localizedMessage = colorize(localizedMessage); + } + + } else + { + // Report if the message is null. + debugger.sendDebugMessage(Level.SEVERE, "String " + path + " is null!"); + } + // Return the message, whether it's colored, not colored or null (if it's null, it's the same as writing "return null"). + return localizedMessage; + } + + // Colorize Strings! + public static String colorize(String str) + { + /* + Since the translateAlternateColors method works with only one char and overwrites the previous one, + we are going to replace '&' with '§' and then run that method with all the '§'s. + */ + str = str.replace('&', '§'); + ChatColor.translateAlternateColorCodes('§', str); + return str; + } +} \ No newline at end of file diff --git a/src/net/mindoverflow/lasergun/utils/PermissionUtils.java b/src/net/mindoverflow/lasergun/utils/PermissionUtils.java new file mode 100644 index 0000000..0048a3d --- /dev/null +++ b/src/net/mindoverflow/lasergun/utils/PermissionUtils.java @@ -0,0 +1,46 @@ +package net.mindoverflow.lasergun.utils; + +import net.mindoverflow.lasergun.LaserGun; +import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.entity.Player; + +import java.util.logging.Level; + +public class PermissionUtils +{ + + // Initialize the Debugger instance. + private static Debugger debugger = new Debugger(PermissionUtils.class.getName()); + + + private static LaserGun plugin; + public PermissionUtils(LaserGun givenPlugin) { plugin = givenPlugin; } + + // Method to get the permission string from the Permissions enum. + public static boolean playerHasPermission(String username, Permissions permission) + { + debugger.sendDebugMessage(Level.INFO, "Permission: " + permission.permission + "; Player name is: " + username); + Player user = plugin.getServer().getPlayer(username); + { + if (user != null && user.hasPermission(permission.permission)) + { + return true; + } + } + return false; + } + + + public static boolean playerHasPermission(CommandSender sender, Permissions permission) + { + debugger.sendDebugMessage(Level.INFO, "Permission: " + permission.permission + "; Player name is: " + sender.getName()); + { + if(sender.hasPermission(permission.permission) || sender instanceof ConsoleCommandSender) + { + return true; + } + } + return false; + } +} diff --git a/src/net/mindoverflow/lasergun/utils/Permissions.java b/src/net/mindoverflow/lasergun/utils/Permissions.java new file mode 100644 index 0000000..4a44fd0 --- /dev/null +++ b/src/net/mindoverflow/lasergun/utils/Permissions.java @@ -0,0 +1,18 @@ +package net.mindoverflow.lasergun.utils; + +public enum Permissions +{ + ITEM_GET("lasergun.command.getgun"), + + ITEM_USE("lasergun.usegun"), + + COMMAND_RELOAD("lasergun.command.reload"), + + GET_UPDATES_NOTIFICATIONS("lasergun.updates"), + + ; + + public String permission; + + Permissions(String permission) { this.permission = permission; } +} diff --git a/src/net/mindoverflow/lasergun/utils/stats/UpdateChecker.java b/src/net/mindoverflow/lasergun/utils/stats/UpdateChecker.java new file mode 100644 index 0000000..6116242 --- /dev/null +++ b/src/net/mindoverflow/lasergun/utils/stats/UpdateChecker.java @@ -0,0 +1,268 @@ +package net.mindoverflow.lasergun.utils.stats; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import net.mindoverflow.lasergun.LaserGun; +import net.mindoverflow.lasergun.utils.*; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitTask; + +import javax.net.ssl.HttpsURLConnection; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.logging.Level; + +public class UpdateChecker implements Runnable +{ + + public static BukkitTask task; + + Debugger debugger = new Debugger(getClass().getName()); + + + + public String newVersion, updateLink; + public ArrayList updateText = new ArrayList<>(), warningMessage = new ArrayList<>(); + public Boolean updateWarningBoolean, isNewVersionOut = false; + + public Boolean isServerUnreachable = true; + public String errorCode; + + private LaserGun plugin; + public UpdateChecker(LaserGun givenPlugin) + { + plugin = givenPlugin; + } + + private String servicesUrl = "https://services.mind-overflow.net/"; + private String lasergunUrl = "java/plugins/lasergun/updates/"; + + @Override + public void run() + { + CommandSender console = plugin.getServer().getConsoleSender(); + updateText.clear(); + warningMessage.clear(); + + + try + { + // Open an HTTPS Connection to the MOWS (Mind Overflow Web Services) + HttpsURLConnection connection = (HttpsURLConnection) new URL(servicesUrl).openConnection(); + connection.setRequestMethod("HEAD"); + + // Read the response code. + int responseCode = connection.getResponseCode(); + + // If it's not "OK"... Stop + if (responseCode != 200) + { + setAndSendErrorCode(responseCode + "", console); + return; + } + + errorCode = null; + + + } // Exception means the server was unreachable. Stop + catch (IOException e) + { + sendUnreachableCode(console); + isServerUnreachable = true; + return; + } + isServerUnreachable = false; + + // Now, try loading the JSON file... + InputStream jsonIS; + try + { + + jsonIS = new URL( servicesUrl + lasergunUrl + "update.json").openStream(); + + } catch (IOException e) + { + + setAndSendErrorCode("null json", console); + return; + } + + // And parsing it... + JsonParser jsonParser = new JsonParser(); + JsonObject json = (JsonObject)jsonParser.parse(new InputStreamReader(jsonIS, StandardCharsets.UTF_8)); + + // Close the input stream... + try { + jsonIS.close(); + } catch (IOException ignored) + { + } + + // Check if the "version" String is present... + newVersion = null; + if(json.get("version") == null) + { + setAndSendErrorCode("null version", console); + return; + } + + // Store it. + newVersion = json.get("version").getAsString(); + + // Check if versions match... And stop + if(newVersion.equalsIgnoreCase(plugin.getDescription().getVersion())) + { + isNewVersionOut = false; + return; + } + + // If we are here, it means a new version is out. + isNewVersionOut = true; + + // Load the update link... + updateLink = null; + if(json.get("link") == null) + { + setAndSendErrorCode("null link", console); + return; + } + updateLink = json.get("link").getAsString(); + + + // Load all the lines from the String Array... + if(json.get("text") == null) + { + setAndSendErrorCode("null text", console); + return; + } + JsonArray updateTextArray = json.get("text").getAsJsonArray(); + for(JsonElement obj : updateTextArray) + { + String relatedString = obj.getAsString(); + updateText.add(relatedString); + } + + // Load the warning object... + if(json.get("warning") == null) + { + setAndSendErrorCode("null warning", console); + return; + } + JsonObject warning = json.get("warning").getAsJsonObject(); + + // See if the warning is enabled... + if(warning.get("enabled") == null) + { + setAndSendErrorCode("null warning boolean", console); + return; + } + updateWarningBoolean = warning.get("enabled").getAsBoolean(); + + // Load all the lines from the String Array... + if(warning.get("text") == null) + { + setAndSendErrorCode("null warning text", console); + return; + } + JsonArray warningTextArray = warning.get("text").getAsJsonArray(); + for(JsonElement obj : warningTextArray) + { + String relatedString = obj.getAsString(); + warningMessage.add(relatedString); + } + + // And finally send the message! + sendUpdateMessages(console); + + } + + + public void sendUnreachableCode(CommandSender sender) + { + String pluginName = plugin.getName(); + MessageUtils.sendColorizedMessage(sender, "&7-----[&3 " + pluginName + " Updater &7]-----"); + MessageUtils.sendColorizedMessage(sender, "&cWarning! Updates Server is unreachable."); + MessageUtils.sendColorizedMessage(sender, "&cTry fixing connectivity problems and reload " + pluginName + " with &3/" + pluginName.toLowerCase() + " reload&c!"); + } + + public void setAndSendErrorCode(String code, CommandSender sender) + { + isNewVersionOut = false; + errorCode = code; + sendErrorCode(sender); + } + + public void sendErrorCode(CommandSender sender) + { + String pluginName = plugin.getName(); + MessageUtils.sendColorizedMessage(sender, "&7-----[&3 " + pluginName + " Updater &7]-----"); + MessageUtils.sendColorizedMessage(sender, "&cWarning! Updates Server returned error code: &4" + errorCode); + MessageUtils.sendColorizedMessage(sender, "&cPlease contact the developer (" + debugger.authorName + ") immediately."); + } + + + public void sendUpdateMessages(CommandSender sender) + { + String pluginName = plugin.getName(); + MessageUtils.sendColorizedMessage(sender, "&7-----[&3 " + pluginName + " Updater &7]-----"); + MessageUtils.sendColorizedMessage(sender, "&7A new version is out: &6" + newVersion); + MessageUtils.sendColorizedMessage(sender, "&7Download: &6" + updateLink); + for(String line : updateText) + { + MessageUtils.sendColorizedMessage(sender, line); + } + if(updateWarningBoolean) + { + for(String line : warningMessage) + { + MessageUtils.sendColorizedMessage(sender, line); + } + } + } + + public void playerMessage(CommandSender player) + { + plugin.getServer().getScheduler().runTaskLater(plugin, () -> + { + // Stop this in case the sender is the console: it already receives intended messages. + if(!(player instanceof Player)) return; + + // Check if the updater is enabled. + if(CommonValues.updateChecker) + { + debugger.sendDebugMessage(Level.INFO, "Update Checker is enabled!"); + // Check if the player has permissions to get notifications about updates. + if(PermissionUtils.playerHasPermission(player, Permissions.GET_UPDATES_NOTIFICATIONS)) + { + debugger.sendDebugMessage(Level.INFO, "Player has permissions to check updates."); + // Instantiate the update checker so we can access it. + + if(isNewVersionOut) + { + sendUpdateMessages(player); + } + + if(isServerUnreachable) + {sendUnreachableCode(player); + } + + if(errorCode != null) + { + + sendErrorCode(player); + } + } + } + }, 40); + + + } +} + diff --git a/src/plugin.yml b/src/plugin.yml new file mode 100644 index 0000000..82a341d --- /dev/null +++ b/src/plugin.yml @@ -0,0 +1,11 @@ +name: LaserGun +version: alpha-BUILD_NUMBER +author: mind_overflow +main: net.mindoverflow.lasergun.LaserGun +api-version: 1.13 +softdepend: [ProtocolLib] + +commands: + lasergun: + description: LaserGun base command. + usage: /lasergun \ No newline at end of file