Skip to content

Commit 39a8cc6

Browse files
committed
feat: add new LiteralEvents
v0.1.2
1 parent 4ef53e8 commit 39a8cc6

4 files changed

Lines changed: 99 additions & 50 deletions

File tree

src/KillServer/README.md

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,28 @@
99

1010
对于下面的两种情况(实际可能还有更多适用的情况):
1111

12-
- Fabric 服务器卡死不关闭
13-
- [MCDReforged/MCDReforged#150](https://github.com/MCDReforged/MCDReforged/issues/150)
14-
- [EngineHub/WorldEdit#2459](https://github.com/EngineHub/WorldEdit/issues/2459)
15-
- `pause` 命令诱发用户Ctrl+C操作,导致 MCDR 关闭与存档恢复冲突,最终致使存档损坏
16-
- [TISUnion/PrimeBackup#85](https://github.com/TISUnion/PrimeBackup/issues/85)
12+
1. Fabric 服务器卡死不关闭
13+
- [MCDReforged/MCDReforged#150](https://github.com/MCDReforged/MCDReforged/issues/150)
14+
- [EngineHub/WorldEdit#2459](https://github.com/EngineHub/WorldEdit/issues/2459)
15+
2. `pause` 命令诱发用户Ctrl+C操作,导致 MCDR 关闭与存档恢复冲突,最终致使存档损坏
16+
- [TISUnion/PrimeBackup#85](https://github.com/TISUnion/PrimeBackup/issues/85)
1717

1818

1919
本插件提供监听服务器关闭并且在这些情况下强制关闭服务器的功能, 给小白腐竹们提供一个简单且无脑的解决方案
2020

2121
## 配置
2222

23-
本插件只有一项配置: `waiting_time`
24-
25-
这个配置是等待服务器关闭的时间, **单位为秒**, 默认为 60 秒
23+
| 配置项 | 类型 | 默认值 | 含义 | 注释 |
24+
|:--------------:|:-------:|:------:|:-------------------|:--------|
25+
| `enable` | `bool` | `True` | 是否启用插件 | 不影响事件分发 |
26+
| `waiting_time` | `float` | `60` | 等待服务器关闭的时间, 超时强制关闭 | 单位为秒 |
2627

2728
## 使用方法
2829

29-
直接安装到 MCDR 的插件文件夹下即可
30+
直接安装到 MCDR 的插件文件夹下即可, 可以从 [GitHub](https://github/xieyuen/MCDR-Plugins)
31+
[PluginCatalogue](https://mcdreforged.com/zh-CN/plugin/kill_server) 手动下载插件文件
32+
33+
你也可以用下面的 MCDR 命令安装 KillServer
3034

3135
```mcdr
3236
!!MCDR plg install kill_server
@@ -37,3 +41,41 @@
3741

3842
> 你都用 MCDR 了竟然还不知道原生 `/stop` 会让 MCDR 关闭吗?<br>
3943
> 你都用 MCDR 了竟然还用不支持运行时回档的备份模组而不是 PrimeBackup、QuickBackupM 吗?
44+
45+
## 新的事件
46+
47+
KillServer 创建了三个字面量事件 [`ServerStoppingEvent`](#serverstoppingevent),
48+
[`PluginStoppingServerEvent`](#pluginstoppingserverevent)
49+
`WorldSavedEvent`
50+
51+
```python
52+
from kill_server import ServerStoppingEvent, PluginStoppingServerEvent, WorldSavedEvent
53+
```
54+
55+
### ServerStoppingEvent
56+
57+
KillServer 创建了一个字面量事件 `ServerStoppingEvent = LiteralEvent("kill_server.server_stopping")`
58+
用以监听服务器关闭, 这个事件会在服务器关闭时 (例如 `/stop` 被调用时) 分发
59+
60+
- **事件 ID**: `kill_server.server_stopping`
61+
- **回调参数**: `PluginServerInterface`
62+
63+
### PluginStoppingServerEvent
64+
65+
KillServer 创建了一个字面量事件 `PluginStoppingServerEvent = LiteralEvent("kill_server.plugin_stopping_server")`
66+
用以监听 ***由插件或调用 MCDR 命令*** 导致的服务器关闭, 这个事件会在服务器关闭时 (例如 `!!MCDR server stop` 被调用时) 分发
67+
68+
- **事件 ID**: `kill_server.plugin_stopping_server`
69+
- **回调参数**: `PluginServerInterface`
70+
71+
### ServerStoppingEvent
72+
73+
KillServer 创建了一个字面量事件 `ServerStoppingEvent = LiteralEvent("kill_server.world_saved")`
74+
用以监听服务器是否将世界保存好, 这个事件会在服务器保存世界完成时 (例如 `/save` 被调用之后) 分发
75+
76+
- **事件 ID**: `kill_server.world_saved`
77+
- **回调参数**: `PluginServerInterface`
78+
79+
> [!TIP]
80+
> 如果你只是需要各个事件而不需要强制关闭功能的话可以把配置中的 `enable` 项设定为 `false`,
81+
> 该配置只会影响强制关闭功能而不会停止事件分发
Lines changed: 27 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,56 @@
11
import re
22
import time
3-
from typing import Any
43

54
from dowhen import when
65
from dowhen.handler import EventHandler
76
from mcdreforged import *
87

8+
from kill_server.config import Config
99

10-
class Config(Serializable):
11-
waiting_time: float = 60
12-
"""等待时间, 超时之后才强制关闭服务器, 单位为秒"""
13-
14-
def validate_attribute(self, attr_name: str, attr_value: Any, **kwargs):
15-
if attr_value <= 0:
16-
raise ValueError(f"配置项 waiting_time 必须是正值, 实际配置: {attr_value}")
17-
if attr_value <= 3:
18-
server_interface.logger.warning(f"配置项 waiting_time 单位为秒, 实际配置 {attr_value} 可能过小")
19-
20-
21-
server_interface: PluginServerInterface
10+
psi: PluginServerInterface
2211
config: Config
23-
2412
handler: EventHandler
25-
is_world_saved: bool = False
2613

14+
ServerStoppingEvent = LiteralEvent("kill_server.server_stopping")
15+
PluginStoppingServerEvent = LiteralEvent("kill_server.plugin_stopping_server")
16+
WorldSavedEvent = LiteralEvent("kill_server.world_saved")
2717

18+
19+
@event_listener(ServerStoppingEvent)
20+
@new_thread("KillServer")
2821
def force_kill_server():
2922
"""强制关闭服务器"""
23+
if not config.enable:
24+
return
25+
26+
psi.logger.info("检测到服务器关闭命令执行, 等待服务器自动关闭")
3027

31-
@new_thread("KillServer")
32-
def logic():
33-
"""开新线程运行并且保证 force_kill_server 返回 None"""
34-
server_interface.logger.info("检测到服务器关闭命令执行, 等待服务器自动关闭")
28+
time.sleep(config.waiting_time)
29+
if not psi.is_server_running():
30+
return
31+
psi.logger.info("等待服务器关闭超时, 正在强制关闭服务器")
32+
# TODO: 检查世界是否保存
33+
psi.kill()
3534

36-
time.sleep(config.waiting_time)
37-
if not server_interface.is_server_running():
38-
return
39-
server_interface.logger.info("等待服务器关闭超时, 正在强制关闭服务器")
40-
# TODO: 检查世界是否保存
41-
# if not is_world_saved:
42-
# server_interface.logger.warning("世界未完全保存, 重新等待")
43-
# goto("time.sleep(config.waiting_time)")
44-
# return
45-
server_interface.kill()
4635

47-
logic()
36+
def dispatch(event: PluginEvent):
37+
psi.dispatch_event(event, ())
4838

4939

5040
def on_load(server: PluginServerInterface, prev_module):
51-
global server_interface, config, handler
52-
server_interface = server
41+
global psi, config, handler
42+
psi = server
5343
config = server.load_config_simple(target_class=Config)
5444

5545
if prev_module is not None:
5646
prev_module.handler.remove()
5747

58-
handler = when(server.stop, "return").do(force_kill_server)
59-
60-
61-
def on_server_startup(_server: PluginServerInterface):
62-
global is_world_saved
63-
is_world_saved = False
48+
# noinspection PyTypeChecker
49+
handler = when(server.stop, "return").do(lambda: dispatch(PluginStoppingServerEvent))
6450

6551

6652
def on_info(_server: PluginServerInterface, info: Info):
53+
if re.fullmatch(r"Stopping the server", info.content):
54+
dispatch(ServerStoppingEvent)
6755
if re.fullmatch(r".*All dimensions are saved", info.content):
68-
global is_world_saved
69-
is_world_saved = True
56+
dispatch(WorldSavedEvent)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from typing import Any
2+
3+
from mcdreforged import *
4+
5+
psi = ServerInterface.psi()
6+
7+
8+
class Config(Serializable):
9+
enable: bool = True
10+
"""是否启用插件"""
11+
12+
waiting_time: float = 60
13+
"""等待时间, 超时之后才强制关闭服务器, 单位为秒"""
14+
15+
def validate_attribute(self, attr_name: str, attr_value: Any, **kwargs):
16+
if attr_name == "waiting_time":
17+
if attr_value <= 0:
18+
raise ValueError(f"配置项 waiting_time 必须是正值, 实际配置: {attr_value}")
19+
if attr_value <= 3:
20+
psi.logger.warning(f"配置项 waiting_time 单位为秒, 实际配置 {attr_value} 可能过小")

src/KillServer/mcdreforged.plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"id": "kill_server",
3-
"version": "0.1.1",
3+
"version": "0.1.2",
44
"name": "KillServer",
55
"description": {
66
"en_us": "Force to kill mc server",

0 commit comments

Comments
 (0)