Skip to content

这页聚焦 HNMail 和 HNCoreHNEconomyPlaceholderAPI 的关系,以及当前已经存在的对外 API。


HNMail 在整体架构里的位置

如果把 HN 系列拆层来看,HNMail 是一个 建立在 HNCore 共享能力之上的业务插件

可以这样理解:

  • HNCore:数据库、共享消息、命令注册、日志、调度等底座
  • HNEconomy:统一经济服务
  • HNMail:邮箱与奖励投递层

HNMail 最重要的价值,不是自己再造一套奖励系统,而是把:

  • 消息
  • 奖励
  • 附件
  • 离线领取
  • 模板投递
  • 群发审计

统一放进一套邮件模型里。


与 HNCore 的关系

HNMail 当前最核心的依赖有这些:

1. 共享数据库

用途:

  • 邮件主表
  • 附件表
  • 玩家设置
  • 黑名单
  • 审计
  • 玩家目录
  • 广播任务
  • 广播明细

这意味着 HNMail 天然适合多服共库,而不是单服孤立运行。

2. 共享消息总线

用途:

  • 新邮件实时提醒
  • 多服之间的提醒同步

3. 统一消息门面与 Audience 输出

HNMail 当前的消息发送,不只是简单读取 messages.yml

实际流程是:

  • 优先尝试获取 HNCore 的 MessageFacade
  • 优先尝试获取 HNCore 的 AudienceService
  • 如果可用,则优先走 HNCore 的统一渲染与发送链路
  • 如果不可用,再回退到插件本地的消息管理与基础输出

这意味着:

  • messages.yml 仍然是 HNMail 的消息来源
  • 但消息渲染、占位符上下文、发送通道,会优先走 HNCore 的统一能力
  • 对二开来说,HNMail 当前已经在消息层接入了 HNCore 的更高层门面,而不只是共享配置文件

4. 统一物品库网关 ItemLibraryGateway

/hnmail sendlibitem 当前不是直接对接某一个具体物品库插件,而是通过 HNCore 的统一物品库网关工作。

大致流程是:

  • 先根据 source:itemId 解析来源与物品 ID
  • 再通过 ItemLibraryGateway 检查来源是否可用
  • 必要时把来源别名归一化到 canonical source
  • 最后由统一网关完成实际物品解析

这意味着:

  • HNMail 不需要自己为每个外部物品库重复维护一套解析入口
  • mythic / mmneige / ni 这类别名兼容可以在网关层统一处理
  • 文档里应该把它描述为"统一物品库网关接入",而不是"HNMail 内置某几个来源"

5. GUI 与命令体系

用途:

  • 收件箱 GUI
  • 邮件详情 GUI
  • 主命令与子命令注册
  • 面向玩家 / 管理员的反馈输出

6. 输入会话框架(HNCore 2.3.0+)

HNMail 使用 HNCore 的统一输入会话框架处理玩家输入:

  • 邮件收件人输入(铁砧)
  • 邮件标题输入(铁砧)
  • 邮件内容输入(聊天)
  • 黑名单添加(铁砧)

这意味着:

  • 统一的输入体验
  • 自动超时机制
  • 更健壮的事件处理
  • 支持多种输入渠道(聊天/铁砧/告示牌)

与 HNEconomy 的关系

HNMail 本身不维护自己的金币账本。

正确分工是:

  • HNMail 负责"金币奖励以附件形式投递"
  • HNEconomy 负责"领取时真正入账"

这样可以避免绕过:

  • 正式货币定义
  • 最大余额限制
  • 账变流水
  • 统一审计

所以金币附件领取时,应始终走 HNEconomy 的正式服务层,而不是在 HNMail 里自己改数据库。


与 PlaceholderAPI 的关系

PlaceholderAPI 不影响邮箱主业务,只影响展示层。

当前版本已实现的典型占位符包括:

  • %hnmail_unread%
  • %hnmail_total%
  • %hnmail_allow_player_mail%
  • %hnmail_allow_player_mail_text%
  • %hnmail_template_count%
  • %hnmail_broadcast_job_count%
  • %hnmail_latest_broadcast_status_text%
  • %hnmail_latest_broadcast_success_rate_text%

