Skip to content

Commit

Permalink
Cleanup client init states by bumping protocol version
Browse files Browse the repository at this point in the history
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 authored and sapier committed Apr 8, 2014
1 parent 556bdc2 commit 142e2d3
Show file tree
Hide file tree
Showing 15 changed files with 625 additions and 144 deletions.
23 changes: 23 additions & 0 deletions doc/lua_api.txt
Expand Up @@ -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)
Expand Down
57 changes: 33 additions & 24 deletions src/client.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -372,9 +363,6 @@ void Client::step(float dtime)
m_packetcounter.clear();
}
}

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

#if 0
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}
Expand All @@ -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();
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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
Expand Down
21 changes: 13 additions & 8 deletions src/client.h
Expand Up @@ -57,6 +57,12 @@ struct QueuedMeshUpdate
~QueuedMeshUpdate();
};

enum LocalClientState {
LC_Created,
LC_Init,
LC_Ready
};

/*
A thread-safe queue of mesh update tasks
*/
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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; }
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
46 changes: 37 additions & 9 deletions src/clientiface.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -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:
Expand All @@ -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;

Expand All @@ -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;

Expand All @@ -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;

Expand All @@ -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;

Expand All @@ -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;
Expand All @@ -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),
Expand Down Expand Up @@ -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();
}
Expand All @@ -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.