Initial commit

This commit is contained in:
Bea 2020-04-09 16:31:14 +02:00
commit 915257692f
39 changed files with 3420 additions and 0 deletions

31
HubThat-Reborn.iml Normal file
View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/17.0.0/annotations-17.0.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library" scope="PROVIDED">
<library>
<CLASSES>
<root url="jar://D:/Coding/# Server per Test Plugins #/spigot-1.15.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://D:/Coding/# Server per Test Plugins #/spigot-1.15.2.jar!/" />
</SOURCES>
</library>
</orderEntry>
</component>
</module>

38
ant_build_increment.xml Normal file
View File

@ -0,0 +1,38 @@
<project name="BuildIncrement" default="init" basedir=".">
<description>
simple example increment build variable
</description>
<!-- set global properties for this build -->
<property name="src" location="src"/>
<property name="version" value="10.0"/>
<loadproperties>
<file file="build.number"/>
</loadproperties>
<target name="init">
<echo file="ant_buildversion_init.txt">Changing build version from BUILD_VERSION to ${version}.${build.number} in file plugin.yml...</echo>
<replaceregexp file="${src}/plugin.yml"
match="BUILD_NUMBER"
replace="${version}.${build.number}"
byline="true"
/>
<echo file="ant_buildversion_init.txt">Changed!</echo>
</target>
<target name="end">
<echo file="ant_buildversion_end.txt">Changing back build version ${version}.${build.number} in file plugin.yml to BUILD_VERSION...</echo>
<replaceregexp file="${src}/plugin.yml"
match="${version}.${build.number}"
replace="BUILD_NUMBER"
byline="true"
/>
<buildnumber/>
<echo file="ant_buildversion_init.txt">Changed!</echo>
</target>
</project>

1
ant_buildversion_end.txt Normal file
View File

@ -0,0 +1 @@
Changing back build version 10.0.161 in file plugin.yml to BUILD_VERSION...

View File

@ -0,0 +1 @@
Changed!

5
build.number Normal file
View File

@ -0,0 +1,5 @@
#Build Number for ANT. Do not edit!
#Sat Apr 04 18:08:45 CEST 2020
build.number=162
\#Build=Number for ANT. Do not edit\!
\#Tue=Jul 30 16\:09\:09 CEST 2019

19
src/config.yml Normal file
View File

@ -0,0 +1,19 @@
hub:
delay: 5
spawn:
delay: 5
chat:
limit-to-worlds-sharing-spawns: false
update-checker:
enable: true
movement-detection:
enable: true
gamemode:
set-on-join: true
mode: 0
teleportation:
teleport-to-hub-on-join: true
teleport-to-hub-on-respawn: false
respawn-handler: true
settings:
multiverse-bypass: false

7
src/hub.yml Normal file
View File

@ -0,0 +1,7 @@
hub:
world: __UNSET__
x: 0.0
y: 0.0
z: 0.0
yaw: 0.0
pitch: 0.0

27
src/lang.yml Normal file
View File

@ -0,0 +1,27 @@
error:
console-access-blocked: '&cSorry, but this command is not available via console.'
already-teleporting: '&cYou are already in the teleportation queue!'
hub-not-set: '&cThe hub is not set.'
spawn-not-set: '&cThe spawn is not set.'
unknown-world: '&cError: world "%w%" does not exist!'
wrong-usage: '&cWrong usage! Correct usage is %usage%'
no-permission: '&cYou do not have permission: &4%permission%'
player-offline: '&cPlayer %player% is offline!'
warning:
console-access: '&eWarning! You are accessing the plugin command from console.'
teleportation-cancelled: '&cYou moved! Teleportation cancelled.'
info:
global:
teleport-delay: '&eYou will be teleported in %delay% seconds!'
prefix: '&0[&3HT&0] &f'
hub:
teleported: '&eYou have been teleported to the hub!'
teleported-other: '&eYou teleported &3%player%&e to the hub!'
set: '&eYou have successfully set the hub! World: &3%w%&e X: &3%x%&e Y: &3%y%&e Z: &3%z%'
spawn:
teleported: '&eYou have been teleported to the spawn!'
teleported-other: '&eYou teleported &3%player%&e to world &3%world%&e''s spawn!'
set: '&eYou have successfully set the spawn for world &3%dw%&e in world: &3%cw%&e X: &3%x%&e Y: &3%y%&e Z: &3%z%'
worldtp:
teleported: '&eYou have been teleported to world "%w%"!'
worlds-list: '&3Worlds List:'

View File

@ -0,0 +1,182 @@
package net.mindoverflow.hubthat;
import net.mindoverflow.hubthat.commands.*;
import net.mindoverflow.hubthat.completers.InfoCompleter;
import net.mindoverflow.hubthat.completers.SpawnCompleter;
import net.mindoverflow.hubthat.listeners.PlayerChatListener;
import net.mindoverflow.hubthat.listeners.PlayerJoinListener;
import net.mindoverflow.hubthat.listeners.PlayerMoveListener;
import net.mindoverflow.hubthat.listeners.PlayerRespawnListener;
import net.mindoverflow.hubthat.utils.files.FileUtils;
import net.mindoverflow.hubthat.utils.files.OldConfigConversion;
import net.mindoverflow.hubthat.utils.statistics.Metrics;
import net.mindoverflow.hubthat.utils.statistics.UpdateChecker;
import net.mindoverflow.hubthat.utils.*;
import org.bukkit.World;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.logging.Level;
import java.util.logging.Logger;
public class HubThat 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 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);
HubThatCommand hubThatCommandInstance = new HubThatCommand(this);
HubCommand hubCommandInstance = new HubCommand(this);
SetHubCommand setHubCommandInstance = new SetHubCommand(this);
SpawnCommand spawnCommandInstance = new SpawnCommand(this);
SetSpawnCommand setSpawnCommandInstance = new SetSpawnCommand(this);
WorldListCommand worldListCommandInstance = new WorldListCommand(this);
WorldTpCommand worldTpCommandInstance = new WorldTpCommand(this);
PermissionUtils permissionUtilsInstance = new PermissionUtils(this);
TeleportUtils teleportUtilsInstance = new TeleportUtils(this);
MessageUtils messageUtilsInstance = new MessageUtils(this);
UpdateChecker updateCheckerInstance = new UpdateChecker(this);
updateChecker = new UpdateChecker(this);
debugger.sendDebugMessage(Level.INFO, "Done instantiating classes!");
// Register Listeners
debugger.sendDebugMessage(Level.INFO, "Registering listeners...");
pluginManager.registerEvents(new PlayerJoinListener(this), this);
pluginManager.registerEvents(new PlayerMoveListener(this), this);
pluginManager.registerEvents(new PlayerChatListener(this), this);
pluginManager.registerEvents(new PlayerRespawnListener(this), this);
debugger.sendDebugMessage(Level.INFO, "Done registering listeners!");
// Register Commands
debugger.sendDebugMessage(Level.INFO, "Registering commands...");
getCommand("hubthat").setExecutor(hubThatCommandInstance);
getCommand("hubthat").setTabCompleter(new InfoCompleter());
getCommand("hub").setExecutor(hubCommandInstance);
getCommand("sethub").setExecutor(setHubCommandInstance);
getCommand("spawn").setExecutor(spawnCommandInstance);
getCommand("spawn").setTabCompleter(new SpawnCompleter());
getCommand("setspawn").setExecutor(setSpawnCommandInstance);
getCommand("setspawn").setTabCompleter(new SpawnCompleter());
getCommand("worldlist").setExecutor(worldListCommandInstance);
getCommand("worldtp").setExecutor(worldTpCommandInstance);
getCommand("worldtp").setTabCompleter(new SpawnCompleter());
debugger.sendDebugMessage(Level.INFO, "Done registering commands!");
OldConfigConversion.checkOldConfig(this, logger);
// 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!");
// Check for updates, if they are enabled.
if(FileUtils.FileType.CONFIG_YAML.yaml.getBoolean(ConfigEntries.UPDATE_CHECKER_ENABLED.path))
{
debugger.sendDebugMessage(Level.INFO, "Update checking is enabled.");
// Start the update checking delayed job. It will handle checking updates, storing variables and telling the console.
debugger.sendDebugMessage(Level.INFO, "Running task (via Main).");
//UpdateChecker.runTimer();
// Check if the links are valid.
/*debugger.sendDebugMessage(Level.INFO, "Checking if links are valid via Main.");
if(updateCheckerInstance.linksValid())
{
debugger.sendDebugMessage(Level.INFO, "Links are valid.");
// Check if the update is needed (if newest version is different from current version).
// We need to surround it with try/catch because it may throw a IOException,
try
{
debugger.sendDebugMessage(Level.INFO, "Checking updates are needed via Main.");
updateCheckerInstance.checkUpdates();
} catch (IOException e)
{
e.printStackTrace();
}
}
else
{ // If the links are not valid... (eg: server/internet is offline)
// Log it to the console.
logger.log(Level.SEVERE, "There's a problem with the updates server.");
logger.log(Level.SEVERE, "Please check if there are any updates manually.");
}*/
}
debugger.sendDebugMessage(Level.INFO,"Setting up Metrics...");
setupMetrics();
debugger.sendDebugMessage(Level.INFO,"Done setting up Metrics!");
// 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 ]---");
getServer().getScheduler().cancelTasks(this);
logger.log(Level.INFO, "Plugin " + getDescription().getName() + " Successfully Unloaded!");
debugger.sendDebugMessage(Level.WARNING, "---[ PLUGIN DISABLED ]---");
}
private void setupMetrics()
{
Metrics metrics = new Metrics(this);
YamlConfiguration config = FileUtils.FileType.CONFIG_YAML.yaml;
metrics.addCustomChart(new Metrics.SimplePie("respawn-handler", () -> config.getString(ConfigEntries.TELEPORTATION_RESPAWN_HANDLER.path)));
metrics.addCustomChart(new Metrics.SimplePie("world-related-chat", () -> config.getString(ConfigEntries.WORLD_RELATED_CHAT.path)));
metrics.addCustomChart(new Metrics.SimplePie("update-notify", () -> config.getString(ConfigEntries.UPDATE_CHECKER_ENABLED.path)));
metrics.addCustomChart(new Metrics.SimplePie("set-gamemode-on-join", () -> config.getString(ConfigEntries.GAMEMODE_SET_ON_JOIN.path)));
metrics.addCustomChart(new Metrics.SimplePie("tp-hub-on-join", () -> config.getString(ConfigEntries.TELEPORTATION_TP_HUB_ON_JOIN.path)));
metrics.addCustomChart(new Metrics.SimplePie("tp-hub-on-respawn", () -> config.getString(ConfigEntries.TELEPORTATION_TP_HUB_ON_RESPAWN.path)));
if(config.getBoolean(ConfigEntries.GAMEMODE_SET_ON_JOIN.path))
{
metrics.addCustomChart(new Metrics.SimplePie("join-gamemode", () -> config.getString(ConfigEntries.GAMEMODE.path)));
}
}
}

