Skip to content

Commit beebb9d

Browse files
author
p4user_0
committed
disconnects are handled properly; auto-latency for clients
1 parent d830f76 commit beebb9d

File tree

19 files changed

+291
-126
lines changed

19 files changed

+291
-126
lines changed

game/src/tank/Level.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ Level::Level()
240240
, _pause(0)
241241
, _time(0)
242242
, _timeBuffer(0)
243+
, _dropedFrames(0)
243244
, _limitHit(false)
244245
, _frozen(false)
245246
, _safeMode(true)
@@ -344,6 +345,8 @@ void Level::Clear()
344345

345346
_cmdQueue.c.clear();
346347
_ctrlQueue.c.clear();
348+
_dropedFrames = 0;
349+
_lag.clear();
347350
}
348351

349352
void Level::HitLimit()
@@ -1083,11 +1086,18 @@ void Level::OnNewData(const DataBlock &db)
10831086
_cmdQueue.push(db);
10841087
}
10851088

1086-
ControlPacket Level::GetControlPacket()
1089+
ControlPacket Level::GetControlPacket(GC_Object *player)
10871090
{
10881091
_ASSERT(!_ctrlQueue.empty());
10891092
ControlPacket cp = _ctrlQueue.front();
10901093
_ctrlQueue.pop();
1094+
1095+
ASSERT_TYPE(player, GC_Player);
1096+
if( MISC_YOUARETHELAST & cp.wControlState )
1097+
{
1098+
_lag = static_cast<GC_Player*>(player)->GetNick();
1099+
}
1100+
10911101
return cp;
10921102
}
10931103

