1
1
mirror of https://github.com/geekfrog/PermissionsTime.git synced 2024-11-24 17:28:51 +00:00

权限包到期可执行自定义命令

Signed-off-by: GeekFrog <admin@frog.gg>
This commit is contained in:
GeekFrog 2017-08-01 17:50:44 +08:00
commit 2efc629ea4
8 changed files with 329 additions and 258 deletions

View File

@ -51,6 +51,7 @@
- **提示权限包到期** - **提示权限包到期**
- **玩家登录时删除过期的或无效数据** - **玩家登录时删除过期的或无效数据**
- **提示剩余时间** - **提示剩余时间**
- **权限包到期可执行自定义命令**
- 取消前置插件 - 取消前置插件

View File

@ -42,3 +42,8 @@ packages:
groups: groups:
- group1 - group1
- group2:world1 - group2:world1
# 权限包过期后执行的控制台命令
# Package expire console commands.
expireCommands:
- 'bc %player% 的权限包到期了.'
- 'bc 请及时续期.'

12
pom.xml
View File

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>gg.frog.mc</groupId> <groupId>gg.frog.mc</groupId>
<artifactId>permissionstime</artifactId> <artifactId>permissionstime</artifactId>
<version>0.2.4-SNAPSHOT</version> <version>0.3.0-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>PermissionsTime</name> <name>PermissionsTime</name>
<description>支持跨服的权限限时插件</description> <description>支持跨服的权限限时插件</description>
@ -34,6 +34,10 @@
<id>bstats-repo</id> <id>bstats-repo</id>
<url>http://repo.bstats.org/content/repositories/releases/</url> <url>http://repo.bstats.org/content/repositories/releases/</url>
</repository> </repository>
<repository>
<id>placeholderapi</id>
<url>http://repo.extendedclip.com/content/repositories/placeholderapi/</url>
</repository>
</repositories> </repositories>
<dependencies> <dependencies>
<dependency> <dependency>
@ -54,6 +58,12 @@
<version>1.6</version> <version>1.6</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>
<version>2.0.8</version>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>lib.PatPeter.SQLibrary</groupId> <groupId>lib.PatPeter.SQLibrary</groupId>
<artifactId>SQLibrary</artifactId> <artifactId>SQLibrary</artifactId>

View File

