- 版权类型
- 原创
- 插件中文名称
- MVIP专业级MC卡密管理
- 插件英文名称
- MVIP
- 原帖地址
- #
- 支持的核心(服务端)
- Paper
- 语言支持
- 中文(简体)
- 前置组件
- 无
- 适配版本(Java)
- 1.21
[MD]
# Svip Key
**SVIP 级卡密运营** · 游戏内兑换 · 嵌入式 Web 管理后台
> **Mvip Key**(`plugin.yml` 中插件名为 `MvipKey`)在服务端完成:卡密入库、玩家兑换、按模板执行控制台命令、写入兑换日志; 具体实现和安装方式可以观看下方视频体验
[/MD]
[MD]
---
## 目录
- [适用场景](#适用场景)
- [核心卖点](#核心卖点)
- [功能详情](#功能详情)
- [环境与兼容](#环境与兼容)
- [命令与权限](#命令与权限)
- [Web 管理后台](#web-管理后台)
- [配置项速览](#配置项速览)
- [数据与安全](#数据与安全)
- [最适合做什么](#最适合做什么)
- [联系与定制](#联系与定制)
- [附注](#附注)
---
## 适用场景
- 需要向玩家发放**可追踪的卡密**(赞助、活动、渠道礼包),兑换后自动执行预先配置的服务端命令。
- 需要**浏览器管理界面**:维护分类、批量生成卡密、吊销或删除记录、查看兑换日志与可发布数量统计。
- 希望数据落在 **SQLite**(默认)或 **MySQL**,便于备份或与现有运维习惯一致。
---
## 核心卖点
| 能力 | 说明 |
|------|------|
| **兑换闭环** | 玩家使用 `/redeem`(可配别名)提交卡密;成功则按模板逐行执行命令并记成功日志;失败原因写入日志(含无效码、命令失败等)。 |
| **控制台执行模板** | 模板按行拆分后,每行通过 `Bukkit.dispatchCommand(ConsoleSender, line)` 执行,占位符替换为当前玩家信息(见下文)。 |
| **分类 + 卡密** | 分类带默认命令模板;批量创建时可只选分类以继承模板,或直接传命令模板。卡密支持最大使用次数、过期时间、备注、所属分类等字段。 |
| **吊销与删除** | **吊销**:将状态标为 `revoked`,记录仍在库中。**批量删除**:按 ID 从库中删除记录,与吊销不同。 |
| **内嵌 Web** | Javalin 提供 `/admin/` 静态页与 `/api/*` JSON;会话登录后操作除登录外的 API。 |
| **CSV** | 管理端前端在批量生成后可**导出 CSV**(浏览器下载),便于交付渠道。 |
---
## 功能详情
### 1. 游戏内兑换(`RedeemCommand` + `RedeemService`)
- 仅**玩家**可执行;非玩家发送者会收到英文提示 `This command can only be used by players.`。
- 须具备 **`mvipkey.redeem` 或 `cardkey.redeem`** 之一,否则提示无权限中文文案。
- 无参数时发送配置项 `messages.usage`(默认含 `/redeem <卡密>` 说明)。
- 非 `mvipkey.admin` / `cardkey.admin` 时,受 `redeem.cooldown-seconds` 冷却限制(秒,0 关闭)。
- 卡密经 `security.pepper` 与规范化后的输入做 SHA-256 指纹,在库中匹配**未吊销、未用尽、未过期**的记录;成功消费一次使用后执行命令模板。
### 2. 命令模板与占位符(`RedeemService.expandTemplate`)
模板中每行一条命令,支持换行;执行前会做 `trim`,空行跳过。
| 占位符 | 替换为 |
|--------|--------|
| `{player}` 或 `<player>` | 玩家名 |
| `{uuid}` | 玩家 UUID 字符串 |
| `{world}` | 玩家当前世界名 |
**说明**:以上为代码中实际替换的占位符;未实现 PlaceholderAPI 等扩展占位符。
### 3. 执行失败与回滚
若任一行 `dispatchCommand` 返回 `false` 或抛出异常,实现会尝试 **`revertLastConsume`** 回滚本次扣次,并写入失败日志(如 `command_failed: …`)。成功则写入成功日志及已执行命令快照(多行拼接)。
### 4. HTTP API(`AdminServer` 注册路由)
除登录外,`/api/*` 需在会话中已登录(与 `http.auth.username` 一致)。
| 方法 | 路径 | 作用 |
|------|------|------|
| POST | `/api/auth/login` | 用户名密码登录(明文密码与配置常量时间比较,或 bcrypt 校验 `password-hash`) |
| POST | `/api/auth/logout` | 注销会话 |
| GET | `/api/auth/me` | 当前登录用户 |
| GET | `/api/health` | 返回 `status: ok`;与其它 `/api/*` 相同,**需已登录会话**(仅 `login` / `logout` 匿名) |
| GET | `/api/categories` | 列出分类 |
| POST | `/api/categories` | 创建分类(名称 + 默认模板必填) |
| PATCH | `/api/categories/{id}` | 更新分类 |
| DELETE | `/api/categories/{id}` | 删除分类(若该分类下仍有卡密则返回冲突,不删除) |
| GET | `/api/stats/publish` | 可发布卡密统计(总数、按分类等) |
| POST | `/api/keys/batch` | 批量创建卡密(单次 `count` 上限 **500**;须自带 `commandTemplate` 或有效 `categoryId`) |
| GET | `/api/keys` | 分页列表;查询参数含 `page`、`limit`、`status`、`uncategorized`、`categoryId` |
| PATCH | `/api/keys/{id}/plain-code` | 为无明码记录补录明码(校验与 `code_hash` 一致) |
| PATCH | `/api/keys/{id}/revoke` | 单条吊销 |
| POST | `/api/keys/revoke-batch` | 批量吊销(body 中 `ids` 列表,上限 500) |
| POST | `/api/keys/delete-batch` | 批量删除(同上) |
| GET | `/api/logs` | 分页兑换日志(`page`、`limit`) |
根路径 `/` **302** 到 `/admin/`;静态资源与 SPA 入口在 `/admin/`。
### 5. 首次启动与自动生成(`CardKeyPlugin.persistSecureDefaultsIfNeeded`)
- `security.pepper` 为空、仅空白或为 shipped 占位串时,会生成 **Base64URL** 随机串并写回配置。
- `http.auth.username` 为空时写入默认 `admin`。
- 当未配置明文 `http.auth.password` 且 `http.auth.password-hash` 也不是合法 bcrypt 时,生成 **16 位**随机明文密码写入配置,并在**控制台打印一次**用户名与密码。
### 6. HTTP 服务未启动的常见条件(`AdminServer.start`)
- `http.enabled` 为 `false`:直接不启动。
- `http.auth.username` 为空:跳过启动并打日志警告。
- 明文密码未配置且 `password-hash` 也不是可识别的 bcrypt:跳过启动并打日志警告。
(数据库初始化失败时整插件会禁用,与上列独立。)
---
## 环境与兼容
| 项目 | 值 |
|------|-----|
| `api-version` | `1.21` |
| Folia | `folia-supported: false`(不支持) |
| 服务端类型 | Bukkit API(Paper / Spigot 等常见分支以你实测为准) |
| 数据库 | `sqlite` 或 `mysql`(`config.yml`) |
---
## 命令与权限
**命令**(`plugin.yml`)
| 命令 | 说明 |
|------|------|
| `/redeem <卡密>` | 使用卡密;卡密可含空格(实现为拼接所有参数) |
别名:`config.yml` 中 `redeem.command-aliases` 列表,在启用时注册到同一命令。
**权限**
| 节点 | 默认 | 说明 |
|------|------|------|
| `mvipkey.redeem` | true | 允许兑换 |
| `mvipkey.admin` | op | 跳过冷却 |
| `cardkey.redeem` | false | 与 `mvipkey.redeem` 等效(二选一即可兑换) |
| `cardkey.admin` | false | 与 `mvipkey.admin` 等效 |
---
## Web 管理后台
- 浏览器访问:`http://<http.host>:<http.port>/admin/`(默认 `127.0.0.1:8123`,见 `config.yml`)。
- 前端模块与路由对应:**概览**、**卡密**、**分类**、**兑换日志**;批量生成成功后会提示保存明码或 **导出 CSV**。
- 远程访问建议反代 + HTTPS 或 SSH 隧道;勿将弱密码与明文管理口长期暴露公网。
---
## 配置项速览
配置位于服务端 `plugins/MvipKey/config.yml`(首次运行由 jar 释放默认值)。
| 区块 | 作用 |
|------|------|
| `database` | `type`、`sqlite-file` 或 `mysql.*` |
| `security.pepper` | 卡密指纹盐渍;勿泄露 |
| `generation` | `code-length`、`charset` |
| `http` | `enabled`、`host`、`port`、`auth.username` / `password` / `password-hash` |
| `redeem` | `command-aliases`、`cooldown-seconds`、`case-insensitive` |
| `messages` | 用法、成功、无效、冷却、错误等玩家提示文案 |
更完整的键说明见仓库内 `src/main/resources/config.yml` 注释。
---
## 数据与安全
- 库中存卡密 **哈希**;**明文**依赖生成时写入及可选 `plain_code` 字段(补录接口会校验与哈希一致)。
- **修改 `security.pepper`** 会使已有卡密指纹全部失效,需重新发卡。
- **分类删除**:仅当该分类下 **卡密数量为 0** 时才可删除(否则 API 返回冲突)。
- 备份 `config.yml` 与数据库文件或 MySQL 库;限制能读取配置的操作系统用户。
---
## 最适合做什么
- **赞助 / 礼包 / 活动码** 的标准化发放与兑换。
- 需要**日志对账**与**浏览器运营**、减少纯人工私聊发奖。
- 用**控制台命令**串联你服已有插件(经济、权限等),由卡密触发,无需本插件内置各插件 SDK。
---
## 联系与定制
- **作者**:Meiji622(明志)
- **定制 / 维护 / BUG上报**:QQ **2734253564**
---
## 附注
- 该插件仅供娱乐交流,不对任何商业行为的后果负责,该插件为免费开发 不支持转卖倒卖
- 我不支持任何形式的搬运,该插件目前只登录MINEBBS 且未发布源码
[/MD]