View File

@ -0,0 +1,152 @@
package net.mindoverflow.hubthat.commands;
import net.mindoverflow.hubthat.HubThat;
import net.mindoverflow.hubthat.utils.*;
import net.mindoverflow.hubthat.utils.files.FileUtils;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.Objects;
import java.util.logging.Level;
public class HubCommand implements CommandExecutor
{
// Initialize the debugger so I can debug the plugin.
private static Debugger debugger = new Debugger(HubCommand.class.getName());
// Initialize the plugin variable so we can access all of the plugin's data.
private static HubThat plugin;
// Constructor to actually give "plugin" a value.
public HubCommand(HubThat givenPlugin) { plugin = givenPlugin; }
@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());
// Store the commandSender name for easy access.
String username = commandSender.getName();
if(args.length > 0)
{
// Check if the player has permission to teleport to the hub.
if(PermissionUtils.playerHasPermission(commandSender, Permissions.HUB_TELEPORT_OTHERS))
{
String teleportingPlayerName = args[0];
Player teleportingPlayer = plugin.getServer().getPlayer(teleportingPlayerName);
if(teleportingPlayer == null)
{
String errorMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.ERROR_PLAYER_OFFLINE, true).replace("%player%", teleportingPlayerName);
commandSender.sendMessage(errorMessage);
return true;
}
else
{
teleportToHub(commandSender, teleportingPlayer);
return true;
}
}
else
{
// Warn the player he doesn't have permissions to teleport others to the hub.
String errorMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.NO_PERMISSION, true).replace("%permission%", Permissions.HUB_TELEPORT_OTHERS.permission);
commandSender.sendMessage(errorMessage);
return true;
}
}
// If the command comes from Console, stop it and give a warning.
boolean senderIsConsole = !(commandSender instanceof Player);
if(senderIsConsole)
{
MessageUtils.sendLocalizedMessage(commandSender, LocalizedMessages.ERROR_CONSOLE_ACCESS_BLOCKED);
return true;
}
// Check if the player has permission to teleport to the hub.
if(PermissionUtils.playerHasPermission(commandSender, Permissions.HUB_TELEPORT))
{
// Check if the player has permission to skip the teleport delay.
if(PermissionUtils.playerHasPermission(commandSender, Permissions.NO_HUB_DELAY))
{
teleportToHub(commandSender, (Player)commandSender);
return true;
}
// If the player doesn't have permission to skip the teleport delay...
else
{
// Check if he's not already teleporting.
if(!CommonValues.teleporting.contains(username))
{
// Put the player in the ArrayList of players waiting to be teleported.
CommonValues.teleporting.add(username);
// Load the teleportation delay.
int delay = FileUtils.FileType.CONFIG_YAML.yaml.getInt(ConfigEntries.HUB_DELAY.path);
// Warn the player about the delay.
String delayMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.INFO_TELEPORT_DELAY, false);
delayMessage = delayMessage.replace("%delay%", delay + "");
MessageUtils.sendColorizedMessage(commandSender, delayMessage);
// Start a timer.
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable()
{
@Override
public void run()
{
if(!CommonValues.cancelRunnable.contains(username) && CommonValues.teleporting.contains(username))
{
teleportToHub(commandSender, (Player)commandSender);
}
CommonValues.cancelRunnable.remove(username);
}
}, delay * 20); // Convert seconds to ticks.
return true;
}
// If it's already teleporting...
else
{
// Send a message to the player stating it, and do nothing.
MessageUtils.sendLocalizedMessage(commandSender, LocalizedMessages.ERROR_ALREADY_TELEPORTING);
return true;
}
}
}
else
{
// Warn the player he doesn't have permissions to go to the hub.
String errorMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.NO_PERMISSION, true).replace("%permission%", Permissions.HUB_TELEPORT.permission);
commandSender.sendMessage(errorMessage);
return true;
}
}
// Method to teleport the player to the hub.
public static void teleportToHub(CommandSender sender, Player player)
{
String username = player.getName();
// Require the world to be Non Null
String worldName = Objects.requireNonNull(player.getWorld().getName());
debugger.sendDebugMessage(Level.INFO, "Player name: " + username + "; World name: " + worldName);
// Teleport the player to the destination.
TeleportUtils.teleportPlayer(sender, player, FileUtils.FileType.HUB_YAML, worldName);
// Remove it from the "teleporting" list - so it won't get teleported if it's waiting the spawn delay.
CommonValues.teleporting.remove(username);
}
}

View File

@ -0,0 +1,71 @@
package net.mindoverflow.hubthat.commands;
import net.mindoverflow.hubthat.HubThat;
import net.mindoverflow.hubthat.commands.hubthatcommands.HelpCommand;
import net.mindoverflow.hubthat.commands.hubthatcommands.ReloadCommand;
import net.mindoverflow.hubthat.utils.Debugger;
import net.mindoverflow.hubthat.utils.MessageUtils;
import net.mindoverflow.hubthat.utils.LocalizedMessages;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import java.util.logging.Level;
public class HubThatCommand implements CommandExecutor
{
// Initialize the plugin variable so we can access all of the plugin's data.
private HubThat 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 HubThatCommand(HubThat 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.
// We need no warning because this command is not player reliant.
/*boolean senderIsConsole = (commandSender instanceof ConsoleCommandSender);
if(senderIsConsole)
{
MessageUtils.sendLocalizedMessage(commandSender.getName(), LocalizedMessages.WARNING_CONSOLE_ACCESS);
}*/
// Check if there are any args.
if(args.length == 0)
{
MessageUtils.sendColorizedMessage(commandSender, "&7HubThat version &6" + plugin.getDescription().getVersion() + " for SpigotMC/CraftBukkit &61.7&7-&61.15&7.");
MessageUtils.sendColorizedMessage(commandSender, "&7Coded by &6mind_overflow&7, all rights reserved (&6Copyright © '20&7).");
commandSender.sendMessage("");
MessageUtils.sendColorizedMessage(commandSender, "&7Write &6/hubthat help&7 to see plugin commands.");
}
// Check if there is a single argument after the command itself.
else if (args.length == 1)
{
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);
}
}
return true;
}
}

View File

@ -0,0 +1,87 @@
package net.mindoverflow.hubthat.commands;
import net.mindoverflow.hubthat.HubThat;
import net.mindoverflow.hubthat.utils.*;
import net.mindoverflow.hubthat.utils.files.FileUtils;
import org.bukkit.Location;
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 SetHubCommand implements CommandExecutor
{
// Initialize the debugger so I can debug the plugin.
private Debugger debugger = new Debugger(getClass().getName());
// Initialize the plugin variable so we can access all of the plugin's data.
private HubThat plugin;
// Constructor to actually give "plugin" a value.
public SetHubCommand(HubThat givenPlugin) { plugin = givenPlugin; }
@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, stop it and give a warning.
boolean senderIsConsole = (commandSender instanceof ConsoleCommandSender);
if(senderIsConsole)
{
MessageUtils.sendLocalizedMessage(commandSender, LocalizedMessages.ERROR_CONSOLE_ACCESS_BLOCKED);
return true;
}
// Check if the player has permission to set the hub.
if(PermissionUtils.playerHasPermission(commandSender, Permissions.HUB_SET))
{
// Cast player to commandSender so we can get its position.
Player player = (Player)commandSender;
// Load the player's position.
Location playerLocation = player.getLocation();
double x, y, z, yaw, pitch;
String worldName;
x = playerLocation.getX();
y = playerLocation.getY();
z = playerLocation.getZ();
yaw = playerLocation.getYaw();
pitch = playerLocation.getPitch();
worldName = playerLocation.getWorld().getName();
// Set the location to the Yaml file.
FileUtils.FileType.HUB_YAML.yaml.set("hub.x", x);
FileUtils.FileType.HUB_YAML.yaml.set("hub.y", y);
FileUtils.FileType.HUB_YAML.yaml.set("hub.z", z);
FileUtils.FileType.HUB_YAML.yaml.set("hub.yaw", yaw);
FileUtils.FileType.HUB_YAML.yaml.set("hub.pitch", pitch);
FileUtils.FileType.HUB_YAML.yaml.set("hub.world", worldName);
// Save the file to the disk. We don't need to reload the Yaml file because we already set the values in the RAM.
FileUtils.saveExistingYaml(FileUtils.FileType.HUB_YAML);
// Tell the player he set the hub successfully.
String hubSetMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.INFO_HUB_SET, false);
hubSetMessage = hubSetMessage.replace("%w%", worldName);
hubSetMessage = hubSetMessage.replace("%x%", (int)x + "");
hubSetMessage = hubSetMessage.replace("%y%", (int)y + "");
hubSetMessage = hubSetMessage.replace("%z%", (int)z + "");
MessageUtils.sendColorizedMessage(commandSender, hubSetMessage);
}
else
{
String errorMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.NO_PERMISSION, true).replace("%permission%", Permissions.HUB_SET.permission);
commandSender.sendMessage(errorMessage);
}
return true;
}
}

View File

