mirror of
https://github.com/luanti-org/luanti.git
synced 2025-08-11 17:51:04 +00:00
Cleanup client init states by bumping protocol version
Don't use TOSERVER_RECEIVED_MEDIA but TOSERVER_CLIENT_READY as indicatio for client ready Handle clients with protocol version < 23 (almost) same way as before Make client tell server about it's version Add client state to not send bogus player position updates prior init complete Add access to statistics information (peer connction time,rtt,version) Fix clients standing stalled in world while preloading item visuals (new clients only) Add get_player_information to read client specific information from lua
This commit is contained in:
parent
556bdc260a
commit
142e2d3b74
15 changed files with 625 additions and 144 deletions
277
src/server.cpp
277
src/server.cpp
|
@ -1191,6 +1191,111 @@ void Server::Receive()
|
|||
|
||||
m_env->removePlayer(peer_id);*/
|
||||
}
|
||||
catch(ClientStateError &e)
|
||||
{
|
||||
errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
|
||||
DenyAccess(peer_id, L"Your client sent something server didn't expect."
|
||||
L"Try reconnecting or updating your client");
|
||||
}
|
||||
}
|
||||
|
||||
PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
|
||||
{
|
||||
std::string playername = "";
|
||||
PlayerSAO *playersao = NULL;
|
||||
m_clients.Lock();
|
||||
RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,InitDone);
|
||||
if (client != NULL) {
|
||||
playername = client->getName();
|
||||
playersao = emergePlayer(playername.c_str(), peer_id);
|
||||
}
|
||||
m_clients.Unlock();
|
||||
|
||||
RemotePlayer *player =
|
||||
static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
|
||||
|
||||
// If failed, cancel
|
||||
if((playersao == NULL) || (player == NULL))
|
||||
{
|
||||
if(player && player->peer_id != 0){
|
||||
errorstream<<"Server: "<<playername<<": Failed to emerge player"
|
||||
<<" (player allocated to an another client)"<<std::endl;
|
||||
DenyAccess(peer_id, L"Another client is connected with this "
|
||||
L"name. If your client closed unexpectedly, try again in "
|
||||
L"a minute.");
|
||||
} else {
|
||||
errorstream<<"Server: "<<playername<<": Failed to emerge player"
|
||||
<<std::endl;
|
||||
DenyAccess(peer_id, L"Could not allocate player.");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
Send complete position information
|
||||
*/
|
||||
SendMovePlayer(peer_id);
|
||||
|
||||
// Send privileges
|
||||
SendPlayerPrivileges(peer_id);
|
||||
|
||||
// Send inventory formspec
|
||||
SendPlayerInventoryFormspec(peer_id);
|
||||
|
||||
// Send inventory
|
||||
UpdateCrafting(peer_id);
|
||||
SendInventory(peer_id);
|
||||
|
||||
// Send HP
|
||||
if(g_settings->getBool("enable_damage"))
|
||||
SendPlayerHP(peer_id);
|
||||
|
||||
// Send Breath
|
||||
SendPlayerBreath(peer_id);
|
||||
|
||||
// Show death screen if necessary
|
||||
if(player->hp == 0)
|
||||
SendDeathscreen(peer_id, false, v3f(0,0,0));
|
||||
|
||||
// Note things in chat if not in simple singleplayer mode
|
||||
if(!m_simple_singleplayer_mode)
|
||||
{
|
||||
// Send information about server to player in chat
|
||||
SendChatMessage(peer_id, getStatusString());
|
||||
|
||||
// Send information about joining in chat
|
||||
{
|
||||
std::wstring name = L"unknown";
|
||||
Player *player = m_env->getPlayer(peer_id);
|
||||
if(player != NULL)
|
||||
name = narrow_to_wide(player->getName());
|
||||
|
||||
std::wstring message;
|
||||
message += L"*** ";
|
||||
message += name;
|
||||
message += L" joined the game.";
|
||||
SendChatMessage(PEER_ID_INEXISTENT,message);
|
||||
}
|
||||
}
|
||||
|
||||
actionstream<<player->getName() <<" joins game. " << std::endl;
|
||||
/*
|
||||
Print out action
|
||||
*/
|
||||
{
|
||||
std::vector<std::string> names = m_clients.getPlayerNames();
|
||||
|
||||
actionstream<<player->getName() <<" joins game. List of players: ";
|
||||
|
||||
for (std::vector<std::string>::iterator i = names.begin();
|
||||
i != names.end(); i++)
|
||||
{
|
||||
actionstream << *i << " ";
|
||||
}
|
||||
|
||||
actionstream<<std::endl;
|
||||
}
|
||||
return playersao;
|
||||
}
|
||||
|
||||
void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
|
@ -1543,6 +1648,21 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
m_clients.event(peer_id, GotInit2);
|
||||
u16 protocol_version = m_clients.getProtocolVersion(peer_id);
|
||||
|
||||
|
||||
///// begin compatibility code
|
||||
PlayerSAO* playersao = NULL;
|
||||
if (protocol_version <= 22) {
|
||||
playersao = StageTwoClientInit(peer_id);
|
||||
|
||||
if (playersao == NULL) {
|
||||
errorstream
|
||||
<< "TOSERVER_INIT2 stage 2 client init failed for peer "
|
||||
<< peer_id << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
///// end compatibility code
|
||||
|
||||
/*
|
||||
Send some initialization data
|
||||
*/
|
||||
|
@ -1572,6 +1692,13 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
float time_speed = g_settings->getFloat("time_speed");
|
||||
SendTimeOfDay(peer_id, time, time_speed);
|
||||
|
||||
///// begin compatibility code
|
||||
if (protocol_version <= 22) {
|
||||
m_clients.event(peer_id, SetClientReady);
|
||||
m_script->on_joinplayer(playersao);
|
||||
}
|
||||
///// end compatibility code
|
||||
|
||||
// Warnings about protocol version can be issued here
|
||||
if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
|
||||
{
|
||||
|
@ -1583,6 +1710,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
}
|
||||
|
||||
u8 peer_ser_ver = getClient(peer_id,InitDone)->serialization_version;
|
||||
u16 peer_proto_ver = getClient(peer_id,InitDone)->net_proto_version;
|
||||
|
||||
if(peer_ser_ver == SER_FMT_VER_INVALID)
|
||||
{
|
||||
|
@ -1615,105 +1743,34 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
return;
|
||||
}
|
||||
else if(command == TOSERVER_RECEIVED_MEDIA) {
|
||||
std::string playername = "";
|
||||
PlayerSAO *playersao = NULL;
|
||||
m_clients.Lock();
|
||||
RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,DefinitionsSent);
|
||||
if (client != NULL) {
|
||||
playername = client->getName();
|
||||
playersao = emergePlayer(playername.c_str(), peer_id);
|
||||
}
|
||||
m_clients.Unlock();
|
||||
return;
|
||||
}
|
||||
else if(command == TOSERVER_CLIENT_READY) {
|
||||
// clients <= protocol version 22 did not send ready message,
|
||||
// they're already initialized
|
||||
assert(peer_proto_ver > 22);
|
||||
|
||||
RemotePlayer *player =
|
||||
static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
|
||||
PlayerSAO* playersao = StageTwoClientInit(peer_id);
|
||||
|
||||
// If failed, cancel
|
||||
if((playersao == NULL) || (player == NULL))
|
||||
{
|
||||
if(player && player->peer_id != 0){
|
||||
errorstream<<"Server: "<<playername<<": Failed to emerge player"
|
||||
<<" (player allocated to an another client)"<<std::endl;
|
||||
DenyAccess(peer_id, L"Another client is connected with this "
|
||||
L"name. If your client closed unexpectedly, try again in "
|
||||
L"a minute.");
|
||||
} else {
|
||||
errorstream<<"Server: "<<playername<<": Failed to emerge player"
|
||||
<<std::endl;
|
||||
DenyAccess(peer_id, L"Could not allocate player.");
|
||||
}
|
||||
if (playersao == NULL) {
|
||||
errorstream
|
||||
<< "TOSERVER_CLIENT_READY stage 2 client init failed for peer "
|
||||
<< peer_id << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Send complete position information
|
||||
*/
|
||||
SendMovePlayer(peer_id);
|
||||
|
||||
// Send privileges
|
||||
SendPlayerPrivileges(peer_id);
|
||||
if(datasize < 2+8)
|
||||
return;
|
||||
|
||||
// Send inventory formspec
|
||||
SendPlayerInventoryFormspec(peer_id);
|
||||
m_clients.setClientVersion(
|
||||
peer_id,
|
||||
data[2], data[3], data[4],
|
||||
std::string((char*) &data[8],(u16) data[6]));
|
||||
|
||||
// Send inventory
|
||||
UpdateCrafting(peer_id);
|
||||
SendInventory(peer_id);
|
||||
|
||||
// Send HP
|
||||
if(g_settings->getBool("enable_damage"))
|
||||
SendPlayerHP(peer_id);
|
||||
|
||||
// Send Breath
|
||||
SendPlayerBreath(peer_id);
|
||||
|
||||
// Show death screen if necessary
|
||||
if(player->hp == 0)
|
||||
SendDeathscreen(peer_id, false, v3f(0,0,0));
|
||||
|
||||
// Note things in chat if not in simple singleplayer mode
|
||||
if(!m_simple_singleplayer_mode)
|
||||
{
|
||||
// Send information about server to player in chat
|
||||
SendChatMessage(peer_id, getStatusString());
|
||||
|
||||
// Send information about joining in chat
|
||||
{
|
||||
std::wstring name = L"unknown";
|
||||
Player *player = m_env->getPlayer(peer_id);
|
||||
if(player != NULL)
|
||||
name = narrow_to_wide(player->getName());
|
||||
|
||||
std::wstring message;
|
||||
message += L"*** ";
|
||||
message += name;
|
||||
message += L" joined the game.";
|
||||
SendChatMessage(PEER_ID_INEXISTENT,message);
|
||||
}
|
||||
}
|
||||
|
||||
actionstream<<player->getName()<<" ["<<addr_s<<"] "<<"joins game. " << std::endl;
|
||||
/*
|
||||
Print out action
|
||||
*/
|
||||
{
|
||||
std::vector<std::string> names = m_clients.getPlayerNames();
|
||||
|
||||
actionstream<<player->getName()<<" ["<<addr_s<<"] "
|
||||
<<"joins game. List of players: ";
|
||||
|
||||
for (std::vector<std::string>::iterator i = names.begin();
|
||||
i != names.end(); i++)
|
||||
{
|
||||
actionstream << *i << " ";
|
||||
}
|
||||
|
||||
actionstream<<std::endl;
|
||||
}
|
||||
|
||||
m_clients.event(peer_id,SetMediaSent);
|
||||
m_clients.event(peer_id, SetClientReady);
|
||||
m_script->on_joinplayer(playersao);
|
||||
return;
|
||||
|
||||
}
|
||||
else if(command == TOSERVER_GOTBLOCKS)
|
||||
{
|
||||
|
@ -2809,6 +2866,46 @@ void Server::deletingPeer(con::Peer *peer, bool timeout)
|
|||
m_peer_change_queue.push_back(c);
|
||||
}
|
||||
|
||||
bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
|
||||
{
|
||||
*retval = m_con.getPeerStat(peer_id,type);
|
||||
if (*retval == -1) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Server::getClientInfo(
|
||||
u16 peer_id,
|
||||
ClientState* state,
|
||||
u32* uptime,
|
||||
u8* ser_vers,
|
||||
u16* prot_vers,
|
||||
u8* major,
|
||||
u8* minor,
|
||||
u8* patch,
|
||||
std::string* vers_string
|
||||
)
|
||||
{
|
||||
*state = m_clients.getClientState(peer_id);
|
||||
m_clients.Lock();
|
||||
RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,Invalid);
|
||||
|
||||
if (client == NULL)
|
||||
return false;
|
||||
|
||||
*uptime = client->uptime();
|
||||
*ser_vers = client->serialization_version;
|
||||
*prot_vers = client->net_proto_version;
|
||||
|
||||
*major = client->getMajor();
|
||||
*minor = client->getMinor();
|
||||
*patch = client->getPatch();
|
||||
*vers_string = client->getPatch();
|
||||
|
||||
m_clients.Unlock();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Server::handlePeerChanges()
|
||||
{
|
||||
while(m_peer_change_queue.size() > 0)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue