This commit is contained in:
HybridDog 2024-12-31 15:02:11 +01:00 committed by GitHub
commit cb421cfafb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 63 additions and 88 deletions

View File

@ -776,17 +776,20 @@ enum ToServerCommand : u16
TOSERVER_INTERACT = 0x39,
/*
[0] u16 command
[2] u8 action
[3] u16 item
[5] u32 length of the next item
[9] serialized PointedThing
actions:
0: start digging (from undersurface) or use
1: stop digging (all parameters ignored)
2: digging completed
3: place block or item (to abovesurface)
4: use item
u16 command
u8 action (InteractAction)
u16 item
u32 length of the next item
u8[length] serialized PointedThing
v3s32 player position multiplied by 100 and converted to integers
v3s32 player speed multiplied by 100 and converted to integers
s32 player pitch multiplied by 100 and converted to an integer
s32 player yaw multiplied by 100 and converted to an integer
u32 keyPressed
u8 fov
u8 wanted drawing range
optional:
u8 flags; it is 0x01 if the camera is inverted
*/
TOSERVER_REMOVED_SOUNDS = 0x3a,

View File

@ -878,15 +878,6 @@ static inline void getWieldedItem(const PlayerSAO *playersao, std::optional<Item
void Server::handleCommand_Interact(NetworkPacket *pkt)
{
/*
[0] u16 command
[2] u8 action
[3] u16 item
[5] u32 length of the next item (plen)
[9] serialized PointedThing
[9 + plen] player position information
*/
InteractAction action;
u16 item_i;
@ -923,13 +914,7 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
if (playersao->isDead()) {
actionstream << "Server: " << player->getName()
<< " tried to interact while dead; ignoring." << std::endl;
if (pointed.type == POINTEDTHING_NODE) {
// Re-send block to revert change on client-side
RemoteClient *client = getClient(peer_id);
v3s16 blockpos = getNodeBlockPos(pointed.node_undersurface);
client->SetBlockNotSent(blockpos);
}
// Call callbacks
getClient(peer_id)->respondToInteraction(action, pointed, false);
m_script->on_cheat(playersao, "interacted_while_dead");
return;
}
@ -969,22 +954,7 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
if (!checkPriv(player->getName(), "interact")) {
actionstream << player->getName() << " attempted to interact with " <<
pointed.dump() << " without 'interact' privilege" << std::endl;
if (pointed.type != POINTEDTHING_NODE)
return;
// Re-send block to revert change on client-side
RemoteClient *client = getClient(peer_id);
// Digging completed -> under
if (action == INTERACT_DIGGING_COMPLETED) {
v3s16 blockpos = getNodeBlockPos(pointed.node_undersurface);
client->SetBlockNotSent(blockpos);
}
// Placement -> above
else if (action == INTERACT_PLACE) {
v3s16 blockpos = getNodeBlockPos(pointed.node_abovesurface);
client->SetBlockNotSent(blockpos);
}
getClient(peer_id)->respondToInteraction(action, pointed, false);
return;
}
@ -1012,12 +982,7 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
float d = playersao->getEyePosition().getDistanceFrom(target_pos);
if (!checkInteractDistance(player, d, pointed.dump())) {
if (pointed.type == POINTEDTHING_NODE) {
// Re-send block to revert change on client-side
RemoteClient *client = getClient(peer_id);
v3s16 blockpos = getNodeBlockPos(pointed.node_undersurface);
client->SetBlockNotSent(blockpos);
}
getClient(peer_id)->respondToInteraction(action, pointed, false);
return;
}
}
@ -1170,14 +1135,12 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
if (is_valid_dig && n.getContent() != CONTENT_IGNORE)
m_script->node_on_dig(p_under, n, playersao);
v3s16 blockpos = getNodeBlockPos(p_under);
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);
// For whatever reason we assume that the client always predicts that a
// dug node is air irrespective of the node's node_dig_prediction
bool prediction_success =
m_env->getMap().getNode(p_under).getContent() == CONTENT_AIR;
getClient(peer_id)->respondToInteraction(action, pointed,
prediction_success);
return;
} // action == INTERACT_DIGGING_COMPLETED
@ -1221,24 +1184,11 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
SendInventory(player, true);
}
if (pointed.type != POINTEDTHING_NODE)
return;
// 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(pointed.node_abovesurface);
v3s16 blockpos2 = getNodeBlockPos(pointed.node_undersurface);
if (had_prediction) {
client->SetBlockNotSent(blockpos);
if (blockpos2 != blockpos)
client->SetBlockNotSent(blockpos2);
} else {
client->ResendBlockIfOnWire(blockpos);
if (blockpos2 != blockpos)
client->ResendBlockIfOnWire(blockpos2);
}
// Since we do not known if the client has predicted the node at
// pointed.above or pointed.under,
// we assume that a prediction is always wrong.
getClient(peer_id)->respondToInteraction(action, pointed,
!had_prediction);
return;
} // action == INTERACT_PLACE

View File

@ -65,14 +65,6 @@ RemoteClient::RemoteClient() :
{
}
void RemoteClient::ResendBlockIfOnWire(v3s16 p)
{
// if this block is on wire, mark it for sending again as soon as possible
if (m_blocks_sending.find(p) != m_blocks_sending.end()) {
SetBlockNotSent(p);
}
}
static LuaEntitySAO *getAttachedObject(PlayerSAO *sao, ServerEnvironment *env)
{
ServerActiveObject *ao = sao;
@ -457,6 +449,30 @@ void RemoteClient::SetBlocksNotSent(const std::vector<v3s16> &blocks)
}
}
void RemoteClient::respondToInteraction(InteractAction action,
const PointedThing &pointed, bool prediction_success)
{
if ((action != INTERACT_PLACE && action != INTERACT_DIGGING_COMPLETED)
|| pointed.type != POINTEDTHING_NODE)
// The client has not predicted not node changes
return;
// The client may have an outdated mapblock if the placement or dig
// prediction was wrong or if an old mapblock is still being sent to it.
v3s16 blockpos = getNodeBlockPos(pointed.node_undersurface);
if (!prediction_success
|| m_blocks_sending.find(blockpos) != m_blocks_sending.end()) {
SetBlockNotSent(blockpos);
}
if (action != INTERACT_PLACE)
return;
v3s16 blockpos2 = getNodeBlockPos(pointed.node_abovesurface);
if (blockpos2 != blockpos && (!prediction_success
|| m_blocks_sending.find(blockpos2) != m_blocks_sending.end())) {
SetBlockNotSent(blockpos2);
}
}
void RemoteClient::notifyEvent(ClientStateEvent event)
{
std::ostringstream myerror;

View File

@ -13,6 +13,7 @@
#include "porting.h"
#include "threading/mutex_auto_lock.h"
#include "clientdynamicinfo.h"
#include "util/pointedthing.h"
#include <list>
#include <vector>
@ -255,12 +256,17 @@ public:
void SetBlocksNotSent(const std::vector<v3s16> &blocks);
/**
* tell client about this block being modified right now.
* this information is required to requeue the block in case it's "on wire"
* while modification is processed by server
* @param p position of modified block
* Trigger block sending to undo client-side predicted node changes
*
* \param action The interact action to determine which predictions the
* client could have made
* \param pointed The positions where the client has interacted
* \param prediction_success If true, assume that the client has made a
* correct prediction and send the mapblock only if an outdated mapblock
* is currently "on wire", which can erroneously override the prediction
*/
void ResendBlockIfOnWire(v3s16 p);
void respondToInteraction(InteractAction action,
const PointedThing &pointed, bool prediction_success);
u32 getSendingCount() const { return m_blocks_sending.size(); }