@ -0,0 +1,127 @@
package net.mindoverflow.hubthat.commands;
import net.mindoverflow.hubthat.HubThat;
import net.mindoverflow.hubthat.utils.*;
import net.mindoverflow.hubthat.utils.files.FileUtils;
import org.bukkit.Location;
import org.bukkit.World;
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.Objects;
import java.util.logging.Level;
public class SetSpawnCommand implements CommandExecutor
{
// Initialize the debugger so I can debug the plugin.
private Debugger debugger = new Debugger(getClass().getName());
// Initialize the plugin variable so we can access all of the plugin's data.
private HubThat plugin;
// Constructor to actually give "plugin" a value.
public SetSpawnCommand(HubThat givenPlugin) { plugin = givenPlugin; }
@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, stop it and give a warning.
boolean senderIsConsole = (commandSender instanceof ConsoleCommandSender);
if(senderIsConsole)
{
MessageUtils.sendLocalizedMessage(commandSender, LocalizedMessages.ERROR_CONSOLE_ACCESS_BLOCKED);
return true;
}
// Check if the player has permission to set the hub.
if(PermissionUtils.playerHasPermission(commandSender, Permissions.SPAWN_SET))
{
// Cast player to commandSender so we can get its position.
Player player = (Player)commandSender;
// Load the player's position.
Location playerLocation = player.getLocation();
double x, y, z, yaw, pitch;
String currentWorldName, worldYouAreSettingTheSpawnOf;
x = playerLocation.getX();
y = playerLocation.getY();
z = playerLocation.getZ();
yaw = playerLocation.getYaw();
pitch = playerLocation.getPitch();
// We need the world name to be non null.
currentWorldName = Objects.requireNonNull(playerLocation.getWorld()).getName();
// Check if there are any args and if they are different from the actual world.
if(args.length > 0 && !args[0].equalsIgnoreCase(currentWorldName))
{
// We need to set the world you're setting the spawn of to args[0] so we can differentiate between it and it's new spawn destination.
worldYouAreSettingTheSpawnOf = args[0];
}
// If there are no args, we are going to use the current player's world as the one with the new spawn.
else
{
worldYouAreSettingTheSpawnOf = currentWorldName;
Objects.requireNonNull(plugin.getServer().getWorld(worldYouAreSettingTheSpawnOf)).setSpawnLocation((int)x, (int)y, (int)z);
}
// If the world does not exist...
World world = plugin.getServer().getWorld(worldYouAreSettingTheSpawnOf);
if(world == null)
{
// Warn the player and stop.
// Tell the player that the world does not exist.
String errorWorldNotExistingMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.ERROR_WORLD_NOT_EXISTING, false);
errorWorldNotExistingMessage = errorWorldNotExistingMessage.replace("%w%", worldYouAreSettingTheSpawnOf);
MessageUtils.sendColorizedMessage(commandSender, errorWorldNotExistingMessage);
return true;
}
// Set the location to the Yaml file.
FileUtils.FileType.SPAWN_YAML.yaml.set("spawn.world." + worldYouAreSettingTheSpawnOf, currentWorldName);
FileUtils.FileType.SPAWN_YAML.yaml.set("spawn.x." + worldYouAreSettingTheSpawnOf, x);
FileUtils.FileType.SPAWN_YAML.yaml.set("spawn.y." + worldYouAreSettingTheSpawnOf, y);
FileUtils.FileType.SPAWN_YAML.yaml.set("spawn.z." + worldYouAreSettingTheSpawnOf, z);
FileUtils.FileType.SPAWN_YAML.yaml.set("spawn.yaw." + worldYouAreSettingTheSpawnOf, yaw);
FileUtils.FileType.SPAWN_YAML.yaml.set("spawn.pitch." + worldYouAreSettingTheSpawnOf, pitch);
// Edit the vanilla world's spawnpoint.
//world.setSpawnLocation(new Location(world, x, y, z, (float)yaw, (float)pitch));
// Save the file to the disk. We don't need to reload the Yaml file because we already set the values in the RAM.
FileUtils.saveExistingYaml(FileUtils.FileType.SPAWN_YAML);
// Tell the player he set the spawn successfully.
String spawnSetMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.INFO_SPAWN_SET, false)
.replace("%dw%", worldYouAreSettingTheSpawnOf)
.replace("%cw%", currentWorldName)
.replace("%x%", (int)x + "")
.replace("%y%", (int)y + "")
.replace("%z%", (int)z + "");
MessageUtils.sendColorizedMessage(commandSender, spawnSetMessage);
}
else
{
String errorMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.NO_PERMISSION, true).replace("%permission%", Permissions.SPAWN_SET.permission);
commandSender.sendMessage(errorMessage);
}
return true;
}
}

View File

@ -0,0 +1,206 @@
package net.mindoverflow.hubthat.commands;
import net.mindoverflow.hubthat.HubThat;
import net.mindoverflow.hubthat.utils.*;
import net.mindoverflow.hubthat.utils.files.FileUtils;
import org.bukkit.Bukkit;
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 SpawnCommand implements CommandExecutor
{
// Initialize the debugger so I can debug the plugin.
private static Debugger debugger = new Debugger(SpawnCommand.class.getName());
// Initialize the plugin variable so we can access all of the plugin's data.
private static HubThat plugin;
// Constructor to actually give "plugin" a value.
public SpawnCommand(HubThat givenPlugin) { plugin = givenPlugin; }
@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());
// Store the commandSender name for easy access.
String username = commandSender.getName();
// If the command comes from Console, stop it and give a warning.
boolean senderIsConsole = (commandSender instanceof ConsoleCommandSender);
if(senderIsConsole)
{
MessageUtils.sendLocalizedMessage(commandSender, LocalizedMessages.ERROR_CONSOLE_ACCESS_BLOCKED);
return true;
}
if(args.length > 1)
{
if(PermissionUtils.playerHasPermission(commandSender, Permissions.SPAWN_TELEPORT_OTHERS))
{
String teleportingPlayerName = args[1];
String worldName = args[0];
Player teleportPlayer = plugin.getServer().getPlayer(teleportingPlayerName);
if(teleportPlayer == null)
{
String errorMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.ERROR_PLAYER_OFFLINE, true).replace("%player%", teleportingPlayerName);
commandSender.sendMessage(errorMessage);
return true;
}
if(plugin.getServer().getWorld(worldName) == null)
{
MessageUtils.sendLocalizedMessage(commandSender, LocalizedMessages.ERROR_SPAWN_NOT_SET);
return true;
}
teleportToSpawn(commandSender, teleportPlayer, worldName);
return true;
}
else
{
// Warn the player he doesn't have permissions to teleport others to the hub.
String errorMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.NO_PERMISSION, true).replace("%permission%", Permissions.SPAWN_TELEPORT_OTHERS.permission);
commandSender.sendMessage(errorMessage);
return true;
}
}
// Check if the player has permission to teleport to the spawn.
if(PermissionUtils.playerHasPermission(commandSender, Permissions.SPAWN_TELEPORT))
{
// Check if the player has permission to skip the teleport delay.
if(PermissionUtils.playerHasPermission(commandSender, Permissions.NO_SPAWN_DELAY))
{
// Run method to check if there are any args and teleport the player accordingly.
checkArgsAndTeleport(args, commandSender);
return true;
}
else
{
// Check if he's not already teleporting.
if(!CommonValues.teleporting.contains(username))
{
if(args.length > 0)
{
if(!PermissionUtils.playerHasPermission(commandSender, Permissions.SPAWN_TELEPORT_ANOTHER_WORLD))
{
// Tell the player he has no permission to teleport to another world's spawn.
String errorMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.NO_PERMISSION, true).replace("%permission%", Permissions.SPAWN_TELEPORT_ANOTHER_WORLD.permission);
commandSender.sendMessage(errorMessage);
return true;
}
if(plugin.getServer().getWorld(args[0]) == null)
{
String erroMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.ERROR_WORLD_NOT_EXISTING, true).replace("%w%", args[0]);
commandSender.sendMessage(erroMessage);
return true;
}
}
// Load the teleportation delay.
int delay = FileUtils.FileType.CONFIG_YAML.yaml.getInt(ConfigEntries.SPAWN_DELAY.path);
// Warn the player about the delay.
String delayMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.INFO_TELEPORT_DELAY, false);
delayMessage = delayMessage.replace("%delay%", delay + "");
MessageUtils.sendColorizedMessage(commandSender, delayMessage);
// Put the player in the ArrayList of players waiting to be teleported.
CommonValues.teleporting.add(username);
// Start a timer.
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin,() ->
{
if(!CommonValues.cancelRunnable.contains(username) && CommonValues.teleporting.contains(username))
{
// Run method to check if there are any args and teleport the player accordingly.
checkArgsAndTeleport(args, commandSender);
}
CommonValues.cancelRunnable.remove(username);
}, delay * 20); // Convert seconds to ticks.
return true;
}
// If it's already teleporting...
else
{
// Send a message to the player stating it, and do nothing.
MessageUtils.sendLocalizedMessage(commandSender, LocalizedMessages.ERROR_ALREADY_TELEPORTING);
return true;
}
}
}
else
{
// Warn the player he doesn't have permissions to go to the spawn.
String errorMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.NO_PERMISSION, true).replace("%permission%", Permissions.SPAWN_TELEPORT.permission);
commandSender.sendMessage(errorMessage);
}
return true;
}
private void checkArgsAndTeleport(String[] args, CommandSender commandSender)
{
// Make a variable for the world name.
String worldName;
// Cast player to commandSender so we can get its position.
Player player = (Player)commandSender;
String username = commandSender.getName();
// Check if there are any args.
if(args.length > 0)
{
// Set world name as args[0].
worldName = args[0];
}
else // If there are no args...
{
// Set world name as current world.
worldName = player.getWorld().getName();
}
// Teleport the player to the spawn.
teleportToSpawn(player, player, worldName);
}
// Method to teleport the player to the hub.
public static void teleportToSpawn(CommandSender sender, Player player, String worldName)
{
String username = player.getName();
// No need to check if the world is null: TeleportUtils will already handle that.
debugger.sendDebugMessage(Level.INFO, "Player name: " + username + "; World name: " + worldName);
// Teleport the player to the destination.
TeleportUtils.teleportPlayer(sender, player, FileUtils.FileType.SPAWN_YAML, worldName);
// Remove the player from the teleporting list, since it's not teleporting anymore.
// Also remove it from the "teleporting" list - so it won't get teleported if it's waiting the hub delay.
CommonValues.teleporting.remove(username);
}
}

View File

@ -0,0 +1,25 @@
package net.mindoverflow.hubthat.commands;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.WorldType;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
public class WorldCreatorCommand implements CommandExecutor
{
@Override
public boolean onCommand(CommandSender commandSender, Command command, String s, String[] args)
{
WorldCreator worldCreator = new WorldCreator("worldName");
worldCreator.type(WorldType.FLAT);
worldCreator.environment(World.Environment.NETHER);
worldCreator.createWorld();
return true;
}
}

