Skip to content

Commit 7426141

Browse files
committedAug 3, 2013
Fix anticheat
1 parent bc5db9b commit 7426141

File tree

5 files changed

+146
-70
lines changed

5 files changed

+146
-70
lines changed
 

‎src/content_sao.cpp

+67-62
Original file line numberDiff line numberDiff line change
@@ -934,7 +934,6 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
934934
m_peer_id(peer_id_),
935935
m_inventory(NULL),
936936
m_last_good_position(0,0,0),
937-
m_last_good_position_age(0),
938937
m_time_from_last_punch(0),
939938
m_nocheat_dig_pos(32767, 32767, 32767),
940939
m_nocheat_dig_time(0),
@@ -1002,7 +1001,6 @@ void PlayerSAO::addedToEnvironment(u32 dtime_s)
10021001
m_player->setPlayerSAO(this);
10031002
m_player->peer_id = m_peer_id;
10041003
m_last_good_position = m_player->getPosition();
1005-
m_last_good_position_age = 0.0;
10061004
}
10071005

10081006
// Called before removing from environment
@@ -1106,6 +1104,19 @@ void PlayerSAO::step(float dtime, bool send_recommended)
11061104
m_moved = true;
11071105
}
11081106

1107+
//dstream<<"PlayerSAO::step: dtime: "<<dtime<<std::endl;
1108+
1109+
// Set lag pool maximums based on estimated lag
1110+
const float LAG_POOL_MIN = 5.0;
1111+
float lag_pool_max = m_env->getMaxLagEstimate() * 2.0;
1112+
if(lag_pool_max < LAG_POOL_MIN)
1113+
lag_pool_max = LAG_POOL_MIN;
1114+
m_dig_pool.setMax(lag_pool_max);
1115+
m_move_pool.setMax(lag_pool_max);
1116+
1117+
// Increment cheat prevention timers
1118+
m_dig_pool.add(dtime);
1119+
m_move_pool.add(dtime);
11091120
m_time_from_last_punch += dtime;
11101121
m_nocheat_dig_time += dtime;
11111122

@@ -1115,66 +1126,8 @@ void PlayerSAO::step(float dtime, bool send_recommended)
11151126
{
11161127
v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
11171128
m_last_good_position = pos;
1118-
m_last_good_position_age = 0;
11191129
m_player->setPosition(pos);
11201130
}
1121-
else
1122-
{
1123-
if(m_is_singleplayer || g_settings->getBool("disable_anticheat"))
1124-
{
1125-
m_last_good_position = m_player->getPosition();
1126-
m_last_good_position_age = 0;
1127-
}
1128-
else
1129-
{
1130-
/*
1131-
Check player movements
1132-
1133-
NOTE: Actually the server should handle player physics like the
1134-
client does and compare player's position to what is calculated
1135-
on our side. This is required when eg. players fly due to an
1136-
explosion. Altough a node-based alternative might be possible
1137-
too, and much more lightweight.
1138-
*/
1139-
1140-
float player_max_speed = 0;
1141-
float player_max_speed_up = 0;
1142-
if(m_privs.count("fast") != 0){
1143-
// Fast speed
1144-
player_max_speed = BS * 20;
1145-
player_max_speed_up = BS * 20;
1146-
} else {
1147-
// Normal speed
1148-
player_max_speed = BS * 4.0;
1149-
player_max_speed_up = BS * 4.0;
1150-
}
1151-
// Tolerance
1152-
player_max_speed *= 2.5;
1153-
player_max_speed_up *= 2.5;
1154-
1155-
m_last_good_position_age += dtime;
1156-
if(m_last_good_position_age >= 1.0){
1157-
float age = m_last_good_position_age;
1158-
v3f diff = (m_player->getPosition() - m_last_good_position);
1159-
float d_vert = diff.Y;
1160-
diff.Y = 0;
1161-
float d_horiz = diff.getLength();
1162-
/*infostream<<m_player->getName()<<"'s horizontal speed is "
1163-
<<(d_horiz/age)<<std::endl;*/
1164-
if(d_horiz <= age * player_max_speed &&
1165-
(d_vert < 0 || d_vert < age * player_max_speed_up)){
1166-
m_last_good_position = m_player->getPosition();
1167-
} else {
1168-
actionstream<<"Player "<<m_player->getName()
1169-
<<" moved too fast; resetting position"
1170-
<<std::endl;
1171-
m_player->setPosition(m_last_good_position);
1172-
m_moved = true;
1173-
}
1174-
m_last_good_position_age = 0;
1175-
}
1176-
}
1177-
}
11781131

