Reorder client initialization (#15554)

Previously, ServerEnv created a player instance before they're fully initialized.
This commit moves all initialization steps and callbacks into TOSERVER_CLIENT_READY
^ which includes StageTwoClientInit for player loading or creation
This commit is contained in:
SmallJoker 2024-12-24 15:24:56 +01:00 committed by GitHub
parent c49ff76955
commit d1dd044455
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 41 additions and 40 deletions

@ -1168,24 +1168,25 @@ void Server::yieldToOtherThreads(float dtime)
g_profiler->avg("Server::yieldTo...() progress [#]", qs_initial - qs); g_profiler->avg("Server::yieldTo...() progress [#]", qs_initial - qs);
} }
PlayerSAO* Server::StageTwoClientInit(session_t peer_id) PlayerSAO *Server::StageTwoClientInit(session_t peer_id)
{ {
std::string playername; std::string playername;
PlayerSAO *playersao = NULL; std::unique_ptr<PlayerSAO> sao;
{ {
ClientInterface::AutoLock clientlock(m_clients); ClientInterface::AutoLock clientlock(m_clients);
RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone); RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
if (client) { if (client) {
playername = client->getName(); playername = client->getName();
playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version); sao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
} }
} }
RemotePlayer *player = m_env->getPlayer(playername.c_str(), true); RemotePlayer *player = sao ? sao->getPlayer() : nullptr;
// If failed, cancel // If failed, cancel
if (!playersao || !player) { if (!player) {
if (player && player->getPeerId() != PEER_ID_INEXISTENT) { RemotePlayer *joined = m_env->getPlayer(playername.c_str());
if (joined && joined->getPeerId() != PEER_ID_INEXISTENT) {
actionstream << "Server: Failed to emerge player \"" << playername actionstream << "Server: Failed to emerge player \"" << playername
<< "\" (player allocated to another client)" << std::endl; << "\" (player allocated to another client)" << std::endl;
DenyAccess(peer_id, SERVER_ACCESSDENIED_ALREADY_CONNECTED); DenyAccess(peer_id, SERVER_ACCESSDENIED_ALREADY_CONNECTED);
@ -1197,6 +1198,19 @@ PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
return nullptr; return nullptr;
} }
// Add player to environment
m_env->addPlayer(player);
/* Clean up old HUD elements from previous sessions */
player->clearHud();
/* Add object to environment */
PlayerSAO *playersao = sao.get();
m_env->addActiveObject(std::move(sao));
if (playersao->isNewPlayer())
m_script->on_newplayer(playersao);
/* /*
Send complete position information Send complete position information
*/ */
@ -3229,9 +3243,7 @@ void Server::reportPrivsModified(const std::string &name)
PlayerSAO *sao = player->getPlayerSAO(); PlayerSAO *sao = player->getPlayerSAO();
if(!sao) if(!sao)
return; return;
sao->updatePrivileges( sao->updatePrivileges(getPlayerEffectivePrivs(name));
getPlayerEffectivePrivs(name),
isSingleplayer());
} }
} }
@ -3965,7 +3977,8 @@ void Server::requestShutdown(const std::string &msg, bool reconnect, float delay
m_shutdown_state.trigger(delay, msg, reconnect); m_shutdown_state.trigger(delay, msg, reconnect);
} }
PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version) std::unique_ptr<PlayerSAO> Server::emergePlayer(const char *name, session_t peer_id,
u16 proto_version)
{ {
/* /*
Try to get an existing player Try to get an existing player
@ -4008,20 +4021,13 @@ PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_v
player = new RemotePlayer(name, idef()); player = new RemotePlayer(name, idef());
} }
bool newplayer = false;
// Load player // Load player
PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer()); auto playersao = m_env->loadPlayer(player, peer_id);
// Complete init with server parts // Complete init with server parts
playersao->finalize(player, getPlayerEffectivePrivs(player->getName())); playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
player->protocol_version = proto_version; player->protocol_version = proto_version;
/* Run scripts */
if (newplayer) {
m_script->on_newplayer(playersao);
}
return playersao; return playersao;
} }