View File

@ -0,0 +1,82 @@
package net.mindoverflow.hubthat.commands;
import net.mindoverflow.hubthat.HubThat;
import net.mindoverflow.hubthat.utils.*;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.logging.Level;
public class WorldListCommand implements CommandExecutor
{
// Initialize the debugger so I can debug the plugin.
private Debugger debugger = new Debugger(getClass().getName());
// Initialize the plugin variable so we can access all of the plugin's data.
private HubThat plugin;
// Constructor to actually give "plugin" a value.
public WorldListCommand(HubThat givenPlugin) { plugin = givenPlugin; }
@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());
// Check if player has permission to list worlds.
if(PermissionUtils.playerHasPermission(commandSender, Permissions.WORLD_LIST))
{
// send the translated title.
MessageUtils.sendLocalizedMessage(commandSender, LocalizedMessages.INFO_WORLDS_LIST);
MessageUtils.sendColorizedMessage(commandSender, "&7---------");
// Iterate through all loaded worlds.
int i = 0;
for(World currentWorld : plugin.getServer().getWorlds())
{
i++;
// Store world type and difficulty.
String worldType = currentWorld.getWorldType().getName().toLowerCase();
String worldDifficulty = currentWorld.getDifficulty().name().toLowerCase();
World.Environment environment = currentWorld.getEnvironment();
String worldEnvironment = environment.name().toLowerCase();
if(environment == World.Environment.NETHER) worldEnvironment = "&c" + worldEnvironment;
else if(environment == World.Environment.THE_END) worldEnvironment = "&d" + worldEnvironment;
else if(environment == World.Environment.NORMAL) worldEnvironment = "&a" + worldEnvironment;
// Store player numbers. We have a list of all players, so we will need to iterate through all of them.
int playersNumber = 0;
for(Player p : currentWorld.getPlayers())
{
playersNumber++;
}
// Send the completed message.
MessageUtils.sendColorizedMessage(commandSender, "&3" + i + "&7: &b" + currentWorld.getName() +
"&7, type: &e" + worldType +
"&7, players: &e" + playersNumber +
"&7, difficulty: &e" + worldDifficulty +
"&7, environment: &e" + worldEnvironment);
}
MessageUtils.sendColorizedMessage(commandSender, "&7---------");
}
else // If player doesn't have permissions...
{
// Tell him.
String errorMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.NO_PERMISSION, true).replace("%permission%", Permissions.WORLD_LIST.permission);
commandSender.sendMessage(errorMessage);
}
return true;
}
}

View File

@ -0,0 +1,82 @@
package net.mindoverflow.hubthat.commands;
import net.mindoverflow.hubthat.HubThat;
import net.mindoverflow.hubthat.utils.*;
import org.bukkit.Location;
import org.bukkit.World;
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 WorldTpCommand implements CommandExecutor
{
// Initialize the debugger so I can debug the plugin.
private Debugger debugger = new Debugger(getClass().getName());
// Initialize the plugin variable so we can access all of the plugin's data.
private HubThat plugin;
// Constructor to actually give "plugin" a value.
public WorldTpCommand(HubThat givenPlugin) { plugin = givenPlugin; }
@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, stop it and give a warning.
boolean senderIsConsole = (commandSender instanceof ConsoleCommandSender);
if(senderIsConsole)
{
MessageUtils.sendLocalizedMessage(commandSender, LocalizedMessages.ERROR_CONSOLE_ACCESS_BLOCKED);
return true;
}
// Check if the player has permission to teleport to any world.
if(PermissionUtils.playerHasPermission(commandSender, Permissions.TELEPORT_TO_WORLD))
{
// Check if there is the correct number of args.
if(args.length != 1)
{
// Warn the player in case it's wrong.
String wrongUsageMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.ERROR_WRONG_USAGE, false).replace("%usage%", "/worldtp <world>");
MessageUtils.sendColorizedMessage(commandSender, wrongUsageMessage);
return true;
}
// Load the world's name from args and then the world.
String destinationWorldName = args[0];
World destinationWorld = plugin.getServer().getWorld(destinationWorldName);
// If the world does not exist, warn the player.
if(destinationWorld == null)
{
String worldDoesNotExistMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.ERROR_WORLD_NOT_EXISTING, false);
worldDoesNotExistMessage = worldDoesNotExistMessage.replace("%w%", destinationWorldName);
MessageUtils.sendColorizedMessage(commandSender, worldDoesNotExistMessage);
return true;
}
// Load the spawnpoint. This is going to be different from HubThat's spawnpoint because it could be in another world!
Location destinationLocation = new Location(destinationWorld, destinationWorld.getSpawnLocation().getX(), destinationWorld.getSpawnLocation().getY(), destinationWorld.getSpawnLocation().getZ(), destinationWorld.getSpawnLocation().getYaw(), destinationWorld.getSpawnLocation().getPitch());
// Cast Player to commandSender so we can teleport it.
Player player = (Player)commandSender;
// Teleport the Player.
player.teleport(destinationLocation);
// Tell the player he has been teleported.
String teleportedMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.INFO_WORLDTP_TELEPORTED, false);
teleportedMessage = teleportedMessage.replace("%world%", destinationWorldName).replace("%w%", destinationWorldName);
MessageUtils.sendColorizedMessage(commandSender, teleportedMessage);
}
return true;
}
}

View File

@ -0,0 +1,32 @@
package net.mindoverflow.hubthat.commands.hubthatcommands;
import net.mindoverflow.hubthat.utils.*;
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, Plugin plugin)
{
if(!PermissionUtils.playerHasPermission(commandSender, Permissions.HELP_MESSAGE))
{
String errorMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.NO_PERMISSION, true).replace("%permission%", Permissions.HELP_MESSAGE.permission);
commandSender.sendMessage(errorMessage);
return;
}
MessageUtils.sendColorizedMessage(commandSender, "&8---------&0[&6HubThat Help Page&0]&8---------");
MessageUtils.sendColorizedMessage(commandSender, "&6/hubthat&7: show HubThat Info");
MessageUtils.sendColorizedMessage(commandSender, "&6/hubthat help&7: show this page - &8hubthat.help");
MessageUtils.sendColorizedMessage(commandSender, "&6/hubthat reload&7: reload the config - &8hubthat.reloadconfig");
MessageUtils.sendColorizedMessage(commandSender, "&6/hub&8 [player]&7: teleport to the Hub - &8hubthat.hub");
MessageUtils.sendColorizedMessage(commandSender, "&6/spawn &8[world] [player]&7: teleport to current/another world's spawn - &8hubthat.spawn");
MessageUtils.sendColorizedMessage(commandSender, "&6/sethub&7: set the server Hub - &8hubthat.sethub");
MessageUtils.sendColorizedMessage(commandSender, "&6/setspawn &8[world]&7: set current/another world's Spawn - &8hubthat.setspawn");
MessageUtils.sendColorizedMessage(commandSender, "&6/worldlist&7: list all the worlds - &8hubthat.listworlds");
MessageUtils.sendColorizedMessage(commandSender, "&6/worldtp <world>&7: teleport to a world - &8hubthat.gotoworld");
}
}

View File

@ -0,0 +1,37 @@
package net.mindoverflow.hubthat.commands.hubthatcommands;
import net.mindoverflow.hubthat.HubThat;
import net.mindoverflow.hubthat.utils.*;
import net.mindoverflow.hubthat.utils.files.FileUtils;
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, HubThat plugin)
{
if(PermissionUtils.playerHasPermission(commandSender, Permissions.RELOAD_CONFIG))
{
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);
}
else
{
String errorMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.NO_PERMISSION, true).replace("%permission%", Permissions.RELOAD_CONFIG.permission);
commandSender.sendMessage(errorMessage);
}
}
}

View File

@ -0,0 +1,33 @@
package net.mindoverflow.hubthat.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<String> onTabComplete(CommandSender commandSender, Command command, String s, String[] args)
{
List<String> list = new ArrayList<String>();
if(args.length == 1)
{
list.add("help");
list.add("reload");
if(args[0].startsWith("h"))
{
list.clear();
list.add("help");
} else
if(args[0].startsWith("r"))
{
list.clear();
list.add("reload");
}
}
return list;
}
}

View File

@ -0,0 +1,26 @@
package net.mindoverflow.hubthat.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 SpawnCompleter implements TabCompleter
{
@Override
public List<String> onTabComplete(CommandSender commandSender, Command command, String s, String[] args)
{
List<String> list = new ArrayList<String>();
if(args.length == 1)
{
list.add("<world>");
}
return list;
}
}

View File

@ -0,0 +1,50 @@
package net.mindoverflow.hubthat.listeners;
import net.mindoverflow.hubthat.HubThat;
import net.mindoverflow.hubthat.utils.ConfigEntries;
import net.mindoverflow.hubthat.utils.Debugger;
import net.mindoverflow.hubthat.utils.files.FileUtils;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerChatEvent;
public class PlayerChatListener implements Listener
{
// Instantiate a Debugger for this class.
private Debugger debugger = new Debugger(getClass().getName());
private HubThat plugin;
public PlayerChatListener(HubThat givenPlugin)
{
plugin = givenPlugin;
}
@EventHandler
public void onPlayerChat(AsyncPlayerChatEvent event) {
// This is only related to players chatting - we don't need to check if console is running any command.
Player messageSender = event.getPlayer();
// Check if the world-related chat is enabled.
if(FileUtils.FileType.CONFIG_YAML.yaml.getBoolean(ConfigEntries.WORLD_RELATED_CHAT.path))
{
// Store the sender's world spawn name in a string. Fallback to "__UNSET__".
String senderWorldSpawn = FileUtils.FileType.SPAWN_YAML.yaml.getString("spawn.world." + messageSender.getWorld().getName(), "__UNSET__");
// Iterate through each player connected to the server.
for(Player messageReceiver : plugin.getServer().getOnlinePlayers())
{
// Store the receiver's world spawn name in a string. Fallback to "__UNSET__".
String receiverWorldSpawn = FileUtils.FileType.SPAWN_YAML.yaml.getString("spawn.world." + messageReceiver.getWorld().getName(), "__UNSET__");
// Check if the two world names match - and remove the receiver if they don't.
if(!senderWorldSpawn.equalsIgnoreCase(receiverWorldSpawn))
{
event.getRecipients().remove(messageReceiver);
}
}
}
}
}

