- 版权类型
- 原创
- 插件中文名称
- 掉落保险
- 插件英文名称
- inventory insurance
- 原帖地址
- #
- 支持的核心(服务端)
- Spigot
- Paper
- Leaves
- 其他核心
- 语言支持
- 中文(简体)
- 适配版本(Java)
- 最新版本
- 26.x
- 1.21
[MD]
# Insurance — Spigot 保险插件
Insurance 是面向 Spigot 1.21.11 的死亡保险商店。玩家使用 Vault 账户余额购买保险;死亡时插件按照保单范围选择性保护背包、装备或经验,也可以提供现金赔付或生成限时实体保险箱。
## 1. 运行要求
- Java 21
- Spigot 1.21.11
- Vault
- 一个实现 Vault Economy 的经济插件,例如 EssentialsX Economy
- SQLite 无需单独安装,驱动已经打入插件 JAR
服务器必须使用正常死亡掉落规则:
```mcfunction
/gamerule keepInventory false
```
## 2. 编译与安装
```bash
mvn clean package
```
将 `target/insurance-1.0-SNAPSHOT.jar` 放入服务器的 `plugins` 目录,并确保 Vault 和经济插件已经安装。首次启动后会生成:
```text
plugins/insurance/config.yml
plugins/insurance/insurance.db
```
修改配置后执行 `/insurance reload`。`database.file` 的变化必须重启服务器才能生效。
升级前应关闭服务器并备份整个 `plugins/insurance` 目录。不要在服务器运行时直接复制 SQLite 文件;若必须热备份,应同时处理数据库的 `-wal` 和 `-shm` 文件。
从包含“部分赔付保险”的旧版本升级时,所有仍有效的该类保单会在启动时标记为 `REMOVED`,不会退款;历史理赔金额和已经进入待付款队列的旧赔付仍会保留。
卸载时先关闭服务器,再移除插件 JAR。需要一并删除数据时才删除 `plugins/insurance`,否则重装后原保单仍会恢复。
## 3. 保险类型
| 类型 | 保护内容 | 默认主世界价格 |
|---|---|---:|
| 基础保险 | 背包 36 格及快捷栏,不含盔甲和副手 | 5000 |
| 装备保险 | 盔甲、当前主手和副手 | 3000 |
| 贵重物品保险 | 附魔、稀有材质、自定义名称、Lore、模型数据、ItemMeta/PDC 物品 | 3500 |
| 经验保险 | 保留死亡前整数等级,当前等级进度清零 | 2500 |
| 掉落回收保险 | 将未保护的物品放入本人专属实体保险箱 | 4500 |
| 高级保险 | 同时保护背包、装备和整数等级 | 9000 |
每次购买获得一份额度。普通区域死亡消耗一份,高风险区域死亡需要并消耗两份。高风险区域只有一份时不会部分消耗。
物品保险只选择一个产品,优先级为:
```text
高级保险 > 基础保险 > 装备保险 > 贵重物品保险
```
高级保险已包含经验,不会重复消耗经验险。没有高级保险时,经验险可与一个物品险同时触发。回收险只处理仍未保护的掉落;未被其他保险保护的剩余物品正常掉落。
同类保障同时存在维度专属与跨维度额度时,优先使用维度专属额度。保单默认有效 7 天,每种产品与范围默认最多持有 10 份。
## 4. 玩家使用教程
执行 `/insurance` 打开保险商店:
1. 点击一种保险产品。
2. 选择具体世界或“跨维度”。
3. 确认界面会列出基础价格、近期死亡数、倍率、新手优惠、续保优惠和最终价格。
4. 点击绿色玻璃确认购买,余额不足或处于理赔冷却时不会扣款。
主菜单下方还可查看:
- 当前保单:显示每份额度、范围、来源、实付金额和到期时间。
- 理赔记录:最多显示最近 100 次保险触发记录。
- 退保:点击具体有效额度并二次确认,返还实付金额的 80%。
- ActionBar:开启或关闭当前维度保险状态。
### 死亡与复活
死亡时插件会先保存理赔数据,再从掉落列表中移除受保护物品。复活后物品恢复到原栏位;栏位被其他插件占用时,物品会掉落在复活点,避免覆盖。
复活后聊天栏显示触发的保险、消耗额度、保护数量、经验等级、赔付金额或保险箱坐标。没有触发时会说明无适用保单、维度不匹配或高风险额度不足。
### 实体保险箱
回收险会在死亡点附近寻找有实体方块支撑的空气位置,并生成单箱或双箱:
- 只有死亡玩家本人可以打开。
- 保险箱不能被玩家破坏、爆炸、活塞或漏斗移动。
- 默认存在 30 分钟,取空后立即移除。
- 到期后箱子消失,剩余物品在原位置正常掉落并失去所有权保护。
- 区块未加载时不会强制加载,到期处理会延迟至区块再次加载。
- 找不到安全位置时不消耗回收险,物品保持正常掉落。
### 到期提醒与 ActionBar
登录时,插件会汇总 24 小时内即将到期以及离线期间已经到期的保单。永久的管理员保单不参与到期提醒。
ActionBar 采用事件驱动,只在切换世界、购买、退保、实际理赔、管理员修改、在线保单到期或玩家主动开启显示时出现一次:
```text
当前维度保险:已启用(3份/2种)
```
它只表示当前维度有可用额度,不会定时重复占用 ActionBar,也不会周期性搜索当前结构。使用 `/insurance actionbar` 可以为自己永久开关显示。
## 5. 指令与 Tab 补全
| 指令 | 用途 | 权限 |
|---|---|---|
| `/insurance` | 打开商店 | `insurance.use` |
| `/insurance status` | 查看当前保单 | `insurance.use` |
| `/insurance cancel` | 打开可退保保单 | `insurance.use` |
| `/insurance logs` | 查看理赔日志 | `insurance.logs` |
| `/insurance actionbar` | 开关状态栏 | `insurance.use` |
| `/insurance admin <玩家>` | 管理指定玩家 | `insurance.admin.view` |
| `/insurance reload` | 重载并校验配置 | `insurance.reload` |
| `/insurance help` | 显示可用帮助 | 无 |
别名 `/ins` 与 `/insurance` 相同。
所有子命令均支持 Tab 补全:补全会忽略大小写、排序、去重并按照发送者权限过滤。普通玩家看不到 `admin` 或 `reload`;`admin` 的第二个参数会补全在线玩家及保险数据库中已知的离线玩家。控制台仅补全可在控制台使用且有权限的命令。
权限默认值:
| 权限 | 默认 |
|---|---|
| `insurance.use` | 所有玩家 |
| `insurance.logs` | 所有玩家 |
| `insurance.admin.view` | OP |
| `insurance.admin.modify` | OP |
| `insurance.reload` | OP |
## 6. 管理员教程
执行 `/insurance admin <玩家>`。目标可以是在线玩家、曾经登录且记录在数据库中的离线玩家。
管理界面可以:
- 查看目标的全部有效保单并进入其理赔日志。
- 点击“添加保险”,依次选择产品、具体世界/跨维度、数量 `1/2/5`、期限 `1/7/30 天`或永久。
- 点击现有额度,选择“移除且不退款”或“移除并全额退款”。
管理员添加的额度实付金额为零、来源为 `ADMIN`,不增加玩家购买次数,不消耗新手优惠,也不会在到期时产生续保九折资格。所有添加、移除和退款都会写入管理员审计表。
`insurance.admin.view` 只能查看;添加和删除还要求 `insurance.admin.modify`。
## 7. 价格与优惠计算
默认统计最近 7 天全部死亡,无论是否触发保险。每次死亡增加 10%,最高为基础价 2 倍。前三笔成功购买半价;未理赔自然到期的产品会给下一份相同产品和范围一次九折资格。
计算顺序:
```text
最终价格 = 基础价格 × 死亡倍率 × 续保折扣 × 新手折扣
```
例如主世界基础保险价格 5000,最近死亡 2 次、仍处于前三笔、没有续保优惠:
```text
5000 × 1.2 × 0.5 = 3000
```
任何保单实际理赔后,15 分钟内不能购买新额度,但已经持有的其他额度仍然有效。
## 8. 完整默认配置
以下键名与插件内置 `config.yml` 一致;实际配置文件已为每一项提供单位、用途和可选值的中文注释:
```yaml
database:
file: insurance.db
policy:
default-duration-days: 7
max-units-per-product-scope: 10
refund-rate: 0.80
claim-cooldown-minutes: 15
pricing:
recent-death-window-days: 7
surcharge-per-death: 0.10
maximum-multiplier: 2.0
newbie-half-price-purchases: 3
renewal-discount: 0.90
worlds:
world:
BASIC: 5000
EQUIPMENT: 3000
VALUABLE: 3500
EXPERIENCE: 2500
RECOVERY: 4500
ADVANCED: 9000
world_nether:
BASIC: 7500
EQUIPMENT: 4500
VALUABLE: 5250
EXPERIENCE: 3750
RECOVERY: 6750
ADVANCED: 13500
world_the_end:
BASIC: 10000
EQUIPMENT: 6000
VALUABLE: 7000
EXPERIENCE: 5000
RECOVERY: 9000
ADVANCED: 18000
global:
BASIC: 15000
EQUIPMENT: 9000
VALUABLE: 10500
EXPERIENCE: 7500
RECOVERY: 13500
ADVANCED: 27000
valuable-items:
rare-materials:
- DIAMOND_SWORD
- DIAMOND_PICKAXE
- DIAMOND_AXE
- DIAMOND_SHOVEL
- DIAMOND_HOE
- DIAMOND_HELMET
- DIAMOND_CHESTPLATE
- DIAMOND_LEGGINGS
- DIAMOND_BOOTS
- DIAMOND_SPEAR
- NETHERITE_SWORD
- NETHERITE_PICKAXE
- NETHERITE_AXE
- NETHERITE_SHOVEL
- NETHERITE_HOE
- NETHERITE_HELMET
- NETHERITE_CHESTPLATE
- NETHERITE_LEGGINGS
- NETHERITE_BOOTS
- ELYTRA
- TOTEM_OF_UNDYING
- ENCHANTED_GOLDEN_APPLE
- NETHERITE_SPEAR
high-risk:
enabled: true
structure-padding-blocks: 16
worlds:
world:
biomes:
- DEEP_DARK
- PALE_GARDEN
structures:
- ANCIENT_CITY
- TRIAL_CHAMBERS
- MANSION
- MONUMENT
- PILLAGER_OUTPOST
- STRONGHOLD
world_nether:
biomes:
- BASALT_DELTAS
- SOUL_SAND_VALLEY
structures:
- FORTRESS
- BASTION_REMNANT
world_the_end:
biomes:
- END_HIGHLANDS
- SMALL_END_ISLANDS
structures:
- END_CITY
recovery-box:
lifetime-minutes: 30
search-radius: 5
notifications:
expiry-warning-hours: 24
actionbar-enabled-by-default: true
logs:
maximum-visible: 100
retention-days: 180
messages:
prefix: "&6[保险] &r"
no-permission: "&c你没有权限执行此操作。"
players-only: "&c该命令只能由玩家执行。"
reloaded: "&a配置已成功重载。"
reload-failed: "&c配置重载失败,请检查控制台。"
purchase-success: "&a购买成功:{type},范围:{scope},支付:{price}。"
insufficient-money: "&c余额不足,需要 {price}。"
cooldown: "&c理赔冷却中,还需等待 {minutes} 分钟才能购买。"
max-units: "&c该保险与范围已达到额度上限。"
actionbar-on: "&a保险 ActionBar 已开启。"
actionbar-off: "&e保险 ActionBar 已关闭。"
actionbar-enabled: "&a当前维度保险:已启用({units}份/{types}种)"
actionbar-disabled: "&7当前维度保险:未启用"
expiry-warning: "&e你有 {count} 份保险将在 24 小时内到期,最早:{time}。"
expired-offline: "&c你离线期间有 {count} 份保险已经到期。"
claim-success: "&a本次触发:{types};消耗 {units} 份;保护 {items} 件物品;保护等级 {level}。"
claim-none: "&e本次死亡未触发保险:{reason}。"
recovery-created: "&a保险箱位于 {world} ({x}, {y}, {z}),将在 {minutes} 分钟后解除保护。"
```
### 配置说明
- `pricing.worlds` 的键必须等于服务器实际世界名。某世界未配置时不能购买该世界专属险。
- `pricing.global` 是每种跨维度保险的独立价格,而不是倍率。
- `valuable-items.rare-materials` 使用 Bukkit 材质名;配置中的未知材质会使重载失败并保留旧配置。
- 群系和结构使用 namespaced key。结构边界只查询死亡区块附近已经加载、已经生成的数据,不会调用卡顿风险较高的最近结构搜索。
- 所有消息支持 `&` 颜色代码和花括号占位符。
### 新增自定义世界
例如服务器世界名为 `survival`:
```yaml
pricing:
worlds:
survival:
BASIC: 5000
EQUIPMENT: 3000
VALUABLE: 3500
EXPERIENCE: 2500
RECOVERY: 4500
ADVANCED: 9000
```
需要高风险配置时同时添加:
```yaml
high-risk:
worlds:
survival:
biomes: [minecraft:deep_dark]
structures: [minecraft:ancient_city]
```
## 9. 数据库与可靠性
SQLite 使用 WAL、外键和 5 秒忙等待。数据包括玩家设置、死亡计价历史、每份保单、续保资格、理赔、待恢复物品、保险箱、待处理款项和管理员审计。
Vault 退款或赔付失败时不会静默丢失:款项进入 `pending_money`,插件每分钟重试。死亡时受保物品会先写入 `pending_restores`,玩家复活或下次登录时恢复。理赔日志默认保留 180 天,计价死亡历史保留 7 天。
不要手工编辑运行中的数据库。需要迁移数据时,关闭服务器后复制整个插件数据目录。
## 10. 常见问题
### 插件启动后立即禁用
检查是否安装 Vault 和一个经济插件,并确认控制台出现 Vault Economy 服务名称。只有 Vault 本体、没有经济实现时仍然无法启动。
### GUI 中没有自己的世界
`pricing.worlds` 的世界名与实际世界文件夹名不一致。使用服务器实际名称新增完整的六种价格,然后重载。
### 余额足够却不能购买
检查是否处于理赔后的 15 分钟冷却、该产品和范围是否已达到 10 份上限,以及 Vault 经济插件是否正常。
### 高风险结构没有生效
确认 namespaced key 正确、结构已经生成,并且死亡所在区块处于加载状态。可增加 `structure-padding-blocks`,但插件不会为了识别结构强制加载新区块。
### 没有生成保险箱
死亡点搜索半径内必须存在空气方块,且下方为可支撑方块。找不到位置时物品正常掉落且不会扣回收险。
### 配置重载失败
检查 YAML 缩进、材质名、七种产品价格是否齐全及数值是否非负。失败时当前运行配置不会被替换,详细原因会写入控制台。
### ActionBar 覆盖其他插件
ActionBar 已经只在保险或世界状态变化时显示一次。玩家仍可执行 `/insurance actionbar` 将其完全关闭。
[/MD]