NightCore-API开发指南

作者:XiaoLin 发布时间: 2025-09-18 阅读量:12 评论数:0

🌙 NightCore-API 开发指南

📖 项目概述

NightCore 是一个轻量级的 Spigot/Paper 插件开发框架,为 Java 21+ 环境设计,提供完整的工具集来简化插件开发流程。

✨ 核心特性

  • 🚀 现代化架构:基于 Java 21,支持 Spigot/Paper 1.20+

  • 🔧 完整工具集:UI 系统、命令框架、配置管理、数据库支持

  • 🏗️ 多模块架构:Manager 系统支持复杂插件开发

  • 🌐 国际化支持:内置多语言系统

  • 📦 模块化设计:按需使用各个功能模块

  • 生命周期管理:自动化的资源管理和清理

项目架构

nightcore/
├── main/          # 主模块 - 核心功能集成
├── bridge/        # 桥接模块 - 平台兼容性
├── utils/         # 工具模块 - 实用工具类
├── spigot/        # Spigot专用功能
└── paper/         # Paper专用功能

🚀 快速开始

1. 项目依赖配置

Maven 配置

<repositories>
    <repository>
        <id>nightexpress</id>
        <url>https://repo.nightexpressdev.com/releases</url>
    </repository>
</repositories>

<dependencies>
    <dependency>
        <groupId>su.nightexpress.nightcore</groupId>
        <artifactId>nightcore</artifactId>
        <version>2.7.16</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

系统要求

  • Java 21 或更高版本

  • Spigot/Paper 1.20+

  • NightCore 插件 安装在服务器上

2. 创建插件主类

package com.yourname.yourplugin;

import org.jetbrains.annotations.NotNull;
import su.nightexpress.nightcore.NightPlugin;
import su.nightexpress.nightcore.config.PluginDetails;

public class YourPlugin extends NightPlugin {

    @Override
    @NotNull
    protected PluginDetails getDefaultDetails() {
        return PluginDetails.create("YourPlugin", new String[]{"yourplugin", "yp"})
            .setConfigClass(YourConfig.class)
            .setPermissionsClass(YourPerms.class);
    }

    @Override
    public void enable() {
        // 插件启用逻辑
        this.info("YourPlugin 已启用!");
    }

    @Override
    public void disable() {
        // 插件禁用逻辑
        this.info("YourPlugin 已禁用!");
    }
}

3. plugin.yml 配置

name: YourPlugin
main: com.yourname.yourplugin.YourPlugin
version: '1.0.0'
api-version: 1.20
depend: [nightcore]
author: YourName
description: 基于NightCore开发的插件

🔧 核心功能

📋 配置管理系统

创建配置类

public class YourConfig {

    @ConfigValue(path = "Settings.Debug_Mode")
    public static boolean DEBUG_MODE = false;

    @ConfigValue(path = "Settings.Max_Players")
    public static int MAX_PLAYERS = 100;

    @ConfigValue(path = "Messages.Welcome")
    public static String WELCOME_MESSAGE = "欢迎来到服务器!";
}

使用配置

// 读取配置
boolean debug = YourConfig.DEBUG_MODE;
int maxPlayers = YourConfig.MAX_PLAYERS;

// 保存配置更改
this.getConfig().saveChanges();

🎯 命令系统

import su.nightexpress.nightcore.command.experimental.builder.DirectNodeBuilder;

public class YourCommands {

    public static void register(YourPlugin plugin) {
        DirectNodeBuilder.create(plugin, "yourcommand")
            .description("你的插件主命令")
            .permission("yourplugin.command")
            .executes((context, arguments) -> {
                context.getSender().sendMessage("Hello from YourPlugin!");
            })
            .then("reload")
                .description("重载插件")
                .permission("yourplugin.admin")
                .executes((context, arguments) -> {
                    plugin.reload();
                    context.getSender().sendMessage("插件已重载!");
                });
    }
}

🎨 GUI 菜单系统

import su.nightexpress.nightcore.menu.impl.AbstractMenu;
import su.nightexpress.nightcore.menu.MenuSize;

public class YourMenu extends AbstractMenu<YourPlugin> {