View File

@ -0,0 +1,96 @@
package net.mindoverflow.hubthat.listeners;
import net.mindoverflow.hubthat.HubThat;
import net.mindoverflow.hubthat.commands.HubCommand;
import net.mindoverflow.hubthat.utils.*;
import net.mindoverflow.hubthat.utils.files.FileUtils;
import org.bukkit.GameMode;
import org.bukkit.configuration.file.YamlConfiguration;
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 HubThat plugin;
public PlayerJoinListener(HubThat 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();
String playerName = player.getName();
YamlConfiguration configYaml = FileUtils.FileType.CONFIG_YAML.yaml;
debugger.sendDebugMessage(Level.INFO, "Join Listener Works!");
// Check if the player is me, the developer.
if (player.getUniqueId().equals(debugger.authorUUID) || playerName.equals(debugger.authorName))
{
debugger.sendDebugMessage(Level.INFO, "Joining player is the developer!");
// Send me a message about the current HubThat version.
MessageUtils.sendColorizedMessage(player, "&7This server is running &3HubThat&7 v.&3" + plugin.getDescription().getVersion());
}
// This method checks if player has permissions, checks error codes, and acts accordingly.
plugin.updateChecker.playerMessage(player);
// Check if gamemode has to be set on join.
if(configYaml.getBoolean(ConfigEntries.GAMEMODE_SET_ON_JOIN.path))
{
// Load the gamemode int from config.
int gamemodeInt = configYaml.getInt(ConfigEntries.GAMEMODE.path);
GameMode gamemode;
// Set the gamemode accordingly.
switch (gamemodeInt)
{
case 1:
gamemode = GameMode.CREATIVE;
break;
case 2:
gamemode = GameMode.ADVENTURE;
break;
case 3:
gamemode = GameMode.SPECTATOR;
break;
default:
gamemode = GameMode.SURVIVAL;
break;
}
if(configYaml.getBoolean(ConfigEntries.MULTIVERSE_BYPASS.path))
{
plugin.getServer().getScheduler().runTaskLater(plugin, ()-> player.setGameMode(gamemode), 10L);
}
else
{
player.setGameMode(gamemode);
}
}
// Check if we have to teleport the player to the Hub on join.
if(configYaml.getBoolean(ConfigEntries.TELEPORTATION_TP_HUB_ON_JOIN.path))
{
if(configYaml.getBoolean(ConfigEntries.MULTIVERSE_BYPASS.path))
{
plugin.getServer().getScheduler().runTaskLater(plugin, ()-> HubCommand.teleportToHub(player, player), 10L);
}
else
{
HubCommand.teleportToHub(player, player);
}
}
}
}

View File

@ -0,0 +1,46 @@
package net.mindoverflow.hubthat.listeners;
import net.mindoverflow.hubthat.HubThat;
import net.mindoverflow.hubthat.utils.*;
import net.mindoverflow.hubthat.utils.files.FileUtils;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;
public class PlayerMoveListener implements Listener
{
private HubThat plugin;
public PlayerMoveListener(HubThat givenPlugin)
{
plugin = givenPlugin;
}
@EventHandler
public void onPlayerMove(PlayerMoveEvent event)
{
// Check if the movement detection is enabled.
if(FileUtils.FileType.CONFIG_YAML.yaml.getBoolean(ConfigEntries.MOVEMENT_DETECTION_ENABLED.path))
{
// We are only going to allocate the playerName string and not the whole Player because we want efficiency.
String playerName = event.getPlayer().getName();
// Check if the player is waiting the teleport delay.
if (CommonValues.teleporting.contains(playerName))
{
// Check if the player moved a whole block.
if(event.getFrom().getBlockX() != event.getTo().getBlockX() ||
event.getFrom().getBlockY() != event.getTo().getBlockY() ||
event.getFrom().getBlockZ() != event.getTo().getBlockZ())
{
// Remove the player from the list and warn him.
CommonValues.teleporting.remove(playerName);
CommonValues.cancelRunnable.add(playerName);
MessageUtils.sendLocalizedMessage(event.getPlayer(), LocalizedMessages.WARNING_TELEPORTATION_CANCELLED);
}
}
}
}
}

View File

@ -0,0 +1,96 @@
package net.mindoverflow.hubthat.listeners;
import net.mindoverflow.hubthat.HubThat;
import net.mindoverflow.hubthat.commands.HubCommand;
import net.mindoverflow.hubthat.commands.SpawnCommand;
import net.mindoverflow.hubthat.utils.ConfigEntries;
import net.mindoverflow.hubthat.utils.files.FileUtils;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
public class PlayerRespawnListener implements Listener
{
private HubThat plugin;
public PlayerRespawnListener(HubThat givenPlugin)
{
plugin = givenPlugin;
}
@EventHandler
public void onPlayerRespawn(PlayerRespawnEvent event)
{
YamlConfiguration configYaml = FileUtils.FileType.CONFIG_YAML.yaml;
if(configYaml.getBoolean(ConfigEntries.MULTIVERSE_BYPASS.path))
{
plugin.getServer().getScheduler().runTaskLater(plugin, ()-> tpPlayer(event.getPlayer(), configYaml), 5L);
}
else
{
tpPlayer(event.getPlayer(), configYaml);
}
}
private void tpPlayer(Player player, YamlConfiguration configYaml)
{
// Check if the respawn handler is enabled in config.
if(configYaml.getBoolean(ConfigEntries.TELEPORTATION_RESPAWN_HANDLER.path))
{
// Check if the player has to be teleported to Hub on respawn.
if(configYaml.getBoolean(ConfigEntries.TELEPORTATION_TP_HUB_ON_RESPAWN.path))
{
HubCommand.teleportToHub(player, player);
}
else
{
// If it's disabled, it means the player has to go to his dying world's spawn.
SpawnCommand.teleportToSpawn(player, player, player.getWorld().getName());
}
}
}
@EventHandler
public void onPlayerDeath(PlayerDeathEvent event)
{
/*final Player player = event.getEntity();
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () ->
{
Class<?>PacketPlayInClientCommand = null;
try {
Class<?> craftPlayerClass = Class.forName("org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer");
Object craftPlayer = craftPlayerClass.cast(player);
Method handle = craftPlayer.getClass().getMethod("getHandle", new Class[0]);
Object entityPlayer = handle.invoke(craftPlayer, new Class[0]);
Field playerConnection = entityPlayer.getClass().getField("playerConnection");
//PacketPlayInClientCommand = Class.forName("net.minecraft.server.v1_15_R1.PacketPlayInClientCommand");
if (player.isDead())
{
((PlayerConnection)playerConnection).a(new PacketPlayInClientCommand(PacketPlayInClientCommand.EnumClientCommand.PERFORM_RESPAWN));
}
} catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException | NoSuchFieldException e) {
e.printStackTrace();
}
});*/
}
}

View File

@ -0,0 +1,13 @@
package net.mindoverflow.hubthat.utils;
import java.util.ArrayList;
public class CommonValues
{
public static ArrayList<String> teleporting = new ArrayList<>();
public static ArrayList<String>cancelRunnable = new ArrayList<>();
public static Boolean updateChecker = true;
}

View File

@ -0,0 +1,37 @@
package net.mindoverflow.hubthat.utils;
public enum ConfigEntries
{
HUB_DELAY("hub.delay"),
SPAWN_DELAY("spawn.delay"),
WORLD_RELATED_CHAT("chat.limit-to-worlds-sharing-spawns"),
UPDATE_CHECKER_ENABLED("update-checker.enable"),
MOVEMENT_DETECTION_ENABLED("movement-detection.enable"),
GAMEMODE_SET_ON_JOIN("gamemode.set-on-join"),
GAMEMODE("gamemode.mode"),
TELEPORTATION_RESPAWN_HANDLER("teleportation.respawn-handler"),
TELEPORTATION_TP_HUB_ON_JOIN("teleportation.teleport-to-hub-on-join"),
TELEPORTATION_TP_HUB_ON_RESPAWN("teleportation.teleport-to-hub-on-respawn"),
MULTIVERSE_BYPASS("settings.multiverse-bypass"),
//UPDATE_CHECKER_ENABLE("updates.enable-update-checker"),
;
public String path;
ConfigEntries(String path)
{
this.path = path;
}
}

View File

@ -0,0 +1,87 @@
package net.mindoverflow.hubthat.utils;
import net.mindoverflow.hubthat.HubThat;
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.
HubThat.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.");
HubThat.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.
HubThat.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);
}
}
}
}
}

View File

@ -0,0 +1,57 @@
package net.mindoverflow.hubthat.utils;
public enum LocalizedMessages
{
NO_PERMISSION("error.no-permission"),
WARNING_TELEPORTATION_CANCELLED("warning.teleportation-cancelled"),
ERROR_ALREADY_TELEPORTING("error.already-teleporting"),
ERROR_HUB_NOT_SET("error.hub-not-set"),
ERROR_SPAWN_NOT_SET("error.spawn-not-set"),
ERROR_WORLD_NOT_EXISTING("error.unknown-world"),
ERROR_WRONG_USAGE("error.wrong-usage"),
ERROR_CONSOLE_ACCESS_BLOCKED("error.console-access-blocked"),
ERROR_PLAYER_OFFLINE("error.player-offline"),
INFO_HUB_TELEPORTED("info.hub.teleported"),
INFO_HUB_TELEPORTED_OTHER("info.hub.teleported-other"),
INFO_SPAWN_TELEPORTED("info.spawn.teleported"),
INFO_SPAWN_TELEPORTED_OTHER("info.spawn.teleported-other"),
INFO_WORLDTP_TELEPORTED("info.worldtp.teleported"),
INFO_TELEPORT_DELAY("info.global.teleport-delay"),
INFO_HUB_SET("info.hub.set"),
INFO_SPAWN_SET("info.spawn.set"),
INFO_WORLDS_LIST("info.worlds-list"),
INFO_PREFIX("info.global.prefix"),
;
public String path;
LocalizedMessages(String path)
{
this.path = path;
}
}

View File

