A mod containing powerful tools for collecting and analyzing data from players.
This mod allows owners of BDS servers managed by LeviLamina to store player data, mainly obtained from LoginPacket. The mod is largely intended for developers who face the following problems:
- by what parameter to save the record (data) of a player without an account Xbox Live;
- how to solve the problem with resetting progress for a player without an account Xbox Live;
- how to give a rank to a player who has never logged into the server;
- how to quickly find similar accounts;
- and other similar tasks.
| Hooks are the foundation of data persistence | |||
|---|---|---|---|
| Number | Event | Identifier | Priority |
| 1 | Connecting a player to the server | ServerNetworkHandler::sendLoginMessageLocal |
HookPriority::High |
| 2 | Player exit | ServerPlayer::disconnect |
HookPriority::Normal |
| 3 | Player spawn | ServerPlayer::doInitialSpawn |
HookPriority::Normal |
| 4 | Changing the logic for obtaining the UUID (identity) of a player |
LegacyMultiplayerToken::getIdentity |
HookPriority::Normal |
For hook #1, this priority was not chosen by chance: first, players with fake data must be screened out using third-party tools, then the data that has passed the check is recorded in the database, after which the punishment system determines whether a player with a punishment enters the server.
Hook #4 is used to prevent players who do not have an Xbox Live account from resetting their progress: it often happens that MsaId is reset when reinstalling or updating the game. More details in the diagram.
---
title: Saving player data in BDS (storage is the world)
---
flowchart LR
A("`**MsaId** - player identifier`")
--> B("`Key **MsaId** in a storage: *player_{uuid}*`")
--> C("`NBT object with profile data, including **ServerId** - an identifier randomly generated on the server side`")
--> D("`Key **ServerId** in a storage: *player_server_{uuid}*`")
--> E("Player data: inventory, position, capabilities, etc.")
subgraph Info["Advanced"]
F1("`This ID is **UUIDv3**`")
F2("`**UUIDv4** generated via: *Crypto::Random::generateUUID()*`")
end
A -.-> F1
C -.-> F2
When a player connects to the server, all useful data is collected from him, which he transmits to the server, including login time (in Unix format). But if the player has not yet been registered in the database, then a “temporary record” is created. These records were made to protect the database from being overfilled with unnecessary data. If a player does not spawn, but immediately leaves, then this entry is deleted.
The database is an SQLite3 file controlled by the library sqlite_orm, which simplifies access to data for system administrators and also allows solving the problem of quickly filtering players.
Class PlayerEntry |
|||
|---|---|---|---|
| Number | Field type and name | Explained name | |
| 1 | mce::UUID uuid |
Unique record identifier | |
| 2 | std::string name |
Player nickname | |
| 3 | std::optional<std::string> xuid |
Xbox Live Account ID | |
| 4 | mce::UUID minecraftUUID |
Game account ID | |
| 5 | std::string latestIpAddress |
Latest IPv4 address | |
| 6 | time_t latestJoinTime |
Recent time (in Unix format) connecting to the server | |
| 7 | time_t latestQuitTime |
Latest time (in Unix format) the logout from the server | |
| 8 | std::string latestLocaleCode |
Latest language code of the client | |
| 9 | unsigned long long latestCID |
Latest CID of the client | |
| 10 | std::string latestSkinId |
Latest identifier of the client's skin | |
| 11 | std::string latestGameVersion |
Latest version of the client | |
| 12 | std::string latestDeviceId |
Latest identifier of the client's device | |
| 13 | DeviceOS latestDeviceOS |
Latest type (Android, iOS) of the client's device | |
| 14 | std::string latestSkinId |
Latest is the client's skin ID | |
| 15 | std::string latestDeviceModel |
Latest model of the client's device | |
| 16 | std::string latestSelfSignedId |
Latest SelfSignedId of the client | |
| 17 | std::string latestPlayFabId |
Latest PlayFabId of the client | |
| 18 | std::string latestAccountPlayfabId |
Latest TitleAccountPlayfabId of the client | |
| 19 | std::optional<std::string> latestTitleId |
Latest TitleId of the client | |
Descriptions of class fields PlayerEntry |
|||
|---|---|---|---|
| Number | Description | ||
| 1 | This is the UUID (it can be any version) that PlayerDB randomly generated. The value should be used by other mods that are going to store player data | ||
| 2 | The value may change, but PlayerDB will synchronize the value anyway. Note: changing a nickname is NOT creating a new account with a new XUID! |
||
| 3 | — | ||
| 4 | The seemingly immutable part. But it can change for unverified players. The parameter may be named differently: MsaId, Identity |
||
| 5 | — | ||
| 6 | — | ||
| 7 | A value of 0 indicates that the player is currently on the server | ||
| 8 | — | ||
| 9 | — | ||
| 10 | — | ||
| 11 | — | ||
| 12 | — | ||
| 13 | — | ||
| 14 | — | ||
| 15 | — | ||
| 16 | — | ||
| 17 | — | ||
| 18 | — | ||
| 19 | — | ||
| Title | License | Link |
|---|---|---|
| sqlite_orm | GNU Affero General Public License v3.0 | https://github.com/fnc12/sqlite_orm |
| magic_enum | MIT License | https://github.com/Neargye/magic_enum |
| cppcodec | MIT License | https://github.com/tplgy/cppcodec |
Copyright © 2025 LordBombardir. All rights reserved.