Skip to content
Permalink
Browse files

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
  • Loading branch information
sapier sapier
sapier authored and sapier committed Apr 8, 2014
1 parent 556bdc2 commit 142e2d3b74ad886eed83b0fc9d6cfea100dae10a
Showing with 625 additions and 144 deletions.
  1. +23 −0 doc/lua_api.txt
  2. +33 −24 src/client.cpp
  3. +13 −8 src/client.h
  4. +37 −9 src/clientiface.cpp
  5. +164 −2 src/clientiface.h
  6. +16 −2 src/clientserver.h
  7. +2 −2 src/connection.cpp
  8. +1 −1 src/connection.h
  9. +5 −0 src/exceptions.h
  10. +2 −2 src/game.cpp
  11. +3 −3 src/hud.cpp
  12. +131 −1 src/script/lua_api/l_server.cpp
  13. +3 −0 src/script/lua_api/l_server.h
  14. +187 −90 src/server.cpp
  15. +5 −0 src/server.h
@@ -1200,6 +1200,29 @@ minetest.features
minetest.has_feature(arg) -> bool, missing_features
^ arg: string or table in format {foo=true, bar=true}
^ missing_features: {foo=true, bar=true}
minetest.get_player_information(playername)
^ table containing information about player peer:
{
address = "127.0.0.1", -- ip address of client
ip_version = 4, -- IPv4 / IPv6
min_rtt = 0.01, -- minimum round trip time
max_rtt = 0.2, -- maximum round trip time
avg_rtt = 0.02, -- average round trip time
min_jitter = 0.01, -- minimum packet time jitter
max_jitter = 0.5, -- maximum packet time jitter
avg_jitter = 0.03, -- average packet time jitter
connection_uptime = 200, -- seconds since client connected

-- following information is available on debug build only!!!
-- DO NOT USE IN MODS
--ser_vers = 26, -- serialization version used by client
--prot_vers = 23, -- protocol version used by client
--major = 0, -- major version number
--minor = 4, -- minor version number
--patch = 10, -- patch version number
--vers_string = "0.4.9-git", -- full version string
--state = "Active" -- current client state
}

Logging:
minetest.debug(line)
@@ -47,6 +47,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "serialization.h"
#include "util/serialize.h"
#include "config.h"
#include "cmake_config_githash.h"
#include "util/directiontables.h"
#include "util/pointedthing.h"
#include "version.h"
@@ -252,7 +253,8 @@ Client::Client(
m_last_time_of_day_f(-1),
m_time_of_day_update_timer(0),
m_recommended_send_interval(0.1),
m_removed_sounds_check_timer(0)
m_removed_sounds_check_timer(0),
m_state(LC_Created)
{
m_packetcounter_timer = 0.0;
//m_delete_unused_sectors_timer = 0.0;
@@ -325,17 +327,6 @@ void Client::connect(Address address)
m_con.Connect(address);
}

bool Client::connectedAndInitialized()
{
if(m_con.Connected() == false)
return false;

if(m_server_ser_ver == SER_FMT_VER_INVALID)
return false;

return true;
}

void Client::step(float dtime)
{
DSTACK(__FUNCTION_NAME);
@@ -372,9 +363,6 @@ void Client::step(float dtime)
m_packetcounter.clear();
}
}

// Get connection status
bool connected = connectedAndInitialized();

#if 0
{
@@ -467,7 +455,7 @@ void Client::step(float dtime)
}
#endif

if(connected == false)
if(m_state == LC_Created)
{
float &counter = m_connection_reinit_timer;
counter -= dtime;
@@ -632,7 +620,7 @@ void Client::step(float dtime)
{
counter = 0.0;
// connectedAndInitialized() is true, peer exists.
float avg_rtt = m_con.GetPeerAvgRTT(PEER_ID_SERVER);
float avg_rtt = getRTT();
infostream<<"Client: avg_rtt="<<avg_rtt<<std::endl;
}
}
@@ -643,7 +631,7 @@ void Client::step(float dtime)
{
float &counter = m_playerpos_send_timer;
counter += dtime;
if(counter >= m_recommended_send_interval)
if((m_state == LC_Ready) && (counter >= m_recommended_send_interval))
{
counter = 0.0;
sendPlayerPos();
@@ -1051,6 +1039,8 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
// Send as reliable
m_con.Send(PEER_ID_SERVER, 1, reply, true);

m_state = LC_Init;

return;
}

@@ -1937,7 +1927,7 @@ void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)

