build: 更改项目结构

This commit is contained in:
2023-06-16 19:29:00 +08:00
parent 57357c6ae2
commit 20517e7207
61 changed files with 19 additions and 38 deletions

View File

@@ -0,0 +1,112 @@
package cn.hamster3.mc.plugin.core.bukkit;
import cn.hamster3.mc.plugin.core.bukkit.api.CoreBukkitAPI;
import cn.hamster3.mc.plugin.core.bukkit.command.core.ParentCoreCommand;
import cn.hamster3.mc.plugin.core.bukkit.command.lore.ParentLoreCommand;
import cn.hamster3.mc.plugin.core.bukkit.constant.CoreMessage;
import cn.hamster3.mc.plugin.core.bukkit.hook.PointAPI;
import cn.hamster3.mc.plugin.core.bukkit.hook.VaultAPI;
import cn.hamster3.mc.plugin.core.bukkit.listener.CallbackListener;
import cn.hamster3.mc.plugin.core.bukkit.listener.DebugListener;
import cn.hamster3.mc.plugin.core.bukkit.page.handler.PageHandler;
import cn.hamster3.mc.plugin.core.bukkit.page.listener.PageListener;
import cn.hamster3.mc.plugin.core.bukkit.util.serializer.ItemStackAdapter;
import cn.hamster3.mc.plugin.core.bukkit.util.serializer.PotionEffectAdapter;
import cn.hamster3.mc.plugin.core.common.data.DisplayMessage;
import cn.hamster3.mc.plugin.core.common.util.serializer.ComponentTypeAdapter;
import cn.hamster3.mc.plugin.core.common.util.serializer.MessageTypeAdapter;
import cn.hamster3.mc.plugin.core.common.util.CoreUtils;
import com.google.gson.GsonBuilder;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.potion.PotionEffect;
import java.util.logging.Logger;
public class HamsterCorePlugin extends JavaPlugin {
private static HamsterCorePlugin instance;
private BukkitAudiences audienceProvider;
public static HamsterCorePlugin getInstance() {
return instance;
}
@Override
public void onLoad() {
instance = this;
Logger logger = getLogger();
long start = System.currentTimeMillis();
logger.info("仓鼠核心正在初始化...");
saveDefaultConfig();
reloadConfig();
logger.info("已读取配置文件.");
CoreUtils.GSON = new GsonBuilder()
.registerTypeAdapter(Component.class, ComponentTypeAdapter.INSTANCE)
.registerTypeAdapter(DisplayMessage.class, MessageTypeAdapter.INSTANCE)
.registerTypeAdapter(ItemStack.class, ItemStackAdapter.INSTANCE)
.registerTypeAdapter(PotionEffect.class, PotionEffectAdapter.INSTANCE)
.create();
CoreBukkitAPI.init();
logger.info("已初始化 CoreBukkitAPI.");
CoreMessage.init(this);
logger.info("已初始化语言文本.");
long time = System.currentTimeMillis() - start;
logger.info("仓鼠核心初始化完成,总计耗时 " + time + " ms.");
}
@Override
public void onEnable() {
Logger logger = getLogger();
long start = System.currentTimeMillis();
logger.info("仓鼠核心正在启动...");
VaultAPI.reloadVaultHook();
logger.info("已完成 VaultAPI 挂载.");
PointAPI.reloadPlayerPointAPIHook();
logger.info("已完成 PlayerPoints 挂载.");
audienceProvider = BukkitAudiences.create(this);
logger.info("已完成 BukkitAudiences 挂载.");
Bukkit.getPluginManager().registerEvents(PageListener.INSTANCE, this);
logger.info("已注册 PageListener.");
Bukkit.getPluginManager().registerEvents(CallbackListener.INSTANCE, this);
logger.info("已注册 CallbackListener.");
Bukkit.getPluginManager().registerEvents(DebugListener.INSTANCE, this);
logger.info("已注册 DebugListener.");
ParentCoreCommand.INSTANCE.hook();
ParentLoreCommand.INSTANCE.hook();
long time = System.currentTimeMillis() - start;
logger.info("仓鼠核心启动完成,总计耗时 " + time + " ms.");
}
@Override
public void onDisable() {
Logger logger = getLogger();
long start = System.currentTimeMillis();
logger.info("仓鼠核心正在关闭...");
CoreUtils.WORKER_EXECUTOR.shutdownNow();
logger.info("已暂停 WORKER_EXECUTOR.");
CoreUtils.SCHEDULED_EXECUTOR.shutdownNow();
logger.info("已暂停 SCHEDULED_EXECUTOR.");
for (Player player : Bukkit.getOnlinePlayers()) {
InventoryView view = player.getOpenInventory();
Inventory inventory = view.getTopInventory();
if (!(inventory.getHolder() instanceof PageHandler)) {
continue;
}
player.closeInventory();
}
long time = System.currentTimeMillis() - start;
logger.info("仓鼠核心已关闭,总计耗时 " + time + " ms.");
}
public BukkitAudiences getAudienceProvider() {
return audienceProvider;
}
}

View File

@@ -0,0 +1,69 @@
package cn.hamster3.mc.plugin.core.bukkit.api;
import cn.hamster3.mc.plugin.core.bukkit.HamsterCorePlugin;
import cn.hamster3.mc.plugin.core.common.api.CoreAPI;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.jetbrains.annotations.NotNull;
@SuppressWarnings("unused")
public final class CoreBukkitAPI extends CoreAPI {
private final HikariDataSource datasource;
private CoreBukkitAPI() {
FileConfiguration config = HamsterCorePlugin.getInstance().getConfig();
ConfigurationSection datasourceConfig = config.getConfigurationSection("datasource");
if (datasourceConfig == null) {
throw new IllegalArgumentException("配置文件中未找到 datasource 节点!");
}
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setDriverClassName(datasourceConfig.getString("driver"));
hikariConfig.setJdbcUrl(datasourceConfig.getString("url"));
hikariConfig.setUsername(datasourceConfig.getString("username"));
hikariConfig.setPassword(datasourceConfig.getString("password"));
hikariConfig.setMaximumPoolSize(datasourceConfig.getInt("maximum-pool-size", 3));
hikariConfig.setMinimumIdle(datasourceConfig.getInt("minimum-idle", 1));
long keepAliveTime = datasourceConfig.getLong("keep-alive-time", 0);
if (keepAliveTime > 5000) {
hikariConfig.setKeepaliveTime(keepAliveTime);
}
hikariConfig.setIdleTimeout(datasourceConfig.getLong("idle-timeout", 10 * 60 * 1000));
hikariConfig.setMaxLifetime(datasourceConfig.getLong("max-lifetime", 30 * 60 * 1000));
hikariConfig.setValidationTimeout(datasourceConfig.getLong("validation-timeout", 5000));
hikariConfig.setPoolName("HamsterCore-Pool");
datasource = new HikariDataSource(hikariConfig);
}
public static CoreBukkitAPI getInstance() {
return (CoreBukkitAPI) instance;
}
public static void init() {
if (instance != null) {
return;
}
instance = new CoreBukkitAPI();
}
@Override
public @NotNull BukkitAudiences getAudienceProvider() {
return HamsterCorePlugin.getInstance().getAudienceProvider();
}
@Override
public @NotNull HikariDataSource getDataSource() {
return datasource;
}
public void reportError(@NotNull String projectID, @NotNull Throwable exception) {
}
public void reportFile(@NotNull String projectID, @NotNull String filename, byte @NotNull [] bytes) {
}
}

View File

@@ -0,0 +1,19 @@
package cn.hamster3.mc.plugin.core.bukkit.command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import org.jetbrains.annotations.NotNull;
public abstract class ChildCommand implements TabExecutor {
@NotNull
public abstract String getName();
@NotNull
public abstract String getUsage();
public abstract boolean hasPermission(@NotNull CommandSender sender);
@NotNull
public abstract String getDescription();
}

View File

@@ -0,0 +1,174 @@
package cn.hamster3.mc.plugin.core.bukkit.command;
import cn.hamster3.mc.plugin.core.bukkit.constant.CoreMessage;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.stream.Collectors;
@SuppressWarnings("unused")
public abstract class ParentCommand extends ChildCommand {
@NotNull
private final String name;
@NotNull
private final List<ChildCommand> childCommands;
public ParentCommand(@NotNull String name) {
this.name = name;
childCommands = new ArrayList<>();
}
@NotNull
public abstract JavaPlugin getPlugin();
@Override
public @NotNull String getName() {
return name;
}
@Nullable
public ParentCommand getParent() {
return null;
}
@NotNull
public List<ChildCommand> getChildCommands() {
return childCommands;
}
@NotNull
@Override
public String getUsage() {
ParentCommand parent = getParent();
if (parent == null) {
return "/" + name;
}
return parent.getUsage() + " " + name;
}
@Override
public boolean hasPermission(@NotNull CommandSender sender) {
return true;
}
@Override
public @NotNull String getDescription() {
return "";
}
/**
* 获取所有子命令
* <p>
* 如果子命令也是 ParentCommand 类型,则继续递归获取该 ParentCommand 的子命令
*
* @return 所有子命令
*/
@NotNull
public List<ChildCommand> getEndChildCommands() {
ArrayList<ChildCommand> list = new ArrayList<>();
for (ChildCommand command : childCommands) {
if (command instanceof ParentCommand) {
list.addAll(((ParentCommand) command).getEndChildCommands());
} else {
list.add(command);
}
}
return list;
}
public void addChildCommand(@NotNull ChildCommand command) {
childCommands.add(command);
}
@NotNull
public Map<String, String> getCommandHelp(CommandSender sender) {
HashMap<String, String> map = new HashMap<>();
for (ChildCommand child : childCommands) {
if (!child.hasPermission(sender)) {
continue;
}
if (child instanceof ParentCommand) {
Map<String, String> childMap = ((ParentCommand) child).getCommandHelp(sender);
map.putAll(childMap);
continue;
}
map.put(getUsage() + " " + child.getUsage(), child.getDescription());
}
return map;
}
public void sendHelp(@NotNull CommandSender sender) {
sender.sendMessage("§e==================== [ " + name + " 使用帮助] ====================");
Map<String, String> helpMap = getCommandHelp(sender);
int maxLength = helpMap.keySet().stream()
.map(String::length)
.max(Integer::compareTo)
.orElse(-1);
ArrayList<Map.Entry<String, String>> list = new ArrayList<>(helpMap.entrySet());
list.sort(Map.Entry.comparingByKey());
for (Map.Entry<String, String> entry : list) {
sender.sendMessage(String.format("§a%-" + maxLength + "s - %s", entry.getKey(), entry.getValue()));
}
}
public void hook() {
JavaPlugin plugin = getPlugin();
PluginCommand command = plugin.getCommand(getName());
if (command == null) {
throw new IllegalArgumentException("在插件 " + plugin.getName() + " 中未找到指令 " + getName() + ".");
}
command.setExecutor(this);
command.setTabCompleter(this);
plugin.getLogger().info("已注册指令 " + getUsage() + ".");
}
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (!hasPermission(sender)) {
CoreMessage.COMMAND_NOT_HAS_PERMISSION.show(sender);
return true;
}
if (args.length == 0) {
sendHelp(sender);
return true;
}
for (ChildCommand childCommand : childCommands) {
if (!childCommand.getName().equalsIgnoreCase(args[0])) {
continue;
}
if (!childCommand.hasPermission(sender)) {
CoreMessage.COMMAND_NOT_HAS_PERMISSION.show(sender);
return true;
}
return childCommand.onCommand(sender, command, label, Arrays.copyOfRange(args, 1, args.length));
}
CoreMessage.COMMAND_NOT_FOUND.show(sender);
return true;
}
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
if (args.length == 0) {
return childCommands.stream()
.filter(o -> o.hasPermission(sender))
.map(ChildCommand::getName)
.collect(Collectors.toList());
}
for (ChildCommand child : childCommands) {
if (args[0].equalsIgnoreCase(child.getName())) {
return child.onTabComplete(sender, command, alias, Arrays.copyOfRange(args, 1, args.length));
}
}
args[0] = args[0].toLowerCase();
return childCommands.stream()
.filter(o -> o.hasPermission(sender))
.map(ChildCommand::getName)
.filter(o -> o.toLowerCase().startsWith(args[0].toLowerCase()))
.collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,27 @@
package cn.hamster3.mc.plugin.core.bukkit.command.core;
import cn.hamster3.mc.plugin.core.bukkit.HamsterCorePlugin;
import cn.hamster3.mc.plugin.core.bukkit.command.ParentCommand;
import cn.hamster3.mc.plugin.core.bukkit.command.core.sub.*;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
public class ParentCoreCommand extends ParentCommand {
public static final ParentCoreCommand INSTANCE = new ParentCoreCommand();
private ParentCoreCommand() {
super("hamster-core");
addChildCommand(EnvCommand.INSTANCE);
addChildCommand(GCCommand.INSTANCE);
addChildCommand(YamlCommand.INSTANCE);
addChildCommand(InfoModeCommand.INSTANCE);
addChildCommand(ReloadCommand.INSTANCE);
addChildCommand(MemoryCommand.INSTANCE);
addChildCommand(SystemCommand.INSTANCE);
}
@Override
public @NotNull JavaPlugin getPlugin() {
return HamsterCorePlugin.getInstance();
}
}