@ -31,279 +31,305 @@ import net.milkbowl.vault.permission.Permission;
*/ */
public class PermissionPackageBean implements IConfigBean { public class PermissionPackageBean implements IConfigBean {
private String displayName = null; private String displayName = null;
private String id; private String id;
private String type; private String type;
private Boolean glowing; private Boolean glowing;
private List<String> lores = new ArrayList<>(); private List<String> lores = new ArrayList<>();
private Boolean global; private Boolean global;
private List<String> permissions = new ArrayList<>(); private List<String> permissions = new ArrayList<>();
private List<String> groups = new ArrayList<>(); private List<String> groups = new ArrayList<>();
private static Map<String, BukkitTask> taskMap = new ConcurrentHashMap<>(); private List<String> expireCommands = new ArrayList<>();
private static Map<String, BukkitTask> taskMap = new ConcurrentHashMap<>();
public String getDisplayName() { public String getDisplayName() {
return displayName; return displayName;
} }
public void setDisplayName(String displayName) { public void setDisplayName(String displayName) {
this.displayName = displayName; this.displayName = displayName;
} }
public String getId() { public String getId() {
return id; return id;
} }
public void setId(String id) { public void setId(String id) {
this.id = id; this.id = id;
} }
public String getType() { public String getType() {
return type; return type;
} }
public void setType(String type) { public void setType(String type) {
this.type = type; this.type = type;
} }
public Boolean getGlowing() { public Boolean getGlowing() {
return glowing; return glowing;
} }
public void setGlowing(Boolean glowing) { public void setGlowing(Boolean glowing) {
this.glowing = glowing; this.glowing = glowing;
} }
public List<String> getLores() { public List<String> getLores() {
return lores; return lores;
} }
public void setLores(List<String> lores) { public void setLores(List<String> lores) {
this.lores = lores; this.lores = lores;
} }
public Boolean getGlobal() { public Boolean getGlobal() {
return global; return global;
} }
public void setGlobal(Boolean global) { public void setGlobal(Boolean global) {
this.global = global; this.global = global;
} }
public List<String> getPermissions() { public List<String> getPermissions() {
return permissions; return permissions;
} }
public void setPermissions(List<String> permissions) { public void setPermissions(List<String> permissions) {
this.permissions = permissions; this.permissions = permissions;
} }
public List<String> getGroups() { public List<String> getGroups() {
return groups; return groups;
} }
public void setGroups(List<String> groups) { public void setGroups(List<String> groups) {
this.groups = groups; this.groups = groups;
} }
@Override public List<String> getExpireCommands() {
public YamlConfiguration toConfig() { return expireCommands;
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;
}
@Override public void setExpireCommands(List<String> expireCommands) {
public void toConfigBean(MemorySection config) { this.expireCommands = expireCommands;
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");
}
@Override @Override
public String toString() { public YamlConfiguration toConfig() {
return "PermissionPackageBean [displayName=" + displayName + ", id=" + id + ", type=" + type + ", glowing=" + glowing + ", lores=" + lores + ", global=" + global + ", permissions=" + permissions + ", groups=" + groups + "]"; 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) { @Override
List<World> worlds = server.getWorlds(); public void toConfigBean(MemorySection config) {
for (String pem : permissions) { displayName = config.getString("displayName");
String[] args = pem.split(":"); if (displayName == null) {
pem = args[0]; displayName = "No Name";
if (args.length > 1) { }
for (int i = 1; i < args.length; i++) { id = config.getString("id");
String worldName = args[i]; type = config.getString("type");
permission.playerAdd(worldName, player, pem); if (id == null && type == null) {
} type = "NETHER_STAR";
} else { }
for (World world : worlds) { glowing = config.getBoolean("glowing");
String worldName = world.getName(); lores = config.getStringList("lores");
permission.playerAdd(worldName, player, pem); global = config.getBoolean("global");
} permissions = config.getStringList("permissions");
} groups = config.getStringList("groups");
} expireCommands = config.getStringList("expireCommands");
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);
}
}
}
}
private void clearPlayer(OfflinePlayer player, Server server, Permission permission) { @Override
List<World> worlds = server.getWorlds(); public String toString() {
for (String pem : permissions) { return "PermissionPackageBean [displayName=" + displayName + ", id=" + id + ", type=" + type + ", glowing="
String[] args = pem.split(":"); + glowing + ", lores=" + lores + ", global=" + global + ", permissions=" + permissions + ", groups="
pem = args[0]; + groups + ", expireCommands=" + expireCommands + "]";
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 reloadPlayerPermissions(OfflinePlayer player, List<PlayerDataBean> pdbList, PluginMain plugin) { private void givePlayer(OfflinePlayer player, Server server, Permission permission) {
reloadPlayerPermissions(player, pdbList, plugin, true); List<World> 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<PlayerDataBean> pdbList, PluginMain plugin, boolean async) { private void clearPlayer(OfflinePlayer player, Server server, Permission permission) {
long delay = -1; List<World> worlds = server.getWorlds();
long now = new Date().getTime(); for (String pem : permissions) {
PermissionPackageBean addPpb = new PermissionPackageBean(); String[] args = pem.split(":");
addPpb.getGroups().add(PackagesCfg.DEFAULT_GROUP); pem = args[0];
PermissionPackageBean subPpb = new PermissionPackageBean(); if (args.length > 1) {
subPpb.getPermissions().addAll(PackagesCfg.allPermissions); for (int i = 1; i < args.length; i++) {
subPpb.getGroups().addAll(PackagesCfg.allGroups); String worldName = args[i];
for (PlayerDataBean pdb : pdbList) { permission.playerRemove(worldName, player, pem);
long leftTime = pdb.getExpire() - now; }
if (leftTime > 0) { } else {
if (delay == -1) { for (World world : worlds) {
delay = leftTime; String worldName = world.getName();
} else if (delay > leftTime) { permission.playerRemove(worldName, player, pem);
delay = leftTime; }
} }
} }
PermissionPackageBean p = PackagesCfg.PACKAGES.get(pdb.getPackageName()); for (String groupName : groups) {
if (p != null) { String[] args = groupName.split(":");
addPpb.getPermissions().addAll(p.getPermissions()); groupName = args[0];
subPpb.getPermissions().removeAll(p.getPermissions()); if (args.length > 1) {
addPpb.getGroups().addAll(p.getGroups()); for (int i = 1; i < args.length; i++) {
subPpb.getGroups().removeAll(p.getGroups()); String worldName = args[i];
} permission.playerRemoveGroup(worldName, player, groupName);
} }
if (async) { } else {
plugin.getServer().getScheduler().runTask(plugin, new Runnable() { for (World world : worlds) {
@Override String worldName = world.getName();
public void run() { permission.playerRemoveGroup(worldName, player, groupName);
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<PlayerDataBean> 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 { public static void reloadPlayerPermissions(OfflinePlayer player, List<PlayerDataBean> pdbList, PluginMain plugin) {
PermissionPackageBean subPpb = new PermissionPackageBean(); reloadPlayerPermissions(player, pdbList, plugin, true);
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) { public static void reloadPlayerPermissions(OfflinePlayer player, List<PlayerDataBean> pdbList, PluginMain plugin,
List<PlayerDataBean> playerDataList = plugin.getSqlManager().getAllTime(player.getUniqueId().toString()); boolean async) {
long now = new Date().getTime(); long delay = -1;
for (PlayerDataBean playerData : playerDataList) { long now = new Date().getTime();
if (playerData.getExpire() < now) { PermissionPackageBean addPpb = new PermissionPackageBean();
PermissionPackageBean packageBean = PackagesCfg.PACKAGES.get(playerData.getPackageName()); addPpb.getGroups().add(PackagesCfg.DEFAULT_GROUP);
plugin.getServer().getScheduler().runTask(plugin, new Runnable() { PermissionPackageBean subPpb = new PermissionPackageBean();
@Override subPpb.getPermissions().addAll(PackagesCfg.allPermissions);
public void run() { subPpb.getGroups().addAll(PackagesCfg.allGroups);
Player p = player.getPlayer(); for (PlayerDataBean pdb : pdbList) {
if (p != null) { long leftTime = pdb.getExpire() - now;
p.sendMessage(StrUtil.messageFormat(PluginCfg.PLUGIN_PREFIX + LangCfg.MSG_IS_EXPIRATION_DATE, packageBean != null ? packageBean.getDisplayName() : LangCfg.MSG_UNKNOWN_PACKAGE, playerData.getPackageName())); if (leftTime > 0) {
} if (delay == -1) {
} delay = leftTime;
}); } else if (delay > leftTime) {
plugin.getSqlManager().delById(playerData.getId()); 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<PlayerDataBean> 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<PlayerDataBean> 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());
}
}
}
} }

View File

@ -4,9 +4,12 @@ import java.text.MessageFormat;
import java.util.Date; import java.util.Date;
import org.apache.commons.lang.time.DateFormatUtils; 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.config.LangCfg;
import gg.frog.mc.permissionstime.database.IPlayerDataDao; import gg.frog.mc.permissionstime.database.IPlayerDataDao;
import me.clip.placeholderapi.PlaceholderAPI;
public class StrUtil { public class StrUtil {
@ -14,9 +17,26 @@ public class StrUtil {
private static final long dt = 24 * 60 * IPlayerDataDao.TIME_UNIT; private static final long dt = 24 * 60 * IPlayerDataDao.TIME_UNIT;
private static final long ht = 60 * IPlayerDataDao.TIME_UNIT; private static final long ht = 60 * IPlayerDataDao.TIME_UNIT;
private static final long mt = 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) { 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) { public static String timestampToString(long time) {

View File

@ -42,3 +42,8 @@ packages:
groups: groups:
- group1 - group1
- group2:world1 - group2:world1
# 权限包过期后执行的控制台命令
# Package expire console commands.
expireCommands:
- 'bc %player% 的权限包到期了.'
- 'bc 请及时续期.'

View File

@ -1,10 +1,11 @@
name: PermissionsTime name: PermissionsTime
version: 0.2.4-SNAPSHOT version: 0.3.0-SNAPSHOT
main: gg.frog.mc.permissionstime.PluginMain main: gg.frog.mc.permissionstime.PluginMain
author: GeekFrog author: GeekFrog
softdepend: softdepend:
- SQLibrary - SQLibrary
- Vault - Vault
- PlaceholderAPI
commands: commands:
permissionstime: permissionstime:
description: Show all commands. description: Show all commands.

View File

@ -3,7 +3,7 @@
[align=center][table=98%,#4169e1] [align=center][table=98%,#4169e1]
[tr][td][align=center][size=6][color=#ffffff][b]唠叨[/b][/color][/size][/align][/td][/tr] [tr][td][align=center][size=6][color=#ffffff][b]唠叨[/b][/color][/size][/align][/td][/tr]
[/table][/align][align=center][table=98%,gray] [/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] [/table][/align][align=center][table=98%,#4169e1]
[tr][td][align=center][size=6][color=#ffffff][b]前言[/b][/color][/size][/align][/td][/tr] [tr][td][align=center][size=6][color=#ffffff][b]前言[/b][/color][/size][/align][/td][/tr]
[/table][/align][align=center][table=98%,gray] [/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] [tr][td][align=center][size=6][color=#ffffff][b]更新日志[/b][/color][/size][/align][/td][/tr]
[/table][/align][align=center][table=98%,gray] [/table][/align][align=center][table=98%,gray]
[tr][td][spoiler][size=4][b][url=http://ci.frog.gg/jenkins/job/PermissionsTime/changes]详细的更新记录[/url] [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] [color=#ffffff]2017年7月27日 V0.2.3[/color][quote][color=#000000]
1.取消保存配置文件 1.取消保存配置文件
2.语言文件整理[/color][/quote] 2.语言文件整理[/color][/quote]
@ -221,15 +226,13 @@ cmd:
[/table][/align][align=center][table=98%,#4169e1] [/table][/align][align=center][table=98%,#4169e1]
[tr][td][align=center][size=6][color=#ffffff][b]下载地址[/b][/color][/size][/align][/td][/tr] [tr][td][align=center][size=6][color=#ffffff][b]下载地址[/b][/color][/size][/align][/td][/tr]
[/table][/align][align=center][table=98%,gray] [/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][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] [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] [/table][/align][align=center][table=98%,#4169e1]
[tr][td][align=center][size=6][color=#ffffff][b]使用统计[/b][/color][/size][/align][/td][/tr] [tr][td][align=center][size=6][color=#ffffff][b]使用统计[/b][/color][/size][/align][/td][/tr]
[/table][/align][align=center][table=98%,gray] [/table][/align][align=center][table=98%,gray]
[tr][td][align=center][b][size=4][color=#ff0000]图片可能经常抽风[/color][/size][/b][/align] [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]
[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]
[/table][/align][align=center][table=98%,#4169e1] [/table][/align][align=center][table=98%,#4169e1]
[tr][td][align=center][size=6][color=#ffffff][b]此插件已加入我的世界公益插件计划[/b][/color][/size][/align][/td][/tr] [tr][td][align=center][size=6][color=#ffffff][b]此插件已加入我的世界公益插件计划[/b][/color][/size][/align][/td][/tr]
[/table][/align][align=center][table=98%,gray] [/table][/align][align=center][table=98%,gray]