m_peer_id(peer_id_),
m_inventory(NULL),
m_last_good_position(0,0,0),
- m_last_good_position_age(0),
m_time_from_last_punch(0),
m_nocheat_dig_pos(32767, 32767, 32767),
m_nocheat_dig_time(0),
m_player->setPlayerSAO(this);
m_player->peer_id = m_peer_id;
m_last_good_position = m_player->getPosition();
- m_last_good_position_age = 0.0;
}
// Called before removing from environment
m_moved = true;
}
+ //dstream<<"PlayerSAO::step: dtime: "<<dtime<<std::endl;
+
+ // Set lag pool maximums based on estimated lag
+ const float LAG_POOL_MIN = 5.0;
+ float lag_pool_max = m_env->getMaxLagEstimate() * 2.0;
+ if(lag_pool_max < LAG_POOL_MIN)
+ lag_pool_max = LAG_POOL_MIN;
+ m_dig_pool.setMax(lag_pool_max);
+ m_move_pool.setMax(lag_pool_max);
+
+ // Increment cheat prevention timers
+ m_dig_pool.add(dtime);
+ m_move_pool.add(dtime);
m_time_from_last_punch += dtime;
m_nocheat_dig_time += dtime;
{
v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
m_last_good_position = pos;
- m_last_good_position_age = 0;
m_player->setPosition(pos);
}
- else
- {
- if(m_is_singleplayer || g_settings->getBool("disable_anticheat"))
- {
- m_last_good_position = m_player->getPosition();
- m_last_good_position_age = 0;
- }
- else
- {
- /*
- Check player movements
-
- NOTE: Actually the server should handle player physics like the
- client does and compare player's position to what is calculated
- on our side. This is required when eg. players fly due to an
- explosion. Altough a node-based alternative might be possible
- too, and much more lightweight.
- */
-
- float player_max_speed = 0;
- float player_max_speed_up = 0;
- if(m_privs.count("fast") != 0){
- // Fast speed
- player_max_speed = BS * 20;
- player_max_speed_up = BS * 20;
- } else {
- // Normal speed
- player_max_speed = BS * 4.0;
- player_max_speed_up = BS * 4.0;
- }
- // Tolerance
- player_max_speed *= 2.5;
- player_max_speed_up *= 2.5;
-
- m_last_good_position_age += dtime;
- if(m_last_good_position_age >= 1.0){
- float age = m_last_good_position_age;
- v3f diff = (m_player->getPosition() - m_last_good_position);
- float d_vert = diff.Y;
- diff.Y = 0;
- float d_horiz = diff.getLength();
- /*infostream<<m_player->getName()<<"'s horizontal speed is "
- <<(d_horiz/age)<<std::endl;*/
- if(d_horiz <= age * player_max_speed &&
- (d_vert < 0 || d_vert < age * player_max_speed_up)){
- m_last_good_position = m_player->getPosition();
- } else {
- actionstream<<"Player "<<m_player->getName()
- <<" moved too fast; resetting position"
- <<std::endl;
- m_player->setPosition(m_last_good_position);
- m_moved = true;
- }
- m_last_good_position_age = 0;
- }
- }
- }
if(send_recommended == false)
return;
m_player->setPosition(pos);
// Movement caused by this command is always valid
m_last_good_position = pos;
- m_last_good_position_age = 0;
// Force position change on client
m_moved = true;
}
m_player->setPosition(pos);
// Movement caused by this command is always valid
m_last_good_position = pos;
- m_last_good_position_age = 0;
// Force position change on client
m_moved = true;
}
return gob_cmd_set_properties(m_prop);
}
+void PlayerSAO::checkMovementCheat()
+{
+ if(isAttached() || m_is_singleplayer ||
+ g_settings->getBool("disable_anticheat"))
+ {
+ m_last_good_position = m_player->getPosition();
+ }
+ else
+ {
+ /*
+ Check player movements
+
+ NOTE: Actually the server should handle player physics like the
+ client does and compare player's position to what is calculated
+ on our side. This is required when eg. players fly due to an
+ explosion. Altough a node-based alternative might be possible
+ too, and much more lightweight.
+ */
+
+ float player_max_speed = 0;
+ float player_max_speed_up = 0;
+ if(m_privs.count("fast") != 0){
+ // Fast speed
+ player_max_speed = m_player->movement_speed_fast;
+ player_max_speed_up = m_player->movement_speed_fast;
+ } else {
+ // Normal speed
+ player_max_speed = m_player->movement_speed_walk;
+ player_max_speed_up = m_player->movement_speed_walk;
+ }
+ // Tolerance. With the lag pool we shouldn't need it.
+ //player_max_speed *= 2.5;
+ //player_max_speed_up *= 2.5;
+
+ v3f diff = (m_player->getPosition() - m_last_good_position);
+ float d_vert = diff.Y;
+ diff.Y = 0;
+ float d_horiz = diff.getLength();
+ float required_time = d_horiz/player_max_speed;
+ if(d_vert > 0 && d_vert/player_max_speed > required_time)
+ required_time = d_vert/player_max_speed;
+ if(m_move_pool.grab(required_time)){
+ m_last_good_position = m_player->getPosition();
+ } else {
+ actionstream<<"Player "<<m_player->getName()
+ <<" moved too fast; resetting position"
+ <<std::endl;
+ m_player->setPosition(m_last_good_position);
+ m_moved = true;
+ }
+ }
+}
+
bool PlayerSAO::getCollisionBox(aabb3f *toset) {
//update collision box
*toset = m_player->getCollisionbox();
bool PlayerSAO::collideWithObjects(){
return true;
}
+
{
JMutexAutoLock lock(m_env_mutex);
+ // Figure out and report maximum lag to environment
+ float max_lag = m_env->getMaxLagEstimate();
+ max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
+ if(dtime > max_lag){
+ if(dtime > 0.1 && dtime > max_lag * 2.0)
+ infostream<<"Server: Maximum lag peaked to "<<dtime
+ <<" s"<<std::endl;
+ max_lag = dtime;
+ }
+ m_env->reportMaxLagEstimate(max_lag);
// Step environment
ScopeProfiler sp(g_profiler, "SEnv step");
ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
player->control.LMB = (bool)(keyPressed&128);
player->control.RMB = (bool)(keyPressed&256);
+ playersao->checkMovementCheat();
+
/*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
<<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
<<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
<<std::endl;
is_valid_dig = false;
}
- // If time is considerably too short, ignore dig
- // Check time only for medium and slow timed digs
- if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
+ // Check digging time
+ // If already invalidated, we don't have to
+ if(!is_valid_dig){
+ // Well not our problem then
+ }
+ // Clean and long dig
+ else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
+ // All is good, but grab time from pool; don't care if
+ // it's actually available
+ playersao->getDigPool().grab(params.time);
+ }
+ // Short or laggy dig
+ // Try getting the time from pool
+ else if(playersao->getDigPool().grab(params.time)){
+ // All is good
+ }
+ // Dig not possible
+ else{
infostream<<"Server: NoCheat: "<<player->getName()
- <<" completed digging "
- <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
- <<params.time<<"s; not digging."<<std::endl;
+ <<" completed digging "<<PP(p_under)
+ <<"too fast; not digging."<<std::endl;
is_valid_dig = false;
}
}
os<<L"version="<<narrow_to_wide(VERSION_STRING);
// Uptime
os<<L", uptime="<<m_uptime.get();
+ // Max lag estimate
+ os<<L", max_lag="<<m_env->getMaxLagEstimate();
// Information about clients
std::map<u16, RemoteClient*>::iterator i;
bool first;