void Server::handleCommand_Damage(NetworkPacket* pkt) { //const auto peer_id = pkt->getPeerId(); auto & packet = *(pkt->packet); auto player = m_env->getPlayer(pkt->getPeerId()); if (!player) { m_con.DisconnectPeer(pkt->getPeerId()); return; } auto playersao = player->getPlayerSAO(); if (!playersao) { m_con.DisconnectPeer(pkt->getPeerId()); return; } u8 damage = packet[TOSERVER_DAMAGE_VALUE].as<u8>(); if(g_settings->getBool("enable_damage")) { actionstream << player->getName() << " damaged by " << (int)damage << " hp at " << PP(player->getPosition() / BS) << std::endl; playersao->setHP(playersao->getHP() - damage); SendPlayerHPOrDie(playersao); stat.add("damage", player->getName(), damage); } }
void Server::handleCommand_RemovedSounds(NetworkPacket* pkt) { const auto peer_id = pkt->getPeerId(); auto & packet = *(pkt->packet); auto player = m_env->getPlayer(pkt->getPeerId()); if (!player) { m_con.DisconnectPeer(pkt->getPeerId()); return; } auto playersao = player->getPlayerSAO(); if (!playersao) { m_con.DisconnectPeer(pkt->getPeerId()); return; } std::vector<s32> removed_ids; packet[TOSERVER_REMOVED_SOUNDS_IDS].convert(removed_ids); for (auto & id : removed_ids) { std::map<s32, ServerPlayingSound>::iterator i = m_playing_sounds.find(id); if(i == m_playing_sounds.end()) continue; ServerPlayingSound &psound = i->second; psound.clients.erase(peer_id); if(psound.clients.empty()) m_playing_sounds.erase(i); } }
void Server::SendPlayerBreath(u16 peer_id) { DSTACK(FUNCTION_NAME); PlayerSAO *playersao = getPlayerSAO(peer_id); if (!playersao) return; m_script->player_event(playersao, "breath_changed"); SendBreath(peer_id, playersao->getBreath()); }
void Server::SendPlayerHP(u16 peer_id) { DSTACK(FUNCTION_NAME); PlayerSAO *playersao = getPlayerSAO(peer_id); if (!playersao) return; SendHP(peer_id, playersao->getHP()); m_script->player_event(playersao,"health_changed"); // Send to other clients std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP()); ActiveObjectMessage aom(playersao->getId(), true, str); playersao->m_messages_out.push(aom); }
void Server::handleCommand_PlayerItem(NetworkPacket* pkt) { //const auto peer_id = pkt->getPeerId(); auto & packet = *(pkt->packet); auto player = m_env->getPlayer(pkt->getPeerId()); if (!player) { m_con.DisconnectPeer(pkt->getPeerId()); return; } auto playersao = player->getPlayerSAO(); if (!playersao) { m_con.DisconnectPeer(pkt->getPeerId()); return; } u16 item = packet[TOSERVER_PLAYERITEM_VALUE].as<u16>(); playersao->setWieldIndex(item); }
void Server::handleCommand_Drawcontrol(NetworkPacket* pkt) { const auto peer_id = pkt->getPeerId(); auto & packet = *(pkt->packet); auto player = m_env->getPlayer(pkt->getPeerId()); if (!player) { m_con.DisconnectPeer(pkt->getPeerId()); return; } auto playersao = player->getPlayerSAO(); if (!playersao) { m_con.DisconnectPeer(pkt->getPeerId()); return; } auto client = getClient(peer_id); auto lock = client->lock_unique_rec(); client->wanted_range = packet[TOSERVER_DRAWCONTROL_WANTED_RANGE].as<u32>(); client->range_all = packet[TOSERVER_DRAWCONTROL_RANGE_ALL].as<u32>(); client->farmesh = packet[TOSERVER_DRAWCONTROL_FARMESH].as<u8>(); client->fov = packet[TOSERVER_DRAWCONTROL_FOV].as<f32>(); //client->block_overflow = packet[TOSERVER_DRAWCONTROL_BLOCK_OVERFLOW].as<bool>(); }
void Server::handleCommand_InventoryFields(NetworkPacket* pkt) { //const auto peer_id = pkt->getPeerId(); auto & packet = *(pkt->packet); auto player = m_env->getPlayer(pkt->getPeerId()); if (!player) { m_con.DisconnectPeer(pkt->getPeerId()); return; } auto playersao = player->getPlayerSAO(); if (!playersao) { m_con.DisconnectPeer(pkt->getPeerId()); return; } std::string formname; std::map<std::string, std::string> fields; packet[TOSERVER_INVENTORY_FIELDS_FORMNAME].convert(formname); packet[TOSERVER_INVENTORY_FIELDS_DATA].convert(fields); m_script->on_playerReceiveFields(playersao, formname, fields); }
void Server::handleCommand_Respawn(NetworkPacket* pkt) { const auto peer_id = pkt->getPeerId(); //auto & packet = *(pkt->packet); auto player = m_env->getPlayer(pkt->getPeerId()); if (!player) { m_con.DisconnectPeer(pkt->getPeerId()); return; } auto playersao = player->getPlayerSAO(); if (!playersao) { m_con.DisconnectPeer(pkt->getPeerId()); return; } if(!player->isDead()) return; RespawnPlayer(peer_id); actionstream << player->getName() << " respawns at " << PP(player->getPosition() / BS) << std::endl; // ActiveObject is added to environment in AsyncRunStep after // the previous addition has been successfully removed }
void Server::handleCommand_Breath(NetworkPacket* pkt) { const auto peer_id = pkt->getPeerId(); auto & packet = *(pkt->packet); auto player = m_env->getPlayer(pkt->getPeerId()); if (!player) { m_con.DisconnectPeer(pkt->getPeerId()); return; } auto playersao = player->getPlayerSAO(); if (!playersao) { m_con.DisconnectPeer(pkt->getPeerId()); return; } /* * If player is dead, we don't need to update the breath * He is dead ! */ if (!player->isDead()) { playersao->setBreath(packet[TOSERVER_BREATH_VALUE].as<u16>()); SendPlayerBreath(peer_id); } }
void Server::handleCommand_NodeMetaFields(NetworkPacket* pkt) { //const auto peer_id = pkt->getPeerId(); auto & packet = *(pkt->packet); auto player = m_env->getPlayer(pkt->getPeerId()); if (!player) { m_con.DisconnectPeer(pkt->getPeerId()); return; } auto playersao = player->getPlayerSAO(); if (!playersao) { m_con.DisconnectPeer(pkt->getPeerId()); return; } v3s16 p = packet[TOSERVER_NODEMETA_FIELDS_POS].as<v3s16>(); std::string formname = packet[TOSERVER_NODEMETA_FIELDS_FORMNAME].as<std::string>(); std::map<std::string, std::string> fields; packet[TOSERVER_NODEMETA_FIELDS_DATA].convert(fields); // If something goes wrong, this player is to blame RollbackScopeActor rollback_scope(m_rollback, std::string("player:") + player->getName()); // Check the target node for rollback data; leave others unnoticed RollbackNode rn_old(&m_env->getMap(), p, this); m_script->node_on_receive_fields(p, formname, fields, playersao); // Report rollback data RollbackNode rn_new(&m_env->getMap(), p, this); if(rollback() && rn_new != rn_old) { RollbackAction action; action.setSetNode(p, rn_old, rn_new); rollback()->reportAction(action); } }
void Server::handleCommand_Interact(NetworkPacket* pkt) { const auto peer_id = pkt->getPeerId(); auto & packet = *(pkt->packet); auto player = m_env->getPlayer(pkt->getPeerId()); if (!player) { m_con.DisconnectPeer(pkt->getPeerId()); return; } auto playersao = player->getPlayerSAO(); if (!playersao) { m_con.DisconnectPeer(pkt->getPeerId()); return; } u8 action; u16 item_i; PointedThing pointed; packet[TOSERVER_INTERACT_ACTION].convert(action); packet[TOSERVER_INTERACT_ITEM].convert(item_i); packet[TOSERVER_INTERACT_POINTED_THING].convert(pointed); if(player->hp == 0) { verbosestream << "TOSERVER_INTERACT: " << player->getName() << " tried to interact, but is dead!" << std::endl; return; } MAP_NOTHREAD_LOCK((&m_env->getMap())); v3f player_pos = playersao->getLastGoodPosition(); // Update wielded item playersao->setWieldIndex(item_i); // Get pointed to node (undefined if not POINTEDTYPE_NODE) v3s16 p_under = pointed.node_undersurface; v3s16 p_above = pointed.node_abovesurface; // Get pointed to object (NULL if not POINTEDTYPE_OBJECT) ServerActiveObject *pointed_object = NULL; if(pointed.type == POINTEDTHING_OBJECT) { pointed_object = m_env->getActiveObject(pointed.object_id); if(pointed_object == NULL) { verbosestream << "TOSERVER_INTERACT: " "pointed object is NULL" << std::endl; return; } } v3f pointed_pos_under = player_pos; v3f pointed_pos_above = player_pos; if(pointed.type == POINTEDTHING_NODE) { pointed_pos_under = intToFloat(p_under, BS); pointed_pos_above = intToFloat(p_above, BS); } else if(pointed.type == POINTEDTHING_OBJECT) { pointed_pos_under = pointed_object->getBasePosition(); pointed_pos_above = pointed_pos_under; } /* Check that target is reasonably close (only when digging or placing things) */ static const bool enable_anticheat = !g_settings->getBool("disable_anticheat"); if ((action == 0 || action == 2 || action == 3) && (enable_anticheat && !isSingleplayer())) { float d = player_pos.getDistanceFrom(pointed_pos_under); float max_d = BS * 14; // Just some large enough value if(d > max_d) { actionstream << "Player " << player->getName() << " tried to access " << pointed.dump() << " from too far: " << "d=" << d << ", max_d=" << max_d << ". ignoring." << std::endl; // Re-send block to revert change on client-side RemoteClient *client = getClient(peer_id); v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS)); client->SetBlockNotSent(blockpos); // Call callbacks m_script->on_cheat(playersao, "interacted_too_far"); // Do nothing else return; } } /* Make sure the player is allowed to do it */ if(!checkPriv(player->getName(), "interact")) { actionstream << player->getName() << " attempted to interact with " << pointed.dump() << " without 'interact' privilege" << std::endl; // Re-send block to revert change on client-side RemoteClient *client = getClient(peer_id); // Digging completed -> under if(action == 2) { v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS)); client->SetBlockNotSent(blockpos); } // Placement -> above if(action == 3) { v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS)); client->SetBlockNotSent(blockpos); } stat.add("interact_denied", player->getName()); return; } /* If something goes wrong, this player is to blame */ RollbackScopeActor rollback_scope(m_rollback, std::string("player:") + player->getName()); /* 0: start digging or punch object */ if(action == 0) { if(pointed.type == POINTEDTHING_NODE) { /* NOTE: This can be used in the future to check if somebody is cheating, by checking the timing. */ MapNode n = m_env->getMap().getNode(p_under); if (!n) { infostream << "Server: Not punching: Node not found." << " Adding block to emerge queue." << std::endl; m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false); } if(n.getContent() != CONTENT_IGNORE) m_script->node_on_punch(p_under, n, playersao, pointed); // Cheat prevention playersao->noCheatDigStart(p_under); } else if(pointed.type == POINTEDTHING_OBJECT) { // Skip if object has been removed if(pointed_object->m_removed) return; actionstream << player->getName() << " punches object " << pointed.object_id << ": " << pointed_object->getDescription() << std::endl; ItemStack punchitem = playersao->getWieldedItem(); ToolCapabilities toolcap = punchitem.getToolCapabilities(m_itemdef); v3f dir = (pointed_object->getBasePosition() - (player->getPosition() + player->getEyeOffset()) ).normalize(); float time_from_last_punch = playersao->resetTimeFromLastPunch(); s16 src_original_hp = pointed_object->getHP(); s16 dst_origin_hp = playersao->getHP(); pointed_object->punch(dir, &toolcap, playersao, time_from_last_punch); // If the object is a player and its HP changed if (src_original_hp != pointed_object->getHP() && pointed_object->getType() == ACTIVEOBJECT_TYPE_PLAYER) { SendPlayerHPOrDie(((PlayerSAO*)pointed_object)); } // If the puncher is a player and its HP changed if (dst_origin_hp != playersao->getHP()) { SendPlayerHPOrDie(playersao); } stat.add("punch", player->getName()); } } // action == 0 /* 1: stop digging */ else if(action == 1) { } // action == 1 /* 2: Digging completed */ else if(action == 2) { // Only digging of nodes if(pointed.type == POINTEDTHING_NODE) { MapNode n = m_env->getMap().getNode(p_under); if (!n) { infostream << "Server: Not finishing digging: Node not found." << " Adding block to emerge queue." << std::endl; m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false); } /* Cheat prevention */ bool is_valid_dig = true; if (enable_anticheat && !isSingleplayer()) { v3s16 nocheat_p = playersao->getNoCheatDigPos(); float nocheat_t = playersao->getNoCheatDigTime(); playersao->noCheatDigEnd(); // If player didn't start digging this, ignore dig if(nocheat_p != p_under) { infostream << "Server: NoCheat: " << player->getName() << " started digging " << PP(nocheat_p) << " and completed digging " << PP(p_under) << "; not digging." << std::endl; is_valid_dig = false; // Call callbacks m_script->on_cheat(playersao, "finished_unknown_dig"); } // Get player's wielded item ItemStack playeritem; InventoryList *mlist = playersao->getInventory()->getList("main"); if(mlist != NULL) playeritem = mlist->getItem(playersao->getWieldIndex()); ToolCapabilities playeritem_toolcap = playeritem.getToolCapabilities(m_itemdef); // Get diggability and expected digging time DigParams params = getDigParams(m_nodedef->get(n).groups, &playeritem_toolcap); // If can't dig, try hand if(!params.diggable) { const ItemDefinition &hand = m_itemdef->get(""); const ToolCapabilities *tp = hand.tool_capabilities; if(tp) params = getDigParams(m_nodedef->get(n).groups, tp); } // If can't dig, ignore dig if(!params.diggable) { infostream << "Server: NoCheat: " << player->getName() << " completed digging " << PP(p_under) << ", which is not diggable with tool. not digging." << std::endl; is_valid_dig = false; // Call callbacks m_script->on_cheat(playersao, "dug_unbreakable"); } // 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) << "too fast; not digging." << std::endl; is_valid_dig = false; // Call callbacks m_script->on_cheat(playersao, "dug_too_fast"); } } /* Actually dig node */ if(is_valid_dig && n.getContent() != CONTENT_IGNORE) { m_script->node_on_dig(p_under, n, playersao); stat.add("dig", player->getName()); stat.add("dig_" + m_nodedef->get(n).name , player->getName()); } v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS)); RemoteClient *client = getClient(peer_id); // Send unusual result (that is, node not being removed) if(m_env->getMap().getNode(p_under).getContent() != CONTENT_AIR) { // Re-send block to revert change on client-side client->SetBlockNotSent(blockpos); } else { client->ResendBlockIfOnWire(blockpos); } m_env->nodeUpdate(p_under, 5, 0); } } // action == 2 /* 3: place block or right-click object */ else if(action == 3) { ItemStack item = playersao->getWieldedItem(); // Reset build time counter if(pointed.type == POINTEDTHING_NODE && item.getDefinition(m_itemdef).type == ITEM_NODE) getClient(peer_id)->m_time_from_building = 0.0; if(pointed.type == POINTEDTHING_OBJECT) { // Right click object // Skip if object has been removed if(pointed_object->m_removed) return; /* android bug - too many actionstream<<player->getName()<<" right-clicks object " <<pointed.object_id<<": " <<pointed_object->getDescription()<<std::endl; */ // Do stuff pointed_object->rightClick(playersao); } else if(m_script->item_OnPlace( item, playersao, pointed)) { // Placement was handled in lua // Apply returned ItemStack if (playersao->setWieldedItem(item)) { SendInventory(playersao); } stat.add("place", player->getName()); //stat.add("place_" + item.name, player->getName()); } // If item has node placement prediction, always send the // blocks to make sure the client knows what exactly happened RemoteClient *client = getClient(peer_id); v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS)); v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS)); if(item.getDefinition(m_itemdef).node_placement_prediction != "") { client->SetBlockNotSent(blockpos); if(blockpos2 != blockpos) { client->SetBlockNotSent(blockpos2); } } else { client->ResendBlockIfOnWire(blockpos); if(blockpos2 != blockpos) { client->ResendBlockIfOnWire(blockpos2); } } m_env->nodeUpdate(p_under, 5, 0); } // action == 3 /* 4: use */ else if(action == 4) { ItemStack item = playersao->getWieldedItem(); actionstream << player->getName() << " uses " << item.name << ", pointing at " << pointed.dump() << std::endl; if(m_script->item_OnUse( item, playersao, pointed)) { // Apply returned ItemStack if (playersao->setWieldedItem(item)) { SendInventory(playersao); } stat.add("use", player->getName()); stat.add("use_" + item.name, player->getName()); m_env->nodeUpdate(p_under, 5, 0); } } // action == 4 /* 5: rightclick air */ else if (action == 5) { ItemStack item = playersao->getWieldedItem(); actionstream << player->getName() << " activates " << item.name << std::endl; if (m_script->item_OnSecondaryUse( item, playersao)) { if( playersao->setWieldedItem(item)) { SendInventory(playersao); } } } /* Catch invalid actions */ else { infostream << "WARNING: Server: Invalid action " << action << std::endl; } }
void Server::handleCommand_ChatMessage(NetworkPacket* pkt) { const auto peer_id = pkt->getPeerId(); auto & packet = *(pkt->packet); auto player = m_env->getPlayer(pkt->getPeerId()); if (!player) { m_con.DisconnectPeer(pkt->getPeerId()); return; } auto playersao = player->getPlayerSAO(); if (!playersao) { m_con.DisconnectPeer(pkt->getPeerId()); return; } std::string message = packet[TOSERVER_CHAT_MESSAGE_DATA].as<std::string>(); // If something goes wrong, this player is to blame RollbackScopeActor rollback_scope(m_rollback, std::string("player:") + player->getName()); // Get player name of this client std::string name = player->getName(); // Run script hook bool ate = m_script->on_chat_message(name, message); // If script ate the message, don't proceed if(ate) return; // Line to send to players std::string line; // Whether to send to other players bool send_to_others = false; // Commands are implemented in Lua, so only catch invalid // commands that were not "eaten" and send an error back if(message[0] == '/') { message = message.substr(1); if(message.length() == 0) line += "-!- Empty command"; else // TODO: str_split(message, ' ')[0] line += "-!- Invalid command: " + message; } else { if(checkPriv(player->getName(), "shout")) { line += "<"; if (name.size() > 25) { auto cutted = name; cutted.resize(25); line += cutted + "."; } else { line += name; } line += "> "; line += message; send_to_others = true; } else line += "-!- You don't have permission to shout."; } if(!line.empty()) { if(send_to_others) { stat.add("chat", name); actionstream << "CHAT: " << line << std::endl; SendChatMessage(PEER_ID_INEXISTENT, line); } else SendChatMessage(peer_id, line); } }
void Server::handleCommand_InventoryAction(NetworkPacket* pkt) { //const auto peer_id = pkt->getPeerId(); auto & packet = *(pkt->packet); auto player = m_env->getPlayer(pkt->getPeerId()); if (!player) { m_con.DisconnectPeer(pkt->getPeerId()); return; } auto playersao = player->getPlayerSAO(); if (!playersao) { m_con.DisconnectPeer(pkt->getPeerId()); return; } std::string datastring; packet[TOSERVER_INVENTORY_ACTION_DATA].convert(datastring); std::istringstream is(datastring, std::ios_base::binary); // Create an action InventoryAction *a = InventoryAction::deSerialize(is); if(a == NULL) { infostream << "TOSERVER_INVENTORY_ACTION: " << "InventoryAction::deSerialize() returned NULL" << std::endl; return; } // If something goes wrong, this player is to blame RollbackScopeActor rollback_scope(m_rollback, std::string("player:") + player->getName()); /* Note: Always set inventory not sent, to repair cases where the client made a bad prediction. */ /* Handle restrictions and special cases of the move action */ if(a->getType() == IACTION_MOVE) { IMoveAction *ma = (IMoveAction*)a; ma->from_inv.applyCurrentPlayer(player->getName()); ma->to_inv.applyCurrentPlayer(player->getName()); setInventoryModified(ma->from_inv, false); setInventoryModified(ma->to_inv, false); bool from_inv_is_current_player = (ma->from_inv.type == InventoryLocation::PLAYER) && (ma->from_inv.name == player->getName()); bool to_inv_is_current_player = (ma->to_inv.type == InventoryLocation::PLAYER) && (ma->to_inv.name == player->getName()); /* Disable moving items out of craftpreview */ if(ma->from_list == "craftpreview") { infostream << "Ignoring IMoveAction from " << (ma->from_inv.dump()) << ":" << ma->from_list << " to " << (ma->to_inv.dump()) << ":" << ma->to_list << " because src is " << ma->from_list << std::endl; delete a; return; } /* Disable moving items into craftresult and craftpreview */ if(ma->to_list == "craftpreview" || ma->to_list == "craftresult") { infostream << "Ignoring IMoveAction from " << (ma->from_inv.dump()) << ":" << ma->from_list << " to " << (ma->to_inv.dump()) << ":" << ma->to_list << " because dst is " << ma->to_list << std::endl; delete a; return; } // Disallow moving items in elsewhere than player's inventory // if not allowed to interact if(!checkPriv(player->getName(), "interact") && (!from_inv_is_current_player || !to_inv_is_current_player)) { infostream << "Cannot move outside of player's inventory: " << "No interact privilege" << std::endl; delete a; return; } } /* Handle restrictions and special cases of the drop action */ else if(a->getType() == IACTION_DROP) { IDropAction *da = (IDropAction*)a; da->from_inv.applyCurrentPlayer(player->getName()); setInventoryModified(da->from_inv, false); /* Disable dropping items out of craftpreview */ if(da->from_list == "craftpreview") { infostream << "Ignoring IDropAction from " << (da->from_inv.dump()) << ":" << da->from_list << " because src is " << da->from_list << std::endl; delete a; return; } // Disallow dropping items if not allowed to interact if(!checkPriv(player->getName(), "interact")) { delete a; return; } stat.add("drop", player->getName()); } /* Handle restrictions and special cases of the craft action */ else if(a->getType() == IACTION_CRAFT) { ICraftAction *ca = (ICraftAction*)a; ca->craft_inv.applyCurrentPlayer(player->getName()); setInventoryModified(ca->craft_inv, false); //bool craft_inv_is_current_player = // (ca->craft_inv.type == InventoryLocation::PLAYER) && // (ca->craft_inv.name == player->getName()); // Disallow crafting if not allowed to interact if(!checkPriv(player->getName(), "interact")) { infostream << "Cannot craft: " << "No interact privilege" << std::endl; delete a; return; } stat.add("craft", player->getName()); } // Do the action a->apply(this, playersao, this); // Eat the action delete a; SendInventory(playersao); }
void Server::handleCommand_PlayerPos(NetworkPacket* pkt) { const auto peer_id = pkt->getPeerId(); auto & packet = *(pkt->packet); auto player = m_env->getPlayer(pkt->getPeerId()); if (!player) { m_con.DisconnectPeer(pkt->getPeerId()); return; } auto playersao = player->getPlayerSAO(); if (!playersao) { m_con.DisconnectPeer(pkt->getPeerId()); return; } // If player is dead we don't care of this packet if (player->hp != 0 && playersao->m_ms_from_last_respawn > 1000) player->setPosition(packet[TOSERVER_PLAYERPOS_POSITION].as<v3f>()); player->setSpeed(packet[TOSERVER_PLAYERPOS_SPEED].as<v3f>()); player->setPitch(modulo360f(packet[TOSERVER_PLAYERPOS_PITCH].as<f32>())); player->setYaw(modulo360f(packet[TOSERVER_PLAYERPOS_YAW].as<f32>())); u32 keyPressed = packet[TOSERVER_PLAYERPOS_KEY_PRESSED].as<u32>(); player->keyPressed = keyPressed; { std::lock_guard<Mutex> lock(player->control_mutex); player->control.up = (bool)(keyPressed & 1); player->control.down = (bool)(keyPressed & 2); player->control.left = (bool)(keyPressed & 4); player->control.right = (bool)(keyPressed & 8); player->control.jump = (bool)(keyPressed & 16); player->control.aux1 = (bool)(keyPressed & 32); player->control.sneak = (bool)(keyPressed & 64); player->control.LMB = (bool)(keyPressed & 128); player->control.RMB = (bool)(keyPressed & 256); } auto old_pos = playersao->m_last_good_position; if(playersao->checkMovementCheat()) { // Call callbacks m_script->on_cheat(playersao, "moved_too_fast"); SendMovePlayer(peer_id); } else if (playersao->m_ms_from_last_respawn > 3000) { auto dist = (old_pos / BS).getDistanceFrom(playersao->m_last_good_position / BS); if (dist) stat.add("move", playersao->getPlayer()->getName(), dist); } if (playersao->m_ms_from_last_respawn > 2000) { auto obj = playersao; // copypasted from server step: auto uptime = m_uptime.get(); if (!obj->m_uptime_last) // not very good place, but minimum modifications obj->m_uptime_last = uptime - 0.1; if (uptime - obj->m_uptime_last > 0.5) { obj->step(uptime - obj->m_uptime_last, true); //todo: maybe limit count per time obj->m_uptime_last = uptime; } } /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to " <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")" <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/ }