diff --git a/README.md b/README.md index 179fc99..e2c0c36 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ - **提示权限包到期** - **玩家登录时删除过期的或无效数据** - **提示剩余时间** +- **权限包到期可执行自定义命令** - 取消前置插件 diff --git a/config/packages.yml b/config/packages.yml index 82d53fa..7d831ed 100644 --- a/config/packages.yml +++ b/config/packages.yml @@ -42,3 +42,8 @@ packages: groups: - group1 - group2:world1 + # 权限包过期后执行的控制台命令 + # Package expire console commands. + expireCommands: + - 'bc %player% 的权限包到期了.' + - 'bc 请及时续期.' diff --git a/pom.xml b/pom.xml index 7ab6edb..81b8dfd 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 gg.frog.mc permissionstime - 0.2.4-SNAPSHOT + 0.3.0-SNAPSHOT jar PermissionsTime 支持跨服的权限限时插件 @@ -34,6 +34,10 @@ bstats-repo http://repo.bstats.org/content/repositories/releases/ + + placeholderapi + http://repo.extendedclip.com/content/repositories/placeholderapi/ + @@ -54,6 +58,12 @@ 1.6 provided + + me.clip + placeholderapi + 2.0.8 + provided + lib.PatPeter.SQLibrary SQLibrary diff --git a/src/main/gg/frog/mc/permissionstime/model/cfg/PermissionPackageBean.java b/src/main/gg/frog/mc/permissionstime/model/cfg/PermissionPackageBean.java index 2526cb5..6d877af 100644 --- a/src/main/gg/frog/mc/permissionstime/model/cfg/PermissionPackageBean.java +++ b/src/main/gg/frog/mc/permissionstime/model/cfg/PermissionPackageBean.java @@ -31,279 +31,305 @@ import net.milkbowl.vault.permission.Permission; */ public class PermissionPackageBean implements IConfigBean { - private String displayName = null; - private String id; - private String type; - private Boolean glowing; - private List lores = new ArrayList<>(); - private Boolean global; - private List permissions = new ArrayList<>(); - private List groups = new ArrayList<>(); - private static Map taskMap = new ConcurrentHashMap<>(); + private String displayName = null; + private String id; + private String type; + private Boolean glowing; + private List lores = new ArrayList<>(); + private Boolean global; + private List permissions = new ArrayList<>(); + private List groups = new ArrayList<>(); + private List expireCommands = new ArrayList<>(); + private static Map taskMap = new ConcurrentHashMap<>(); - public String getDisplayName() { - return displayName; - } + public String getDisplayName() { + return displayName; + } - public void setDisplayName(String displayName) { - this.displayName = displayName; - } + public void setDisplayName(String displayName) { + this.displayName = displayName; + } - public String getId() { - return id; - } + public String getId() { + return id; + } - public void setId(String id) { - this.id = id; - } + public void setId(String id) { + this.id = id; + } - public String getType() { - return type; - } + public String getType() { + return type; + } - public void setType(String type) { - this.type = type; - } + public void setType(String type) { + this.type = type; + } - public Boolean getGlowing() { - return glowing; - } + public Boolean getGlowing() { + return glowing; + } - public void setGlowing(Boolean glowing) { - this.glowing = glowing; - } + public void setGlowing(Boolean glowing) { + this.glowing = glowing; + } - public List getLores() { - return lores; - } + public List getLores() { + return lores; + } - public void setLores(List lores) { - this.lores = lores; - } + public void setLores(List lores) { + this.lores = lores; + } - public Boolean getGlobal() { - return global; - } + public Boolean getGlobal() { + return global; + } - public void setGlobal(Boolean global) { - this.global = global; - } + public void setGlobal(Boolean global) { + this.global = global; + } - public List getPermissions() { - return permissions; - } + public List getPermissions() { + return permissions; + } - public void setPermissions(List permissions) { - this.permissions = permissions; - } + public void setPermissions(List permissions) { + this.permissions = permissions; + } - public List getGroups() { - return groups; - } + public List getGroups() { + return groups; + } - public void setGroups(List groups) { - this.groups = groups; - } + public void setGroups(List groups) { + this.groups = groups; + } - @Override - public YamlConfiguration toConfig() { - YamlConfiguration config = new YamlConfiguration(); - config.set("displayName", displayName); - config.set("id", id); - config.set("type", type); - config.set("glowing", glowing); - config.set("lores", lores); - config.set("global", global); - config.set("permissions", permissions); - config.set("groups", groups); - return config; - } + public List getExpireCommands() { + return expireCommands; + } - @Override - public void toConfigBean(MemorySection config) { - displayName = config.getString("displayName"); - if (displayName == null) { - displayName = "No Name"; - } - id = config.getString("id"); - type = config.getString("type"); - if (id == null && type == null) { - type = "NETHER_STAR"; - } - glowing = config.getBoolean("glowing"); - lores = config.getStringList("lores"); - global = config.getBoolean("global"); - permissions = config.getStringList("permissions"); - groups = config.getStringList("groups"); - } + public void setExpireCommands(List expireCommands) { + this.expireCommands = expireCommands; + } - @Override - public String toString() { - return "PermissionPackageBean [displayName=" + displayName + ", id=" + id + ", type=" + type + ", glowing=" + glowing + ", lores=" + lores + ", global=" + global + ", permissions=" + permissions + ", groups=" + groups + "]"; - } + @Override + public YamlConfiguration toConfig() { + YamlConfiguration config = new YamlConfiguration(); + config.set("displayName", displayName); + config.set("id", id); + config.set("type", type); + config.set("glowing", glowing); + config.set("lores", lores); + config.set("global", global); + config.set("permissions", permissions); + config.set("groups", groups); + config.set("expireCommands", expireCommands); + return config; + } - private void givePlayer(OfflinePlayer player, Server server, Permission permission) { - List worlds = server.getWorlds(); - for (String pem : permissions) { - String[] args = pem.split(":"); - pem = args[0]; - if (args.length > 1) { - for (int i = 1; i < args.length; i++) { - String worldName = args[i]; - permission.playerAdd(worldName, player, pem); - } - } else { - for (World world : worlds) { - String worldName = world.getName(); - permission.playerAdd(worldName, player, pem); - } - } - } - for (String groupName : groups) { - String[] args = groupName.split(":"); - groupName = args[0]; - if (args.length > 1) { - for (int i = 1; i < args.length; i++) { - String worldName = args[i]; - permission.playerAddGroup(worldName, player, groupName); - } - } else { - for (World world : worlds) { - String worldName = world.getName(); - permission.playerAddGroup(worldName, player, groupName); - } - } - } - } + @Override + public void toConfigBean(MemorySection config) { + displayName = config.getString("displayName"); + if (displayName == null) { + displayName = "No Name"; + } + id = config.getString("id"); + type = config.getString("type"); + if (id == null && type == null) { + type = "NETHER_STAR"; + } + glowing = config.getBoolean("glowing"); + lores = config.getStringList("lores"); + global = config.getBoolean("global"); + permissions = config.getStringList("permissions"); + groups = config.getStringList("groups"); + expireCommands = config.getStringList("expireCommands"); + } - private void clearPlayer(OfflinePlayer player, Server server, Permission permission) { - List worlds = server.getWorlds(); - for (String pem : permissions) { - String[] args = pem.split(":"); - pem = args[0]; - if (args.length > 1) { - for (int i = 1; i < args.length; i++) { - String worldName = args[i]; - permission.playerRemove(worldName, player, pem); - } - } else { - for (World world : worlds) { - String worldName = world.getName(); - permission.playerRemove(worldName, player, pem); - } - } - } - for (String groupName : groups) { - String[] args = groupName.split(":"); - groupName = args[0]; - if (args.length > 1) { - for (int i = 1; i < args.length; i++) { - String worldName = args[i]; - permission.playerRemoveGroup(worldName, player, groupName); - } - } else { - for (World world : worlds) { - String worldName = world.getName(); - permission.playerRemoveGroup(worldName, player, groupName); - } - } - } - } + @Override + public String toString() { + return "PermissionPackageBean [displayName=" + displayName + ", id=" + id + ", type=" + type + ", glowing=" + + glowing + ", lores=" + lores + ", global=" + global + ", permissions=" + permissions + ", groups=" + + groups + ", expireCommands=" + expireCommands + "]"; + } - public static void reloadPlayerPermissions(OfflinePlayer player, List pdbList, PluginMain plugin) { - reloadPlayerPermissions(player, pdbList, plugin, true); - } + private void givePlayer(OfflinePlayer player, Server server, Permission permission) { + List worlds = server.getWorlds(); + for (String pem : permissions) { + String[] args = pem.split(":"); + pem = args[0]; + if (args.length > 1) { + for (int i = 1; i < args.length; i++) { + String worldName = args[i]; + permission.playerAdd(worldName, player, pem); + } + } else { + for (World world : worlds) { + String worldName = world.getName(); + permission.playerAdd(worldName, player, pem); + } + } + } + for (String groupName : groups) { + String[] args = groupName.split(":"); + groupName = args[0]; + if (args.length > 1) { + for (int i = 1; i < args.length; i++) { + String worldName = args[i]; + permission.playerAddGroup(worldName, player, groupName); + } + } else { + for (World world : worlds) { + String worldName = world.getName(); + permission.playerAddGroup(worldName, player, groupName); + } + } + } + } - public static void reloadPlayerPermissions(OfflinePlayer player, List pdbList, PluginMain plugin, boolean async) { - long delay = -1; - long now = new Date().getTime(); - PermissionPackageBean addPpb = new PermissionPackageBean(); - addPpb.getGroups().add(PackagesCfg.DEFAULT_GROUP); - PermissionPackageBean subPpb = new PermissionPackageBean(); - subPpb.getPermissions().addAll(PackagesCfg.allPermissions); - subPpb.getGroups().addAll(PackagesCfg.allGroups); - for (PlayerDataBean pdb : pdbList) { - long leftTime = pdb.getExpire() - now; - if (leftTime > 0) { - if (delay == -1) { - delay = leftTime; - } else if (delay > leftTime) { - delay = leftTime; - } - } - PermissionPackageBean p = PackagesCfg.PACKAGES.get(pdb.getPackageName()); - if (p != null) { - addPpb.getPermissions().addAll(p.getPermissions()); - subPpb.getPermissions().removeAll(p.getPermissions()); - addPpb.getGroups().addAll(p.getGroups()); - subPpb.getGroups().removeAll(p.getGroups()); - } - } - if (async) { - plugin.getServer().getScheduler().runTask(plugin, new Runnable() { - @Override - public void run() { - try { - subPpb.clearPlayer(player, plugin.getServer(), plugin.getPermission()); - addPpb.givePlayer(player, plugin.getServer(), plugin.getPermission()); - } catch (Exception e) { - e.printStackTrace(); - player.getPlayer().sendMessage(StrUtil.messageFormat(PluginCfg.PLUGIN_PREFIX + LangCfg.MSG_FAIL_SET_PERMISSION)); - } - } - }); - } else { - subPpb.clearPlayer(player, plugin.getServer(), plugin.getPermission()); - addPpb.givePlayer(player, plugin.getServer(), plugin.getPermission()); - } - checkExpire(player, plugin); - BukkitTask task = taskMap.get(player.getUniqueId().toString()); - if (pdbList.size() > 0) { - delay = (delay / 1000 + 1) * 20;// 1秒=20ticks - task = plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, new Runnable() { - @Override - public void run() { - List tpdbList = plugin.getSqlManager().getTime(player.getUniqueId().toString()); - reloadPlayerPermissions(player, tpdbList, plugin); - } - }, delay); - taskMap.put(player.getUniqueId().toString(), task); - } - } + private void clearPlayer(OfflinePlayer player, Server server, Permission permission) { + List worlds = server.getWorlds(); + for (String pem : permissions) { + String[] args = pem.split(":"); + pem = args[0]; + if (args.length > 1) { + for (int i = 1; i < args.length; i++) { + String worldName = args[i]; + permission.playerRemove(worldName, player, pem); + } + } else { + for (World world : worlds) { + String worldName = world.getName(); + permission.playerRemove(worldName, player, pem); + } + } + } + for (String groupName : groups) { + String[] args = groupName.split(":"); + groupName = args[0]; + if (args.length > 1) { + for (int i = 1; i < args.length; i++) { + String worldName = args[i]; + permission.playerRemoveGroup(worldName, player, groupName); + } + } else { + for (World world : worlds) { + String worldName = world.getName(); + permission.playerRemoveGroup(worldName, player, groupName); + } + } + } + } - public static void delPlayerAllPermissions(OfflinePlayer player, PluginMain plugin) throws Exception { - PermissionPackageBean subPpb = new PermissionPackageBean(); - subPpb.getPermissions().addAll(PackagesCfg.allPermissions); - subPpb.getGroups().addAll(PackagesCfg.allGroups); - plugin.getServer().getScheduler().runTask(plugin, new Runnable() { - @Override - public void run() { - subPpb.clearPlayer(player, plugin.getServer(), plugin.getPermission()); - } - }); - BukkitTask task = taskMap.get(player.getUniqueId().toString()); - if (task != null) { - plugin.getServer().getScheduler().cancelTask(task.getTaskId()); - } - } + public static void reloadPlayerPermissions(OfflinePlayer player, List pdbList, PluginMain plugin) { + reloadPlayerPermissions(player, pdbList, plugin, true); + } - public static void checkExpire(OfflinePlayer player, PluginMain plugin) { - List playerDataList = plugin.getSqlManager().getAllTime(player.getUniqueId().toString()); - long now = new Date().getTime(); - for (PlayerDataBean playerData : playerDataList) { - if (playerData.getExpire() < now) { - PermissionPackageBean packageBean = PackagesCfg.PACKAGES.get(playerData.getPackageName()); - plugin.getServer().getScheduler().runTask(plugin, new Runnable() { - @Override - public void run() { - Player p = player.getPlayer(); - if (p != null) { - p.sendMessage(StrUtil.messageFormat(PluginCfg.PLUGIN_PREFIX + LangCfg.MSG_IS_EXPIRATION_DATE, packageBean != null ? packageBean.getDisplayName() : LangCfg.MSG_UNKNOWN_PACKAGE, playerData.getPackageName())); - } - } - }); - plugin.getSqlManager().delById(playerData.getId()); - } - } - } + public static void reloadPlayerPermissions(OfflinePlayer player, List pdbList, PluginMain plugin, + boolean async) { + long delay = -1; + long now = new Date().getTime(); + PermissionPackageBean addPpb = new PermissionPackageBean(); + addPpb.getGroups().add(PackagesCfg.DEFAULT_GROUP); + PermissionPackageBean subPpb = new PermissionPackageBean(); + subPpb.getPermissions().addAll(PackagesCfg.allPermissions); + subPpb.getGroups().addAll(PackagesCfg.allGroups); + for (PlayerDataBean pdb : pdbList) { + long leftTime = pdb.getExpire() - now; + if (leftTime > 0) { + if (delay == -1) { + delay = leftTime; + } else if (delay > leftTime) { + delay = leftTime; + } + } + PermissionPackageBean p = PackagesCfg.PACKAGES.get(pdb.getPackageName()); + if (p != null) { + addPpb.getPermissions().addAll(p.getPermissions()); + subPpb.getPermissions().removeAll(p.getPermissions()); + addPpb.getGroups().addAll(p.getGroups()); + subPpb.getGroups().removeAll(p.getGroups()); + } + } + if (async) { + plugin.getServer().getScheduler().runTask(plugin, new Runnable() { + @Override + public void run() { + try { + subPpb.clearPlayer(player, plugin.getServer(), plugin.getPermission()); + addPpb.givePlayer(player, plugin.getServer(), plugin.getPermission()); + } catch (Exception e) { + e.printStackTrace(); + player.getPlayer().sendMessage( + StrUtil.messageFormat(PluginCfg.PLUGIN_PREFIX + LangCfg.MSG_FAIL_SET_PERMISSION)); + } + } + }); + } else { + subPpb.clearPlayer(player, plugin.getServer(), plugin.getPermission()); + addPpb.givePlayer(player, plugin.getServer(), plugin.getPermission()); + } + checkExpire(player, plugin); + BukkitTask task = taskMap.get(player.getUniqueId().toString()); + if (pdbList.size() > 0) { + delay = (delay / 1000 + 1) * 20;// 1秒=20ticks + task = plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, new Runnable() { + @Override + public void run() { + List tpdbList = plugin.getSqlManager().getTime(player.getUniqueId().toString()); + reloadPlayerPermissions(player, tpdbList, plugin); + } + }, delay); + taskMap.put(player.getUniqueId().toString(), task); + } + } + + public static void delPlayerAllPermissions(OfflinePlayer player, PluginMain plugin) throws Exception { + PermissionPackageBean subPpb = new PermissionPackageBean(); + subPpb.getPermissions().addAll(PackagesCfg.allPermissions); + subPpb.getGroups().addAll(PackagesCfg.allGroups); + plugin.getServer().getScheduler().runTask(plugin, new Runnable() { + @Override + public void run() { + subPpb.clearPlayer(player, plugin.getServer(), plugin.getPermission()); + } + }); + BukkitTask task = taskMap.get(player.getUniqueId().toString()); + if (task != null) { + plugin.getServer().getScheduler().cancelTask(task.getTaskId()); + } + } + + public static void checkExpire(OfflinePlayer player, PluginMain plugin) { + List playerDataList = plugin.getSqlManager().getAllTime(player.getUniqueId().toString()); + long now = new Date().getTime(); + for (PlayerDataBean playerData : playerDataList) { + if (playerData.getExpire() < now) { + PermissionPackageBean packageBean = PackagesCfg.PACKAGES.get(playerData.getPackageName()); + plugin.getServer().getScheduler().runTask(plugin, new Runnable() { + @Override + public void run() { + Player p = player.getPlayer(); + if (p != null) { + p.sendMessage(StrUtil.messageFormat( + PluginCfg.PLUGIN_PREFIX + LangCfg.MSG_IS_EXPIRATION_DATE, + packageBean != null ? packageBean.getDisplayName() : LangCfg.MSG_UNKNOWN_PACKAGE, + playerData.getPackageName())); + for (String commands : packageBean.getExpireCommands()) { + try { + commands = StrUtil.messageFormat(player.getPlayer(), commands); + plugin.getServer().dispatchCommand(plugin.getServer().getConsoleSender(), commands); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + }); + plugin.getSqlManager().delById(playerData.getId()); + } + } + } } diff --git a/src/main/gg/frog/mc/permissionstime/utils/StrUtil.java b/src/main/gg/frog/mc/permissionstime/utils/StrUtil.java index f1f0e6e..e4189a1 100644 --- a/src/main/gg/frog/mc/permissionstime/utils/StrUtil.java +++ b/src/main/gg/frog/mc/permissionstime/utils/StrUtil.java @@ -4,9 +4,12 @@ import java.text.MessageFormat; import java.util.Date; import org.apache.commons.lang.time.DateFormatUtils; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; import gg.frog.mc.permissionstime.config.LangCfg; import gg.frog.mc.permissionstime.database.IPlayerDataDao; +import me.clip.placeholderapi.PlaceholderAPI; public class StrUtil { @@ -14,9 +17,26 @@ public class StrUtil { private static final long dt = 24 * 60 * IPlayerDataDao.TIME_UNIT; private static final long ht = 60 * IPlayerDataDao.TIME_UNIT; private static final long mt = IPlayerDataDao.TIME_UNIT; + private static final boolean placeholderAPI; + + static { + if(Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) { + placeholderAPI = true; + }else { + placeholderAPI = false; + } + } public static String messageFormat(String src, Object... args) { - return MessageFormat.format(src, args).replace("&", "§").replace("\\n", "\n"); + return MessageFormat.format(src, args).replace("&", "§").replace("\\n", "\n"); + } + + public static String messageFormat(Player player, String src, Object... args) { + String message = MessageFormat.format(src, args).replace("&", "§").replace("\\n", "\n").replace("%player%", player.getDisplayName()); + if(placeholderAPI) { + message = PlaceholderAPI.setPlaceholders(player, message); + } + return message; } public static String timestampToString(long time) { diff --git a/src/resources/packages.yml b/src/resources/packages.yml index 82d53fa..7d831ed 100644 --- a/src/resources/packages.yml +++ b/src/resources/packages.yml @@ -42,3 +42,8 @@ packages: groups: - group1 - group2:world1 + # 权限包过期后执行的控制台命令 + # Package expire console commands. + expireCommands: + - 'bc %player% 的权限包到期了.' + - 'bc 请及时续期.' diff --git a/src/resources/plugin.yml b/src/resources/plugin.yml index a3643fa..2b556fc 100644 --- a/src/resources/plugin.yml +++ b/src/resources/plugin.yml @@ -1,10 +1,11 @@ name: PermissionsTime -version: 0.2.4-SNAPSHOT +version: 0.3.0-SNAPSHOT main: gg.frog.mc.permissionstime.PluginMain author: GeekFrog softdepend: - SQLibrary - Vault +- PlaceholderAPI commands: permissionstime: description: Show all commands. diff --git a/帖子代码.txt b/帖子代码.txt index 85f94a0..7b4ef3b 100644 --- a/帖子代码.txt +++ b/帖子代码.txt @@ -3,7 +3,7 @@ [align=center][table=98%,#4169e1] [tr][td][align=center][size=6][color=#ffffff][b]唠叨[/b][/color][/size][/align][/td][/tr] [/table][/align][align=center][table=98%,gray] -[tr][td][align=center][size=4][color=#ffa500][b]这是本人第一个发布的插件, 希望能让大家满意![/b][/color][/size][/align][align=center][size=4][color=#dda0dd][b]本插件需要JAVA8!!![/b][/color][/size][/align][align=center][size=4][color=#98fb98][b]下载地址在最下面![/b][/color][/size][/align][align=center][size=4][color=#c0c0c0][b]最新版本: [/b][/color][b][color=#8b0000]0.2.3[/color][color=#c0c0c0],推荐大家使用新版本,只需替换插件的jar包和语言文件即可![/color][/b][/size][/align][/td][/tr] +[tr][td][align=center][size=4][color=#ffa500][b]这是本人第一个发布的插件, 希望能让大家满意![/b][/color][/size][/align][align=center][size=4][color=#dda0dd][b]本插件需要JAVA8!!![/b][/color][/size][/align][align=center][size=4][color=#98fb98][b]下载地址在最下面![/b][/color][/size][/align][align=center][size=4][color=#c0c0c0][b]最新版本: [/b][/color][b][color=#8b0000]0.3.0[/color][color=#c0c0c0],推荐大家使用新版本,只需替换插件的jar包和语言文件即可![/color][/b][/size][/align][/td][/tr] [/table][/align][align=center][table=98%,#4169e1] [tr][td][align=center][size=6][color=#ffffff][b]前言[/b][/color][/size][/align][/td][/tr] [/table][/align][align=center][table=98%,gray] @@ -197,6 +197,11 @@ cmd: [tr][td][align=center][size=6][color=#ffffff][b]更新日志[/b][/color][/size][/align][/td][/tr] [/table][/align][align=center][table=98%,gray] [tr][td][spoiler][size=4][b][url=http://ci.frog.gg/jenkins/job/PermissionsTime/changes]详细的更新记录[/url] +[color=#ffffff]2017年8月1日 V0.3.0[/color][quote][color=#000000] +1.权限包到期可执行自定义命令[/color][/quote] +[color=#ffffff]2017年7月31日 V0.2.4[/color][quote][color=#000000] +1.插件统计更换成bstats +2.兼容服务端文件夹路径含有空格字符[/color][/quote] [color=#ffffff]2017年7月27日 V0.2.3[/color][quote][color=#000000] 1.取消保存配置文件 2.语言文件整理[/color][/quote] @@ -221,15 +226,13 @@ cmd: [/table][/align][align=center][table=98%,#4169e1] [tr][td][align=center][size=6][color=#ffffff][b]下载地址[/b][/color][/size][/align][/td][/tr] [/table][/align][align=center][table=98%,gray] -[tr][td][size=4][b][align=center][color=#000] [url=http://ci.frog.gg/jenkins/job/PermissionsTime/57/]V0.2.3版下载地址[/url][/color][/align][align=center][color=#ffffff]前置插件:[/color][color=#000][url=https://dev.bukkit.org/projects/vault/files]vault[/url][/color][color=#000000] , [/color][color=#000][url=https://dev.bukkit.org/projects/sqlibrary/files]sqlibrary[/url][/color][/align][align=center][color=#ffffff]前置插件最好去原站下载适合的版本, 如果无法下载可以在帖内下载。[/color][/align] +[tr][td][size=4][b][align=center][color=#000] [url=http://ci.frog.gg/jenkins/job/PermissionsTime/63/]V0.3.0版下载地址[/url][/color][/align][align=center][color=#ffffff]前置插件:[/color][color=#000][url=https://dev.bukkit.org/projects/vault/files]vault[/url][/color][color=#000000] , [/color][color=#000][url=https://dev.bukkit.org/projects/sqlibrary/files]sqlibrary[/url][/color][/align][align=center][color=#ffffff]前置插件最好去原站下载适合的版本, 如果无法下载可以在帖内下载。[/color][/align] [align=center][b][color=#ffffff]帖内下载:[/color][/b][/align][align=center][color=#000][attach]1101088[/attach][/color][/align][align=center][color=#000][b][color=#ff0000]前置插件必须安装[/color][/b][/color][/align][align=center][color=#000][attach]1101089[/attach][/color][/align][align=center][color=#000][attach]1101090[/attach][/color][/align][align=center][color=#000][attach]1101110[/attach][/color][/align] [align=center][color=#000][color=#ff0000][b]如果大家觉得好用就给点金粒吧,如果不好请告诉我,帮助我改进。[/b][/color][/color][/align][align=center][color=#000][b]BUG可以在帖内回复我。[/b][/color][/align][/b][/size][/td][/tr] [/table][/align][align=center][table=98%,#4169e1] [tr][td][align=center][size=6][color=#ffffff][b]使用统计[/b][/color][/size][/align][/td][/tr] [/table][/align][align=center][table=98%,gray] -[tr][td][align=center][b][size=4][color=#ff0000]图片可能经常抽风[/color][/size][/b][/align] -[align=center][img]http://i.mcstats.org/PermissionsTime/Global+Statistics.borderless.png[/img][/align] -[align=center][img]http://i.mcstats.org/PermissionsTime/Version+Demographics.borderless.png[/img][/align][/td][/tr] +[tr][td][align=center][url=https://bstats.org/plugin/bukkit/PermissionsTime][size=4][b]https://bstats.org/plugin/bukkit/PermissionsTime[/b][/size][/url][/align][/td][/tr] [/table][/align][align=center][table=98%,#4169e1] [tr][td][align=center][size=6][color=#ffffff][b]此插件已加入我的世界公益插件计划[/b][/color][/size][/align][/td][/tr] [/table][/align][align=center][table=98%,gray]