完善 @TCommand 注解

新增 TCommandHandler 类用于动态命令注册
This commit is contained in:
坏黑 2018-08-27 00:21:06 +08:00
parent 20ec68ff7f
commit 1e50bd526b
33 changed files with 474 additions and 788 deletions

View File

@ -12,6 +12,7 @@ import sun.reflect.Reflection;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;

View File

@ -1,58 +1,37 @@
package me.skymc.taboolib; package me.skymc.taboolib;
import com.ilummc.tlib.TLib; import com.ilummc.tlib.TLib;
import com.ilummc.tlib.annotations.Dependency;
import com.ilummc.tlib.inject.TDependencyInjector;
import com.ilummc.tlib.resources.TLocale; import com.ilummc.tlib.resources.TLocale;
import com.ilummc.tlib.util.IO; import com.ilummc.tlib.util.IO;
import com.ilummc.tlib.util.Strings; import com.ilummc.tlib.util.Strings;
import me.skymc.taboolib.anvil.AnvilContainerAPI;
import me.skymc.taboolib.bstats.Metrics;
import me.skymc.taboolib.commands.TabooLibExecuteCommand;
import me.skymc.taboolib.commands.TabooLibMainCommand;
import me.skymc.taboolib.commands.internal.TBaseCommand;
import me.skymc.taboolib.commands.language.Language2Command;
import me.skymc.taboolib.commands.locale.TabooLibLocaleCommand;
import me.skymc.taboolib.commands.plugin.TabooLibPluginCommand;
import me.skymc.taboolib.commands.taboolib.listener.ListenerItemListCommand;
import me.skymc.taboolib.commands.taboolib.listener.ListenerSoundsCommand;
import me.skymc.taboolib.database.GlobalDataManager; import me.skymc.taboolib.database.GlobalDataManager;
import me.skymc.taboolib.database.PlayerDataManager; import me.skymc.taboolib.database.PlayerDataManager;
import me.skymc.taboolib.economy.EcoUtils; import me.skymc.taboolib.economy.EcoUtils;
import me.skymc.taboolib.entity.EntityUtils;
import me.skymc.taboolib.fileutils.ConfigUtils; import me.skymc.taboolib.fileutils.ConfigUtils;
import me.skymc.taboolib.fileutils.FileUtils; import me.skymc.taboolib.fileutils.FileUtils;
import me.skymc.taboolib.fileutils.TLogs;
import me.skymc.taboolib.inventory.ItemUtils; import me.skymc.taboolib.inventory.ItemUtils;
import me.skymc.taboolib.inventory.speciaitem.SpecialItem; import me.skymc.taboolib.inventory.speciaitem.SpecialItem;
import me.skymc.taboolib.itagapi.TagDataHandler; import me.skymc.taboolib.itagapi.TagDataHandler;
import me.skymc.taboolib.javascript.ScriptHandler; import me.skymc.taboolib.javascript.ScriptHandler;
import me.skymc.taboolib.javashell.JavaShell; import me.skymc.taboolib.listener.TListenerHandler;
import me.skymc.taboolib.listener.*;
import me.skymc.taboolib.message.ChatCatcher;
import me.skymc.taboolib.mysql.hikari.HikariHandler; import me.skymc.taboolib.mysql.hikari.HikariHandler;
import me.skymc.taboolib.mysql.protect.MySQLConnection; import me.skymc.taboolib.mysql.protect.MySQLConnection;
import me.skymc.taboolib.nms.item.DabItemUtils; import me.skymc.taboolib.nms.item.DabItemUtils;
import me.skymc.taboolib.other.NumberUtils; import me.skymc.taboolib.other.NumberUtils;
import me.skymc.taboolib.permission.PermissionUtils; import me.skymc.taboolib.permission.PermissionUtils;
import me.skymc.taboolib.playerdata.DataUtils; import me.skymc.taboolib.playerdata.DataUtils;
import me.skymc.taboolib.sign.SignUtils;
import me.skymc.taboolib.skript.SkriptHandler; import me.skymc.taboolib.skript.SkriptHandler;
import me.skymc.taboolib.socket.TabooLibClient; import me.skymc.taboolib.socket.TabooLibClient;
import me.skymc.taboolib.string.StringUtils;
import me.skymc.taboolib.string.language2.Language2; import me.skymc.taboolib.string.language2.Language2;
import me.skymc.taboolib.support.SupportPlaceholder; import me.skymc.taboolib.support.SupportPlaceholder;
import me.skymc.taboolib.timecycle.TimeCycleManager; import me.skymc.taboolib.timecycle.TimeCycleManager;
import me.skymc.taboolib.translateuuid.TranslateUUID; import me.skymc.taboolib.translateuuid.TranslateUUID;
import me.skymc.taboolib.translateuuid.TranslateUUIDCommand;
import me.skymc.taboolib.update.UpdateTask; import me.skymc.taboolib.update.UpdateTask;
import me.skymc.tlm.TLM; import me.skymc.tlm.TLM;
import me.skymc.tlm.command.TLMCommands;
import me.skymc.tlm.module.TabooLibraryModule; import me.skymc.tlm.module.TabooLibraryModule;
import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.economy.Economy;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
@ -60,11 +39,9 @@ import org.bukkit.scheduler.BukkitRunnable;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.InetAddress;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.Arrays; import java.util.Arrays;
import java.util.Random; import java.util.Random;
import java.util.stream.Collectors;
/** /**
* @author sky * @author sky
@ -118,7 +95,7 @@ public class Main extends JavaPlugin {
TLib.init(); TLib.init();
TLib.injectPluginManager(); TLib.injectPluginManager();
// 载入插件设置 // 载入插件设置
TabooLibSettings.setup(); TabooLibLoader.setup();
// 载入大饼 // 载入大饼
TLib.initPost(); TLib.initPost();
// 载入连接池 // 载入连接池
@ -128,7 +105,7 @@ public class Main extends JavaPlugin {
@Override @Override
public void onEnable() { public void onEnable() {
// 注册插件配置 // 注册插件配置
TabooLibSettings.register(); TabooLibLoader.register();
// 载入经济 // 载入经济
EcoUtils.setupEconomy(); EcoUtils.setupEconomy();
// 载入权限 // 载入权限
@ -211,8 +188,6 @@ public class Main extends JavaPlugin {
DataUtils.saveAllCaches(); DataUtils.saveAllCaches();
// 保存玩家数据 // 保存玩家数据
PlayerDataManager.saveAllPlayers(false, true); PlayerDataManager.saveAllPlayers(false, true);
// 结束脚本
JavaShell.javaShellCancel();
// 注销 SpecialItem 接口 // 注销 SpecialItem 接口
SpecialItem.getInst().unloadItems(); SpecialItem.getInst().unloadItems();
// 注销 TLM 接口 // 注销 TLM 接口

View File

@ -23,7 +23,7 @@ import java.util.stream.Collectors;
* @Author sky * @Author sky
* @Since 2018-08-23 17:04 * @Since 2018-08-23 17:04
*/ */
class TabooLibSettings { class TabooLibLoader {
static void setup() { static void setup() {
testInternet(); testInternet();
@ -33,8 +33,8 @@ class TabooLibSettings {
} }
static void register() { static void register() {
registerCommands();
registerListener(); registerListener();
registerCommands();
registerMetrics(); registerMetrics();
} }

View File

@ -19,7 +19,7 @@ public class LogClient extends JFrame {
super(title); super(title);
// DEFAULT CLOSE OPERATION // DEFAULT CLOSE OPERATION
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// SETTINGS // SETTINGS
final JScrollPane scrollPane = new JScrollPane(); final JScrollPane scrollPane = new JScrollPane();
@ -37,30 +37,21 @@ public class LogClient extends JFrame {
textArea.setBackground(Color.black); textArea.setBackground(Color.black);
textArea.setForeground(Color.LIGHT_GRAY); textArea.setForeground(Color.LIGHT_GRAY);
addstr(title); addString(title);
addstr(""); addString("");
} }
public void addString(String a) { public void addString(String a) {
textArea.append("[" + sdf.format(System.currentTimeMillis()) + " NONE]: " + a + '\n');
textArea.setSelectionStart(textArea.getText().length());
}
public void addstr(String a) {
textArea.append(a + '\n'); textArea.append(a + '\n');
textArea.setSelectionStart(textArea.getText().length()); textArea.setSelectionStart(textArea.getText().length());
} }
public void info(String a) { public void info(String a) {
textArea.append("[" + sdf.format(System.currentTimeMillis()) + " INFO]: " + a + '\n'); textArea.append("[" + sdf.format(System.currentTimeMillis()) + " INFO]: " + a + '\n');
textArea.setSelectionStart(textArea.getText().length()); textArea.setSelectionStart(textArea.getText().length());
} }
public void warn(String a) { public void warn(String a) {
textArea.append("[" + sdf.format(System.currentTimeMillis()) + " WARN]: " + a + '\n'); textArea.append("[" + sdf.format(System.currentTimeMillis()) + " WARN]: " + a + '\n');
textArea.setSelectionStart(textArea.getText().length()); textArea.setSelectionStart(textArea.getText().length());
} }

View File

@ -19,7 +19,11 @@ import org.bukkit.event.server.ServerCommandEvent;
* @Author sky * @Author sky
* @Since 2018-07-04 21:32 * @Since 2018-07-04 21:32
*/ */
@TCommand(name = "taboolibexecute") @TCommand(
name = "taboolibexecute",
aliases = {"texecute"},
permission = "taboolib.admin"
)
public class TabooLibExecuteCommand extends BaseMainCommand { public class TabooLibExecuteCommand extends BaseMainCommand {
@Override @Override

View File

@ -28,13 +28,18 @@ import org.bukkit.command.CommandSender;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
import java.io.File; import java.io.File;
import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
* @Author sky * @Author sky
* @Since 2018-05-09 21:38 * @Since 2018-05-09 21:38
*/ */
@TCommand(name = "taboolib") @TCommand(
name = "taboolib",
permission = "taboolib.admin",
aliases = "tlib"
)
public class TabooLibMainCommand extends BaseMainCommand { public class TabooLibMainCommand extends BaseMainCommand {
@Override @Override
@ -563,72 +568,7 @@ public class TabooLibMainCommand extends BaseMainCommand {
@CommandRegister(priority = 17) @CommandRegister(priority = 17)
BaseSubCommand getEmptyLine4 = null; BaseSubCommand getEmptyLine4 = null;
@CommandRegister(priority = 18)
BaseSubCommand shellLoad = new BaseSubCommand() {
@Override
public String getLabel() {
return "shellLoad";
}
@Override
public String getDescription() {
return TLocale.asString("COMMANDS.TABOOLIB.JAVASHELL.DESCRIPTION.LOAD");
}
@Override
public CommandArgument[] getArguments() {
return new CommandArgument[]{
new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.JAVASHELL.ARGUMENTS.LOAD.0"))
};
}
@Override
public void onCommand(CommandSender sender, Command command, String label, String[] args) {
new ShellLoadCommand(sender, args);
}
@Override
public boolean ignoredLabel() {
return false;
}
};
@CommandRegister(priority = 19)
BaseSubCommand shellUnload = new BaseSubCommand() {
@Override
public String getLabel() {
return "shellUnload";
}
@Override
public String getDescription() {
return TLocale.asString("COMMANDS.TABOOLIB.JAVASHELL.DESCRIPTION.UNLOAD");
}
@Override
public CommandArgument[] getArguments() {
return new CommandArgument[]{
new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.JAVASHELL.ARGUMENTS.UNLOAD.0"))
};
}
@Override
public void onCommand(CommandSender sender, Command command, String label, String[] args) {
new ShellUnloadCommand(sender, args);
}
@Override
public boolean ignoredLabel() {
return false;
}
};
@CommandRegister(priority = 20) @CommandRegister(priority = 20)
BaseSubCommand getEmptyLine5 = null;
@CommandRegister(priority = 20.5)
BaseSubCommand tagDisplay = new BaseSubCommand() { BaseSubCommand tagDisplay = new BaseSubCommand() {
@Override @Override

View File

@ -25,14 +25,21 @@ import java.util.stream.Collectors;
* @Author sky * @Author sky
* @Since 2018-05-07 21:38 * @Since 2018-05-07 21:38
*/ */
public abstract class BaseMainCommand implements IMainCommand, CommandExecutor, TabExecutor { public abstract class BaseMainCommand implements CommandExecutor, TabExecutor {
private PluginCommand registerCommand; private PluginCommand registerCommand;
private List<Class<?>> linkClasses = new CopyOnWriteArrayList<>(); private List<Class<?>> linkClasses = new CopyOnWriteArrayList<>();
private List<BaseSubCommand> subCommands = new CopyOnWriteArrayList<>(); private List<BaseSubCommand> subCommands = new CopyOnWriteArrayList<>();
/**
* 指令标题
*
* @return 文本
*/
abstract public String getCommandTitle();
public static BaseMainCommand createCommandExecutor(String command, BaseMainCommand baseMainCommand) { public static BaseMainCommand createCommandExecutor(String command, BaseMainCommand baseMainCommand) {
Preconditions.checkArgument(Bukkit.getPluginCommand(command) != null, "PluginCommand \"" + command + "\"not found"); Preconditions.checkArgument(Bukkit.getPluginCommand(command) != null, "PluginCommand \"" + command + "\" not found");
Preconditions.checkArgument(baseMainCommand != null, "Executor cannot be null"); Preconditions.checkArgument(baseMainCommand != null, "Executor cannot be null");
Preconditions.checkArgument(baseMainCommand.getClass() != BaseMainCommand.class, "Executor can not be \"BaseMainCommand.class\""); Preconditions.checkArgument(baseMainCommand.getClass() != BaseMainCommand.class, "Executor can not be \"BaseMainCommand.class\"");
baseMainCommand.setRegisterCommand(Bukkit.getPluginCommand(command)); baseMainCommand.setRegisterCommand(Bukkit.getPluginCommand(command));
@ -99,6 +106,11 @@ public abstract class BaseMainCommand implements IMainCommand, CommandExecutor,
subCommands.add(subCommand); subCommands.add(subCommand);
} }
@Override
public List<String> onTabComplete(CommandSender commandSender, Command command, String s, String[] args) {
return args.length == 1 ? subCommands.stream().filter(subCommand -> subCommand != null && hasPermission(commandSender, subCommand) && (args[0].isEmpty() || subCommand.getLabel().toLowerCase().startsWith(args[0].toLowerCase()))).map(BaseSubCommand::getLabel).collect(Collectors.toList()) : null;
}
@Override @Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (args.length == 0) { if (args.length == 0) {
@ -134,11 +146,6 @@ public abstract class BaseMainCommand implements IMainCommand, CommandExecutor,
return true; return true;
} }
@Override
public List<String> onTabComplete(CommandSender commandSender, Command command, String s, String[] args) {
return args.length == 1 ? subCommands.stream().filter(subCommand -> subCommand != null && hasPermission(commandSender, subCommand) && (args[0].isEmpty() || subCommand.getLabel().toLowerCase().startsWith(args[0].toLowerCase()))).map(ISubCommand::getLabel).collect(Collectors.toList()) : null;
}
@Override @Override
public String toString() { public String toString() {
return "registerCommand=" + "BaseMainCommand{" + registerCommand + ", linkClasses=" + linkClasses + ", subCommands=" + subCommands + '}'; return "registerCommand=" + "BaseMainCommand{" + registerCommand + ", linkClasses=" + linkClasses + ", subCommands=" + subCommands + '}';
@ -161,6 +168,12 @@ public abstract class BaseMainCommand implements IMainCommand, CommandExecutor,
return Objects.hash(getRegisterCommand(), getLinkClasses(), getSubCommands()); return Objects.hash(getRegisterCommand(), getLinkClasses(), getSubCommands());
} }
// *********************************
//
// Private Methods
//
// *********************************
private String getEmptyLine() { private String getEmptyLine() {
return TabooLib.getVerint() < 10800 ? "~" : ""; return TabooLib.getVerint() < 10800 ? "~" : "";
} }

View File

@ -1,7 +1,10 @@
package me.skymc.taboolib.commands.internal; package me.skymc.taboolib.commands.internal;
import com.ilummc.tlib.resources.TLocale; import com.ilummc.tlib.resources.TLocale;
import me.skymc.taboolib.commands.internal.type.CommandArgument;
import me.skymc.taboolib.commands.internal.type.CommandType; import me.skymc.taboolib.commands.internal.type.CommandType;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import java.util.Arrays; import java.util.Arrays;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -11,28 +14,91 @@ import java.util.stream.IntStream;
* @author Bkm016 * @author Bkm016
* @since 2018-04-17 * @since 2018-04-17
*/ */
public abstract class BaseSubCommand implements ISubCommand { public abstract class BaseSubCommand {
/**
* 指令名
*
* @return 文本
*/
abstract public String getLabel();
/**
* 指令描述
*
* @return 文本
*/
abstract public String getDescription();
/**
* 指令参数
*
* @return {@link CommandArgument}
*/
abstract public CommandArgument[] getArguments();
/**
* 指令执行方法
*
* @param sender 指令使用者
* @param command 指令对象
* @param label 主命令
* @param args 参数不含主命令及子命令
*/
abstract public void onCommand(CommandSender sender, Command command, String label, String[] args);
/**
* 指令执行者
*
* @return {@link CommandType}
*/
public CommandType getType() { public CommandType getType() {
return CommandType.ALL; return CommandType.ALL;
} }
/**
* 参数是否屏蔽子命令名
*
* @return boolean
*/
public boolean ignoredLabel() { public boolean ignoredLabel() {
return true; return true;
} }
/**
* 是否需要玩家在线
*
* @return boolean
*/
public boolean requiredPlayer() { public boolean requiredPlayer() {
return false; return false;
} }
/**
* 需要权限
*
* @return boolean
*/
public String getPermission() { public String getPermission() {
return null; return null;
} }
/**
* 参数是否符合
*
* @param args 参数
* @return boolean
*/
public boolean isParameterConform(String[] args) { public boolean isParameterConform(String[] args) {
return IntStream.range(0, getArguments().length).noneMatch(i -> getArguments()[i].isRequired() && (args == null || args.length <= i)); return IntStream.range(0, getArguments().length).noneMatch(i -> getArguments()[i].isRequired() && (args == null || args.length <= i));
} }
/**
* 获取帮助文本
*
* @param label 子命令标题
* @return String
*/
public String getCommandString(String label) { public String getCommandString(String label) {
String stringBuilder = Arrays.stream(getArguments()).map(parameter -> parameter.toString() + " ").collect(Collectors.joining()); String stringBuilder = Arrays.stream(getArguments()).map(parameter -> parameter.toString() + " ").collect(Collectors.joining());
return TLocale.asString("COMMANDS.INTERNAL.COMMAND-HELP", label, getLabel(), stringBuilder.trim(), getDescription()); return TLocale.asString("COMMANDS.INTERNAL.COMMAND-HELP", label, getLabel(), stringBuilder.trim(), getDescription());

View File

@ -1,16 +0,0 @@
package me.skymc.taboolib.commands.internal;
/**
* @Author sky
* @Since 2018-05-07 21:36
*/
public interface IMainCommand {
/**
* 指令标题
*
* @return 文本
*/
String getCommandTitle();
}

View File

@ -1,44 +0,0 @@
package me.skymc.taboolib.commands.internal;
import me.skymc.taboolib.commands.internal.type.CommandArgument;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
/**
* @author Bkm016
* @since 2018-04-17
*/
public interface ISubCommand {
/**
* 指令名
*
* @return 文本
*/
String getLabel();
/**
* 指令描述
*
* @return 文本
*/
String getDescription();
/**
* 指令参数
*
* @return {@link CommandArgument}
*/
CommandArgument[] getArguments();
/**
* 指令执行方法
*
* @param sender 指令使用者
* @param command 指令对象
* @param label 主命令
* @param args 参数不含主命令及子命令
*/
void onCommand(CommandSender sender, Command command, String label, String[] args);
}

View File

@ -1,71 +0,0 @@
package me.skymc.taboolib.commands.internal;
import me.skymc.taboolib.fileutils.FileUtils;
import me.skymc.taboolib.listener.TListener;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.plugin.Plugin;
/**
* @Author sky
* @Since 2018-05-23 2:43
*/
@TListener(register = "onLoad")
public class TBaseCommand implements Listener {
void onLoad() {
registerCommands();
}
/**
* 向服务端注册 BaseMainCommand
*
* @param command 命令全称需在 plugin.yml 内注册
* @param baseMainCommand 命令对象
* @return {@link BaseMainCommand}
*/
public static BaseMainCommand registerCommand(String command, BaseMainCommand baseMainCommand) {
return BaseMainCommand.createCommandExecutor(command, baseMainCommand);
}
/**
* 注册所有插件的所有 TCommand 命令
*/
public static void registerCommands() {
for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
try {
registerCommand(plugin);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 注册插件的所有 TCommand 命令
*
* @param plugin 插件
*/
public static void registerCommand(Plugin plugin) {
for (Class pluginClass : FileUtils.getClasses(plugin)) {
if (BaseMainCommand.class.isAssignableFrom(pluginClass) && pluginClass.isAnnotationPresent(TCommand.class)) {
TCommand tCommand = (TCommand) pluginClass.getAnnotation(TCommand.class);
try {
registerCommand(tCommand.name(), (BaseMainCommand) pluginClass.newInstance());
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
@EventHandler
public void onEnable(PluginEnableEvent e) {
try {
registerCommand(e.getPlugin());
} catch (Exception ignored) {
}
}
}

View File

@ -4,6 +4,7 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import java.util.List;
/** /**
* @Author sky * @Author sky
@ -15,4 +16,13 @@ public @interface TCommand {
String name(); String name();
String permission() default "";
String permissionMessage() default "";
String description() default "";
String usage() default "";
String[] aliases() default "";
} }

View File

@ -0,0 +1,181 @@
package me.skymc.taboolib.commands.internal;
import com.ilummc.tlib.resources.TLocale;
import me.skymc.taboolib.fileutils.FileUtils;
import me.skymc.taboolib.listener.TListener;
import me.skymc.taboolib.methods.ReflectionUtils;
import me.skymc.taboolib.string.ArrayUtils;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.plugin.Plugin;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* @Author sky
* @Since 2018-05-23 2:43
*/
@TListener
public class TCommandHandler implements Listener {
private static SimpleCommandMap commandMap;
public TCommandHandler() {
try {
Field commandMap = Bukkit.getPluginManager().getClass().getDeclaredField("commandMap");
commandMap.setAccessible(true);
TCommandHandler.commandMap = (SimpleCommandMap) commandMap.get(Bukkit.getPluginManager());
} catch (Exception e) {
e.printStackTrace();
}
try {
registerCommands();
} catch (Exception e) {
e.printStackTrace();
}
}
@EventHandler
public void onEnable(PluginEnableEvent e) {
try {
registerCommand(e.getPlugin());
} catch (Exception ignored) {
}
}
public static boolean registerPluginCommand(Plugin plugin, String command, CommandExecutor commandExecutor) {
return registerPluginCommand(plugin, command, "", "/" + command, new ArrayList<>(), null, null, commandExecutor, null);
}
public static boolean registerPluginCommand(Plugin plugin, String command, CommandExecutor commandExecutor, TabExecutor tabExecutor) {
return registerPluginCommand(plugin, command, "", "/" + command, new ArrayList<>(), null, null, commandExecutor, tabExecutor);
}
public static boolean registerPluginCommand(Plugin plugin, String command, String description, CommandExecutor commandExecutor, TabExecutor tabExecutor) {
return registerPluginCommand(plugin, command, description, "/" + command, new ArrayList<>(), null, null, commandExecutor, tabExecutor);
}
public static boolean registerPluginCommand(Plugin plugin, String command, String description, String usage, CommandExecutor commandExecutor, TabExecutor tabExecutor) {
return registerPluginCommand(plugin, command, description, usage, new ArrayList<>(), null, null, commandExecutor, tabExecutor);
}
public static boolean registerPluginCommand(Plugin plugin, String command, String description, String usage, List<String> aliases, CommandExecutor commandExecutor, TabExecutor tabExecutor) {
return registerPluginCommand(plugin, command, description, usage, aliases, null, null, commandExecutor, tabExecutor);
}
/**
* 向服务端动态注册命令
*
* @param plugin 所属插件
* @param command 命令名称
* @param description 命令描述
* @param usage 命令用法
* @param aliases 别名
* @param permission 权限
* @param permissionMessage 权限提示
* @param commandExecutor 命令执行器
* @param tabExecutor 补全执行器
* @return 注册结果(boolean)
*/
public static boolean registerPluginCommand(Plugin plugin, String command, String description, String usage, List<String> aliases, String permission, String permissionMessage, CommandExecutor commandExecutor, TabExecutor tabExecutor) {
try {
Constructor<PluginCommand> constructor = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class);
constructor.setAccessible(true);
PluginCommand pluginCommand = constructor.newInstance(command, plugin);
pluginCommand.setExecutor(commandExecutor);
pluginCommand.setTabCompleter(tabExecutor);
ReflectionUtils.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "description", description);
ReflectionUtils.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "usageMessage", usage);
ReflectionUtils.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "aliases", aliases);
ReflectionUtils.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "activeAliases", aliases);
ReflectionUtils.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "permission", permission);
ReflectionUtils.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "permissionMessage", permissionMessage);
commandMap.register(command, pluginCommand);
TLocale.Logger.info("COMMANDS.INTERNAL.COMMAND-CREATE", plugin.getName(), command);
return true;
} catch (Exception e) {
TLocale.Logger.info("COMMANDS.INTERNAL.COMMAND-CREATE-FAILED", plugin.getName(), command, e.getMessage());
return false;
}
}
/**
* 向服务端注册 BaseMainCommand
*
* @param command 命令全称需在 plugin.yml 内注册
* @param baseMainCommand 命令对象
* @return {@link BaseMainCommand}
*/
public static BaseMainCommand registerCommand(TCommand tCommand, String command, BaseMainCommand baseMainCommand, Plugin plugin) {
if (Bukkit.getPluginCommand(command) == null) {
registerPluginCommand(
plugin,
command,
ArrayUtils.skipEmpty(tCommand.description(), "Registered by TabooLib."),
ArrayUtils.skipEmpty(tCommand.usage(), "/" + command),
ArrayUtils.skipEmpty(ArrayUtils.asList(tCommand.aliases()), new ArrayList<>()),
ArrayUtils.skipEmpty(tCommand.permission()),
ArrayUtils.skipEmpty(tCommand.permissionMessage()),
baseMainCommand,
baseMainCommand);
}
return BaseMainCommand.createCommandExecutor(command, baseMainCommand);
}
/**
* 注册所有插件的所有 TCommand 命令
*/
public static void registerCommands() {
for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
try {
registerCommand(plugin);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 注册插件的所有 TCommand 命令
*
* @param plugin 插件
*/
public static void registerCommand(Plugin plugin) {
for (Class pluginClass : FileUtils.getClasses(plugin)) {
if (BaseMainCommand.class.isAssignableFrom(pluginClass) && pluginClass.isAnnotationPresent(TCommand.class)) {
TCommand tCommand = (TCommand) pluginClass.getAnnotation(TCommand.class);
try {
registerCommand(tCommand, tCommand.name(), (BaseMainCommand) pluginClass.newInstance(), plugin);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
* 获取插件注册的命令
*
* @param command 命令名称
* @return {@link Command}
*/
public static Command getPluginCommand(String command) {
return commandMap.getCommand(command);
}
// *********************************
//
// Getter and Setter
//
// *********************************
public static SimpleCommandMap getCommandMap() {
return commandMap;
}
}

View File

@ -22,7 +22,11 @@ import java.util.stream.IntStream;
* @author sky * @author sky
* @since 2018-04-22 14:36:28 * @since 2018-04-22 14:36:28
*/ */
@TCommand(name = "tabooliblocale") @TCommand(
name = "tabooliblocale",
aliases = {"taboolocale", "tlocale"},
permission = "taboolib.admin"
)
public class TabooLibLocaleCommand extends BaseMainCommand { public class TabooLibLocaleCommand extends BaseMainCommand {
@Override @Override

View File

@ -4,7 +4,6 @@ import com.google.common.base.Joiner;
import com.ilummc.tlib.resources.TLocale; import com.ilummc.tlib.resources.TLocale;
import me.skymc.taboolib.commands.internal.BaseMainCommand; import me.skymc.taboolib.commands.internal.BaseMainCommand;
import me.skymc.taboolib.commands.internal.BaseSubCommand; import me.skymc.taboolib.commands.internal.BaseSubCommand;
import me.skymc.taboolib.commands.internal.ISubCommand;
import me.skymc.taboolib.commands.internal.TCommand; import me.skymc.taboolib.commands.internal.TCommand;
import me.skymc.taboolib.commands.internal.type.CommandArgument; import me.skymc.taboolib.commands.internal.type.CommandArgument;
import me.skymc.taboolib.commands.internal.type.CommandRegister; import me.skymc.taboolib.commands.internal.type.CommandRegister;
@ -26,7 +25,11 @@ import java.util.stream.Collectors;
* @Author sky * @Author sky
* @Since 2018-05-07 20:14 * @Since 2018-05-07 20:14
*/ */
@TCommand(name = "taboolibplugin") @TCommand(
name = "taboolibplugin",
aliases = {"tabooplugin", "tplugin"},
permission = "taboolib.admin"
)
public class TabooLibPluginCommand extends BaseMainCommand { public class TabooLibPluginCommand extends BaseMainCommand {
@Override @Override
@ -37,7 +40,7 @@ public class TabooLibPluginCommand extends BaseMainCommand {
@Override @Override
public List<String> onTabComplete(CommandSender commandSender, Command command, String s, String[] args) { public List<String> onTabComplete(CommandSender commandSender, Command command, String s, String[] args) {
if (args.length == 1) { if (args.length == 1) {
return getSubCommands().stream().filter(internalCommandExecutor -> internalCommandExecutor != null && (args[0].isEmpty() || internalCommandExecutor.getLabel().toLowerCase().startsWith(args[0].toLowerCase()))).map(ISubCommand::getLabel).collect(Collectors.toList()); return getSubCommands().stream().filter(internalCommandExecutor -> internalCommandExecutor != null && (args[0].isEmpty() || internalCommandExecutor.getLabel().toLowerCase().startsWith(args[0].toLowerCase()))).map(BaseSubCommand::getLabel).collect(Collectors.toList());
} else if (args.length > 1 && isPluginCommand(args[0])) { } else if (args.length > 1 && isPluginCommand(args[0])) {
return Arrays.stream(Bukkit.getPluginManager().getPlugins()).filter(x -> !PluginUtils.isIgnored(x)).collect(Collectors.toList()).stream().filter(plugin -> args[1].isEmpty() || plugin.getName().toLowerCase().startsWith(args[1].toLowerCase())).map(Plugin::getName).collect(Collectors.toList()); return Arrays.stream(Bukkit.getPluginManager().getPlugins()).filter(x -> !PluginUtils.isIgnored(x)).collect(Collectors.toList()).stream().filter(plugin -> args[1].isEmpty() || plugin.getName().toLowerCase().startsWith(args[1].toLowerCase())).map(Plugin::getName).collect(Collectors.toList());
} else { } else {
@ -60,7 +63,7 @@ public class TabooLibPluginCommand extends BaseMainCommand {
@Override @Override
public CommandArgument[] getArguments() { public CommandArgument[] getArguments() {
return new CommandArgument[]{new CommandArgument(TLocale.asString("COMMANDS.TPLUGIN.LOAD.ARGUMENTS.0"), true)}; return new CommandArgument[] {new CommandArgument(TLocale.asString("COMMANDS.TPLUGIN.LOAD.ARGUMENTS.0"), true)};
} }
@Override @Override
@ -110,7 +113,7 @@ public class TabooLibPluginCommand extends BaseMainCommand {
@Override @Override
public CommandArgument[] getArguments() { public CommandArgument[] getArguments() {
return new CommandArgument[]{new CommandArgument(TLocale.asString("COMMANDS.TPLUGIN.UNLOAD.ARGUMENTS.0"), true)}; return new CommandArgument[] {new CommandArgument(TLocale.asString("COMMANDS.TPLUGIN.UNLOAD.ARGUMENTS.0"), true)};
} }
@Override @Override
@ -152,7 +155,7 @@ public class TabooLibPluginCommand extends BaseMainCommand {
@Override @Override
public CommandArgument[] getArguments() { public CommandArgument[] getArguments() {
return new CommandArgument[]{new CommandArgument(TLocale.asString("COMMANDS.TPLUGIN.RELOAD.ARGUMENTS.0"), true)}; return new CommandArgument[] {new CommandArgument(TLocale.asString("COMMANDS.TPLUGIN.RELOAD.ARGUMENTS.0"), true)};
} }
@Override @Override
@ -185,7 +188,7 @@ public class TabooLibPluginCommand extends BaseMainCommand {
@Override @Override
public CommandArgument[] getArguments() { public CommandArgument[] getArguments() {
return new CommandArgument[]{new CommandArgument(TLocale.asString("COMMANDS.TPLUGIN.INFO.ARGUMENTS.0"), true)}; return new CommandArgument[] {new CommandArgument(TLocale.asString("COMMANDS.TPLUGIN.INFO.ARGUMENTS.0"), true)};
} }
@Override @Override

View File

@ -1,35 +0,0 @@
package me.skymc.taboolib.commands.taboolib;
import com.ilummc.tlib.resources.TLocale;
import me.skymc.taboolib.commands.SubCommand;
import me.skymc.taboolib.javashell.JavaShell;
import org.bukkit.command.CommandSender;
import java.io.File;
public class ShellLoadCommand extends SubCommand {
public ShellLoadCommand(CommandSender sender, String[] args) {
super(sender, args);
if (args.length < 2) {
TLocale.sendTo(sender, "COMMANDS.TABOOLIB.JAVASHELL.INVALID-NAME");
return;
}
File file = new File(JavaShell.getScriptFolder(), args[2].contains(".java") ? args[2] : args[2] + ".java");
if (!file.exists()) {
TLocale.sendTo(sender, "COMMANDS.TABOOLIB.JAVASHELL.INVALID-SHELL", args[2]);
return;
}
if (JavaShell.reloadShell(args[2])) {
TLocale.sendTo(sender, "COMMANDS.TABOOLIB.JAVASHELL.SUCCESS-LOAD", args[2]);
}
}
@Override
public boolean command() {
return true;
}
}

View File

@ -1,34 +0,0 @@
package me.skymc.taboolib.commands.taboolib;
import com.ilummc.tlib.resources.TLocale;
import me.skymc.taboolib.commands.SubCommand;
import me.skymc.taboolib.javashell.JavaShell;
import org.bukkit.command.CommandSender;
import java.io.File;
public class ShellUnloadCommand extends SubCommand {
public ShellUnloadCommand(CommandSender sender, String[] args) {
super(sender, args);
if (args.length < 2) {
TLocale.sendTo(sender, "COMMANDS.TABOOLIB.JAVASHELL.INVALID-NAME");
return;
}
File file = new File(JavaShell.getScriptFolder(), args[2].contains(".java") ? args[2] : args[2] + ".java");
if (!file.exists()) {
TLocale.sendTo(sender, "COMMANDS.TABOOLIB.JAVASHELL.INVALID-SHELL", args[2]);
return;
}
JavaShell.unloadShell(args[2]);
TLocale.sendTo(sender, "COMMANDS.TABOOLIB.JAVASHELL.SUCCESS-UNLOAD", args[2]);
}
@Override
public boolean command() {
return true;
}
}

View File

@ -20,7 +20,11 @@ import java.text.SimpleDateFormat;
/** /**
* @author sky * @author sky
*/ */
@TCommand(name = "tabooliblogs") @TCommand(
name = "tabooliblogs",
aliases = {"tlog", "tlogs"},
permission = "taboolib.admin"
)
public class TLogs extends BaseMainCommand { public class TLogs extends BaseMainCommand {
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");

View File

@ -1,215 +0,0 @@
package me.skymc.taboolib.javashell;
import com.ilummc.tlib.dependency.TDependencyLoader;
import me.skymc.taboolib.Main;
import me.skymc.taboolib.message.MsgUtils;
import org.apache.commons.lang.ArrayUtils;
import org.bukkit.Bukkit;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.plugin.RegisteredListener;
import org.bukkit.scheduler.BukkitRunnable;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Objects;
@Deprecated
public class JavaShell {
private static String paths = "";
private static File javaShellFolder;
private static File scriptFolder;
private static File cacheFolder;
private static File libFolder;
private static HashMap<String, Class<?>> shells = new HashMap<>();
public static String getPaths() {
return paths;
}
public static void setPaths(String paths) {
JavaShell.paths = paths;
}
public static File getJavaShellFolder() {
return javaShellFolder;
}
public static void setJavaShellFolder(File javaShellFolder) {
JavaShell.javaShellFolder = javaShellFolder;
}
public static File getScriptFolder() {
return scriptFolder;
}
public static void setScriptFolder(File scriptFolder) {
JavaShell.scriptFolder = scriptFolder;
}
public static File getCacheFolder() {
return cacheFolder;
}
public static void setCacheFolder(File cacheFolder) {
JavaShell.cacheFolder = cacheFolder;
}
public static File getLibFolder() {
return libFolder;
}
public static void setLibFolder(File libFolder) {
JavaShell.libFolder = libFolder;
}
public static HashMap<String, Class<?>> getShells() {
return shells;
}
public static void setShells(HashMap<String, Class<?>> shells) {
JavaShell.shells = shells;
}
public static void javaShellSetup() {
File dataFolder = Main.getInst().getDataFolder();
File pluginsFolder = dataFolder.getParentFile();
File serverRoot = Bukkit.getWorldContainer();
File[] rootJars = serverRoot.listFiles((dir, name) -> name.toLowerCase().endsWith("jar"));
File[] pluginJars = pluginsFolder.listFiles((dir, name) -> name.toLowerCase().endsWith("jar"));
for (File file : (File[]) ArrayUtils.addAll(rootJars, pluginJars)) {
String path = file.getAbsolutePath();
paths += File.pathSeparator + path;
}
javaShellFolder = new File(Main.getInst().getDataFolder(), "JavaShells");
if (!javaShellFolder.exists()) {
Main.getInst().saveResource("JavaShells/scripts/-testshell.java", true);
}
scriptFolder = new File(javaShellFolder, "scripts");
if (!scriptFolder.exists()) {
scriptFolder.mkdir();
}
cacheFolder = new File(javaShellFolder, "cache");
if (!cacheFolder.exists()) {
cacheFolder.mkdir();
}
libFolder = new File(javaShellFolder, "lib");
if (!libFolder.exists()) {
libFolder.mkdir();
}
File tools = new File(Main.getInst().getDataFolder(), "JavaShells/lib/com.sun.tools.jar");
if (!tools.exists()) {
MsgUtils.warn("&4JavaShell &c工具的必要依赖 &4com.sun.tools.jar &c不存在, 功能关闭!");
return;
}
loadLibrary();
new BukkitRunnable() {
@Override
public void run() {
long time = System.currentTimeMillis();
Arrays.stream(Objects.requireNonNull(scriptFolder.listFiles())).filter(file -> !file.getName().startsWith("-")).map(File::getName).forEach(JavaShell::reloadShell);
MsgUtils.send("载入 " + shells.size() + " 个脚本, 耗时 &f" + (System.currentTimeMillis() - time) + "ms");
}
}.runTask(Main.getInst());
}
public static void javaShellCancel() {
try {
Arrays.stream(Objects.requireNonNull(cacheFolder.listFiles())).forEach(File::delete);
shells.keySet().forEach(name -> invokeMethod(name, "onDisable"));
} catch (Exception ignored) {
}
}
public static void invokeMethod(String name, String method) {
if (shells.containsKey(name)) {
Class<?> clazz = shells.get(name);
try {
Method disableMethod = clazz.getMethod(method);
if (disableMethod != null) {
disableMethod.invoke(clazz.newInstance());
}
} catch (Exception ignored) {
}
}
}
public static void unloadShell(String shell) {
invokeMethod(shell, "onDisable");
Class<?> clazz = shells.remove(shell);
try {
if (clazz.newInstance() instanceof Listener) {
HandlerList.getRegisteredListeners(Main.getInst()).stream().filter(listener -> listener.getListener().getClass().getName().equals(clazz.getName())).map(RegisteredListener::getListener).forEach(HandlerList::unregisterAll);
MsgUtils.send("已为脚本 &f" + shell + " &7注销监听器");
}
} catch (Exception ignored) {
}
}
public static boolean reloadShell(String shell) {
unloadShell(shell = shell.replace(".java", ""));
try {
Class.forName("com.sun.tools.javac.main.Main");
} catch (Exception e) {
MsgUtils.warn("&4JavaShell &c工具的必要依赖 &4com.sun.tools.jar &c丢失, 无法载入!");
return false;
}
File javaFile = new File(scriptFolder, shell + ".java");
if (!javaFile.exists()) {
MsgUtils.send("&c脚本 &4" + shell + "&c 不存在");
return false;
}
String[] args = {
"-nowarn",
"-classpath", "." + File.pathSeparator + JavaShell.getPaths(),
"-d", cacheFolder.getAbsolutePath() + File.separator,
javaFile.getAbsolutePath()
};
int code = new com.sun.tools.javac.main.Main("javac").compile(args).exitCode;
if (code == 0) {
MsgUtils.send("&f" + shell + "&7 载入成功");
try {
URL[] urls = {cacheFolder.toURI().toURL()};
URLClassLoader sysloader = new URLClassLoader(urls, Main.class.getClassLoader());
Class<?> clazz = sysloader.loadClass(shell);
shells.put(shell, clazz);
sysloader.close();
invokeMethod(shell, "onEnable");
if (clazz.newInstance() instanceof Listener) {
Bukkit.getPluginManager().registerEvents((Listener) clazz.newInstance(), Main.getInst());
MsgUtils.send("已为脚本 &f" + shell + " &7注册监听器");
}
} catch (Exception e) {
//
}
return true;
} else {
MsgUtils.send("&4" + shell + "&c 载入失败");
return false;
}
}
private static void loadLibrary() {
Arrays.stream(Objects.requireNonNull(libFolder.listFiles())).forEach(jar -> TDependencyLoader.addToPath(Main.getInst(), jar));
}
}

View File

@ -1,100 +0,0 @@
package me.skymc.taboolib.javashell.utils;
import me.skymc.taboolib.message.MsgUtils;
import org.bukkit.Bukkit;
import java.io.*;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class JarUtils {
public static boolean extractFromJar(final String fileName, final String dest) throws IOException {
if (getRunningJar() == null) {
return false;
}
final File file = new File(dest);
if (file.isDirectory()) {
file.mkdir();
return false;
}
if (!file.exists()) {
file.getParentFile().mkdirs();
}
final JarFile jar = getRunningJar();
final Enumeration<JarEntry> e = jar.entries();
while (e.hasMoreElements()) {
final JarEntry je = e.nextElement();
if (!je.getName().contains(fileName)) {
continue;
}
final InputStream in = new BufferedInputStream(jar.getInputStream(je));
final OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
copyInputStream(in, out);
jar.close();
return true;
}
jar.close();
return false;
}
private static void copyInputStream(final InputStream in, final OutputStream out) throws IOException {
try {
final byte[] buff = new byte[4096];
int n;
while ((n = in.read(buff)) > 0) {
out.write(buff, 0, n);
}
} finally {
out.flush();
out.close();
in.close();
}
}
@Deprecated
public static URL getJarUrl(final File file) throws IOException {
return new URL("jar:" + file.toURI().toURL().toExternalForm() + "!/");
}
public static JarFile getRunningJar() throws IOException {
if (!RUNNING_FROM_JAR) {
// null if not running from jar
return null;
}
String path = new File(JarUtils.class.getProtectionDomain().getCodeSource().getLocation().getPath())
.getAbsolutePath();
path = URLDecoder.decode(path, "UTF-8");
return new JarFile(path);
}
private static boolean RUNNING_FROM_JAR = false;
static {
final URL resource = JarUtils.class.getClassLoader().getResource("plugin.yml");
if (resource != null) {
RUNNING_FROM_JAR = true;
}
}
@Deprecated
public static void addClassPath(final URL url) {
final URLClassLoader sysloader = (URLClassLoader) Bukkit.class.getClassLoader();
final Class<URLClassLoader> sysclass = URLClassLoader.class;
try {
final Method method = sysclass.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(sysloader, url);
} catch (Throwable t) {
MsgUtils.warn("无法添加添加 &4" + url + "&c 到运行库");
MsgUtils.warn(t.getMessage());
}
}
}

View File

@ -0,0 +1,9 @@
package me.skymc.taboolib.listener;
/**
* @Author sky
* @Since 2018-08-25 10:16
*/
public class TListenerCommand {
}

View File

@ -1,5 +1,6 @@
package me.skymc.taboolib.listener; package me.skymc.taboolib.listener;
import com.ilummc.tlib.util.Ref;
import com.ilummc.tlib.util.Strings; import com.ilummc.tlib.util.Strings;
import me.skymc.taboolib.fileutils.FileUtils; import me.skymc.taboolib.fileutils.FileUtils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -10,6 +11,7 @@ import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.event.server.PluginEnableEvent; import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.*;
@ -56,7 +58,7 @@ public class TListenerHandler implements Listener {
// 实例化监听器 // 实例化监听器
Listener listener = plugin.getClass().equals(pluginClass) ? (Listener) plugin : (Listener) pluginClass.newInstance(); Listener listener = plugin.getClass().equals(pluginClass) ? (Listener) plugin : (Listener) pluginClass.newInstance();
listeners.computeIfAbsent(plugin.getName(), name -> new ArrayList<>()).add(listener); listeners.computeIfAbsent(plugin.getName(), name -> new ArrayList<>()).add(listener);
} catch (InstantiationException | IllegalAccessException e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }

View File

@ -5,6 +5,8 @@ import net.milkbowl.vault.permission.Permission;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.RegisteredServiceProvider;
import java.util.Arrays;
public class PermissionUtils { public class PermissionUtils {
private static Permission perms; private static Permission perms;
@ -27,14 +29,6 @@ public class PermissionUtils {
} }
public static boolean hasPermission(Player player, String perm) { public static boolean hasPermission(Player player, String perm) {
if (perms.playerHas(player, perm)) { return perms.playerHas(player, perm) || Arrays.stream(perms.getPlayerGroups(player)).anyMatch(group -> perms.groupHas(player.getWorld(), group, perm));
return true;
}
for (String group : perms.getPlayerGroups(player)) {
if (perms.groupHas(player.getWorld(), group, perm)) {
return true;
}
}
return false;
} }
} }

View File

@ -4,9 +4,11 @@ import com.google.common.collect.ImmutableList;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -88,4 +90,50 @@ public class PlayerUtils {
player.setScoreboard(Bukkit.getScoreboardManager().getNewScoreboard()); player.setScoreboard(Bukkit.getScoreboardManager().getNewScoreboard());
} }
} }
/**
* 获取玩家的鱼钩
*
* @param player 玩家
* @return net.minecraft.server.{version}.EntityFishingHook
*/
public static Object getPlayerHookedFish(HumanEntity player) {
try {
Object entityHuman = player.getClass().getMethod("getHandle").invoke(player);
return entityHuman.getClass().getField("hookedFish").get(entityHuman);
} catch (Exception ignored) {
}
return null;
}
/**
* 获取鱼钩的钓鱼时间
*
* @param fishHook 鱼钩
* @return int
*/
public static int getFishingTicks(Object fishHook) {
try {
Field fishingTicks = fishHook.getClass().getDeclaredField("h");
fishingTicks.setAccessible(true);
return (int) fishingTicks.get(fishHook);
} catch (Exception ignored) {
}
return -1;
}
/**
* 设置鱼钩的钓鱼时间
*
* @param fishHook 鱼钩
* @param ticks 时间
*/
public static void setFishingTicks(Object fishHook, int ticks) {
try {
Field fishingTicks = fishHook.getClass().getDeclaredField("h");
fishingTicks.setAccessible(true);
fishingTicks.set(fishHook, ticks);
} catch (Exception ignored) {
}
}
} }

View File

@ -2,7 +2,6 @@ package me.skymc.taboolib.scoreboard;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
@ -14,7 +13,6 @@ import java.lang.reflect.Constructor;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
public class SimpleScoreboard { public class SimpleScoreboard {
private static Map<String, OfflinePlayer> cache = new HashMap<>(); private static Map<String, OfflinePlayer> cache = new HashMap<>();
@ -38,11 +36,9 @@ public class SimpleScoreboard {
public void add(String text, Integer score) { public void add(String text, Integer score) {
text = ChatColor.translateAlternateColorCodes('&', text); text = ChatColor.translateAlternateColorCodes('&', text);
if (remove(score, text, false) || !scores.containsValue(score)) { if (remove(score, text, false) || !scores.containsValue(score)) {
updated.add(text); updated.add(text);
} }
scores.put(text, score); scores.put(text, score);
} }
@ -52,28 +48,23 @@ public class SimpleScoreboard {
public boolean remove(Integer score, String n, boolean b) { public boolean remove(Integer score, String n, boolean b) {
String toRemove = get(score, n); String toRemove = get(score, n);
if (toRemove == null) {
if (toRemove == null)
return false; return false;
}
scores.remove(toRemove); scores.remove(toRemove);
if (b) {
if(b)
removed.add(score); removed.add(score);
}
return true; return true;
} }
public String get(int score, String n) { public String get(int score, String n) {
String str = null; String str = null;
for (Map.Entry<String, Integer> entry : scores.entrySet()) { for (Map.Entry<String, Integer> entry : scores.entrySet()) {
if (entry.getValue().equals(score) && if (entry.getValue().equals(score) && !entry.getKey().equals(n)) {
!entry.getKey().equals(n)) {
str = entry.getKey(); str = entry.getKey();
} }
} }
return str; return str;
} }
@ -81,18 +72,15 @@ public class SimpleScoreboard {
Team team; Team team;
ChatColor color = ChatColor.values()[pos]; ChatColor color = ChatColor.values()[pos];
OfflinePlayer result; OfflinePlayer result;
if (!cache.containsKey(color.toString())) {
if (!cache.containsKey(color.toString()))
cache.put(color.toString(), getOfflinePlayerSkipLookup(color.toString())); cache.put(color.toString(), getOfflinePlayerSkipLookup(color.toString()));
}
result = cache.get(color.toString()); result = cache.get(color.toString());
try { try {
team = scoreboard.registerNewTeam("text-" + (teams.size() + 1)); team = scoreboard.registerNewTeam("text-" + (teams.size() + 1));
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
team = scoreboard.getTeam("text-" + (teams.size())); team = scoreboard.getTeam("text-" + (teams.size()));
} }
applyText(team, text, result); applyText(team, text, result);
teams.add(team); teams.add(team);
@ -102,30 +90,26 @@ public class SimpleScoreboard {
private void applyText(Team team, String text, OfflinePlayer result) { private void applyText(Team team, String text, OfflinePlayer result) {
Iterator<String> iterator = Splitter.fixedLength(16).split(text).iterator(); Iterator<String> iterator = Splitter.fixedLength(16).split(text).iterator();
String prefix = iterator.next(); String prefix = iterator.next();
team.setPrefix(prefix); team.setPrefix(prefix);
if (!team.hasPlayer(result)) {
if(!team.hasPlayer(result))
team.addPlayer(result); team.addPlayer(result);
}
if (text.length() > 16) { if (text.length() > 16) {
String prefixColor = ChatColor.getLastColors(prefix); String prefixColor = ChatColor.getLastColors(prefix);
String suffix = iterator.next(); String suffix = iterator.next();
if (prefix.endsWith(String.valueOf(ChatColor.COLOR_CHAR))) { if (prefix.endsWith(String.valueOf(ChatColor.COLOR_CHAR))) {
prefix = prefix.substring(0, prefix.length() - 1); prefix = prefix.substring(0, prefix.length() - 1);
team.setPrefix(prefix); team.setPrefix(prefix);
prefixColor = ChatColor.getByChar(suffix.charAt(0)).toString(); prefixColor = ChatColor.getByChar(suffix.charAt(0)).toString();
suffix = suffix.substring(1); suffix = suffix.substring(1);
} }
if (prefixColor == null) {
if (prefixColor == null)
prefixColor = ""; prefixColor = "";
if (suffix.length() > 16) {
suffix = suffix.substring(0, (13 - prefixColor.length())); // cut off suffix, done if text is over 30 characters
} }
if (suffix.length() > 16) {
// cut off suffix, done if text is over 30 characters
suffix = suffix.substring(0, (13 - prefixColor.length()));
}
team.setSuffix((prefixColor.equals("") ? ChatColor.RESET : prefixColor) + suffix); team.setSuffix((prefixColor.equals("") ? ChatColor.RESET : prefixColor) + suffix);
} }
} }
@ -134,74 +118,59 @@ public class SimpleScoreboard {
if (updated.isEmpty()) { if (updated.isEmpty()) {
return; return;
} }
if (obj == null) { if (obj == null) {
obj = scoreboard.registerNewObjective((title.length() > 16 ? title.substring(0, 15) : title), "dummy"); obj = scoreboard.registerNewObjective((title.length() > 16 ? title.substring(0, 15) : title), "dummy");
obj.setDisplayName(title); obj.setDisplayName(title);
obj.setDisplaySlot(DisplaySlot.SIDEBAR); obj.setDisplaySlot(DisplaySlot.SIDEBAR);
} }
removed.forEach((remove) -> {
removed.stream().forEach((remove) -> {
for (String s : scoreboard.getEntries()) { for (String s : scoreboard.getEntries()) {
Score score = obj.getScore(s); Score score = obj.getScore(s);
if (score == null) {
if (score == null)
continue; continue;
}
if (score.getScore() != remove) if (score.getScore() != remove) {
continue; continue;
}
scoreboard.resetScores(s); scoreboard.resetScores(s);
} }
}); });
removed.clear(); removed.clear();
int index = scores.size(); int index = scores.size();
for (Map.Entry<String, Integer> text : scores.entrySet()) { for (Map.Entry<String, Integer> text : scores.entrySet()) {
Team t = scoreboard.getTeam(ChatColor.values()[text.getValue()].toString()); Team t = scoreboard.getTeam(ChatColor.values()[text.getValue()].toString());
Map.Entry<Team, OfflinePlayer> team; Map.Entry<Team, OfflinePlayer> team;
if (!updated.contains(text.getKey())) {
if(!updated.contains(text.getKey())) {
continue; continue;
} }
if (t != null) {
if(t != null) {
String color = ChatColor.values()[text.getValue()].toString(); String color = ChatColor.values()[text.getValue()].toString();
if (!cache.containsKey(color)) { if (!cache.containsKey(color)) {
cache.put(color, getOfflinePlayerSkipLookup(color)); cache.put(color, getOfflinePlayerSkipLookup(color));
} }
team = new AbstractMap.SimpleEntry<>(t, cache.get(color)); team = new AbstractMap.SimpleEntry<>(t, cache.get(color));
applyText(team.getKey(), text.getKey(), team.getValue()); applyText(team.getKey(), text.getKey(), team.getValue());
index -= 1; index -= 1;
continue; continue;
} else { } else {
team = createTeam(text.getKey(), text.getValue()); team = createTeam(text.getKey(), text.getValue());
} }
Integer score = text.getValue() != null ? text.getValue() : index; Integer score = text.getValue() != null ? text.getValue() : index;
obj.getScore(team.getValue()).setScore(score); obj.getScore(team.getValue()).setScore(score);
index -= 1; index -= 1;
} }
updated.clear(); updated.clear();
} }
public void setTitle(String title) { public void setTitle(String title) {
this.title = ChatColor.translateAlternateColorCodes('&', title); this.title = ChatColor.translateAlternateColorCodes('&', title);
if (obj != null) {
if(obj != null)
obj.setDisplayName(this.title); obj.setDisplayName(this.title);
} }
}
public void reset() { public void reset() {
for (Team t : teams) teams.forEach(Team::unregister);
t.unregister();
teams.clear(); teams.clear();
scores.clear(); scores.clear();
} }
@ -211,8 +180,7 @@ public class SimpleScoreboard {
} }
public void send(Player... players) { public void send(Player... players) {
for (Player p : players) Arrays.stream(players).forEach(p -> p.setScoreboard(scoreboard));
p.setScoreboard(scoreboard);
} }
private final UUID invalidUserUUID = UUID.nameUUIDFromBytes("InvalidUsername".getBytes(Charsets.UTF_8)); private final UUID invalidUserUUID = UUID.nameUUIDFromBytes("InvalidUsername".getBytes(Charsets.UTF_8));
@ -234,17 +202,14 @@ public class SimpleScoreboard {
} }
if (craftOfflinePlayerConstructor == null) { if (craftOfflinePlayerConstructor == null) {
Class<?> serverClass = Bukkit.getServer().getClass(); Class<?> serverClass = Bukkit.getServer().getClass();
Class<?> craftOfflinePlayerClass = Class.forName(serverClass.getName() Class<?> craftOfflinePlayerClass = Class.forName(serverClass.getName().replace("CraftServer", "CraftOfflinePlayer"));
.replace("CraftServer", "CraftOfflinePlayer")); craftOfflinePlayerConstructor = craftOfflinePlayerClass.getDeclaredConstructor(serverClass, gameProfileClass);
craftOfflinePlayerConstructor = craftOfflinePlayerClass.getDeclaredConstructor(
serverClass, gameProfileClass
);
craftOfflinePlayerConstructor.setAccessible(true); craftOfflinePlayerConstructor.setAccessible(true);
} }
Object gameProfile = gameProfileConstructor.newInstance(invalidUserUUID, name); Object gameProfile = gameProfileConstructor.newInstance(invalidUserUUID, name);
Object craftOfflinePlayer = craftOfflinePlayerConstructor.newInstance(Bukkit.getServer(), gameProfile); Object craftOfflinePlayer = craftOfflinePlayerConstructor.newInstance(Bukkit.getServer(), gameProfile);
return (OfflinePlayer) craftOfflinePlayer; return (OfflinePlayer) craftOfflinePlayer;
} catch (Throwable t) { // Fallback if fail } catch (Throwable t) {
return Bukkit.getOfflinePlayer(name); return Bukkit.getOfflinePlayer(name);
} }
} }

View File

@ -30,7 +30,7 @@ public class TabooLibClient {
public static void init() { public static void init() {
if (TabooLibSettings.load()) { if (TabooLibSettings.load()) {
connect(); connect();
Bukkit.getScheduler().runTaskTimerAsynchronously(TabooLib.instance(), TabooLibClient::reconnect, 0, 20); Bukkit.getScheduler().runTaskTimerAsynchronously(TabooLib.instance(), TabooLibClient::reconnect, 0, 100);
} else { } else {
TLocale.sendToConsole("COMMUNICATION.FAILED-LOAD-SETTINGS", TabooLibSettings.getThrowable().toString()); TLocale.sendToConsole("COMMUNICATION.FAILED-LOAD-SETTINGS", TabooLibSettings.getThrowable().toString());
} }
@ -70,7 +70,7 @@ public class TabooLibClient {
} }
return; return;
} catch (IOException e) { } catch (IOException e) {
TLocale.sendToConsole("COMMUNICATION.FAILED-CONNECT-CLIENT", e.toString()); TLocale.sendToConsole("COMMUNICATION.FAILED-CONNECT-CLIENT", e.getMessage());
return; return;
} }
@ -80,7 +80,7 @@ public class TabooLibClient {
packet.readOnClient(); packet.readOnClient();
} }
} catch (IOException e) { } catch (IOException e) {
TLocale.sendToConsole("COMMUNICATION.FAILED-READING-PACKET", e.toString()); TLocale.sendToConsole("COMMUNICATION.FAILED-READING-PACKET", e.getMessage());
} }
}); });
} }

View File

@ -1,5 +1,8 @@
package me.skymc.taboolib.string; package me.skymc.taboolib.string;
import com.ilummc.tlib.util.Strings;
import javax.annotation.Nullable;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
@ -65,6 +68,26 @@ public class ArrayUtils {
return (T) objectInputStream.readObject(); return (T) objectInputStream.readObject();
} }
public static <T> T skipEmpty(T obj) {
return skipEmpty(obj, null);
}
public static <T> T[] skipEmpty(T[] obj) {
return skipEmpty(obj, null);
}
public static <T> T skipEmpty(T obj, T def) {
return Strings.isEmpty(String.valueOf(obj)) ? def : obj;
}
public static <T> T[] skipEmpty(T[] obj, T[] def) {
if (obj.length == 0) {
return def;
}
T firstElement = skipEmpty(obj[0]);
return firstElement == null ? def : obj;
}
// ********************************* // *********************************
// //
// Deprecated // Deprecated

View File

@ -2,6 +2,7 @@ package me.skymc.taboolib.string.obfuscated;
import javax.xml.bind.DatatypeConverter; import javax.xml.bind.DatatypeConverter;
@Deprecated
public class CT { public class CT {
public static String decode(CodeType type, String string) { public static String decode(CodeType type, String string) {
@ -16,6 +17,7 @@ public class CT {
} }
return text.toString(); return text.toString();
} }
default:
} }
return ""; return "";
} }
@ -27,16 +29,17 @@ public class CT {
} }
case BINARY: { case BINARY: {
StringBuilder binary = new StringBuilder(); StringBuilder binary = new StringBuilder();
for (byte b: string.getBytes()) { for (byte b : string.getBytes()) {
int value = b; int value = b;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
binary.append((value & 128) == 0 ? 0: 1); binary.append((value & 128) == 0 ? 0 : 1);
value <<= 1; value <<= 1;
} }
binary.append(" "); binary.append(" ");
} }
return binary.toString(); return binary.toString();
} }
default:
} }
return ""; return "";
} }

View File

@ -5,6 +5,7 @@ import java.util.LinkedList;
/** /**
* @author sky * @author sky
*/ */
@Deprecated
public class ThreadUtils { public class ThreadUtils {
private static final LinkedList<Runnable> queue = new LinkedList<>(); private static final LinkedList<Runnable> queue = new LinkedList<>();

View File

@ -13,7 +13,11 @@ import org.bukkit.command.CommandSender;
* @Author sky * @Author sky
* @Since 2018-06-22 17:09 * @Since 2018-06-22 17:09
*/ */
@TCommand(name = "translateuuid") @TCommand(
name = "translateuuid",
aliases = "tuuid",
permission = "taboolib.admin"
)
public class TranslateUUIDCommand extends BaseMainCommand { public class TranslateUUIDCommand extends BaseMainCommand {
@Override @Override

View File

@ -1,12 +0,0 @@
import org.bukkit.Bukkit;
public class testshell {
public void onEnable() {
Bukkit.broadcastMessage("testshell enable!");
}
public void onDisable() {
Bukkit.broadcastMessage("testshell disable!");
}
}

View File

@ -172,7 +172,9 @@ COMMANDS:
- '&8[&3&lTabooLib&8] &7指令 &f{0} &7不存在' - '&8[&3&lTabooLib&8] &7指令 &f{0} &7不存在'
- '&8[&3&lTabooLib&8] &7你可能想要:' - '&8[&3&lTabooLib&8] &7你可能想要:'
- '&8[&3&lTabooLib&8] &7{1}' - '&8[&3&lTabooLib&8] &7{1}'
COMMAND-REGISTER: '&7自动为插件 &f{0} &7的命令 &f{1} &7注册 &f{2} &7条子命令' COMMAND-CREATE: '&7自动为插件 &f{0} &7的 &f{1} &7命令注册到服务器'
COMMAND-CREATE-FAILED: '&7插件 &f{0} &7的 &f{1} &7命令注册失败: &c{2}'
COMMAND-REGISTER: '&7自动为插件 &f{0} &7的 &f{1} &7命令注册 &f{2} &7条子命令'
COMMAND-HELP: ' §f/{0} {1} {2} §6- §e{3}' COMMAND-HELP: ' §f/{0} {1} {2} §6- §e{3}'
COMMAND-ARGUMENT: '§7<§8{0}§7>' COMMAND-ARGUMENT: '§7<§8{0}§7>'
COMMAND-ARGUMENT-REQUIRE: '§7[§8{0}§7]' COMMAND-ARGUMENT-REQUIRE: '§7[§8{0}§7]'
@ -242,19 +244,6 @@ COMMANDS:
PLAYER-ONLINE: '&8[&3&lTabooLib&8] &4服务器有玩家在线无法更新插件.' PLAYER-ONLINE: '&8[&3&lTabooLib&8] &4服务器有玩家在线无法更新插件.'
UPDATE-START: '&8[&3&lTabooLib&8] &7开始下载:&f {0}' UPDATE-START: '&8[&3&lTabooLib&8] &7开始下载:&f {0}'
UPDATE-SUCCESS: '&8[&3&lTabooLib&8] &7最新版下载完成, 服务器即将重启!' UPDATE-SUCCESS: '&8[&3&lTabooLib&8] &7最新版下载完成, 服务器即将重启!'
JAVASHELL:
DESCRIPTION:
LOAD: '载入脚本'
UNLOAD: '卸载脚本'
ARGUMENTS:
LOAD:
0: '名称'
UNLOAD:
0: '名称'
INVALID-NAME: '&8[&3&lTabooLib&8] &4请输入正确的名称'
INVALID-SHELL: '&8[&3&lTabooLib&8] &4脚本 &c{0} &4不存在'
SUCCESS-LOAD: '&8[&3&lTabooLib&8] &7脚本 &f{0} &7已载入'
SUCCESS-UNLOAD: '&8[&3&lTabooLib&8] &7脚本 &f{0} &7已卸载'
PLAYERTAG: PLAYERTAG:
DESCRIPTION: DESCRIPTION:
DISPLAY: '设置玩家展示名称' DISPLAY: '设置玩家展示名称'
@ -582,4 +571,4 @@ COMMUNICATION:
SUCCESS-CONNECTED: '§8[§3§lTabooLibClient§8] &7本地通讯网络连接成功.' SUCCESS-CONNECTED: '§8[§3§lTabooLibClient§8] &7本地通讯网络连接成功.'
CLIENT-JOINED: '§8[§3§lTabooLibClient§8] &7服务器 &flocalhost:{0} &7加入本地通讯网络.' CLIENT-JOINED: '§8[§3§lTabooLibClient§8] &7服务器 &flocalhost:{0} &7加入本地通讯网络.'
CLIENT-QUITED: '§8[§3§lTabooLibClient§8] &7服务器 &flocalhost:{0} &7退出本地通讯网络.' CLIENT-QUITED: '§8[§3§lTabooLibClient§8] &7服务器 &flocalhost:{0} &7退出本地通讯网络.'
CLIENT-MESSAGE: '§8[§3§lTabooLibClient§8] &7服务器 &flocalhost:{0} &7发送信息: &f{1}' PACKET-MESSAGE: '§8[§3§lTabooLibClient§8] &7服务器 &flocalhost:{0} &7发送信息: &f{1}'

View File

@ -6,27 +6,10 @@ author: [lzzelAliz, 坏黑]
depend: [Vault] depend: [Vault]
softdepend: [PlaceholderAPI, Skript, MassiveLag] softdepend: [PlaceholderAPI, Skript, MassiveLag]
# 两个命令删除预定
commands: commands:
taboolib:
aliases: [tlib]
permission: taboolib.admin
language2: language2:
aliases: [lang2] aliases: [lang2]
permission: taboolib.admin permission: taboolib.admin
tabooliblocale:
aliases: [taboolocale, tlocale]
permission: taboolib.admin
taboolibplugin:
aliases: [tabooplugin, tplugin]
permission: taboolib.admin
taboolibexecute:
aliases: [texecute]
permission: taboolib.admin
taboolibrarymodule: taboolibrarymodule:
aliases: [tlm] aliases: [tlm]
translateuuid:
aliases: [tuuid]
permission: taboolib.admin
tabooliblogs:
aliases: [tlog, tlogs]
permission: taboolib.admin