@@ -1130,6 +1140,7 @@ void Level::TimeStep(float dt)
11301140
DataBlock::type_type type = db.type();
11311141
switch( type )
11321142
{
1143+
case DBTYPE_ERRORMSG:
11331144
case DBTYPE_TEXTMESSAGE:
11341145
static_cast<UI::Desktop*>(g_gui->GetDesktop())->GetMsgArea()->puts((const char*) db.Data());
11351146
break;
@@ -1175,7 +1186,8 @@ void Level::TimeStep(float dt)
11751186

11761187
if( _ctrlQueue.empty() )
11771188
{
1178-
_timeBuffer = 0;
1189+
_timeBuffer -= fixed_dt;
1190+
_dropedFrames += 1;
11791191
break; // íåò êàäðà. ïðîïóñêàåì
11801192
}
11811193

@@ -1204,8 +1216,9 @@ void Level::TimeStep(float dt)
12041216
#endif
12051217

12061218

1207-
_time += fixed_dt;
1208-
_timeBuffer -= fixed_dt;
1219+
_time += fixed_dt;
1220+
_timeBuffer -= fixed_dt;
1221+
_dropedFrames = __max(0, _dropedFrames - fixed_dt); // it's allowed one dropped frame per second
12091222

12101223
if( !_frozen )
12111224
{

game/src/tank/Level.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,13 @@ class Level : public RefCounted
224224
int _pause;
225225
float _time;
226226
float _timeBuffer;
227+
float _dropedFrames;
228+
string_t _lag;
227229
std::queue<DataBlock> _cmdQueue;
228230
void OnNewData(const DataBlock &db);
229231

230232
std::queue<ControlPacket> _ctrlQueue;
231-
ControlPacket GetControlPacket();
233+
ControlPacket GetControlPacket(GC_Object *player);
232234

233235

234236
Field _field;

game/src/tank/config/Config.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ CONFIG_BEGIN(ConfCache) // var_name def_value
3030
CONFIG_VAR_STR( sv_name, "ZOD server" )
3131
CONFIG_VAR_INT( sv_port, 1945 )
3232
CONFIG_VAR_FLOAT( sv_fps, 30 )
33-
CONFIG_VAR_FLOAT( sv_latency, 4 )
33+
CONFIG_VAR_FLOAT( sv_latency, 1 )
34+
CONFIG_VAR_BOOL( sv_autoLatency, true )
3435
CONFIG_VAR_FLOAT( sv_speed, 100 ) // percent
3536
CONFIG_VAR_FLOAT( sv_timelimit, 7 ) // minutes
3637
CONFIG_VAR_INT( sv_fraglimit, 21 )
@@ -43,6 +44,7 @@ CONFIG_BEGIN(ConfCache) // var_name def_value
4344
CONFIG_VAR_INT( cl_fraglimit, 21 )
4445
CONFIG_VAR_BOOL( cl_nightmode, false )
4546
CONFIG_VAR_STR( cl_server, "localhost" )
47+
CONFIG_VAR_FLOAT( cl_latency, 4 )
4648
CONFIG_VAR_TABLE( cl_playerinfo )
4749

4850
// sound

game/src/tank/gc/Player.cpp

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,21 @@ GC_Player::GC_Player()
4949
SetEvents(GC_FLAG_OBJECT_EVENTS_TS_FIXED);
5050

5151

52+
5253
// select nick from the random_names table
5354
lua_getglobal(g_env.L, "random_name"); // push function
5455
lua_call(g_env.L, 0, 1); // call it
5556
SetNick(lua_tostring(g_env.L, -1)); // get value
5657
lua_pop(g_env.L, 1); // pop result
5758

59+
// !! avoid using net_rand in constructor since it may cause sync error
5860

59-
// select random class
61+
// select first available class
6062
int count = 0;
6163
lua_getglobal(g_env.L, "classes");
6264
for( lua_pushnil(g_env.L); lua_next(g_env.L, -2); lua_pop(g_env.L, 1) )
6365
{
64-
if( 0 == g_level->net_rand() % ++count )
66+
// if( 0 == g_level->net_rand() % ++count )
6567
{
6668
SetClass(lua_tostring(g_env.L, -2)); // get vehicle class
6769
}
@@ -414,12 +416,25 @@ IMPLEMENT_SELF_REGISTRATION(GC_PlayerLocal)
414416
}
415417

416418
GC_PlayerLocal::GC_PlayerLocal()
419+
: _lastLightKeyState(false)
420+
, _lights(true)
421+
, _aimToMouse(false)
417422
{
418423
new GC_Camera(WrapRawPtr(this));
419-
_lastLightKeyState = false;
420-
_lights = true;
421-
_aimToMouse = false;
424+
SelectFreeProfile();
425+
}
426+
427+
GC_PlayerLocal::GC_PlayerLocal(FromFile)
428+
: GC_Player(FromFile())
429+
{
430+
}
431+
432+
GC_PlayerLocal::~GC_PlayerLocal()
433+
{
434+
}
422435

436+
void GC_PlayerLocal::SelectFreeProfile()
437+
{
423438
// find first available profile that is not used by another player
424439
string_t profile;
425440

@@ -448,15 +463,6 @@ GC_PlayerLocal::GC_PlayerLocal()
448463
SetProfile(""); // there was no available profile found
449464
}
450465

451-
GC_PlayerLocal::GC_PlayerLocal(FromFile)
452-
: GC_Player(FromFile())
453-
{
454-
}
455-
456-
GC_PlayerLocal::~GC_PlayerLocal()
457-
{
458-
}
459-
460466
void GC_PlayerLocal::Serialize(SaveFile &f)
461467
{
462468
GC_Player::Serialize(f);
@@ -500,7 +506,7 @@ void GC_PlayerLocal::TimeStepFixed(float dt)
500506
if( g_client )
501507
{
502508
g_client->SendControl(cp);
503-
g_level->GetControlPacket();
509+
g_level->GetControlPacket(this);
504510
}
505511
}
506512
else
@@ -537,10 +543,29 @@ void GC_PlayerLocal::TimeStepFixed(float dt)
537543

538544
cp.fromvs(vs);
539545
g_client->SendControl(cp);
540-
cp = g_level->GetControlPacket();
546+
cp = g_level->GetControlPacket(this);
541547
cp.tovs(vs);
542-
543548
GetVehicle()->SetState(vs);
549+
550+
551+
//
552+
// auto adjust latency
553+
//
554+
555+
if( !g_server && g_conf->sv_autoLatency->Get() && g_conf->sv_latency->GetInt() < g_conf->sv_fps->GetInt() )
556+
{
557+
if( (cp.wControlState & MISC_YOUARETHELAST) && g_level->_dropedFrames > g_conf->sv_fps->GetInt() )
558+
{
559+
g_level->_dropedFrames = 0;
560+
g_conf->sv_latency->SetInt(g_conf->sv_latency->GetInt() + 1);
561+
TRACE("conf.sv_latency is set to %d\n", g_conf->sv_latency->GetInt());
562+
563+
if( g_conf->sv_latency->GetInt() >= g_conf->sv_fps->GetInt() )
564+
{
565+
TRACE("WARNING: latency is too high to play\n", g_conf->sv_latency->GetInt());
566+
}
567+
}
568+
}
544569
}
545570
else
546571
{
@@ -581,6 +606,8 @@ void GC_PlayerLocal::SetProfile(const string_t &name)
581606
}
582607
else
583608
{
609+
TRACE("WARNING: profile '%s' not found\n", name);
610+
584611
_keyForward = 0;
585612
_keyBack = 0;
586613
_keyLeft = 0;
@@ -595,8 +622,6 @@ void GC_PlayerLocal::SetProfile(const string_t &name)
595622
_lights = true;
596623
_aimToMouse = false;
597624
_moveToMouse = false;
598-
599-
TRACE("WARNING: profile '%s' not found\n", name);
600625
}
601626
}
602627

