Remove Player Data Storage From Dedicated Server Mod

It was very complicated and because it lacked proper authentication and inventory saving, it was basically useless.
This commit is contained in:
TheBrokenRail 2020-12-15 14:17:04 -05:00
parent 46cb46d6a1
commit f1c95b433d
6 changed files with 2 additions and 306 deletions

View File

@ -52,7 +52,7 @@ To use, install the ``minecraft-pi-server`` package and run ``minecraft-pi-serve
This is also compatible with MCPE 0.6.1.
### Limitations
- Player inventories are not saved because of limitations with MCPE LAN worlds
- Player data is not saved because of limitations with MCPE LAN worlds
- An easy workaround is to place your inventory in a chest before logging off
- Survival mode servers are only compatible with ``minecraft-pi-docker`` clients

View File

@ -28,7 +28,7 @@ target_link_libraries(core dl)
add_library(feature SHARED src/feature/feature.c)
add_library(server SHARED src/server/server.cpp src/server/server_properties.cpp src/server/playerdata.cpp)
add_library(server SHARED src/server/server.cpp src/server/server_properties.cpp)
target_link_libraries(server core feature dl SDL pthread)
add_library(screenshot SHARED src/screenshot/screenshot.c)

View File

@ -35,9 +35,6 @@ static unsigned char **Tile_grass_carried = (unsigned char **) 0x181dd4;
static float *InvGuiScale = (float *) 0x135d98;
typedef long int (*getRemainingFileSize_t)(FILE *file);
static getRemainingFileSize_t getRemainingFileSize = (getRemainingFileSize_t) 0xba520;
// Structures
struct LevelSettings {
@ -48,23 +45,10 @@ struct LevelSettings {
struct RakNet_RakNetGUID {
unsigned char data[10];
};
struct RakNet_SystemAddress {
unsigned char data[20];
};
struct RakNet_BitStream {
unsigned char data[273];
};
struct RakDataOutput {
unsigned char data[8];
};
struct RakDataInput {
unsigned char data[8];
};
// GameMode
typedef void (*GameMode_releaseUsingItem_t)(unsigned char *game_mode, unsigned char *player);
@ -115,9 +99,6 @@ static void *MouseBuildInput_tickBuild_vtable_addr = (void *) 0x102564;
typedef int (*Player_isUsingItem_t)(unsigned char *player);
static Player_isUsingItem_t Player_isUsingItem = (Player_isUsingItem_t) 0x8f15c;
typedef void (*Player_setArmor_t)(unsigned char *player, int32_t slot, unsigned char *item);
static Player_setArmor_t Player_setArmor = (Player_setArmor_t) 0x8fde0;
// Player
static void *LocalPlayer_openTextEdit_vtable_addr = (void *) 0x106460;
@ -201,22 +182,6 @@ static FillingContainer_addItem_t FillingContainer_addItem = (FillingContainer_a
typedef struct RakNet_SystemAddress (*RakNet_RakPeer_GetSystemAddressFromGuid_t)(unsigned char *rak_peer, struct RakNet_RakNetGUID guid);
// RakNet::BitStream
typedef unsigned char *(*RakNet_BitStream_constructor_t)(struct RakNet_BitStream *stream);
static RakNet_BitStream_constructor_t RakNet_BitStream_constructor = (RakNet_BitStream_constructor_t) 0xd3b84;
typedef void (*RakNet_BitStream_destructor_t)(struct RakNet_BitStream *stream);
static RakNet_BitStream_destructor_t RakNet_BitStream_destructor = (RakNet_BitStream_destructor_t) 0xd3ce8;
// RakDataOutput
static unsigned char *RakDataOutput_vtable = (unsigned char *) 0x109628;
// RakDataInput
static unsigned char *RakDataInput_vtable = (unsigned char *) 0x1095c8;
// ServerSideNetworkHandler
typedef void (*ServerSideNetworkHandler_onDisconnect_t)(unsigned char *server_side_network_handler, unsigned char *guid);
@ -226,44 +191,12 @@ static void *ServerSideNetworkHandler_onDisconnect_vtable_addr = (void *) 0x109b
typedef unsigned char *(*ServerSideNetworkHandler_getPlayer_t)(unsigned char *server_side_network_handler, unsigned char *guid);
static ServerSideNetworkHandler_getPlayer_t ServerSideNetworkHandler_getPlayer = (ServerSideNetworkHandler_getPlayer_t) 0x75464;
// CompoundTag
typedef unsigned char *(*CompoundTag_t)(unsigned char *tag);
static CompoundTag_t CompoundTag = (CompoundTag_t) 0xb9920;
// Tag
typedef void (*Tag_writeNamedTag_t)(unsigned char *tag, struct RakDataOutput *output);
static Tag_writeNamedTag_t Tag_writeNamedTag = (Tag_writeNamedTag_t) 0x6850c;
typedef void (*Tag_deleteChildren_t)(unsigned char *tag);
typedef void (*Tag_destructor_t)(unsigned char *tag);
// Entity
typedef void (*Entity_saveWithoutId_t)(unsigned char *entity, unsigned char *tag);
typedef void (*Entity_load_t)(unsigned char *entity, unsigned char *tag);
typedef void (*Entity_moveTo_t)(unsigned char *entity, float param_1, float param_2, float param_3, float param_4, float param_5);
static Entity_moveTo_t Entity_moveTo = (Entity_moveTo_t) 0x7a834;
typedef void (*Entity_die_t)(unsigned char *entity, unsigned char *cause);
// ServerPlayer
static void *ServerPlayer_moveTo_vtable_addr = (void *) 0x109e54;
// NbtIo
typedef unsigned char *(*NbtIo_read_t)(struct RakDataInput *input);
static NbtIo_read_t NbtIo_read = (NbtIo_read_t) 0xb98cc;
// Inventory
typedef void (*Inventory_clearInventoryWithDefault_t)(unsigned char *inventory);
static Inventory_clearInventoryWithDefault_t Inventory_clearInventoryWithDefault = (Inventory_clearInventoryWithDefault_t) 0x8e7c8;
typedef void (*Inventory_selectSlot_t)(unsigned char *inventory, int32_t slot);
static Inventory_selectSlot_t Inventory_selectSlot = (Inventory_selectSlot_t) 0x8d13c;
@ -333,11 +266,6 @@ static Textures_tick_t Textures_tick = (Textures_tick_t) 0x531c4;
typedef bool (*RakNet_RakPeer_IsBanned_t)(unsigned char *rakpeer, const char *ip);
static RakNet_RakPeer_IsBanned_t RakNet_RakPeer_IsBanned = (RakNet_RakPeer_IsBanned_t) 0xda3b4;
// RakNet::BitStream
typedef struct RakNet_BitStream *(*RakNet_BitStream_constructor_with_data_t)(struct RakNet_BitStream *stream, unsigned char *data, uint32_t size, bool copyData);
static RakNet_BitStream_constructor_with_data_t RakNet_BitStream_constructor_with_data = (RakNet_BitStream_constructor_with_data_t) 0xd3c30;
// RakNet::SystemAddress
typedef char *(*RakNet_SystemAddress_ToString_t)(struct RakNet_SystemAddress *system_address, bool print_delimiter, char delimiter);

View File

@ -1,217 +0,0 @@
#include <libcore/libcore.h>
#include "playerdata.h"
#include "server_internal.h"
#include "../minecraft.h"
// Execute Command Without LD_PRELOAD
static void exec_without_preload(std::string str) {
std::string preload = getenv("LD_PRELOAD");
unsetenv("LD_PRELOAD");
system(str.c_str());
setenv("LD_PRELOAD", preload.c_str(), 1);
}
// Get Player Data NBT Path
static std::string get_player_data_path(std::string username) {
std::string path = std::string(getenv("HOME")) + "/.minecraft/games/com.mojang/minecraftWorlds/" + server_internal_get_world_name() + "/playerdata";
exec_without_preload("mkdir -p " + path);
return path + '/' + username + ".dat";
}
// Destruct Tag
static void destruct_tag(unsigned char *tag) {
unsigned char *tag_vtable = *(unsigned char **) tag;
Tag_deleteChildren_t Tag_deleteChildren = *(Tag_deleteChildren_t *) (tag_vtable + 0x8);
(*Tag_deleteChildren)(tag);
Tag_destructor_t Tag_destructor = *(Tag_destructor_t *) (tag_vtable + 0x4);
(*Tag_destructor)(tag);
}
// Save Player Callback
static void save_player_callback(std::string username, unsigned char *player) {
std::string nbt_file = get_player_data_path(username);
// Open File
FILE *file = fopen(nbt_file.c_str(), "wb");
// Write Storage Version
uint32_t storage_version = 3;
fwrite(&storage_version, 4, 1, file);
// Create Tag
unsigned char *tag = (unsigned char *) ::operator new(0x38);
(*CompoundTag)(tag);
// Allocate
RakNet_BitStream stream;
RakDataOutput output;
// Set VTable
*(unsigned char **) &output.data[0] = RakDataOutput_vtable;
// Construct BitStream
(*RakNet_BitStream_constructor)(&stream);
// Set BitStream
*(RakNet_BitStream **) &output.data[4] = &stream;
// Save NBT
unsigned char *player_vtable = *(unsigned char **) player;
Entity_saveWithoutId_t Entity_saveWithoutId = *(Entity_saveWithoutId_t *) (player_vtable + 0xcc);
(*Entity_saveWithoutId)(player, tag);
// Write NBT
(*Tag_writeNamedTag)(tag, &output);
// Destruct Tag
destruct_tag(tag);
// Write To File
uint32_t numberOfBitsUsed = *(uint32_t *) &stream.data[0];
uint32_t size = (numberOfBitsUsed + 7) >> 3;
fwrite(&size, 4, 1, file);
unsigned char *data = *(unsigned char **) &stream.data[12];
fwrite(data, 1, size, file);
// Destruct BitStream
(*RakNet_BitStream_destructor)(&stream);
// Close File
fclose(file);
}
// Clear Player Inventory And Armor
static void clear_inventory(unsigned char *player) {
unsigned char *inventory = *(unsigned char **) (player + 0xbe0);
(*Inventory_clearInventoryWithDefault)(inventory);
for (int i = 0; i < 4; i++) {
(*Player_setArmor)(player, i, NULL);
}
}
// Load Player Callback
static void load_player_callback(std::string username, unsigned char *player) {
std::string nbt_file = get_player_data_path(username);
// Open File
FILE *file = fopen(nbt_file.c_str(), "rb");
if (file) {
uint32_t storage_version;
size_t data_read = fread(&storage_version, 4, 1, file);
// Check File
if (data_read == 1 && storage_version == 3) {
// Read Expected File Size
uint32_t expected_size;
data_read = fread(&expected_size, 4, 1, file);
// Get Actual Size
long int remaining = (*getRemainingFileSize)(file);
if (data_read == 1 && expected_size > 0 && ((uint32_t) remaining) == expected_size) {
// Read File
unsigned char *data = (unsigned char *) malloc(expected_size);
data_read = fread(data, 1, expected_size, file);
if (data_read == expected_size) {
// Allocate
RakNet_BitStream stream;
RakDataInput input;
// Set VTable
*(unsigned char **) &input.data[0] = RakDataInput_vtable;
// Construct BitStream
(*RakNet_BitStream_constructor_with_data)(&stream, data, expected_size, false);
// Set BitStream
*(RakNet_BitStream **) &input.data[4] = &stream;
// Create Tag
unsigned char *tag = (*NbtIo_read)(&input);
if (tag != NULL) {
// Load Data
unsigned char *player_vtable = *(unsigned char **) player;
Entity_load_t Entity_load = *(Entity_load_t *) (player_vtable + 0xd0);
(*Entity_load)(player, tag);
// Clear Inventory Because The Client Will Also Have An Empty Inventory
clear_inventory(player);
// Destruct tag
destruct_tag(tag);
}
// Destruct BitStream
(*RakNet_BitStream_destructor)(&stream);
}
// Free Data
free(data);
}
}
// Close File
fclose(file);
}
}
static uint32_t get_entity_id(unsigned char *entity) {
return *(uint32_t *) (entity + 0x1c);
}
static void ServerPlayer_moveTo_injection(unsigned char *player, float param_1, float param_2, float param_3, float param_4, float param_5) {
// Call Original Method
(*Entity_moveTo)(player, param_1, param_2, param_3, param_4, param_5);
// Check If Player Is Spawned
unsigned char *minecraft = server_internal_get_minecraft(player);
unsigned char *level = server_internal_get_level(minecraft);
std::vector<unsigned char *> players = server_internal_get_players(level);
bool spawned = false;
uint32_t player_id = get_entity_id(player);
for (std::size_t i = 0; i < players.size(); i++) {
if (player_id == get_entity_id(players[i])) {
spawned = true;
break;
}
}
// Load Data
if (!spawned) {
load_player_callback(server_internal_get_server_player_username(player), player);
}
}
void playerdata_save(unsigned char *level) {
// Save Players
std::vector<unsigned char *> players = server_internal_get_players(level);
for (std::size_t i = 0; i < players.size(); i++) {
// Iterate Players
unsigned char *player = players[i];
std::string username = server_internal_get_server_player_username(player);
save_player_callback(username, player);
}
}
static void ServerSideNetworkHandler_onDisconnect_injection(unsigned char *server_side_network_handler, unsigned char *guid) {
// Save Player Data
unsigned char *player = (*ServerSideNetworkHandler_getPlayer)(server_side_network_handler, guid);
if (player != NULL) {
std::string username = server_internal_get_server_player_username(player);
save_player_callback(username, player);
}
// Call Original Method
(*ServerSideNetworkHandler_onDisconnect)(server_side_network_handler, guid);
}
void playerdata_init() {
// Load Player NBT
patch_address(ServerPlayer_moveTo_vtable_addr, (void *) ServerPlayer_moveTo_injection);
// Save On Logout
patch_address(ServerSideNetworkHandler_onDisconnect_vtable_addr, (void *) ServerSideNetworkHandler_onDisconnect_injection);
}

View File

@ -1,8 +0,0 @@
#ifndef PLAYERDATA_H
#define PLAYERDATA_H
void playerdata_save(unsigned char *level);
void playerdata_init();
#endif

View File

@ -17,7 +17,6 @@
#include "server.h"
#include "server_internal.h"
#include "server_properties.h"
#include "playerdata.h"
#include "../feature/feature.h"
#include "../init/init.h"
@ -244,9 +243,6 @@ static void Level_saveLevelData_injection(unsigned char *level) {
// Call Original Method
(*Level_saveLevelData)(level);
// Save Player Data
playerdata_save(level);
}
// Stop Server
@ -495,9 +491,6 @@ static void server_init() {
// Custom Banned IP List
overwrite((void *) RakNet_RakPeer_IsBanned, (void *) RakNet_RakPeer_IsBanned_injection);
// Load Player Data
playerdata_init();
if (get_server_properties().get_bool("show-minecon-badge", DEFAULT_SHOW_MINECON_BADGE)) {
// Show The MineCon Icon Next To MOTD In Server List
unsigned char minecon_badge_patch[4] = {0x04, 0x1a, 0x9f, 0xe5};