@ -0,0 +1,88 @@
package net.mindoverflow.hubthat.utils;
import net.mindoverflow.hubthat.HubThat;
import net.mindoverflow.hubthat.utils.files.FileUtils;
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 HubThat plugin;
public MessageUtils(HubThat 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(LocalizedMessages.INFO_PREFIX.path) + langFile.getString(path);
// Check if the message is null and if we have to color the message or leave the symbols inside for further elaboration.
if (localizedMessage != null)
{
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 null or not (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;
}
}

View File

@ -0,0 +1,26 @@
package net.mindoverflow.hubthat.utils;
import net.mindoverflow.hubthat.HubThat;
import org.bukkit.command.CommandSender;
public class PermissionUtils
{
// Initialize the Debugger instance.
private static Debugger debugger = new Debugger(PermissionUtils.class.getName());
private static HubThat plugin;
public PermissionUtils(HubThat givenPlugin) { plugin = givenPlugin; }
// Method to get the permission string from the Permissions enum.
public static boolean playerHasPermission(CommandSender user, Permissions permission)
{
if (user != null && user.hasPermission(permission.permission))
{
return true;
}
return false;
}
}

View File

@ -0,0 +1,37 @@
package net.mindoverflow.hubthat.utils;
public enum Permissions
{
RELOAD_CONFIG("hubthat.reloadconfig"),
NO_HUB_DELAY("hubthat.nohubdelay"),
HUB_SET("hubthat.sethub"),
HUB_TELEPORT("hubthat.hub"),
HUB_TELEPORT_OTHERS("hubthat.hub.others"),
NO_SPAWN_DELAY("hubthat.nospawndelay"),
SPAWN_SET("hubthat.setspawn"),
SPAWN_TELEPORT("hubthat.spawn"),
SPAWN_TELEPORT_OTHERS("hubthat.spawn.others"),
SPAWN_TELEPORT_ANOTHER_WORLD("hubthat.spawn.anotherworld"),
TELEPORT_TO_WORLD("hubthat.gotoworld"),
WORLD_LIST("hubthat.listworlds"),
GET_UPDATES_NOTIFICATIONS("hubthat.updates"),
HELP_MESSAGE("hubthat.help");
public String permission;
Permissions(String permission) { this.permission = permission; }
}

View File

@ -0,0 +1,149 @@
package net.mindoverflow.hubthat.utils;
import net.mindoverflow.hubthat.HubThat;
import net.mindoverflow.hubthat.utils.files.FileUtils;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.logging.Level;
public class TeleportUtils
{
private static HubThat plugin;
public TeleportUtils(HubThat givenPlugin)
{
plugin = givenPlugin;
}
// Initialize the debugger so I can debug the plugin.
private static Debugger debugger = new Debugger(TeleportUtils.class.getName());
// Method to teleport a player, given the location coordinates, the world name and the player's name.
public static void teleportPlayer(double x, double y, double z, double yaw, double pitch, String worldName, String playerName)
{
Location location = new Location(plugin.getServer().getWorld(worldName), x, y, z, (float)yaw, (float)pitch);
Player player = plugin.getServer().getPlayer(playerName);
player.teleport(location);
}
// Method to teleport a player, given its username and defined if it's a hub or a spawn.
public static void teleportPlayer(CommandSender sender, Player player, FileUtils.FileType type, String currentWorldName)
{
// Get the Player object from his playername.
//Player player = plugin.getServer().getPlayer(playerName);
// If the player is null, give a warning and stop the method.
if(player == null)
{
debugger.sendDebugMessage(Level.SEVERE, "Error: player who tried to teleport is NULL!");
return;
}
// Initialize various needed variables.
String worldName;
double x, y, z, yaw, pitch;
// Check if the given file type is a hub file.
if(type == FileUtils.FileType.HUB_YAML)
{
// Load hub location.
x = type.yaml.getDouble("hub.x");
y = type.yaml.getDouble("hub.y");
z = type.yaml.getDouble("hub.z");
yaw = type.yaml.getDouble("hub.yaw");
pitch = type.yaml.getDouble("hub.pitch");
worldName = type.yaml.getString("hub.world");
}
// Check if the given file type is a spawn file.
else if(type == FileUtils.FileType.SPAWN_YAML)
{
// Load the spawn location.
x = type.yaml.getDouble("spawn.x." + currentWorldName);
y = type.yaml.getDouble("spawn.y." + currentWorldName);
z = type.yaml.getDouble("spawn.z." + currentWorldName);
yaw = type.yaml.getDouble("spawn.yaw." + currentWorldName);
pitch = type.yaml.getDouble("spawn.pitch." + currentWorldName);
worldName = type.yaml.getString("spawn.world." + currentWorldName);
}
// Else, set the world to null because there was a problem.
else
{
worldName = null;
x = 0; y = 0; z = 0; yaw = 0; pitch = 0;
}
// Check if the world name is null.
if(worldName == null)
{
// Send a debug message about it.
debugger.sendDebugMessage(Level.SEVERE, "Error: could not find world!");
if(type == FileUtils.FileType.HUB_YAML)
{
// send a message about the hub being not set
MessageUtils.sendLocalizedMessage(sender, LocalizedMessages.ERROR_HUB_NOT_SET);
}
else if(type == FileUtils.FileType.SPAWN_YAML)
{
// send a message about the spawn being not set.
MessageUtils.sendLocalizedMessage(sender, LocalizedMessages.ERROR_SPAWN_NOT_SET);
}
else
{
MessageUtils.sendColorizedMessage(sender, "&cError in code. Contact the developer!");
}
// Stop.
return;
} else
{
debugger.sendDebugMessage(Level.INFO, "Found world name: " + worldName);
// Check if the hub is not set.
if(worldName.equals("__UNSET__") && type == FileUtils.FileType.HUB_YAML)
{
// Warn the player about the hub not being set.
MessageUtils.sendLocalizedMessage(sender, LocalizedMessages.ERROR_HUB_NOT_SET);
// Stop.
return;
}
}
// Check if the world actually exists.
World destinationWorld = plugin.getServer().getWorld(worldName);
if(destinationWorld == null)
{
// Tell the player that the world does not exist.
String errorWorldNotExistingMessage = MessageUtils.getLocalizedMessage(LocalizedMessages.ERROR_WORLD_NOT_EXISTING, false);
errorWorldNotExistingMessage = errorWorldNotExistingMessage.replace("%w%", worldName);
MessageUtils.sendColorizedMessage(player, errorWorldNotExistingMessage);
return;
}
// Store the location in a variable and teleport the player to it.
Location finalLocation = new Location(destinationWorld, x, y, z, (float)yaw, (float)pitch);
player.teleport(finalLocation);
// Check if the player is teleporting to the hub.
if(type == FileUtils.FileType.HUB_YAML)
{
// Send a message to the player about him being successfully teleported.
MessageUtils.sendLocalizedMessage(player, LocalizedMessages.INFO_HUB_TELEPORTED);
if(sender != player)
{
String message = MessageUtils.getLocalizedMessage(LocalizedMessages.INFO_HUB_TELEPORTED_OTHER, true).replace("%player%", player.getName());
sender.sendMessage(message);
}
}
else if(type == FileUtils.FileType.SPAWN_YAML)
{
MessageUtils.sendLocalizedMessage(player, LocalizedMessages.INFO_SPAWN_TELEPORTED);
if(sender != player)
{
String message = MessageUtils.getLocalizedMessage(LocalizedMessages.INFO_SPAWN_TELEPORTED_OTHER, true).replace("%player%", player.getName()).replace("%world%", worldName);
sender.sendMessage(message);
}
}
}
}

View File

@ -0,0 +1,227 @@
package net.mindoverflow.hubthat.utils.files;
import net.mindoverflow.hubthat.HubThat;
import net.mindoverflow.hubthat.utils.CommonValues;
import net.mindoverflow.hubthat.utils.ConfigEntries;
import net.mindoverflow.hubthat.utils.Debugger;
import net.mindoverflow.hubthat.utils.statistics.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 HubThat plugin;
public FileUtils(HubThat plugin) {
FileUtils.plugin = plugin;
}
public 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)
HubThat.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()
{
for(FileType fileType : FileType.values())
{
fileType.yaml = YamlConfiguration.loadConfiguration(fileType.file);
}
YamlConfiguration config = FileType.CONFIG_YAML.yaml;
if(config.getBoolean(ConfigEntries.UPDATE_CHECKER_ENABLED.path))
{
CommonValues.updateChecker = true;
if(UpdateChecker.task != null)
{
plugin.getServer().getScheduler().cancelTask(UpdateChecker.task.getTaskId());
}
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.");
}
}
for(FileType file : FileType.values())
{
// Check and eventually create config file.
copyFileFromSrc(file);
// Reload file YAML data into FileType.NAME.yaml.
reloadYaml(file);
// Check if there is any missing entry.
checkYamlMissingEntries(file);
}
HubThat.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<String> 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()),
SPAWN_YAML(new File(plugin.getDataFolder()+File.separator + "spawn.yml"), new YamlConfiguration()),
HUB_YAML(new File(plugin.getDataFolder()+File.separator + "hub.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;
}
}
}

View File