void Client::interact(u8 action, const PointedThing& pointed)
{
if(connectedAndInitialized() == false){
if(m_state != LC_Ready){
infostream<<"Client::interact() "
"cancelled (not connected)"
<<std::endl;
@@ -2152,6 +2142,27 @@ void Client::sendRespawn()
Send(0, data, true);
}

void Client::sendReady()
{
DSTACK(__FUNCTION_NAME);
std::ostringstream os(std::ios_base::binary);

writeU16(os, TOSERVER_CLIENT_READY);
writeU8(os,VERSION_MAJOR);
writeU8(os,VERSION_MINOR);
writeU8(os,VERSION_PATCH_ORIG);
writeU8(os,0);

writeU16(os,strlen(CMAKE_VERSION_GITHASH));
os.write(CMAKE_VERSION_GITHASH,strlen(CMAKE_VERSION_GITHASH));

// Make data buffer
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
Send(0, data, true);
}

void Client::sendPlayerPos()
{
LocalPlayer *myplayer = m_env.getLocalPlayer();
@@ -2650,16 +2661,14 @@ void Client::afterContentReceived(IrrlichtDevice *device, gui::IGUIFont* font)
infostream<<"- Starting mesh update thread"<<std::endl;
m_mesh_update_thread.Start();

m_state = LC_Ready;
sendReady();
infostream<<"Client::afterContentReceived() done"<<std::endl;
}

float Client::getRTT(void)
{
try{
return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
} catch(con::PeerNotFoundException &e){
return 1337;
}
return m_con.getPeerStat(PEER_ID_SERVER,con::AVG_RTT);
}

// IGameDef interface
@@ -57,6 +57,12 @@ struct QueuedMeshUpdate
~QueuedMeshUpdate();
};

enum LocalClientState {
LC_Created,
LC_Init,
LC_Ready
};

/*
A thread-safe queue of mesh update tasks
*/
@@ -319,14 +325,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
calling this, as it is sent in the initialization.
*/
void connect(Address address);
/*
returns true when
m_con.Connected() == true
AND m_server_ser_ver != SER_FMT_VER_INVALID
throws con::PeerNotFoundException if connection has been deleted,
eg. timed out.
*/
bool connectedAndInitialized();

/*
Stuff that references the environment is valid only as
long as this is not called. (eg. Players)
@@ -354,6 +353,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
void sendDamage(u8 damage);
void sendBreath(u16 breath);
void sendRespawn();
void sendReady();

ClientEnvironment& getEnv()
{ return m_env; }
@@ -454,6 +454,8 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
// Send a notification that no conventional media transfer is needed
void received_media();

LocalClientState getState() { return m_state; }

private:

// Virtual methods from con::PeerHandler
@@ -537,6 +539,9 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef

// Storage for mesh data for creating multiple instances of the same mesh
std::map<std::string, std::string> m_mesh_data;

// own state
LocalClientState m_state;
};

#endif // !CLIENT_HEADER
@@ -17,6 +17,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <sstream>

#include "clientiface.h"
#include "player.h"
#include "settings.h"
@@ -397,10 +399,11 @@ void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)

void RemoteClient::notifyEvent(ClientStateEvent event)
{
std::ostringstream myerror;
switch (m_state)
{
case Invalid:
assert("State update for client in invalid state" != 0);
//intentionally do nothing
break;

case Created:
@@ -420,7 +423,8 @@ void RemoteClient::notifyEvent(ClientStateEvent event)

/* GotInit2 SetDefinitionsSent SetMediaSent */
default:
assert("Invalid client state transition!" == 0);
myerror << "Created: Invalid client state transition! " << event;
throw ClientStateError(myerror.str());
}
break;

@@ -446,7 +450,8 @@ void RemoteClient::notifyEvent(ClientStateEvent event)

/* Init SetDefinitionsSent SetMediaSent */
default:
assert("Invalid client state transition!" == 0);
myerror << "InitSent: Invalid client state transition! " << event;
throw ClientStateError(myerror.str());
}
break;

@@ -467,14 +472,15 @@ void RemoteClient::notifyEvent(ClientStateEvent event)

/* Init GotInit2 SetMediaSent */
default:
assert("Invalid client state transition!" == 0);
myerror << "InitDone: Invalid client state transition! " << event;
throw ClientStateError(myerror.str());
}
break;

case DefinitionsSent:
switch(event)
{
case SetMediaSent:
case SetClientReady:
m_state = Active;
break;

@@ -488,7 +494,8 @@ void RemoteClient::notifyEvent(ClientStateEvent event)

/* Init GotInit2 SetDefinitionsSent */
default:
assert("Invalid client state transition!" == 0);
myerror << "DefinitionsSent: Invalid client state transition! " << event;
throw ClientStateError(myerror.str());
}
break;

@@ -505,7 +512,8 @@ void RemoteClient::notifyEvent(ClientStateEvent event)

/* Init GotInit2 SetDefinitionsSent SetMediaSent SetDenied */
default:
assert("Invalid client state transition!" == 0);
myerror << "Active: Invalid client state transition! " << event;
throw ClientStateError(myerror.str());
break;
}
break;
@@ -516,6 +524,11 @@ void RemoteClient::notifyEvent(ClientStateEvent event)
}
}

u32 RemoteClient::uptime()
{
return getTime(PRECISION_SECONDS) - m_connection_time;
}

ClientInterface::ClientInterface(con::Connection* con)
:
m_con(con),
@@ -749,7 +762,7 @@ void ClientInterface::event(u16 peer_id, ClientStateEvent event)
n->second->notifyEvent(event);
}

if ((event == SetMediaSent) || (event == Disconnect) || (event == SetDenied))
if ((event == SetClientReady) || (event == Disconnect) || (event == SetDenied))
{
UpdatePlayerList();
}
@@ -763,9 +776,24 @@ u16 ClientInterface::getProtocolVersion(u16 peer_id)
std::map<u16, RemoteClient*>::iterator n;
n = m_clients.find(peer_id);

// No client to deliver event
// No client to get version
if (n == m_clients.end())
return 0;

return n->second->net_proto_version;
}

void ClientInterface::setClientVersion(u16 peer_id, u8 major, u8 minor, u8 patch, std::string full)
{
JMutexAutoLock conlock(m_clients_mutex);

// Error check
std::map<u16, RemoteClient*>::iterator n;
n = m_clients.find(peer_id);

// No client to set versions
if (n == m_clients.end())
return;

n->second->setVersionInfo(major,minor,patch,full);
}

0 comments on commit 142e2d3

Please sign in to comment.
You can’t perform that action at this time.