View File

@@ -0,0 +1,59 @@
package cn.hamster3.mc.plugin.core.bukkit.command.core.sub;
import cn.hamster3.mc.plugin.core.bukkit.command.ChildCommand;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class EnvCommand extends ChildCommand {
public static final EnvCommand INSTANCE = new EnvCommand();
private EnvCommand() {
}
@Override
public @NotNull String getName() {
return "env";
}
@Override
public @NotNull String getUsage() {
return "env [变量名]";
}
@Override
public boolean hasPermission(@NotNull CommandSender sender) {
return true;
}
@Override
public @NotNull String getDescription() {
return "获取系统环境变量";
}
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (args.length < 1) {
sender.sendMessage(System.getenv().toString());
return true;
}
sender.sendMessage(args[0] + "=" + System.getenv().getOrDefault(args[0], ""));
return true;
}
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
if (args.length == 1) {
String lowerCase = args[0].toLowerCase();
return System.getenv().keySet()
.stream()
.filter(o -> o.toLowerCase().startsWith(lowerCase))
.collect(Collectors.toList());
}
return Collections.emptyList();
}
}

View File

@@ -0,0 +1,48 @@
package cn.hamster3.mc.plugin.core.bukkit.command.core.sub;
import cn.hamster3.mc.plugin.core.bukkit.command.ChildCommand;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
public class GCCommand extends ChildCommand {
public static final GCCommand INSTANCE = new GCCommand();
private GCCommand() {
}
@Override
public @NotNull String getName() {
return "gc";
}
@Override
public @NotNull String getUsage() {
return "gc";
}
@Override
public boolean hasPermission(@NotNull CommandSender sender) {
return true;
}
@Override
public @NotNull String getDescription() {
return "通知 JVM 进行一次垃圾回收";
}
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
System.gc();
sender.sendMessage("§a已发送 GC 信号.");
return true;
}
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
return Collections.emptyList();
}
}

View File

@@ -0,0 +1,81 @@
package cn.hamster3.mc.plugin.core.bukkit.command.core.sub;
import cn.hamster3.mc.plugin.core.bukkit.command.ChildCommand;
import cn.hamster3.mc.plugin.core.bukkit.constant.CoreMessage;
import cn.hamster3.mc.plugin.core.bukkit.listener.DebugListener;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.UUID;
public class InfoModeCommand extends ChildCommand {
public static final InfoModeCommand INSTANCE = new InfoModeCommand();
private InfoModeCommand() {
}
@Override
@SuppressWarnings("SpellCheckingInspection")
public @NotNull String getName() {
return "infomode";
}
@Override
@SuppressWarnings("SpellCheckingInspection")
public @NotNull String getUsage() {
return "infomode [on/off]";
}
@Override
public boolean hasPermission(@NotNull CommandSender sender) {
return true;
}
@Override
public @NotNull String getDescription() {
return "开启信息查询模式";
}
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (!(sender instanceof Player)) {
CoreMessage.COMMAND_MUST_USED_BY_PLAYER.show(sender);
return true;
}
Player player = (Player) sender;
UUID uuid = player.getUniqueId();
if (args.length >= 1) {
switch (args[0]) {
case "1":
case "on": {
DebugListener.INFO_MODE_PLAYERS.add(uuid);
CoreMessage.COMMAND_DEBUG_INFO_MODE_ON.show(player);
return true;
}
case "0":
case "off": {
DebugListener.INFO_MODE_PLAYERS.remove(uuid);
CoreMessage.COMMAND_DEBUG_INFO_MODE_OFF.show(player);
return true;
}
}
}
if (DebugListener.INFO_MODE_PLAYERS.contains(uuid)) {
DebugListener.INFO_MODE_PLAYERS.remove(uuid);
CoreMessage.COMMAND_DEBUG_INFO_MODE_OFF.show(player);
} else {
DebugListener.INFO_MODE_PLAYERS.add(uuid);
CoreMessage.COMMAND_DEBUG_INFO_MODE_ON.show(player);
}
return true;
}
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
return null;
}
}

View File

@@ -0,0 +1,51 @@
package cn.hamster3.mc.plugin.core.bukkit.command.core.sub;
import cn.hamster3.mc.plugin.core.bukkit.command.ChildCommand;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
public class MemoryCommand extends ChildCommand {
public static final MemoryCommand INSTANCE = new MemoryCommand();
private MemoryCommand() {
}
@Override
public @NotNull String getName() {
return "memory";
}
@Override
public @NotNull String getUsage() {
return "memory";
}
@Override
public boolean hasPermission(@NotNull CommandSender sender) {
return true;
}
@Override
public @NotNull String getDescription() {
return "查看内存信息";
}
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
Runtime runtime = Runtime.getRuntime();
sender.sendMessage(String.format("活跃内存:%.2f MB", (runtime.totalMemory() - runtime.freeMemory()) / 1024.0 / 1024.0));
sender.sendMessage(String.format("空闲内存:%.2f MB", runtime.freeMemory() / 1024.0 / 1024.0));
sender.sendMessage(String.format("占用系统内存:%.2f MB", runtime.totalMemory() / 1024.0 / 1024.0));
sender.sendMessage(String.format("最大可用内存:%.2f MB", runtime.maxMemory() / 1024.0 / 1024.0));
return true;
}
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
return Collections.emptyList();
}
}

View File

@@ -0,0 +1,49 @@
package cn.hamster3.mc.plugin.core.bukkit.command.core.sub;
import cn.hamster3.mc.plugin.core.bukkit.command.ChildCommand;
import cn.hamster3.mc.plugin.core.bukkit.page.PageManager;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
public class ReloadCommand extends ChildCommand {
public static final ReloadCommand INSTANCE = new ReloadCommand();
private ReloadCommand() {
}
@Override
public @NotNull String getName() {
return "reload";
}
@Override
public @NotNull String getUsage() {
return "reload";
}
@Override
public boolean hasPermission(@NotNull CommandSender sender) {
return true;
}
@Override
public @NotNull String getDescription() {
return "重载页面配置文件";
}
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
PageManager.PAGE_CONFIG.clear();
sender.sendMessage("§a已重载页面配置文件.");
return true;
}
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
return Collections.emptyList();
}
}

View File

@@ -0,0 +1,60 @@
package cn.hamster3.mc.plugin.core.bukkit.command.core.sub;
import cn.hamster3.mc.plugin.core.bukkit.command.ChildCommand;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class SystemCommand extends ChildCommand {
public static final SystemCommand INSTANCE = new SystemCommand();
private SystemCommand() {
}
@Override
public @NotNull String getName() {
return "system";
}
@Override
public @NotNull String getUsage() {
return "system";
}
@Override
public boolean hasPermission(@NotNull CommandSender sender) {
return true;
}
@Override
public @NotNull String getDescription() {
return "查看系统属性";
}
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (args.length < 1) {
sender.sendMessage(System.getProperties().toString());
return true;
}
sender.sendMessage(args[0] + "=" + System.getProperty(args[0], ""));
return true;
}
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
if (args.length == 1) {
String lowerCase = args[0].toLowerCase();
return System.getProperties().keySet()
.stream()
.map(Object::toString)
.filter(o -> o.toLowerCase().startsWith(lowerCase))
.collect(Collectors.toList());
}
return Collections.emptyList();
}
}

View File

@@ -0,0 +1,97 @@
package cn.hamster3.mc.plugin.core.bukkit.command.core.sub;
import cn.hamster3.mc.plugin.core.bukkit.HamsterCorePlugin;
import cn.hamster3.mc.plugin.core.bukkit.command.ChildCommand;
import cn.hamster3.mc.plugin.core.bukkit.util.CoreBukkitUtils;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class YamlCommand extends ChildCommand {
public static final YamlCommand INSTANCE = new YamlCommand();
private YamlCommand() {
}
@Override
public @NotNull String getName() {
return "yaml";
}
@Override
public @NotNull String getUsage() {
return "yaml";
}
@Override
public boolean hasPermission(@NotNull CommandSender sender) {
return sender.hasPermission("hamster.core.admin");
}
@Override
public @NotNull String getDescription() {
return "将当前信息保存至 yaml 中";
}
@SuppressWarnings({"deprecation", "ConstantConditions"})
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
YamlConfiguration config = new YamlConfiguration();
config.set("mc-version", CoreBukkitUtils.getMCVersion());
config.set("nms-version", CoreBukkitUtils.getNMSVersion());
config.set("server-version", Bukkit.getBukkitVersion());
config.set("bukkit-version", Bukkit.getVersion());
if (sender instanceof Player) {
Player player = (Player) sender;
config.set("player-name", player.getName());
config.set("player-uuid", player.getUniqueId().toString());
config.set("location", player.getLocation());
config.set("hand-item", player.getInventory().getItemInHand());
}
ItemStack stack = new ItemStack(Material.DIAMOND_SWORD);
ItemMeta meta = stack.getItemMeta();
List<String> lore = new ArrayList<>();
lore.add("§e测试 lore 1");
lore.add("§e测试 lore 2");
lore.add("§e测试 lore 3");
meta.setDisplayName("§a测试物品");
meta.setLore(lore);
meta.addItemFlags(ItemFlag.values());
meta.addEnchant(Enchantment.DAMAGE_ALL, 1, true);
stack.setItemMeta(meta);
config.set("test-item", stack);
File dataFolder = new File(HamsterCorePlugin.getInstance().getDataFolder(), "yaml");
if (dataFolder.mkdirs()) {
HamsterCorePlugin.getInstance().getLogger().info("创建 yaml 存档文件夹...");
}
File saveFile = new File(dataFolder, sender.getName() + "_" + System.currentTimeMillis() + ".yml");
try {
config.save(saveFile);
} catch (IOException e) {
e.printStackTrace();
}
sender.sendMessage("§a信息已保存至文件 " + saveFile.getAbsolutePath());
return true;
}
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
return Collections.emptyList();
}
}

View File

@@ -0,0 +1,37 @@
package cn.hamster3.mc.plugin.core.bukkit.command.lore;
import cn.hamster3.mc.plugin.core.bukkit.HamsterCorePlugin;
import cn.hamster3.mc.plugin.core.bukkit.command.ParentCommand;
import cn.hamster3.mc.plugin.core.bukkit.command.lore.sub.*;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
public final class ParentLoreCommand extends ParentCommand {
public static final ParentLoreCommand INSTANCE = new ParentLoreCommand();
public ParentLoreCommand() {
super("lore");
addChildCommand(LoreAddCommand.INSTANCE);
addChildCommand(LoreRemoveCommand.INSTANCE);
addChildCommand(LoreSetCommand.INSTANCE);
addChildCommand(LoreClearCommand.INSTANCE);
addChildCommand(LoreNameCommand.INSTANCE);
addChildCommand(LoreCustomModelDataCommand.INSTANCE);
addChildCommand(LoreFlagCommand.INSTANCE);
}
@Override
public @NotNull JavaPlugin getPlugin() {
return HamsterCorePlugin.getInstance();
}
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
for (int i = 0; i < args.length; i++) {
args[i] = args[i].replace("&", "§");
}
return super.onCommand(sender, command, label, args);
}
}

View File

