diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..5869b87 --- /dev/null +++ b/.classpath @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ddf7b8a --- /dev/null +++ b/.gitignore @@ -0,0 +1,107 @@ +# ---> Maven +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +# https://github.com/takari/maven-wrapper#usage-without-binary-jar +.mvn/wrapper/maven-wrapper.jar +# ---> Java +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +# *.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..d72d30e --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/discord.xml b/.idea/discord.xml new file mode 100644 index 0000000..d8e9561 --- /dev/null +++ b/.idea/discord.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..66d5240 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..e95b7ea --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..139f35a --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.project b/.project new file mode 100644 index 0000000..880704b --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + DITSystem + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..29abf99 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,6 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..ca4c66e --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/README.md b/README.md new file mode 100644 index 0000000..d9c792e --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# SimplifyTools +### An 'All-in-one' helper plugin for Minecraft Spigot Servers. +| Build Status | ![ Build Status](https://ci.dit-services.tk/buildStatus/icon?job=DIT-System) | +|:-------------:|:-----------------------------------------------------------------------------------------------------------------:| +| MC Version | ![ MC Version](https://ci.dit-services.tk/job/SimplifyTools/badge/icon?subject=MC&status=1.16.5&color=darkblue) | +| Lines of code | ![ Lines of code](https://tokei.rs/b1/github/LabodiDavid/SimplifyTools?category=code) | +| Files | ![ Files](https://tokei.rs/b1/github/LabodiDavid/SimplifyTools?category=files) | +## Features + + - **Tab Manager** - Allows you to specify colored texts, with animations on the tab window. + Also you can display the average ping, Server RAM statistics. + ![Tab manager preview](https://ci.dit-services.tk/userContent/simplifytools/1.gif) + - **Automatic/command saving** - Allows you to schedule auto saving of the world/player data on your server, or you can initiate a save by a command. + - **Custom Connect/Disconnect messages** - Allows you to customize the message that is broadcasted when someone joins or leaves the server. + ![Connect messages preview](https://ci.dit-services.tk/userContent/simplifytools/2.gif) + - **Plugin Manager** - Allows you to unload/load plugins without a server restart. + (Note: This may be removed in 1.17.x versions for security reasons) + - **Gameplay statistics** - You can check your gameplay statistics such as player/mob kills, etc. + (Note: The plugin just shows the stats not recording itself, so stats before installing this plugin are counted too.) + ![Stats preview](https://ci.dit-services.tk/userContent/simplifytools/3.gif) + - **Custom Advancement Messages** - You can customize the advancement messages in three categories: advancement, goal, challenge. + (Note: The advancement names are currently only can be displayed in english. In future versions there will be a feature to translate to any languages.) + ![Advancement Messages preview](https://ci.dit-services.tk/userContent/simplifytools/4.gif) + - **Logging** - A logger with fully customizable format for dis/connect, chat, commands actions. +### [Check the config file for more explanation and examples](https://github.com/LabodiDavid/SimplifyTools/blob/main/src/main/resources/config.yml) + +### [Commands & Permissions](docs/cmd_perms.md) + +### If you have an idea or bug report [Create an issue](https://github.com/LabodiDavid/SimplifyTools/issues/new/choose) or [Create a pull request](https://github.com/LabodiDavid/SimplifyTools/compare) + +## Main goal +My main goal is to create a single plugin that has many features, so it's can replace so many plugins that i often use on my servers while lowering the plugins count. + +## 3rd party libraries used by this plugin +### [Config-Updater by tchristofferson](https://github.com/tchristofferson/Config-Updater) \ No newline at end of file diff --git a/SimplifyTools.iml b/SimplifyTools.iml new file mode 100644 index 0000000..76d178c --- /dev/null +++ b/SimplifyTools.iml @@ -0,0 +1,26 @@ + + + + + + + SPIGOT + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/ChangeLog.md b/docs/ChangeLog.md new file mode 100644 index 0000000..baeeb81 --- /dev/null +++ b/docs/ChangeLog.md @@ -0,0 +1,4 @@ +## SimplifyTools Changelog + + - 1.0.0 - First Release + - Notice: If the /st reload command not reloading the new settings, you need to restart your MC server. diff --git a/docs/cmd_perms.md b/docs/cmd_perms.md new file mode 100644 index 0000000..91e5196 --- /dev/null +++ b/docs/cmd_perms.md @@ -0,0 +1,16 @@ +## SimplifyTools Commands +You can use the following commands to use the features of SimplifyTools. +- **/st**: The main SimplifyTools command.
Requires `st.st` +- **/st help**: Displays all SimplifyTools related commands.
Requires `st.help` +- **/st ping**: Displays your ping to the current server.
Requires `st.ping` +- **/st stats**: Displays your gameplay statistics.
Requires `st.stats` +- **/st save-all**: Saves the players, worlds data on the server.
Requires `st.save` +- **/st pmanager** : A built-in plugin manager.
Requires `st.pmanager.*` +- **/st pmanager load** : Plugin loading.
Requires `st.pmanager.load (can be inherited from st.pmanager.*)` +- **/st pmanager unload** : Plugin unload.
Requires `st.pmanager.unload (can be inherited from st.pmanager.*)` +- **/st reload**: Plugin settings reload.
Requires `st.reload` +
+## SimplifyTools Wildcard Permissions +- **st.*** - Wildcard permission for all commands, permissions for this plugin. +- **st.pmanager.*** - Wildcard permission for the plugin manager commands. +- **st.admin** - A wildcard permission for admins. This is used for notify when update available, also grants usage for `st.save` and `st.pmanager.*` \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..9918eeb --- /dev/null +++ b/pom.xml @@ -0,0 +1,95 @@ + + + 4.0.0 + + tk.ditservices + SimplifyTools + 1.0.0-SNAPSHOT + jar + + SimplifyTools + + SimplifyTools - All-in-one helper plugin. + + 1.8 + UTF-8 + + dit-services.tk + + + jenkins + https://ci.dit-services.tk/job/SimplifyTools/ + + + + GitHub + https://github.com/LabodiDavid/SimplifyTools/issues + + + + + The GNU General Public Licence version 3 (GPLv3) + https://www.gnu.org/licenses/gpl-3.0.html + repo + + + + + clean package + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + ${java.version} + ${java.version} + + + + org.apache.maven.plugins + maven-shade-plugin + 3.1.0 + + + package + + shade + + + false + + + + + + + + src/main/resources + true + + + + + + + sonatype + https://oss.sonatype.org/content/groups/public/ + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + + + + org.spigotmc + spigot + 1.16.5-R0.1-SNAPSHOT + provided + + + diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 0000000..ccb1ba6 --- /dev/null +++ b/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: DITSystem + diff --git a/src/main/java/tk/ditservices/DITLog.java b/src/main/java/tk/ditservices/DITLog.java new file mode 100644 index 0000000..72d24ad --- /dev/null +++ b/src/main/java/tk/ditservices/DITLog.java @@ -0,0 +1,70 @@ +package tk.ditservices; + + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Calendar; + +import org.bukkit.event.Listener; + +public class DITLog implements Listener { + public static String Location = "plugins/SimplifyTools/logs/"; + + /** + * Gets the current date in yyyy-MM-dd format. + */ + public static String getDate() { + Calendar cal = Calendar.getInstance(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + return sdf.format(cal.getTime()); + } + /** + * Gets the current time in HH:mm:ss format. + */ + public static String getTime() { + Calendar cal = Calendar.getInstance(); + SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); + return sdf.format(cal.getTime()); + } + /** + * Logs a line in the today's log file. + * @param text The text to log. + */ + public static void logLine(String text){ + String fileName = DITLog.getDate()+".txt"; + + File file = new File(DITLog.Location+fileName); + if (!file.exists()){ createFile(); } + + try { + BufferedWriter writer = new BufferedWriter(new FileWriter(file,true)); + writer.write(text); + writer.newLine(); + writer.close(); + + } catch (Exception e){ e.printStackTrace(); } + } + + + private static void createFile(){ + String fileName = getDate() + ".txt"; + File directory = new File(DITLog.Location); + if(!directory.exists()){ + directory.mkdirs(); + } + + File file = new File(DITLog.Location + fileName); + if( !file.exists() ){ + try { + file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + +} diff --git a/src/main/java/tk/ditservices/DITSystem.java b/src/main/java/tk/ditservices/DITSystem.java new file mode 100644 index 0000000..df0ab60 --- /dev/null +++ b/src/main/java/tk/ditservices/DITSystem.java @@ -0,0 +1,127 @@ +package tk.ditservices; + +import org.bukkit.scheduler.BukkitScheduler; +import tk.ditservices.commands.DitCmd; +import tk.ditservices.listeners.ChatEvents; +import tk.ditservices.listeners.LogChat; +import tk.ditservices.listeners.LogCommand; +import tk.ditservices.listeners.LogConnect; +import tk.ditservices.utils.ConfigUpdater; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.GameRule; +import org.bukkit.World; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.PluginCommand; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.event.Listener; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; +import tk.ditservices.utils.Math; + +import java.io.*; +import java.util.Collections; +import java.util.List; +import java.util.logging.Logger; + +public final class DITSystem extends JavaPlugin implements CommandExecutor, Listener { + private static DITSystem instance; + Logger log = Bukkit.getLogger(); + private DitPluginManager dplug; + public TabManager tab; + + public FileConfiguration config; + + + @Override + public void onEnable() { + saveDefaultConfig(); + instance = this; + this.DIT_initialize(); + this.tab = new TabManager(this,this.config); + this.dplug = new DitPluginManager(this); + + + + System.out.println(this.getPrefix()+"Started running."); + } + + private void DIT_initialize() { + if (this.Reload()){ + initOptions(); + + PluginCommand ditCmd = this.getCommand("st"); + ditCmd.setExecutor(new DitCmd(this)); + ditCmd.setTabCompleter(new DITTabCompleter()); + + getServer().getPluginManager().registerEvents(this, this); + getServer().getPluginManager().registerEvents(new LogChat(this), this); + getServer().getPluginManager().registerEvents(new LogCommand(this), this); + getServer().getPluginManager().registerEvents(new LogConnect(this), this); + getServer().getPluginManager().registerEvents(new ChatEvents(this), this); + + } + } + public String getPrefix(){ + if (this.config.isSet("Prefix")){ + return ChatColor.translateAlternateColorCodes('&', this.config.getString("Prefix")); + }else{ + return ChatColor.translateAlternateColorCodes('&',"&a[&fSimplify&7Tools&2] &4- &f"); + } + } + public static DITSystem getInstance(){ + return instance; + } + public void initOptions(){ + + + + if (config.getBoolean("Saving.enabled") && config.getInt("Saving.interval")>0){ + BukkitScheduler scheduler = getServer().getScheduler(); + scheduler.scheduleSyncRepeatingTask(instance, new Runnable() { + @Override + public void run() { + String p = config.isSet("Saving.broadcastMsgProgress") ? config.getString("Saving.broadcastMsgProgress").replace("{PREFIX}",instance.getPrefix()) : instance.getPrefix()+"Auto save in progress.."; + String d = config.isSet("Saving.broadcastMsgDone") ? config.getString("Saving.broadcastMsgDone").replace("{PREFIX}",instance.getPrefix()) : instance.getPrefix()+"Auto save done."; + Bukkit.broadcast(p,"st.st"); + for(World w : Bukkit.getServer().getWorlds()){ + w.save(); + } + Bukkit.savePlayers(); + Bukkit.broadcast(d,"st.st"); + } + }, 0L, Math.convert(Math.Convert.SECONDS,Math.Convert.TICKS,instance.config.getInt("Saving.interval"))); + } + + + if (this.config.isSet("CustomAdvancement.enabled")) { + if(config.getBoolean("CustomAdvancement.enabled")){ + + List worlds = getServer().getWorlds(); + for (World w : worlds) { + if(w.getGameRuleValue(GameRule.ANNOUNCE_ADVANCEMENTS)) { + w.setGameRule(GameRule.ANNOUNCE_ADVANCEMENTS, false); + log.info(this.getPrefix()+"Disabling vanilla advancement messages for " + w.getName()); + } + } + } + } + + } + public boolean Reload(){ + File configFile = new File(getDataFolder(), "config.yml"); + try { + ConfigUpdater.update(this, "config.yml", configFile, Collections.emptyList()); + } catch (IOException e) { + e.printStackTrace(); + } + reloadConfig(); + this.config = getConfig(); + + return true; + } + @Override + public void onDisable() { + System.out.println(this.getPrefix()+" stopped."); + } +} diff --git a/src/main/java/tk/ditservices/DITTabCompleter.java b/src/main/java/tk/ditservices/DITTabCompleter.java new file mode 100644 index 0000000..ca7eaeb --- /dev/null +++ b/src/main/java/tk/ditservices/DITTabCompleter.java @@ -0,0 +1,88 @@ +package tk.ditservices; + +import org.bukkit.Bukkit; +import org.bukkit.command.*; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginManager; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +public class DITTabCompleter implements TabCompleter { + + List arguments = new ArrayList(); + + @Override + public List onTabComplete(CommandSender commandSender, Command command, String s, String[] args) { + + if (command.getName().equals("st")) { + + if (arguments.isEmpty()){ + String curr_cmd = ""; + for (Plugin plug : Bukkit.getPluginManager().getPlugins()) { + List cmdList = PluginCommandYamlParser.parse(plug); + for (int i = 0; i <= cmdList.size() - 1; i++) { + if (cmdList.get(i).getLabel().contains("st ")) { + curr_cmd =cmdList.get(i).getLabel(); + curr_cmd = curr_cmd.replace("st ",""); + arguments.add(curr_cmd); + } + } + } + } + + + List idea = new ArrayList<>(); + List result = new ArrayList<>(); + String curr_cmd = ""; + //String[] vizsg_args = new String[args.length+1]; + List vizsg_list = new ArrayList<>(); + boolean vizsg_2 = false; + if (args.length == 1) { + for (String a : arguments){ + if (a.toLowerCase().startsWith(args[0].toLowerCase())){ + result.add(a); + } + } + return result; + } + if (args.length >= 2) { + for (String a : arguments) { + vizsg_2 = false; + if (a.contains(" ")){ + vizsg_list = Arrays.asList(a.split(" ")); + vizsg_2 = true; + } + if (vizsg_2 && args.length ==2){ // length-1 + idea.add(vizsg_list.get(1)); + } + if (vizsg_2&& args[1].startsWith(vizsg_list.get(1))) { + idea.add(vizsg_list.get(1)); + } + } + + if (args[0].equalsIgnoreCase("pmanager")&& args[1].equalsIgnoreCase("unload") || args[1].equalsIgnoreCase("load")) { + if (args.length == 3) { + result.clear(); + PluginManager pm = Bukkit.getServer().getPluginManager(); + for (Plugin pl : pm.getPlugins()) { + if (pl.getName().toLowerCase().startsWith(args[2].toLowerCase()) && args[1].equalsIgnoreCase("unload")) { + result.add(pl.getName()); + } + if (!pl.isEnabled()){ + if (pl.getName().toLowerCase().startsWith(args[2].toLowerCase()) && args[1].equalsIgnoreCase("load")) { + result.add(pl.getName()); + } + } + } + return result; + } + } + return idea; + + + } + } + return null; + } +} diff --git a/src/main/java/tk/ditservices/DitPluginManager.java b/src/main/java/tk/ditservices/DitPluginManager.java new file mode 100644 index 0000000..f9ef744 --- /dev/null +++ b/src/main/java/tk/ditservices/DitPluginManager.java @@ -0,0 +1,183 @@ +package tk.ditservices; +import tk.ditservices.DITSystem; +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.PluginCommand; +import org.bukkit.command.SimpleCommandMap; +import org.bukkit.event.Event; +import org.bukkit.plugin.*; +import java.io.File; +import java.lang.reflect.Field; +import java.util.*; +public class DitPluginManager { + private static DITSystem plugin; + public DitPluginManager(DITSystem instance){ + plugin = instance; + } + /** + * Loads the requested plugin. + * @param pluginName Plugin name in string. + */ + public static int load(final String pluginName) { + PluginManager pm = Bukkit.getServer().getPluginManager(); + boolean there = false; + for (Plugin pl : pm.getPlugins()){ + if (pl.getName().toLowerCase().startsWith(pluginName)){ + there = true; + } + } + + + if (there) + { return 1;} //plugin already exists + else { + String name = ""; + String path = plugin.getDataFolder().getParent(); + File folder = new File(path); + ArrayList files = new ArrayList(); + File[] listOfFiles = folder.listFiles(); + for (File compare : listOfFiles) { + if (compare.isFile()) { + try { + name = plugin.getPluginLoader().getPluginDescription(compare).getName(); + } catch (InvalidDescriptionException e) { + plugin.getLogger().warning("[Loading Plugin] " + compare.getName() + " didn't match"); + } + if (name.toLowerCase().startsWith(pluginName.toLowerCase())) { + files.add(compare); + try { + Bukkit.getServer().getPluginManager().loadPlugin(compare); + } catch (UnknownDependencyException e) { + return 2; //missing dependent plugin + } catch (InvalidPluginException e) { + return -1; //not a plugin + } catch (InvalidDescriptionException e) { + return 3; //invalid description + } + } + } + } + + Plugin[] plugins = pm.getPlugins(); + for (Plugin pl : plugins) { + for (File compare : files) { + try { + if (pl.getName().equalsIgnoreCase(plugin.getPluginLoader().getPluginDescription(compare).getName())) + if (!pl.isEnabled()){ + pm.enablePlugin(pl); + }else { return 5; } + } catch (InvalidDescriptionException e) { + e.printStackTrace(); + } + } + } + } + return 0; //success + } + + + @SuppressWarnings("unchecked") + public static int unload(String pluginName) { + pluginName = pluginName.toLowerCase().trim(); + PluginManager manager = Bukkit.getServer().getPluginManager(); + SimplePluginManager spm = (SimplePluginManager) manager; + SimpleCommandMap commandMap = null; + List plugins = null; + Map lookupNames = null; + Map knownCommands = null; + Map> listeners = null; + boolean reloadlisteners = true; + try { + if (spm != null) { + Field pluginsField = spm.getClass().getDeclaredField("plugins"); + pluginsField.setAccessible(true); + plugins = (List) pluginsField.get(spm); + + Field lookupNamesField = spm.getClass().getDeclaredField("lookupNames"); + lookupNamesField.setAccessible(true); + lookupNames = (Map) lookupNamesField.get(spm); + + try { + Field listenersField = spm.getClass().getDeclaredField("listeners"); + listenersField.setAccessible(true); + listeners = (Map>) listenersField.get(spm); + } catch (Exception e) { + reloadlisteners = false; + } + + Field commandMapField = spm.getClass().getDeclaredField("commandMap"); + commandMapField.setAccessible(true); + commandMap = (SimpleCommandMap) commandMapField.get(spm); + + Field knownCommandsField = commandMap.getClass().getDeclaredField("knownCommands"); + knownCommandsField.setAccessible(true); + knownCommands = (Map) knownCommandsField.get(commandMap); + } + } catch (Exception e) { + e.printStackTrace(); + } + boolean in = false; + + for (Plugin pl : Bukkit.getServer().getPluginManager().getPlugins()) { + if (in) + break; + if (pl.getName().toLowerCase().startsWith(pluginName.toLowerCase())) { + if (pl.isEnabled()) { + manager.disablePlugin(pl); + if (plugins != null && plugins.contains(pl)) + plugins.remove(pl); + + if (lookupNames != null && lookupNames.containsKey(pl.getName())) { + lookupNames.remove(pl.getName()); + } + + if (listeners != null && reloadlisteners) { + for (SortedSet set : listeners.values()) { + for (Iterator it = set.iterator(); it.hasNext(); ) { + RegisteredListener value = it.next(); + + if (value.getPlugin() == pl) { + it.remove(); + } + } + } + } + + if (commandMap != null) { + for (Iterator> it = knownCommands.entrySet().iterator(); it.hasNext(); ) { + Map.Entry entry = it.next(); + if (entry.getValue() instanceof PluginCommand) { + PluginCommand c = (PluginCommand) entry.getValue(); + if (c.getPlugin() == pl) { + c.unregister(commandMap); + it.remove(); + } + } + } + } + for (Plugin plu : Bukkit.getServer().getPluginManager().getPlugins()) { + if (plu.getDescription().getDepend() != null) { + for (String depend : plu.getDescription().getDepend()) { + if (depend.equalsIgnoreCase(pl.getName())) { + plugin.getLogger().info("[Unloading Plugin] " + plu.getName() + " must be disabled!"); + unload(plu.getName()); + return 1; //dependencies also disabled + } + } + } + } + in = true; + } else { return 5; } + } + } + if (!in) { + plugin.getLogger().info("Not an existing plugin"); + return -1; //non-existent + } + System.gc(); + return 0; //success + } + + + +} diff --git a/src/main/java/tk/ditservices/TabManager.java b/src/main/java/tk/ditservices/TabManager.java new file mode 100644 index 0000000..f85e7bd --- /dev/null +++ b/src/main/java/tk/ditservices/TabManager.java @@ -0,0 +1,207 @@ +package tk.ditservices; + +import tk.ditservices.utils.Math; +import tk.ditservices.utils.Server; +import net.minecraft.server.v1_16_R3.ChatComponentText; +import net.minecraft.server.v1_16_R3.IChatBaseComponent; +import net.minecraft.server.v1_16_R3.PacketPlayOutPlayerListHeaderFooter; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +public class TabManager { + private List headers = new ArrayList<>(); + private List footers = new ArrayList<>(); + + private Integer refreshRate; + + private DITSystem plugin; + private FileConfiguration config; + private List headeranimList = new ArrayList(); + private List footeranimList = new ArrayList(); + + private ArrayList formatArray = new ArrayList<>(); + private List DynamicHeaders = new ArrayList<>(); + private List DynamicFooters = new ArrayList<>(); + + private enum AddLine { + HEADER, FOOTER + } + + public TabManager(DITSystem instance,FileConfiguration c){ + + this.plugin = instance; + this.config = c; + + if(this.init()){ + this.showTab(); + } + + } + + public void showTab(){ + if (headers.isEmpty() && footers.isEmpty()){ + return; + } + Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, new Runnable() { + PacketPlayOutPlayerListHeaderFooter packet = new PacketPlayOutPlayerListHeaderFooter(); + int count1 = 0; //headers + int count2 = 0; //footers + @Override + public void run() { + try { + //Tab code + Field a = packet.getClass().getDeclaredField("header"); + a.setAccessible(true); + Field b = packet.getClass().getDeclaredField("footer"); + b.setAccessible(true); + if (count1>=headers.size()){ + count1=0; + } + if (count2>=footers.size()){ + count2=0; + } + + //Re adding all lines where we replaced something like the RAM usage to every refresh + //display current value. (We check those lines in the init()) + if (DynamicHeaders.size()>0 && count1 < DynamicHeaders.size()){ + if (DynamicHeaders.get(count1) == count1){ + addHeaderFooter(AddLine.HEADER,headeranimList.get(count1),true,count1); + } + } + if (DynamicFooters.size()>0 && count2 < DynamicFooters.size()){ + if (DynamicFooters.get(count2) == count2){ + addHeaderFooter(AddLine.FOOTER,footeranimList.get(count2),true,count2); + } + } + + a.set(packet, headers.get(count1)); + b.set(packet,footers.get(count2)); + + if (Bukkit.getOnlinePlayers().size() !=0){ + for (Player player : Bukkit.getOnlinePlayers()){ + ((CraftPlayer)player).getHandle().playerConnection.sendPacket(packet); + } + } + if (headers.size()>1){ + count1++; + } + if (footers.size()>1){ + count2++; + } + + } catch (Exception e){ + e.printStackTrace(); + } + } + },10, Math.convert(Math.Convert.SECONDS,Math.Convert.TICKS,this.refreshRate)); + } + + private boolean init(){ + if (config.getBoolean("Tab.enabled")){ + if (config.isSet("Tab.refreshRate")){ + this.refreshRate = config.getInt("Tab.refreshRate"); + }else{ + this.refreshRate=40; + } + + //Getting the tab lines from the config + headeranimList = config.getStringList("Tab.headerAnimation"); + footeranimList = config.getStringList("Tab.footerAnimation"); + + //Investigating lines where we need to run the formatting every tab refresh for example for the RAM usage. + //Only storing those lines indexes. + formatArray.add("{TOTALRAM}"); + formatArray.add("{FREERAM}"); + formatArray.add("{USEDRAM}"); + formatArray.add("{AVERAGEPING}"); + formatArray.add("{ONLINEPLAYERS}"); + formatArray.add("{MAXPLAYERS}"); + for (String f: formatArray){ + for (int i = 0; i ignoredSections) throws IOException { + BufferedReader newReader = new BufferedReader(new InputStreamReader(plugin.getResource(resourceName), StandardCharsets.UTF_8)); + List newLines = newReader.lines().collect(Collectors.toList()); + newReader.close(); + + FileConfiguration oldConfig = YamlConfiguration.loadConfiguration(toUpdate); + FileConfiguration newConfig = YamlConfiguration.loadConfiguration(new InputStreamReader(plugin.getResource(resourceName), StandardCharsets.UTF_8)); + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(toUpdate), StandardCharsets.UTF_8)); + + List ignoredSectionsArrayList = new ArrayList<>(ignoredSections); + //ignoredSections can ONLY contain configurations sections + ignoredSectionsArrayList.removeIf(ignoredSection -> !newConfig.isConfigurationSection(ignoredSection)); + + Yaml yaml = new Yaml(); + Map comments = parseComments(newLines, ignoredSectionsArrayList, oldConfig, yaml); + write(newConfig, oldConfig, comments, ignoredSectionsArrayList, writer, yaml); + } + + //Write method doing the work. + //It checks if key has a comment associated with it and writes comment then the key and value + private static void write(FileConfiguration newConfig, FileConfiguration oldConfig, Map comments, List ignoredSections, BufferedWriter writer, Yaml yaml) throws IOException { + outer: for (String key : newConfig.getKeys(true)) { + String[] keys = key.split("\\."); + String actualKey = keys[keys.length - 1]; + String comment = comments.remove(key); + + StringBuilder prefixBuilder = new StringBuilder(); + int indents = keys.length - 1; + appendPrefixSpaces(prefixBuilder, indents); + String prefixSpaces = prefixBuilder.toString(); + + if (comment != null) { + writer.write(comment);//No \n character necessary, new line is automatically at end of comment + } + + for (String ignoredSection : ignoredSections) { + if (key.startsWith(ignoredSection)) { + continue outer; + } + } + + Object newObj = newConfig.get(key); + Object oldObj = oldConfig.get(key); + + if (newObj instanceof ConfigurationSection && oldObj instanceof ConfigurationSection) { + //write the old section + writeSection(writer, actualKey, prefixSpaces, (ConfigurationSection) oldObj); + } else if (newObj instanceof ConfigurationSection) { + //write the new section, old value is no more + writeSection(writer, actualKey, prefixSpaces, (ConfigurationSection) newObj); + } else if (oldObj != null) { + //write the old object + write(oldObj, actualKey, prefixSpaces, yaml, writer); + } else { + //write new object + write(newObj, actualKey, prefixSpaces, yaml, writer); + } + } + + String danglingComments = comments.get(null); + + if (danglingComments != null) { + writer.write(danglingComments); + } + + writer.close(); + } + + //Doesn't work with configuration sections, must be an actual object + //Auto checks if it is serializable and writes to file + private static void write(Object obj, String actualKey, String prefixSpaces, Yaml yaml, BufferedWriter writer) throws IOException { + if (obj instanceof ConfigurationSerializable) { + writer.write(prefixSpaces + actualKey + ": " + yaml.dump(((ConfigurationSerializable) obj).serialize())); + } else if (obj instanceof String || obj instanceof Character) { + if (obj instanceof String) { + String s = (String) obj; + obj = s.replace("\n", "\\n"); + } + + writer.write(prefixSpaces + actualKey + ": " + yaml.dump(obj)); + } else if (obj instanceof List) { + writeList((List) obj, actualKey, prefixSpaces, yaml, writer); + } else { + writer.write(prefixSpaces + actualKey + ": " + yaml.dump(obj)); + } + } + + //Writes a configuration section + private static void writeSection(BufferedWriter writer, String actualKey, String prefixSpaces, ConfigurationSection section) throws IOException { + if (section.getKeys(false).isEmpty()) { + writer.write(prefixSpaces + actualKey + ": {}"); + } else { + writer.write(prefixSpaces + actualKey + ":"); + } + + writer.write("\n"); + } + + //Writes a list of any object + private static void writeList(List list, String actualKey, String prefixSpaces, Yaml yaml, BufferedWriter writer) throws IOException { + writer.write(getListAsString(list, actualKey, prefixSpaces, yaml)); + } + + private static String getListAsString(List list, String actualKey, String prefixSpaces, Yaml yaml) { + StringBuilder builder = new StringBuilder(prefixSpaces).append(actualKey).append(":"); + + if (list.isEmpty()) { + builder.append(" []\n"); + return builder.toString(); + } + + builder.append("\n"); + + for (int i = 0; i < list.size(); i++) { + Object o = list.get(i); + + if (o instanceof String || o instanceof Character) { + builder.append(prefixSpaces).append("- '").append(o).append("'"); + } else if (o instanceof List) { + builder.append(prefixSpaces).append("- ").append(yaml.dump(o)); + } else { + builder.append(prefixSpaces).append("- ").append(o); + } + + if (i != list.size()) { + builder.append("\n"); + } + } + + return builder.toString(); + } + + //Key is the config key, value = comment and/or ignored sections + //Parses comments, blank lines, and ignored sections + private static Map parseComments(List lines, List ignoredSections, FileConfiguration oldConfig, Yaml yaml) { + Map comments = new HashMap<>(); + StringBuilder builder = new StringBuilder(); + StringBuilder keyBuilder = new StringBuilder(); + int lastLineIndentCount = 0; + + outer: for (String line : lines) { + if (line != null && line.trim().startsWith("-")) + continue; + + if (line == null || line.trim().equals("") || line.trim().startsWith("#")) { + builder.append(line).append("\n"); + } else { + lastLineIndentCount = setFullKey(keyBuilder, line, lastLineIndentCount); + + for (String ignoredSection : ignoredSections) { + if (keyBuilder.toString().equals(ignoredSection)) { + Object value = oldConfig.get(keyBuilder.toString()); + + if (value instanceof ConfigurationSection) + appendSection(builder, (ConfigurationSection) value, new StringBuilder(getPrefixSpaces(lastLineIndentCount)), yaml); + + continue outer; + } + } + + if (keyBuilder.length() > 0) { + comments.put(keyBuilder.toString(), builder.toString()); + builder.setLength(0); + } + } + } + + if (builder.length() > 0) { + comments.put(null, builder.toString()); + } + + return comments; + } + + private static void appendSection(StringBuilder builder, ConfigurationSection section, StringBuilder prefixSpaces, Yaml yaml) { + builder.append(prefixSpaces).append(getKeyFromFullKey(section.getCurrentPath())).append(":"); + Set keys = section.getKeys(false); + + if (keys.isEmpty()) { + builder.append(" {}\n"); + return; + } + + builder.append("\n"); + prefixSpaces.append(" "); + + for (String key : keys) { + Object value = section.get(key); + String actualKey = getKeyFromFullKey(key); + + if (value instanceof ConfigurationSection) { + appendSection(builder, (ConfigurationSection) value, prefixSpaces, yaml); + prefixSpaces.setLength(prefixSpaces.length() - 2); + } else if (value instanceof List) { + builder.append(getListAsString((List) value, actualKey, prefixSpaces.toString(), yaml)); + } else { + builder.append(prefixSpaces.toString()).append(actualKey).append(": ").append(yaml.dump(value)); + } + } + } + + //Counts spaces in front of key and divides by 2 since 1 indent = 2 spaces + private static int countIndents(String s) { + int spaces = 0; + + for (char c : s.toCharArray()) { + if (c == ' ') { + spaces += 1; + } else { + break; + } + } + + return spaces / 2; + } + + //Ex. keyBuilder = key1.key2.key3 --> key1.key2 + private static void removeLastKey(StringBuilder keyBuilder) { + String temp = keyBuilder.toString(); + String[] keys = temp.split("\\."); + + if (keys.length == 1) { + keyBuilder.setLength(0); + return; + } + + temp = temp.substring(0, temp.length() - keys[keys.length - 1].length() - 1); + keyBuilder.setLength(temp.length()); + } + + private static String getKeyFromFullKey(String fullKey) { + String[] keys = fullKey.split("\\."); + return keys[keys.length - 1]; + } + + //Updates the keyBuilder and returns configLines number of indents + private static int setFullKey(StringBuilder keyBuilder, String configLine, int lastLineIndentCount) { + int currentIndents = countIndents(configLine); + String key = configLine.trim().split(":")[0]; + + if (keyBuilder.length() == 0) { + keyBuilder.append(key); + } else if (currentIndents == lastLineIndentCount) { + //Replace the last part of the key with current key + removeLastKey(keyBuilder); + + if (keyBuilder.length() > 0) { + keyBuilder.append("."); + } + + keyBuilder.append(key); + } else if (currentIndents > lastLineIndentCount) { + //Append current key to the keyBuilder + keyBuilder.append(".").append(key); + } else { + int difference = lastLineIndentCount - currentIndents; + + for (int i = 0; i < difference + 1; i++) { + removeLastKey(keyBuilder); + } + + if (keyBuilder.length() > 0) { + keyBuilder.append("."); + } + + keyBuilder.append(key); + } + + return currentIndents; + } + + private static String getPrefixSpaces(int indents) { + StringBuilder builder = new StringBuilder(); + + for (int i = 0; i < indents; i++) { + builder.append(" "); + } + + return builder.toString(); + } + + private static void appendPrefixSpaces(StringBuilder builder, int indents) { + builder.append(getPrefixSpaces(indents)); + } +} \ No newline at end of file diff --git a/src/main/java/tk/ditservices/utils/Cooldown.java b/src/main/java/tk/ditservices/utils/Cooldown.java new file mode 100644 index 0000000..6809dfa --- /dev/null +++ b/src/main/java/tk/ditservices/utils/Cooldown.java @@ -0,0 +1,73 @@ +package tk.ditservices.utils; + +import tk.ditservices.DITSystem; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +public class Cooldown { + private int delay = 2; //seconds + DITSystem plugin; + Map cooldowns = new HashMap<>(); + public long time_left; + FileConfiguration config; + public Cooldown(DITSystem instance){ + this.plugin = instance; + this.config = plugin.config; + if (config.isSet("Cooldown.seconds")){ + int cd = this.delay; + if (cd!=config.getInt("Cooldown.seconds")){ + this.delay = config.getInt("Cooldown.seconds"); + } + } + } + /** + * Checks if the command sender has a cooldown in time. + * @param sender The CommandSender object. + */ + public boolean Check(CommandSender sender){ + if (sender instanceof Player){ + Player player = (Player) sender; + if (config.getBoolean("Cooldown.enabled")) { + if (this.cooldowns.containsKey(player.getName())) { + if (this.cooldowns.get(player.getName()) > System.currentTimeMillis()) { + this.time_left = (this.cooldowns.get(player.getName()) - System.currentTimeMillis()) / 1000; + if (this.time_left == 0) { + return true; + } + return false; + } + return true; + } + } else{ + return true; + } + } + if (sender instanceof ConsoleCommandSender){ + return true; + } + + return true; + } + public void Add(Player player){ + if (config.getBoolean("Cooldown.enabled")) { + if (this.cooldowns.containsKey(player.getName())) { + this.cooldowns.remove(player.getName()); + } + this.cooldowns.put(player.getName(), System.currentTimeMillis() + (this.delay * 1000L)); + } + } + public void CDText(CommandSender sender){ + String msg = config.getString("Cooldown.Msg"); + msg = msg.replace("{PREFIX}", plugin.getPrefix()); + msg = msg.replace("{SECONDS}",String.valueOf(this.time_left)); + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',msg)); + } + +} diff --git a/src/main/java/tk/ditservices/utils/Math.java b/src/main/java/tk/ditservices/utils/Math.java new file mode 100644 index 0000000..b64e201 --- /dev/null +++ b/src/main/java/tk/ditservices/utils/Math.java @@ -0,0 +1,21 @@ +package tk.ditservices.utils; + +import java.io.IOException; + +public class Math { + public enum Convert { + TICKS,SECONDS,MINUTES,HOURS + } + /** + * Converting time measurement units from one to another. + * @param from The unit FROM you want to convert. Math.Convert + * @param to The unit TO you want to convert. Math.Convert + * @param value An integer which you want to convert. + */ + public static long convert(Convert from, Convert to, int value){ + if (from== Convert.SECONDS && to==Convert.TICKS){ + return value*20L; + } + return 0; + } +} diff --git a/src/main/java/tk/ditservices/utils/Server.java b/src/main/java/tk/ditservices/utils/Server.java new file mode 100644 index 0000000..435ee80 --- /dev/null +++ b/src/main/java/tk/ditservices/utils/Server.java @@ -0,0 +1,65 @@ +package tk.ditservices.utils; + +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer; +import org.bukkit.entity.Player; +import java.lang.Math; + +import java.lang.reflect.InvocationTargetException; + +public class Server { + public enum RAM { + FREE,USED,TOTAL + } + /** + * Get RAM usage statistics of the MC server. + * @param t The RAM usage type you want to get. Server.RAM enum. It could be FREE,TOTAL,USED + */ + public static long getRAM(Server.RAM t) { + long mb = 1048576L; + Runtime runtime = Runtime.getRuntime(); + runtime.gc(); + if (t == RAM.FREE){ + return runtime.freeMemory() / mb; + } + if (t == RAM.TOTAL){ + return runtime.totalMemory() / mb; + } + if (t == RAM.USED){ + return (runtime.totalMemory() - runtime.freeMemory()) / mb; + } + + return 0; + } + /** + * Get a player's ping. + * @param player The player object. + */ + public static int getPlayerPing(Player player){ + try { + Object entityPlayer = player.getClass().getMethod("getHandle").invoke(player); + return (int) entityPlayer.getClass().getField("ping").get(entityPlayer); + } catch (IllegalAccessException | IllegalArgumentException | NoSuchMethodException | SecurityException | NoSuchFieldException | InvocationTargetException e) { + e.printStackTrace(); + } + return -1; + } + /** + * Get an average of the currently online player's ping. + */ + public static int getAveragePing(){ + int sum = 0; + int avg = 0; + int onlineplayers = 0; + if (Bukkit.getOnlinePlayers().size() !=0){ + onlineplayers =Bukkit.getOnlinePlayers().size(); + for (Player player : Bukkit.getOnlinePlayers()){ + sum += Server.getPlayerPing(player); + } + avg = Math.floorDiv(sum,onlineplayers); + + } + return avg; + + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..e0e01c6 --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,87 @@ +# SimplifyTools +# Config file +# +# REMOVING SETTINGS MAY CAUSE ERRORS DO NOT DO THAT!!! +# +# +# ░██████╗██╗███╗░░░███╗██████╗░██╗░░░░░██╗███████╗██╗░░░██╗████████╗░█████╗░░█████╗░██╗░░░░░░██████╗ +# ██╔════╝██║████╗░████║██╔══██╗██║░░░░░██║██╔════╝╚██╗░██╔╝╚══██╔══╝██╔══██╗██╔══██╗██║░░░░░██╔════╝ +# ╚█████╗░██║██╔████╔██║██████╔╝██║░░░░░██║█████╗░░░╚████╔╝░░░░██║░░░██║░░██║██║░░██║██║░░░░░╚█████╗░ +# ░╚═══██╗██║██║╚██╔╝██║██╔═══╝░██║░░░░░██║██╔══╝░░░░╚██╔╝░░░░░██║░░░██║░░██║██║░░██║██║░░░░░░╚═══██╗ +# ██████╔╝██║██║░╚═╝░██║██║░░░░░███████╗██║██║░░░░░░░░██║░░░░░░██║░░░╚█████╔╝╚█████╔╝███████╗██████╔╝ +# ╚═════╝░╚═╝╚═╝░░░░░╚═╝╚═╝░░░░░╚══════╝╚═╝╚═╝░░░░░░░░╚═╝░░░░░░╚═╝░░░░╚════╝░░╚════╝░╚══════╝╚═════╝░ +# +# Logging options +# If you enable one of them, a txt file will be created every day automatically with the current date. +Log: + Chat: false #Chat messages + Connect: false #Connections, disconnects + Command: false #All command will be logged !for example private messaging, authme passwords!! + #You can customize the format for the three types. + # These values will be replaced like that: {DATE} = YYYY-MM-DD, {TIME} = HH:MM:SS, {ACTION} = [CHAT] or [COMMAND] etc.. + # Example connect in the log: [2020-12-08] - 19:07:04 - [CONNECT] - PlayerName UUID: 01010101-1010-asd1-1212-404826345656 + FormatChat: '[{DATE}] - {TIME} - {ACTION} - {PLAYERNAME}: {MSG}' + FormatConnect: '[{DATE}] - {TIME} - {ACTION} - {PLAYERNAME} UUID: {UUID}' # Note: The disconnect message will be based on this too. + FormatCommand: '[{DATE}] - {TIME} - {ACTION} - {PLAYERNAME}: {COMMAND}' + +# Custom Advance Messages +# Replaces vanilla advancement broadcasting +CustomAdvancement: + enabled: false + formats: + # {NAME} represent the player's name. + # {ADV} represent the advancement name. + advancement: '&l&f{NAME}&r &bhas completed the &f[&a&n{ADV}&r&f]&b advancement!' + goal: '&l&f{NAME}&r&f]&b &bhas reached the &f[&a&n{ADV}&r&f]&b goal!' + challenge: '&l&f{NAME}&r &bcompleted the &f[&a&n{ADV}&r&f]&b challenge!' + +# Tab Customization +# +# You can use Minecraft color, format codes with '&' in the texts. +# example: header: &cThis server is using SimplifyTools by &1SimplifyDave +# Note: Use \n to add a new line +# Note: The RAM values are in MB. +# {USEDRAM} {TOTALRAM} {FREERAM} {AVERAGEPING} {ONLINEPLAYERS} {MAXPLAYERS} represents their values. +# NOTICE: You will need a full MC server restart when you want to apply new settings here. +Tab: + enabled: false # If you want to enable customization on the tab + refreshRate: 2 # The refresh rate in SECONDS + headerAnimation: #If animation set to true, you can set the animations per line. +#If you don't want animations, just leave one line text here! + #- '&l&cThis is an example header text without animation\nAnd this is a new line!' + - '&cThis server is using SimplifyTools by &1SimplifyDave \nAverage ping: {AVERAGEPING} ms' + - '&bThis server is using SimplifyTools by &9SimplifyDave \nAverage ping: {AVERAGEPING} ms' + - '&b&lThis server is using SimplifyTools by &9SimplifyDave \nAverage ping: {AVERAGEPING} ms' + + footerAnimation: +#If you don't want animations, just leave one line text here! + #- '&l&cThis is an example footer text without animation\n with multiple lines in one element!' + - '&l&4Server RAM Usage: {TOTALRAM}MB / {USEDRAM}MB\nOnline players: {MAXPLAYERS}/{ONLINEPLAYERS}' + - '&l&aServer RAM Usage: {TOTALRAM}MB / {USEDRAM}MB\nOnline players: {MAXPLAYERS}/{ONLINEPLAYERS}' + +# Custom Connect/Disconnect messages +CustomMsg: + enabled: false + connect: '{PREFIX}{NAME} &aconnected to the server.' + disconnect: '{PREFIX}{NAME} leaved the game.' + +# Auto Save options +# Saves Worlds/Users data to disk. +# Note: You can do a save like this with the /st save-all command. +# NOTICE: You will need a full MC server restart when you want to apply new settings here. +Saving: + enabled: true + onDisconnect: true # When a player disconnects + interval: 0 # Auto saving interval in SECONDS. If this set to zero it means disabled. + broadcastMsgProgress: '{PREFIX}Auto save in progress..' + broadcastMsgDone: '{PREFIX}Auto save done.' + +# Cooldown options (only applicable for this plugin!) +Cooldown: + enabled: true + # The time must be passed between using this plugin commands. + seconds: 2 #The command cooldown in seconds + Msg: '{PREFIX} Please wait {SECONDS} seconds!' # The message when the user spamming a command + +# Miscellaneous +Prefix: '&a[&fSimplify&7Tools&2] &4- &f' diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..60aa141 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,98 @@ +name: SimplifyTools +version: ${project.version} +main: tk.ditservices.DITSystem +api-version: 1.13 +prefix: SimplifyTools +load: POSTWORLD +description: SimplifyTools - An All-in-one helper plugin. +author: SimplifyDave +website: https://dit-services.tk +commands: + st: + description: The default command for the plugin. + usage: "/st" + permission: st.st + st help: + description: Displays all SimplifyTools related commands. + usage: "/st help" + permission: st.help + st ping: + description: Displays your ping to the current server. + usage: "/st ping" + permission: st.ping + st stats: + description: Displays your gameplay statistics. + usage: "/st stats" + permission: st.stats + st save-all: + description: Saves the players, worlds data on the server. + usage: "/st save-all" + permission: st.save + st pmanager: + description: A built-in plugin manager. + usage: "/st pmanager " + permission: st.pmanager + st pmanager load: + description: Plugin loading. + usage: "/st pmanager load " + permission: st.pmanager.load + st pmanager unload: + description: Plugin unloading. + usage: "/st pmanager unload " + permission: st.pmanager.unload + st reload: + description: Plugin settings reload. + usage: "/st reload" + permission: st.reload + +permissions: + st.help: + description: Enables the help command. + default: true + st.status: + description: Enables the status command. + default: true + st.ping: + description: Enables the ping command. + default: true + st.reload: + description: Enables the reload command. + default: op + st.pmanager.load: + description: Enables the plugin loading command. + default: op + st.pmanager.unload: + description: Enables the plugin disabling command. + default: op + st.st: + description: This is the default permission. + default: true + st.stats: + description: Enables the stats command. + default: true + st.save: + description: Enables the save-all command. + default: op + st.admin: + description: An admin permission for the maintenance commands and for update notifies. + default: op + children: + st.save: true + st.pmanager.*: true + st.*: + description: Wildcard permission for all commands. + default: op + children: + st.st: true + st.help: true + st.ping: true + st.status: true + st.save: true + st.stats: true + st.settings: true + st.pmanager.*: + description: The plugin manager commands. + default: op + children: + st.pmanager.load: true + st.pmanager.unload: true \ No newline at end of file