中文 | English
本文档记录插件的实现结构和处理流程,面向需要维护或扩展插件的开发者。
velocity_forget_me/
├── __init__.py # MCDR 入口、配置加载、on_info 监听
├── processor.py # 事件顺序、session 和记录删除
└── utils/
├── config.py # Serializable 配置类和字段校验
├── connection.py # Velocity 连接日志解析
├── paths.py # MCDR working_directory 路径解析
└── uuid.py # PlayerDB UUID 查询
插件使用 MCDR 的 on_info 处理 mcdr.general_info:
- 只接受
info.is_from_server为真的信息。 - 将
info.content交给ConnectionEventParser。 - 正则必须提供
player、server和action三个命名捕获组。 - 解析成功后为事件分配顺序号,并交给
ConnectionProcessor.process()。
process() 使用 MCDR 的 @new_thread() 装饰器运行在 daemon thread 中。网络查询和文件操作不会阻塞 MCDR 的信息处理线程。
JoinSession 表示一个玩家在一个后端服务器上的连接 session。session key 为:
(player_name.casefold(), server_name)因此:
(Player, lobby)
(Player, survival)
是两个独立 session。一个服务器的连接或断开不会覆盖、结束或修改另一个服务器的 session。
同一个玩家再次连接同一个服务器时,会递增该 (player, server) 对应的 generation,并替换当前 session。generation 用于确认异步处理仍然针对当前 session。
Session 主要保存:
- 玩家名;
- 服务器名;
- generation;
- 连接时间;
- UUID;
- 断开时间;
- 是否已经执行过删除。
on_info() 在提交后台任务前调用 reserve() 分配递增的顺序号。每个处理线程会等待自己的顺序号成为当前序号,保证日志事件按照 MCDR 接收到的顺序处理。
连接事件只创建或替换对应 session,不立即查询 UUID,也不删除记录。
断开事件按 (player, disconnect_server) 查找 session。如果不存在对应 session,事件直接忽略。
删除流程必须同时满足:
- 存在同一玩家、同一服务器的 session;
- 断开时间不早于连接时间;
- 连接到断开的时间不超过
disconnect_window_seconds; - session 仍然是该
(player, server)对的当前 generation; - UUID 已从 session、缓存或 PlayerDB 获得;
- RememberMe 文件内容同时等于连接服务器和断开服务器。
文件路径为:
<record_directory>/<uuid>.txt
只有完成全部检查后才调用 Path.unlink()。
删除失败不会伪造成功日志。文件不存在使用 DEBUG 日志,读取或删除失败使用 ERROR 日志,服务器名不匹配使用 WARNING 日志。
当前没有独立的后台定时器清理未收到断开事件的 session:
- 收到对应断开事件且超过时间窗口时,session 被删除,但 RememberMe 文件保留;
- 收到对应断开事件且符合条件时,完成检查后删除 session;
- UUID 查询失败时,当前 session 被删除,记录保留;
- 插件卸载或重载时,
close()清理全部内存 session; - 如果始终没有收到断开事件,session 会一直保留到上述清理时机。
PluginConfig 继承 MCDR 的 Serializable。入口通过以下方式加载:
server.load_config_simple(
target_class=PluginConfig,
failure_policy='raise',
)字段默认值由 Serializable 类属性提供。validate_attribute() 在反序列化字段时校验路径、数值、正则表达式和 UUID API URL。记录目录在配置加载后,根据 MCDR 的 working_directory 解析为绝对路径;解析后的路径单独传给 processor,不修改配置对象中的原始字符串。
- 修改连接日志格式时,应优先修改配置中的
connection_regex,并保留三个命名捕获组。 - 修改 session 相关逻辑时,必须同时检查
_sessions、_generations和_is_current_session()。 - 不要把 PlayerDB 查询移回
on_info();它必须继续在@new_thread()处理器中执行。 - 删除记录前必须保留服务器名检查,避免一个服务器的断开事件删除另一个服务器的 RememberMe 记录。
- 插件只处理文件形式的 RememberMe,不应假设
VelocityRememberServer或 LuckPerms 的存储结构。
编译所有源文件:
python -m py_compile velocity_forget_me/__init__.py velocity_forget_me/processor.py velocity_forget_me/utils/__init__.py velocity_forget_me/utils/config.py velocity_forget_me/utils/connection.py velocity_forget_me/utils/paths.py velocity_forget_me/utils/uuid.py使用 MCDR 原生命令打包:
python -m mcdreforged pack