@@ -0,0 +1,77 @@
package cn.hamster3.mc.plugin.core.bukkit.command.lore.sub;
import cn.hamster3.mc.plugin.core.bukkit.command.ChildCommand;
import cn.hamster3.mc.plugin.core.bukkit.constant.CoreMessage;
import cn.hamster3.mc.plugin.core.bukkit.util.CoreBukkitUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public class LoreAddCommand extends ChildCommand {
public static final LoreAddCommand INSTANCE = new LoreAddCommand();
private LoreAddCommand() {
}
@Override
public @NotNull String getName() {
return "add";
}
@Override
public @NotNull String getUsage() {
return "add <lore>";
}
@Override
public boolean hasPermission(@NotNull CommandSender sender) {
return true;
}
@Override
public @NotNull String getDescription() {
return "为手持物品添加一条 lore";
}
@SuppressWarnings("deprecation")
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (args.length < 1) {
CoreMessage.COMMAND_LORE_EMPTY_INPUT.show(sender);
return true;
}
if (!(sender instanceof Player)) {
CoreMessage.COMMAND_MUST_USED_BY_PLAYER.show(sender);
return true;
}
Player player = (Player) sender;
ItemStack stack = player.getItemInHand();
if (CoreBukkitUtils.isEmptyItemStack(stack)) {
CoreMessage.COMMAND_LORE_HAND_EMPTY.show(player);
return true;
}
ItemMeta meta = stack.getItemMeta();
if (meta != null) {
List<String> lore = meta.getLore();
if (lore == null) {
lore = new ArrayList<>();
}
lore.add(String.join(" ", args));
meta.setLore(lore);
}
stack.setItemMeta(meta);
CoreMessage.COMMAND_LORE_ADD_SUCCESS.show(player);
return true;
}
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
return null;
}
}

View File

@@ -0,0 +1,73 @@
package cn.hamster3.mc.plugin.core.bukkit.command.lore.sub;
import cn.hamster3.mc.plugin.core.bukkit.command.ChildCommand;
import cn.hamster3.mc.plugin.core.bukkit.constant.CoreMessage;
import cn.hamster3.mc.plugin.core.bukkit.util.CoreBukkitUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public class LoreClearCommand extends ChildCommand {
public static final LoreClearCommand INSTANCE = new LoreClearCommand();
private LoreClearCommand() {
}
@Override
public @NotNull String getName() {
return "clear";
}
@Override
public @NotNull String getUsage() {
return "clear";
}
@Override
public boolean hasPermission(@NotNull CommandSender sender) {
return true;
}
@Override
public @NotNull String getDescription() {
return "清除手持物品的所有 lore";
}
@SuppressWarnings("deprecation")
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (!(sender instanceof Player)) {
CoreMessage.COMMAND_MUST_USED_BY_PLAYER.show(sender);
return true;
}
Player player = (Player) sender;
ItemStack stack = player.getItemInHand();
if (CoreBukkitUtils.isEmptyItemStack(stack)) {
CoreMessage.COMMAND_LORE_HAND_EMPTY.show(player);
return true;
}
ItemMeta meta = stack.getItemMeta();
if (meta != null) {
List<String> lore = meta.getLore();
if (lore == null || lore.isEmpty()) {
CoreMessage.COMMAND_LORE_CLEAR_NOTHING.show(player);
return true;
}
meta.setLore(new ArrayList<>());
}
stack.setItemMeta(meta);
CoreMessage.COMMAND_LORE_CLEAR_SUCCESS.show(player);
return true;
}
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
return null;
}
}

View File

@@ -0,0 +1,83 @@
package cn.hamster3.mc.plugin.core.bukkit.command.lore.sub;
import cn.hamster3.mc.plugin.core.bukkit.command.ChildCommand;
import cn.hamster3.mc.plugin.core.bukkit.constant.CoreMessage;
import cn.hamster3.mc.plugin.core.bukkit.util.CoreBukkitUtils;
import net.kyori.adventure.text.TextReplacementConfig;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class LoreCustomModelDataCommand extends ChildCommand {
public static final LoreCustomModelDataCommand INSTANCE = new LoreCustomModelDataCommand();
private LoreCustomModelDataCommand() {
}
@Override
public @NotNull String getName() {
return "cmd";
}
@Override
public @NotNull String getUsage() {
return "cmd [data]";
}
@Override
public boolean hasPermission(@NotNull CommandSender sender) {
return true;
}
@Override
public @NotNull String getDescription() {
return "设置手持物品的自定义模型数据";
}
@SuppressWarnings("deprecation")
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (!(sender instanceof Player)) {
CoreMessage.COMMAND_MUST_USED_BY_PLAYER.show(sender);
return true;
}
Player player = (Player) sender;
ItemStack stack = player.getItemInHand();
if (CoreBukkitUtils.isEmptyItemStack(stack)) {
CoreMessage.COMMAND_LORE_HAND_EMPTY.show(player);
return true;
}
ItemMeta meta = stack.getItemMeta();
if (meta == null) {
return true;
}
if (args.length < 1) {
meta.setCustomModelData(null);
stack.setItemMeta(meta);
CoreMessage.COMMAND_LORE_CMD_CLEAR_SUCCESS.show(sender);
return true;
}
try {
int data = Integer.parseInt(args[0]);
meta.setCustomModelData(data);
stack.setItemMeta(meta);
CoreMessage.COMMAND_LORE_CMD_SET_SUCCESS.show(sender, TextReplacementConfig.builder()
.matchLiteral("%data%").replacement(args[0])
.build());
} catch (NumberFormatException e) {
CoreMessage.COMMAND_LORE_CMD_SET_INPUT_ERROR.show(sender);
return true;
}
return true;
}
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
return null;
}
}

View File

@@ -0,0 +1,91 @@
package cn.hamster3.mc.plugin.core.bukkit.command.lore.sub;
import cn.hamster3.mc.plugin.core.bukkit.command.ChildCommand;
import cn.hamster3.mc.plugin.core.bukkit.constant.CoreMessage;
import cn.hamster3.mc.plugin.core.bukkit.util.CoreBukkitUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class LoreFlagCommand extends ChildCommand {
public static final LoreFlagCommand INSTANCE = new LoreFlagCommand();
private LoreFlagCommand() {
}
@Override
public @NotNull String getName() {
return "flag";
}
@Override
public @NotNull String getUsage() {
return "flag <ItemFlag>";
}
@Override
public boolean hasPermission(@NotNull CommandSender sender) {
return true;
}
@Override
public @NotNull String getDescription() {
return "为手持物品添加一条 lore";
}
@SuppressWarnings("deprecation")
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (args.length < 1) {
CoreMessage.COMMAND_LORE_EMPTY_INPUT.show(sender);
return true;
}
if (!(sender instanceof Player)) {
CoreMessage.COMMAND_MUST_USED_BY_PLAYER.show(sender);
return true;
}
Player player = (Player) sender;
ItemStack stack = player.getItemInHand();
if (CoreBukkitUtils.isEmptyItemStack(stack)) {
CoreMessage.COMMAND_LORE_HAND_EMPTY.show(player);
return true;
}
ItemFlag flag;
try {
flag = ItemFlag.valueOf(args[0]);
} catch (IllegalArgumentException e) {
CoreMessage.COMMAND_LORE_FLAG_SET_INPUT_ERROR.show(player);
return true;
}
ItemMeta meta = stack.getItemMeta();
if (meta != null) {
if (meta.hasItemFlag(flag)) {
meta.removeItemFlags(flag);
CoreMessage.COMMAND_LORE_FLAG_REMOVE_SUCCESS.show(player);
} else {
meta.addItemFlags(flag);
CoreMessage.COMMAND_LORE_FLAG_SET_SUCCESS.show(player);
}
}
stack.setItemMeta(meta);
return true;
}
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
return Arrays.stream(ItemFlag.values())
.map(Enum::name)
.filter(o -> o.startsWith(args[0].toUpperCase()))
.collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,71 @@
package cn.hamster3.mc.plugin.core.bukkit.command.lore.sub;
import cn.hamster3.mc.plugin.core.bukkit.command.ChildCommand;
import cn.hamster3.mc.plugin.core.bukkit.constant.CoreMessage;
import cn.hamster3.mc.plugin.core.bukkit.util.CoreBukkitUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class LoreNameCommand extends ChildCommand {
public static final LoreNameCommand INSTANCE = new LoreNameCommand();
private LoreNameCommand() {
}
@Override
public @NotNull String getName() {
return "name";
}
@Override
public @NotNull String getUsage() {
return "name <name>";
}
@Override
public boolean hasPermission(@NotNull CommandSender sender) {
return true;
}
@Override
public @NotNull String getDescription() {
return "更改手持物品的显示名称";
}
@SuppressWarnings("deprecation")
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (args.length < 1) {
CoreMessage.COMMAND_LORE_EMPTY_INPUT.show(sender);
return true;
}
if (!(sender instanceof Player)) {
CoreMessage.COMMAND_MUST_USED_BY_PLAYER.show(sender);
return true;
}
Player player = (Player) sender;
ItemStack stack = player.getItemInHand();
if (CoreBukkitUtils.isEmptyItemStack(stack)) {
CoreMessage.COMMAND_LORE_HAND_EMPTY.show(player);
return true;
}
ItemMeta meta = stack.getItemMeta();
if (meta != null) {
meta.setDisplayName(String.join(" ", args));
}
stack.setItemMeta(meta);
CoreMessage.COMMAND_LORE_NAME_SUCCESS.show(player);
return true;
}
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
return null;
}
}

View File

@@ -0,0 +1,86 @@
package cn.hamster3.mc.plugin.core.bukkit.command.lore.sub;
import cn.hamster3.mc.plugin.core.bukkit.command.ChildCommand;
import cn.hamster3.mc.plugin.core.bukkit.constant.CoreMessage;
import cn.hamster3.mc.plugin.core.bukkit.util.CoreBukkitUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public class LoreRemoveCommand extends ChildCommand {
public static final LoreRemoveCommand INSTANCE = new LoreRemoveCommand();
private LoreRemoveCommand() {
}
@Override
public @NotNull String getName() {
return "remove";
}
@Override
public @NotNull String getUsage() {
return "remove <line>";
}
@Override
public boolean hasPermission(@NotNull CommandSender sender) {
return true;
}
@Override
public @NotNull String getDescription() {
return "为手持物品删除一条 lore";
}
@SuppressWarnings("deprecation")
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (args.length < 1) {
CoreMessage.COMMAND_LORE_REMOVE_NOT_INPUT_NUMBER.show(sender);
return true;
}
if (!(sender instanceof Player)) {
CoreMessage.COMMAND_MUST_USED_BY_PLAYER.show(sender);
return true;
}
int i = Integer.parseInt(args[0]);
if (i <= 0) {
CoreMessage.COMMAND_LORE_REMOVE_INPUT_NUMBER_ERROR.show(sender);
return true;
}
Player player = (Player) sender;
ItemStack stack = player.getItemInHand();
if (CoreBukkitUtils.isEmptyItemStack(stack)) {
CoreMessage.COMMAND_LORE_HAND_EMPTY.show(player);
return true;
}
ItemMeta meta = stack.getItemMeta();
if (meta != null) {
List<String> lore = meta.getLore();
if (lore == null) {
lore = new ArrayList<>();
}
if (lore.size() < i) {
CoreMessage.COMMAND_LORE_REMOVE_INDEX_OUT_OF_RANGE.show(player);
return true;
}
lore.remove(i - 1);
meta.setLore(lore);
}
stack.setItemMeta(meta);
CoreMessage.COMMAND_LORE_REMOVE_SUCCESS.show(player);
return true;
}
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
return null;
}
}

View File