    public YourMenu(YourPlugin plugin) {
        super(plugin, "你的菜单", MenuSize.CHEST_54);
    }

    @Override
    public void onPrepare(@NotNull MenuViewer viewer, @NotNull MenuOptions options) {
        // 设置菜单项
        this.addItem(Material.DIAMOND, 22)
            .setDisplayName("§b钻石道具")
            .setLore("§7点击获取奖励")
            .setClickHandler((viewer1, event) -> {
                Player player = viewer1.getPlayer();
                player.getInventory().addItem(new ItemStack(Material.DIAMOND));
                player.sendMessage("§a你获得了一颗钻石!");
                return ClickResult.CLOSE;
            });
    }

    @Override
    public void onReady(@NotNull MenuViewer viewer, @NotNull Inventory inventory) {
        // 菜单准备完成
    }
}

🌐 国际化支持

定义语言文件

public class YourLang {

    public static final LangElement WELCOME_MESSAGE = LangElement.of("welcome_message",
        "§a欢迎 %player% 来到服务器!");

    public static final LangElement INSUFFICIENT_PERMISSION = LangElement.of("no_permission",
        "§c你没有权限执行此命令!");
}

使用多语言消息

// 发送本地化消息
YourLang.WELCOME_MESSAGE
    .replace("%player%", player.getName())
    .send(player);

🏗️ 多模块插件架构

Manager 系统层次结构

SimpleManager<P>              // 基础管理器
    ↓
AbstractManager<P>            // 完整功能管理器
    ↓
AbstractDataManager<P>        // 数据管理器
AbstractUserManager<P, U>     // 用户数据管理器

基础 Manager 实现

import su.nightexpress.nightcore.manager.AbstractManager;

public class AdvancedManager extends AbstractManager<YourPlugin> {

    private SomeListener listener;

    public AdvancedManager(@NotNull YourPlugin plugin) {
        super(plugin);
    }

    @Override
    protected void onLoad() {
        // 1. 注册监听器
        this.listener = new SomeListener(this.plugin);
        this.addListener(this.listener);

        // 2. 添加定时任务
        this.addTask(() -> {
            // 每秒执行一次的任务
        }, 20L);

        // 3. 添加异步任务
        this.addAsyncTask(() -> {
            // 异步处理重任务
        }, 200L);
    }

    @Override
    protected void onShutdown() {
        // AbstractManager会自动清理监听器、菜单和任务
    }
}

多模块插件示例

public class MultiModulePlugin extends NightPlugin {

    private EconomyManager economyManager;
    private ShopManager shopManager;
    private DatabaseManager databaseManager;

    @Override
    public void enable() {
        // 按依赖顺序启动模块
        this.databaseManager = new DatabaseManager(this);
        this.databaseManager.setup();

        this.economyManager = new EconomyManager(this);
        this.economyManager.setup();

        this.shopManager = new ShopManager(this);
        this.shopManager.setup();

        // 后加载任务
        this.onPostLoad(() -> {
            this.performCrossModuleInitialization();
        });
    }

    @Override
    public void disable() {
        // 按相反顺序关闭模块
        if (this.shopManager != null) this.shopManager.shutdown();
        if (this.economyManager != null) this.economyManager.shutdown();
        if (this.databaseManager != null) this.databaseManager.shutdown();
    }

    private void performCrossModuleInitialization() {
        // 模块间的交互初始化
        this.shopManager.setEconomyProvider(this.economyManager);
    }
}

🎯 事件处理系统

事件监听器基类

AbstractListener 实现

import su.nightexpress.nightcore.manager.AbstractListener;

public class YourListener extends AbstractListener<YourPlugin> {

    public YourListener(@NotNull YourPlugin plugin) {
        super(plugin);
    }

    @EventHandler(priority = EventPriority.NORMAL)
    public void onPlayerJoin(PlayerJoinEvent event) {
        Player player = event.getPlayer();
        this.plugin.info("玩家 " + player.getName() + " 加入了服务器");
    }
}

在 Manager 中使用事件监听器

public class EventManager extends AbstractManager<YourPlugin> {

