1
mirror of https://github.com/CarmJos/ScriptItems synced 2026-06-25 05:21:08 +08:00

完成指令部分

This commit is contained in:
2022-03-13 17:31:20 +08:00
parent 19330f1bb5
commit 1a6f2071df
31 changed files with 391 additions and 244 deletions
@@ -0,0 +1,99 @@
package cc.carm.plugin.scriptitems;
import cc.carm.lib.easyplugin.EasyPlugin;
import cc.carm.lib.easyplugin.i18n.EasyPluginMessageProvider;
import cc.carm.plugin.scriptitems.command.ScriptItemsCommand;
import cc.carm.plugin.scriptitems.configuration.PluginConfig;
import cc.carm.plugin.scriptitems.hooker.GHUpdateChecker;
import cc.carm.plugin.scriptitems.listener.ItemListener;
import cc.carm.plugin.scriptitems.manager.ConfigManager;
import cc.carm.plugin.scriptitems.manager.ItemsManager;
import cc.carm.plugin.scriptitems.util.JarResourceUtils;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import java.util.Optional;
public class Main extends EasyPlugin {
private static Main instance;
public Main() {
super(new EasyPluginMessageProvider.zh_CN());
instance = this;
}
public static Main getInstance() {
return instance;
}
protected ConfigManager configManager;
protected ItemsManager itemsManager;
@Override
protected boolean initialize() {
info("加载配置文件...");
this.configManager = new ConfigManager(this);
if (!configManager.initConfig()) {
severe("配置文件初始化失败,请检查。");
setEnabled(false);
return false;
}
info("加载物品配置...");
this.itemsManager = new ItemsManager();
this.itemsManager.initialize();
info("注册指令...");
registerCommand("ScriptItems", new ScriptItemsCommand());
info("注册监听器...");
regListener(new ItemListener());
if (PluginConfig.METRICS.get()) {
info("启用统计数据...");
new Metrics(this, 14615);
}
if (PluginConfig.CHECK_UPDATE.get()) {
log("开始检查更新...");
GHUpdateChecker checker = new GHUpdateChecker(getLogger(), "CarmJos", "CommandItem");
getScheduler().runAsync(() -> checker.checkUpdate(getDescription().getVersion()));
} else {
log("已禁用检查更新,跳过。");
}
return true;
}
@Override
protected void shutdown() {
log("卸载监听器...");
Bukkit.getServicesManager().unregisterAll(this);
}
@Override
public boolean isDebugging() {
return PluginConfig.DEBUG.get();
}
@Override
public void outputInfo() {
Optional.ofNullable(JarResourceUtils.readResource(this.getResource("PLUGIN_INFO"))).ifPresent(this::log);
}
public static void info(String... messages) {
getInstance().log(messages);
}
public static void severe(String... messages) {
getInstance().error(messages);
}
public static void debugging(String... messages) {
getInstance().debug(messages);
}
}
@@ -0,0 +1,26 @@
package cc.carm.plugin.scriptitems;
import cc.carm.plugin.scriptitems.manager.ConfigManager;
import cc.carm.plugin.scriptitems.manager.ItemsManager;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import java.util.stream.IntStream;
public class ScriptItemsAPI {
public static ItemsManager getItemsManager() {
return Main.getInstance().itemsManager;
}
public static ConfigManager getConfigManager() {
return Main.getInstance().configManager;
}
public static boolean hasEmptySlot(Player player) {
return IntStream.range(0, 36)
.mapToObj(i -> player.getInventory().getItem(i))
.anyMatch(i -> i == null || i.getType() == Material.AIR);
}
}
@@ -0,0 +1,166 @@
package cc.carm.plugin.scriptitems.command;
import cc.carm.plugin.scriptitems.ScriptItemsAPI;
import cc.carm.plugin.scriptitems.configuration.PluginMessages;
import cc.carm.plugin.scriptitems.item.ItemSettings;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
public class ScriptItemsCommand implements CommandExecutor, TabCompleter {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String alias, @NotNull String[] args) {
if (args.length >= 1) {
String aim = args[0];
if (aim.equalsIgnoreCase("reload")) {
try {
ScriptItemsAPI.getConfigManager().reload();
sender.sendMessage("配置文件重载完成!");
} catch (Exception e) {
sender.sendMessage("配置文件重载失败!");
e.printStackTrace();
}
return true;
} else if (aim.equalsIgnoreCase("apply")) {
if (args.length < 2) {
PluginMessages.USAGE.send(sender);
return true;
}
if (!(sender instanceof Player)) {
PluginMessages.ONLY_PLAYER.send(sender);
return true;
}
ItemSettings settings = ScriptItemsAPI.getItemsManager().getItemSettings(args[1]);
if (settings == null) {
PluginMessages.NOT_EXISTS.send(sender);
return true;
}
Player player = (Player) sender;
ItemStack item = player.getInventory().getItemInMainHand();
if (item.getType() == Material.AIR) {
PluginMessages.USE_ITEM.send(sender);
return true;
}
ItemStack after = settings.applyItem(item);
player.getInventory().setItemInMainHand(after);
PluginMessages.APPLIED.send(sender);
return true;
} else if (aim.equalsIgnoreCase("give")) {
if (args.length < 3) {
PluginMessages.USAGE.send(sender);
return true;
}
Player player = Bukkit.getPlayer(args[1]);
if (player == null) {
PluginMessages.NOT_ONLINE.send(sender);
return true;
}
ItemSettings settings = ScriptItemsAPI.getItemsManager().getItemSettings(args[2]);
if (settings == null) {
PluginMessages.NOT_EXISTS.send(sender);
return true;
}
int amount = 1;
if (args.length >= 4) {
try {
amount = Integer.parseInt(args[3]);
} catch (Exception ignored) {
amount = -1;
}
}
if (amount < 1) {
PluginMessages.WRONG_AMOUNT.send(sender);
return true;
}
ItemStack item = settings.generateItem(amount);
if (item == null) {
PluginMessages.WRONG_ITEM.send(sender);
return true;
}
HashMap<Integer, ItemStack> remain = player.getInventory().addItem(item);
if (remain.isEmpty()) {
PluginMessages.GIVEN_ALL.send(sender, player, item.getAmount(), settings.getName());
} else {
int remainAmount = remain.values().stream().mapToInt(ItemStack::getAmount).sum();
PluginMessages.GIVEN_SOME.send(sender, player, item.getAmount() - remainAmount, settings.getName(), remainAmount);
}
return true;
} else {
PluginMessages.USAGE.send(sender);
return true;
}
} else {
PluginMessages.USAGE.send(sender);
return true;
}
}
@Nullable
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String alias, @NotNull String[] args) {
List<String> allCompletes = new ArrayList<>();
switch (args.length) {
case 1: {
allCompletes.add("help");
allCompletes.add("give");
if (sender instanceof Player) allCompletes.add("apply");
allCompletes.add("reload");
break;
}
case 2: {
String aim = args[args.length - 1];
if (aim.equalsIgnoreCase("give")) {
allCompletes = Bukkit.getOnlinePlayers().stream().map(HumanEntity::getName).collect(Collectors.toList());
} else if (aim.equalsIgnoreCase("apply")) {
allCompletes = new ArrayList<>(ScriptItemsAPI.getItemsManager().listItemSettings().keySet());
}
break;
}
case 3: {
String aim = args[args.length - 1];
if (aim.equalsIgnoreCase("give")) {
allCompletes = new ArrayList<>(ScriptItemsAPI.getItemsManager().listItemSettings().keySet());
}
break;
}
}
return allCompletes.stream()
.filter(s -> StringUtil.startsWithIgnoreCase(s, args[args.length - 1]))
.limit(10).collect(Collectors.toList());
}
}
@@ -0,0 +1,40 @@
package cc.carm.plugin.scriptitems.configuration;
import cc.carm.lib.easyplugin.configuration.values.ConfigValue;
public class PluginConfig {
public static final ConfigValue<Boolean> DEBUG = new ConfigValue<>(
"debug", Boolean.class, false
);
public static final ConfigValue<Boolean> METRICS = new ConfigValue<>(
"metrics", Boolean.class, true
);
public static final ConfigValue<Boolean> CHECK_UPDATE = new ConfigValue<>(
"check-update", Boolean.class, true
);
public static final ConfigValue<Boolean> LOG_STORAGE = new ConfigValue<>(
"log-storage.enable", Boolean.class, true
);
public static class CustomStorage {
public static ConfigValue<Boolean> ENABLE = new ConfigValue<>("custom-storage.enable", Boolean.class, false);
public static ConfigValue<String> PATH = new ConfigValue<>("custom-storage.path", String.class, "items/");
}
public static class CoolDown {
public static ConfigValue<Boolean> ENABLE = new ConfigValue<>("cooldown.enable", Boolean.class, true);
public static ConfigValue<Long> TIME = new ConfigValue<>("cooldown.time", Long.class, 3000L);
}
}
@@ -0,0 +1,76 @@
package cc.carm.plugin.scriptitems.configuration;
import cc.carm.lib.easyplugin.configuration.language.EasyMessageList;
import cc.carm.lib.easyplugin.configuration.language.MessagesRoot;
public class PluginMessages extends MessagesRoot {
public static final EasyMessageList USAGE = EasyMessageList.builder().contents(
"&2&l脚本指令 &f指令帮助",
"&8#&f give &a<玩家名> &a<箱子ID> &2[数量]",
"&8-&7 给予指定玩家指定数量的物品。",
"&8#&f apply &a<箱子ID>",
"&8-&7 为手中的物品直接绑定一个配置。",
"&8#&f reload",
"&8-&7 重载配置文件。"
).build();
public final static EasyMessageList COOLDOWN = EasyMessageList.builder()
.contents("&f您需要等待 &c%(time)秒 &f才可再次使用该物品。")
.params("time").build();
public final static EasyMessageList ONLY_PLAYER = EasyMessageList.builder()
.contents("&c抱歉,只有作为玩家时才能使用该指令。").build();
public final static EasyMessageList USE_ITEM = EasyMessageList.builder()
.contents("&f请手持任意物品后再使用该指令。").build();
public final static EasyMessageList NOT_ONLINE = EasyMessageList.builder()
.contents("&f玩家 &a%(player) &f并不在线。")
.params("player").build();
public final static EasyMessageList NOT_EXISTS = EasyMessageList.builder()
.contents("&f脚本配置 &a%(id) &f并不存在。")
.params("id").build();
public final static EasyMessageList WRONG_AMOUNT = EasyMessageList.builder()
.contents("&f请输入正确的数量!")
.build();
public final static EasyMessageList WRONG_ITEM = EasyMessageList.builder()
.contents("&f该脚本并未成功配置具体物品,请使用 &a/ScriptItems apply &f来绑定到指定物品上,或在配置文件中正确配置物品。")
.build();
public final static EasyMessageList GIVEN_ALL = EasyMessageList.builder()
.contents("&f您成功给予 &a%(player) &f了 &a%(amount) &f个 &a%(item) &f。")
.params("player", "amount", "item").build();
public final static EasyMessageList GIVEN_SOME = EasyMessageList.builder().contents(
"&f您成功给予 &a%(player) &f了 &a%(amount) &f个 &a%(item) &f。",
"&f但由于目标玩家背包已满,仍有 &a%(remain) &f个 &a%(item) &f未成功放入背包。"
).params("player", "amount", "item", "remain").build();
public final static EasyMessageList APPLIED = EasyMessageList.builder()
.contents("&f已成功为手上物品绑定脚本。").build();
public static class Restrictions {
public final static EasyMessageList INVALID = EasyMessageList.builder()
.contents("&c&l抱歉!&f由于配置的时间限制错误,该物品目前暂不可用。")
.build();
public final static EasyMessageList NOT_STARTED = EasyMessageList.builder()
.contents("&f该物品目前还到可使用的时间,请在 &c%(time) &f后使用~")
.params("time")
.build();
public final static EasyMessageList EXPIRED = EasyMessageList.builder()
.contents("&c&l抱歉!&f由于该物品已过最后使用期限,故无法继续使用。")
.params("time")
.build();
}
}
@@ -0,0 +1,49 @@
package cc.carm.plugin.scriptitems.database;
import cc.carm.lib.easyplugin.configuration.values.ConfigValue;
public class DBConfiguration {
protected static final ConfigValue<String> DRIVER_NAME = new ConfigValue<>(
"log-storage.database.driver", String.class,
"com.mysql.cj.jdbc.Driver"
);
protected static final ConfigValue<String> HOST = new ConfigValue<>(
"log-storage.database.host", String.class,
"127.0.0.1"
);
protected static final ConfigValue<Integer> PORT = new ConfigValue<>(
"log-storage.database.port", Integer.class,
3306
);
protected static final ConfigValue<String> DATABASE = new ConfigValue<>(
"log-storage.database.database", String.class,
"minecraft"
);
protected static final ConfigValue<String> USERNAME = new ConfigValue<>(
"log-storage.database.username", String.class,
"root"
);
protected static final ConfigValue<String> PASSWORD = new ConfigValue<>(
"log-storage.database.password", String.class,
"password"
);
protected static final ConfigValue<String> EXTRA_SETTINGS = new ConfigValue<>(
"log-storage.database.extra", String.class,
"?useSSL=false"
);
protected static String buildJDBC() {
return String.format("jdbc:mysql://%s:%s/%s%s",
HOST.get(), PORT.get(), DATABASE.get(), EXTRA_SETTINGS.get()
);
}
}
@@ -0,0 +1,54 @@
package cc.carm.plugin.scriptitems.database;
import cc.carm.lib.easyplugin.configuration.values.ConfigValue;
public class DBTables {
/**
* 物品发放记录表
* 用于记录每个物品的发放情况,包含发放时间,发放人,发放数量以及发放给了谁。
*/
public static class GiveTable {
protected static final ConfigValue<String> TABLE_NAME = new ConfigValue<>(
"log-storage.database.tables.give", String.class,
"log_item_give"
);
protected static final String[] TABLE_COLUMNS = new String[]{
"`id` INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE KEY",
"`uuid` VARCHAR(36) NOT NULL PRIMARY KEY", // ItemUUID
"`settings` VARCHAR(36) NOT NULL", // 该物品配置对应的Identifier
"`operator` VARCHAR(36)", "`operator_name` VARCHAR(32)", // 发放人的相关信息
"`receiver` VARCHAR(36)", "`receiver_name` VARCHAR(32)", // 接受者的相关信息
"`amount` INT UNSIGNED NOT NULL DEFAULT 1", // 同uuid物品的发放数量
"`time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP" // 发放时间
};
}
/**
* 物品拿取记录表
* 改表用于记录物品的使用情况,即谁在什么时候使用了哪个物品,以及领取时任务的执行情况。
* 请注意:只有在发生物品拿取(即 take action )事件时才会记录!
*/
public static class TakeTable {
protected static final ConfigValue<String> TABLE_NAME = new ConfigValue<>(
"log-storage.database.tables.received", String.class,
"log_item_received"
);
protected static final String[] TABLE_COLUMNS = new String[]{
"`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY",
"`uuid` VARCHAR(36) NOT NULL", // ItemUUID
"`receiver` VARCHAR(36)", "`receiver_name` VARCHAR(32)", // 接受者的相关信息
"`result` TINYINT(2) NOT NULL DEFAULT 0",// 领取结果
"`time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP",
"INDEX `item`(`uuid`)"
};
}
}
@@ -0,0 +1,69 @@
package cc.carm.plugin.scriptitems.database;
import cc.carm.lib.easysql.EasySQL;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.plugin.scriptitems.Main;
import cc.carm.plugin.scriptitems.util.DatabaseTable;
import java.sql.SQLException;
public class DataManager {
private SQLManager sqlManager;
private DatabaseTable givenTable;
private DatabaseTable receivedTable;
public boolean initialize() {
try {
Main.info(" 尝试连接到数据库...");
this.sqlManager = EasySQL.createManager(
DBConfiguration.DRIVER_NAME.get(), DBConfiguration.buildJDBC(),
DBConfiguration.USERNAME.get(), DBConfiguration.PASSWORD.get()
);
this.sqlManager.setDebugMode(() -> Main.getInstance().isDebugging());
} catch (Exception exception) {
Main.severe("无法连接到数据库,请检查配置文件。");
exception.printStackTrace();
return false;
}
try {
Main.info(" 创建插件记录所需表...");
this.givenTable = new DatabaseTable(DBTables.GiveTable.TABLE_NAME.get(), DBTables.GiveTable.TABLE_COLUMNS);
this.receivedTable = new DatabaseTable(DBTables.TakeTable.TABLE_NAME.get(), DBTables.TakeTable.TABLE_COLUMNS);
this.givenTable.createTable(this.sqlManager);
this.receivedTable.createTable(this.sqlManager);
} catch (SQLException exception) {
Main.severe("无法创建插件所需的表,请检查数据库权限。");
exception.printStackTrace();
return false;
}
return true;
}
public void shutdown() {
Main.info(" 关闭数据库连接...");
EasySQL.shutdownManager(getSQLManager());
this.sqlManager = null;
}
public SQLManager getSQLManager() {
return sqlManager;
}
public DatabaseTable getGivenTable() {
return givenTable;
}
public DatabaseTable getReceivedTable() {
return receivedTable;
}
}
@@ -0,0 +1,38 @@
package cc.carm.plugin.scriptitems.hooker;
import cc.carm.lib.githubreleases4j.GithubReleases4J;
import java.util.logging.Logger;
public class GHUpdateChecker {
private final Logger logger;
private final String owner;
private final String repo;
public GHUpdateChecker(Logger logger, String owner, String repo) {
this.logger = logger;
this.owner = owner;
this.repo = repo;
}
public void checkUpdate(String currentVersion) {
Integer behindVersions = GithubReleases4J.getVersionBehind(owner, repo, currentVersion);
String downloadURL = GithubReleases4J.getReleasesURL(owner, repo);
if (behindVersions == null) {
logger.severe("检查更新失败,请您定期查看插件是否更新,避免安全问题。");
logger.severe("下载地址 " + downloadURL);
} else if (behindVersions == 0) {
logger.info("检查完成,当前已是最新版本。");
} else if (behindVersions > 0) {
logger.info("发现新版本! 目前已落后 " + behindVersions + " 个版本。");
logger.info("最新版下载地址 " + downloadURL);
} else {
logger.severe("检查更新失败! 当前版本未知,请您使用原生版本以避免安全问题。");
logger.severe("最新版下载地址 " + downloadURL);
}
}
}
@@ -0,0 +1,43 @@
package cc.carm.plugin.scriptitems.item;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ItemAction {
@NotNull ItemActionType type;
@Nullable String actionContent;
public ItemAction(@NotNull ItemActionType type, @Nullable String actionContent) {
this.type = type;
this.actionContent = actionContent;
}
public @NotNull ItemActionType getType() {
return type;
}
public @Nullable String getActionContent() {
return actionContent;
}
public boolean execute(Player player) {
return getType().execute(player, getActionContent());
}
public static @Nullable ItemAction read(@Nullable String actionString) {
if (actionString == null) return null;
int prefixStart = actionString.indexOf("[");
int prefixEnd = actionString.indexOf("]");
if (prefixStart < 0 || prefixEnd < 0) return null;
String prefix = actionString.substring(prefixStart + 1, prefixEnd);
ItemActionType actionType = ItemActionType.read(prefix);
if (actionType == null) return null;
return new ItemAction(actionType, actionString.substring(prefixEnd + 1).trim());
}
}
@@ -0,0 +1,29 @@
package cc.carm.plugin.scriptitems.item;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
public class ItemActionGroup {
List<ItemAction> actions;
public ItemActionGroup(List<ItemAction> actions) {
this.actions = actions;
}
public void execute(Player player) {
actions.forEach(action -> action.execute(player));
}
public static @NotNull ItemActionGroup read(@NotNull List<String> actionsString) {
List<ItemAction> actions = actionsString.stream()
.map(ItemAction::read).filter(Objects::nonNull).collect(Collectors.toList());
return new ItemActionGroup(actions);
}
}
@@ -0,0 +1,121 @@
package cc.carm.plugin.scriptitems.item;
import cc.carm.lib.easyplugin.utils.MessageUtils;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.BiFunction;
public enum ItemActionType {
/**
* 以玩家聊天的形式执行
* 若内容以 “/" 开头,则会以玩家身份执行命令。
*/
CHAT((player, string) -> {
if (string == null) return true; //没有需要执行的
List<String> finalContents = MessageUtils.setPlaceholders(player, Collections.singletonList(string));
boolean success = true;
for (String finalContent : finalContents) {
try {
player.chat(finalContent);
} catch (Exception ex) {
success = false;
}
}
return success;
}),
/**
* 以后台的形式执行指令
* 指令内容不需要以“/”开头。
*/
CONSOLE((player, string) -> {
if (string == null) return true;
List<String> finalCommands = MessageUtils.setPlaceholders(player, Collections.singletonList(string));
boolean success = true;
for (String finalCommand : finalCommands) {
try {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), finalCommand);
} catch (Exception ex) {
success = false;
}
}
return success;
}),
/**
* 向玩家发送消息。
*/
MESSAGE((sender, messages) -> {
MessageUtils.send(sender, messages);
return true;
}),
/**
* 向玩家发送声音。
* 允许配置音量与音调
* <ul>
* <li>SOUND_NAME</li>
* <li>SOUND_NAME:VOLUME</li>
* <li>SOUND_NAME:VOLUME:PITCH</li>
* </ul>
*/
SOUND((player, string) -> {
if (string == null) return true;
try {
String[] args = string.contains(":") ? string.split(":") : new String[]{string};
Sound sound = Arrays.stream(Sound.values())
.filter(s -> s.name().equals(args[0]))
.findFirst().orElse(null);
if (sound == null) return true;
float volume = args.length > 1 ? Float.parseFloat(args[1]) : 1F;
float pitch = args.length > 2 ? Float.parseFloat(args[2]) : 1F;
player.playSound(player.getLocation(), sound, volume, pitch);
} catch (Exception ignored) {
}
return true; // 声音放不放无关紧要
}),
/**
* 拿取玩家手上的一个物品
*/
TAKE((player, string) -> {
if (player.getInventory().getItemInMainHand().getType() != Material.AIR) {
int current = player.getInventory().getItemInMainHand().getAmount();
player.getInventory().getItemInMainHand().setAmount(current - 1);
return true;
}
return false;
});
BiFunction<@NotNull Player, @Nullable String, @NotNull Boolean> executor;
ItemActionType(BiFunction<@NotNull Player, @Nullable String, @NotNull Boolean> executor) {
this.executor = executor;
}
public BiFunction<Player, String, Boolean> getExecutor() {
return executor;
}
public boolean execute(@NotNull Player player, @Nullable String content) {
return getExecutor().apply(player, content);
}
public static ItemActionType read(String string) {
return Arrays.stream(ItemActionType.values())
.filter(action -> action.name().equalsIgnoreCase(string))
.findFirst().orElse(null);
}
}
@@ -0,0 +1,20 @@
package cc.carm.plugin.scriptitems.item;
public enum ItemExecuteResult {
SUCCESS(0),
FAILED(1),
;
int id;
ItemExecuteResult(int id) {
this.id = id;
}
public int getId() {
return id;
}
}
@@ -0,0 +1,98 @@
package cc.carm.plugin.scriptitems.item;
import cc.carm.lib.easyplugin.configuration.language.EasyMessageList;
import cc.carm.lib.easysql.api.util.TimeDateUtils;
import cc.carm.plugin.scriptitems.configuration.PluginMessages;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Function;
import java.util.function.Supplier;
public class ItemRestrictions {
long startTime;
long endTime;
public ItemRestrictions() {
this(-1, -1);
}
public ItemRestrictions(long startTime, long endTime) {
this.startTime = startTime;
this.endTime = endTime;
}
/**
* @return 限定的开始时间,-1表示不限定。
*/
public long getStartTime() {
return startTime;
}
/**
* @return 限定的结束时间,-1表示不限定。
*/
public long getEndTime() {
return endTime;
}
public CheckResult check() {
if (getStartTime() < 0 && getEndTime() < 0) return CheckResult.AVAILABLE;
if (getStartTime() > 0 && getEndTime() > 0 && getStartTime() > getEndTime()) return CheckResult.INVALID;
if (getStartTime() > 0 && getStartTime() > System.currentTimeMillis()) return CheckResult.NOT_STARTED;
if (getEndTime() > 0 && getEndTime() < System.currentTimeMillis()) return CheckResult.EXPIRED;
return CheckResult.AVAILABLE;
}
public enum CheckResult {
AVAILABLE(() -> null, (res) -> null),
INVALID(() -> PluginMessages.Restrictions.INVALID, (res) -> null),
NOT_STARTED(
() -> PluginMessages.Restrictions.NOT_STARTED,
(res) -> new Object[]{TimeDateUtils.getTimeString(res.getStartTime())}
),
EXPIRED(
() -> PluginMessages.Restrictions.EXPIRED,
(res) -> new Object[]{TimeDateUtils.getTimeString(res.getEndTime())}
);
Supplier<@Nullable EasyMessageList> message;
Function<@NotNull ItemRestrictions, Object[]> params;
CheckResult(@NotNull Supplier<@Nullable EasyMessageList> message,
@NotNull Function<@NotNull ItemRestrictions, @Nullable Object[]> params) {
this.message = message;
this.params = params;
}
public Supplier<EasyMessageList> getMessage() {
return message;
}
public void send(Player player, ItemRestrictions restrictions) {
Object[] params = this.params.apply(restrictions);
if (params == null) {
getMessage().get().send(player);
} else {
getMessage().get().send(player, params);
}
}
}
public static @NotNull ItemRestrictions read(@Nullable ConfigurationSection section) {
if (section == null) return new ItemRestrictions();
return new ItemRestrictions(
TimeDateUtils.parseTimeMillis(section.getString("time.start")),
TimeDateUtils.parseTimeMillis(section.getString("time.end"))
);
}
}
@@ -0,0 +1,112 @@
package cc.carm.plugin.scriptitems.item;
import cc.carm.plugin.scriptitems.ScriptItemsAPI;
import cc.carm.plugin.scriptitems.manager.ConfigManager;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.Map;
import java.util.UUID;
public class ItemSettings {
protected final @NotNull String identifier;
@Nullable String name;
@Nullable ItemStackConfig item;
@NotNull ItemRestrictions restrictions;
@NotNull Map<String, String> permissions;
@NotNull Map<String, ItemActionGroup> actions;
public ItemSettings(@NotNull String identifier, @Nullable String name,
@Nullable ItemStackConfig item, @NotNull ItemRestrictions restrictions,
@NotNull Map<String, String> permissions,
@NotNull Map<String, ItemActionGroup> actions) {
this.identifier = identifier;
this.name = name;
this.item = item;
this.restrictions = restrictions;
this.permissions = permissions;
this.actions = actions;
}
public @NotNull String getIdentifier() {
return identifier;
}
public @Nullable String getName() {
return name;
}
public ItemStackConfig getItemConfig() {
return item;
}
public @Nullable ItemStack generateItem(int amount) {
ItemStackConfig config = getItemConfig();
ItemStack originalItem = config == null ? null : config.getItemStack(amount);
if (originalItem == null) return null;
return applyItem(originalItem);
}
public @Nullable ItemStack generateItem() {
return generateItem(1);
}
public @NotNull Map<String, String> getPermissions() {
return this.permissions;
}
public @NotNull ItemRestrictions getRestrictions() {
return restrictions;
}
public ItemRestrictions.CheckResult checkRestrictions() {
return getRestrictions().check();
}
public @NotNull Map<String, ItemActionGroup> getActions() {
return this.actions;
}
public @Nullable ItemActionGroup getDefaultActions() {
return getActions().get("default");
}
public @Nullable ItemActionGroup getPlayerActions(@NotNull Player player) {
@NotNull String actionGroup = getPermissions().entrySet().stream()
.filter(entry -> player.hasPermission(entry.getValue()))
.map(Map.Entry::getKey).findFirst().orElse("default");
return getActions().get(actionGroup);
}
public @NotNull ItemStack applyItem(ItemStack originalItem) {
return ScriptItemsAPI.getItemsManager().applyTag(originalItem, identifier, UUID.randomUUID());
}
public static @NotNull ItemSettings load(@NotNull File file) throws Exception {
return load(YamlConfiguration.loadConfiguration(file));
}
public static @NotNull ItemSettings load(@NotNull FileConfiguration config) throws Exception {
String identifier = config.getString("identifier");
if (identifier == null) throw new Exception("identifier not provided.");
return new ItemSettings(
identifier, config.getString("name"),
config.isItemStack("item") ?
ItemStackConfig.create(config.getItemStack("item")) :
ItemStackConfig.read(config.getConfigurationSection("item")),
ItemRestrictions.read(config.getConfigurationSection("restrictions")),
ConfigManager.readStringMap(config.getConfigurationSection("permissions"), (s -> s)),
ConfigManager.readListMap(config.getConfigurationSection("actions"), ItemActionGroup::read)
);
}
}
@@ -0,0 +1,63 @@
package cc.carm.plugin.scriptitems.item;
import cc.carm.lib.easyplugin.utils.ColorParser;
import cc.carm.lib.easyplugin.utils.ItemStackFactory;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Optional;
@SuppressWarnings("UnusedReturnValue")
public class ItemStackConfig {
protected @Nullable ItemStack item;
public ItemStackConfig() {
}
public ItemStackConfig(@Nullable Material material, @Nullable String displayName, @Nullable List<String> lore) {
if (material == null) {
this.item = null;
return;
}
ItemStackFactory factory = new ItemStackFactory(material);
if (displayName != null) factory.setDisplayName(ColorParser.parse(displayName));
if (lore != null && !lore.isEmpty()) factory.setLore(lore);
this.item = factory.toItemStack();
}
public ItemStackConfig(@Nullable ItemStack item) {
this.item = item;
}
public @Nullable ItemStack getItemStack(int amount) {
if (amount <= 0 || item == null) return null;
ItemStack item = this.item.clone();
item.setAmount(amount);
return item;
}
public @Nullable ItemStack getItemStack() {
return getItemStack(1);
}
public static @Nullable ItemStackConfig read(@Nullable ConfigurationSection section) {
if (section == null) return null;
return new ItemStackConfig(
Optional.ofNullable(section.getString("type")).map(Material::matchMaterial).orElse(null),
section.getString("name"),
section.getStringList("lore")
);
}
public static @Nullable ItemStackConfig create(@Nullable ItemStack item) {
if (item == null) return null;
return new ItemStackConfig(item);
}
}
@@ -0,0 +1,34 @@
package cc.carm.plugin.scriptitems.item;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
public class ScriptItem {
@NotNull UUID uuid;
@NotNull ItemSettings settings;
@NotNull ItemStack itemStack;
public ScriptItem(@NotNull UUID uuid, @NotNull ItemSettings settings, @NotNull ItemStack itemStack) {
this.uuid = uuid;
this.settings = settings;
this.itemStack = itemStack;
}
public @NotNull UUID getUUID() {
return uuid;
}
public @NotNull ItemSettings getSettings() {
return settings;
}
public @NotNull ItemStack getItemStack() {
return itemStack;
}
}
@@ -0,0 +1,134 @@
package cc.carm.plugin.scriptitems.listener;
import cc.carm.plugin.scriptitems.ScriptItemsAPI;
import cc.carm.plugin.scriptitems.configuration.PluginConfig;
import cc.carm.plugin.scriptitems.configuration.PluginMessages;
import cc.carm.plugin.scriptitems.item.ScriptItem;
import cc.carm.plugin.scriptitems.item.ItemActionGroup;
import cc.carm.plugin.scriptitems.item.ItemRestrictions;
import cc.carm.plugin.scriptitems.item.ItemSettings;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityPickupItemEvent;
import org.bukkit.event.inventory.CraftItemEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.ItemStack;
import java.util.Arrays;
import java.util.HashMap;
import java.util.UUID;
public class ItemListener implements Listener {
private final HashMap<UUID, Long> clickTime = new HashMap<>();
/**
* 监听玩家点击,并执行物品对应的操作。
*
* @param event 玩家点击事件
*/
@EventHandler
public void onClick(PlayerInteractEvent event) {
if (event.getAction() != Action.RIGHT_CLICK_AIR && event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
ItemStack item = event.getPlayer().getInventory().getItemInMainHand();
ScriptItem scriptItem = ScriptItemsAPI.getItemsManager().parseItem(item);
if (scriptItem == null) return;
event.setCancelled(true); // 阻止事件执行
Player player = event.getPlayer();
if (!isClickable(player.getUniqueId())) {
PluginMessages.COOLDOWN.send(player, getRemainSeconds(player.getUniqueId()));
return;
}
updateTime(player.getUniqueId());
ItemSettings settings = scriptItem.getSettings();
// 检查物品的相关使用限制是否满足要求
ItemRestrictions.CheckResult result = settings.getRestrictions().check();
if (result != ItemRestrictions.CheckResult.AVAILABLE) {
result.send(player, settings.getRestrictions()); // 发送提示
return;
}
// 获取玩家的对应操作组
ItemActionGroup actions = settings.getPlayerActions(player);
if (actions == null) return;
actions.execute(player);
}
/**
* 监听玩家合成,阻止玩家将指令物品合成浪费掉。
*
* @param event 合成事件
*/
@EventHandler
public void onCraft(CraftItemEvent event) {
boolean shouldCancel = Arrays.stream(event.getInventory().getMatrix())
.anyMatch(matrix -> ScriptItemsAPI.getItemsManager().isScriptItem(matrix));
if (shouldCancel) event.setCancelled(true);
}
/**
* 阻止非玩家捡起指令物品
*
* @param event 捡起事件
*/
@EventHandler
public void onPickup(EntityPickupItemEvent event) {
if (event.getEntity().getType() == EntityType.PLAYER) return;
ItemStack item = event.getItem().getItemStack();
if (ScriptItemsAPI.getItemsManager().isScriptItem(item)) {
event.setCancelled(true);
}
}
/**
* 阻止物品被烧掉
*
* @param event 伤害事件
*/
@EventHandler
public void onEntityDamage(EntityDamageEvent event) {
if (event.getEntity().getType() != EntityType.DROPPED_ITEM) return;
Item droppedItem = ((org.bukkit.entity.Item) event.getEntity());
ItemStack item = droppedItem.getItemStack();
if (ScriptItemsAPI.getItemsManager().isScriptItem(item)) {
event.setCancelled(true);
}
}
@EventHandler
public void onLeave(PlayerQuitEvent event) {
this.clickTime.remove(event.getPlayer().getUniqueId());
}
public void updateTime(UUID uuid) {
this.clickTime.put(uuid, System.currentTimeMillis());
}
public boolean isClickable(UUID uuid) {
return !PluginConfig.CoolDown.ENABLE.get()
|| !this.clickTime.containsKey(uuid)
|| System.currentTimeMillis() - this.clickTime.get(uuid) > PluginConfig.CoolDown.TIME.get();
}
public int getRemainSeconds(UUID uuid) {
if (!this.clickTime.containsKey(uuid)) return 0;
if (!PluginConfig.CoolDown.ENABLE.get()) return 0;
long start = this.clickTime.get(uuid);
return (int) ((PluginConfig.CoolDown.TIME.get() - (System.currentTimeMillis() - start)) / 1000) + 1;
}
}
@@ -0,0 +1,100 @@
package cc.carm.plugin.scriptitems.manager;
import cc.carm.lib.easyplugin.configuration.file.FileConfig;
import cc.carm.lib.easyplugin.configuration.language.MessagesConfig;
import cc.carm.lib.easyplugin.configuration.language.MessagesInitializer;
import cc.carm.plugin.scriptitems.configuration.PluginMessages;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
public class ConfigManager {
private final JavaPlugin plugin;
private FileConfig config;
private MessagesConfig messageConfig;
public ConfigManager(JavaPlugin plugin) {
this.plugin = plugin;
}
public boolean initConfig() {
try {
this.config = new FileConfig(plugin);
this.messageConfig = new MessagesConfig(plugin);
FileConfig.pluginConfiguration = () -> config;
FileConfig.messageConfiguration = () -> messageConfig;
MessagesInitializer.initialize(messageConfig, PluginMessages.class);
return true;
} catch (IOException e) {
return false;
}
}
public FileConfig getPluginConfig() {
return config;
}
public FileConfig getMessageConfig() {
return messageConfig;
}
public void reload() throws Exception {
getPluginConfig().reload();
getMessageConfig().reload();
}
public void saveConfig() throws Exception {
getPluginConfig().save();
getMessageConfig().save();
}
public static <V> Map<String, V> readStringMap(@Nullable ConfigurationSection section,
@NotNull Function<String, V> valueCast) {
if (section == null) return new LinkedHashMap<>();
Map<String, V> result = new LinkedHashMap<>();
for (String key : section.getKeys(false)) {
V finalValue = valueCast.apply(section.getString(key));
if (finalValue != null) result.put(key, finalValue);
}
return result;
}
public static <V> Map<String, V> readSectionMap(@Nullable ConfigurationSection section,
@NotNull Function<ConfigurationSection, V> valueCast) {
if (section == null) return new LinkedHashMap<>();
Map<String, V> result = new LinkedHashMap<>();
for (String key : section.getKeys(false)) {
if (!section.isConfigurationSection(key)) continue;
V finalValue = valueCast.apply(section.getConfigurationSection(key));
if (finalValue != null) result.put(key, finalValue);
}
return result;
}
public static <V> Map<String, V> readListMap(@Nullable ConfigurationSection section,
@NotNull Function<@NotNull List<String>, V> valueCast) {
if (section == null) return new LinkedHashMap<>();
Map<String, V> result = new LinkedHashMap<>();
for (String key : section.getKeys(false)) {
if (!section.isList(key)) continue;
V finalValue = valueCast.apply(section.getStringList(key));
if (finalValue != null) result.put(key, finalValue);
}
return result;
}
}
@@ -0,0 +1,128 @@
package cc.carm.plugin.scriptitems.manager;
import cc.carm.plugin.scriptitems.Main;
import cc.carm.plugin.scriptitems.item.ItemSettings;
import cc.carm.plugin.scriptitems.item.ScriptItem;
import cc.carm.plugin.scriptitems.util.JarResourceUtils;
import com.google.common.collect.ImmutableMap;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.tags.CustomItemTagContainer;
import org.bukkit.inventory.meta.tags.ItemTagType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;
public class ItemsManager {
private static final String FOLDER_NAME = "items";
public HashMap<String, ItemSettings> items = new HashMap<>();
protected NamespacedKey idKey;
protected NamespacedKey uuidKey;
public void initialize() {
this.idKey = new NamespacedKey(Main.getInstance(), "id");
this.uuidKey = new NamespacedKey(Main.getInstance(), "uuid");
loadItems();
Main.info("成功加载了 " + items.size() + " 个脚本物品。");
}
public void loadItems() {
File prefixDataFolder = getStorageFolder();
if (!prefixDataFolder.isDirectory() || !prefixDataFolder.exists()) {
try {
JarResourceUtils.copyFolderFromJar(
FOLDER_NAME, Main.getInstance().getDataFolder(),
JarResourceUtils.CopyOption.COPY_IF_NOT_EXIST
);
} catch (Exception ex) {
boolean success = prefixDataFolder.mkdirs();
}
}
String[] filesList = prefixDataFolder.list();
if (filesList == null || filesList.length < 1) {
Main.severe(" 配置文件夹中暂无任何物品,请检查。");
Main.severe(" There's no configured items.");
return;
}
List<File> files = Arrays.stream(filesList)
.map(s -> new File(prefixDataFolder, s))
.filter(File::isFile)
.collect(Collectors.toList());
HashMap<String, ItemSettings> dataItems = new HashMap<>();
if (files.size() > 0) {
for (File file : files) {
String fileName = file.getName();
if (fileName.startsWith(".")) continue;
try {
ItemSettings item = ItemSettings.load(file);
Main.info(" 完成物品加载 [#" + item.getIdentifier() + "] " + item.getName() + " (" + fileName + ")");
dataItems.put(item.getIdentifier(), item);
} catch (Exception ex) {
Main.severe("在加载物品 " + file.getAbsolutePath() + " 时出错,请检查配置!");
Main.severe("Error occurred when loading item #" + file.getAbsolutePath() + " !");
ex.printStackTrace();
}
}
}
items = dataItems;
}
private static File getStorageFolder() {
return new File(Main.getInstance().getDataFolder(), FOLDER_NAME);
}
@Unmodifiable
public Map<String, ItemSettings> listItemSettings() {
return ImmutableMap.copyOf(items);
}
public @Nullable ItemSettings getItemSettings(@NotNull String identifier) {
return items.get(identifier);
}
public ItemStack applyTag(@NotNull ItemStack originalItem, String identifier, UUID uuid) {
if (!originalItem.hasItemMeta()) return originalItem;
ItemMeta meta = originalItem.getItemMeta();
if (meta == null) return originalItem;
CustomItemTagContainer container = meta.getCustomTagContainer();
container.setCustomTag(idKey, ItemTagType.STRING, identifier);
container.setCustomTag(uuidKey, ItemTagType.STRING, uuid.toString());
originalItem.setItemMeta(meta);
return originalItem;
}
public @Nullable ScriptItem parseItem(@Nullable ItemStack item) {
if (item == null || item.getType() == Material.AIR) return null;
if (!item.hasItemMeta()) return null;
ItemMeta meta = item.getItemMeta();
if (meta == null) return null;
CustomItemTagContainer container = meta.getCustomTagContainer();
String settingsID = container.getCustomTag(this.idKey, ItemTagType.STRING);
String itemUUID = container.getCustomTag(this.uuidKey, ItemTagType.STRING);
if (settingsID == null || itemUUID == null) return null;
ItemSettings settings = getItemSettings(settingsID);
if (settings == null) return null;
return new ScriptItem(UUID.fromString(itemUUID), settings, item);
}
public boolean isScriptItem(ItemStack item) {
return item.hasItemMeta() && item.getItemMeta() != null
&& item.getItemMeta().getCustomTagContainer().hasCustomTag(idKey, ItemTagType.STRING);
}
}
@@ -0,0 +1,77 @@
package cc.carm.plugin.scriptitems.util;
import cc.carm.lib.easysql.api.SQLManager;
import cc.carm.lib.easysql.api.action.PreparedSQLUpdateAction;
import cc.carm.lib.easysql.api.action.PreparedSQLUpdateBatchAction;
import cc.carm.lib.easysql.api.builder.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.sql.SQLException;
public class DatabaseTable {
private final @NotNull String tableName;
private final @NotNull String[] columns;
@Nullable String tableSettings;
public DatabaseTable(@NotNull String tableName, @NotNull String[] columns) {
this(tableName, columns, null);
}
public DatabaseTable(@NotNull String tableName, @NotNull String[] columns,
@Nullable String tableSettings) {
this.tableName = tableName;
this.columns = columns;
this.tableSettings = tableSettings;
}
public @NotNull String getTableName() {
return tableName;
}
public @NotNull String[] getColumns() {
return columns;
}
public @Nullable String getTableSettings() {
return tableSettings;
}
public int createTable(SQLManager sqlManager) throws SQLException {
TableCreateBuilder createAction = sqlManager.createTable(getTableName());
createAction.setColumns(getColumns());
if (getTableSettings() != null) createAction.setTableSettings(getTableSettings());
return createAction.build().execute();
}
public TableQueryBuilder createQuery(SQLManager sqlManager) {
return sqlManager.createQuery().inTable(getTableName());
}
public DeleteBuilder createDelete(SQLManager sqlManager) {
return sqlManager.createDelete(getTableName());
}
public UpdateBuilder createUpdate(SQLManager sqlManager) {
return sqlManager.createUpdate(getTableName());
}
public InsertBuilder<PreparedSQLUpdateAction> createInsert(SQLManager sqlManager) {
return sqlManager.createInsert(getTableName());
}
public InsertBuilder<PreparedSQLUpdateBatchAction> createInsertBatch(SQLManager sqlManager) {
return sqlManager.createInsertBatch(getTableName());
}
public ReplaceBuilder<PreparedSQLUpdateAction> createReplace(SQLManager sqlManager) {
return sqlManager.createReplace(getTableName());
}
public ReplaceBuilder<PreparedSQLUpdateBatchAction> createReplaceBatch(SQLManager sqlManager) {
return sqlManager.createReplaceBatch(getTableName());
}
}
@@ -0,0 +1,106 @@
package cc.carm.plugin.scriptitems.util;
import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@SuppressWarnings("ResultOfMethodCallIgnored")
public class JarResourceUtils {
public static final char JAR_SEPARATOR = '/';
public static @Nullable String[] readResource(@Nullable InputStream resourceStream) {
if (resourceStream == null) return null;
try (Scanner scanner = new Scanner(resourceStream, StandardCharsets.UTF_8.name())) {
List<String> contents = new ArrayList<>();
while (scanner.hasNextLine()) {
contents.add(scanner.nextLine());
}
return contents.toArray(new String[0]);
} catch (Exception e) {
return null;
}
}
public static void copyFolderFromJar(String folderName, File destFolder, CopyOption option)
throws IOException {
copyFolderFromJar(folderName, destFolder, option, null);
}
public static void copyFolderFromJar(String folderName, File destFolder,
CopyOption option, PathTrimmer trimmer) throws IOException {
if (!destFolder.exists())
destFolder.mkdirs();
byte[] buffer = new byte[1024];
File fullPath;
String path = JarResourceUtils.class.getProtectionDomain().getCodeSource().getLocation().getPath();
if (trimmer != null)
path = trimmer.trim(path);
try {
if (!path.startsWith("file"))
path = "file://" + path;
fullPath = new File(new URI(path));
} catch (URISyntaxException e) {
e.printStackTrace();
return;
}
ZipInputStream zis = new ZipInputStream(new FileInputStream(fullPath));
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
if (!entry.getName().startsWith(folderName + JAR_SEPARATOR))
continue;
String fileName = entry.getName();
if (fileName.charAt(fileName.length() - 1) == JAR_SEPARATOR) {
File file = new File(destFolder + File.separator + fileName);
if (file.isFile()) {
file.delete();
}
file.mkdirs();
continue;
}
File file = new File(destFolder + File.separator + fileName);
if (option == CopyOption.COPY_IF_NOT_EXIST && file.exists())
continue;
if (!file.getParentFile().exists())
file.getParentFile().mkdirs();
if (!file.exists())
file.createNewFile();
FileOutputStream fos = new FileOutputStream(file);
int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.close();
}
zis.closeEntry();
zis.close();
}
public enum CopyOption {
COPY_IF_NOT_EXIST, REPLACE_IF_EXIST
}
@FunctionalInterface
public interface PathTrimmer {
String trim(String original);
}
}