@@ -790,11 +815,11 @@ void GC_PlayerRemote::TimeStepFixed(float dt)
790815
_ASSERT(g_client);
791816
if( IsVehicleDead() )
792817
{
793-
g_level->GetControlPacket();
818+
g_level->GetControlPacket(this);
794819
}
795820
else
796821
{
797-
ControlPacket cp = g_level->GetControlPacket();
822+
ControlPacket cp = g_level->GetControlPacket(this);
798823
VehicleState vs;
799824
cp.tovs(vs);
800825
GetVehicle()->SetState(vs);

game/src/tank/gc/Player.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@ class GC_PlayerLocal : public GC_Player
132132

133133
void GetControl(VehicleState &vs);
134134

135-
136135
protected:
137136
class MyPropertySet : public GC_Player::MyPropertySet
138137
{
@@ -154,6 +153,9 @@ class GC_PlayerLocal : public GC_Player
154153
GC_PlayerLocal(FromFile);
155154
virtual ~GC_PlayerLocal();
156155

156+
void SelectFreeProfile();
157+
158+
157159
virtual DWORD GetNetworkID() const;
158160

159161
virtual void TimeStepFixed(float dt);

game/src/tank/gc/Weapons.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,6 +1082,8 @@ void GC_Weap_Ram::TimeStepFloat(float dt)
10821082
}
10831083
}
10841084
}
1085+
1086+
GC_Weapon::TimeStepFloat(dt);
10851087
}
10861088

10871089
void GC_Weap_Ram::TimeStepFixed(float dt)

game/src/tank/network/ControlPacket.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,11 @@ struct VehicleState
5454
#define STATE_TOWERCENTER 0x0100
5555
#define STATE_ENABLELIGHT 0x0200
5656

57-
#define MODE_EXPLICITTOWER 0x4000
58-
#define MODE_EXPLICITBODY 0x8000
57+
#define MODE_EXPLICITTOWER 0x1000
58+
#define MODE_EXPLICITBODY 0x2000
59+
60+
#define MISC_YOUARETHELAST 0x4000
61+
5962

6063
#pragma pack(push)
6164
#pragma pack(2)