    @Override
    protected void onLoad() {
        // 自动管理事件监听器
        this.addListener(new YourListener(this.plugin));
        this.addListener(new CustomListener(this.plugin));
    }
}

🔐 权限控制系统

UniPermission 权限定义

import su.nightexpress.nightcore.util.wrapper.UniPermission;

public class MyPluginPerms {

    // 基础权限定义
    public static final UniPermission ADMIN = new UniPermission("myplugin.admin");

    // 带描述的权限
    public static final UniPermission RELOAD = new UniPermission("myplugin.reload", "重载插件配置");

    // 自定义默认值的权限
    public static final UniPermission USER_BASIC = new UniPermission("myplugin.user",
        "基础用户权限", PermissionDefault.TRUE);
}

权限校验方法

基础权限检查

public class PermissionCheck {

    public boolean checkPlayerPermission(Player player, String permission) {
        if (!player.hasPermission(permission)) {
            player.sendMessage("§c你没有权限执行此操作!");
            return false;
        }
        return true;
    }

    public boolean opOrPermission(Player player, String permission) {
        // OP或特定权限二选一
        if (!player.isOp() && !player.hasPermission(permission)) {
            player.sendMessage("§c需要管理员权限或权限: " + permission);
            return false;
        }
        return true;
    }
}

权限组校验

import su.nightexpress.nightcore.util.Players;

public boolean checkPrimaryGroup(Player player, String requiredGroup) {
    String primaryGroup = Players.getPrimaryGroup(player);
    if (primaryGroup == null || !primaryGroup.equalsIgnoreCase(requiredGroup)) {
        player.sendMessage("§c需要权限组: " + requiredGroup);
        return false;
    }
    return true;
}

public boolean checkInAnyGroup(Player player, String... allowedGroups) {
    Set<String> playerGroups = Players.getInheritanceGroups(player);
    for (String allowedGroup : allowedGroups) {
        if (playerGroups.contains(allowedGroup.toLowerCase())) {
            return true;
        }
    }
    return false;
}

📨 消息发送系统

基础消息发送

使用插件前缀

public class MessageSending {

    private final MyPlugin plugin;

    public void sendPrefixedMessages(CommandSender sender) {
        String prefix = plugin.getPrefix();
        sender.sendMessage(prefix + "§a这是带前缀的消息");
    }

    public void sendSuccessMessage(CommandSender sender, String message) {
        String prefix = plugin.getPrefix();
        sender.sendMessage(prefix + "§a" + message);
    }

    public void sendErrorMessage(CommandSender sender, String message) {
        String prefix = plugin.getPrefix();
        sender.sendMessage(prefix + "§c" + message);
    }
}

国际化消息发送

public class InternationalMessageSending {

    public void sendLocalizedMessages(Player player) {
        // 发送带占位符的消息
        MyPluginLang.WELCOME_MESSAGE
            .replace("%player%", player.getName())
            .send(player);

        // 自动带前缀的消息
        MyPluginLang.COMMAND_SUCCESS.send(player);
    }
}

现代化消息组件

import su.nightexpress.nightcore.util.text.night.NightMessage;

public void sendInteractiveMessages(Player player) {
    // 点击消息
    NightMessage.create("§a点击这里传送到出生点")
        .clickEvent(ClickEventType.RUN_COMMAND, "/spawn")
        .hoverEvent(HoverEventType.SHOW_TEXT, "§7点击执行 /spawn 命令")
        .send(player);

    // 多功能消息
    NightMessage.create("§7选择操作: ")
        .append("§a[传送]")
        .clickEvent(ClickEventType.RUN_COMMAND, "/spawn")
        .hoverEvent(HoverEventType.SHOW_TEXT, "§7传送到出生点")
        .append(" ")
        .append("§c[商店]")
        .clickEvent(ClickEventType.RUN_COMMAND, "/shop")
        .hoverEvent(HoverEventType.SHOW_TEXT, "§7打开商店")
        .send(player);
}

特殊消息类型

// ActionBar消息
player.sendActionBar("§a血量: " + player.getHealth() + "/20");

// Title消息
player.sendTitle(
    "§a欢迎!",           // 主标题
    "§7享受游戏时光",      // 副标题
    10, 70, 20           // 淡入、显示、淡出时间
);