11791132
if(send_recommended == false)
11801133
return;
@@ -1267,7 +1220,6 @@ void PlayerSAO::setPos(v3f pos)
12671220
m_player->setPosition(pos);
12681221
// Movement caused by this command is always valid
12691222
m_last_good_position = pos;
1270-
m_last_good_position_age = 0;
12711223
// Force position change on client
12721224
m_moved = true;
12731225
}
@@ -1279,7 +1231,6 @@ void PlayerSAO::moveTo(v3f pos, bool continuous)
12791231
m_player->setPosition(pos);
12801232
// Movement caused by this command is always valid
12811233
m_last_good_position = pos;
1282-
m_last_good_position_age = 0;
12831234
// Force position change on client
12841235
m_moved = true;
12851236
}
@@ -1503,6 +1454,59 @@ std::string PlayerSAO::getPropertyPacket()
15031454
return gob_cmd_set_properties(m_prop);
15041455
}
15051456

1457+
void PlayerSAO::checkMovementCheat()
1458+
{
1459+
if(isAttached() || m_is_singleplayer ||
1460+
g_settings->getBool("disable_anticheat"))
1461+
{
1462+
m_last_good_position = m_player->getPosition();
1463+
}
1464+
else
1465+
{
1466+
/*
1467+
Check player movements
1468+
1469+
NOTE: Actually the server should handle player physics like the
1470+
client does and compare player's position to what is calculated
1471+
on our side. This is required when eg. players fly due to an
1472+
explosion. Altough a node-based alternative might be possible
1473+
too, and much more lightweight.
1474+
*/
1475+
1476+
float player_max_speed = 0;
1477+
float player_max_speed_up = 0;
1478+
if(m_privs.count("fast") != 0){
1479+
// Fast speed
1480+
player_max_speed = m_player->movement_speed_fast;
1481+
player_max_speed_up = m_player->movement_speed_fast;
1482+
} else {
1483+
// Normal speed
1484+
player_max_speed = m_player->movement_speed_walk;
1485+
player_max_speed_up = m_player->movement_speed_walk;
1486+
}
1487+
// Tolerance. With the lag pool we shouldn't need it.
1488+
//player_max_speed *= 2.5;
1489+
//player_max_speed_up *= 2.5;
1490+
1491+
v3f diff = (m_player->getPosition() - m_last_good_position);
1492+
float d_vert = diff.Y;
1493+
diff.Y = 0;
1494+
float d_horiz = diff.getLength();
1495+
float required_time = d_horiz/player_max_speed;
1496+
if(d_vert > 0 && d_vert/player_max_speed > required_time)
1497+
required_time = d_vert/player_max_speed;
1498+
if(m_move_pool.grab(required_time)){
1499+
m_last_good_position = m_player->getPosition();
1500+
} else {
1501+
actionstream<<"Player "<<m_player->getName()
1502+
<<" moved too fast; resetting position"
1503+
<<std::endl;
1504+
m_player->setPosition(m_last_good_position);
1505+
m_moved = true;
1506+
}
1507+
}
1508+
}
1509+
15061510
bool PlayerSAO::getCollisionBox(aabb3f *toset) {
15071511
//update collision box
15081512
*toset = m_player->getCollisionbox();
@@ -1516,3 +1520,4 @@ bool PlayerSAO::getCollisionBox(aabb3f *toset) {
15161520
bool PlayerSAO::collideWithObjects(){
15171521
return true;
15181522
}
1523+

‎src/content_sao.h

+37-1
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,36 @@ class LuaEntitySAO : public ServerActiveObject
122122
PlayerSAO needs some internals exposed.
123123
*/
124124

125+
class LagPool
126+
{
127+
float pool;
128+
float max;
129+
public:
130+
LagPool(): pool(15), max(15)
131+
{}
132+
void setMax(float new_max)
133+
{
134+
max = new_max;
135+
if(pool > new_max)
136+
pool = new_max;
137+
}
138+
void add(float dtime)
139+
{
140+
pool -= dtime;
141+
if(pool < 0)
142+
pool = 0;
143+
}
144+
bool grab(float dtime)
145+
{
146+
if(dtime <= 0)
147+
return true;
148+
if(pool + dtime > max)
149+
return false;
150+
pool += dtime;
151+
return true;
152+
}
153+
};
154+
125155
class PlayerSAO : public ServerActiveObject
126156
{
127157
public:
@@ -228,6 +258,11 @@ class PlayerSAO : public ServerActiveObject
228258
{
229259
m_nocheat_dig_pos = v3s16(32767, 32767, 32767);
230260
}
261+
LagPool& getDigPool()
262+
{
263+
return m_dig_pool;
264+
}
265+
void checkMovementCheat();
231266

232267
// Other
233268

@@ -249,8 +284,9 @@ class PlayerSAO : public ServerActiveObject
249284
Inventory *m_inventory;
250285

251286
// Cheat prevention
287+
LagPool m_dig_pool;
288+
LagPool m_move_pool;
252289
v3f m_last_good_position;
253-
float m_last_good_position_age;
254290
float m_time_from_last_punch;
255291
v3s16 m_nocheat_dig_pos;
256292
float m_nocheat_dig_time;

‎src/environment.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,8 @@ ServerEnvironment::ServerEnvironment(ServerMap *map, ScriptApi *scriptIface,
332332
m_active_block_interval_overload_skip(0),
333333
m_game_time(0),
334334
m_game_time_fraction_counter(0),
335-
m_recommended_send_interval(0.1)
335+
m_recommended_send_interval(0.1),
336+
m_max_lag_estimate(0.1)
336337
{
337338
}
338339

‎src/environment.h

+6
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,9 @@ class ServerEnvironment : public Environment
304304
bool line_of_sight(v3f pos1, v3f pos2, float stepsize=1.0);
305305

306306
u32 getGameTime() { return m_game_time; }
307+
308+
void reportMaxLagEstimate(float f) { m_max_lag_estimate = f; }
309+
float getMaxLagEstimate() { return m_max_lag_estimate; }
307310
private:
308311

309312
/*
@@ -378,6 +381,9 @@ class ServerEnvironment : public Environment
378381
std::list<ABMWithState> m_abms;
379382
// An interval for generally sending object positions and stuff
380383
float m_recommended_send_interval;
384+
// Estimate for general maximum lag as determined by server.
385+
// Can raise to high values like 15s with eg. map generation mods.
386+
float m_max_lag_estimate;
381387
};
382388

383389
#ifndef SERVER

‎src/server.cpp

+34-6
Original file line numberDiff line numberDiff line change
@@ -1090,6 +1090,16 @@ void Server::AsyncRunStep()
10901090

10911091
{
10921092
JMutexAutoLock lock(m_env_mutex);
1093+
// Figure out and report maximum lag to environment
1094+
float max_lag = m_env->getMaxLagEstimate();
1095+
max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
1096+
if(dtime > max_lag){
1097+
if(dtime > 0.1 && dtime > max_lag * 2.0)
1098+
infostream<<"Server: Maximum lag peaked to "<<dtime
1099+
<<" s"<<std::endl;
1100+
max_lag = dtime;
1101+
}
1102+
m_env->reportMaxLagEstimate(max_lag);
10931103
// Step environment
10941104
ScopeProfiler sp(g_profiler, "SEnv step");
10951105
ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
@@ -2241,6 +2251,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
22412251
player->control.LMB = (bool)(keyPressed&128);
22422252
player->control.RMB = (bool)(keyPressed&256);
22432253

2254+
playersao->checkMovementCheat();
2255+
22442256
/*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
22452257
<<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
22462258
<<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
@@ -2953,13 +2965,27 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
29532965
<<std::endl;
29542966
is_valid_dig = false;
29552967
}
2956-
// If time is considerably too short, ignore dig
2957-
// Check time only for medium and slow timed digs
2958-
if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
2968+
// Check digging time
2969+
// If already invalidated, we don't have to
2970+
if(!is_valid_dig){
2971+
// Well not our problem then
2972+
}
2973+
// Clean and long dig
2974+
else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2975+
// All is good, but grab time from pool; don't care if
2976+
// it's actually available
2977+
playersao->getDigPool().grab(params.time);
2978+
}
2979+
// Short or laggy dig
2980+
// Try getting the time from pool
2981+
else if(playersao->getDigPool().grab(params.time)){
2982+
// All is good
2983+
}
2984+
// Dig not possible
2985+
else{
29592986
infostream<<"Server: NoCheat: "<<player->getName()
2960-
<<" completed digging "
2961-
<<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
2962-
<<params.time<<"s; not digging."<<std::endl;
2987+
<<" completed digging "<<PP(p_under)
2988+
<<"too fast; not digging."<<std::endl;
29632989
is_valid_dig = false;
29642990
}
29652991
}
@@ -4617,6 +4643,8 @@ std::wstring Server::getStatusString()
46174643
os<<L"version="<<narrow_to_wide(VERSION_STRING);
46184644
// Uptime
46194645
os<<L", uptime="<<m_uptime.get();
4646+
// Max lag estimate
4647+
os<<L", max_lag="<<m_env->getMaxLagEstimate();
46204648
// Information about clients
46214649
std::map<u16, RemoteClient*>::iterator i;
46224650
bool first;

0 commit comments

Comments
 (0)
Please sign in to comment.