@@ -0,0 +1,92 @@
package cn.hamster3.mc.plugin.core.bukkit.command.lore.sub;
import cn.hamster3.mc.plugin.core.bukkit.command.ChildCommand;
import cn.hamster3.mc.plugin.core.bukkit.constant.CoreMessage;
import cn.hamster3.mc.plugin.core.bukkit.util.CoreBukkitUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class LoreSetCommand extends ChildCommand {
public static final LoreSetCommand INSTANCE = new LoreSetCommand();
private LoreSetCommand() {
}
@Override
public @NotNull String getName() {
return "set";
}
@Override
public @NotNull String getUsage() {
return "set <line> <lore>";
}
@Override
public boolean hasPermission(@NotNull CommandSender sender) {
return true;
}
@Override
public @NotNull String getDescription() {
return "设置指定行数的 lore";
}
@SuppressWarnings("deprecation")
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (args.length < 1) {
CoreMessage.COMMAND_LORE_SET_NOT_INPUT_NUMBER.show(sender);
return true;
}
if (args.length < 2) {
CoreMessage.COMMAND_LORE_SET_NOT_INPUT_TEXT.show(sender);
return true;
}
if (!(sender instanceof Player)) {
CoreMessage.COMMAND_MUST_USED_BY_PLAYER.show(sender);
return true;
}
int i = Integer.parseInt(args[0]);
if (i <= 0) {
CoreMessage.COMMAND_LORE_SET_INPUT_NUMBER_ERROR.show(sender);
return true;
}
Player player = (Player) sender;
ItemStack stack = player.getItemInHand();
if (CoreBukkitUtils.isEmptyItemStack(stack)) {
CoreMessage.COMMAND_LORE_HAND_EMPTY.show(player);
return true;
}
ItemMeta meta = stack.getItemMeta();
if (meta != null) {
List<String> lore = meta.getLore();
if (lore == null) {
lore = new ArrayList<>();
}
if (lore.size() < i) {
CoreMessage.COMMAND_LORE_SET_INDEX_OUT_OF_RANGE.show(player);
return true;
}
args = Arrays.copyOfRange(args, 1, args.length);
lore.set(i - 1, String.join(" ", args));
meta.setLore(lore);
}
stack.setItemMeta(meta);
CoreMessage.COMMAND_LORE_SET_SUCCESS.show(player);
return true;
}
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
return null;
}
}

View File

@@ -0,0 +1,76 @@
package cn.hamster3.mc.plugin.core.bukkit.constant;
import cn.hamster3.mc.plugin.core.bukkit.api.CoreBukkitAPI;
import cn.hamster3.mc.plugin.core.bukkit.util.CoreBukkitUtils;
import cn.hamster3.mc.plugin.core.common.data.DisplayMessage;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.TextReplacementConfig;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
public enum CoreMessage {
COMMAND_NOT_FOUND,
COMMAND_NOT_HAS_PERMISSION,
COMMAND_MUST_USED_BY_PLAYER,
COMMAND_DEBUG_INFO_MODE_ON,
COMMAND_DEBUG_INFO_MODE_OFF,
COMMAND_LORE_HAND_EMPTY,
COMMAND_LORE_EMPTY_INPUT,
COMMAND_LORE_ADD_SUCCESS,
COMMAND_LORE_CLEAR_NOTHING,
COMMAND_LORE_CLEAR_SUCCESS,
COMMAND_LORE_CMD_CLEAR_SUCCESS,
COMMAND_LORE_CMD_SET_SUCCESS,
COMMAND_LORE_CMD_SET_INPUT_ERROR,
COMMAND_LORE_FLAG_SET_SUCCESS,
COMMAND_LORE_FLAG_REMOVE_SUCCESS,
COMMAND_LORE_FLAG_SET_INPUT_ERROR,
COMMAND_LORE_NAME_SUCCESS,
COMMAND_LORE_REMOVE_NOT_INPUT_NUMBER,
COMMAND_LORE_REMOVE_INPUT_NUMBER_ERROR,
COMMAND_LORE_REMOVE_INDEX_OUT_OF_RANGE,
COMMAND_LORE_REMOVE_SUCCESS,
COMMAND_LORE_SET_NOT_INPUT_NUMBER,
COMMAND_LORE_SET_INPUT_NUMBER_ERROR,
COMMAND_LORE_SET_NOT_INPUT_TEXT,
COMMAND_LORE_SET_INDEX_OUT_OF_RANGE,
COMMAND_LORE_SET_SUCCESS;
private DisplayMessage message;
public static void init(@NotNull Plugin plugin) {
ConfigurationSection config = plugin.getConfig().getConfigurationSection("messages");
if (config == null) {
plugin.getLogger().warning("加载消息失败: 配置文件中未找到 messages 节点!");
return;
}
for (CoreMessage value : values()) {
ConfigurationSection section = config.getConfigurationSection(value.name());
if (section == null) {
continue;
}
try {
value.message = CoreBukkitUtils.getDisplayMessage(section);
} catch (Exception e) {
plugin.getLogger().warning("加载消息设置 " + value.name() + " 时遇到了一个异常: ");
e.printStackTrace();
}
}
}
public void show(CommandSender sender, TextReplacementConfig... replacement) {
if (message == null) {
sender.sendMessage(name());
return;
}
Audience audience = CoreBukkitAPI.getInstance().getAudienceProvider().sender(sender);
message.show(audience, replacement);
}
@SuppressWarnings("unused")
public DisplayMessage getMessage() {
return message;
}
}

View File

@@ -0,0 +1,158 @@
package cn.hamster3.mc.plugin.core.bukkit.hook;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
/**
* Vault Economy API
*/
@SuppressWarnings("unused")
public class EconomyAPI {
private EconomyAPI() {
}
/**
* 返回服务器是否安装了经济插件
*
* @return true代表安装了false代表未安装
*/
public static boolean isSetupEconomy() {
return VaultAPI.isSetupVault() && VaultAPI.getEconomy() != null;
}
/**
* 给玩家钱
*
* @param player 玩家
* @param money 钱的数量
* @return 成功则返回 true
*/
public static boolean giveMoney(@NotNull final OfflinePlayer player, final double money) {
if (isSetupEconomy()) {
return VaultAPI.getEconomy().depositPlayer(player, money).transactionSuccess();
}
return false;
}
/**
* 给玩家钱
*
* @param uuid 玩家的uuid
* @param money 钱的数量
* @return 成功则返回 true
*/
public static boolean giveMoney(@NotNull final UUID uuid, final double money) {
return giveMoney(Bukkit.getOfflinePlayer(uuid), money);
}
/**
* 从玩家账户上扣钱
*
* @param player 玩家
* @param money 钱的数量
* @return 成功则返回 true
*/
public static boolean takeMoney(@NotNull final OfflinePlayer player, final double money) {
if (isSetupEconomy()) {
return VaultAPI.getEconomy().withdrawPlayer(player, money).transactionSuccess();
}
return false;
}
/**
* 从玩家账户上扣钱
*
* @param uuid 玩家的uuid
* @param money 钱的数量
* @return 成功则返回 true
*/
public static boolean takeMoney(@NotNull final UUID uuid, final double money) {
return takeMoney(Bukkit.getOfflinePlayer(uuid), money);
}
/**
* 设置玩家的余额
*
* @param player 玩家
* @param money 钱的数量
* @return 成功则返回 true
*/
public static boolean setMoney(@NotNull OfflinePlayer player, final double money) {
if (!isSetupEconomy()) {
return false;
}
double v = seeMoney(player);
if (v > money) {
return takeMoney(player, v - money);
} else if (v < money) {
return giveMoney(player, money - v);
}
return true;
}
/**
* 设置玩家的余额
*
* @param uuid 玩家的uuid
* @param money 钱的数量
* @return 成功则返回 true
*/
public static boolean setMoney(@NotNull final UUID uuid, final double money) {
return setMoney(Bukkit.getOfflinePlayer(uuid), money);
}
/**
* 检查玩家有多少钱
* <p>
* 若没有安装经济插件则返回NaN
*
* @param player 玩家
* @return 玩家的余额
*/
public static double seeMoney(@NotNull final OfflinePlayer player) {
if (!isSetupEconomy()) {
return Double.NaN;
}
return VaultAPI.getEconomy().getBalance(player);
}
/**
* 检查玩家有多少钱
* <p>
* 若没有安装经济插件则返回NaN
*
* @param uuid 玩家的uuid
* @return 玩家的余额
*/
public static double seeMoney(@NotNull final UUID uuid) {
return seeMoney(Bukkit.getOfflinePlayer(uuid));
}
/**
* 检测玩家是否有足够的钱
*
* @param player 玩家
* @param money 金钱的数量
* @return 是否有足够的钱(若没有安装经济插件则直接返回 false
*/
public static boolean hasMoney(@NotNull final OfflinePlayer player, final double money) {
if (!isSetupEconomy()) {
return false;
}
return VaultAPI.getEconomy().has(player, money);
}
/**
* 检测玩家是否有足够的钱
*
* @param uuid 玩家的uuid
* @param money 金钱的数量
* @return 是否有足够的钱(若没有安装经济插件则直接返回 false
*/
public static boolean hasMoney(@NotNull final UUID uuid, final double money) {
return hasMoney(Bukkit.getOfflinePlayer(uuid), money);
}
}

View File

@@ -0,0 +1,178 @@
package cn.hamster3.mc.plugin.core.bukkit.hook;
import cn.hamster3.mc.plugin.core.bukkit.HamsterCorePlugin;
import org.black_ixx.playerpoints.PlayerPoints;
import org.black_ixx.playerpoints.PlayerPointsAPI;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.plugin.Plugin;
import java.util.UUID;
/**
* PlayerPointsAPI
*/
@SuppressWarnings("unused")
public class PointAPI {
private static PlayerPointsAPI playerPointsAPI;
private PointAPI() {
}
/**
* 重载 PlayerPointAPI 点券系统挂接
*/
public static void reloadPlayerPointAPIHook() {
Plugin plugin = Bukkit.getPluginManager().getPlugin("PlayerPoints");
if (plugin == null) {
HamsterCorePlugin.getInstance().getLogger().warning("未检测到 PlayerPointAPI 插件!");
return;
}
playerPointsAPI = ((PlayerPoints) plugin).getAPI();
HamsterCorePlugin.getInstance().getLogger().info("PlayerPointAPI 挂接成功!");
}
/**
* 获取 PlayerPointsAPI 实例
*
* @return PlayerPointsAPI 实例
*/
public static PlayerPointsAPI getPlayerPointsAPI() {
return playerPointsAPI;
}
/**
* 返回服务器是否安装了 PlayerPointAPI 插件
*
* @return true代表安装了false代表未安装
*/
public static boolean isSetupPlayerPointAPI() {
return playerPointsAPI != null;
}
/**
* 给予玩家点券
*
* @param player 玩家
* @param point 点券数量
*/
public static void givePoint(final OfflinePlayer player, final int point) {
if (playerPointsAPI != null) {
playerPointsAPI.give(player.getUniqueId(), point);
}
}
/**
* 给予玩家点券
*
* @param uuid 玩家的uuid
* @param point 点券数量
*/
public static void givePoint(final UUID uuid, final int point) {
if (playerPointsAPI != null) {
playerPointsAPI.give(uuid, point);
}
}
/**
* 扣除玩家点券
*
* @param player 玩家
* @param point 点券数量
*/
public static void takePoint(final OfflinePlayer player, final int point) {
if (playerPointsAPI != null) {
playerPointsAPI.take(player.getUniqueId(), point);
}
}
/**
* 扣除玩家点券
*
* @param uuid 玩家的uuid
* @param point 点券数量
*/
public static void takePoint(final UUID uuid, final int point) {
if (playerPointsAPI != null) {
playerPointsAPI.take(uuid, point);
}
}
/**
* 设置玩家的点券
*
* @param player 玩家
* @param point 点券数量
*/
public static void setPoint(final OfflinePlayer player, final int point) {
if (playerPointsAPI != null) {
playerPointsAPI.set(player.getUniqueId(), point);
}
}
/**
* 设置玩家的点券
*
* @param uuid 玩家的uuid
* @param point 点券数量
*/
public static void setPoint(final UUID uuid, final int point) {
if (playerPointsAPI != null) {
playerPointsAPI.set(uuid, point);
}
}
/**
* 查看玩家的点券数量
*
* @param player 玩家
* @return 玩家的点券数量
*/
public static int getPoint(final OfflinePlayer player) {
if (playerPointsAPI != null) {
return playerPointsAPI.look(player.getUniqueId());
}
return 0;
}
/**
* 查看玩家的点券数量
*
* @param uuid 玩家的uuid
* @return 玩家的点券数量
*/
public static int getPoint(final UUID uuid) {
if (playerPointsAPI != null) {
return playerPointsAPI.look(uuid);
}
return 0;
}
/**
* 检查玩家是否有足够的点券
*
* @param player 玩家
* @param point 点券数量
* @return 若未安装 PlayerPointAPI 则直接返回 false
*/
public static boolean hasPoint(final OfflinePlayer player, final int point) {
if (playerPointsAPI != null) {
return playerPointsAPI.look(player.getUniqueId()) >= point;
}
return false;
}
/**
* 检查玩家是否有足够的点券
*
* @param uuid 玩家的uuid
* @param point 点券数量
* @return 若未安装 PlayerPointAPI 则直接返回 false
*/
public static boolean hasPoint(final UUID uuid, final int point) {
if (playerPointsAPI != null) {
return playerPointsAPI.look(uuid) >= point;
}
return false;
}
}

