Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
.idea
.venv/
.venv-*/
.pytest_cache/
isolated-mcdr.log
rendered-*.txt
*.mcdr
*.pyz
*/__pycache__/
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@

1. 配置一个MCDR实例(包括MC服务端)并加入此插件, 将其启动

2. 依照 (配置选项)[## 配置选项] 修改主体插件配置, **特别是自动检测挂载点的配置**, 然后重载此插件(使用指令`!!mount -r`即可)
2. 依照 [配置选项](#配置选项) 修改主体插件配置, **特别是自动检测挂载点的配置**, 然后重载此插件(使用指令`!!mount --reload`即可)

3. 修改在第二步配置的`overwrite_name`文件, 建议添加服务器端口和RCON相关配置来获取一致的体验
3. 修改在第二步配置的`overwrite_path`文件, 建议添加服务器端口和RCON相关配置来获取一致的体验

4. 在第二步配置的自动检测目录中, 放入更多MC服务端实例, 然后可以游戏内输入`!!mount -l`查看并修改相关配置选项, 在修改完毕之后将`人工检查`项设置为`True`
4. 在第二步配置的自动检测目录中, 放入更多MC服务端实例, 然后可以游戏内输入`!!mount list`查看并修改相关配置选项, 在修改完毕之后将`人工检查`项设置为`True`

5. 此时重新输入`!!mount -l` 即可看到人工检查通过的服务端处于可用状态, 挂载即可
5. 此时重新输入`!!mount list` 即可看到人工检查通过的服务端处于可用状态, 挂载即可

6. 更多指令, 可在游戏内输入`!!mount`获取帮助信息

Expand Down Expand Up @@ -78,4 +78,9 @@
## 其他
- 在自动检测目录的子目录下添加名为`.mount-ignore`的文件可以使该子目录免于检测
- 通过手动修改配置文件, 可以添加任意目录的服务器作为挂载点
- 实际配置格式均需要满足json格式,即不得包含上例中以`//`开头的注释
- 实际配置格式均需要满足json格式,即不得包含上例中以`//`开头的注释
## 投票、强制操作与备份

安装版本2.0.0时按上面的格式创建配置,`servers_path` 必须是字符串数组。`!!mount switch <完整路径或token>` 创建切换投票;`reset` 创建重置投票;`vote <id> yes|no` 显式投票,`status [id]` 查看,`cancel <id>` 授权取消。含空格或尾随 ` --confirm` 的路径按完整目标解析。

`force switch <目标>` 和 `force reset` 仅授权者可用,须以 `force confirm <id>` 本人确认。独立 `backup` 仅授权者可见并直接执行,完全停服后复制及校验,再恢复原先运行的服务。详细配置、full/region范围、权限与失败处理见[操作说明](docs/operations.md)。
17 changes: 11 additions & 6 deletions README_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@

1. Deploy a MCDR instance(with MC server), and start it with this plugin

2. Edit the main config according to (Config)[## Config], then reload this plugin(by command `!!mount -r` or other command provided by MCDR)
2. Edit the main config according to [Config](#config), then reload this plugin(by command `!!mount --reload` or other command provided by MCDR)

3. Edit the file of `overwrite_name` which is configed at setp 2, Recommand to set up server port and rcon to get a consistent experience
3. Edit the file of `overwrite_path` which is configed at setp 2, Recommand to set up server port and rcon to get a consistent experience

4. Add more MC server into the `servers_path` at step 2, then you can use `!!mount -l` to see them and edit their config according to (Config)[## Config], finally make sure set `checked` to true
4. Add more MC server into the `servers_path` at step 2, then you can use `!!mount list` to see them and edit their config according to [Config](#config), finally make sure set `checked` to true

5. Type `!!mount -l` now, you can see available servers now, and then mount it
5. Type `!!mount list` now, you can see available servers now, and then mount it

6. For more command, type `!!mount` in game to get help

Expand Down Expand Up @@ -69,7 +69,7 @@
// reset method, full for reset all, region for keep up player data(e.g. Parkour record)
"reset_type": "full",
// mcdr plugin dir for this server, '' and '.' means empty
"plugin_dir": "",
"plugin_dir": "",
"stats": {
// Stats for this server, will generate automaticaly
}
Expand All @@ -78,4 +78,9 @@
## Other
- add file with name `.mount-ignore` under folder in auto-detect folder to not detect that folder
- by editing config file, you can add any server in any folder as mountable server
- the actual config file must be json format, so remove the comments starting with `//` from above config sample
- the actual config file must be json format, so remove the comments starting with `//` from above config sample
## Voting, force and backup

For version2.0.0 create configuration in the format above; `servers_path` must be an array of strings. Use `!!mount switch <full path or token>`, `reset`, `vote <id> yes|no`, `status [id]` and authorized `cancel <id>`. Paths containing spaces or a trailing ` --confirm` are resolved as complete targets.

Authorized `force switch/reset` requires personal `force confirm <id>`. Authorized `backup` executes directly, stops a running server before copying and verifying worlds, then restores its previous running state. See [operations](docs/operations.md) for configuration, full/region scope, permissions and failure handling.
119 changes: 119 additions & 0 deletions docs/operations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
## 投票与操作 / Voting and operations

切换默认 60%、重置默认 100%、60 秒超时。冻结在线分母,门槛向上取整,发起者
必须显式投票,一人一票且不能改票。加入不增员、离开不降低门槛;已经离线的玩家
不能继续投票。普通投票仅受信任玩家命令源可发起,控制台只看进度。
同实例同类投票从上次终结起冷却 60 秒;比例、超时和冷却均可配置。
无在线玩家或在线快照不可信时拒绝发起,不会自动通过。

运行中加载、重载及切服后查询 `list` 恢复完整在线集合。只支持 vanilla/bukkit
英文在线列表格式;超时、人数不匹配或其他 handler 安全拒绝投票,单次进出事件
不恢复信任。已收到但尚未处理的旧输出通过 MCDR 单调 Info.id 屏障过滤。
查询不重叠,过期/卸载前的查询必须先丢弃旧回复再重查;完全不回复时持续拒绝投票,直到新服务会话。
查询期间的进出事件合并进快照。服务器身份依赖其认证方式,离线模式同名冒用
风险必须由部署者处理;不要将普通聊天字符串作为强制名单身份来源。

## 操作配置

在 Mount 实例配置文件中设置,重载生效:

| 字段 | 默认值 / 说明 |
|---|---|
| `switch_ratio`, `reset_ratio` | `0.6`, `1.0`;范围 `(0,1]` |
| `vote_timeout`, `vote_cooldown` | `60`, `60` 秒 |
| `backup_permission`, `cancel_permission` | `3`, `3`;MCDR 0–4 等级 |
| `force_players`, `force_console` | `[]`, `false`;按认证玩家名精确匹配,名单不附带其他权限 |
| `force_timeout` | `60` 秒,所有强制操作本人确认有效期 |
| `backup_root` | `../mount-backups`;须与实例、源世界和重置模板隔离 |
| `backup_worlds` | `["world", "world_nether", "world_the_end"]`;可配置相对当前 MC 服务器目录的路径 |
| `stop_timeout`, `start_timeout` | `60`, `120` 秒 |

非法比例、权限或计时拒绝加载,修正配置后重载。

## 操作命令

`!!mount switch <完整路径>` 支持空格。`reset` 发起当前服重置投票;
`vote <id> yes|no` 投票,`status [id]` 查看,`cancel <id>` 由发起者或达到
`cancel_permission`(默认 MCDR 3 级)的管理者取消。
`list [page]` 按配置顺序分页,展示投票和授权操作入口。

授权者看到独立 `backup` 按钮,点击直接开始,无确认、无投票、不切换或重置。
服务器原在运行则完全停服后复制并尝试恢复;原已停机则保持停机。
至少一个世界存在才备份,缺失世界列入 manifest。逐文件相对路径、大小、SHA-256
及空目录校验一致后,写 manifest 并在同一文件系统内将临时目录改名提交。
不自动删除历史备份、不提供恢复命令、不备份插件数据;自行安排容量与人工恢复。
符号链接、Windows 重解析点、世界/模板/目的包含关系拒绝。
启动命令发出不等于启动完成,结果分别报告文件操作与真实启动状态。
备份结果仅向发起者及管理日志显示;掉线结果限本次运行期保存并在回服后补发。

`force switch <完整路径>`、`force reset` 默认仅名单玩家可用;控制台须启用
`force_console`且具有 MCDR 4 级权限。均需
`force confirm <id>` 本人确认。确认摘要绑定操作者、完整目标、配置与原投票 ID。
确认前原投票继续;放弃、过期或原投票变化使摘要失效。确认不等待他人同意,
也不能抢占执行中的操作。

重置仅替换模板实际提供的默认三个世界。full 替换整个世界;region 仅保留
主世界`world`内的 `playerdata`、`advancements`、`stats`,其余主世界内容以模板替换;
下界与末地整世界替换。模板缺失的世界保持原样,`backup_worlds`不改变重置范围。重置不是备份,
中途磁盘失败可能留下部分替换的世界,无自动回滚,应使用人工备份恢复。

卸载取消待投票/待确认,执行器协作收尾并恢复本次停下的服务器。
执行中重载复用旧管理器避免双执行器,完成后再次重载才加载新实例配置。
跨实例 `occupied_by` 仍为文件检查与写入,存在既有 TOCTOU 限制,不提供跨实例原子锁保证。

## English

Use `switch <full path>` (spaces supported), `reset`, `vote <id> yes|no`, `status [id]`,
`cancel <id>` and `list [page]`. Switch/reset require 60%/100% of the frozen online
electorate, rounded up; timeout and per-kind cooldown are 60 seconds. The initiator
must vote explicitly. First votes are final; arrivals are excluded, departures
do not lower the threshold, and offline players cannot cast new votes. Console
can inspect votes but cannot initiate or vote. Empty or untrusted snapshots refuse
initiation. Ratios, timeout and cooldown are configurable. Vote owners or users meeting
`cancel_permission` (default MCDR level 3) can cancel; force names grant no such management permission.

Load/reload/startup queries `list`. Only supported vanilla/bukkit English output
establishes a complete snapshot. Failure stays untrusted despite subsequent
join/leave events. Already queued old output is filtered by a monotonic Info.id
barrier.
Queries never overlap; expired/unloaded queries drain their old reply before a
new query starts. A server that never responds stays untrusted until a new session.
Authentication remains the Minecraft server's responsibility; offline mode allows
name impersonation. Force names match trusted player command sources.

The table above lists operation configuration fields.

`backup` is visible only to users meeting `backup_permission` (default 3), and
executes immediately without voting or confirmation. It stops a running server,
copies configured worlds including player data, verifies paths/sizes/SHA-256 and
empty directories, writes a manifest, and atomically renames the temporary copy.
Missing worlds are recorded; all missing is rejected. Originally stopped servers
remain stopped. File results and verified startup results are reported separately.
Backup results are private to the requester/admin log; offline delivery is kept
only in memory. No retention deletion, restore command, plugin-data or cross-instance
backup is supplied. Reject links/reparse points and overlapping source/template/destination.

`force_players` defaults to empty and `force_console` to false. Names do not grant
backup or management-cancel permission. Every `force switch/reset` requires personal
`force confirm <id>` within `force_timeout` (60 seconds). The old vote continues
until confirmation; changing/ending it invalidates the summary. Execution cannot
be preempted. Force confirmation binds owner, target, configuration and exact old vote.

Console force requires both `force_console=true` and MCDR permission level 4.

Reset considers only `world`, `world_nether`, `world_the_end` provided by the template;
missing template worlds stay unchanged. Full replaces entire selected worlds;
region preserves only `playerdata`, `advancements`, `stats` inside the main `world`,
replacing its other contents from the template. Selected Nether/End worlds
are replaced entirely. `backup_worlds` does not change reset scope. Reset disk failures can leave partially replaced worlds;
there is no automatic rollback. Keep an independent backup for manual recovery.

Unload cancels pending sessions and lets an executor finish recovery. Reload during
execution reuses that executor's manager; reload again after completion to load new
instance configuration. File-based occupied_by retains its pre-existing cross-instance
TOCTOU limitation.
## 投票展示 / Vote presentation

投票创建广播包含实际比例、赞成门槛、冻结人数、剩余时间及进出规则。重置创建广播与 status 在赞成按钮之前显示本轮预检得到的模式、世界、模板名称和 full/region 玩家数据后果;不增加投票前确认。

Vote creation broadcasts include ratio, threshold, frozen electorate, remaining time and join/leave rules. Reset broadcasts and status show the preflight scope (mode, worlds, template name and full/region player-data consequences) before Yes buttons, without adding confirmation before voting.
57 changes: 57 additions & 0 deletions lang/en_us.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,61 @@
mount:
flow:
action_switch: 'switch'
action_reset: 'reset'
action_backup: 'backup'
progress: '[Progress]'
help: 'Switch/reset start an online-player vote. Vote explicitly with the active request ID. First votes are final, and departures do not lower the threshold. Status shows progress; only the initiator or authorized managers may cancel.'
completed: 'Completed'
failed: 'Failed (error ID {error}); contact an administrator'
unknown: 'Unknown; contact an administrator'
operation_result: '{action} request {id}: {outcome}; server: {recovery}.'
cancel_force: '[Abandon force confirmation]'
force_cancelled: 'Force confirmation abandoned; the original vote is unchanged.'
yes: '[Yes]'
no: '[No]'
cancel: '[Cancel vote]'
confirm: '[Confirm force]'
switch: '[Vote switch]'
reset: '[Vote reset]'
backup: '[Backup]'
previous: '[Previous]'
next: '[Next]'
force_switch: '[Force switch]'
force_reset: '[Force reset]'
management: 'Management (force actions require personal confirmation)'
unavailable: 'Unavailable / current server'
permission: 'Permission denied.'
busy: 'An operation is pending or executing; no new operation started.'
invalid_target: 'Target unavailable, unchecked or occupied; no operation started.'
invalid_reset_path: 'Reset template or world paths are unsafe or unavailable.'
snapshot_unknown: 'Online player snapshot unavailable; no vote started.'
no_players: 'No players online; no vote started.'
not_in_roster: 'Only online players in the frozen electorate can participate.'
duplicate_vote: 'You already voted; the first vote is final.'
cooldown: 'This operation is cooling down. Try again later.'
stale: 'No matching active request; this button has expired.'
recorded: 'Vote recorded.'
vote_started: '{actor} started {action} vote: {target}. Request {id}. Ratio {ratio}%, required {required}/{total} frozen players, {seconds}s left. New arrivals excluded; departures do not lower threshold. The initiator must vote explicitly.'
current: '[Current]'
available: '[Available]'
occupied: '[Unavailable: occupied]'
unchecked: '[Unavailable: unchecked]'
missing: '[Unavailable: directory missing]'
invalid: '[Unavailable: invalid configuration]'
page_corrected: 'Invalid page; showing page 1.'
status: '{action}: {target}; initiator {actor}; request {id}. Yes {yes}/{required}, electorate {total}, No {no}, {seconds}s left. New arrivals excluded; departures do not lower threshold.'
cancelled: 'Vote {id} cancelled; no action executed.'
expired: 'Vote {id} timed out; no action executed.'
force_summary: 'Force {action}: {target}. Request {id}. Confirmation cancels exactly vote {old}; the vote continues until confirmation. Confirm within the configured timeout.'
reset_scope: 'Reset mode {mode}; worlds: {worlds}; template: {template}. Full replaces world/player data; region preserves playerdata, advancements and stats only in the main world. No chat undo.'
backup_preflight: 'Backup not started: unsafe/unavailable source or destination, or an operation is pending.'
stopping: 'Server is stopping briefly for maintenance.'
result: '{action} request {id}: {outcome}; verified backup {result}; worlds {worlds}; skipped {skipped}; server: {recovery}.'
unchanged: 'Unchanged'
started: 'Startup verified'
startup_failed: 'Startup failed or timed out; contact an administrator'
still_running: 'Original server still running; no offline operation performed'
stayed_stopped: 'Originally stopped; remains stopped'
help_msg:
welcome: "This MCDR server has multi MC server support by mount plugin, type §e!!mount§r to get help"
click_to_fill: "Click to fill {cmd}"
Expand Down
Loading
Loading