// 广播消息
Bukkit.broadcastMessage("§e[系统公告] 服务器将在5分钟后重启!");
Bukkit.broadcast("§a[VIP消息] VIP专属活动开始了!", "server.vip");

📱 全息消息系统

基础全息文本实现

import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.EntityType;
import su.nightexpress.nightcore.util.EntityUtil;

public class HologramManager extends AbstractManager<YourPlugin> {

    private final Map<String, List<ArmorStand>> holograms = new HashMap<>();

    public void createHologram(@NotNull String id, @NotNull Location location, @NotNull List<String> lines) {
        this.removeHologram(id); // 移除已存在的

        List<ArmorStand> stands = new ArrayList<>();
        double yOffset = 0.0;

        for (int i = lines.size() - 1; i >= 0; i--) {
            String line = lines.get(i);
            Location standLocation = location.clone().add(0, yOffset, 0);

            ArmorStand stand = (ArmorStand) location.getWorld().spawnEntity(standLocation, EntityType.ARMOR_STAND);

            // 配置ArmorStand
            stand.setVisible(false);
            stand.setCustomNameVisible(true);
            stand.setGravity(false);
            stand.setInvulnerable(true);
            stand.setMarker(true);

            EntityUtil.setCustomName(stand, line);
            stands.add(stand);
            yOffset += 0.25;
        }

        this.holograms.put(id, stands);
    }

    public void updateHologram(@NotNull String id, @NotNull List<String> newLines) {
        List<ArmorStand> stands = this.holograms.get(id);
        if (stands == null) return;

        for (int i = 0; i < Math.min(stands.size(), newLines.size()); i++) {
            ArmorStand stand = stands.get(i);
            String newLine = newLines.get(newLines.size() - 1 - i);
            EntityUtil.setCustomName(stand, newLine);
        }
    }

    public void removeHologram(@NotNull String id) {
        List<ArmorStand> stands = this.holograms.remove(id);
        if (stands != null) {
            stands.forEach(ArmorStand::remove);
        }
    }

    @Override
    protected void onShutdown() {
        this.holograms.values().forEach(stands ->
            stands.forEach(ArmorStand::remove));
        this.holograms.clear();
    }
}

实用全息文本示例

public class HologramExamples {

    public static void createWelcomeHologram(HologramManager manager, Location location) {
        List<String> welcomeLines = List.of(
            "§e§l=== 欢迎来到服务器 ===",
            "§7当前在线: §a" + Bukkit.getOnlinePlayers().size(),
            "§7输入 §e/help §7获取帮助",
            "§b祝你游戏愉快!"
        );
        manager.createHologram("spawn_welcome", location, welcomeLines);
    }

    public static void createShopHologram(HologramManager manager, Location location, String shopName) {
        List<String> shopLines = List.of(
            "§6§l🏪 " + shopName,
            "§7━━━━━━━━━━━━━━━━",
            "§f• 武器装备",
            "§f• 食物药水",
            "§f• 建筑材料",
            "§7━━━━━━━━━━━━━━━━",
            "§e点击商店NPC进行购买"
        );
        manager.createHologram("shop_" + shopName.toLowerCase(), location, shopLines);
    }
}

🛠️ 实用工具类

字符串和数字处理

import su.nightexpress.nightcore.util.Strings;
import su.nightexpress.nightcore.util.Numbers;

// 颜色代码转换
String colored = Strings.color("&a这是绿色文本");

// 格式化数字
String formatted = Numbers.format(1234567); // "1,234,567"

// 时间格式化
String timeStr = TimeUtil.formatTime(System.currentTimeMillis());

物品处理

import su.nightexpress.nightcore.util.bukkit.NightItem;

// 创建物品
ItemStack item = NightItem.builder(Material.DIAMOND_SWORD)
    .setDisplayName("§b传奇之剑")
    .setLore("§7一把强大的武器")
    .addEnchantment(Enchantment.SHARPNESS, 5)
    .build();

声音播放

import su.nightexpress.nightcore.util.bukkit.NightSound;

// 播放声音
NightSound.of(Sound.ENTITY_PLAYER_LEVELUP, 1.0f, 1.0f).play(player);