View File

@@ -0,0 +1,96 @@
package cn.hamster3.mc.plugin.core.bukkit.hook;
import cn.hamster3.mc.plugin.core.bukkit.HamsterCorePlugin;
import net.milkbowl.vault.chat.Chat;
import net.milkbowl.vault.economy.Economy;
import net.milkbowl.vault.permission.Permission;
import org.bukkit.Bukkit;
import org.bukkit.plugin.RegisteredServiceProvider;
/**
* Vault API
*/
@SuppressWarnings("unused")
public class VaultAPI {
private static boolean vaultEnabled;
private static Chat chat;
private static Economy economy;
private static Permission permission;
private VaultAPI() {
}
public static void reloadVaultHook() {
chat = null;
economy = null;
permission = null;
vaultEnabled = Bukkit.getPluginManager().isPluginEnabled("Vault");
if (!vaultEnabled) {
HamsterCorePlugin.getInstance().getLogger().warning("未检测到 Vault 插件!");
return;
}
HamsterCorePlugin.getInstance().getLogger().info("已连接 Vault!");
RegisteredServiceProvider<Chat> chatProvider = Bukkit.getServer().getServicesManager().getRegistration(Chat.class);
if (chatProvider != null) {
chat = chatProvider.getProvider();
HamsterCorePlugin.getInstance().getLogger().info("聊天系统挂接成功.");
} else {
HamsterCorePlugin.getInstance().getLogger().warning("未检测到聊天系统!");
}
RegisteredServiceProvider<Economy> economyProvider = Bukkit.getServer().getServicesManager().getRegistration(Economy.class);
if (economyProvider != null) {
economy = economyProvider.getProvider();
HamsterCorePlugin.getInstance().getLogger().info("经济系统挂接成功.");
} else {
HamsterCorePlugin.getInstance().getLogger().warning("未检测到经济系统!");
}
RegisteredServiceProvider<Permission> permissionProvider = Bukkit.getServer().getServicesManager().getRegistration(Permission.class);
if (permissionProvider != null) {
permission = permissionProvider.getProvider();
HamsterCorePlugin.getInstance().getLogger().info("权限系统挂接成功.");
} else {
HamsterCorePlugin.getInstance().getLogger().warning("未检测到权限插件!");
}
}
/**
* 返回服务器是否安装了 Vault 插件
*
* @return true 代表服务器已安装
*/
public static boolean isSetupVault() {
return vaultEnabled;
}
/**
* 返回 Vault 的 Chat 前置系统
*
* @return Chat 系统
*/
public static Chat getChat() {
return chat;
}
/**
* 返回 Vault 的 Economy 前置系统
*
* @return Economy 系统
*/
public static Economy getEconomy() {
return economy;
}
/**
* 返回 Vault 的 Permission 前置系统
*
* @return Permission 系统
*/
public static Permission getPermission() {
return permission;
}
}

View File

@@ -0,0 +1,81 @@
package cn.hamster3.mc.plugin.core.bukkit.listener;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
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.player.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public class CallbackListener implements Listener {
public static final CallbackListener INSTANCE = new CallbackListener();
public static final HashMap<UUID, CompletableFuture<String>> CHATS = new HashMap<>();
public static final HashMap<UUID, CompletableFuture<Block>> BLOCKS = new HashMap<>();
public static final HashMap<UUID, CompletableFuture<Entity>> ENTITIES = new HashMap<>();
private CallbackListener() {
}
@EventHandler(ignoreCancelled = true)
public void onAsyncPlayerChat(AsyncPlayerChatEvent event) {
Player player = event.getPlayer();
CompletableFuture<String> future = CHATS.remove(player.getUniqueId());
if (future == null) {
return;
}
future.complete(event.getMessage());
event.setCancelled(true);
}
@EventHandler(ignoreCancelled = true)
public void onPlayerInteract(PlayerInteractEvent event) {
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) {
return;
}
Player player = event.getPlayer();
CompletableFuture<Block> future = BLOCKS.remove(player.getUniqueId());
if (future == null) {
return;
}
future.complete(event.getClickedBlock());
event.setCancelled(true);
}
@EventHandler(ignoreCancelled = true)
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
Player player = event.getPlayer();
CompletableFuture<Entity> future = ENTITIES.remove(player.getUniqueId());
if (future == null) {
return;
}
future.complete(event.getRightClicked());
event.setCancelled(true);
}
@EventHandler(ignoreCancelled = true)
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
UUID uuid = player.getUniqueId();
CompletableFuture<String> chat = CHATS.remove(uuid);
if (chat != null) {
chat.cancel(true);
}
CompletableFuture<Block> block = BLOCKS.remove(uuid);
if (block != null) {
block.cancel(true);
}
CompletableFuture<Entity> entity = ENTITIES.remove(uuid);
if (entity != null) {
entity.cancel(true);
}
}
}

View File

@@ -0,0 +1,90 @@
package cn.hamster3.mc.plugin.core.bukkit.listener;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import java.util.HashSet;
import java.util.UUID;
public class DebugListener implements Listener {
public static final DebugListener INSTANCE = new DebugListener();
/**
* 要查看方块信息的玩家
*/
public static final HashSet<UUID> INFO_MODE_PLAYERS = new HashSet<>();
private DebugListener() {
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOW)
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
UUID uuid = player.getUniqueId();
INFO_MODE_PLAYERS.remove(uuid);
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOW)
public void onPlayerInteract(PlayerInteractEvent event) {
Player player = event.getPlayer();
UUID uuid = player.getUniqueId();
if (!INFO_MODE_PLAYERS.contains(uuid)) {
return;
}
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) {
return;
}
event.setCancelled(true);
Block block = event.getClickedBlock();
if (block == null) {
return;
}
player.sendMessage("§e==============================");
player.sendMessage(String.format("§a方块位置: %s %d %d %d",
block.getWorld().getName(),
block.getX(), block.getY(),
block.getZ()
));
player.sendMessage("§a方块材质: " + block.getType().name());
player.sendMessage("§a方块能量: " + block.getBlockPower());
player.sendMessage("§a方块湿度: " + block.getHumidity());
player.sendMessage("§a自发光亮度: " + block.getLightLevel());
player.sendMessage("§a获取天空亮度: " + block.getLightFromSky());
player.sendMessage("§a方块吸收亮度: " + block.getLightFromBlocks());
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOW)
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
Player player = event.getPlayer();
UUID uuid = player.getUniqueId();
if (!INFO_MODE_PLAYERS.contains(uuid)) {
return;
}
event.setCancelled(true);
Entity entity = event.getRightClicked();
player.sendMessage("§e==============================");
Location location = entity.getLocation();
player.sendMessage(String.format("§a实体位置: %s %.2f %.2f %.2f %.2f %.2f",
entity.getWorld().getName(), location.getX(),
location.getY(),
location.getZ(),
location.getPitch(),
location.getYaw()
));
player.sendMessage("§a实体UUID: " + entity.getUniqueId());
player.sendMessage("§a实体类型: " + entity.getType().name());
player.sendMessage("§a实体名称: " + entity.getName());
player.sendMessage("§a自定义名称: " + entity.getCustomName());
player.sendMessage("§a名称可见: " + entity.isCustomNameVisible());
player.sendMessage("§a计分板标签: " + entity.getScoreboardTags());
}
}

View File