game/src/tank/network/Peer.cpp

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ Peer::Peer(SOCKET s)
1515
{
1616
_socket = s;
1717

18-
if( _socket.SetEvents(FD_READ|FD_WRITE|FD_CONNECT) )
18+
if( _socket.SetEvents(FD_READ|FD_WRITE|FD_CONNECT|FD_CLOSE) )
1919
{
2020
TRACE("peer: ERROR - Unable to select event (%u)\n", WSAGetLastError());
21-
return; // TODO: report error
21+
throw std::runtime_error("peer: Unable to select event");
2222
}
2323

2424
Delegate<void()> d;
@@ -74,7 +74,9 @@ void Peer::Send(const DataBlock &db)
7474
if( WSAEWOULDBLOCK != err )
7575
{
7676
TRACE("peer: network error %u\n", err);
77-
// TODO: disconnect peer
77+
_ASSERT(eventDisconnect);
78+
INVOKE(eventDisconnect) (this, err);
79+
return;
7880
}
7981
_outgoing.insert(_outgoing.end(), db.RawData() + sent, db.RawData() + db.RawSize());
8082
break;
@@ -101,6 +103,8 @@ void Peer::OnSocketEvent()
101103
if( _socket.EnumNetworkEvents(&ne) )
102104
{
103105
TRACE("peer: EnumNetworkEvents error 0x%08x\n", WSAGetLastError());
106+
_ASSERT(eventDisconnect);
107+
INVOKE(eventDisconnect) (this, WSAGetLastError());
104108
return;
105109
}
106110

@@ -110,18 +114,41 @@ void Peer::OnSocketEvent()
110114
INVOKE(eventConnect) (ne.iErrorCode[FD_CONNECT_BIT]);
111115
}
112116

117+
if( ne.lNetworkEvents & FD_CLOSE )
118+
{
119+
_ASSERT(eventDisconnect);
120+
INVOKE(eventDisconnect) (this, ne.iErrorCode[FD_CLOSE_BIT]);
121+
}
122+
113123
if( ne.lNetworkEvents & FD_READ )
114124
{
115125
if( ne.iErrorCode[FD_READ_BIT] )
116126
{
117127
TRACE("peer: read error 0x%08x\n", ne.iErrorCode[FD_READ_BIT]);
128+
_ASSERT(eventDisconnect);
129+
INVOKE(eventDisconnect) (this, ne.iErrorCode[FD_READ_BIT]);
118130
return;
119131
}
120132

121133
char buf[1024];
122134
int result = recv(_socket, buf, sizeof(buf), 0);
123135

124-
if( result > 0 )
136+
if( result < 0 )
137+
{
138+
TRACE("peer: unexpected error 0x%08x\n", WSAGetLastError());
139+
_ASSERT(eventDisconnect);
140+
INVOKE(eventDisconnect) (this, WSAGetLastError());
141+
return;
142+
}
143+
else if( 0 == result )
144+
{
145+
// connection was gracefully closed
146+
TRACE("peer: connection closed by remote side\n");
147+
_ASSERT(eventDisconnect);
148+
INVOKE(eventDisconnect) (this, 0);
149+
return;
150+
}
151+
else
125152
{
126153
DataBlock db;
127154
if( _incoming.empty() )
@@ -158,6 +185,8 @@ void Peer::OnSocketEvent()
158185
if( ne.iErrorCode[FD_WRITE_BIT] )
159186
{
160187
TRACE("peer: write error 0x%08x\n", ne.iErrorCode[FD_WRITE_BIT]);
188+
_ASSERT(eventDisconnect);
189+
INVOKE(eventDisconnect) (this, ne.iErrorCode[FD_WRITE_BIT]);
161190
return;
162191
}
163192

@@ -178,7 +207,9 @@ void Peer::OnSocketEvent()
178207
if( WSAEWOULDBLOCK != err )
179208
{
180209
TRACE("peer: network error %u\n", err);
181-
// TODO: disconnect peer
210+
_ASSERT(eventDisconnect);
211+
INVOKE(eventDisconnect) (this, err);
212+
return;
182213
}
183214
break;
184215
}

game/src/tank/network/Peer.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ class Peer : public RefCounted
2424
void Connect(const sockaddr_in *addr);
2525
void Send(const DataBlock &db);
2626
Delegate<void(Peer *, const DataBlock &)> eventRecv;
27-
Delegate<void(int)> eventConnect;
27+
Delegate<void(Peer *, int errorCode)> eventDisconnect;
28+
Delegate<void(int errorCode)> eventConnect;
2829

2930
private:
3031
void OnSocketEvent();

0 commit comments

Comments
 (0)