适合接到:

  • 菜单
  • 计分板
  • TAB
  • 全息文字

如果 PlaceholderAPI 不可用,HNMail 本体仍应能正常工作。

更完整的占位符列表,建议直接看 PlaceholderAPI 占位符


当前对外 API

HNMail 2.0+ 采用了符合团队规范的多模块架构,提供了清晰的 API 边界。

模块结构

  • hnmail-api - 公共 API 模块(接口、数据模型)
  • hnmail-plugin - 插件实现模块(业务逻辑)

依赖方式

在你的插件中添加依赖:

gradle
dependencies {
    compileOnly("com.github.hnplugins:hnmail-api:2.0.0")
}

核心 API

1. 获取邮件服务

java
import com.github.hnplugins.hnmail.api.HNMailAPI;
import com.github.hnplugins.hnmail.service.IMailService;

// 获取邮件服务接口
IMailService mailService = HNMailAPI.getMailService();

2. 发送邮件

发送系统邮件

java
import com.github.hnplugins.hnmail.model.MailAttachment;
import com.github.hnplugins.hnmail.model.MailAttachmentType;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;

// 发送带附件的系统邮件
List<MailAttachment> attachments = List.of(
    new MailAttachment(
        MailAttachmentType.MONEY,
        "coins",           // 货币ID
        1000,              // 金额
        null               // 附加数据
    )
);

String mailUuid = mailService.sendAdminMail(
    sender,              // 发送者(控制台或管理员)
    targetPlayer,        // 收件人
    "每日奖励",          // 标题
    "感谢你的登录!",    // 内容
    attachments          // 附件列表
);

发送玩家邮件

java
// 玩家之间发送邮件
String mailUuid = mailService.sendPlayerMail(
    senderPlayer,        // 发送者(必须是在线玩家)
    targetPlayer,        // 收件人
    "问候",              // 标题
    "你好!"             // 内容
);

// 带附件的玩家邮件
String mailUuid = mailService.sendPlayerMail(
    senderPlayer,
    targetPlayer,
    "礼物",
    "送你一些物品",
    attachments
);

3. 查询邮件

查询收件箱

java
import com.github.hnplugins.hnmail.model.MailInboxFilter;
import com.github.hnplugins.hnmail.model.MailInboxPageSnapshot;

// 加载收件箱分页
MailInboxPageSnapshot inbox = mailService.loadInboxPage(
    playerId,
    1,                           // 页码
    MailInboxFilter.UNREAD       // 过滤器:ALL, UNREAD, HAS_ATTACHMENT
);

// 获取未读数量
int unreadCount = mailService.countUnread(playerId);

查看邮件详情

java
import com.github.hnplugins.hnmail.model.MailDetailView;

MailDetailView detail = mailService.viewMailDetail(
    player,
    mailUuid
);

4. 领取附件

java
// 领取邮件附件
int claimedCount = mailService.claimAttachments(player, mailUuid);

5. 删除邮件

java
// 删除邮件
mailService.deleteMail(player, mailUuid);

模板服务

java
import com.github.hnplugins.hnmail.service.IMailTemplateService;
import com.github.hnplugins.hnmail.model.MailTemplate;

IMailTemplateService templateService = HNMailAPI.getTemplateService();

// 解析模板附件
List<MailAttachment> attachments = templateService.resolveAttachments(
    template,
    targetPlayer,
    sender
);

广播服务

java
import com.github.hnplugins.hnmail.service.IMailBroadcastService;

IMailBroadcastService broadcastService = HNMailAPI.getBroadcastService();

// 群发模板邮件
broadcastService.sendTemplateToAll(
    sender,
    template,
    true  // 仅在线玩家
);

数据模型

所有数据模型都在 hnmail-api 模块中,可以直接使用:

java
import com.github.hnplugins.hnmail.model.*;

// 邮件消息
MailMessage message = ...;

// 邮件附件
MailAttachment attachment = new MailAttachment(
    MailAttachmentType.ITEM,  // 附件类型:ITEM, MONEY, COMMAND
    "payload",                 // 附件数据
    1,                         // 排序
    null                       // 附加数据
);