@@ -0,0 +1,195 @@
package cn.hamster3.mc.plugin.core.bukkit.page;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@SuppressWarnings("unused")
public class ButtonGroup {
@NotNull
private final String name;
@NotNull
private final PageConfig config;
@NotNull
private final Map<Character, String> buttonNameMap;
/**
* 实例化这个按钮组
*
* @param pageConfig Page 设定
* @param config 按钮组设定
*/
public ButtonGroup(@NotNull PageConfig pageConfig, @NotNull ConfigurationSection config) {
this.config = pageConfig;
name = config.getName();
buttonNameMap = new HashMap<>();
for (String key : config.getKeys(false)) {
buttonNameMap.put(key.charAt(0), config.getString(key));
}
}
public ButtonGroup(@NotNull String name, @NotNull PageConfig config, @NotNull Map<Character, String> buttonNameMap) {
this.name = name;
this.config = config;
this.buttonNameMap = buttonNameMap;
}
/**
* 以图形字符来获取按钮名称
* <p>
* 若未找到则返回 "empty"
*
* @param graphicKey 图形字符
* @return 按钮名称
*/
@NotNull
public String getButtonName(char graphicKey) {
return buttonNameMap.getOrDefault(graphicKey, "empty");
}
/**
* 以索引位置来获取按钮名称
* <p>
* 若未找到则返回 "empty"
*
* @param index 索引位置
* @return 按钮名称
*/
@NotNull
public String getButtonName(int index) {
return buttonNameMap.getOrDefault(config.getButtonKey(index), "empty");
}
/**
* 获取按钮在 GUI 中的第一个索引位置
*
* @param buttonName 按钮名称
* @return 按钮在 GUI 中的第一个索引位置
*/
public int getButtonIndex(String buttonName) {
Character graphicKey = getGraphicKey(buttonName);
if (graphicKey == null) {
return -1;
}
List<String> graphic = config.getGraphic();
for (int i = 0; i < graphic.size(); i++) {
char[] chars = graphic.get(i).toCharArray();
for (int j = 0; j < chars.length; j++) {
if (chars[j] == graphicKey) {
return i * 9 + j;
}
}
}
return -1;
}
/**
* 获得按钮在 GUI 中全部的索引位置
*
* @param buttonName 按钮名称
* @return 按钮在 GUI 中全部的索引位置
*/
public ArrayList<Integer> getButtonAllIndex(@NotNull String buttonName) {
ArrayList<Integer> list = new ArrayList<>();
Character graphicKey = getGraphicKey(buttonName);
if (graphicKey == null) {
return list;
}
List<String> graphic = config.getGraphic();
for (int i = 0; i < graphic.size(); i++) {
char[] chars = graphic.get(i).toCharArray();
for (int j = 0; j < chars.length; j++) {
if (chars[j] == graphicKey) {
list.add(i * 9 + j);
}
}
}
return list;
}
/**
* 以按钮名称来获取图形字符
*
* @param buttonName 按钮名称
* @return 图形中的字符
*/
@Nullable
public Character getGraphicKey(@NotNull String buttonName) {
for (Map.Entry<Character, String> entry : buttonNameMap.entrySet()) {
if (entry.getValue().equalsIgnoreCase(buttonName)) {
return entry.getKey();
}
}
return null;
}
/**
* 以图形字符来获取按钮物品
*
* @param graphicKey 图形字符
* @return 按钮物品
*/
public ItemStack getButtonItem(char graphicKey) {
return getButtonItem(getButtonName(graphicKey));
}
/**
* 以按钮名称来获取按钮物品
*
* @param buttonName 按钮名称
* @return 按钮物品
*/
public ItemStack getButtonItem(@NotNull String buttonName) {
ItemStack stack = config.getButtons().get(buttonName);
if (stack != null) {
stack = stack.clone();
}
return stack;
}
/**
* 获取这个按钮组的名称
*
* @return 按钮组名称
*/
@NotNull
public String getName() {
return name;
}
/**
* 获取把图形字符映射到按钮名称的表
*
* @return 把图形字符映射到按钮名称的表
*/
@NotNull
public Map<Character, String> getButtonNameMap() {
return buttonNameMap;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ButtonGroup that = (ButtonGroup) o;
return name.equals(that.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
@Override
public String toString() {
return "ButtonGroup{" +
"name='" + name + '\'' +
", buttonNameMap=" + buttonNameMap +
'}';
}
}

View File

@@ -0,0 +1,206 @@
package cn.hamster3.mc.plugin.core.bukkit.page;
import cn.hamster3.mc.plugin.core.bukkit.HamsterCorePlugin;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
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.Map;
@SuppressWarnings("unused")
public class PageConfig implements InventoryHolder {
@NotNull
private final Plugin plugin;
@NotNull
private final ConfigurationSection rawConfig;
@NotNull
private final String title;
@NotNull
private final List<String> graphic;
@NotNull
private final ArrayList<ButtonGroup> buttonGroups;
@NotNull
private final HashMap<String, Sound> buttonSounds;
@NotNull
private final HashMap<String, ItemStack> buttons;
@NotNull
private final Inventory inventory;
public PageConfig(@NotNull Plugin plugin, @NotNull ConfigurationSection rawConfig) {
this.plugin = plugin;
this.rawConfig = rawConfig;
title = rawConfig.getString("title", "").replace("&", "§");
List<String> graphicString = rawConfig.getStringList("graphic");
if (graphicString.size() > 6) {
graphicString = graphicString.subList(0, 6);
}
for (int i = 0; i < graphicString.size(); i++) {
String s = graphicString.get(i);
if (s.length() > 9) {
s = s.substring(0, 9);
}
graphicString.set(i, s);
}
graphic = graphicString;
inventory = Bukkit.createInventory(this, graphicString.size() * 9, title);
buttons = new HashMap<>();
ConfigurationSection buttonsConfig = rawConfig.getConfigurationSection("buttons");
if (buttonsConfig != null) {
for (String key : buttonsConfig.getKeys(false)) {
buttons.put(key, buttonsConfig.getItemStack(key));
}
}
buttonGroups = new ArrayList<>();
ConfigurationSection buttonGroupsConfig = rawConfig.getConfigurationSection("groups");
if (buttonGroupsConfig != null) {
for (String key : buttonGroupsConfig.getKeys(false)) {
//noinspection ConstantConditions
ButtonGroup buttonGroup = new ButtonGroup(this, buttonGroupsConfig.getConfigurationSection(key));
buttonGroups.add(buttonGroup);
}
}
ButtonGroup group = getButtonGroup("default");
for (int i = 0; i < graphicString.size(); i++) {
char[] chars = graphicString.get(i).toCharArray();
for (int j = 0; j < chars.length; j++) {
char c = chars[j];
int index = i * 9 + j;
inventory.setItem(index, group.getButtonItem(c));
}
}
buttonSounds = new HashMap<>();
ConfigurationSection buttonSoundConfig = rawConfig.getConfigurationSection("sounds");
if (buttonSoundConfig != null) {
for (String key : buttonSoundConfig.getKeys(false)) {
String soundName = buttonSoundConfig.getString(key, "");
if (soundName.isEmpty() || soundName.equalsIgnoreCase("null")) {
buttonSounds.put(key, null);
continue;
}
try {
buttonSounds.put(key, Sound.valueOf(soundName));
} catch (Exception e) {
HamsterCorePlugin.getInstance().getLogger().warning("初始化 PageConfig 时遇到了一个异常:");
e.printStackTrace();
}
}
}
}
/**
* 获取把 buttonName 映射到 展示物品 的表
*
* @return 把 buttonName 映射到 展示物品 的表
*/
@NotNull
public HashMap<String, ItemStack> getButtons() {
return buttons;
}
/**
* 获取索引位置上的 graphicKey
*
* @param index 索引
* @return 若超出 graphic 范围则返回 null
*/
@Nullable
public Character getButtonKey(int index) {
if (index < 0) return null;
if (index / 9 >= graphic.size()) return null;
String s = graphic.get(index / 9);
return s.charAt(index % 9);
}
/**
* 获取该显示物品对应的 buttonName
*
* @param stack 显示物品
* @return 按钮名称,若无法找到则返回 "empty"
*/
@NotNull
public String getButtonName(@Nullable ItemStack stack) {
if (stack == null) {
return "empty";
}
for (Map.Entry<String, ItemStack> entry : buttons.entrySet()) {
if (entry.getValue().isSimilar(stack)) {
return entry.getKey();
}
}
return "empty";
}
@Nullable
public Sound getButtonSound(@NotNull String buttonName) {
return buttonSounds.get(buttonName);
}
@NotNull
public ButtonGroup getButtonGroup(@NotNull String groupName) {
for (ButtonGroup group : buttonGroups) {
if (group.getName().equalsIgnoreCase(groupName)) {
return group;
}
}
throw new IllegalArgumentException("未找到名称为 " + groupName + " 的按钮编组!");
}
@NotNull
public Plugin getPlugin() {
return plugin;
}
@NotNull
public ConfigurationSection getRawConfig() {
return rawConfig;
}
@NotNull
public String getTitle() {
return title;
}
@NotNull
public List<String> getGraphic() {
return graphic;
}
@NotNull
public ArrayList<ButtonGroup> getButtonGroups() {
return buttonGroups;
}
@NotNull
@Override
public Inventory getInventory() {
return inventory;
}
@Override
public String toString() {
return "PageConfig{" +
", title='" + title + '\'' +
", graphic=" + graphic +
", buttonMap=" + buttons +
", buttonGroups=" + buttonGroups +
'}';
}
}

View File

@@ -0,0 +1,62 @@
package cn.hamster3.mc.plugin.core.bukkit.page;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
public class PageManager {
public static final HashMap<String, PageConfig> PAGE_CONFIG = new HashMap<>();
@NotNull
public static PageConfig getPageConfig(@NotNull Class<?> clazz) {
PageConfig pageConfig = PAGE_CONFIG.get(clazz.getName());
if (pageConfig != null) {
return pageConfig;
}
if (!clazz.isAnnotationPresent(PluginPage.class)) {
throw new IllegalArgumentException(clazz.getName() + " 未被 @PluginPage 注解修饰!");
}
PluginPage annotation = clazz.getAnnotation(PluginPage.class);
String pluginName = annotation.value();
Plugin plugin = Bukkit.getPluginManager().getPlugin(pluginName);
if (plugin == null) {
throw new IllegalArgumentException("未找到插件 " + pluginName + " !");
}
pageConfig = getPageConfig(plugin, clazz.getSimpleName());
PAGE_CONFIG.put(clazz.getName(), pageConfig);
return pageConfig;
}
@NotNull
public static PageConfig getPageConfig(@NotNull Plugin plugin, @NotNull String pageName) {
String pluginName = plugin.getName();
File pageFolder = new File(plugin.getDataFolder(), "pages");
if (pageFolder.mkdirs()) {
plugin.getLogger().info("创建页面配置文件夹...");
}
String filename = pageName + ".yml";
File pageConfigFile = new File(pageFolder, filename);
if (pageConfigFile.exists()) {
YamlConfiguration config = YamlConfiguration.loadConfiguration(pageConfigFile);
return new PageConfig(plugin, config);
}
try (InputStream resource = plugin.getResource("pages/" + filename)) {
if (resource == null) {
throw new IllegalArgumentException("在插件 " + plugin.getName() + " 的 Jar 文件内部未找到 /pages/" + filename + " !");
}
Files.copy(resource, pageConfigFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
YamlConfiguration config = YamlConfiguration.loadConfiguration(pageConfigFile);
return new PageConfig(plugin, config);
} catch (IOException e) {
throw new IllegalArgumentException("为插件 " + pluginName + " 加载页面配置文件 " + filename + " 时出错!", e);
}
}
}

View File

@@ -0,0 +1,15 @@
package cn.hamster3.mc.plugin.core.bukkit.page;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PluginPage {
/**
* @return 插件名称
*/
String value();
}

View File

@@ -0,0 +1,44 @@
package cn.hamster3.mc.plugin.core.bukkit.page.handler;
import cn.hamster3.mc.plugin.core.bukkit.page.ButtonGroup;
import cn.hamster3.mc.plugin.core.bukkit.page.PageConfig;
import org.bukkit.Bukkit;
import org.bukkit.entity.HumanEntity;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* 固定页面的 GUI
*/
@SuppressWarnings("unused")
public class FixedPageHandler extends PageHandler {
public FixedPageHandler(@NotNull HumanEntity player) {
super(player);
}
public FixedPageHandler(@NotNull PageConfig config, @NotNull HumanEntity player) {
super(config, player);
}
@Override
public void initPage() {
if (inventory == null) {
inventory = Bukkit.createInventory(this, getPageConfig().getInventory().getSize(), getTitle());
}
HumanEntity player = getPlayer();
PageConfig config = getPageConfig();
ButtonGroup group = getButtonGroup();
List<String> graphic = config.getGraphic();
for (int i = 0; i < graphic.size(); i++) {
char[] chars = graphic.get(i).toCharArray();
for (int j = 0; j < chars.length; j++) {
char c = chars[j];
int index = i * 9 + j;
inventory.setItem(index, group.getButtonItem(c));
}
}
}
}

View File

@@ -0,0 +1,137 @@
package cn.hamster3.mc.plugin.core.bukkit.page.handler;
import cn.hamster3.mc.plugin.core.bukkit.page.ButtonGroup;
import cn.hamster3.mc.plugin.core.bukkit.page.PageConfig;
import cn.hamster3.mc.plugin.core.bukkit.page.PageManager;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.*;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
/**
* GUI 处理类
*/
@SuppressWarnings("unused")
public abstract class PageHandler implements InventoryHolder {
private final PageConfig pageConfig;
private final HumanEntity player;
protected Inventory inventory;
public PageHandler(@NotNull HumanEntity player) {
pageConfig = PageManager.getPageConfig(getClass());
this.player = player;
}
public PageHandler(@NotNull PageConfig pageConfig, @NotNull HumanEntity player) {
this.pageConfig = pageConfig;
this.player = player;
}
public abstract void initPage();
public void onOpen(@NotNull InventoryOpenEvent event) {
}
public void onClick(@NotNull InventoryClickEvent event) {
if (event.getSlot() == event.getRawSlot()) {
return;
}
event.setCancelled(true);
}
public void onClickInside(@NotNull InventoryClickEvent event) {
event.setCancelled(true);
}
public void onClickInside(@NotNull ClickType clickType, @NotNull InventoryAction action, int index) {
}
public void onPlayButtonSound(@NotNull ClickType clickType, @NotNull InventoryAction action, int index) {
if (!(player instanceof Player)) {
return;
}
PageConfig config = getPageConfig();
String buttonName = getButtonGroup().getButtonName(index);
Sound sound = config.getButtonSound(buttonName);
if (sound == null) {
switch (buttonName) {
case "empty":
case "barrier":
break;
default:
sound = config.getButtonSound("default");
}
}
if (sound == null) {
return;
}
((Player) player).playSound(player.getLocation(), sound, 1, 1);
}
public void onDrag(@NotNull InventoryDragEvent event) {
}
public void onDragInside(@NotNull InventoryDragEvent event) {
event.setCancelled(true);
}
public void onClose(@NotNull InventoryCloseEvent event) {
}
public void show() {
show(true);
}
public void show(boolean init) {
if (init) {
initPage();
}
Bukkit.getScheduler().runTask(pageConfig.getPlugin(), () -> player.openInventory(getInventory()));
}
public void close() {
Bukkit.getScheduler().runTask(pageConfig.getPlugin(), player::closeInventory);
}
@NotNull
public PageConfig getPageConfig() {
return pageConfig;
}
@NotNull
public HumanEntity getPlayer() {
return player;
}
@NotNull
public ButtonGroup getButtonGroup() {
return getPageConfig().getButtonGroup("default");
}
@NotNull
public String getTitle() {
String title = pageConfig.getTitle();
for (Map.Entry<String, String> entry : getPageVariables().entrySet()) {
title = title.replace(entry.getKey(), entry.getValue());
}
return title;
}
@NotNull
@Override
public Inventory getInventory() {
return inventory;
}
@NotNull
public HashMap<String, String> getPageVariables() {
return new HashMap<>();
}
}

View File

@@ -0,0 +1,225 @@
package cn.hamster3.mc.plugin.core.bukkit.page.handler;
import cn.hamster3.mc.plugin.core.bukkit.page.ButtonGroup;
import cn.hamster3.mc.plugin.core.bukkit.page.PageConfig;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 支持翻页的 GUI
*
* @param <E> 页面元素
*/
@SuppressWarnings("unused")
public abstract class PageableHandler<E> extends FixedPageHandler {
private static final ItemStack EMPTY_STACK = new ItemStack(Material.AIR);
private String previewButtonName = "preview";
private String nextButtonName = "next";
private String barrierButtonName = "barrier";
private String elementButtonName = "element";
private int page;
private HashMap<Integer, E> elementSlot;
public PageableHandler(@NotNull HumanEntity player) {
super(player);
this.page = 0;
}
public PageableHandler(@NotNull HumanEntity player, int page) {
super(player);
this.page = page;
}
public PageableHandler(@NotNull PageConfig config, @NotNull HumanEntity player, int page) {
super(config, player);
this.page = page;
}
@NotNull
public abstract List<E> getPageElements();
public abstract void onClickElement(@NotNull ClickType clickType, @NotNull InventoryAction action, @NotNull E element);
public String getElementButtonName() {
return elementButtonName;
}
@NotNull
public String getElementButtonName(@NotNull E element) {
return elementButtonName;
}
@Override
public void onClickInside(@NotNull InventoryClickEvent event) {
event.setCancelled(true);
int slot = event.getSlot();
E e = elementSlot.get(slot);
if (e != null) {
onClickElement(event.getClick(), event.getAction(), e);
return;
}
String name = getPageConfig().getButtonName(event.getCurrentItem());
if (name.equalsIgnoreCase(nextButtonName)) {
showNextPage();
return;
}
if (name.equalsIgnoreCase(previewButtonName)) {
showPreviewPage();
}
}
@Override
public void onPlayButtonSound(@NotNull ClickType clickType, @NotNull InventoryAction action, int index) {
HumanEntity player = getPlayer();
if (!(player instanceof Player)) {
return;
}
PageConfig config = getPageConfig();
String buttonName = getButtonGroup().getButtonName(index);
Sound sound = config.getButtonSound(buttonName);
if (sound == null) {
switch (buttonName) {
case "empty":
case "barrier": {
break;
}
default: {
sound = config.getButtonSound("default");
break;
}
}
}
if (buttonName.equals("element") && elementSlot.get(index) == null) {
sound = null;
}
if (sound == null) {
return;
}
((Player) player).playSound(player.getLocation(), sound, 1, 1);
}
@Override
public void initPage() {
super.initPage();
List<E> elements = getPageElements();
ButtonGroup group = getButtonGroup();
Inventory inventory = getInventory();
HumanEntity player = getPlayer();
ArrayList<Integer> buttonIndexes = group.getButtonAllIndex(elementButtonName);
int pageSize = buttonIndexes.size(); // 一页有多少个按钮
elementSlot = new HashMap<>();
HashMap<String, String> variables = getPageVariables();
for (int i = 0; i < pageSize; i++) {
// 元素在当前 page 中的索引位置
int elementIndex = page * pageSize + i;
// 按钮在 GUI 中的索引位置
int buttonIndex = buttonIndexes.get(i);
if (elementIndex >= elements.size()) {
inventory.setItem(buttonIndex, null);
continue;
}
E element = elements.get(elementIndex);
elementSlot.put(buttonIndex, element);
String buttonName = getElementButtonName(element);
ItemStack buttonItem = group.getButtonItem(buttonName);
initElementButton(buttonIndex, element, buttonItem, variables);
}
if (page == 0) {
// 如果页面已在首页则撤掉上一页按钮
inventory.setItem(group.getButtonIndex(previewButtonName), group.getButtonItem(barrierButtonName));
}
if (elements.size() <= (page + 1) * pageSize) {
// 如果页面显示超出已有元素数量则撤掉下一页按钮
inventory.setItem(group.getButtonIndex(nextButtonName), group.getButtonItem(barrierButtonName));
}
}
public void initElementButton(int index, @NotNull E element, @NotNull ItemStack stack, @NotNull Map<String, String> variables) {
ItemMeta meta = stack.getItemMeta();
if (meta == null) {
return;
}
if (meta.hasDisplayName()) {
String displayName = meta.getDisplayName();
for (Map.Entry<String, String> entry : variables.entrySet()) {
displayName = displayName.replace(entry.getKey(), entry.getValue());
}
meta.setDisplayName(displayName);
}
List<String> lore = meta.getLore();
if (lore != null) {
for (int i = 0; i < lore.size(); i++) {
String s = lore.get(i);
for (Map.Entry<String, String> entry : variables.entrySet()) {
s = s.replace(entry.getKey(), entry.getValue());
}
lore.set(i, s);
}
meta.setLore(lore);
}
stack.setItemMeta(meta);
inventory.setItem(index, stack);
}
public void showPreviewPage() {
page--;
show();
}
public void showNextPage() {
page++;
show();
}
@NotNull
public HashMap<Integer, E> getElementSlot() {
return elementSlot;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public void setPreviewButtonName(String previewButtonName) {
this.previewButtonName = previewButtonName;
}
public void setNextButtonName(String nextButtonName) {
this.nextButtonName = nextButtonName;
}
public void setBarrierButtonName(String barrierButtonName) {
this.barrierButtonName = barrierButtonName;
}
public void setElementButtonName(String elementButtonName) {
this.elementButtonName = elementButtonName;
}
}

View File

@@ -0,0 +1,120 @@
package cn.hamster3.mc.plugin.core.bukkit.page.listener;
import cn.hamster3.mc.plugin.core.bukkit.HamsterCorePlugin;
import cn.hamster3.mc.plugin.core.bukkit.page.handler.PageHandler;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.inventory.Inventory;
/**
* GUI 监听器
*/
public class PageListener implements Listener {
public static final PageListener INSTANCE = new PageListener();
private PageListener() {
}
@EventHandler
public void onInventoryOpen(InventoryOpenEvent event) {
Inventory inventory = event.getView().getTopInventory();
if (!(inventory.getHolder() instanceof PageHandler)) {
return;
}
PageHandler pageHandler = (PageHandler) inventory.getHolder();
pageHandler.onOpen(event);
}
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
Inventory inventory = event.getView().getTopInventory();
if (!(inventory.getHolder() instanceof PageHandler)) {
return;
}
PageHandler pageHandler = (PageHandler) inventory.getHolder();
try {
pageHandler.onClick(event);
} catch (Exception e) {
HamsterCorePlugin.getInstance().getLogger().warning(String.format("执行 %s 的 onClick(event) 时遇到了一个异常: ", pageHandler.getClass().getName()));
e.printStackTrace();
}
if (event.isCancelled()) {
return;
}
int index = event.getRawSlot();
if (index < 0) {
return;
}
if (index != event.getSlot()) {
return;
}
try {
pageHandler.onClickInside(event);
} catch (Exception e) {
HamsterCorePlugin.getInstance().getLogger().warning(String.format("执行 %s 的 onClickInside(event) 时遇到了一个异常: ", pageHandler.getClass().getName()));
e.printStackTrace();
}
try {
pageHandler.onClickInside(event.getClick(), event.getAction(), index);
} catch (Exception e) {
HamsterCorePlugin.getInstance().getLogger().warning(String.format(
"执行 %s 的 onClickInside(%s, %s, %d) 时遇到了一个异常: ",
pageHandler.getClass().getName(),
event.getClick().name(),
event.getAction().name(),
index
));
e.printStackTrace();
}
try {
pageHandler.onPlayButtonSound(event.getClick(), event.getAction(), index);
} catch (Exception e) {
HamsterCorePlugin.getInstance().getLogger().warning(String.format(
"执行 %s 的 onPlayButtonSound(%s, %s, %d) 时遇到了一个异常: ",
pageHandler.getClass().getName(),
event.getClick().name(),
event.getAction().name(),
index
));
}
}
@EventHandler
public void onInventoryDrag(InventoryDragEvent event) {
Inventory inventory = event.getView().getTopInventory();
if (!(inventory.getHolder() instanceof PageHandler)) {
return;
}
PageHandler pageHandler = (PageHandler) inventory.getHolder();
try {
pageHandler.onDrag(event);
} catch (Exception e) {
HamsterCorePlugin.getInstance().getLogger().warning(String.format("执行 %s 的 onDrag(event) 时遇到了一个异常: ", pageHandler.getClass().getName()));
e.printStackTrace();
}
if (event.isCancelled()) {
return;
}
int size = inventory.getSize();
for (Integer slot : event.getRawSlots()) {
if (slot < size) {
pageHandler.onDragInside(event);
break;
}
}
}
@EventHandler
public void onInventoryClose(InventoryCloseEvent event) {
Inventory inventory = event.getView().getTopInventory();
if (!(inventory.getHolder() instanceof PageHandler)) {
return;
}
PageHandler pageHandler = (PageHandler) inventory.getHolder();
pageHandler.onClose(event);
}
}

View File

@@ -0,0 +1,291 @@
package cn.hamster3.mc.plugin.core.bukkit.util;
import cn.hamster3.mc.plugin.core.bukkit.listener.CallbackListener;
import cn.hamster3.mc.plugin.core.common.data.DisplayMessage;
import com.google.gson.JsonObject;
import de.tr7zw.changeme.nbtapi.NBTContainer;
import de.tr7zw.changeme.nbtapi.NBTItem;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Entity;
import org.bukkit.entity.HumanEntity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.plugin.Plugin;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@SuppressWarnings("unused")
public final class CoreBukkitUtils {
private CoreBukkitUtils() {
}
@NotNull
public static String getMCVersion() {
return Bukkit.getBukkitVersion().split("-")[0];
}
@NotNull
public static String getNMSVersion() {
return Bukkit.getServer().getClass().getName().split("\\.")[3];
}
@SuppressWarnings("deprecation")
@NotNull
public static Package getNMSPackage() {
String nmsVersion = getNMSVersion();
return Package.getPackage("net.minecraft.server." + nmsVersion);
}
@NotNull
public static Class<?> getNMSClass(@NotNull String className) throws ClassNotFoundException {
String nmsVersion = getNMSVersion();
return Class.forName("net.minecraft.server." + nmsVersion + "." + className);
}
/**
* 获取玩家的头颅
* 在1.11以上的服务端中获取头颅材质是在服务器上运行的
* 因此建议使用异步线程调用该方法
*
* @param uuid 要获取的玩家
* @return 玩家的头颅物品
*/
@NotNull
public static ItemStack getPlayerHead(@NotNull UUID uuid) {
return getPlayerHead(Bukkit.getOfflinePlayer(uuid));
}
/**
* 获取玩家的头颅
* <p>
* 在 1.11 以上的服务端建议使用异步线程调用该方法
* <p>
* 因为这些服务端中通过网络获取头颅材质是在服务器上运行的
*
* @param offlinePlayer 要获取的玩家
* @return 玩家的头颅物品
*/
@NotNull
public static ItemStack getPlayerHead(@NotNull OfflinePlayer offlinePlayer) {
ItemStack stack;
try {
stack = new ItemStack(Material.valueOf("PLAYER_HEAD"));
} catch (IllegalArgumentException e) {
//noinspection deprecation
stack = new ItemStack(Material.valueOf("SKULL_ITEM"), 1, (short) 3);
}
SkullMeta meta = (SkullMeta) stack.getItemMeta();
if (meta != null) {
meta.setOwningPlayer(offlinePlayer);
}
stack.setItemMeta(meta);
return stack;
}
/**
* 获取玩家的头颅
* 在1.11以上的服务端中获取头颅材质是在服务器上运行的
* 因此建议使用异步线程调用该方法
*
* @param name 要获取的玩家
* @return 玩家的头颅物品
*/
@NotNull
@SuppressWarnings("deprecation")
public static ItemStack getPlayerHead(@NotNull String name) {
ItemStack stack;
try {
stack = new ItemStack(Material.valueOf("PLAYER_HEAD"));
} catch (IllegalArgumentException e) {
stack = new ItemStack(Material.valueOf("SKULL_ITEM"), 1, (short) 3);
}
SkullMeta meta = (SkullMeta) stack.getItemMeta();
if (meta != null) {
meta.setOwner(name);
stack.setItemMeta(meta);
}
return stack;
}
/**
* 判断物品是否为空
* 当对象为null时返回true
* 当物品的Material为AIR时返回true
* 当物品的数量小于1时返回true
*
* @param stack 物品
* @return 是否为空
*/
public static boolean isEmptyItemStack(@Nullable ItemStack stack) {
return stack == null || stack.getAmount() < 1 || stack.getType() == Material.AIR;
}
/**
* 判断物品是否包含某条 lore
*
* @param stack 要检测的物品
* @param string 需要包含的 lore
* @return 检测结果
*/
public static boolean containsLore(@Nullable ItemStack stack, @NotNull String string) {
if (stack == null) {
return false;
}
ItemMeta meta = stack.getItemMeta();
if (meta == null) {
return false;
}
List<String> lore = meta.getLore();
if (lore == null) {
return false;
}
for (String s : lore) {
if (s.contains(string)) {
return true;
}
}
return false;
}
/**
* 给予玩家一个物品, 当玩家背包满时
* <p>
* 将会在玩家附近生成这个物品的掉落物
*
* @param player 玩家
* @param stack 物品
*/
public static void giveItem(@NotNull HumanEntity player, @NotNull ItemStack stack) {
if (isEmptyItemStack(stack)) {
return;
}
World world = player.getWorld();
for (ItemStack dropItem : player.getInventory().addItem(stack).values()) {
world.dropItem(player.getLocation(), dropItem);
}
}
@NotNull
public static DisplayMessage getDisplayMessage(@NotNull ConfigurationSection config) {
DisplayMessage displayMessage = new DisplayMessage();
String message = config.getString("message");
if (message != null) {
displayMessage.setMessage(message);
}
String actionbar = config.getString("actionbar");
if (actionbar != null) {
displayMessage.setActionbar(actionbar);
}
String title = config.getString("title");
String subtitle = config.getString("subtitle");
if (title != null || subtitle != null) {
displayMessage.setTitle(
title,
subtitle,
config.getInt("fade-in", 10),
config.getInt("stay", 70),
config.getInt("fade-out", 20)
);
}
String sound = config.getString("sound");
if (sound != null) {
displayMessage.setSound(sound,
(float) config.getDouble("volume", 1f),
(float) config.getDouble("pitch", 1f)
);
}
return displayMessage;
}
@NotNull
public static YamlConfiguration getPluginConfig(@NotNull Plugin plugin, @NotNull String filename) {
File dataFolder = plugin.getDataFolder();
if (dataFolder.mkdirs()) {
plugin.getLogger().info("已生成插件存档文件夹...");
}
File file = new File(dataFolder, filename);
if (!file.exists()) {
try (InputStream stream = plugin.getResource(filename)) {
if (stream == null) {
throw new IllegalArgumentException("在插件 " + plugin.getName() + " 的文件内部未找到 " + filename + " !");
}
Files.copy(stream, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
throw new IllegalArgumentException("在插件 " + plugin.getName() + " 内部读取文件 " + filename + " 时发生错误!");
}
}
return YamlConfiguration.loadConfiguration(file);
}
@NotNull
public static String serializeItemStack(@NotNull ItemStack stack) {
NBTContainer container = NBTItem.convertItemtoNBT(stack);
return container.toString();
}
@NotNull
public static ItemStack deserializeItemStack(@NotNull String s) {
return NBTItem.convertNBTtoItem(new NBTContainer(s));
}
@NotNull
public static ItemStack deserializeItemStack(@NotNull String s, @NotNull ItemStack defaultValue) {
try {
return NBTItem.convertNBTtoItem(new NBTContainer(s));
} catch (Exception e) {
return defaultValue;
}
}
@NotNull
public static JsonObject serializePotionEffect(@NotNull PotionEffect effect) {
JsonObject object = new JsonObject();
object.addProperty("type", effect.getType().getName());
object.addProperty("duration", effect.getDuration());
object.addProperty("amplifier", effect.getAmplifier());
return object;
}
@NotNull
public static PotionEffect deserializePotionEffect(@NotNull JsonObject object) {
//noinspection ConstantConditions
return new PotionEffect(
PotionEffectType.getByName(object.get("type").getAsString()),
object.get("duration").getAsInt(),
object.get("amplifier").getAsInt()
);
}
@NotNull
public static CompletableFuture<String> getPlayerChat(HumanEntity player) {
return CallbackListener.CHATS.computeIfAbsent(player.getUniqueId(), o -> new CompletableFuture<>());
}
@NotNull
public static CompletableFuture<Block> getPlayerClickedBlock(HumanEntity player) {
return CallbackListener.BLOCKS.computeIfAbsent(player.getUniqueId(), o -> new CompletableFuture<>());
}
@NotNull
public static CompletableFuture<Entity> getPlayerClickedEntity(HumanEntity player) {
return CallbackListener.ENTITIES.computeIfAbsent(player.getUniqueId(), o -> new CompletableFuture<>());
}
}

View File

@@ -0,0 +1,31 @@
package cn.hamster3.mc.plugin.core.bukkit.util.serializer;
import cn.hamster3.mc.plugin.core.bukkit.util.CoreBukkitUtils;
import com.google.gson.*;
import org.bukkit.inventory.ItemStack;
import java.lang.reflect.Type;
public final class ItemStackAdapter implements JsonSerializer<ItemStack>, JsonDeserializer<ItemStack> {
public static final ItemStackAdapter INSTANCE = new ItemStackAdapter();
private ItemStackAdapter() {
}
@Override
public ItemStack deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (json.isJsonNull()) {
return null;
}
return CoreBukkitUtils.deserializeItemStack(json.getAsString());
}
@Override
public JsonElement serialize(ItemStack src, Type typeOfSrc, JsonSerializationContext context) {
if (src == null) {
return JsonNull.INSTANCE;
}
String s = CoreBukkitUtils.serializeItemStack(src);
return new JsonPrimitive(s);
}
}

View File

@@ -0,0 +1,30 @@
package cn.hamster3.mc.plugin.core.bukkit.util.serializer;
import cn.hamster3.mc.plugin.core.bukkit.util.CoreBukkitUtils;
import com.google.gson.*;
import org.bukkit.potion.PotionEffect;
import java.lang.reflect.Type;
public final class PotionEffectAdapter implements JsonSerializer<PotionEffect>, JsonDeserializer<PotionEffect> {
public static final PotionEffectAdapter INSTANCE = new PotionEffectAdapter();
private PotionEffectAdapter() {
}
@Override
public PotionEffect deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (json.isJsonNull()) {
return null;
}
return CoreBukkitUtils.deserializePotionEffect(json.getAsJsonObject());
}
@Override
public JsonElement serialize(PotionEffect src, Type typeOfSrc, JsonSerializationContext context) {
if (src == null) {
return JsonNull.INSTANCE;
}
return CoreBukkitUtils.serializePotionEffect(src);
}
}

View File

@@ -0,0 +1,79 @@
datasource:
# 数据库链接驱动地址
# 除非你知道自己在做什么,否则不建议更改该项
# 旧版服务端低于1.13请使用com.mysql.jdbc.Driver
driver: "com.mysql.cj.jdbc.Driver"
# 数据库链接填写格式:
# jdbc:mysql://{数据库地址}:{数据库端口}/{使用的库名}?参数
# 除非你知道自己在做什么,否则不建议随意更改参数
url: "jdbc:mysql://sql.hamster3.cn:3306/Test1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true"
# 如果你不需要做多端跨服,那么请使用 sqlite 作本地数据库
# driver: "org.sqlite.JDBC"
# url: "jdbc:sqlite:./plugins/HamsterCore/database.db"
# 用户名
username: "Test"
# 密码
password: "Test123.."
# 最小闲置链接数
# 推荐值1~3
minimum-idle: 0
# 最大链接数
# 推荐值不低于3
maximum-pool-size: 3
# 保持连接池可用的间隔
# 除非你的服务器数据库连接经常断开,否则不建议启用该选项
# 单位:毫秒
# 默认值为0禁用
keep-alive-time: 0
# 连接闲置回收时间
# 单位:毫秒
# 推荐值60000010分钟
idle-timeout: 600000
# 链接最长存活时间
# 单位:毫秒
max-lifetime: 1800000
# 验证连接存活的超时时间
# 单位:毫秒
validation-timeout: 5000
messages:
COMMAND_NOT_FOUND:
message: "§c未找到该指令"
COMMAND_NOT_HAS_PERMISSION:
message: "§c你没有这个权限"
COMMAND_MUST_USED_BY_PLAYER:
message: "§c这个命令只能由玩家执行"
COMMAND_DEBUG_INFO_MODE_ON:
message: "§a已开启信息查询模式"
COMMAND_DEBUG_INFO_MODE_OFF:
message: "§a已关闭信息查询模式"
COMMAND_LORE_HAND_EMPTY:
message: "§c你必须手持一个物品才能使用这个命令"
COMMAND_LORE_EMPTY_INPUT:
message: "§c你没有输入lore文本"
COMMAND_LORE_ADD_SUCCESS:
message: "§a已成功添加lore文本"
COMMAND_LORE_CLEAR_NOTHING:
message: "§c这个物品没有lore文本"
COMMAND_LORE_CLEAR_SUCCESS:
message: "§c已清理该物品的全部lore文本"
COMMAND_LORE_NAME_SUCCESS:
message: "§a已成功设置物品名称"
COMMAND_LORE_REMOVE_NOT_INPUT_NUMBER:
message: "§c请输入要删除的行号"
COMMAND_LORE_REMOVE_INPUT_NUMBER_ERROR:
message: "§c行号必须是一个大于0的整数"
COMMAND_LORE_REMOVE_INDEX_OUT_OF_RANGE:
message: "§c你的手持物品没有这么多行lore文本"
COMMAND_LORE_REMOVE_SUCCESS:
message: "§a已成功删除lore文本"
COMMAND_LORE_SET_NOT_INPUT_NUMBER:
message: "§c请输入要设置的行号"
COMMAND_LORE_SET_INPUT_NUMBER_ERROR:
message: "§c行号必须是一个大于0的整数"
COMMAND_LORE_SET_NOT_INPUT_TEXT:
message: "§c请输入要设置的lore文本"
COMMAND_LORE_SET_INDEX_OUT_OF_RANGE:
message: "§c你的手持物品没有这么多行lore文本"
COMMAND_LORE_SET_SUCCESS:
message: "§a已成功设置lore文本"

View File

@@ -0,0 +1,58 @@
title: "&c固定页面"
graphic:
- "####!####"
- "# 1 2 3 #"
- "#########"
groups:
default:
'#': "barrier"
'1': "accept"
'2': "deny"
'3': "close"
'!': "info"
sounds:
"empty": ""
"default": "UI_BUTTON_CLICK"
"accept": "ENTITY_PLAYER_LEVELUP"
"deny": "BLOCK_ANVIL_HIT"
buttons:
'barrier':
==: org.bukkit.inventory.ItemStack
type: STAINED_GLASS_PANE
damage: 4
meta:
==: ItemMeta
meta-type: UNSPECIFIC
display-name: "§c屏障"
'accept':
==: org.bukkit.inventory.ItemStack
type: ARROW
meta:
==: ItemMeta
meta-type: UNSPECIFIC
display-name: "§a同意"
'deny':
==: org.bukkit.inventory.ItemStack
type: BARRIER
meta:
==: ItemMeta
meta-type: UNSPECIFIC
display-name: "§c拒绝"
'close':
==: org.bukkit.inventory.ItemStack
type: REDSTONE
meta:
==: ItemMeta
meta-type: UNSPECIFIC
display-name: "§c关闭"
'info':
==: org.bukkit.inventory.ItemStack
type: REDSTONE
meta:
==: ItemMeta
meta-type: UNSPECIFIC
display-name: "§c页面信息展示"

View File

@@ -0,0 +1,50 @@
title: "&c分页页面"
graphic:
- "#########"
- "# #"
- "# 11111 #"
- "# 11111 #"
- "# #"
- "<#######>"
groups:
default:
'#': "barrier"
'<': "preview"
'>': "next"
'1': "element"
sounds:
"default": "UI_BUTTON_CLICK"
buttons:
'barrier':
==: org.bukkit.inventory.ItemStack
type: STAINED_GLASS_PANE
damage: 4
meta:
==: ItemMeta
meta-type: UNSPECIFIC
display-name: "§c屏障"
'preview':
==: org.bukkit.inventory.ItemStack
type: REDSTONE
meta:
==: ItemMeta
meta-type: UNSPECIFIC
display-name: "§c上一页"
'next':
==: org.bukkit.inventory.ItemStack
type: ARROW
meta:
==: ItemMeta
meta-type: UNSPECIFIC
display-name: "§a下一页"
'element':
==: org.bukkit.inventory.ItemStack
type: ARROW
meta:
==: ItemMeta
meta-type: UNSPECIFIC
display-name: "§a玩家信息"

View File

@@ -0,0 +1,32 @@
name: HamsterCore
main: cn.hamster3.mc.plugin.core.bukkit.HamsterCorePlugin
version: ${version}
api-version: 1.13
author: MiniDay
website: https://github.com/MiniDay/hamster-core
description: 仓鼠核心:叁只仓鼠的 Minecraft 插件开发通用工具包
load: STARTUP
softdepend:
- Vault
- PlayerPoints
loadbefore:
- HamsterAPI
commands:
hamster-core:
aliases: [ hcore, hc, core ]
description: 仓鼠核心调试指令
permission: hamster.core.admin
permission-message: §c你没有这个权限
lore:
description: 仓鼠核心的 lore 修改指令
permission: hamster.lore.admin
permission-message: §c你没有这个权限
permissions:
hamster.core.admin:
default: op