Log exceptions using the plugin/component logger

This commit is contained in:
Norbi Peti 2020-10-09 00:08:53 +02:00
parent 01dd8a477e
commit 731065fe2a
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
16 changed files with 137 additions and 99 deletions

View file

@ -83,7 +83,7 @@ public class ComponentCommand extends ICommand2MC {
oc.get().shouldBeEnabled().set(enable); oc.get().shouldBeEnabled().set(enable);
sender.sendMessage(oc.get().getClass().getSimpleName() + " " + (enable ? "en" : "dis") + "abled " + (permanent ? "permanently" : "temporarily") + "."); sender.sendMessage(oc.get().getClass().getSimpleName() + " " + (enable ? "en" : "dis") + "abled " + (permanent ? "permanently" : "temporarily") + ".");
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Couldn't " + (enable ? "en" : "dis") + "able component " + component + "!", e); TBMCCoreAPI.SendException("Couldn't " + (enable ? "en" : "dis") + "able component " + component + "!", e, (JavaPlugin) plugin);
} }
return true; return true;
} }

View file

@ -25,7 +25,7 @@ public final class ComponentManager {
try { try {
Component.setComponentEnabled(c, true); Component.setComponentEnabled(c, true);
} catch (Exception | NoClassDefFoundError e) { } catch (Exception | NoClassDefFoundError e) {
TBMCCoreAPI.SendException("Failed to enable one of the components: " + c.getClass().getSimpleName(), e); TBMCCoreAPI.SendException("Failed to enable one of the components: " + c.getClass().getSimpleName(), e, c);
} }
}); });
componentsEnabled = true; componentsEnabled = true;

View file

@ -142,7 +142,7 @@ public class MainPlugin extends ButtonPlugin {
try { try {
Files.write(new File("plugins", "plugins.txt").toPath(), Arrays.stream(Bukkit.getPluginManager().getPlugins()).map(p -> (CharSequence) p.getDataFolder().getName())::iterator); Files.write(new File("plugins", "plugins.txt").toPath(), Arrays.stream(Bukkit.getPluginManager().getPlugins()).map(p -> (CharSequence) p.getDataFolder().getName())::iterator);
} catch (IOException e) { } catch (IOException e) {
TBMCCoreAPI.SendException("Failed to write plugin list!", e); TBMCCoreAPI.SendException("Failed to write plugin list!", e, this);
} }
} }
if (getServer().getPluginManager().isPluginEnabled("Essentials")) if (getServer().getPluginManager().isPluginEnabled("Essentials"))

View file

@ -77,7 +77,7 @@ public class PlayerListener implements Listener {
try { try {
event.setCancelled(ButtonPlugin.getCommand2MC().handleCommand(new Command2MCSender(event.getSender(), event.getChannel(), event.getPermCheck()), event.getMessage())); event.setCancelled(ButtonPlugin.getCommand2MC().handleCommand(new Command2MCSender(event.getSender(), event.getChannel(), event.getPermCheck()), event.getMessage()));
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Command processing failed for sender '" + event.getSender() + "' and message '" + event.getMessage() + "'", e); TBMCCoreAPI.SendException("Command processing failed for sender '" + event.getSender() + "' and message '" + event.getMessage() + "'", e, MainPlugin.Instance);
} }
} }

View file

