Merge pull request #90 from TBMCPlugins/dev

Configuration comments, fixes, command and other fixes
This commit is contained in:
Norbi Peti 2020-02-01 20:11:39 +01:00 committed by GitHub
commit d48a2d17d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 736 additions and 778 deletions

View file

@ -46,17 +46,17 @@
<bytecodeTargetLevel>
<module name="BuildConfigUpdater" target="8" />
<module name="ButtonCore" target="1.5" />
<module name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" target="13" />
<module name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" target="11" />
<module name="ButtonProcessor" target="8" />
<module name="ChunkArchive" target="1.8" />
<module name="CorePOM" target="13" />
<module name="CorePOM" target="11" />
<module name="RandomTeleport" target="1.8" />
</bytecodeTargetLevel>
</component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="BuildConfigUpdater" options="" />
<module name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" options="--enable-preview" />
<module name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" options="" />
<module name="ButtonProcessor" options="-proc:none" />
</option>
</component>

View file

@ -1,107 +0,0 @@
package buttondevteam.core;
import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.chat.TBMCChatAPI;
import buttondevteam.lib.chat.TBMCCommandBase;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.Arrays;
public class CommandCaller implements CommandExecutor {
private CommandCaller() {
}
private static CommandCaller instance;
public static void RegisterCommand(TBMCCommandBase cmd) throws Exception {
if (instance == null)
instance = new CommandCaller();
String[] topcmd = new String[1]; //Holds out param
PluginCommand pc = getPluginCommand(cmd, topcmd);
pc.setExecutor(instance);
String[] helptext = cmd.GetHelpText(topcmd[0]);
if (helptext == null || helptext.length == 0)
throw new Exception("Command " + cmd.GetCommandPath() + " has no help text!");
pc.setUsage(helptext.length > 1 ? helptext[1] : helptext[0]);
}
@Override
public boolean onCommand(CommandSender sender, Command command, String alias, String[] args) {
StringBuilder path = new StringBuilder(command.getName().toLowerCase());
for (String arg : args)
path.append(" ").append(arg);
TBMCCommandBase cmd = TBMCChatAPI.GetCommands().get(path.toString());
int argc = 0;
String[] subcmds = null;
while (cmd == null && (subcmds = TBMCChatAPI.GetSubCommands(path.toString(), sender)).length == 0 && path.toString().contains(" ")) {
path = new StringBuilder(path.substring(0, path.toString().lastIndexOf(' ')));
argc++;
cmd = TBMCChatAPI.GetCommands().get(path.toString());
}
if (cmd == null) {
if (subcmds.length > 0) //Subcmds will always have value here (see assignment above)
sender.sendMessage(subcmds);
else {
final String errormsg = "§cYou don't have access to any of this command's subcommands or it doesn't have any.";
sender.sendMessage(errormsg);
}
return true;
}
if (cmd.isModOnly() && (MainPlugin.permission != null ? !MainPlugin.permission.has(sender, "tbmc.admin") : !sender.isOp())) {
sender.sendMessage("§cYou need to be a mod to use this command.");
return true;
}
final String[] cmdargs = args.length > 0 ? Arrays.copyOfRange(args, args.length - argc, args.length) : args;
try {
if (!cmd.OnCommand(sender, alias, cmdargs)) {
if (cmd.GetHelpText(alias) == null) {
sender.sendMessage("Wrong usage, but there's no help text! Error is being reported to devs.");
throw new NullPointerException("GetHelpText is null for comand /" + cmd.GetCommandPath());
} else
sender.sendMessage(cmd.GetHelpText(alias));
}
} catch (Exception e) {
TBMCCoreAPI.SendException("Failed to execute command /" + cmd.GetCommandPath() + " with arguments "
+ Arrays.toString(cmdargs), e);
}
return true;
}
public static void UnregisterCommand(TBMCCommandBase cmd) throws Exception {
PluginCommand pc = getPluginCommand(cmd, null);
pc.setExecutor(null); //Sets the executor to this plugin
}
/**
* Gets the plugin command from the TBMC command.
*
* @param cmd The TBMC command
* @param out_topcmd An array with at least 1 elements or null
* @return The Bukkit plugin command - an exception is generated if null
* @throws Exception If the command isn't set up properly (or a different error)
*/
public static PluginCommand getPluginCommand(TBMCCommandBase cmd, String[] out_topcmd) throws Exception {
String topcmd = cmd.GetCommandPath();
if (topcmd == null)
throw new Exception("Command " + cmd.getClass().getSimpleName() + " has no command path!");
if (cmd.getPlugin() == null)
throw new Exception("Command " + cmd.GetCommandPath() + " has no plugin!");
int i;
if ((i = topcmd.indexOf(' ')) != -1) // Get top-level command
topcmd = topcmd.substring(0, i);
if (out_topcmd != null && out_topcmd.length > 0)
out_topcmd[0] = topcmd;
{
PluginCommand pc = ((JavaPlugin) cmd.getPlugin()).getCommand(topcmd);
if (pc == null)
throw new Exception("Top level command " + topcmd + " not registered in plugin.yml for plugin: "
+ cmd.getPlugin().getName());
return pc;
}
}
}

View file

