Skip to content

Latest commit

 

History

History
132 lines (90 loc) · 5.32 KB

File metadata and controls

132 lines (90 loc) · 5.32 KB

Velocity Forget Me Developer Documentation

中文 | English

This document describes the implementation for maintainers and contributors.

Layout

velocity_forget_me/
├── __init__.py              # MCDR entrypoint, config loading, on_info listener
├── processor.py             # event ordering, sessions, and record removal
└── utils/
    ├── config.py            # Serializable config and field validation
    ├── connection.py        # Velocity connection-log parsing
    ├── paths.py             # MCDR working_directory path resolution
    └── uuid.py              # PlayerDB UUID lookup

Event Entry Point

The plugin handles MCDR's mcdr.general_info event through on_info():

  1. Only info.is_from_server messages are accepted.
  2. info.content is passed to ConnectionEventParser.
  3. The configured regex must provide named player, server, and action groups.
  4. A successfully parsed event receives a sequence number and is passed to ConnectionProcessor.process().

process() is decorated with MCDR's @new_thread() and runs in a daemon thread. Network requests and file operations do not block MCDR's info-processing thread.

Session Model

JoinSession represents one player's connection session on one backend server. The session key is:

(player_name.casefold(), server_name)

Therefore these are independent sessions:

(Player, lobby)
(Player, survival)

A connection or disconnect on one server does not overwrite, end, or modify the other server's session.

When the same player connects to the same server again, the generation for that (player, server) pair is incremented and the current session is replaced. The generation is used to verify that asynchronous processing still targets the current session.

A session stores:

  • player name;
  • server name;
  • generation;
  • connection time;
  • UUID;
  • disconnect time;
  • whether removal has already been attempted.

Event Ordering

on_info() calls reserve() before submitting the background task. Each processing thread waits until its sequence number is current, preserving the order in which MCDR received the log events.

A connection event only creates or replaces the corresponding session. It does not immediately query the UUID or remove a record.

A disconnect event looks up the session using (player, disconnect_server). If there is no matching session, it is ignored.

Removal Conditions

All of the following must hold before a record can be removed:

  1. A session exists for the same player and server.
  2. The disconnect time is not earlier than the connection time.
  3. The connection-to-disconnect duration does not exceed disconnect_window_seconds.
  4. The session is still the current generation for that (player, server) pair.
  5. The UUID is available from the session, cache, or PlayerDB.
  6. The RememberMe file content equals both the connection server and disconnect server.

The record path is:

<record_directory>/<uuid>.txt

Path.unlink() is called only after all checks pass.

A failed removal is never logged as successful. A missing file uses DEBUG, read/delete errors use ERROR, and a server-name mismatch uses WARNING.

Session Lifetime

There is currently no independent timer that removes sessions which never receive a disconnect event:

  • when a matching disconnect arrives after the time window, the session is removed but the RememberMe file is retained;
  • when a matching disconnect is eligible, the checks run and the session is then removed;
  • when UUID lookup fails, the current session is removed and the record is retained;
  • unloading or reloading the plugin calls close(), which clears all in-memory sessions;
  • if no disconnect event ever arrives, the session remains until one of those cleanup points.

Configuration Architecture

PluginConfig inherits from MCDR's Serializable. The entrypoint loads it with:

server.load_config_simple(
    target_class=PluginConfig,
    failure_policy='raise',
)

Field defaults are supplied by Serializable class attributes. validate_attribute() validates the path, numeric values, regex, and UUID API URL during deserialization. After loading, the record directory is resolved against MCDR's working_directory and passed separately to the processor; the original config string is not rewritten.

Extension Notes

  • Prefer changing connection_regex in the configuration when the proxy log format changes; keep the three named capture groups.
  • Changes to session logic must consider _sessions, _generations, and _is_current_session() together.
  • Do not move PlayerDB lookup back into on_info(); it must remain inside the @new_thread() processor.
  • Keep the server-name checks before removal so one server's disconnect cannot remove another server's RememberMe record.
  • The plugin supports file-based RememberMe only; do not assume the storage structure of VelocityRememberServer or LuckPerms.

Local Checks

Compile all source files:

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

Pack with MCDR's native command:

python -m mcdreforged pack