📝 开发最佳实践

项目结构建议

src/main/java/com/yourname/yourplugin/
├── YourPlugin.java              # 主插件类
├── config/
│   ├── YourConfig.java         # 配置类
│   └── YourLang.java           # 语言类
├── command/
│   └── YourCommands.java       # 命令类
├── menu/
│   └── YourMenu.java           # 菜单类
├── listener/
│   └── YourListener.java       # 事件监听器
└── manager/
    └── YourManager.java        # 管理器类

生命周期管理

@Override
public void enable() {
    // 1. 加载管理器
    this.yourManager = new YourManager(this);
    this.yourManager.setup();

    // 2. 注册命令
    YourCommands.register(this);

    // 3. 后加载任务
    this.onPostLoad(() -> {
        this.info("插件后加载完成!");
    });
}

@Override
public void disable() {
    if (this.yourManager != null) {
        this.yourManager.shutdown();
    }
}

权限管理

public class YourPerms {
    public static final UniPermission ADMIN = new UniPermission("yourplugin.admin");
    public static final UniPermission USE = new UniPermission("yourplugin.use");
    public static final UniPermission RELOAD = new UniPermission("yourplugin.reload");
}

📋 快速参考

常用类导入

// 核心类
import su.nightexpress.nightcore.NightPlugin;
import su.nightexpress.nightcore.config.FileConfig;
import su.nightexpress.nightcore.config.PluginDetails;

// 菜单系统
import su.nightexpress.nightcore.menu.impl.AbstractMenu;
import su.nightexpress.nightcore.menu.MenuSize;

// 命令系统
import su.nightexpress.nightcore.command.experimental.builder.DirectNodeBuilder;

// 工具类
import su.nightexpress.nightcore.util.Strings;
import su.nightexpress.nightcore.util.Numbers;
import su.nightexpress.nightcore.util.Players;

常用方法速查

// 插件基础
this.info("消息");                    // 输出信息
this.warn("警告");                    // 输出警告
this.error("错误");                   // 输出错误

// 配置操作
this.getConfig().saveChanges();       // 保存配置
this.reload();                        // 重载插件

// 任务调度
this.runTask(() -> {});               // 同步任务
this.runTaskAsync(() -> {});          // 异步任务
this.runTaskLater(() -> {}, 20L);     // 延迟任务

// 消息发送
player.sendMessage(prefix + "消息");   // 带前缀消息
YourLang.MESSAGE.send(player);        // 国际化消息

💡 开发提示

  1. 遵循 NightCore 生命周期 - 使用 enable()/disable() 方法

  2. 利用工具类 - 避免重复造轮子

  3. 模块化设计 - 将功能分解为独立的管理器

  4. 配置外部化 - 可配置项放在配置文件中

  5. 权限检查 - 为所有功能添加适当的权限检查

  6. 错误处理 - 使用 try-catch 处理异常

  7. 资源管理 - 使用 AbstractManager 自动管理资源

  8. 性能意识 - 长时间操作使用异步任务


// 使用内置序列化工具
public class PlayerData {

    @NotNull
    public String toJson() {
        return GsonUtil.toJson(this);
    }

    @NotNull
    public static PlayerData fromJson(@NotNull String json) {
        return GsonUtil.fromJson(json, PlayerData.class);
    }
}

🐛 调试和测试

调试模式

// 在配置中启用调试
if (YourConfig.DEBUG_MODE) {
    this.debug("这是调试信息: " + data);
}

性能监控

// 测量执行时间
long start = System.currentTimeMillis();
// 你的代码
long took = System.currentTimeMillis() - start;
this.info("操作耗时: " + took + "ms");

📚 参考资源

官方文档

示例插件

基于 NightCore 的成功插件案例:

  • ExcellentCrates - 箱子系统

  • ExcellentShop - 商店系统

  • CoinsEngine - 货币系统

依赖管理

<!-- Maven仓库 -->
<repository>
    <id>spigot-repo</id>
    <url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<repository>
    <id>papermc</id>
    <url>https://repo.papermc.io/repository/maven-public/</url>
</repository>

评论