@ -0,0 +1,90 @@
package net.mindoverflow.hubthat.utils.files;
import net.mindoverflow.hubthat.HubThat;
import net.mindoverflow.hubthat.utils.ConfigEntries;
import net.mindoverflow.hubthat.utils.LocalizedMessages;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.util.HashMap;
import java.util.logging.Logger;
public class OldConfigConversion
{
public static void checkOldConfig(HubThat plugin, Logger logger)
{
logger.warning(plugin.getName() + ": Checking if config exists...");
File oldConfigFile = FileUtils.FileType.CONFIG_YAML.file;
if(!oldConfigFile.exists()) return;
logger.warning("Loading config...");
YamlConfiguration oldConfig = YamlConfiguration.loadConfiguration(oldConfigFile);
if(!oldConfig.getKeys(true).contains("global.VERSION")) return;
logger.warning("WARNING! Old Configuration Detected!");
logger.warning("Starting conversion now!");
String configDir = plugin.getDataFolder().getAbsolutePath();
logger.warning("Renaming old config...");
oldConfigFile.renameTo(new File( configDir + File.separator + "config.old"));
logger.warning("generating new files...");
FileUtils.checkFiles();
// newPath, oldPath
HashMap<ConfigEntries, String>newAndOldConfigEntries = new HashMap<>();
logger.warning("Loading config entries...");
newAndOldConfigEntries.put(ConfigEntries.HUB_DELAY, "hub.delay");
newAndOldConfigEntries.put(ConfigEntries.SPAWN_DELAY, "spawn.delay");
newAndOldConfigEntries.put(ConfigEntries.WORLD_RELATED_CHAT, "global.world-related-chat");
newAndOldConfigEntries.put(ConfigEntries.UPDATE_CHECKER_ENABLED, "updates.update-notify");
newAndOldConfigEntries.put(ConfigEntries.MOVEMENT_DETECTION_ENABLED, "global.move-detect");
newAndOldConfigEntries.put(ConfigEntries.GAMEMODE_SET_ON_JOIN, "global.set-gamemode-on-join");
newAndOldConfigEntries.put(ConfigEntries.GAMEMODE, "global.gamemode");
newAndOldConfigEntries.put(ConfigEntries.TELEPORTATION_TP_HUB_ON_JOIN, "global.tp-hub-on-join");
newAndOldConfigEntries.put(ConfigEntries.TELEPORTATION_TP_HUB_ON_RESPAWN, "global.tp-hub-on-respawn");
newAndOldConfigEntries.put(ConfigEntries.TELEPORTATION_RESPAWN_HANDLER, "global.respawn-handler");
logger.warning("Converting config entries...");
for(ConfigEntries entry : newAndOldConfigEntries.keySet())
{
logger.warning("Entry: " + entry.path);
FileUtils.FileType.CONFIG_YAML.yaml.set(entry.path, oldConfig.get(newAndOldConfigEntries.get(entry)));
}
logger.warning("Saving file...");
FileUtils.saveExistingYaml(FileUtils.FileType.CONFIG_YAML);
logger.warning("Done with config.yml!");
logger.warning("Loading lang entries...");
HashMap<LocalizedMessages, String>newAndOldLangEntries = new HashMap<>();
newAndOldLangEntries.put(LocalizedMessages.ERROR_ALREADY_TELEPORTING, "global.ALREADY-TELEPORTING");
newAndOldLangEntries.put(LocalizedMessages.ERROR_HUB_NOT_SET, "hub.HUB_NOT_SET");
newAndOldLangEntries.put(LocalizedMessages.ERROR_SPAWN_NOT_SET, "spawn.SPAWN_NOT_SET");
newAndOldLangEntries.put(LocalizedMessages.ERROR_WORLD_NOT_EXISTING, "worldtp.UNKNOWN_WORLD");
newAndOldLangEntries.put(LocalizedMessages.WARNING_TELEPORTATION_CANCELLED, "global.MOVED");
newAndOldLangEntries.put(LocalizedMessages.INFO_HUB_TELEPORTED, "hub.TELEPORTED");
newAndOldLangEntries.put(LocalizedMessages.INFO_SPAWN_TELEPORTED, "spawn.TELEPORTED");
newAndOldLangEntries.put(LocalizedMessages.INFO_WORLDTP_TELEPORTED, "worldtp.TELEPORTED");
logger.warning("Converting lang entries...");
for(LocalizedMessages message : newAndOldLangEntries.keySet())
{
logger.warning("Entry: " + message.path);
FileUtils.FileType.LANG_YAML.yaml.set(message.path, oldConfig.get(newAndOldLangEntries.get(message)));
}
logger.warning("Saving file...");
FileUtils.saveExistingYaml(FileUtils.FileType.LANG_YAML);
logger.warning("Done with lang.yml!");
}
}

View File