@ -4,6 +4,7 @@ import buttondevteam.core.MainPlugin;
import buttondevteam.core.component.channel.Channel; import buttondevteam.core.component.channel.Channel;
import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.TBMCSystemChatEvent;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ComponentMetadata;
import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.ConfigData;
import buttondevteam.lib.chat.IFakePlayer; import buttondevteam.lib.chat.IFakePlayer;
import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;
@ -14,14 +15,15 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerQuitEvent;
import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
/** /**
* Provides commands such as /schrestart (restart after a countdown) and /primerestart (restart when nobody is online) * Provides commands such as /schrestart (restart after a countdown) and /primerestart (restart when nobody is online).
* Also can automatically restart at a given time.
*/ */
@ComponentMetadata(enabledByDefault = false)
public class RestartComponent extends Component<MainPlugin> implements Listener { public class RestartComponent extends Component<MainPlugin> implements Listener {
@Override @Override
public void enable() { public void enable() {

View file

@ -2,6 +2,7 @@ package buttondevteam.core.component.spawn;
import buttondevteam.core.MainPlugin; import buttondevteam.core.MainPlugin;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ComponentMetadata;
import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.ConfigData;
import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.Command2;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
@ -23,6 +24,7 @@ import java.math.BigDecimal;
/** /**
* Provides a /spawn command that works with BungeeCord. Make sure to set up on each server. * Provides a /spawn command that works with BungeeCord. Make sure to set up on each server.
*/ */
@ComponentMetadata(enabledByDefault = false)
public class SpawnComponent extends Component<MainPlugin> implements PluginMessageListener { public class SpawnComponent extends Component<MainPlugin> implements PluginMessageListener {
@Override @Override
protected void enable() { protected void enable() {

View file

@ -8,7 +8,6 @@ import com.palmergames.bukkit.towny.TownyUniverse;
import com.palmergames.bukkit.towny.exceptions.AlreadyRegisteredException; import com.palmergames.bukkit.towny.exceptions.AlreadyRegisteredException;
import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; import com.palmergames.bukkit.towny.exceptions.NotRegisteredException;
import com.palmergames.bukkit.towny.object.Resident; import com.palmergames.bukkit.towny.object.Resident;
import org.bukkit.Bukkit;
/** /**
* Automatically renames Towny players if they changed their Minecraft name * Automatically renames Towny players if they changed their Minecraft name
@ -48,9 +47,9 @@ public class TownyComponent extends Component<MainPlugin> {
component.log("Renaming done."); component.log("Renaming done.");
} }
} catch (AlreadyRegisteredException e) { } catch (AlreadyRegisteredException e) {
TBMCCoreAPI.SendException("Failed to rename resident, there's already one with this name.", e); TBMCCoreAPI.SendException("Failed to rename resident, there's already one with this name.", e, component);
} catch (NotRegisteredException e) { } catch (NotRegisteredException e) {
TBMCCoreAPI.SendException("Failed to rename resident, the resident isn't registered.", e); TBMCCoreAPI.SendException("Failed to rename resident, the resident isn't registered.", e, component);
} }
} }
} }

View file

@ -1,13 +1,14 @@
package buttondevteam.lib; package buttondevteam.lib;
import org.bukkit.event.Event; import org.bukkit.Bukkit;
import org.bukkit.event.Event;
class EventExceptionCoreHandler extends EventExceptionHandler {
class EventExceptionCoreHandler extends EventExceptionHandler {
@Override
public boolean handle(Throwable ex, Event event) { @Override
TBMCCoreAPI.SendException("An error occured while executing " + event.getEventName() + "!", ex); public boolean handle(Throwable ex, Event event) {
return true; TBMCCoreAPI.SendException("An error occured while executing " + event.getEventName() + "!", ex, false, Bukkit.getLogger()::warning);
} return true;
}
}
}

View file

@ -1,13 +1,14 @@
package buttondevteam.lib; package buttondevteam.lib;
import buttondevteam.core.MainPlugin; import buttondevteam.core.MainPlugin;
import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.ChromaGamerBase;
import buttondevteam.lib.potato.DebugPotato; import buttondevteam.lib.potato.DebugPotato;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -15,6 +16,7 @@ import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.util.*; import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.function.Consumer;
public class TBMCCoreAPI { public class TBMCCoreAPI {
static final List<String> coders = new ArrayList<String>() { static final List<String> coders = new ArrayList<String>() {
@ -51,11 +53,21 @@ public class TBMCCoreAPI {
* @param sourcemsg A message that is shown at the top of the exception (before the exception's message) * @param sourcemsg A message that is shown at the top of the exception (before the exception's message)
* @param e The exception to send * @param e The exception to send
*/ */
public static void SendException(String sourcemsg, Throwable e) { public static void SendException(String sourcemsg, Throwable e, Component<?> component) {
SendException(sourcemsg, e, false); SendException(sourcemsg, e, false, component::logWarn);
} }
public static void SendException(String sourcemsg, Throwable e, boolean debugPotato) { /**
* Send exception to the {@link TBMCExceptionEvent}.
*
* @param sourcemsg A message that is shown at the top of the exception (before the exception's message)
* @param e The exception to send
*/
public static void SendException(String sourcemsg, Throwable e, JavaPlugin plugin) {
SendException(sourcemsg, e, false, plugin.getLogger()::warning);
}
public static void SendException(String sourcemsg, Throwable e, boolean debugPotato, Consumer<String> logWarn) {
try { try {
SendUnsentExceptions(); SendUnsentExceptions();
TBMCExceptionEvent event = new TBMCExceptionEvent(sourcemsg, e); TBMCExceptionEvent event = new TBMCExceptionEvent(sourcemsg, e);
@ -64,7 +76,7 @@ public class TBMCCoreAPI {
if (!event.isHandled()) if (!event.isHandled())
exceptionsToSend.put(sourcemsg, e); exceptionsToSend.put(sourcemsg, e);
} }
Bukkit.getLogger().warning(sourcemsg); logWarn.accept(sourcemsg);
e.printStackTrace(); e.printStackTrace();
if (debugPotato) { if (debugPotato) {
List<Player> devsOnline = new ArrayList<>(); List<Player> devsOnline = new ArrayList<>();
@ -105,6 +117,7 @@ public class TBMCCoreAPI {
} }
private static EventExceptionCoreHandler eventExceptionCoreHandler; private static EventExceptionCoreHandler eventExceptionCoreHandler;
/** /**
* Registers Bukkit events, handling the exceptions occurring in those events * Registers Bukkit events, handling the exceptions occurring in those events
* *

View file

@ -59,7 +59,7 @@ public abstract class ButtonPlugin extends JavaPlugin {
try { try {
pluginEnable(); pluginEnable();
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Error while enabling plugin " + getName() + "!", e); TBMCCoreAPI.SendException("Error while enabling plugin " + getName() + "!", e, this);
} }
if (configGenAllowed(this)) //If it's not disabled (by default it's not) if (configGenAllowed(this)) //If it's not disabled (by default it's not)
IHaveConfig.pregenConfig(this, null); IHaveConfig.pregenConfig(this, null);
@ -85,7 +85,7 @@ public abstract class ButtonPlugin extends JavaPlugin {
getLogger().info("Saved configuration changes."); getLogger().info("Saved configuration changes.");
getCommand2MC().unregisterCommands(this); getCommand2MC().unregisterCommands(this);
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Error while disabling plugin " + getName() + "!", e); TBMCCoreAPI.SendException("Error while disabling plugin " + getName() + "!", e, this);
} }
} }
@ -142,7 +142,7 @@ public abstract class ButtonPlugin extends JavaPlugin {
if (yaml != null) if (yaml != null)
yaml.save(); yaml.save();
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Failed to save config", e); TBMCCoreAPI.SendException("Failed to save config", e, this);
} }
} }

View file

@ -77,7 +77,7 @@ public abstract class Component<TP extends JavaPlugin> {
} }
if (register) { if (register) {
if (components.containsKey(component.getClass())) { if (components.containsKey(component.getClass())) {
TBMCCoreAPI.SendException("Failed to register component " + component.getClassName(), new IllegalArgumentException("The component is already registered!")); TBMCCoreAPI.SendException("Failed to register component " + component.getClassName(), new IllegalArgumentException("The component is already registered!"), plugin);
return false; return false;
} }
component.plugin = plugin; component.plugin = plugin;
@ -92,7 +92,7 @@ public abstract class Component<TP extends JavaPlugin> {
setComponentEnabled(component, true); setComponentEnabled(component, true);
return true; return true;
} catch (Exception | NoClassDefFoundError e) { } catch (Exception | NoClassDefFoundError e) {
TBMCCoreAPI.SendException("Failed to enable component " + component.getClassName() + "!", e); TBMCCoreAPI.SendException("Failed to enable component " + component.getClassName() + "!", e, component);
return true; return true;
} }
} }
@ -103,7 +103,7 @@ public abstract class Component<TP extends JavaPlugin> {
try { try {
setComponentEnabled(component, false); setComponentEnabled(component, false);
} catch (Exception | NoClassDefFoundError e) { } catch (Exception | NoClassDefFoundError e) {
TBMCCoreAPI.SendException("Failed to disable component " + component.getClassName() + "!", e); TBMCCoreAPI.SendException("Failed to disable component " + component.getClassName() + "!", e, component);
return false; //If failed to disable, won't unregister either return false; //If failed to disable, won't unregister either
} }
} }
@ -112,7 +112,7 @@ public abstract class Component<TP extends JavaPlugin> {
} }
return true; return true;
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Failed to " + (register ? "" : "un") + "register component " + component.getClassName() + "!", e); TBMCCoreAPI.SendException("Failed to " + (register ? "" : "un") + "register component " + component.getClassName() + "!", e, plugin);
return false; return false;
} }
} }
@ -153,7 +153,7 @@ public abstract class Component<TP extends JavaPlugin> {
} }
} }
public static void updateConfig(JavaPlugin plugin, Component component) { public static void updateConfig(JavaPlugin plugin, Component<?> component) {
if (plugin.getConfig() != null) { //Production if (plugin.getConfig() != null) { //Production
var compconf = plugin.getConfig().getConfigurationSection("components"); var compconf = plugin.getConfig().getConfigurationSection("components");
if (compconf == null) compconf = plugin.getConfig().createSection("components"); if (compconf == null) compconf = plugin.getConfig().createSection("components");

View file

@ -5,7 +5,9 @@ import buttondevteam.lib.TBMCCoreAPI;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.val; import lombok.val;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.plugin.java.JavaPlugin;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -211,7 +213,13 @@ public final class IHaveConfig {
try { try {
return (ConfigData<?>) m.invoke(obj, kv.getValue()); return (ConfigData<?>) m.invoke(obj, kv.getValue());
} catch (IllegalAccessException | InvocationTargetException e) { } catch (IllegalAccessException | InvocationTargetException e) {
TBMCCoreAPI.SendException("Failed to pregenerate " + m.getName() + " for " + obj + " using config " + kv.getKey() + "!", e); String msg = "Failed to pregenerate " + m.getName() + " for " + obj + " using config " + kv.getKey() + "!";
if (obj instanceof Component<?>)
TBMCCoreAPI.SendException(msg, e, (Component<?>) obj);
else if (obj instanceof JavaPlugin)
TBMCCoreAPI.SendException(msg, e, (JavaPlugin) obj);
else
TBMCCoreAPI.SendException(msg, e, false, Bukkit.getLogger()::warning);
return null; return null;
} }
}).filter(Objects::nonNull).collect(Collectors.toList()); }).filter(Objects::nonNull).collect(Collectors.toList());
@ -228,7 +236,13 @@ public final class IHaveConfig {
c.get(); //Saves the default value if needed - also checks validity c.get(); //Saves the default value if needed - also checks validity
} }
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Failed to pregenerate " + m.getName() + " for " + obj + "!", e); String msg = "Failed to pregenerate " + m.getName() + " for " + obj + "!";
if (obj instanceof Component<?>)
TBMCCoreAPI.SendException(msg, e, (Component<?>) obj);
else if (obj instanceof JavaPlugin)
TBMCCoreAPI.SendException(msg, e, (JavaPlugin) obj);
else
TBMCCoreAPI.SendException(msg, e, false, Bukkit.getLogger()::warning);
} }
} }
} }

View file

@ -147,7 +147,7 @@ public abstract class Command2<TC extends ICommand2<TP>, TP extends Command2Send
try { try {
handleCommandAsync(sender, commandline, sd, subcommand, sync); handleCommandAsync(sender, commandline, sd, subcommand, sync);
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Command execution failed for sender " + sender.getName() + "(" + sender.getClass().getCanonicalName() + ") and message " + commandline, e); TBMCCoreAPI.SendException("Command execution failed for sender " + sender.getName() + "(" + sender.getClass().getCanonicalName() + ") and message " + commandline, e, MainPlugin.Instance);
} }
}); });
return true; //We found a method return true; //We found a method
@ -271,9 +271,9 @@ public abstract class Command2<TC extends ICommand2<TP>, TP extends Command2Send
} else if (ret != null) } else if (ret != null)
throw new Exception("Wrong return type! Must return a boolean or void. Return value: " + ret); throw new Exception("Wrong return type! Must return a boolean or void. Return value: " + ret);
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
TBMCCoreAPI.SendException("An error occurred in a command handler!", e.getCause()); TBMCCoreAPI.SendException("An error occurred in a command handler for " + subcommand + "!", e.getCause(), MainPlugin.Instance);
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Command handling failed for sender " + sender + " and subcommand " + subcommand, e); TBMCCoreAPI.SendException("Command handling failed for sender " + sender + " and subcommand " + subcommand, e, MainPlugin.Instance);
} }
}; };
if (sync) if (sync)
@ -306,7 +306,7 @@ public abstract class Command2<TC extends ICommand2<TP>, TP extends Command2Send
if (!commandHelp.contains(mainPath)) if (!commandHelp.contains(mainPath))
commandHelp.add(mainPath); commandHelp.add(mainPath);
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Could not register default handler for command /" + path, e); TBMCCoreAPI.SendException("Could not register default handler for command /" + path, e, MainPlugin.Instance);
} }
var addedSubcommands = new ArrayList<SubcommandData<TC>>(); var addedSubcommands = new ArrayList<SubcommandData<TC>>();
for (val method : command.getClass().getMethods()) { for (val method : command.getClass().getMethods()) {
@ -347,7 +347,7 @@ public abstract class Command2<TC extends ICommand2<TP>, TP extends Command2Send
private String[] getParameterHelp(Method method, String[] ht, String subcommand, String[] parameters) { private String[] getParameterHelp(Method method, String[] ht, String subcommand, String[] parameters) {
val str = method.getDeclaringClass().getResourceAsStream("/commands.yml"); val str = method.getDeclaringClass().getResourceAsStream("/commands.yml");
if (str == null) if (str == null)
TBMCCoreAPI.SendException("Error while getting command data!", new Exception("Resource not found!")); TBMCCoreAPI.SendException("Error while getting command data!", new Exception("Resource not found!"), MainPlugin.Instance);
else { else {
if (ht.length > 0) if (ht.length > 0)
ht[0] = "§6---- " + ht[0] + " ----"; ht[0] = "§6---- " + ht[0] + " ----";
@ -368,11 +368,11 @@ public abstract class Command2<TC extends ICommand2<TP>, TP extends Command2Send
for (int j = 0; j < paramArray.length && j < parameters.length; j++) for (int j = 0; j < paramArray.length && j < parameters.length; j++)
parameters[j] = paramArray[j]; parameters[j] = paramArray[j];
} else } else
TBMCCoreAPI.SendException("Error while getting command data for " + method + "!", new Exception("Method '" + method.toString() + "' != " + mname + " or params is " + params)); TBMCCoreAPI.SendException("Error while getting command data for " + method + "!", new Exception("Method '" + method.toString() + "' != " + mname + " or params is " + params), MainPlugin.Instance);
} else } else
TBMCCoreAPI.SendException("Error while getting command data for " + method + "!", new Exception("cs is " + cs)); TBMCCoreAPI.SendException("Error while getting command data for " + method + "!", new Exception("cs is " + cs), MainPlugin.Instance);
} else } else
TBMCCoreAPI.SendException("Error while getting command data for " + method + "!", new Exception("ccs is " + ccs + " - class: " + method.getDeclaringClass().getCanonicalName())); TBMCCoreAPI.SendException("Error while getting command data for " + method + "!", new Exception("ccs is " + ccs + " - class: " + method.getDeclaringClass().getCanonicalName()), MainPlugin.Instance);
} }
return ht; return ht;
} }

View file

@ -8,7 +8,6 @@ import buttondevteam.lib.player.ChromaGamerBase;
import com.mojang.brigadier.arguments.*; import com.mojang.brigadier.arguments.*;
import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.tree.CommandNode; import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.LiteralCommandNode; import com.mojang.brigadier.tree.LiteralCommandNode;
import lombok.val; import lombok.val;
@ -233,7 +232,10 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
if (CommodoreProvider.isSupported()) if (CommodoreProvider.isSupported())
TabcompleteHelper.registerTabcomplete(command, subcmds, bukkitCommand); TabcompleteHelper.registerTabcomplete(command, subcmds, bukkitCommand);
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Failed to register command in command map!", e); if (command.getComponent() == null)
TBMCCoreAPI.SendException("Failed to register command in command map!", e, command.getPlugin());
else
TBMCCoreAPI.SendException("Failed to register command in command map!", e, command.getComponent());
shouldRegisterOfficially = false; shouldRegisterOfficially = false;
} }
} }
@ -241,7 +243,7 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
private boolean executeCommand(CommandSender sender, Command command, String label, String[] args) { private boolean executeCommand(CommandSender sender, Command command, String label, String[] args) {
var user = ChromaGamerBase.getFromSender(sender); var user = ChromaGamerBase.getFromSender(sender);
if (user == null) { if (user == null) {
TBMCCoreAPI.SendException("Failed to run Bukkit command for user!", new Throwable("No Chroma user found")); TBMCCoreAPI.SendException("Failed to run Bukkit command for user!", new Throwable("No Chroma user found"), MainPlugin.Instance);
sender.sendMessage("§cAn internal error occurred."); sender.sendMessage("§cAn internal error occurred.");
return true; return true;
} }
@ -372,7 +374,7 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
.filter(t -> param.replaceAll("[\\[\\]<>]", "").equalsIgnoreCase(t.getValue1().param())) .filter(t -> param.replaceAll("[\\[\\]<>]", "").equalsIgnoreCase(t.getValue1().param()))
.findAny(); .findAny();
var argb = RequiredArgumentBuilder.argument(param, type) var argb = RequiredArgumentBuilder.argument(param, type)
.suggests((SuggestionProvider<Object>) (context, builder) -> { .suggests((context, builder) -> {
if (parameter.isVarArgs()) { //Do it before the builder is used if (parameter.isVarArgs()) { //Do it before the builder is used
int nextTokenStart = context.getInput().lastIndexOf(' ') + 1; int nextTokenStart = context.getInput().lastIndexOf(' ') + 1;
builder = builder.createOffset(nextTokenStart); builder = builder.createOffset(nextTokenStart);
@ -399,12 +401,9 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
args[j] = paramValueString; args[j] = paramValueString;
continue; continue;
} }
val converter = ButtonPlugin.getCommand2MC().paramConverters.get(params[j].getType()); val converter = getParamConverter(params[j].getType(), command2MC);
if (converter == null) { if (converter == null)
TBMCCoreAPI.SendException("Could not find a suitable converter for type " + params[j].getType().getSimpleName(),
new NullPointerException("converter is null"));
break; break;
}
val paramValue = converter.converter.apply(paramValueString); val paramValue = converter.converter.apply(paramValueString);
if (paramValue == null) //For example, the player provided an invalid plugin name if (paramValue == null) //For example, the player provided an invalid plugin name
break; break;
@ -427,16 +426,17 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
else else
throw new ClassCastException("Bad return type! It should return a String[] or an Iterable<String>."); throw new ClassCastException("Bad return type! It should return a String[] or an Iterable<String>.");
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Failed to run tabcomplete method " + method.getName() + " for command " + command2MC.getClass().getSimpleName(), e); String msg = "Failed to run tabcomplete method " + method.getName() + " for command " + command2MC.getClass().getSimpleName();
if (command2MC.getComponent() == null)
TBMCCoreAPI.SendException(msg, e, command2MC.getPlugin());
else
TBMCCoreAPI.SendException(msg, e, command2MC.getComponent());
} }
} }
} }
if (!ignoreCustomParamType && customParamType) { if (!ignoreCustomParamType && customParamType) {
val converter = ButtonPlugin.getCommand2MC().paramConverters.get(ptype); val converter = getParamConverter(ptype, command2MC);
if (converter == null) if (converter != null) {
TBMCCoreAPI.SendException("Could not find a suitable converter for type " + ptype.getSimpleName(),
new NullPointerException("converter is null"));
else {
var suggestions = converter.allSupplier.get(); var suggestions = converter.allSupplier.get();
for (String suggestion : suggestions) for (String suggestion : suggestions)
builder.suggest(suggestion); builder.suggest(suggestion);
@ -467,4 +467,18 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
} }
} }
} }
private static ParamConverter<?> getParamConverter(Class<?> cl, ICommand2MC command2MC) {
val converter = ButtonPlugin.getCommand2MC().paramConverters.get(cl);
if (converter == null) {
String msg = "Could not find a suitable converter for type " + cl.getSimpleName();
Exception exception = new NullPointerException("converter is null");
if (command2MC.getComponent() == null)
TBMCCoreAPI.SendException(msg, exception, command2MC.getPlugin());
else
TBMCCoreAPI.SendException(msg, exception, command2MC.getComponent());
return null;
}
return converter;
}
} }

View file

@ -1,5 +1,6 @@
package buttondevteam.lib.player; package buttondevteam.lib.player;
import buttondevteam.core.MainPlugin;
import buttondevteam.core.component.channel.Channel; import buttondevteam.core.component.channel.Channel;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import com.google.common.collect.HashBiMap; import com.google.common.collect.HashBiMap;
@ -30,19 +31,17 @@ public abstract class ChromaGamerBase implements AutoCloseable {
playerTypes.put(userclass, userclass.getAnnotation(UserClass.class).foldername()); playerTypes.put(userclass, userclass.getAnnotation(UserClass.class).foldername());
else if (userclass.isAnnotationPresent(AbstractUserClass.class)) else if (userclass.isAnnotationPresent(AbstractUserClass.class))
playerTypes.put(userclass.getAnnotation(AbstractUserClass.class).prototype(), playerTypes.put(userclass.getAnnotation(AbstractUserClass.class).prototype(),
userclass.getAnnotation(AbstractUserClass.class).foldername()); userclass.getAnnotation(AbstractUserClass.class).foldername());
else // <-- Really important else // <-- Really important
throw new RuntimeException("Class not registered as a user class! Use @UserClass or TBMCPlayerBase"); throw new RuntimeException("Class not registered as a user class! Use @UserClass or TBMCPlayerBase");
} }
/** /**
* Returns the folder name for the given player class. * Returns the folder name for the given player class.
* *
* @param cl * @param cl The class to get the folder from (like {@link TBMCPlayerBase} or one of it's subclasses)
* The class to get the folder from (like {@link TBMCPlayerBase} or one of it's subclasses)
* @return The folder name for the given type * @return The folder name for the given type
* @throws RuntimeException * @throws RuntimeException If the class doesn't have the {@link UserClass} annotation.
* If the class doesn't have the {@link UserClass} annotation.
*/ */
public static <T extends ChromaGamerBase> String getFolderForType(Class<T> cl) { public static <T extends ChromaGamerBase> String getFolderForType(Class<T> cl) {
if (cl.isAnnotationPresent(UserClass.class)) if (cl.isAnnotationPresent(UserClass.class))
@ -54,9 +53,8 @@ public abstract class ChromaGamerBase implements AutoCloseable {
/** /**
* Returns the player class for the given folder name. * Returns the player class for the given folder name.
* *
* @param foldername * @param foldername The folder to get the class from (like "minecraft")
* The folder to get the class from (like "minecraft")
* @return The type for the given folder name or null if not found * @return The type for the given folder name or null if not found
*/ */
public static Class<? extends ChromaGamerBase> getTypeForFolder(String foldername) { public static Class<? extends ChromaGamerBase> getTypeForFolder(String foldername) {
@ -72,16 +70,16 @@ public abstract class ChromaGamerBase implements AutoCloseable {
} }
/** /**
* Use {@link #data(Object)} or {@link #data(String, Object)} where possible; the 'id' must be always set * Use {@link #data(Object)} or {@link #data(String, Object)} where possible; the 'id' must be always set
*/ */
protected YamlConfiguration plugindata; protected YamlConfiguration plugindata;
/*** /***
* Loads a user from disk and returns the user object. Make sure to use the subclasses' methods, where possible, like {@link TBMCPlayerBase#getPlayer(java.util.UUID, Class)} * Loads a user from disk and returns the user object. Make sure to use the subclasses' methods, where possible, like {@link TBMCPlayerBase#getPlayer(java.util.UUID, Class)}
* *
* @param fname Filename without .yml, usually UUID * @param fname Filename without .yml, usually UUID
* @param cl User class * @param cl User class
* @return The user object * @return The user object
*/ */
public static <T extends ChromaGamerBase> T getUser(String fname, Class<T> cl) { public static <T extends ChromaGamerBase> T getUser(String fname, Class<T> cl) {
try { try {
@ -93,7 +91,7 @@ public abstract class ChromaGamerBase implements AutoCloseable {
obj.plugindata.set(folder + "_id", fname); obj.plugindata.set(folder + "_id", fname);
return obj; return obj;
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("An error occured while loading a " + cl.getSimpleName() + "!", e); TBMCCoreAPI.SendException("An error occured while loading a " + cl.getSimpleName() + "!", e, MainPlugin.Instance);
} }
return null; return null;
} }
@ -140,15 +138,14 @@ public abstract class ChromaGamerBase implements AutoCloseable {
try { try {
close(); close();
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Error while saving player to " + getFolder() + "/" + getFileName() + ".yml!", e); TBMCCoreAPI.SendException("Error while saving player to " + getFolder() + "/" + getFileName() + ".yml!", e, MainPlugin.Instance);
} }
} }
/** /**
* Connect two accounts. Do not use for connecting two Minecraft accounts or similar. Also make sure you have the "id" tag set * Connect two accounts. Do not use for connecting two Minecraft accounts or similar. Also make sure you have the "id" tag set
* *
* @param user * @param user The account to connect with
* The account to connect with
*/ */
public <T extends ChromaGamerBase> void connectWith(T user) { public <T extends ChromaGamerBase> void connectWith(T user) {
// Set the ID, go through all linked files and connect them as well // Set the ID, go through all linked files and connect them as well
@ -157,7 +154,7 @@ public abstract class ChromaGamerBase implements AutoCloseable {
final String ownFolder = getFolder(); final String ownFolder = getFolder();
final String userFolder = user.getFolder(); final String userFolder = user.getFolder();
if (ownFolder.equalsIgnoreCase(userFolder)) if (ownFolder.equalsIgnoreCase(userFolder))
throw new RuntimeException("Do not connect two accounts of the same type! Type: "+ownFolder); throw new RuntimeException("Do not connect two accounts of the same type! Type: " + ownFolder);
user.plugindata.set(ownFolder + "_id", plugindata.getString(ownFolder + "_id")); user.plugindata.set(ownFolder + "_id", plugindata.getString(ownFolder + "_id"));
plugindata.set(userFolder + "_id", user.plugindata.getString(userFolder + "_id")); plugindata.set(userFolder + "_id", user.plugindata.getString(userFolder + "_id"));
Consumer<YamlConfiguration> sync = sourcedata -> { Consumer<YamlConfiguration> sync = sourcedata -> {
@ -176,7 +173,7 @@ public abstract class ChromaGamerBase implements AutoCloseable {
cg.plugindata.set(item.getValue() + "_id", sourcedata.getString(item.getValue() + "_id")); // Set all existing IDs cg.plugindata.set(item.getValue() + "_id", sourcedata.getString(item.getValue() + "_id")); // Set all existing IDs
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Failed to update " + sourcefolder + " ID in player files for " + id TBMCCoreAPI.SendException("Failed to update " + sourcefolder + " ID in player files for " + id
+ " in folder with " + entry.getValue() + " id " + otherid + "!", e); + " in folder with " + entry.getValue() + " id " + otherid + "!", e, MainPlugin.Instance);
} }
} }
}; };
@ -186,9 +183,8 @@ public abstract class ChromaGamerBase implements AutoCloseable {
/** /**
* Retunrs the ID for the T typed player object connected with this one or null if no connection found. * Retunrs the ID for the T typed player object connected with this one or null if no connection found.
* *
* @param cl * @param cl The player class to get the ID from
* The player class to get the ID from
* @return The ID or null if not found * @return The ID or null if not found
*/ */
public <T extends ChromaGamerBase> String getConnectedID(Class<T> cl) { public <T extends ChromaGamerBase> String getConnectedID(Class<T> cl) {
@ -198,9 +194,8 @@ public abstract class ChromaGamerBase implements AutoCloseable {
/** /**
* Returns this player as a plugin player. This will return a new instance unless the player is online.<br> * Returns this player as a plugin player. This will return a new instance unless the player is online.<br>
* Make sure to close both the returned and this object. A try-with-resources block or two can help.<br> * Make sure to close both the returned and this object. A try-with-resources block or two can help.<br>
* *
* @param cl * @param cl The target player class
* The target player class
* @return The player as a {@link T} object or null if not having an account there * @return The player as a {@link T} object or null if not having an account there
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -224,16 +219,16 @@ public abstract class ChromaGamerBase implements AutoCloseable {
private void ThrowIfNoUser() { private void ThrowIfNoUser() {
if (!getClass().isAnnotationPresent(UserClass.class) if (!getClass().isAnnotationPresent(UserClass.class)
&& !getClass().isAnnotationPresent(AbstractUserClass.class)) && !getClass().isAnnotationPresent(AbstractUserClass.class))
throw new RuntimeException("Class not registered as a user class! Use @UserClass"); throw new RuntimeException("Class not registered as a user class! Use @UserClass");
} }
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
private final HashMap<String, PlayerData> datamap = new HashMap<>(); private final HashMap<String, PlayerData> datamap = new HashMap<>();
/** /**
* Use from a data() method, which is in a method with the name of the key. For example, use flair() for the enclosing method of the outer data() to save to and load from "flair" * Use from a data() method, which is in a method with the name of the key. For example, use flair() for the enclosing method of the outer data() to save to and load from "flair"
* *
* @return A data object with methods to get and set * @return A data object with methods to get and set
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -247,7 +242,7 @@ public abstract class ChromaGamerBase implements AutoCloseable {
/** /**
* Use from a method with the name of the key. For example, use flair() for the enclosing method to save to and load from "flair" * Use from a method with the name of the key. For example, use flair() for the enclosing method to save to and load from "flair"
* *
* @return A data object with methods to get and set * @return A data object with methods to get and set
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -265,7 +260,7 @@ public abstract class ChromaGamerBase implements AutoCloseable {
/** /**
* Use from a data() method, which is in a method with the name of the key. For example, use flair() for the enclosing method of the outer data() to save to and load from "flair" * Use from a data() method, which is in a method with the name of the key. For example, use flair() for the enclosing method of the outer data() to save to and load from "flair"
* *
* @return A data object with methods to get and set * @return A data object with methods to get and set
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -306,9 +301,8 @@ public abstract class ChromaGamerBase implements AutoCloseable {
/** /**
* Get player information. This method calls the {@link TBMCPlayerGetInfoEvent} to get all the player information across the TBMC plugins. * Get player information. This method calls the {@link TBMCPlayerGetInfoEvent} to get all the player information across the TBMC plugins.
* *
* @param target * @param target The {@link InfoTarget} to return the info for.
* The {@link InfoTarget} to return the info for.
* @return The player information. * @return The player information.
*/ */
public String getInfo(InfoTarget target) { public String getInfo(InfoTarget target) {

View file

@ -16,7 +16,7 @@ import java.util.concurrent.ConcurrentHashMap;
public abstract class TBMCPlayerBase extends ChromaGamerBase { public abstract class TBMCPlayerBase extends ChromaGamerBase {
protected UUID uuid; protected UUID uuid;
private String pluginname; private final String pluginname;
protected TBMCPlayerBase() { protected TBMCPlayerBase() {
if (getClass().isAnnotationPresent(PlayerClass.class)) if (getClass().isAnnotationPresent(PlayerClass.class))
@ -77,8 +77,7 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase {
player.uuid = uuid; player.uuid = uuid;
return player; return player;
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException( TBMCCoreAPI.SendException("Failed to get player with UUID " + uuid + " and class " + cl.getSimpleName() + "!", e, MainPlugin.Instance);
"Failed to get player with UUID " + uuid + " and class " + cl.getSimpleName() + "!", e);
return null; return null;
} }
} }
@ -86,7 +85,7 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase {
/** /**
* Key: UUID-Class * Key: UUID-Class
*/ */
static final ConcurrentHashMap<String, TBMCPlayerBase> playermap = new ConcurrentHashMap<>(); private static final ConcurrentHashMap<String, TBMCPlayerBase> playermap = new ConcurrentHashMap<>();
/** /**
* Gets the TBMCPlayer object as a specific plugin player, keeping it's data<br> * Gets the TBMCPlayer object as a specific plugin player, keeping it's data<br>
@ -147,7 +146,7 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase {
p.close(); p.close();
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Error while saving player " + p.PlayerName().get() + " (" + p.getFolder() TBMCCoreAPI.SendException("Error while saving player " + p.PlayerName().get() + " (" + p.getFolder()
+ "/" + p.getFileName() + ")!", e); + "/" + p.getFileName() + ")!", e, MainPlugin.Instance);
} }
}); });
} }