@ -23,21 +23,33 @@ public class ComponentCommand extends ICommand2MC {
getManager().addParamConverter(Plugin.class, arg -> Bukkit.getPluginManager().getPlugin(arg), "Plugin not found!");
}
@Subcommand
@Subcommand(helpText = {
"Enable component",
"Temporarily enables a component. If you want to permanently enable a component, change it's 'enabled' config option.\""
})
public boolean enable(CommandSender sender, Plugin plugin, String component) {
if (plugin instanceof ButtonPlugin)
((ButtonPlugin) plugin).justReload();
else
if (plugin instanceof ButtonPlugin) {
if (!((ButtonPlugin) plugin).justReload()) {
sender.sendMessage("§cCouldn't reload config, check console.");
return true;
}
} else
plugin.reloadConfig(); //Reload config so the new config values are read - All changes are saved to disk on disable
return enable_disable(sender, plugin, component, true);
}
@Subcommand
@Subcommand(helpText = {
"Disable component",
"Temporarily disables a component. If you want to permanently disable a component, change it's 'enabled' config option."
})
public boolean disable(CommandSender sender, Plugin plugin, String component) {
return enable_disable(sender, plugin, component, false);
}
@Subcommand
@Subcommand(helpText = {
"List components",
"Lists all of the registered Chroma components"
})
public boolean list(CommandSender sender, @Command2.OptionalArg String plugin) {
sender.sendMessage("§6List of components:");
Component.getComponents().values().stream().filter(c -> plugin == null || c.getPlugin().getName().equalsIgnoreCase(plugin)) //If plugin is null, don't check

View file

@ -47,6 +47,7 @@ import java.util.logging.Logger;
public class MainPlugin extends ButtonPlugin {
public static MainPlugin Instance;
public static Permission permission;
@Nullable
public static Essentials ess;
private Logger logger;
@ -60,19 +61,38 @@ public class MainPlugin extends ButtonPlugin {
@Setter
private boolean chatHandlerEnabled = true;
/**
* Sets whether the plugin should write a list of installed plugins in a txt file.
* It can be useful if some other software needs to know the plugins.
*/
private ConfigData<Boolean> writePluginList() {
return getIConfig().getData("writePluginList", false);
}
/**
* The chat format to use for messages from other platforms if Chroma-Chat is not installed.
*/
ConfigData<String> chatFormat() {
return getIConfig().getData("chatFormat", "[{origin}|" +
"{channel}] <{name}> {message}");
}
/**
* Print some debug information.
*/
public ConfigData<Boolean> test() {
return getIConfig().getData("test", true);
return getIConfig().getData("test", false);
}
/*
* By default, the plugin uses Vault for all command permission checks, but this can have issues (with PEX for example) where default permissions aren't granted.
* When this setting is off, the plugin uses Bukkit's built-in way of handling permissions, which usually works fine for players.
* You can also grant chroma.command.* to each player (mod-only commands need another permission, chroma.mod).
*/
/*public ConfigData<Boolean> useVaultForCommands() {
return getIConfig().getData("useVaultForCommands", true);
}*/
@Override
public void pluginEnable() {
// Logs "Plugin Enabled", registers commands
@ -90,6 +110,7 @@ public class MainPlugin extends ButtonPlugin {
Component.registerComponent(this, new ChannelComponent());
Component.registerComponent(this, new RandomTPComponent());
Component.registerComponent(this, new MemberComponent());
if (Bukkit.getPluginManager().isPluginEnabled("Multiverse-Core"))
Component.registerComponent(this, new SpawnComponent());
if (Bukkit.getPluginManager().isPluginEnabled("Towny")) //It fails to load the component class otherwise
Component.registerComponent(this, new TownyComponent());
@ -124,6 +145,7 @@ public class MainPlugin extends ButtonPlugin {
TBMCCoreAPI.SendException("Failed to write plugin list!", e);
}
}
if (getServer().getPluginManager().isPluginEnabled("Essentials"))
ess = Essentials.getPlugin(Essentials.class);
logger.info(pdf.getName() + " has been Enabled (V." + pdf.getVersion() + ") Test: " + test().get() + ".");
}

View file

@ -2,6 +2,7 @@ package buttondevteam.core.component.members;
import buttondevteam.core.MainPlugin;
import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ComponentMetadata;
import buttondevteam.lib.architecture.ConfigData;
import org.bukkit.Statistic;
import org.bukkit.event.EventHandler;
@ -18,6 +19,7 @@ import static buttondevteam.core.MainPlugin.permission;
/**
* Allows giving a 'member' group over some time elapsed OR played.
*/
@ComponentMetadata(enabledByDefault = false)
public class MemberComponent extends Component<MainPlugin> implements Listener {
/**
* The permission group to give to the player
@ -62,12 +64,16 @@ public class MemberComponent extends Component<MainPlugin> implements Listener {
if (permission != null && !permission.playerInGroup(event.getPlayer(), memberGroup().get())
&& (new Date(event.getPlayer().getFirstPlayed()).toInstant().plus(registeredForDays().get(), ChronoUnit.DAYS).isBefore(Instant.now())
|| event.getPlayer().getStatistic(playtime.getKey()) > playtime.getValue() * playedHours().get())) {
try {
if (permission.playerAddGroup(null, event.getPlayer(), memberGroup().get())) {
event.getPlayer().sendMessage("§bYou are a member now. YEEHAW");
MainPlugin.Instance.getLogger().info("Added " + event.getPlayer().getName() + " as a member.");
} else {
MainPlugin.Instance.getLogger().warning("Failed to assign the member role! Please make sure the member group exists or disable the component if it's unused.");
}
} catch (UnsupportedOperationException e) {
MainPlugin.Instance.getLogger().warning("Failed to assign the member role! Groups are not supported by the permissions implementation.");
}
}
}

View file

@ -1,16 +1,20 @@
package buttondevteam.core.component.randomtp;
import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.chat.Command2;
import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.TBMCChatAPI;
import buttondevteam.lib.chat.TBMCCommandBase;
import buttondevteam.lib.chat.ICommand2MC;
import org.bukkit.*;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.logging.Logger;
// @formatter:off
@SuppressWarnings("FieldCanBeLocal")@CommandClass
public class RandomTP extends TBMCCommandBase
@SuppressWarnings("FieldCanBeLocal")@CommandClass(helpText = {
"§6---- Random Teleport ----",
"Teleport player to random location within world border. Every five players teleport to the same general area, and then a new general area is randomly selected for the next five players."
})
public class RandomTP extends ICommand2MC
{
private final int radius = 70; //set how far apart the five teleport positions are
@ -51,37 +55,23 @@ public class RandomTP extends TBMCCommandBase
/*================================================================================================*/
public void onEnable(Component component)
public void onEnable(RandomTPComponent component)
{
System.out.println("Adding command");
TBMCChatAPI.AddCommand(component, this);
System.out.println("Getting world");
world = Bukkit.getWorld("World");
System.out.println("Getting border");
border = world.getWorldBorder();
System.out.println("Getting new location");
System.out.println("Success: "+newLocation()); //TODO: It takes 10-30 seconds to find a location (newLocation() was there)
Logger logger = component.getPlugin().getLogger();
logger.info("Getting new location");
if(border.getSize() > 100000)
logger.warning("World border is wide, it may take a minute...");
logger.info("Success: "+newLocation());
}
/*================================================================================================*/
public String[] GetHelpText(String alias)
@Command2.Subcommand
public boolean def(CommandSender sender, Player player)
{
return new String[]
{
"§6---- Random Teleport ----",
"Teleport player to random location within world border. Every five players teleport to the same general area, and then a new general area is randomly selected for the next five players."
};
}
/*================================================================================================*/
public boolean OnCommand(CommandSender sender, String command, String[] args)
{
if (args.length == 0) return false;
if (sender.isOp()) return rtp(Bukkit.getPlayer(args[0]));
if (sender.isOp()) return rtp(player);
else sender.sendMessage("§7 hmm, " + sender.getName() + "... " + sender.getName() + "... nope, no operator permissions.");

View file

@ -2,15 +2,20 @@ package buttondevteam.core.component.randomtp;
import buttondevteam.core.MainPlugin;
import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ComponentMetadata;
/**
* Teleport player to random location within world border.
* Every five players teleport to the same general area, and then a new general area is randomly selected for the next five players.
* Author: github.com/iiegit
*/
@ComponentMetadata(enabledByDefault = false)
public class RandomTPComponent extends Component<MainPlugin> {
@Override
protected void enable() {
new RandomTP().onEnable(this); //It registers it's command
var rtp = new RandomTP();
registerCommand(rtp);
rtp.onEnable(this);
}
@Override

View file

@ -1,22 +1,28 @@
package buttondevteam.core.component.restart;
import buttondevteam.core.component.channel.Channel;
import buttondevteam.lib.chat.Command2;
import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.ICommand2MC;
import buttondevteam.lib.chat.TBMCChatAPI;
import buttondevteam.lib.chat.TBMCCommandBase;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
@CommandClass(path = "primerestart", modOnly = true)
@CommandClass(path = "primerestart", modOnly = true, helpText = {
"§6---- Prime restart ----", //
"Restarts the server as soon as nobody is online.", //
"To be loud, type something after, like /primerestart lol (it doesn't matter what you write)", //
"To be silent, don't type anything" //
})
@RequiredArgsConstructor
public class PrimeRestartCommand extends TBMCCommandBase {
public class PrimeRestartCommand extends ICommand2MC {
private final RestartComponent component;
@Override
public boolean OnCommand(CommandSender sender, String alias, String[] args) {
loud = args.length > 0;
public void def(CommandSender sender, @Command2.TextArg @Command2.OptionalArg String somethingrandom) {
loud = somethingrandom != null;
if (Bukkit.getOnlinePlayers().size() > 0) {
sender.sendMessage("§bPlayers online, restart delayed.");
if (loud)
@ -28,21 +34,10 @@ public class PrimeRestartCommand extends TBMCCommandBase {
TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, "§cNobody is online. Restarting server.", component.getRestartBroadcast());
Bukkit.spigot().restart();
}
return true;
}
@Getter
private static boolean plsrestart = false;
@Getter
private static boolean loud = false;
@Override
public String[] GetHelpText(String alias) {
return new String[]{ //
"§6---- Prime restart ----", //
"Restarts the server as soon as nobody is online.", //
"To be loud, type something after, like /primerestart lol (it doesn't matter what you write)", //
"To be silent, don't type anything" //
};
}
}

View file

@ -20,7 +20,7 @@ public class RestartComponent extends Component<MainPlugin> implements Listener
@Override
public void enable() {
registerCommand(new ScheduledRestartCommand(this));
TBMCChatAPI.AddCommand(this, new PrimeRestartCommand(this));
registerCommand(new PrimeRestartCommand(this));
registerListener(this);
restartBroadcast = TBMCSystemChatEvent.BroadcastTarget.add("restartCountdown");
}

View file

@ -6,6 +6,7 @@ import buttondevteam.lib.architecture.ConfigData;
import buttondevteam.lib.chat.Command2;
import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.ICommand2MC;
import com.earth2me.essentials.Trade;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
@ -13,10 +14,15 @@ import com.onarandombox.MultiverseCore.MultiverseCore;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.plugin.messaging.PluginMessageListener;
import java.io.*;
import java.math.BigDecimal;
/**
* Provides a /spawn command that works with BungeeCord. Make sure to set up on each server.
*/
public class SpawnComponent extends Component<MainPlugin> implements PluginMessageListener {
@Override
protected void enable() {
@ -69,7 +75,7 @@ public class SpawnComponent extends Component<MainPlugin> implements PluginMessa
}
/**
* Set to empty if this server is the target.
* The BungeeCord server that has the spawn. Set to empty if this server is the target.
*/
private ConfigData<String> targetServer() {
return getConfig().getData("targetServer", "");
@ -86,8 +92,16 @@ public class SpawnComponent extends Component<MainPlugin> implements PluginMessa
@Command2.Subcommand
public void def(Player player) {
if (targetServer().get().length() == 0) {
player.sendMessage("§bTeleporting to spawn.");
player.sendMessage("§bTeleporting to spawn...");
try {
if (MainPlugin.ess != null)
MainPlugin.ess.getUser(player).getTeleport()
.teleport(spawnloc, new Trade(BigDecimal.ZERO, MainPlugin.ess), PlayerTeleportEvent.TeleportCause.COMMAND);
else
player.teleport(spawnloc);
} catch (Exception e) {
player.sendMessage("§cFailed to teleport: " + e);
}
return;
}
ByteArrayDataOutput out = ByteStreams.newDataOutput();

View file

@ -31,7 +31,9 @@ public class TownyComponent extends Component<MainPlugin> {
*/
public static void renameInTowny(String oldName, String newName) {
if (!ComponentManager.isEnabled(TownyComponent.class))
return; TownyUniverse tu = Towny.getPlugin(Towny.class).getTownyUniverse();
return;
Bukkit.getLogger().info("Renaming" + oldName + " in Towny to " + newName);
TownyUniverse tu = Towny.getPlugin(Towny.class).getTownyUniverse();
Resident resident = tu.getResidentMap().get(oldName.toLowerCase()); //The map keys are lowercase
if (resident == null) {
Bukkit.getLogger().warning("Resident not found - couldn't rename in Towny.");
@ -42,6 +44,7 @@ public class TownyComponent extends Component<MainPlugin> {
} else
try {
tu.getDataSource().renamePlayer(resident, newName); //Fixed in Towny 0.91.1.2
Bukkit.getLogger().info("Renaming done.");
} catch (AlreadyRegisteredException e) {
TBMCCoreAPI.SendException("Failed to rename resident, there's already one with this name.", e);
} catch (NotRegisteredException e) {

View file

@ -2,15 +2,16 @@ package buttondevteam.core.component.updater;
import buttondevteam.core.MainPlugin;
import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.chat.TBMCChatAPI;
import buttondevteam.lib.architecture.ComponentMetadata;
/**
* Downloads plugin updates built from their source using JitPack - older code
* Downloads plugin updates built from their source using JitPack - doesn't work anymore
*/
@ComponentMetadata(enabledByDefault = false)
public class PluginUpdaterComponent extends Component<MainPlugin> { //TODO: Config
@Override
public void enable() {
TBMCChatAPI.AddCommand(this, new UpdatePluginCommand());
registerCommand(new UpdatePluginCommand());
}
@Override

View file

@ -2,40 +2,41 @@ package buttondevteam.core.component.updater;
import buttondevteam.core.MainPlugin;
import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.chat.Command2;
import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.TBMCCommandBase;
import buttondevteam.lib.chat.ICommand2MC;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import java.lang.reflect.Method;
@CommandClass(modOnly = true)
public class UpdatePluginCommand extends TBMCCommandBase {
@Override
public boolean OnCommand(CommandSender sender, String alias, String[] args) {
public class UpdatePluginCommand extends ICommand2MC {
public void def(CommandSender sender, @Command2.OptionalArg String plugin, @Command2.OptionalArg String branch) {
Bukkit.getScheduler().runTaskAsynchronously(MainPlugin.Instance, () -> {
if (args.length == 0) {
if (plugin == null) {
sender.sendMessage("Downloading plugin names...");
boolean first = true;
for (String plugin : PluginUpdater.GetPluginNames()) {
for (String plugin2 : PluginUpdater.GetPluginNames()) {
if (first) {
sender.sendMessage("§6---- Plugin names ----");
first = false;
}
sender.sendMessage("- " + plugin);
sender.sendMessage("- " + plugin2);
}
} else {
TBMCCoreAPI.UpdatePlugin(args[0], sender, args.length == 1 ? "master" : args[1]);
TBMCCoreAPI.UpdatePlugin(plugin, sender, branch == null ? "master" : branch);
}
});
return true;
}
@Override
public String[] GetHelpText(String alias) {
return new String[] { //
public String[] getHelpText(Method method, Command2.Subcommand ann) {
return new String[]{ //
"§6---- Update plugin ----", //
"This command downloads the latest version of a TBMC plugin from GitHub", //
"To update a plugin: /" + alias + " <plugin>", //
"To list the plugin names: /" + alias //
"This command downloads the latest version of a custom plugin from GitHub", //
"To update a plugin: add its name", //
"To list the plugin names: don't type a name" //
};
}
}

View file

@ -2,6 +2,7 @@ package buttondevteam.core.component.votifier;
import buttondevteam.core.MainPlugin;
import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ComponentMetadata;
import buttondevteam.lib.architecture.ConfigData;
import com.vexsoftware.votifier.model.Vote;
import com.vexsoftware.votifier.model.VotifierEvent;
@ -15,6 +16,7 @@ import org.bukkit.event.EventHandler;
* Do not use (EULA)
*/
@RequiredArgsConstructor
@ComponentMetadata(enabledByDefault = false)
public class VotifierComponent extends Component<MainPlugin> {
private final Economy economy;
@ -39,11 +41,11 @@ public class VotifierComponent extends Component<MainPlugin> {
getPlugin().getLogger().info("Vote: " + vote);
org.bukkit.OfflinePlayer op = Bukkit.getOfflinePlayer(vote.getUsername());
Player p = Bukkit.getPlayer(vote.getUsername());
if (op != null) {
/*if (op != null) {
economy.depositPlayer(op, rewardAmount().get());
}
if (p != null) {
p.sendMessage("§bThanks for voting! $50 was added to your account.");
}
}*/
}
}

View file

@ -1,34 +1,41 @@
package buttondevteam.lib.architecture;
import buttondevteam.buttonproc.HasConfig;
import buttondevteam.core.ComponentManager;
import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.chat.Command2MC;
import buttondevteam.lib.chat.TBMCChatAPI;
import lombok.AccessLevel;
import lombok.Getter;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.Optional;
import java.util.Stack;
@HasConfig
@HasConfig(global = true)
public abstract class ButtonPlugin extends JavaPlugin {
@Getter
private static Command2MC command2MC = new Command2MC();
@Getter(AccessLevel.PROTECTED)
private IHaveConfig iConfig;
private CommentedConfiguration yaml;
@Getter(AccessLevel.PROTECTED)
private IHaveConfig data; //TODO
private boolean loaded = false;
/**
* Used to unregister components in the right order - and to reload configs
*/
@Getter
private Stack<Component<?>> componentStack = new Stack<>();
;
protected abstract void pluginEnable();
@ -45,7 +52,10 @@ public abstract class ButtonPlugin extends JavaPlugin {
@Override
public final void onEnable() {
loadConfig();
if (!loadConfig()) {
getLogger().warning("Please fix the issues and restart the server to load the plugin.");
return;
}
try {
pluginEnable();
} catch (Exception e) {
@ -55,10 +65,14 @@ public abstract class ButtonPlugin extends JavaPlugin {
IHaveConfig.pregenConfig(this, null);
}
private void loadConfig() {
var section = super.getConfig().getConfigurationSection("global");
if (section == null) section = super.getConfig().createSection("global");
private boolean loadConfig() {
var config = getConfig();
if (config == null)
return false;
var section = config.getConfigurationSection("global");
if (section == null) section = config.createSection("global");
iConfig = new IHaveConfig(section, this::saveConfig);
return true;
}
@Override
@ -67,9 +81,10 @@ public abstract class ButtonPlugin extends JavaPlugin {
pluginPreDisable();
ComponentManager.unregComponents(this);
pluginDisable();
saveConfig();
if (ConfigData.saveNow(getConfig()))
getLogger().info("Saved configuration changes.");
iConfig = null; //Clearing the hashmap is not enough, we need to update the section as well
TBMCChatAPI.RemoveCommands(this);
//TBMCChatAPI.RemoveCommands(this); - TODO
} catch (Exception e) {
TBMCCoreAPI.SendException("Error while disabling plugin " + getName() + "!", e);
}
@ -88,13 +103,48 @@ public abstract class ButtonPlugin extends JavaPlugin {
}
public boolean justReload() {
if (loaded && ConfigData.saveNow(getConfig())) {
getLogger().warning("Saved pending configuration changes to the file, didn't reload (try again).");
if (yaml != null && ConfigData.saveNow(getConfig())) {
getLogger().warning("Saved pending configuration changes to the file, didn't reload. Apply your changes again.");
return false;
}
super.reloadConfig();
loaded = true; //Needed because for the first time it uses reloadConfig() to load it
var file = new File(getDataFolder(), "config.yml");
var yaml = new CommentedConfiguration(file);
if (file.exists()) {
try {
yaml.load(file);
} catch (IOException | InvalidConfigurationException e) {
getLogger().warning("Failed to load config! Check for syntax errors.");
e.printStackTrace();
return false;
}
}
this.yaml = yaml;
var res = getTextResource("configHelp.yml");
if (res == null)
return true;
var yc = YamlConfiguration.loadConfiguration(res);
for (var kv : yc.getValues(true).entrySet())
if (kv.getValue() instanceof String)
yaml.addComment(kv.getKey(), Arrays.stream(((String) kv.getValue()).split("\n"))
.map(str -> "# " + str.trim()).toArray(String[]::new));
return true;
}
@Override
public FileConfiguration getConfig() {
if (yaml == null)
justReload(); //TODO: If it fails to load, it'll probably throw an NPE
return yaml;
}
@Override
public void saveConfig() {
try {
if (yaml != null)
yaml.save();
} catch (Exception e) {
TBMCCoreAPI.SendException("Failed to save config", e);
}
}
@Retention(RetentionPolicy.RUNTIME)

View file

@ -0,0 +1,228 @@
package buttondevteam.lib.architecture;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.configuration.file.YamlConstructor;
import org.bukkit.configuration.file.YamlRepresenter;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.representer.Representer;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.HashMap;
/**
* A copy of Towny's CommentedConfiguration: https://github.com/TownyAdvanced/Towny/blob/master/src/com/palmergames/bukkit/config/CommentedConfiguration.java
* Modified to remove dependency on the FileMgmt class
*
* @author dumptruckman &amp; Articdive
*/
public class CommentedConfiguration extends YamlConfiguration { //TODO: Remove FileMgmt dependency
private HashMap<String, String> comments;
private File file;
private final DumperOptions yamlOptions = new DumperOptions();
private final Representer yamlRepresenter = new YamlRepresenter();
private final Yaml yaml = new Yaml(new YamlConstructor(), yamlRepresenter, yamlOptions);
public CommentedConfiguration(File file) {
super();
comments = new HashMap<>();
this.file = file;
}
public boolean load() {
boolean loaded = true;
try {
this.load(file);
} catch (InvalidConfigurationException | IOException e) {
loaded = false;
}
return loaded;
}
public void save() throws IOException {
boolean saved = true;
// Save the config just like normal
try {
this.save(file);
} catch (Exception e) {
saved = false;
}
// if there's comments to add and it saved fine, we need to add comments
if (!comments.isEmpty() && saved) {
// String array of each line in the config file
String[] yamlContents = Files.readAllLines(file.toPath()).toArray(new String[0]);
// This will hold the newly formatted line
StringBuilder newContents = new StringBuilder();
// This holds the current path the lines are at in the config
String currentPath = "";
// This flags if the line is a node or unknown text.
boolean node;
// The depth of the path. (number of words separated by periods - 1)
int depth = 0;
// Loop through the config lines
for (String line : yamlContents) {
// If the line is a node (and not something like a list value)
if (line.contains(": ") || (line.length() > 1 && line.charAt(line.length() - 1) == ':')) {
// This is a node so flag it as one
node = true;
// Grab the index of the end of the node name
int index;
index = line.indexOf(": ");
if (index < 0) {
index = line.length() - 1;
}
// If currentPath is empty, store the node name as the currentPath. (this is only on the first iteration, i think)
if (currentPath.isEmpty()) {
currentPath = line.substring(0, index);
} else {
// Calculate the whitespace preceding the node name
int whiteSpace = 0;
for (int n = 0; n < line.length(); n++) {
if (line.charAt(n) == ' ') {
whiteSpace++;
} else {
break;
}
}
// Find out if the current depth (whitespace * 2) is greater/lesser/equal to the previous depth
if (whiteSpace / 2 > depth) {
// Path is deeper. Add a . and the node name
currentPath += "." + line.substring(whiteSpace, index);
depth++;
} else if (whiteSpace / 2 < depth) {
// Path is shallower, calculate current depth from whitespace (whitespace / 2) and subtract that many levels from the currentPath
int newDepth = whiteSpace / 2;
for (int i = 0; i < depth - newDepth; i++) {
currentPath = currentPath.replace(currentPath.substring(currentPath.lastIndexOf(".")), "");
}
// Grab the index of the final period
int lastIndex = currentPath.lastIndexOf(".");
if (lastIndex < 0) {
// if there isn't a final period, set the current path to nothing because we're at root
currentPath = "";
} else {
// If there is a final period, replace everything after it with nothing
currentPath = currentPath.replace(currentPath.substring(currentPath.lastIndexOf(".")), "");
currentPath += ".";
}
// Add the new node name to the path
currentPath += line.substring(whiteSpace, index);
// Reset the depth
depth = newDepth;
} else {
// Path is same depth, replace the last path node name to the current node name
int lastIndex = currentPath.lastIndexOf(".");
if (lastIndex < 0) {
// if there isn't a final period, set the current path to nothing because we're at root
currentPath = "";
} else {
// If there is a final period, replace everything after it with nothing
currentPath = currentPath.replace(currentPath.substring(currentPath.lastIndexOf(".")), "");
currentPath += ".";
}
//currentPath = currentPath.replace(currentPath.substring(currentPath.lastIndexOf(".")), "");
currentPath += line.substring(whiteSpace, index);
}
}
} else {
node = false;
}
if (node) {
// If there's a comment for the current path, retrieve it and flag that path as already commented
String comment = comments.get(currentPath);
if (comment != null) {
// Add the comment to the beginning of the current line
line = comment + System.getProperty("line.separator") + line + System.getProperty("line.separator");
} else {
// Add a new line as it is a node, but has no comment
line += System.getProperty("line.separator");
}
}
// Add the (modified) line to the total config String
if (!node) {
newContents.append(line).append(System.getProperty("line.separator"));
} else {
newContents.append(line);
}
}
/*
* Due to a Bukkit Bug with the Configuration
* we just need to remove any extra comments at the start of a file.
*/
while (newContents.toString().startsWith(" " + System.getProperty("line.separator"))) {
newContents = new StringBuilder(newContents.toString().replaceFirst(" " + System.getProperty("line.separator"), ""));
}
Files.write(file.toPath(), newContents.toString().getBytes());
}
}
/**
* Adds a comment just before the specified path. The comment can be
* multiple lines. An empty string will indicate a blank line.
*
* @param path Configuration path to add comment.
* @param commentLines Comments to add. One String per line.
*/
public void addComment(String path, String... commentLines) {
StringBuilder commentstring = new StringBuilder();
StringBuilder leadingSpaces = new StringBuilder();
for (int n = 0; n < path.length(); n++) {
if (path.charAt(n) == '.') {
leadingSpaces.append(" ");
}
}
for (String line : commentLines) {
if (!line.isEmpty()) {
line = leadingSpaces + line;
} else {
line = " ";
}
if (commentstring.length() > 0) {
commentstring.append(System.getProperty("line.separator"));
}
commentstring.append(line);
}
comments.put(path, commentstring.toString());
}
@Override
public String saveToString() {
yamlOptions.setIndent(options().indent());
yamlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
yamlOptions.setWidth(10000);
yamlRepresenter.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
String dump = yaml.dump(getValues(false));
if (dump.equals(BLANK_CONFIG)) {
dump = "";
}
return dump;
}
}

View file

@ -1,11 +1,10 @@
package buttondevteam.lib.architecture;
import buttondevteam.buttonproc.HasConfig;
import buttondevteam.core.ComponentManager;
import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.exceptions.UnregisteredComponentException;
import buttondevteam.lib.chat.ICommand2MC;
import buttondevteam.lib.chat.TBMCChatAPI;
import buttondevteam.lib.chat.TBMCCommandBase;
import lombok.Getter;
import lombok.NonNull;
import lombok.val;
@ -16,13 +15,14 @@ import org.bukkit.plugin.java.JavaPlugin;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
* Configuration is based on class name
*/
@HasConfig //Used for obtaining javadoc
@HasConfig(global = false) //Used for obtaining javadoc
public abstract class Component<TP extends JavaPlugin> {
private static HashMap<Class<? extends Component>, Component<? extends JavaPlugin>> components = new HashMap<>();
@ -37,7 +37,7 @@ public abstract class Component<TP extends JavaPlugin> {
private @Getter IHaveConfig data; //TODO
public final ConfigData<Boolean> shouldBeEnabled() {
return config.getData("enabled", true);
return config.getData("enabled", Optional.ofNullable(getClass().getAnnotation(ComponentMetadata.class)).map(ComponentMetadata::enabledByDefault).orElse(true));
}
/**
@ -141,8 +141,7 @@ public abstract class Component<TP extends JavaPlugin> {
//System.out.println("Done enabling "+component.getClassName());
} else {
component.disable();
component.plugin.saveConfig();
TBMCChatAPI.RemoveCommands(component);
//TBMCChatAPI.RemoveCommands(component); - TODO
}
}
@ -212,15 +211,6 @@ public abstract class Component<TP extends JavaPlugin> {
ButtonPlugin.getCommand2MC().registerCommand(commandBase);
}
/**
* Registers a TBMCCommand to the component. Make sure to add it to plugin.yml and use {@link buttondevteam.lib.chat.CommandClass}.
*
* @param commandBase Custom coded command class
*/
protected final void registerCommand(TBMCCommandBase commandBase) {
TBMCChatAPI.AddCommand(this, commandBase);
}
/**
* Registers a Listener to this component
*

View file

@ -9,4 +9,6 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentMetadata {
Class<? extends Component>[] depends() default {};
boolean enabledByDefault() default true;
}

View file

@ -15,7 +15,7 @@ import org.bukkit.scheduler.BukkitTask;
import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;
/**
@ -32,7 +32,7 @@ public class ConfigData<T> {
@Getter
@Setter(AccessLevel.PACKAGE)
private String path;
private final T def;
protected final T def;
private final Object primitiveDef;
private final Runnable saveAction;
/**
@ -48,10 +48,6 @@ public class ConfigData<T> {
* The config value should not change outside this instance
*/
private T value;
/**
* Whether the default value is saved in the yaml
*/
private boolean saved = false;
//This constructor is needed because it sets the getter and setter
ConfigData(ConfigurationSection config, String path, T def, Object primitiveDef, Function<Object, T> getter, Function<T, Object> setter, Runnable saveAction) {
@ -84,27 +80,35 @@ public class ConfigData<T> {
@SuppressWarnings("unchecked")
public T get() {
if (value != null) return value; //Speed things up
Object val = config == null ? null : config.get(path); //config==null: testing
if (val == null) {
Object val;
if (config == null || !config.isSet(path)) { //Call set() if config == null
val = primitiveDef;
}
if (!saved && Objects.equals(val, primitiveDef)) { //String needs .equals()
if ((def == null || this instanceof ReadOnlyConfigData) && config != null) //In Discord's case def may be null
config.set(path, primitiveDef);
setInternal(primitiveDef); //If read-only then we still need to save the default value so it can be set
else
set(def); //Save default value - def is always set
saved = true;
}
} else
val = config.get(path); //config==null: testing
if (val == null) //If it's set to null explicitly
val = primitiveDef;
BiFunction<Object, Object, Object> convert = (_val, _def) -> {
if (_def instanceof Number) //If we expect a number
if (_val instanceof Number)
_val = ChromaUtils.convertNumber((Number) _val,
(Class<? extends Number>) _def.getClass());
else
_val = _def; //If we didn't get a number, return default (which is a number)
else if (_val instanceof List && _def != null && _def.getClass().isArray())
_val = ((List<T>) _val).toArray((T[]) Array.newInstance(_def.getClass().getComponentType(), 0));
return _val;
};
if (getter != null) {
val = convert.apply(val, primitiveDef);
T hmm = getter.apply(val);
if (hmm == null) hmm = def; //Set if the getter returned null
return hmm;
}
if (val instanceof Number && def != null)
val = ChromaUtils.convertNumber((Number) val,
(Class<? extends Number>) def.getClass());
if (val instanceof List && def != null && def.getClass().isArray())
val = ((List<T>) val).toArray((T[]) Array.newInstance(def.getClass().getComponentType(), 0));
val = convert.apply(val, def);
return value = (T) val; //Always cache, if not cached yet
}
@ -115,7 +119,12 @@ public class ConfigData<T> {
if (setter != null && value != null)
val = setter.apply(value);
else val = value;
if (config != null) {
if (config != null)
setInternal(val);
this.value = value;
}
private void setInternal(Object val) {
config.set(path, val);
if (!saveTasks.containsKey(config.getRoot())) {
synchronized (saveTasks) {
@ -128,8 +137,6 @@ public class ConfigData<T> {
}
}
}
this.value = value;
}
@AllArgsConstructor
private static class SaveTask {
@ -138,6 +145,7 @@ public class ConfigData<T> {
}
public static boolean saveNow(Configuration config) {
synchronized (saveTasks) {
SaveTask st = saveTasks.get(config);
if (st != null) {
st.task.cancel();
@ -145,6 +153,7 @@ public class ConfigData<T> {
st.saveAction.run();
return true;
}
}
return false;
}
}

View file

@ -139,6 +139,21 @@ public final class IHaveConfig {
return (ConfigData<T>) data;
}
/**
* This method overload should only be used with primitves or String.
*
* @param path The path in config to use
* @param <T> The type of this variable (only use primitives or String)
* @return The data object that can be used to get or set the value
*/
@SuppressWarnings("unchecked")
public <T> ListConfigData<T> getListData(String path) {
ConfigData<?> data = datamap.get(path);
if (data == null)
datamap.put(path, data = new ListConfigData<>(config, path, new ListConfigData.List<T>(), saveAction));
return (ListConfigData<T>) data;
}
/**
* Generates the config YAML.
*

View file

@ -0,0 +1,125 @@
package buttondevteam.lib.architecture;
import lombok.val;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
public class ListConfigData<T> extends ConfigData<ListConfigData.List<T>> {
@SuppressWarnings("unchecked")
ListConfigData(ConfigurationSection config, String path, List<T> def, Runnable saveAction) {
super(config, path, def, new ArrayList<>(def), list -> {
var l = new List<>((ArrayList<T>) list);
l.listConfig = def.listConfig;
return l;
}, ArrayList::new, saveAction);
def.listConfig = this; //Can't make the List class non-static or pass this in the super() constructor
}
public static class List<T> extends ArrayList<T> {
private ListConfigData<T> listConfig;
public List(@NotNull Collection<? extends T> c) {
super(c);
}
public List() {
}
private void update() {
listConfig.set(this); //Update the config model and start save task if needed
}
@Override
public T set(int index, T element) {
T ret = super.set(index, element);
update();
return ret;
}
@Override
public boolean add(T t) {
val ret = super.add(t);
update();
return ret;
}
@Override
public void add(int index, T element) {
super.add(index, element);
update();
}
@Override
public T remove(int index) {
T ret = super.remove(index);
update();
return ret;
}
@Override
public boolean remove(Object o) {
val ret = super.remove(o);
update();
return ret;
}
@Override
public boolean addAll(Collection<? extends T> c) {
val ret = super.addAll(c);
update();
return ret;
}
@Override
public boolean addAll(int index, Collection<? extends T> c) {
val ret = super.addAll(index, c);
update();
return ret;
}
@Override
protected void removeRange(int fromIndex, int toIndex) {
super.removeRange(fromIndex, toIndex);
update();
}
@Override
public boolean removeAll(Collection<?> c) {
val ret = super.removeAll(c);
update();
return ret;
}
@Override
public boolean retainAll(Collection<?> c) {
val ret = super.retainAll(c);
update();
return ret;
}
@Override
public boolean removeIf(Predicate<? super T> filter) {
val ret = super.removeIf(filter);
update();
return ret;
}
@Override
public void replaceAll(UnaryOperator<T> operator) {
super.replaceAll(operator);
update();
}
@Override
public void sort(Comparator<? super T> c) {
super.sort(c);
update();
}
}
}

View file

@ -135,7 +135,7 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
try {
handleCommandAsync(sender, commandline, sd, subcommand, sync);
} catch (Exception e) {
TBMCCoreAPI.SendException("Command execution failed for sender " + sender + " and message " + commandline, e);
TBMCCoreAPI.SendException("Command execution failed for sender " + sender.getName() + "(" + sender.getClass().getCanonicalName() + ") and message " + commandline, e);
}
});
return true; //We found a method
@ -144,6 +144,17 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
}
//Needed because permission checking may load the (perhaps offline) sender's file which is disallowed on the main thread
/**
* Handles a command asynchronously
*
* @param sender The command sender
* @param commandline The command line the sender sent
* @param sd The subcommand data
* @param subcommand The subcommand text
* @param sync Whether the command was originally sync
* @throws Exception If something's not right
*/
public void handleCommandAsync(TP sender, String commandline, SubcommandData<TC> sd, String subcommand, boolean sync) throws Exception {
if (sd.method == null || sd.command == null) { //Main command not registered, but we have subcommands
sender.sendMessage(sd.helpText);
@ -247,7 +258,7 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
public abstract void registerCommand(TC command);
protected void registerCommand(TC command, char commandChar) {
protected void registerCommand(TC command, @SuppressWarnings("SameParameterValue") char commandChar) {
val path = command.getCommandPath();
int x = path.indexOf(' ');
val mainPath = commandChar + path.substring(0, x == -1 ? path.length() : x);
@ -277,7 +288,7 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
if (ht != null) {
val subcommand = commandChar + path + //Add command path (class name by default)
(method.getName().equals("def") ? "" : " " + method.getName().replace('_', ' ').toLowerCase()); //Add method name, unless it's 'def'
ht = getHelpText(method, ht, subcommand);
ht = getParameterHelp(method, ht, subcommand);
subcommands.put(subcommand, new SubcommandData<>(method, command, ht)); //Result of the above (def) is that it will show the help text
scmdHelpList.add(subcommand);
nosubs = false;
@ -299,7 +310,7 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
}
}
private String[] getHelpText(Method method, String[] ht, String subcommand) {
private String[] getParameterHelp(Method method, String[] ht, String subcommand) {
val str = method.getDeclaringClass().getResourceAsStream("/commands.yml");
if (str == null)
TBMCCoreAPI.SendException("Error while getting command data!", new Exception("Resource not found!"));

View file

@ -6,6 +6,7 @@ import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.server.TabCompleteEvent;
@ -16,7 +17,6 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.UUID;
import java.util.function.Function;
public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implements Listener {
@ -26,7 +26,7 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
var perm = "chroma.command." + command.getCommandPath().replace(' ', '.');
if (Bukkit.getPluginManager().getPermission(perm) == null) //Check needed for plugin reset
Bukkit.getPluginManager().addPermission(new Permission(perm,
modOnly(command) ? PermissionDefault.OP : PermissionDefault.TRUE)); //Allow commands by default, unless it's mod only - TODO: Test
PermissionDefault.TRUE)); //Allow commands by default, it will check mod-only
for (val method : command.getClass().getMethods()) {
if (!method.isAnnotationPresent(Subcommand.class)) continue;
String pg = permGroup(command, method);
@ -34,7 +34,6 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
perm = "chroma." + pg;
if (Bukkit.getPluginManager().getPermission(perm) == null) //It may occur multiple times
Bukkit.getPluginManager().addPermission(new Permission(perm,
//pg.equals(Subcommand.MOD_GROUP) ? PermissionDefault.OP : PermissionDefault.TRUE)); //Allow commands by default, unless it's mod only
PermissionDefault.OP)); //Do not allow any commands that belong to a group
}
}
@ -50,16 +49,18 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
boolean p = true;
String[] perms = {
"chroma.command." + command.getCommandPath().replace(' ', '.'),
(pg = permGroup(command, method)).length() > 0 ? "chroma." + pg : null,
modOnly(command) ? "tbmc.admin" : null
(pg = permGroup(command, method)).length() > 0 ? "chroma." + pg : null
};
for (String perm : perms) {
if (perm != null) {
if (p) { //Use OfflinePlayer to avoid fetching player data
if (sender instanceof OfflinePlayer)
p = MainPlugin.permission.playerHas(null, (OfflinePlayer) sender, perm);
p = MainPlugin.permission.playerHas(sender instanceof Player ? ((Player) sender).getLocation().getWorld().getName() : null, (OfflinePlayer) sender, perm);
else
p = MainPlugin.permission.playerHas(null, Bukkit.getOfflinePlayer(new UUID(0, 0)), perm);
p = false; //Use sender's method
//System.out.println("playerHas " + perm + ": " + p);
//System.out.println("hasPermission: " + sender.hasPermission(perm));
if (!p) p = sender.hasPermission(perm);
} else break; //If any of the permissions aren't granted then don't allow
}
}
@ -67,17 +68,7 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
}
/**
* Returns true if this class or <u>any</u> of the superclasses are mod only.
*
* @param command The command to check
* @return Whether the command is mod only
*/
private boolean modOnly(ICommand2MC command) {
return getAnnForValue(command.getClass(), CommandClass.class, CommandClass::modOnly, false);
}
/**
* Returns true if this class or <u>any</u> of the superclasses are mod only.
* Returns the first group found in the hierarchy starting from the command method <b>or</b> the mod group if <i>any</i></i> of the superclasses are mod only.
*
* @param method The subcommand to check
* @return The permission group for the subcommand or empty string
@ -87,6 +78,8 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
if (sc != null && sc.permGroup().length() > 0) {
return sc.permGroup();
}
if (getAnnForValue(command.getClass(), CommandClass.class, CommandClass::modOnly, false))
return Subcommand.MOD_GROUP;
return getAnnForValue(command.getClass(), CommandClass.class, CommandClass::permGroup, "");
}

View file

@ -17,4 +17,9 @@ public class Command2MCSender implements Command2Sender {
public void sendMessage(String[] message) {
sender.sendMessage(message);
}
@Override
public String getName() {
return sender.getName();
}
}

View file

@ -4,4 +4,6 @@ public interface Command2Sender { //We don't need the 'extras' of CommandSender
void sendMessage(String message);
void sendMessage(String[] message);
String getName();
}

View file

@ -73,7 +73,7 @@ public abstract class ICommand2<TP extends Command2Sender> {
String path = getClass().getAnnotation(CommandClass.class).path(),
prevpath = path = path.length() == 0 ? getFromClass.apply(getClass()) : path;
for (Class<?> cl = getClass().getSuperclass(); cl != null
&& !cl.getPackage().getName().equals(TBMCCommandBase.class.getPackage().getName()); cl = cl
&& !cl.getPackage().getName().equals(ICommand2MC.class.getPackage().getName()); cl = cl
.getSuperclass()) { //
String newpath;
if (!cl.isAnnotationPresent(CommandClass.class)

View file

@ -1,29 +0,0 @@
package buttondevteam.lib.chat;
import buttondevteam.lib.TBMCCoreAPI;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public abstract class OptionallyPlayerCommandBase extends TBMCCommandBase {
public boolean OnCommand(Player player, String alias, String[] args) {
if (getClass().isAnnotationPresent(OptionallyPlayerCommandClass.class)
&& getClass().getAnnotation(OptionallyPlayerCommandClass.class).playerOnly())
TBMCCoreAPI.SendException("Error while executing command " + getClass().getSimpleName() + "!",
new Exception(
"The PlayerCommand annotation is present and set to playerOnly but the Player overload isn't overriden!"));
return true;
}
@Override
public boolean OnCommand(CommandSender sender, String alias, String[] args) {
if (sender instanceof Player)
return OnCommand((Player) sender, alias, args);
if (!getClass().isAnnotationPresent(OptionallyPlayerCommandClass.class)
|| !getClass().getAnnotation(OptionallyPlayerCommandClass.class).playerOnly())
TBMCCoreAPI.SendException("Error while executing command " + getClass().getSimpleName() + "!",
new Exception(
"Command class doesn't override the CommandSender overload and no PlayerCommandClass annotation is present or playerOnly is false!"));
sender.sendMessage("§cYou need to be a player to use this command.");
return true;
}
}

View file

@ -1,16 +0,0 @@
package buttondevteam.lib.chat;
import java.lang.annotation.*;
/**
* Only needed to use with {@link OptionallyPlayerCommandBase} command classes
*
* @author NorbiPeti
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface OptionallyPlayerCommandClass {
boolean playerOnly();
}

View file

@ -1,16 +0,0 @@
package buttondevteam.lib.chat;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public abstract class PlayerCommandBase extends TBMCCommandBase {
public abstract boolean OnCommand(Player player, String alias, String[] args);
@Override
public final boolean OnCommand(CommandSender sender, String alias, String[] args) {
if (sender instanceof Player)
return OnCommand((Player) sender, alias, args);
sender.sendMessage("§cYou need to be a player to use this command.");
return true;
}
}

View file

@ -1,250 +1,19 @@
package buttondevteam.lib.chat;
import buttondevteam.core.CommandCaller;
import buttondevteam.core.MainPlugin;
import buttondevteam.core.component.channel.Channel;
import buttondevteam.core.component.channel.Channel.RecipientTestResult;
import buttondevteam.lib.*;
import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.ChromaUtils;
import buttondevteam.lib.TBMCChatEvent;
import buttondevteam.lib.TBMCChatPreprocessEvent;
import buttondevteam.lib.TBMCSystemChatEvent;
import lombok.val;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class TBMCChatAPI {
private static final HashMap<String, TBMCCommandBase> commands = new HashMap<>();
public static HashMap<String, TBMCCommandBase> GetCommands() {
return commands;
}
/**
* Returns messages formatted for Minecraft chat listing the subcommands of the command.
*
* @param command The command which we want the subcommands of
* @param sender The sender for permissions
* @return The subcommands
*/
public static String[] GetSubCommands(TBMCCommandBase command, CommandSender sender) {
return GetSubCommands(command.GetCommandPath(), sender);
}
/**
* Returns messages formatted for Minecraft chat listing the subcommands of the command.<br>
* Returns a header if subcommands were found, otherwise returns an empty array.
*
* @param command The command which we want the subcommands of
* @param sender The sender for permissions
* @return The subcommands
*/
public static String[] GetSubCommands(String command, CommandSender sender) {
ArrayList<String> cmds = new ArrayList<String>();
Consumer<String> addToCmds = cmd -> {
if (cmds.size() == 0)
cmds.add("§6---- Subcommands ----");
cmds.add(cmd);
};
for (Entry<String, TBMCCommandBase> cmd : TBMCChatAPI.GetCommands().entrySet()) {
if (cmd.getKey().startsWith(command + " ")) {
if (cmd.getValue().isPlayerOnly() && !(sender instanceof Player))
continue;
if (cmd.getValue().isModOnly() && (MainPlugin.permission != null ? !MainPlugin.permission.has(sender, "tbmc.admin") : !sender.isOp()))
continue;
int ind = cmd.getKey().indexOf(' ', command.length() + 2);
if (ind >= 0) {
String newcmd = cmd.getKey().substring(0, ind);
if (!cmds.contains("/" + newcmd))
addToCmds.accept("/" + newcmd);
} else
addToCmds.accept("/" + cmd.getKey());
}
}
return cmds.toArray(new String[0]); //Apparently it's faster to use an empty array in modern Java
}
/**
* <p>
* This method adds a plugin's commands to help and sets their executor.
* </p>
* <p>
* </p>
* <b>The command classes have to have a constructor each with no parameters</b>
* <p>
* The <u>command must be registered</u> in the caller plugin's plugin.yml. Otherwise the plugin will output a messsage to console.
* </p>
* <p>
* <i>Using this method after the server is done loading will have no effect.</i>
* </p>
*
* @param plugin The caller plugin
* @param acmdclass A command's class to get the package name for commands. The provided class's package and subpackages are scanned for commands.
*/
public static synchronized void AddCommands(JavaPlugin plugin, Class<? extends TBMCCommandBase> acmdclass) {
plugin.getLogger().info("Registering commands from " + acmdclass.getPackage().getName());
Reflections rf = new Reflections(new ConfigurationBuilder()
.setUrls(ClasspathHelper.forPackage(acmdclass.getPackage().getName(),
plugin.getClass().getClassLoader()))
.addUrls(
ClasspathHelper.forClass(OptionallyPlayerCommandBase.class,
OptionallyPlayerCommandBase.class.getClassLoader()),
ClasspathHelper.forClass(PlayerCommandBase.class, PlayerCommandBase.class.getClassLoader())) // http://stackoverflow.com/questions/12917417/using-reflections-for-finding-the-transitive-subtypes-of-a-class-when-not-all
.addClassLoader(plugin.getClass().getClassLoader()).addScanners(new SubTypesScanner()));
Set<Class<? extends TBMCCommandBase>> cmds = rf.getSubTypesOf(TBMCCommandBase.class);
for (Class<? extends TBMCCommandBase> cmd : cmds) {
try {
if (!cmd.getPackage().getName().startsWith(acmdclass.getPackage().getName()))
continue; // It keeps including the commands from here
if (Modifier.isAbstract(cmd.getModifiers()))
continue;
TBMCCommandBase c = cmd.newInstance();
c.plugin = plugin;
CommandCaller.RegisterCommand(c); //Will check for nulls
commands.put(c.GetCommandPath(), c);
} catch (Exception e) {
TBMCCoreAPI.SendException("An error occured while registering command " + cmd.getName(), e);
}
}
}
/**
* <p>
* This method adds a plugin's command to help and sets it's executor. They will be automatically unregistered on plugin disable.
* </p>
* <p>
* The <u>command must be registered</u> in the caller plugin's plugin.yml. Otherwise the plugin will output a messsage to console.
* </p>
* <p>
* <i>Using this method after the server is done loading will have no effect.</i>
* </p>
*
* @param plugin The caller plugin
* @param thecmdclass The command's class to create it (because why let you create the command class)
*/
public static void AddCommand(JavaPlugin plugin, Class<? extends TBMCCommandBase> thecmdclass, Object... params) {
// plugin.getLogger().info("Registering command " + thecmdclass.getSimpleName() + " for " + plugin.getName());
try {
TBMCCommandBase c;
if (params.length > 0)
c = thecmdclass.getConstructor(Arrays.stream(params).map(Object::getClass).toArray(Class[]::new))
.newInstance(params);
else
c = thecmdclass.newInstance();
c.plugin = plugin;
CommandCaller.RegisterCommand(c); //Will check for nulls
commands.put(c.GetCommandPath(), c);
} catch (Exception e) {
TBMCCoreAPI.SendException("An error occured while registering command " + thecmdclass.getSimpleName(), e);
}
}
/**
* <p>
* This method adds a plugin's command to help and sets its executor. They will be automatically unregistered on plugin disable.
* </p>
* <p>
* The <u>command must be registered</u> in the caller plugin's plugin.yml. Otherwise the plugin will output a message to console.
* </p>
* <p>
* <i>Using this method after the server is done loading will have no effect.</i>
* </p>
*
* @param plugin The caller plugin
* @param cmd The command to add
*/
public static void AddCommand(JavaPlugin plugin, TBMCCommandBase cmd) {
try {
if (plugin == null) throw new IllegalArgumentException("The plugin is null!");
if (cmd == null) throw new IllegalArgumentException("The command is null!");
cmd.plugin = plugin;
CommandCaller.RegisterCommand(cmd); //Checks for other nulls
commands.put(cmd.GetCommandPath(), cmd);
} catch (Exception e) {
TBMCCoreAPI.SendException("An error occured while registering command " + (cmd == null ? "n u l l" : cmd.GetCommandPath()), e);
}
}
/**
* <p>
* This method adds a plugin's command to help and sets its executor. They will be automatically unregistered on component disable.
* </p>
* <p>
* The <u>command must be registered</u> in the caller plugin's plugin.yml. Otherwise the plugin will output a message to console.
* </p>
* <p>
* <i>Using this method after the server is done loading will have no effect.</i>
* </p>
*
* @param component The caller component
* @param cmd The command to add
*/
public static void AddCommand(Component component, TBMCCommandBase cmd) {
try {
if (component == null) throw new IllegalArgumentException("The component is null!");
if (cmd == null) throw new IllegalArgumentException("The command is null!");
cmd.plugin = component.getPlugin();
cmd.component = component;
CommandCaller.RegisterCommand(cmd); //Checks for other nulls
commands.put(cmd.GetCommandPath(), cmd);
} catch (Exception e) {
TBMCCoreAPI.SendException("An error occured while registering command " + (cmd == null ? "n u l l" : cmd.GetCommandPath()), e);
}
}
/**
* Removes all commands from the plugin
*
* @param plugin The plugin to remove commands from
*/
public static void RemoveCommands(JavaPlugin plugin) {
commands.values().removeIf(c -> {
try {
if (c.plugin == plugin) {
CommandCaller.UnregisterCommand(c);
return true; //Remove
}
return false;
} catch (Exception e) {
TBMCCoreAPI.SendException("An error occured while unregistering commands for " + plugin.getName(), e);
return true; //Remove if it couldn't get the plugin command
}
});
}
/**
* Removes all commands from the component
*
* @param component The component to remove commands from
*/
public static void RemoveCommands(Component component) {
commands.values().removeIf(c -> {
try {
if (c.component == component) {
CommandCaller.UnregisterCommand(c);
return true; //Remove
}
return false;
} catch (Exception e) {
TBMCCoreAPI.SendException("An error occured while unregistering commands for " + component.getClass().getSimpleName(), e);
return true; //Remove if it couldn't get the plugin command
}
});
}
/**
* Sends a chat message to Minecraft. Make sure that the channel is registered with {@link #RegisterChatChannel(Channel)}.<br>
* This will also send the error message to the sender, if they can't send the message.

View file

@ -1,111 +0,0 @@
package buttondevteam.lib.chat;
import buttondevteam.lib.architecture.Component;
import javassist.Modifier;
import lombok.Getter;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
import java.util.function.Function;
/**
* Extend this class to create new TBMCCommand and use {@link TBMCChatAPI#AddCommand(org.bukkit.plugin.java.JavaPlugin, TBMCCommandBase)} to add it. <u><b>Note:</b></u> The command path (command name
* and subcommand arguments) will be the class name by default, removing any "command" from it. To change it (especially for subcommands), use the path field in the {@link CommandClass} annotation.
*
* @author Norbi
*
*/
@TBMCCommandEnforcer
public abstract class TBMCCommandBase {
public TBMCCommandBase() {
path = getcmdpath();
modonly = ismodonly();
}
public abstract boolean OnCommand(CommandSender sender, String alias, String[] args);
public abstract String[] GetHelpText(String alias);
private final String path;
/**
* The command's path, or name if top-level command.<br>
* For example:<br>
* "u admin updateplugin" or "u" for the top level one<br>
* <u>The path must be lowercase!</u><br>
* <b>Abstract classes with no {@link CommandClass} annotations will be ignored.</b>
*
* @return The command path, <i>which is the command class name by default</i> (removing any "command" from it) - Change via the {@link CommandClass} annotation
*/
public final String GetCommandPath() {
return path;
}
private String getcmdpath() {
if (!getClass().isAnnotationPresent(CommandClass.class))
throw new RuntimeException(
"No @CommandClass annotation on command class " + getClass().getSimpleName() + "!");
Function<Class<?>, String> getFromClass = cl -> cl.getSimpleName().toLowerCase().replace("commandbase", "") // <-- ...
.replace("command", "");
String path = getClass().getAnnotation(CommandClass.class).path(),
prevpath = path = path.length() == 0 ? getFromClass.apply(getClass()) : path;
for (Class<?> cl = getClass().getSuperclass(); cl != null
&& !cl.getPackage().getName().equals(TBMCCommandBase.class.getPackage().getName()); cl = cl
.getSuperclass()) { //
String newpath;
if (!cl.isAnnotationPresent(CommandClass.class)
|| (newpath = cl.getAnnotation(CommandClass.class).path()).length() == 0
|| newpath.equals(prevpath)) {
if ((Modifier.isAbstract(cl.getModifiers()) && !cl.isAnnotationPresent(CommandClass.class))
|| cl.getAnnotation(CommandClass.class).excludeFromPath()) // <--
continue;
newpath = getFromClass.apply(cl);
}
path = (prevpath = newpath) + " " + path;
}
return path;
}
Plugin plugin; // Used By TBMCChatAPI
public final Plugin getPlugin() { // Used by CommandCaller (ButtonChat)
return plugin;
}
public final boolean isPlayerOnly() {
return this instanceof PlayerCommandBase ||
(this instanceof OptionallyPlayerCommandBase &&
(!getClass().isAnnotationPresent(OptionallyPlayerCommandClass.class)
|| getClass().getAnnotation(OptionallyPlayerCommandClass.class).playerOnly()));
}
private final boolean modonly;
/**
* Returns true if this class' or any superclass' modOnly property is set to true.
*/
public final boolean isModOnly() {
return modonly;
}
private boolean ismodonly() {
if (!getClass().isAnnotationPresent(CommandClass.class))
throw new RuntimeException(
"No @CommandClass annotation on command class " + getClass().getSimpleName() + "!");
boolean modOnly = getClass().getAnnotation(CommandClass.class).modOnly();
for (Class<?> cl = getClass().getSuperclass(); cl != null
&& !cl.getPackage().getName().equals(TBMCCommandBase.class.getPackage().getName()); cl = cl
.getSuperclass()) { //
if (cl.isAnnotationPresent(CommandClass.class) && !modOnly
&& cl.getAnnotation(CommandClass.class).modOnly()) {
modOnly = true;
break;
}
}
return modOnly;
}
@Getter
Component component; //May be null
}

View file

@ -1,14 +0,0 @@
package buttondevteam.lib.chat;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
@Inherited
public @interface TBMCCommandEnforcer {
}

View file

@ -57,10 +57,8 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase {
/**
* Get player as a plugin player
*
* @param uuid
* The UUID of the player to get
* @param cl
* The type of the player
* @param uuid The UUID of the player to get
* @param cl The type of the player
* @return The requested player object
*/
@SuppressWarnings("unchecked")
@ -93,8 +91,7 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase {
* Gets the TBMCPlayer object as a specific plugin player, keeping it's data<br>
* Make sure to use try-with-resources with this to save the data, as it may need to load the file
*
* @param cl
* The TBMCPlayer subclass
* @param cl The TBMCPlayer subclass
*/
public <T extends TBMCPlayerBase> T asPluginPlayer(Class<T> cl) {
return getPlayer(uuid, cl);
@ -122,10 +119,9 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase {
player.PlayerName().set(p.getName());
Bukkit.getLogger().info("Player name saved: " + player.PlayerName().get());
} else if (!p.getName().equals(player.PlayerName().get())) {
Bukkit.getLogger().info("Renaming " + player.PlayerName().get() + " to " + p.getName());
TownyComponent.renameInTowny(player.PlayerName().get(), p.getName());
player.PlayerName().set(p.getName());
Bukkit.getLogger().info("Renaming done.");
Bukkit.getLogger().info("Renamed to " + p.getName());
}
playermap.put(p.getUniqueId() + "-" + TBMCPlayer.class.getSimpleName(), player);
@ -168,8 +164,7 @@ public abstract class TBMCPlayerBase extends ChromaGamerBase {
* }
* </pre>
*
* @param name
* The player's name
* @param name The player's name
* @return The {@link TBMCPlayer} object for the player
*/
public static <T extends TBMCPlayerBase> T getFromName(String name, Class<T> cl) {

View file

@ -1,7 +1,7 @@
name: ChromaCore
main: buttondevteam.core.MainPlugin
version: 1.0
author: TBMCPlugins
author: NorbiPeti
commands:
updateplugin:
description: Update a TBMC plugin
@ -22,3 +22,4 @@ softdepend:
- Towny
- Votifier
- Multiverse-Core
- Essentials

View file

@ -1,5 +1,8 @@
package buttondevteam.buttonproc;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
@ -10,29 +13,40 @@ import javax.lang.model.type.TypeMirror;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class ConfigProcessor {
private final ProcessingEnvironment procEnv;
private final FileWriter sw;
private final YamlConfiguration yc = new YamlConfiguration();
private final FileObject fo;
public ConfigProcessor(ProcessingEnvironment procEnv) {
FileObject fo1;
this.procEnv = procEnv;
FileWriter sw = null;
try {
FileObject file = procEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", "configHelp.md");
sw = new FileWriter(new File(file.toUri()));
System.out.println(file.toUri());
fo1 = procEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", "configHelp.yml");
} catch (IOException e) {
e.printStackTrace();
fo1 = null;
}
this.sw = sw;
this.fo = fo1;
}
public void process(Element targetcl) {
if (targetcl.getModifiers().contains(Modifier.ABSTRACT)) return;
final String path = "components." + targetcl.getSimpleName();
HasConfig hasConfig = targetcl.getAnnotation(HasConfig.class);
if (hasConfig == null) {
System.out.println("That's not our HasConfig annotation...");
return;
}
final String path = hasConfig.global() ? "global" : "components." + targetcl.getSimpleName();
File file = new File(fo.toUri());
try {
if (file.exists())
yc.load(file);
} catch (IOException | InvalidConfigurationException e) {
e.printStackTrace();
}
for (Element e : targetcl.getEnclosedElements()) {
/*System.out.println("Element: "+e);
System.out.println("Type: "+e.getClass()+" - "+e.getKind());
@ -49,30 +63,18 @@ public class ConfigProcessor {
String doc = procEnv.getElementUtils().getDocComment(e);
if (doc == null) continue;
System.out.println("DOC: " + doc);
try {
sw.append(path).append(".").append(String.valueOf(e.getSimpleName())).append(System.lineSeparator()).append(System.lineSeparator());
sw.append(doc.trim()).append(System.lineSeparator()).append(System.lineSeparator());
} catch (IOException e1) {
e1.printStackTrace();
}
yc.set(path + "." + e.getSimpleName(), doc.trim());
}
String javadoc = procEnv.getElementUtils().getDocComment(targetcl);
try {
if (javadoc != null) {
System.out.println("JAVADOC");
System.out.println(javadoc.trim());
sw.append(path).append(System.lineSeparator()).append(System.lineSeparator());
sw.append(javadoc).append(System.lineSeparator()).append(System.lineSeparator());
yc.set(path, javadoc.trim());
}
sw.flush();
try {
yc.save(file);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
protected void finalize() throws Throwable {
sw.close();
super.finalize();
}
}

View file

@ -1,4 +1,4 @@
package buttondevteam.lib.architecture;
package buttondevteam.buttonproc;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
@ -10,4 +10,5 @@ import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Inherited
public @interface HasConfig {
boolean global();
}

View file

@ -5,7 +5,7 @@
<module name="ButtonProcessor" />
</modules>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_13_PREVIEW">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_11">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">

View file

@ -95,10 +95,12 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<release>13</release>
<release>11</release>
<!--
<compilerArgs>
<arg>--enable-preview</arg>
<arg>HYPHENHYPHENenable-preview</arg>
</compilerArgs>
-->
</configuration>
</plugin>
</plugins>