// 收件箱条目
MailInboxEntry entry = ...;

// 邮件详情视图
MailDetailView detail = ...;

API 设计原则

HNMail 2.0+ 的 API 遵循以下原则:

  1. 接口优先 - 只暴露接口,不暴露实现类
  2. 不可变数据 - 数据模型使用 record 类型,保证线程安全
  3. 清晰边界 - API 模块不包含任何实现细节
  4. 向后兼容 - 使用 default 方法保持接口兼容性

当前最实用的接入方式

对外业务模块最常用的其实是:

  • 给玩家发一封系统邮件
  • 附带物品 / 金币 / 命令附件

这非常适合:

  • 活动系统
  • 签到系统
  • 商城系统
  • 官网兑换系统
  • 后台补发工具

推荐思路

  • 外部插件负责"资格判断"
  • HNMail 负责"邮件投递"

例如:

  • HNCDK 判断玩家能不能兑换
  • HNMail 负责把奖励投进邮箱

这样职责会非常清晰。

完整示例

java
import com.github.hnplugins.hnmail.api.HNMailAPI;
import com.github.hnplugins.hnmail.service.IMailService;
import com.github.hnplugins.hnmail.model.MailAttachment;
import com.github.hnplugins.hnmail.model.MailAttachmentType;

public class RewardSystem {
    
    private final IMailService mailService;
    
    public RewardSystem() {
        this.mailService = HNMailAPI.getMailService();
    }
    
    public void sendDailyReward(OfflinePlayer player) {
        // 创建金币附件
        List<MailAttachment> attachments = List.of(
            new MailAttachment(
                MailAttachmentType.MONEY,
                "coins",
                1000,
                null
            )
        );
        
        // 发送系统邮件
        try {
            String mailUuid = mailService.sendAdminMail(
                Bukkit.getConsoleSender(),
                player,
                "每日奖励",
                "感谢你的登录!这是你的每日奖励。",
                attachments
            );
            
            getLogger().info("已发送每日奖励邮件给 " + player.getName() + ": " + mailUuid);
        } catch (Exception e) {
            getLogger().warning("发送邮件失败: " + e.getMessage());
        }
    }
    
    public void checkUnreadMail(Player player) {
        int unreadCount = mailService.countUnread(player.getUniqueId());
        if (unreadCount > 0) {
            player.sendMessage("§a你有 " + unreadCount + " 封未读邮件!");
        }
    }
}

命令附件的集成建议

命令附件很强,但也最需要规范。

推荐约束:

  • 只允许管理员创建
  • 只允许后台执行受控命令
  • 命令尽量幂等
  • 变量替换范围尽量明确

当前常见变量包括:

  • {player}
  • {server}

如果外部业务要和 HNMail 做深度联动,建议约定一套稳定的奖励命令,而不是到处临时拼命令文本。


一个实用的架构建议

如果你未来还想做 CDK、活动系统、官网后台,最优解通常是:

  • 外部插件负责"资格判断"
  • HNMail 负责"邮件投递"
  • HNEconomy 负责"金额入账"
  • PlaceholderAPI 负责"状态展示"

这样就不会让每个系统都各自实现一套发奖逻辑。


迁移指南

如果你的插件使用了旧版本的 HNMail API,需要进行以下更新:

1. 更新依赖

gradle
// 旧版本
compileOnly("com.github.hnplugins:HNMail:1.x.x")

// 新版本
compileOnly("com.github.hnplugins:hnmail-api:2.0.0")

2. 更新导入语句

java
// 旧版本
import com.github.hnplugins.hnmail.service.MailService;

// 新版本
import com.github.hnplugins.hnmail.service.IMailService;

3. 更新类型声明

java
// 旧版本
MailService mailService = HNMailAPI.getMailService();

// 新版本
IMailService mailService = HNMailAPI.getMailService();

4. 移除插件实例引用

java
// 旧版本(已移除)
HNMail plugin = HNMailAPI.getPlugin();

// 新版本(直接使用服务接口)
IMailService mailService = HNMailAPI.getMailService();

建议联动阅读

HN 系列插件文档