@ -194,7 +194,9 @@ public:
void Receive(float min_time); void Receive(float min_time);
void yieldToOtherThreads(float dtime); void yieldToOtherThreads(float dtime);
PlayerSAO* StageTwoClientInit(session_t peer_id); // Full player initialization after they processed all static media
// This is a helper function for TOSERVER_CLIENT_READY
PlayerSAO *StageTwoClientInit(session_t peer_id);
/* /*
* Command Handlers * Command Handlers
@ -626,7 +628,8 @@ private:
Call with env and con locked. Call with env and con locked.
*/ */
PlayerSAO *emergePlayer(const char *name, session_t peer_id, u16 proto_version); std::unique_ptr<PlayerSAO> emergePlayer(const char *name, session_t peer_id,
u16 proto_version);
/* /*
Variables Variables

@ -156,12 +156,14 @@ public:
// Other // Other
void updatePrivileges(const std::set<std::string> &privs, bool is_singleplayer) void updatePrivileges(const std::set<std::string> &privs)
{ {
m_privs = privs; m_privs = privs;
m_is_singleplayer = is_singleplayer;
} }
inline void setNewPlayer() { m_is_new_player = true; }
inline bool isNewPlayer() { return m_is_new_player; }
bool getCollisionBox(aabb3f *toset) const override; bool getCollisionBox(aabb3f *toset) const override;
bool getSelectionBox(aabb3f *toset) const override; bool getSelectionBox(aabb3f *toset) const override;
bool collideWithObjects() const override { return true; } bool collideWithObjects() const override { return true; }
@ -202,7 +204,8 @@ private:
// Cached privileges for enforcement // Cached privileges for enforcement
std::set<std::string> m_privs; std::set<std::string> m_privs;
bool m_is_singleplayer; const bool m_is_singleplayer;
bool m_is_new_player = false;
u16 m_breath = PLAYER_MAX_BREATH_DEFAULT; u16 m_breath = PLAYER_MAX_BREATH_DEFAULT;
f32 m_pitch = 0.0f; f32 m_pitch = 0.0f;

@ -667,13 +667,13 @@ void ServerEnvironment::savePlayer(RemotePlayer *player)
} }
} }
PlayerSAO *ServerEnvironment::loadPlayer(RemotePlayer *player, bool *new_player, std::unique_ptr<PlayerSAO> ServerEnvironment::loadPlayer(RemotePlayer *player, session_t peer_id)
session_t peer_id, bool is_singleplayer)
{ {
auto playersao = std::make_unique<PlayerSAO>(this, player, peer_id, is_singleplayer); auto playersao = std::make_unique<PlayerSAO>(this, player, peer_id, m_server->isSingleplayer());
// Create player if it doesn't exist // Create player if it doesn't exist
if (!m_player_database->loadPlayer(player, playersao.get())) { if (!m_player_database->loadPlayer(player, playersao.get())) {
*new_player = true; playersao->setNewPlayer();
// Set player position // Set player position
infostream << "Server: Finding spawn place for player \"" infostream << "Server: Finding spawn place for player \""
<< player->getName() << "\"" << std::endl; << player->getName() << "\"" << std::endl;
@ -692,20 +692,10 @@ PlayerSAO *ServerEnvironment::loadPlayer(RemotePlayer *player, bool *new_player,
} }
} }
// Add player to environment
addPlayer(player);
/* Clean up old HUD elements from previous sessions */
player->clearHud();
/* Add object to environment */
PlayerSAO *ret = playersao.get();
addActiveObject(std::move(playersao));
// Update active blocks quickly for a bit so objects in those blocks appear on the client // Update active blocks quickly for a bit so objects in those blocks appear on the client
m_fast_active_block_divider = 10; m_fast_active_block_divider = 10;
return ret; return playersao;
} }
void ServerEnvironment::saveMeta() void ServerEnvironment::saveMeta()

@ -240,8 +240,7 @@ public:
// Save players // Save players
void saveLoadedPlayers(bool force = false); void saveLoadedPlayers(bool force = false);
void savePlayer(RemotePlayer *player); void savePlayer(RemotePlayer *player);
PlayerSAO *loadPlayer(RemotePlayer *player, bool *new_player, session_t peer_id, std::unique_ptr<PlayerSAO> loadPlayer(RemotePlayer *player, session_t peer_id);
bool is_singleplayer);
void addPlayer(RemotePlayer *player); void addPlayer(RemotePlayer *player);
void removePlayer(RemotePlayer *player); void removePlayer(RemotePlayer *player);
bool removePlayerFromDatabase(const std::string &name); bool removePlayerFromDatabase(const std::string &name);