Breath cheat fix: server side
Breath is now handled server side. Changing this behaviour required some modifications to core: * Ignore TOSERVER_BREATH package, marking it as obsolete * Clients doesn't send the breath to server anymore * Use PlayerSAO pointer instead of peer_id in Server::SendPlayerBreath to prevent a useless lookup (little perf gain) * drop a useless static_cast in emergePlayer
This commit is contained in:
parent
a1346c916e
commit
52ba1f867e
|
@ -499,7 +499,8 @@ void Client::step(float dtime)
|
|||
m_client_event_queue.push(event);
|
||||
}
|
||||
}
|
||||
else if(event.type == CEE_PLAYER_BREATH) {
|
||||
// Protocol v29 or greater obsoleted this event
|
||||
else if (event.type == CEE_PLAYER_BREATH && m_proto_ver < 29) {
|
||||
u16 breath = event.player_breath.amount;
|
||||
sendBreath(breath);
|
||||
}
|
||||
|
@ -1270,6 +1271,10 @@ void Client::sendBreath(u16 breath)
|
|||
{
|
||||
DSTACK(FUNCTION_NAME);
|
||||
|
||||
// Protocol v29 make this obsolete
|
||||
if (m_proto_ver >= 29)
|
||||
return;
|
||||
|
||||
NetworkPacket pkt(TOSERVER_BREATH, sizeof(u16));
|
||||
pkt << breath;
|
||||
Send(&pkt);
|
||||
|
|
|
@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "serialization.h" // For compressZlib
|
||||
#include "tool.h" // For ToolCapabilities
|
||||
#include "gamedef.h"
|
||||
#include "nodedef.h"
|
||||
#include "remoteplayer.h"
|
||||
#include "server.h"
|
||||
#include "scripting_game.h"
|
||||
|
@ -940,8 +941,35 @@ bool PlayerSAO::isAttached()
|
|||
|
||||
void PlayerSAO::step(float dtime, bool send_recommended)
|
||||
{
|
||||
if(!m_properties_sent)
|
||||
{
|
||||
if (m_drowning_interval.step(dtime, 2.0)) {
|
||||
// get head position
|
||||
v3s16 p = floatToInt(m_base_position + v3f(0, BS * 1.6, 0), BS);
|
||||
MapNode n = m_env->getMap().getNodeNoEx(p);
|
||||
const ContentFeatures &c = ((Server*) m_env->getGameDef())->ndef()->get(n);
|
||||
// If node generates drown
|
||||
if (c.drowning > 0) {
|
||||
if (m_hp > 0 && m_breath > 0)
|
||||
setBreath(m_breath - 1);
|
||||
|
||||
// No more breath, damage player
|
||||
if (m_breath == 0) {
|
||||
setHP(m_hp - c.drowning);
|
||||
((Server*) m_env->getGameDef())->SendPlayerHPOrDie(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_breathing_interval.step(dtime, 0.5)) {
|
||||
// get head position
|
||||
v3s16 p = floatToInt(m_base_position + v3f(0, BS * 1.6, 0), BS);
|
||||
MapNode n = m_env->getMap().getNodeNoEx(p);
|
||||
const ContentFeatures &c = ((Server*) m_env->getGameDef())->ndef()->get(n);
|
||||
// If player is alive & no drowning, breath
|
||||
if (m_hp > 0 && c.drowning == 0)
|
||||
setBreath(m_breath + 1);
|
||||
}
|
||||
|
||||
if (!m_properties_sent) {
|
||||
m_properties_sent = true;
|
||||
std::string str = getPropertyPacket();
|
||||
// create message and add to list
|
||||
|
@ -1237,12 +1265,15 @@ void PlayerSAO::setHP(s16 hp)
|
|||
m_properties_sent = false;
|
||||
}
|
||||
|
||||
void PlayerSAO::setBreath(const u16 breath)
|
||||
void PlayerSAO::setBreath(const u16 breath, bool send)
|
||||
{
|
||||
if (m_player && breath != m_breath)
|
||||
m_player->setDirty(true);
|
||||
|
||||
m_breath = breath;
|
||||
m_breath = MYMIN(breath, PLAYER_MAX_BREATH);
|
||||
|
||||
if (send)
|
||||
((Server *) m_env->getGameDef())->SendPlayerBreath(this);
|
||||
}
|
||||
|
||||
void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
|
||||
|
|
|
@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#ifndef CONTENT_SAO_HEADER
|
||||
#define CONTENT_SAO_HEADER
|
||||
|
||||
#include <util/numeric.h>
|
||||
#include "serverobject.h"
|
||||
#include "itemgroup.h"
|
||||
#include "object_properties.h"
|
||||
|
@ -232,7 +233,7 @@ public:
|
|||
void setHPRaw(s16 hp) { m_hp = hp; }
|
||||
s16 readDamage();
|
||||
u16 getBreath() const { return m_breath; }
|
||||
void setBreath(const u16 breath);
|
||||
void setBreath(const u16 breath, bool send = true);
|
||||
void setArmorGroups(const ItemGroupList &armor_groups);
|
||||
ItemGroupList getArmorGroups();
|
||||
void setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop);
|
||||
|
@ -339,6 +340,10 @@ private:
|
|||
v3s16 m_nocheat_dig_pos;
|
||||
float m_nocheat_dig_time;
|
||||
|
||||
// Timers
|
||||
IntervalLimiter m_breathing_interval;
|
||||
IntervalLimiter m_drowning_interval;
|
||||
|
||||
int m_wield_index;
|
||||
bool m_position_not_sent;
|
||||
ItemGroupList m_armor_groups;
|
||||
|
|
|
@ -2511,54 +2511,54 @@ void ClientEnvironment::step(float dtime)
|
|||
}
|
||||
}
|
||||
|
||||
// Protocol v29 make this behaviour obsolete
|
||||
if (((Client*) getGameDef())->getProtoVersion() < 29) {
|
||||
/*
|
||||
Drowning
|
||||
*/
|
||||
if(m_drowning_interval.step(dtime, 2.0))
|
||||
{
|
||||
if (m_drowning_interval.step(dtime, 2.0)) {
|
||||
v3f pf = lplayer->getPosition();
|
||||
|
||||
// head
|
||||
v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
|
||||
v3s16 p = floatToInt(pf + v3f(0, BS * 1.6, 0), BS);
|
||||
MapNode n = m_map->getNodeNoEx(p);
|
||||
ContentFeatures c = m_gamedef->ndef()->get(n);
|
||||
u8 drowning_damage = c.drowning;
|
||||
if(drowning_damage > 0 && lplayer->hp > 0){
|
||||
if (drowning_damage > 0 && lplayer->hp > 0) {
|
||||
u16 breath = lplayer->getBreath();
|
||||
if(breath > 10){
|
||||
if (breath > 10) {
|
||||
breath = 11;
|
||||
}
|
||||
if(breath > 0){
|
||||
if (breath > 0) {
|
||||
breath -= 1;
|
||||
}
|
||||
lplayer->setBreath(breath);
|
||||
updateLocalPlayerBreath(breath);
|
||||
}
|
||||
|
||||
if(lplayer->getBreath() == 0 && drowning_damage > 0){
|
||||
if (lplayer->getBreath() == 0 && drowning_damage > 0) {
|
||||
damageLocalPlayer(drowning_damage, true);
|
||||
}
|
||||
}
|
||||
if(m_breathing_interval.step(dtime, 0.5))
|
||||
{
|
||||
if (m_breathing_interval.step(dtime, 0.5)) {
|
||||
v3f pf = lplayer->getPosition();
|
||||
|
||||
// head
|
||||
v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
|
||||
v3s16 p = floatToInt(pf + v3f(0, BS * 1.6, 0), BS);
|
||||
MapNode n = m_map->getNodeNoEx(p);
|
||||
ContentFeatures c = m_gamedef->ndef()->get(n);
|
||||
if (!lplayer->hp){
|
||||
if (!lplayer->hp) {
|
||||
lplayer->setBreath(11);
|
||||
}
|
||||
else if(c.drowning == 0){
|
||||
} else if (c.drowning == 0) {
|
||||
u16 breath = lplayer->getBreath();
|
||||
if(breath <= 10){
|
||||
if (breath <= 10) {
|
||||
breath += 1;
|
||||
lplayer->setBreath(breath);
|
||||
updateLocalPlayerBreath(breath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update lighting on local player (used for wield item)
|
||||
u32 day_night_ratio = getDayNightRatio();
|
||||
|
|
|
@ -193,7 +193,7 @@ const ServerCommandFactory serverCommandFactoryTable[TOSERVER_NUM_MSG_TYPES] =
|
|||
null_command_factory, // 0x3f
|
||||
{ "TOSERVER_REQUEST_MEDIA", 1, true }, // 0x40
|
||||
{ "TOSERVER_RECEIVED_MEDIA", 1, true }, // 0x41
|
||||
{ "TOSERVER_BREATH", 0, true }, // 0x42
|
||||
null_command_factory, // 0x42 old TOSERVER_BREATH. Ignored by servers
|
||||
{ "TOSERVER_CLIENT_READY", 0, true }, // 0x43
|
||||
null_command_factory, // 0x44
|
||||
null_command_factory, // 0x45
|
||||
|
|
|
@ -138,9 +138,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
Add nodedef v3 - connected nodeboxes
|
||||
PROTOCOL_VERSION 28:
|
||||
CPT2_MESHOPTIONS
|
||||
PROTOCOL_VERSION 29:
|
||||
Server doesn't accept TOSERVER_BREATH anymore
|
||||
*/
|
||||
|
||||
#define LATEST_PROTOCOL_VERSION 28
|
||||
#define LATEST_PROTOCOL_VERSION 29
|
||||
|
||||
// Server's supported network protocol range
|
||||
#define SERVER_PROTOCOL_VERSION_MIN 13
|
||||
|
@ -833,7 +835,7 @@ enum ToServerCommand
|
|||
<no payload data>
|
||||
*/
|
||||
|
||||
TOSERVER_BREATH = 0x42,
|
||||
TOSERVER_BREATH = 0x42, // Obsolete
|
||||
/*
|
||||
u16 breath
|
||||
*/
|
||||
|
|
|
@ -90,7 +90,7 @@ const ToServerCommandHandler toServerCommandTable[TOSERVER_NUM_MSG_TYPES] =
|
|||
null_command_handler, // 0x3f
|
||||
{ "TOSERVER_REQUEST_MEDIA", TOSERVER_STATE_STARTUP, &Server::handleCommand_RequestMedia }, // 0x40
|
||||
{ "TOSERVER_RECEIVED_MEDIA", TOSERVER_STATE_STARTUP, &Server::handleCommand_ReceivedMedia }, // 0x41
|
||||
{ "TOSERVER_BREATH", TOSERVER_STATE_INGAME, &Server::handleCommand_Breath }, // 0x42
|
||||
{ "TOSERVER_BREATH", TOSERVER_STATE_INGAME, &Server::handleCommand_Deprecated }, // 0x42 Old breath model which is now deprecated for anticheating
|
||||
{ "TOSERVER_CLIENT_READY", TOSERVER_STATE_STARTUP, &Server::handleCommand_ClientReady }, // 0x43
|
||||
null_command_handler, // 0x44
|
||||
null_command_handler, // 0x45
|
||||
|
|
|
@ -1136,46 +1136,6 @@ void Server::handleCommand_Damage(NetworkPacket* pkt)
|
|||
}
|
||||
}
|
||||
|
||||
void Server::handleCommand_Breath(NetworkPacket* pkt)
|
||||
{
|
||||
u16 breath;
|
||||
|
||||
*pkt >> breath;
|
||||
|
||||
RemotePlayer *player = m_env->getPlayer(pkt->getPeerId());
|
||||
|
||||
if (player == NULL) {
|
||||
errorstream << "Server::ProcessData(): Canceling: "
|
||||
"No player for peer_id=" << pkt->getPeerId()
|
||||
<< " disconnecting peer!" << std::endl;
|
||||
m_con.DisconnectPeer(pkt->getPeerId());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
PlayerSAO *playersao = player->getPlayerSAO();
|
||||
if (playersao == NULL) {
|
||||
errorstream << "Server::ProcessData(): Canceling: "
|
||||
"No player object for peer_id=" << pkt->getPeerId()
|
||||
<< " disconnecting peer!" << std::endl;
|
||||
m_con.DisconnectPeer(pkt->getPeerId());
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If player is dead, we don't need to update the breath
|
||||
* He is dead !
|
||||
*/
|
||||
if (playersao->isDead()) {
|
||||
verbosestream << "TOSERVER_BREATH: " << player->getName()
|
||||
<< " is dead. Ignoring packet";
|
||||
return;
|
||||
}
|
||||
|
||||
playersao->setBreath(breath);
|
||||
SendPlayerBreath(pkt->getPeerId());
|
||||
}
|
||||
|
||||
void Server::handleCommand_Password(NetworkPacket* pkt)
|
||||
{
|
||||
if (pkt->getSize() != PASSWORD_SIZE * 2)
|
||||
|
|
|
@ -148,7 +148,7 @@ void RemotePlayer::deSerialize(std::istream &is, const std::string &playername,
|
|||
} catch (SettingNotFoundException &e) {}
|
||||
|
||||
try {
|
||||
sao->setBreath(args.getS32("breath"));
|
||||
sao->setBreath(args.getS32("breath"), false);
|
||||
} catch (SettingNotFoundException &e) {}
|
||||
}
|
||||
|
||||
|
|
|
@ -1152,13 +1152,8 @@ int ObjectRef::l_set_breath(lua_State *L)
|
|||
PlayerSAO* co = getplayersao(ref);
|
||||
if (co == NULL) return 0;
|
||||
u16 breath = luaL_checknumber(L, 2);
|
||||
// Do it
|
||||
co->setBreath(breath);
|
||||
|
||||
// If the object is a player sent the breath to client
|
||||
if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
|
||||
getServer(L)->SendPlayerBreath(((PlayerSAO*)co)->getPeerID());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1076,8 +1076,7 @@ PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
|
|||
}
|
||||
m_clients.unlock();
|
||||
|
||||
RemotePlayer *player =
|
||||
static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
|
||||
RemotePlayer *player = m_env->getPlayer(playername.c_str());
|
||||
|
||||
// If failed, cancel
|
||||
if ((playersao == NULL) || (player == NULL)) {
|
||||
|
@ -1113,7 +1112,7 @@ PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
|
|||
SendPlayerHPOrDie(playersao);
|
||||
|
||||
// Send Breath
|
||||
SendPlayerBreath(peer_id);
|
||||
SendPlayerBreath(playersao);
|
||||
|
||||
// Show death screen if necessary
|
||||
if (playersao->isDead())
|
||||
|
@ -1857,14 +1856,13 @@ void Server::SendPlayerHP(u16 peer_id)
|
|||
playersao->m_messages_out.push(aom);
|
||||
}
|
||||
|
||||
void Server::SendPlayerBreath(u16 peer_id)
|
||||
void Server::SendPlayerBreath(PlayerSAO *sao)
|
||||
{
|
||||
DSTACK(FUNCTION_NAME);
|
||||
PlayerSAO *playersao = getPlayerSAO(peer_id);
|
||||
assert(playersao);
|
||||
assert(sao);
|
||||
|
||||
m_script->player_event(playersao, "breath_changed");
|
||||
SendBreath(peer_id, playersao->getBreath());
|
||||
m_script->player_event(sao, "breath_changed");
|
||||
SendBreath(sao->getPeerID(), sao->getBreath());
|
||||
}
|
||||
|
||||
void Server::SendMovePlayer(u16 peer_id)
|
||||
|
@ -2565,7 +2563,6 @@ void Server::RespawnPlayer(u16 peer_id)
|
|||
}
|
||||
|
||||
SendPlayerHP(peer_id);
|
||||
SendPlayerBreath(peer_id);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -180,7 +180,6 @@ public:
|
|||
void handleCommand_InventoryAction(NetworkPacket* pkt);
|
||||
void handleCommand_ChatMessage(NetworkPacket* pkt);
|
||||
void handleCommand_Damage(NetworkPacket* pkt);
|
||||
void handleCommand_Breath(NetworkPacket* pkt);
|
||||
void handleCommand_Password(NetworkPacket* pkt);
|
||||
void handleCommand_PlayerItem(NetworkPacket* pkt);
|
||||
void handleCommand_Respawn(NetworkPacket* pkt);
|
||||
|
@ -358,7 +357,7 @@ public:
|
|||
void printToConsoleOnly(const std::string &text);
|
||||
|
||||
void SendPlayerHPOrDie(PlayerSAO *player);
|
||||
void SendPlayerBreath(u16 peer_id);
|
||||
void SendPlayerBreath(PlayerSAO *sao);
|
||||
void SendInventory(PlayerSAO* playerSAO);
|
||||
void SendMovePlayer(u16 peer_id);
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ void TestPlayer::testSave(IGameDef *gamedef)
|
|||
PlayerSAO sao(NULL, 1, false);
|
||||
sao.initialize(&rplayer, std::set<std::string>());
|
||||
rplayer.setPlayerSAO(&sao);
|
||||
sao.setBreath(10);
|
||||
sao.setBreath(10, false);
|
||||
sao.setHPRaw(8);
|
||||
sao.setYaw(0.1f);
|
||||
sao.setPitch(0.6f);
|
||||
|
@ -64,7 +64,7 @@ void TestPlayer::testLoad(IGameDef *gamedef)
|
|||
PlayerSAO sao(NULL, 1, false);
|
||||
sao.initialize(&rplayer, std::set<std::string>());
|
||||
rplayer.setPlayerSAO(&sao);
|
||||
sao.setBreath(10);
|
||||
sao.setBreath(10, false);
|
||||
sao.setHPRaw(8);
|
||||
sao.setYaw(0.1f);
|
||||
sao.setPitch(0.6f);
|
||||
|
|
Loading…
Reference in New Issue