@ -0,0 +1,731 @@
package net.mindoverflow.hubthat.utils.statistics;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.zip.GZIPOutputStream;
import javax.net.ssl.HttpsURLConnection;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.ServicePriority;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/**
* bStats collects some data for plugin authors.
* <p>
* Check out https://bStats.org/ to learn more about bStats!
*/
public class Metrics {
static {
if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) {
final String defaultPackage = new String(
new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'});
final String examplePackage = new String(new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'});
if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class.getPackage().getName().equals(examplePackage)) {
throw new IllegalStateException("bStats Metrics class has not been relocated correctly!");
}
}
}
// The version of this bStats class
public static final int B_STATS_VERSION = 1;
// The url to which the data is sent
private static final String URL = "https://bStats.org/submitData/bukkit";
// Is bStats enabled on this server?
private boolean enabled;
// Should failed requests be logged?
private static boolean logFailedRequests = false;
// Should the sent data be logged?
private static boolean logSentData = false;
// Should the response text be logged?
private static boolean logResponseStatusText = false;
// The uuid of the server
private static String serverUUID;
// The plugin
private final Plugin plugin;
// A list with all custom charts
private final List<CustomChart> charts = new ArrayList<>();
/**
* Class constructor.
*
* @param plugin The plugin which stats should be submitted.
*/
public Metrics(Plugin plugin) {
if (plugin == null) {
throw new IllegalArgumentException("Plugin cannot be null!");
}
this.plugin = plugin;
// Get the config file
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
File configFile = new File(bStatsFolder, "config.yml");
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
// Check if the config file exists
if (!config.isSet("serverUuid")) {
// Add default values
config.addDefault("enabled", true);
// Every server gets its unique random id.
config.addDefault("serverUuid", UUID.randomUUID().toString());
// Should failed request be logged?
//config.addDefault("logFailedRequests", false);
// Should the sent data be logged?
//config.addDefault("logSentData", false);
// Should the response text be logged?
//config.addDefault("logResponseStatusText", false);
// Inform the server owners about bStats
config.options().header(
"bStats collects some data for plugin authors like how many servers are using their plugins.\n" +
"To honor their work, you should not disable it.\n" +
"All data is anonymous and this has practically no effect on the server performance!\n" +
"Check out https://bStats.org/ to learn more :)"
).copyDefaults(true);
try {
config.save(configFile);
} catch (IOException ignored) { }
}
// Load the data
enabled = config.getBoolean("enabled", true);
serverUUID = config.getString("serverUuid");
//logFailedRequests = config.getBoolean("logFailedRequests", false);
//logSentData = config.getBoolean("logSentData", false);
//logResponseStatusText = config.getBoolean("logResponseStatusText", false);
logFailedRequests = false;
logSentData = false;
logResponseStatusText = false;
if (enabled) {
boolean found = false;
// Search for all other bStats Metrics classes to see if we are the first one
for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
try {
service.getField("B_STATS_VERSION"); // Our identifier :)
found = true; // We aren't the first
break;
} catch (NoSuchFieldException ignored) { }
}
// Register our service
Bukkit.getServicesManager().register(Metrics.class, this, plugin, ServicePriority.Normal);
if (!found) {
// We are the first!
startSubmitting();
}
}
}
/**
* Checks if bStats is enabled.
*
* @return Whether bStats is enabled or not.
*/
public boolean isEnabled() {
return enabled;
}
/**
* Adds a custom chart.
*
* @param chart The chart to add.
*/
public void addCustomChart(CustomChart chart) {
if (chart == null) {
throw new IllegalArgumentException("Chart cannot be null!");
}
charts.add(chart);
}
/**
* Starts the Scheduler which submits our data every 30 minutes.
*/
private void startSubmitting() {
final Timer timer = new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if (!plugin.isEnabled()) { // Plugin was disabled
timer.cancel();
return;
}
// Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler
// Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;)
Bukkit.getScheduler().runTask(plugin, () -> submitData());
}
}, 1000 * 60 * 5, 1000 * 60 * 30);
// Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start
// WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted!
// WARNING: Just don't do it!
}
/**
* Gets the plugin specific data.
* This method is called using Reflection.
*
* @return The plugin specific data.
*/
public JsonObject getPluginData() {
JsonObject data = new JsonObject();
String pluginName = plugin.getDescription().getName();
String pluginVersion = plugin.getDescription().getVersion();
data.addProperty("pluginName", pluginName); // Append the name of the plugin
data.addProperty("pluginVersion", pluginVersion); // Append the version of the plugin
JsonArray customCharts = new JsonArray();
for (CustomChart customChart : charts) {
// Add the data of the custom charts
JsonObject chart = customChart.getRequestJsonObject();
if (chart == null) { // If the chart is null, we skip it
continue;
}
customCharts.add(chart);
}
data.add("customCharts", customCharts);
return data;
}
/**
* Gets the server specific data.
*
* @return The server specific data.
*/
private JsonObject getServerData() {
// Minecraft specific data
int playerAmount;
try {
// Around MC 1.8 the return type was changed to a collection from an array,
// This fixes java.lang.NoSuchMethodError: org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection;
Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers");
playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class)
? ((Collection<?>) onlinePlayersMethod.invoke(Bukkit.getServer())).size()
: ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length;
} catch (Exception e) {
playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed
}
int onlineMode = Bukkit.getOnlineMode() ? 1 : 0;
String bukkitVersion = Bukkit.getVersion();
String bukkitName = Bukkit.getName();
// OS/Java specific data
String javaVersion = System.getProperty("java.version");
String osName = System.getProperty("os.name");
String osArch = System.getProperty("os.arch");
String osVersion = System.getProperty("os.version");
int coreCount = Runtime.getRuntime().availableProcessors();
JsonObject data = new JsonObject();
data.addProperty("serverUUID", serverUUID);
data.addProperty("playerAmount", playerAmount);
data.addProperty("onlineMode", onlineMode);
data.addProperty("bukkitVersion", bukkitVersion);
data.addProperty("bukkitName", bukkitName);
data.addProperty("javaVersion", javaVersion);
data.addProperty("osName", osName);
data.addProperty("osArch", osArch);
data.addProperty("osVersion", osVersion);
data.addProperty("coreCount", coreCount);
return data;
}
/**
* Collects the data and sends it afterwards.
*/
private void submitData() {
final JsonObject data = getServerData();
JsonArray pluginData = new JsonArray();
// Search for all other bStats Metrics classes to get their plugin data
for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
try {
service.getField("B_STATS_VERSION"); // Our identifier :)
for (RegisteredServiceProvider<?> provider : Bukkit.getServicesManager().getRegistrations(service)) {
try {
Object plugin = provider.getService().getMethod("getPluginData").invoke(provider.getProvider());
if (plugin instanceof JsonObject) {
pluginData.add((JsonObject) plugin);
} else { // old bstats version compatibility
try {
Class<?> jsonObjectJsonSimple = Class.forName("org.json.simple.JSONObject");
if (plugin.getClass().isAssignableFrom(jsonObjectJsonSimple)) {
Method jsonStringGetter = jsonObjectJsonSimple.getDeclaredMethod("toJSONString");
jsonStringGetter.setAccessible(true);
String jsonString = (String) jsonStringGetter.invoke(plugin);
JsonObject object = new JsonParser().parse(jsonString).getAsJsonObject();
pluginData.add(object);
}
} catch (ClassNotFoundException e) {
// minecraft version 1.14+
if (logFailedRequests) {
this.plugin.getLogger().log(Level.SEVERE, "Encountered unexpected exception", e);
}
continue; // continue looping since we cannot do any other thing.
}
}
} catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { }
}
} catch (NoSuchFieldException ignored) { }
}
data.add("plugins", pluginData);
// Create a new thread for the connection to the bStats server
new Thread(new Runnable() {
@Override
public void run() {
try {
// Send the data
sendData(plugin, data);
} catch (Exception e) {
// Something went wrong! :(
if (logFailedRequests) {
plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e);
}
}
}
}).start();
}
/**
* Sends the data to the bStats server.
*
* @param plugin Any plugin. It's just used to get a logger instance.
* @param data The data to send.
* @throws Exception If the request failed.
*/
private static void sendData(Plugin plugin, JsonObject data) throws Exception {
if (data == null) {
throw new IllegalArgumentException("Data cannot be null!");
}
if (Bukkit.isPrimaryThread()) {
throw new IllegalAccessException("This method must not be called from the main thread!");
}
if (logSentData) {
plugin.getLogger().info("Sending data to bStats: " + data.toString());
}
HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection();
// Compress the data to save bandwidth
byte[] compressedData = compress(data.toString());
// Add headers
connection.setRequestMethod("POST");
connection.addRequestProperty("Accept", "application/json");
connection.addRequestProperty("Connection", "close");
connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request
connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format
connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION);
// Send data
connection.setDoOutput(true);
DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
outputStream.write(compressedData);
outputStream.flush();
outputStream.close();
InputStream inputStream = connection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder builder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
builder.append(line);
}
bufferedReader.close();
if (logResponseStatusText) {
plugin.getLogger().info("Sent data to bStats and received response: " + builder.toString());
}
}
/**
* Gzips the given String.
*
* @param str The string to gzip.
* @return The gzipped String.
* @throws IOException If the compression failed.
*/
private static byte[] compress(final String str) throws IOException {
if (str == null) {
return null;
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(outputStream);
gzip.write(str.getBytes(StandardCharsets.UTF_8));
gzip.close();
return outputStream.toByteArray();
}
/**
* Represents a custom chart.
*/
public static abstract class CustomChart {
// The id of the chart
final String chartId;
/**
* Class constructor.
*
* @param chartId The id of the chart.
*/
CustomChart(String chartId) {
if (chartId == null || chartId.isEmpty()) {
throw new IllegalArgumentException("ChartId cannot be null or empty!");
}
this.chartId = chartId;
}
private JsonObject getRequestJsonObject() {
JsonObject chart = new JsonObject();
chart.addProperty("chartId", chartId);
try {
JsonObject data = getChartData();
if (data == null) {
// If the data is null we don't send the chart.
return null;
}
chart.add("data", data);
} catch (Throwable t) {
if (logFailedRequests) {
Bukkit.getLogger().log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, t);
}
return null;
}
return chart;
}
protected abstract JsonObject getChartData() throws Exception;
}
/**
* Represents a custom simple pie.
*/
public static class SimplePie extends CustomChart {
private final Callable<String> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public SimplePie(String chartId, Callable<String> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObject getChartData() throws Exception {
JsonObject data = new JsonObject();
String value = callable.call();
if (value == null || value.isEmpty()) {
// Null = skip the chart
return null;
}
data.addProperty("value", value);
return data;
}
}
/**
* Represents a custom advanced pie.
*/
public static class AdvancedPie extends CustomChart {
private final Callable<Map<String, Integer>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public AdvancedPie(String chartId, Callable<Map<String, Integer>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObject getChartData() throws Exception {
JsonObject data = new JsonObject();
JsonObject values = new JsonObject();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean allSkipped = true;
for (Map.Entry<String, Integer> entry : map.entrySet()) {
if (entry.getValue() == 0) {
continue; // Skip this invalid
}
allSkipped = false;
values.addProperty(entry.getKey(), entry.getValue());
}
if (allSkipped) {
// Null = skip the chart
return null;
}
data.add("values", values);
return data;
}
}
/**
* Represents a custom drilldown pie.
*/
public static class DrilldownPie extends CustomChart {
private final Callable<Map<String, Map<String, Integer>>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public DrilldownPie(String chartId, Callable<Map<String, Map<String, Integer>>> callable) {
super(chartId);
this.callable = callable;
}
@Override
public JsonObject getChartData() throws Exception {
JsonObject data = new JsonObject();
JsonObject values = new JsonObject();
Map<String, Map<String, Integer>> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean reallyAllSkipped = true;
for (Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) {
JsonObject value = new JsonObject();
boolean allSkipped = true;
for (Map.Entry<String, Integer> valueEntry : map.get(entryValues.getKey()).entrySet()) {
value.addProperty(valueEntry.getKey(), valueEntry.getValue());
allSkipped = false;
}
if (!allSkipped) {
reallyAllSkipped = false;
values.add(entryValues.getKey(), value);
}
}
if (reallyAllSkipped) {
// Null = skip the chart
return null;
}
data.add("values", values);
return data;
}
}
/**
* Represents a custom single line chart.
*/
public static class SingleLineChart extends CustomChart {
private final Callable<Integer> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public SingleLineChart(String chartId, Callable<Integer> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObject getChartData() throws Exception {
JsonObject data = new JsonObject();
int value = callable.call();
if (value == 0) {
// Null = skip the chart
return null;
}
data.addProperty("value", value);
return data;
}
}
/**
* Represents a custom multi line chart.
*/
public static class MultiLineChart extends CustomChart {
private final Callable<Map<String, Integer>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public MultiLineChart(String chartId, Callable<Map<String, Integer>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObject getChartData() throws Exception {
JsonObject data = new JsonObject();
JsonObject values = new JsonObject();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean allSkipped = true;
for (Map.Entry<String, Integer> entry : map.entrySet()) {
if (entry.getValue() == 0) {
continue; // Skip this invalid
}
allSkipped = false;
values.addProperty(entry.getKey(), entry.getValue());
}
if (allSkipped) {
// Null = skip the chart
return null;
}
data.add("values", values);
return data;
}
}
/**
* Represents a custom simple bar chart.
*/
public static class SimpleBarChart extends CustomChart {
private final Callable<Map<String, Integer>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public SimpleBarChart(String chartId, Callable<Map<String, Integer>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObject getChartData() throws Exception {
JsonObject data = new JsonObject();
JsonObject values = new JsonObject();
Map<String, Integer> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
for (Map.Entry<String, Integer> entry : map.entrySet()) {
JsonArray categoryValues = new JsonArray();
categoryValues.add(entry.getValue());
values.add(entry.getKey(), categoryValues);
}
data.add("values", values);
return data;
}
}
/**
* Represents a custom advanced bar chart.
*/
public static class AdvancedBarChart extends CustomChart {
private final Callable<Map<String, int[]>> callable;
/**
* Class constructor.
*
* @param chartId The id of the chart.
* @param callable The callable which is used to request the chart data.
*/
public AdvancedBarChart(String chartId, Callable<Map<String, int[]>> callable) {
super(chartId);
this.callable = callable;
}
@Override
protected JsonObject getChartData() throws Exception {
JsonObject data = new JsonObject();
JsonObject values = new JsonObject();
Map<String, int[]> map = callable.call();
if (map == null || map.isEmpty()) {
// Null = skip the chart
return null;
}
boolean allSkipped = true;
for (Map.Entry<String, int[]> entry : map.entrySet()) {
if (entry.getValue().length == 0) {
continue; // Skip this invalid
}
allSkipped = false;
JsonArray categoryValues = new JsonArray();
for (int categoryValue : entry.getValue()) {
categoryValues.add(categoryValue);
}
values.add(entry.getKey(), categoryValues);
}
if (allSkipped) {
// Null = skip the chart
return null;
}
data.add("values", values);
return data;
}
}
}

View File

@ -0,0 +1,267 @@
package net.mindoverflow.hubthat.utils.statistics;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import net.mindoverflow.hubthat.HubThat;
import net.mindoverflow.hubthat.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<String> updateText = new ArrayList<>(), warningMessage = new ArrayList<>();
public Boolean updateWarningBoolean, isNewVersionOut = false;
public Boolean isServerUnreachable = true;
public String errorCode;
private HubThat plugin;
public UpdateChecker(HubThat givenPlugin)
{
plugin = givenPlugin;
}
private String servicesUrl = "https://services.mind-overflow.net/";
private String hubthatUrl = "java/plugins/hubthat/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 + hubthatUrl + "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);
}
}

52
src/plugin.yml Normal file
View File

@ -0,0 +1,52 @@
name: HubThat
version: BUILD_NUMBER
author: mind_overflow
main: net.mindoverflow.hubthat.HubThat
api-version: 1.13
commands:
hubthat:
description: HubThat base command.
usage: /hubthat [args]
hub:
description: Teleport to the hub.
usage: /hub
sethub:
description: Set the hub.
usage: /sethub
spawn:
description: Teleport to the spawn.
usage: /spawn [world]
setspawn:
description: Set the spawn.
usage: /setspawn [world]
worldlist:
description: List all worlds and their info.
usage: /worldlist
worldtp:
description: Teleport to a specific world.
usage: /worldtp <world>
permissions:
hubthat.help:
default: true
hubthat.reloadconfig:
default: op
hubthat.nohubdelay:
default: op
hubthat.sethub:
default: op
hubthat.hub:
default: true
hubthat.nospawndelay:
default: op
hubthat.setspawn:
default: op
hubthat.spawn:
default: true
hubthat.spawn.anotherworld:
default: op
hubthat.gotoworld:
default: op
hubthat.listworlds:
default: op
hubthat.updates:
default: op

0
src/spawn.yml Normal file
View File