mirror of
https://github.com/luanti-org/luanti.git
synced 2025-07-27 17:28:41 +00:00
Merge remote-tracking branch 'upstream/master' into Visuals-Vol-2
This commit is contained in:
commit
fa212d19f7
572 changed files with 71629 additions and 67352 deletions
|
@ -83,7 +83,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
|
|||
{ "TOCLIENT_MOVEMENT", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_Movement }, // 0x45
|
||||
{ "TOCLIENT_SPAWN_PARTICLE", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_SpawnParticle }, // 0x46
|
||||
{ "TOCLIENT_ADD_PARTICLESPAWNER", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_AddParticleSpawner }, // 0x47
|
||||
null_command_handler,
|
||||
{ "TOCLIENT_CAMERA", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_Camera }, // 0x48
|
||||
{ "TOCLIENT_HUDADD", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_HudAdd }, // 0x49
|
||||
{ "TOCLIENT_HUDRM", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_HudRemove }, // 0x4a
|
||||
{ "TOCLIENT_HUDCHANGE", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_HudChange }, // 0x4b
|
||||
|
|
|
@ -132,17 +132,10 @@ void Client::handleCommand_AuthAccept(NetworkPacket* pkt)
|
|||
{
|
||||
deleteAuthData();
|
||||
|
||||
v3f playerpos;
|
||||
*pkt >> playerpos >> m_map_seed >> m_recommended_send_interval
|
||||
v3f unused;
|
||||
*pkt >> unused >> m_map_seed >> m_recommended_send_interval
|
||||
>> m_sudo_auth_methods;
|
||||
|
||||
playerpos -= v3f(0, BS / 2, 0);
|
||||
|
||||
// Set player position
|
||||
LocalPlayer *player = m_env.getLocalPlayer();
|
||||
assert(player != NULL);
|
||||
player->setPosition(playerpos);
|
||||
|
||||
infostream << "Client: received map seed: " << m_map_seed << std::endl;
|
||||
infostream << "Client: received recommended send interval "
|
||||
<< m_recommended_send_interval<<std::endl;
|
||||
|
@ -176,6 +169,7 @@ void Client::handleCommand_AcceptSudoMode(NetworkPacket* pkt)
|
|||
// reset again
|
||||
m_chosen_auth_mech = AUTH_MECHANISM_NONE;
|
||||
}
|
||||
|
||||
void Client::handleCommand_DenySudoMode(NetworkPacket* pkt)
|
||||
{
|
||||
ChatMessage *chatMessage = new ChatMessage(CHATMESSAGE_TYPE_SYSTEM,
|
||||
|
@ -193,8 +187,8 @@ void Client::handleCommand_AccessDenied(NetworkPacket* pkt)
|
|||
m_access_denied = true;
|
||||
|
||||
if (pkt->getCommand() != TOCLIENT_ACCESS_DENIED) {
|
||||
// Legacy code from 0.4.12 and older but is still used
|
||||
// in some places of the server code
|
||||
// Servers older than 5.6 still send TOCLIENT_ACCESS_DENIED_LEGACY sometimes.
|
||||
// see commit a65f6f07f3a5601207b790edcc8cc945133112f7
|
||||
if (pkt->getSize() >= 2) {
|
||||
std::wstring wide_reason;
|
||||
*pkt >> wide_reason;
|
||||
|
@ -231,9 +225,6 @@ void Client::handleCommand_AccessDenied(NetworkPacket* pkt)
|
|||
|
||||
void Client::handleCommand_RemoveNode(NetworkPacket* pkt)
|
||||
{
|
||||
if (pkt->getSize() < 6)
|
||||
return;
|
||||
|
||||
v3s16 p;
|
||||
*pkt >> p;
|
||||
removeNode(p);
|
||||
|
@ -241,22 +232,19 @@ void Client::handleCommand_RemoveNode(NetworkPacket* pkt)
|
|||
|
||||
void Client::handleCommand_AddNode(NetworkPacket* pkt)
|
||||
{
|
||||
if (pkt->getSize() < 6 + MapNode::serializedLength(m_server_ser_ver))
|
||||
return;
|
||||
|
||||
v3s16 p;
|
||||
*pkt >> p;
|
||||
|
||||
auto *ptr = reinterpret_cast<const u8*>(pkt->getRemainingString());
|
||||
pkt->skip(MapNode::serializedLength(m_server_ser_ver)); // performs length check
|
||||
|
||||
MapNode n;
|
||||
n.deSerialize(pkt->getU8Ptr(6), m_server_ser_ver);
|
||||
n.deSerialize(ptr, m_server_ser_ver);
|
||||
|
||||
bool remove_metadata = true;
|
||||
u32 index = 6 + MapNode::serializedLength(m_server_ser_ver);
|
||||
if ((pkt->getSize() >= index + 1) && pkt->getU8(index)) {
|
||||
remove_metadata = false;
|
||||
}
|
||||
bool keep_metadata;
|
||||
*pkt >> keep_metadata;
|
||||
|
||||
addNode(p, n, remove_metadata);
|
||||
addNode(p, n, !keep_metadata);
|
||||
}
|
||||
|
||||
void Client::handleCommand_NodemetaChanged(NetworkPacket *pkt)
|
||||
|
@ -272,7 +260,7 @@ void Client::handleCommand_NodemetaChanged(NetworkPacket *pkt)
|
|||
meta_updates_list.deSerialize(sstr, m_itemdef, true);
|
||||
|
||||
Map &map = m_env.getMap();
|
||||
for (NodeMetadataMap::const_iterator i = meta_updates_list.begin();
|
||||
for (auto i = meta_updates_list.begin();
|
||||
i != meta_updates_list.end(); ++i) {
|
||||
v3s16 pos = i->first;
|
||||
|
||||
|
@ -294,7 +282,7 @@ void Client::handleCommand_BlockData(NetworkPacket* pkt)
|
|||
v3s16 p;
|
||||
*pkt >> p;
|
||||
|
||||
std::string datastring(pkt->getString(6), pkt->getSize() - 6);
|
||||
std::string datastring(pkt->getRemainingString(), pkt->getRemainingBytes());
|
||||
std::istringstream istr(datastring, std::ios_base::binary);
|
||||
|
||||
MapSector *sector;
|
||||
|
@ -358,46 +346,15 @@ void Client::handleCommand_TimeOfDay(NetworkPacket* pkt)
|
|||
return;
|
||||
|
||||
u16 time_of_day;
|
||||
|
||||
*pkt >> time_of_day;
|
||||
|
||||
time_of_day = time_of_day % 24000;
|
||||
float time_speed = 0;
|
||||
|
||||
if (pkt->getSize() >= 2 + 4) {
|
||||
*pkt >> time_speed;
|
||||
}
|
||||
else {
|
||||
// Old message; try to approximate speed of time by ourselves
|
||||
float time_of_day_f = (float)time_of_day / 24000.0f;
|
||||
float tod_diff_f = 0;
|
||||
|
||||
if (time_of_day_f < 0.2 && m_last_time_of_day_f > 0.8)
|
||||
tod_diff_f = time_of_day_f - m_last_time_of_day_f + 1.0f;
|
||||
else
|
||||
tod_diff_f = time_of_day_f - m_last_time_of_day_f;
|
||||
|
||||
m_last_time_of_day_f = time_of_day_f;
|
||||
float time_diff = m_time_of_day_update_timer;
|
||||
m_time_of_day_update_timer = 0;
|
||||
|
||||
if (m_time_of_day_set) {
|
||||
time_speed = (3600.0f * 24.0f) * tod_diff_f / time_diff;
|
||||
infostream << "Client: Measured time_of_day speed (old format): "
|
||||
<< time_speed << " tod_diff_f=" << tod_diff_f
|
||||
<< " time_diff=" << time_diff << std::endl;
|
||||
}
|
||||
}
|
||||
float time_speed;
|
||||
*pkt >> time_speed;
|
||||
|
||||
// Update environment
|
||||
m_env.setTimeOfDay(time_of_day);
|
||||
m_env.setTimeOfDaySpeed(time_speed);
|
||||
m_time_of_day_set = true;
|
||||
|
||||
//u32 dr = m_env.getDayNightRatio();
|
||||
//infostream << "Client: time_of_day=" << time_of_day
|
||||
// << " time_speed=" << time_speed
|
||||
// << " dr=" << dr << std::endl;
|
||||
}
|
||||
|
||||
void Client::handleCommand_ChatMessage(NetworkPacket *pkt)
|
||||
|
@ -611,7 +568,7 @@ void Client::handleCommand_MovePlayer(NetworkPacket* pkt)
|
|||
player->setPosition(pos);
|
||||
|
||||
infostream << "Client got TOCLIENT_MOVE_PLAYER"
|
||||
<< " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
|
||||
<< " pos=" << pos
|
||||
<< " pitch=" << pitch
|
||||
<< " yaw=" << yaw
|
||||
<< std::endl;
|
||||
|
@ -649,10 +606,6 @@ void Client::handleCommand_DeathScreenLegacy(NetworkPacket* pkt)
|
|||
|
||||
void Client::handleCommand_AnnounceMedia(NetworkPacket* pkt)
|
||||
{
|
||||
u16 num_files;
|
||||
|
||||
*pkt >> num_files;
|
||||
|
||||
infostream << "Client: Received media announcement: packet size: "
|
||||
<< pkt->getSize() << std::endl;
|
||||
|
||||
|
@ -662,9 +615,7 @@ void Client::handleCommand_AnnounceMedia(NetworkPacket* pkt)
|
|||
"we already saw another announcement" :
|
||||
"all media has been received already";
|
||||
errorstream << "Client: Received media announcement but "
|
||||
<< problem << "! "
|
||||
<< " files=" << num_files
|
||||
<< " size=" << pkt->getSize() << std::endl;
|
||||
<< problem << "!" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -672,16 +623,36 @@ void Client::handleCommand_AnnounceMedia(NetworkPacket* pkt)
|
|||
// updating content definitions
|
||||
sanity_check(!m_mesh_update_manager->isRunning());
|
||||
|
||||
for (u16 i = 0; i < num_files; i++) {
|
||||
if (m_proto_ver >= 48) {
|
||||
// compressed table of media names
|
||||
std::vector<std::string> names;
|
||||
{
|
||||
std::istringstream iss(pkt->readLongString(), std::ios::binary);
|
||||
std::stringstream ss(std::ios::in | std::ios::out | std::ios::binary);
|
||||
decompressZstd(iss, ss);
|
||||
names = deserializeString16Array(ss);
|
||||
}
|
||||
|
||||
// raw hash for each media file
|
||||
for (auto &name : names) {
|
||||
auto sha1_raw = pkt->readRawString(20);
|
||||
m_media_downloader->addFile(name, sha1_raw);
|
||||
}
|
||||
} else {
|
||||
u16 num_files;
|
||||
*pkt >> num_files;
|
||||
|
||||
std::string name, sha1_base64;
|
||||
for (u16 i = 0; i < num_files; i++) {
|
||||
*pkt >> name >> sha1_base64;
|
||||
|
||||
*pkt >> name >> sha1_base64;
|
||||
|
||||
std::string sha1_raw = base64_decode(sha1_base64);
|
||||
m_media_downloader->addFile(name, sha1_raw);
|
||||
std::string sha1_raw = base64_decode(sha1_base64);
|
||||
m_media_downloader->addFile(name, sha1_raw);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Remote media servers
|
||||
std::string str;
|
||||
*pkt >> str;
|
||||
|
||||
|
@ -700,18 +671,6 @@ void Client::handleCommand_AnnounceMedia(NetworkPacket* pkt)
|
|||
|
||||
void Client::handleCommand_Media(NetworkPacket* pkt)
|
||||
{
|
||||
/*
|
||||
u16 command
|
||||
u16 total number of file bunches
|
||||
u16 index of this bunch
|
||||
u32 number of files in this bunch
|
||||
for each file {
|
||||
u16 length of name
|
||||
string name
|
||||
u32 length of data
|
||||
data
|
||||
}
|
||||
*/
|
||||
u16 num_bunches;
|
||||
u16 bunch_i;
|
||||
u32 num_files;
|
||||
|
@ -738,6 +697,12 @@ void Client::handleCommand_Media(NetworkPacket* pkt)
|
|||
|
||||
*pkt >> name;
|
||||
data = pkt->readLongString();
|
||||
if (m_proto_ver >= 48) {
|
||||
std::istringstream iss(data, std::ios::binary);
|
||||
std::ostringstream oss(std::ios::binary);
|
||||
decompressZstd(iss, oss);
|
||||
data = oss.str();
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
if (init_phase) {
|
||||
|
@ -772,7 +737,10 @@ void Client::handleCommand_NodeDef(NetworkPacket* pkt)
|
|||
// Decompress node definitions
|
||||
std::istringstream tmp_is(pkt->readLongString(), std::ios::binary);
|
||||
std::stringstream tmp_os(std::ios::binary | std::ios::in | std::ios::out);
|
||||
decompressZlib(tmp_is, tmp_os);
|
||||
if (m_proto_ver >= 48)
|
||||
decompressZstd(tmp_is, tmp_os);
|
||||
else
|
||||
decompressZlib(tmp_is, tmp_os);
|
||||
|
||||
// Deserialize node definitions
|
||||
m_nodedef->deSerialize(tmp_os, m_proto_ver);
|
||||
|
@ -791,7 +759,10 @@ void Client::handleCommand_ItemDef(NetworkPacket* pkt)
|
|||
// Decompress item definitions
|
||||
std::istringstream tmp_is(pkt->readLongString(), std::ios::binary);
|
||||
std::stringstream tmp_os(std::ios::binary | std::ios::in | std::ios::out);
|
||||
decompressZlib(tmp_is, tmp_os);
|
||||
if (m_proto_ver >= 48)
|
||||
decompressZstd(tmp_is, tmp_os);
|
||||
else
|
||||
decompressZlib(tmp_is, tmp_os);
|
||||
|
||||
// Deserialize node definitions
|
||||
m_itemdef->deSerialize(tmp_os, m_proto_ver);
|
||||
|
@ -851,6 +822,8 @@ void Client::handleCommand_PlaySound(NetworkPacket* pkt)
|
|||
pos = cao->getPosition() * (1.0f/BS);
|
||||
vel = cao->getVelocity() * (1.0f/BS);
|
||||
}
|
||||
// Note that the server sends 'pos' correctly even for attached sounds,
|
||||
// so this fallback path is not a mistake.
|
||||
m_sound->playSoundAt(client_id, spec, pos, vel);
|
||||
break;
|
||||
}
|
||||
|
@ -883,7 +856,7 @@ void Client::handleCommand_StopSound(NetworkPacket* pkt)
|
|||
|
||||
*pkt >> server_id;
|
||||
|
||||
std::unordered_map<s32, int>::iterator i = m_sounds_server_to_client.find(server_id);
|
||||
auto i = m_sounds_server_to_client.find(server_id);
|
||||
if (i != m_sounds_server_to_client.end()) {
|
||||
int client_id = i->second;
|
||||
m_sound->stopSound(client_id);
|
||||
|
@ -898,9 +871,7 @@ void Client::handleCommand_FadeSound(NetworkPacket *pkt)
|
|||
|
||||
*pkt >> sound_id >> step >> gain;
|
||||
|
||||
std::unordered_map<s32, int>::const_iterator i =
|
||||
m_sounds_server_to_client.find(sound_id);
|
||||
|
||||
auto i = m_sounds_server_to_client.find(sound_id);
|
||||
if (i != m_sounds_server_to_client.end())
|
||||
m_sound->fadeSound(i->second, step, gain);
|
||||
}
|
||||
|
@ -958,8 +929,8 @@ void Client::handleCommand_DetachedInventory(NetworkPacket* pkt)
|
|||
inv = inv_it->second;
|
||||
}
|
||||
|
||||
u16 ignore;
|
||||
*pkt >> ignore; // this used to be the length of the following string, ignore it
|
||||
// this used to be the length of the following string, ignore it
|
||||
pkt->skip(2);
|
||||
|
||||
std::string contents(pkt->getRemainingString(), pkt->getRemainingBytes());
|
||||
std::istringstream is(contents, std::ios::binary);
|
||||
|
@ -1009,7 +980,7 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
|
|||
p.amount = readU16(is);
|
||||
p.time = readF32(is);
|
||||
if (p.time < 0)
|
||||
throw SerializationError("particle spawner time < 0");
|
||||
throw PacketError("particle spawner time < 0");
|
||||
|
||||
bool missing_end_values = false;
|
||||
if (m_proto_ver >= 42) {
|
||||
|
@ -1324,10 +1295,7 @@ void Client::handleCommand_HudSetSky(NetworkPacket* pkt)
|
|||
for (size_t i = 0; i < count; i++)
|
||||
skybox.textures.emplace_back(deSerializeString16(is));
|
||||
|
||||
skybox.clouds = true;
|
||||
try {
|
||||
skybox.clouds = readU8(is);
|
||||
} catch (...) {}
|
||||
skybox.clouds = readU8(is) != 0;
|
||||
|
||||
// Use default skybox settings:
|
||||
SunParams sun = SkyboxDefaults::getSunDefaults();
|
||||
|
@ -1530,7 +1498,19 @@ void Client::handleCommand_EyeOffset(NetworkPacket* pkt)
|
|||
*pkt >> player->eye_offset_third_front;
|
||||
} catch (PacketError &e) {
|
||||
player->eye_offset_third_front = player->eye_offset_third;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void Client::handleCommand_Camera(NetworkPacket* pkt)
|
||||
{
|
||||
LocalPlayer *player = m_env.getLocalPlayer();
|
||||
assert(player);
|
||||
|
||||
u8 tmp;
|
||||
*pkt >> tmp;
|
||||
player->allowed_camera_mode = static_cast<CameraMode>(tmp);
|
||||
|
||||
m_client_event_queue.push(new ClientEvent(CE_UPDATE_CAMERA));
|
||||
}
|
||||
|
||||
void Client::handleCommand_UpdatePlayerList(NetworkPacket* pkt)
|
||||
|
|
|
@ -53,6 +53,15 @@ u16 BufferedPacket::getSeqnum() const
|
|||
return readU16(&data[BASE_HEADER_SIZE + 1]);
|
||||
}
|
||||
|
||||
void BufferedPacket::setSenderPeerId(session_t id)
|
||||
{
|
||||
if (size() < BASE_HEADER_SIZE) {
|
||||
assert(false); // should never happen
|
||||
return;
|
||||
}
|
||||
writeU16(&data[4], id);
|
||||
}
|
||||
|
||||
BufferedPacketPtr makePacket(const Address &address, const SharedBuffer<u8> &data,
|
||||
u32 protocol_id, session_t sender_peer_id, u8 channel)
|
||||
{
|
||||
|
@ -337,6 +346,13 @@ void ReliablePacketBuffer::insert(BufferedPacketPtr &p_ptr, u16 next_expected)
|
|||
m_oldest_non_answered_ack = m_list.front()->getSeqnum();
|
||||
}
|
||||
|
||||
void ReliablePacketBuffer::fixPeerId(session_t new_id)
|
||||
{
|
||||
MutexAutoLock listlock(m_list_mutex);
|
||||
for (auto &packet : m_list)
|
||||
packet->setSenderPeerId(new_id);
|
||||
}
|
||||
|
||||
void ReliablePacketBuffer::incrementTimeouts(float dtime)
|
||||
{
|
||||
MutexAutoLock listlock(m_list_mutex);
|
||||
|
@ -569,6 +585,13 @@ ConnectionCommandPtr ConnectionCommand::resend_one(session_t peer_id)
|
|||
return c;
|
||||
}
|
||||
|
||||
ConnectionCommandPtr ConnectionCommand::peer_id_set(session_t own_peer_id)
|
||||
{
|
||||
auto c = create(CONNCMD_PEER_ID_SET);
|
||||
c->peer_id = own_peer_id;
|
||||
return c;
|
||||
}
|
||||
|
||||
ConnectionCommandPtr ConnectionCommand::send(session_t peer_id, u8 channelnum,
|
||||
NetworkPacket *pkt, bool reliable)
|
||||
{
|
||||
|
@ -1615,6 +1638,14 @@ void Connection::DisconnectPeer(session_t peer_id)
|
|||
putCommand(ConnectionCommand::disconnect_peer(peer_id));
|
||||
}
|
||||
|
||||
void Connection::SetPeerID(session_t id)
|
||||
{
|
||||
m_peer_id = id;
|
||||
// fix peer id in existing queued reliable packets
|
||||
if (id != PEER_ID_INEXISTENT)
|
||||
putCommand(ConnectionCommand::peer_id_set(id));
|
||||
}
|
||||
|
||||
void Connection::doResendOne(session_t peer_id)
|
||||
{
|
||||
assert(peer_id != PEER_ID_INEXISTENT);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "network/networkprotocol.h"
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
|
||||
namespace con
|
||||
|
@ -24,7 +25,6 @@ class ConnectionSendThread;
|
|||
|
||||
class Peer;
|
||||
|
||||
// FIXME: Peer refcounting should generally be replaced by std::shared_ptr
|
||||
class PeerHelper
|
||||
{
|
||||
public:
|
||||
|
@ -256,7 +256,7 @@ protected:
|
|||
UDPPeer* createServerPeer(const Address& sender);
|
||||
bool deletePeer(session_t peer_id, bool timeout);
|
||||
|
||||
void SetPeerID(session_t id) { m_peer_id = id; }
|
||||
void SetPeerID(session_t id);
|
||||
|
||||
void doResendOne(session_t peer_id);
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ channel:
|
|||
/*
|
||||
Packet types:
|
||||
|
||||
CONTROL: This is a packet used by the protocol.
|
||||
PACKET_TYPE_CONTROL: This is a packet used by the protocol.
|
||||
- When this is processed, nothing is handed to the user.
|
||||
Header (2 byte):
|
||||
[0] u8 type
|
||||
|
@ -48,25 +48,18 @@ controltype and data description:
|
|||
packet to get a reply
|
||||
CONTROLTYPE_DISCO
|
||||
*/
|
||||
enum ControlType : u8 {
|
||||
CONTROLTYPE_ACK = 0,
|
||||
CONTROLTYPE_SET_PEER_ID = 1,
|
||||
CONTROLTYPE_PING = 2,
|
||||
CONTROLTYPE_DISCO = 3,
|
||||
};
|
||||
|
||||
/*
|
||||
ORIGINAL: This is a plain packet with no control and no error
|
||||
PACKET_TYPE_ORIGINAL: This is a plain packet with no control and no error
|
||||
checking at all.
|
||||
- When this is processed, it is directly handed to the user.
|
||||
Header (1 byte):
|
||||
[0] u8 type
|
||||
*/
|
||||
//#define TYPE_ORIGINAL 1
|
||||
#define ORIGINAL_HEADER_SIZE 1
|
||||
|
||||
/*
|
||||
SPLIT: These are sequences of packets forming one bigger piece of
|
||||
PACKET_TYPE_SPLIT: These are sequences of packets forming one bigger piece of
|
||||
data.
|
||||
- When processed and all the packet_nums 0...packet_count-1 are
|
||||
present (this should be buffered), the resulting data shall be
|
||||
|
@ -80,10 +73,9 @@ data.
|
|||
[3] u16 chunk_count
|
||||
[5] u16 chunk_num
|
||||
*/
|
||||
//#define TYPE_SPLIT 2
|
||||
|
||||
/*
|
||||
RELIABLE: Delivery of all RELIABLE packets shall be forced by ACKs,
|
||||
PACKET_TYPE_RELIABLE: Delivery of all RELIABLE packets shall be forced by ACKs,
|
||||
and they shall be delivered in the same order as sent. This is done
|
||||
with a buffer in the receiving and transmitting end.
|
||||
- When this is processed, the contents of each packet is recursively
|
||||
|
@ -93,15 +85,29 @@ with a buffer in the receiving and transmitting end.
|
|||
[1] u16 seqnum
|
||||
|
||||
*/
|
||||
//#define TYPE_RELIABLE 3
|
||||
#define RELIABLE_HEADER_SIZE 3
|
||||
#define SEQNUM_INITIAL 65500
|
||||
#define SEQNUM_MAX 65535
|
||||
|
||||
/****/
|
||||
|
||||
template<typename T>
|
||||
class ConstSharedPtr {
|
||||
public:
|
||||
ConstSharedPtr(T *ptr) : ptr(ptr) {}
|
||||
ConstSharedPtr(const std::shared_ptr<T> &ptr) : ptr(ptr) {}
|
||||
|
||||
const T* get() const noexcept { return ptr.get(); }
|
||||
const T& operator*() const noexcept { return *ptr.get(); }
|
||||
const T* operator->() const noexcept { return ptr.get(); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<T> ptr;
|
||||
};
|
||||
|
||||
namespace con
|
||||
{
|
||||
|
||||
|
||||
enum PacketType : u8 {
|
||||
PACKET_TYPE_CONTROL = 0,
|
||||
PACKET_TYPE_ORIGINAL = 1,
|
||||
|
@ -110,6 +116,13 @@ enum PacketType : u8 {
|
|||
PACKET_TYPE_MAX
|
||||
};
|
||||
|
||||
enum ControlType : u8 {
|
||||
CONTROLTYPE_ACK = 0,
|
||||
CONTROLTYPE_SET_PEER_ID = 1,
|
||||
CONTROLTYPE_PING = 2,
|
||||
CONTROLTYPE_DISCO = 3,
|
||||
};
|
||||
|
||||
inline bool seqnum_higher(u16 totest, u16 base)
|
||||
{
|
||||
if (totest > base)
|
||||
|
@ -187,6 +200,7 @@ struct BufferedPacket {
|
|||
DISABLE_CLASS_COPY(BufferedPacket)
|
||||
|
||||
u16 getSeqnum() const;
|
||||
void setSenderPeerId(session_t id);
|
||||
|
||||
inline size_t size() const { return m_data.size(); }
|
||||
|
||||
|
@ -250,6 +264,8 @@ public:
|
|||
BufferedPacketPtr popFirst();
|
||||
BufferedPacketPtr popSeqnum(u16 seqnum);
|
||||
void insert(BufferedPacketPtr &p_ptr, u16 next_expected);
|
||||
/// Adjusts the sender peer ID for all packets
|
||||
void fixPeerId(session_t id);
|
||||
|
||||
void incrementTimeouts(float dtime);
|
||||
u32 getTimedOuts(float timeout);
|
||||
|
@ -307,7 +323,8 @@ enum ConnectionCommandType{
|
|||
CONNCMD_SEND_TO_ALL,
|
||||
CONCMD_ACK,
|
||||
CONCMD_CREATE_PEER,
|
||||
CONNCMD_RESEND_ONE
|
||||
CONNCMD_RESEND_ONE,
|
||||
CONNCMD_PEER_ID_SET
|
||||
};
|
||||
|
||||
// This is very similar to ConnectionEvent
|
||||
|
@ -328,6 +345,7 @@ struct ConnectionCommand
|
|||
static ConnectionCommandPtr disconnect();
|
||||
static ConnectionCommandPtr disconnect_peer(session_t peer_id);
|
||||
static ConnectionCommandPtr resend_one(session_t peer_id);
|
||||
static ConnectionCommandPtr peer_id_set(session_t own_peer_id);
|
||||
static ConnectionCommandPtr send(session_t peer_id, u8 channelnum, NetworkPacket *pkt, bool reliable);
|
||||
static ConnectionCommandPtr ack(session_t peer_id, u8 channelnum, const Buffer<u8> &data);
|
||||
static ConnectionCommandPtr createPeer(session_t peer_id, const Buffer<u8> &data);
|
||||
|
|
|
@ -476,6 +476,11 @@ void ConnectionSendThread::processNonReliableCommand(ConnectionCommandPtr &c_ptr
|
|||
<< " UDP processing CONNCMD_DISCONNECT_PEER" << std::endl);
|
||||
disconnect_peer(c.peer_id);
|
||||
return;
|
||||
case CONNCMD_PEER_ID_SET:
|
||||
LOG(dout_con << m_connection->getDesc()
|
||||
<< " UDP processing CONNCMD_PEER_ID_SET" << std::endl);
|
||||
fix_peer_id(c.peer_id);
|
||||
return;
|
||||
case CONNCMD_SEND:
|
||||
LOG(dout_con << m_connection->getDesc()
|
||||
<< " UDP processing CONNCMD_SEND" << std::endl);
|
||||
|
@ -579,6 +584,26 @@ void ConnectionSendThread::disconnect_peer(session_t peer_id)
|
|||
dynamic_cast<UDPPeer *>(&peer)->m_pending_disconnect = true;
|
||||
}
|
||||
|
||||
void ConnectionSendThread::fix_peer_id(session_t own_peer_id)
|
||||
{
|
||||
auto peer_ids = m_connection->getPeerIDs();
|
||||
for (const session_t peer_id : peer_ids) {
|
||||
PeerHelper peer = m_connection->getPeerNoEx(peer_id);
|
||||
if (!peer)
|
||||
continue;
|
||||
|
||||
auto *udp_peer = dynamic_cast<UDPPeer*>(&peer);
|
||||
if (!udp_peer)
|
||||
continue;
|
||||
|
||||
for (int ch = 0; ch < CHANNEL_COUNT; ch++) {
|
||||
auto &channel = udp_peer->channels[ch];
|
||||
|
||||
channel.outgoing_reliables_sent.fixPeerId(own_peer_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionSendThread::send(session_t peer_id, u8 channelnum,
|
||||
const SharedBuffer<u8> &data)
|
||||
{
|
||||
|
|
|
@ -70,6 +70,7 @@ private:
|
|||
void connect(Address address);
|
||||
void disconnect();
|
||||
void disconnect_peer(session_t peer_id);
|
||||
void fix_peer_id(session_t own_peer_id);
|
||||
void send(session_t peer_id, u8 channelnum, const SharedBuffer<u8> &data);
|
||||
void sendReliable(ConnectionCommandPtr &c);
|
||||
void sendToAll(u8 channelnum, const SharedBuffer<u8> &data);
|
||||
|
|
|
@ -49,7 +49,13 @@ const char* NetworkPacket::getString(u32 from_offset) const
|
|||
{
|
||||
checkReadOffset(from_offset, 0);
|
||||
|
||||
return (char*)&m_data[from_offset];
|
||||
return reinterpret_cast<const char*>(&m_data[from_offset]);
|
||||
}
|
||||
|
||||
void NetworkPacket::skip(u32 count)
|
||||
{
|
||||
checkReadOffset(m_read_offset, count);
|
||||
m_read_offset += count;
|
||||
}
|
||||
|
||||
void NetworkPacket::putRawString(const char* src, u32 len)
|
||||
|
@ -63,6 +69,18 @@ void NetworkPacket::putRawString(const char* src, u32 len)
|
|||
m_read_offset += len;
|
||||
}
|
||||
|
||||
void NetworkPacket::readRawString(char *dst, u32 len)
|
||||
{
|
||||
checkReadOffset(m_read_offset, len);
|
||||
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
memcpy(dst, &m_data[m_read_offset], len);
|
||||
m_read_offset += len;
|
||||
}
|
||||
|
||||
|
||||
NetworkPacket& NetworkPacket::operator>>(std::string& dst)
|
||||
{
|
||||
checkReadOffset(m_read_offset, 2);
|
||||
|
@ -311,24 +329,6 @@ NetworkPacket& NetworkPacket::operator>>(u8& dst)
|
|||
return *this;
|
||||
}
|
||||
|
||||
u8 NetworkPacket::getU8(u32 offset)
|
||||
{
|
||||
checkReadOffset(offset, 1);
|
||||
|
||||
return readU8(&m_data[offset]);
|
||||
}
|
||||
|
||||
u8* NetworkPacket::getU8Ptr(u32 from_offset)
|
||||
{
|
||||
if (m_datasize == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
checkReadOffset(from_offset, 1);
|
||||
|
||||
return &m_data[from_offset];
|
||||
}
|
||||
|
||||
NetworkPacket& NetworkPacket::operator>>(u16& dst)
|
||||
{
|
||||
checkReadOffset(m_read_offset, 2);
|
||||
|
@ -339,13 +339,6 @@ NetworkPacket& NetworkPacket::operator>>(u16& dst)
|
|||
return *this;
|
||||
}
|
||||
|
||||
u16 NetworkPacket::getU16(u32 from_offset)
|
||||
{
|
||||
checkReadOffset(from_offset, 2);
|
||||
|
||||
return readU16(&m_data[from_offset]);
|
||||
}
|
||||
|
||||
NetworkPacket& NetworkPacket::operator>>(u32& dst)
|
||||
{
|
||||
checkReadOffset(m_read_offset, 4);
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include "irrlichttypes_bloated.h"
|
||||
#include "networkprotocol.h"
|
||||
#include <SColor.h>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
class NetworkPacket
|
||||
|
@ -35,18 +37,32 @@ public:
|
|||
session_t getPeerId() const { return m_peer_id; }
|
||||
u16 getCommand() const { return m_command; }
|
||||
u32 getRemainingBytes() const { return m_datasize - m_read_offset; }
|
||||
const char *getRemainingString() { return getString(m_read_offset); }
|
||||
|
||||
// Returns a c-string without copying.
|
||||
// Returns a pointer to buffer data.
|
||||
// A better name for this would be getRawString()
|
||||
const char *getString(u32 from_offset) const;
|
||||
// major difference to putCString(): doesn't write len into the buffer
|
||||
const char *getRemainingString() const { return getString(m_read_offset); }
|
||||
|
||||
// Perform length check and skip ahead by `count` bytes.
|
||||
void skip(u32 count);
|
||||
|
||||
// Appends bytes from string buffer to packet
|
||||
void putRawString(const char *src, u32 len);
|
||||
void putRawString(std::string_view src)
|
||||
{
|
||||
putRawString(src.data(), src.size());
|
||||
}
|
||||
|
||||
// Reads bytes from packet into string buffer
|
||||
void readRawString(char *dst, u32 len);
|
||||
std::string readRawString(u32 len)
|
||||
{
|
||||
std::string s;
|
||||
s.resize(len);
|
||||
readRawString(&s[0], len);
|
||||
return s;
|
||||
}
|
||||
|
||||
NetworkPacket &operator>>(std::string &dst);
|
||||
NetworkPacket &operator<<(std::string_view src);
|
||||
|
||||
|
@ -63,14 +79,9 @@ public:
|
|||
NetworkPacket &operator>>(bool &dst);
|
||||
NetworkPacket &operator<<(bool src);
|
||||
|
||||
u8 getU8(u32 offset);
|
||||
|
||||
NetworkPacket &operator>>(u8 &dst);
|
||||
NetworkPacket &operator<<(u8 src);
|
||||
|
||||
u8 *getU8Ptr(u32 offset);
|
||||
|
||||
u16 getU16(u32 from_offset);
|
||||
NetworkPacket &operator>>(u16 &dst);
|
||||
NetworkPacket &operator<<(u16 src);
|
||||
|
||||
|
@ -114,6 +125,7 @@ public:
|
|||
private:
|
||||
void checkReadOffset(u32 from_offset, u32 field_size) const;
|
||||
|
||||
// resize data buffer for writing
|
||||
inline void checkDataSize(u32 field_size)
|
||||
{
|
||||
if (m_read_offset + field_size > m_datasize) {
|
||||
|
@ -124,7 +136,7 @@ private:
|
|||
|
||||
std::vector<u8> m_data;
|
||||
u32 m_datasize = 0;
|
||||
u32 m_read_offset = 0;
|
||||
u32 m_read_offset = 0; // read and write offset
|
||||
u16 m_command = 0;
|
||||
session_t m_peer_id = 0;
|
||||
};
|
||||
|
|
|
@ -63,9 +63,13 @@
|
|||
Add particle blend mode "clip"
|
||||
Add artificial light color, beta_r0, vignette, specular intensity, foliage translucency and cdl parameters to Lighting packets
|
||||
[scheduled bump for 5.11.0]
|
||||
PROTOCOL VERSION 48
|
||||
Add compression to some existing packets
|
||||
[scheduled bump for 5.12.0]
|
||||
*/
|
||||
|
||||
const u16 LATEST_PROTOCOL_VERSION = 47;
|
||||
// Note: Also update core.protocol_versions in builtin when bumping
|
||||
const u16 LATEST_PROTOCOL_VERSION = 48;
|
||||
|
||||
// See also formspec [Version History] in doc/lua_api.md
|
||||
const u16 FORMSPEC_API_VERSION = 8;
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "irrTypes.h"
|
||||
using namespace irr;
|
||||
#include "irrlichttypes.h"
|
||||
|
||||
extern const u16 LATEST_PROTOCOL_VERSION;
|
||||
|
||||
|
@ -33,24 +32,28 @@ enum ToClientCommand : u16
|
|||
u32 supported auth methods
|
||||
std::string unused (used to be username)
|
||||
*/
|
||||
|
||||
TOCLIENT_AUTH_ACCEPT = 0x03,
|
||||
/*
|
||||
Message from server to accept auth.
|
||||
|
||||
v3s16 player's position + v3f(0,BS/2,0) floatToInt'd
|
||||
v3f unused
|
||||
u64 map seed
|
||||
f1000 recommended send interval
|
||||
u32 : supported auth methods for sudo mode
|
||||
(where the user can change their password)
|
||||
*/
|
||||
|
||||
TOCLIENT_ACCEPT_SUDO_MODE = 0x04,
|
||||
/*
|
||||
Sent to client to show it is in sudo mode now.
|
||||
*/
|
||||
|
||||
TOCLIENT_DENY_SUDO_MODE = 0x05,
|
||||
/*
|
||||
Signals client that sudo mode auth failed.
|
||||
*/
|
||||
|
||||
TOCLIENT_ACCESS_DENIED = 0x0A,
|
||||
/*
|
||||
u8 reason
|
||||
|
@ -59,18 +62,26 @@ enum ToClientCommand : u16
|
|||
*/
|
||||
|
||||
TOCLIENT_BLOCKDATA = 0x20,
|
||||
/*
|
||||
v3s16 position
|
||||
serialized MapBlock
|
||||
*/
|
||||
|
||||
TOCLIENT_ADDNODE = 0x21,
|
||||
/*
|
||||
v3s16 position
|
||||
serialized mapnode
|
||||
u8 keep_metadata // Added in protocol version 22
|
||||
u8 keep_metadata
|
||||
*/
|
||||
|
||||
TOCLIENT_REMOVENODE = 0x22,
|
||||
/*
|
||||
v3s16 position
|
||||
*/
|
||||
|
||||
TOCLIENT_INVENTORY = 0x27,
|
||||
/*
|
||||
[0] u16 command
|
||||
[2] serialized inventory
|
||||
serialized inventory
|
||||
*/
|
||||
|
||||
TOCLIENT_TIME_OF_DAY = 0x29,
|
||||
|
@ -167,40 +178,38 @@ enum ToClientCommand : u16
|
|||
|
||||
TOCLIENT_MEDIA = 0x38,
|
||||
/*
|
||||
u16 total number of texture bunches
|
||||
u16 total number of bunches
|
||||
u16 index of this bunch
|
||||
u32 number of files in this bunch
|
||||
for each file {
|
||||
u16 length of name
|
||||
string name
|
||||
u32 length of data
|
||||
data
|
||||
data (zstd-compressed)
|
||||
}
|
||||
u16 length of remote media server url (if applicable)
|
||||
string url
|
||||
*/
|
||||
|
||||
TOCLIENT_NODEDEF = 0x3a,
|
||||
/*
|
||||
u32 length of the next item
|
||||
serialized NodeDefManager
|
||||
u32 length of buffer
|
||||
serialized NodeDefManager (zstd-compressed)
|
||||
*/
|
||||
|
||||
TOCLIENT_ANNOUNCE_MEDIA = 0x3c,
|
||||
/*
|
||||
u32 number of files
|
||||
for each texture {
|
||||
u16 length of name
|
||||
string name
|
||||
u16 length of sha1_digest
|
||||
string sha1_digest
|
||||
u32 length of compressed name array
|
||||
string16array names (zstd-compressed)
|
||||
for each file {
|
||||
char[20] sha1_digest
|
||||
}
|
||||
u16 length of remote media server url
|
||||
string url
|
||||
*/
|
||||
|
||||
TOCLIENT_ITEMDEF = 0x3d,
|
||||
/*
|
||||
u32 length of next item
|
||||
serialized ItemDefManager
|
||||
u32 length of buffer
|
||||
serialized ItemDefManager (zstd-compressed)
|
||||
*/
|
||||
|
||||
TOCLIENT_PLAY_SOUND = 0x3f,
|
||||
|
@ -442,6 +451,11 @@ enum ToClientCommand : u16
|
|||
|
||||
*/
|
||||
|
||||
TOCLIENT_CAMERA = 0x48,
|
||||
/*
|
||||
u8 allowed_camera_mode
|
||||
*/
|
||||
|
||||
TOCLIENT_HUDADD = 0x49,
|
||||
/*
|
||||
u32 id
|
||||
|
@ -716,18 +730,16 @@ enum ToServerCommand : u16
|
|||
|
||||
TOSERVER_PLAYERPOS = 0x23,
|
||||
/*
|
||||
[0] u16 command
|
||||
[2] v3s32 position*100
|
||||
[2+12] v3s32 speed*100
|
||||
[2+12+12] s32 pitch*100
|
||||
[2+12+12+4] s32 yaw*100
|
||||
[2+12+12+4+4] u32 keyPressed
|
||||
[2+12+12+4+4+4] u8 fov*80
|
||||
[2+12+12+4+4+4+1] u8 ceil(wanted_range / MAP_BLOCKSIZE)
|
||||
[2+12+12+4+4+4+1+1] u8 camera_inverted (bool)
|
||||
[2+12+12+4+4+4+1+1+1] f32 movement_speed
|
||||
[2+12+12+4+4+4+1+1+1+4] f32 movement_direction
|
||||
|
||||
v3s32 position*100
|
||||
v3s32 speed*100
|
||||
s32 pitch*100
|
||||
s32 yaw*100
|
||||
u32 keyPressed
|
||||
u8 fov*80
|
||||
u8 ceil(wanted_range / MAP_BLOCKSIZE)
|
||||
u8 camera_inverted (bool)
|
||||
f32 movement_speed
|
||||
f32 movement_direction
|
||||
*/
|
||||
|
||||
TOSERVER_GOTBLOCKS = 0x24,
|
||||
|
|
|
@ -183,7 +183,7 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] =
|
|||
{ "TOCLIENT_MOVEMENT", 0, true }, // 0x45
|
||||
{ "TOCLIENT_SPAWN_PARTICLE", 0, true }, // 0x46
|
||||
{ "TOCLIENT_ADD_PARTICLESPAWNER", 0, true }, // 0x47
|
||||
null_command_factory, // 0x48
|
||||
{ "TOCLIENT_CAMERA", 0, true }, // 0x48
|
||||
{ "TOCLIENT_HUDADD", 1, true }, // 0x49
|
||||
{ "TOCLIENT_HUDRM", 1, true }, // 0x4a
|
||||
{ "TOCLIENT_HUDCHANGE", 1, true }, // 0x4b
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#include "util/srp.h"
|
||||
#include "clientdynamicinfo.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
void Server::handleCommand_Deprecated(NetworkPacket* pkt)
|
||||
{
|
||||
infostream << "Server: " << toServerCommandTable[pkt->getCommand()].name
|
||||
|
@ -323,13 +325,6 @@ void Server::handleCommand_Init2(NetworkPacket* pkt)
|
|||
SendTimeOfDay(peer_id, time, time_speed);
|
||||
|
||||
SendCSMRestrictionFlags(peer_id);
|
||||
|
||||
// Warnings about protocol version can be issued here
|
||||
if (client->net_proto_version < LATEST_PROTOCOL_VERSION) {
|
||||
SendChatMessage(peer_id, ChatMessage(CHATMESSAGE_TYPE_SYSTEM,
|
||||
L"# Server: WARNING: YOUR CLIENT'S VERSION MAY NOT BE FULLY COMPATIBLE "
|
||||
L"WITH THIS SERVER!"));
|
||||
}
|
||||
}
|
||||
|
||||
void Server::handleCommand_RequestMedia(NetworkPacket* pkt)
|
||||
|
@ -419,13 +414,10 @@ void Server::handleCommand_GotBlocks(NetworkPacket* pkt)
|
|||
u8 count;
|
||||
*pkt >> count;
|
||||
|
||||
if ((s16)pkt->getSize() < 1 + (int)count * 6) {
|
||||
throw con::InvalidIncomingDataException
|
||||
("GOTBLOCKS length is too short");
|
||||
}
|
||||
|
||||
ClientInterface::AutoLock lock(m_clients);
|
||||
RemoteClient *client = m_clients.lockedGetClientNoEx(pkt->getPeerId());
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
for (u16 i = 0; i < count; i++) {
|
||||
v3s16 p;
|
||||
|
@ -468,7 +460,11 @@ void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
|
|||
*pkt >> bits;
|
||||
|
||||
if (pkt->getRemainingBytes() >= 8) {
|
||||
*pkt >> player->control.movement_speed;
|
||||
f32 movement_speed;
|
||||
*pkt >> movement_speed;
|
||||
if (movement_speed != movement_speed) // NaN
|
||||
movement_speed = 0.0f;
|
||||
player->control.movement_speed = std::clamp(movement_speed, 0.0f, 1.0f);
|
||||
*pkt >> player->control.movement_direction;
|
||||
} else {
|
||||
player->control.movement_speed = 0.0f;
|
||||
|
@ -505,20 +501,14 @@ void Server::handleCommand_PlayerPos(NetworkPacket* pkt)
|
|||
{
|
||||
session_t peer_id = pkt->getPeerId();
|
||||
RemotePlayer *player = m_env->getPlayer(peer_id);
|
||||
if (player == NULL) {
|
||||
errorstream <<
|
||||
"Server::ProcessData(): Canceling: No player for peer_id=" <<
|
||||
peer_id << " disconnecting peer!" << std::endl;
|
||||
DisconnectPeer(peer_id);
|
||||
if (!player) {
|
||||
warningstream << FUNCTION_NAME << ": player is null" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerSAO *playersao = player->getPlayerSAO();
|
||||
if (playersao == NULL) {
|
||||
errorstream <<
|
||||
"Server::ProcessData(): Canceling: No player object for peer_id=" <<
|
||||
peer_id << " disconnecting peer!" << std::endl;
|
||||
DisconnectPeer(peer_id);
|
||||
if (!playersao) {
|
||||
warningstream << FUNCTION_NAME << ": player SAO is null" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -548,12 +538,10 @@ void Server::handleCommand_DeletedBlocks(NetworkPacket* pkt)
|
|||
u8 count;
|
||||
*pkt >> count;
|
||||
|
||||
RemoteClient *client = getClient(pkt->getPeerId());
|
||||
|
||||
if ((s16)pkt->getSize() < 1 + (int)count * 6) {
|
||||
throw con::InvalidIncomingDataException
|
||||
("DELETEDBLOCKS length is too short");
|
||||
}
|
||||
ClientInterface::AutoLock lock(m_clients);
|
||||
RemoteClient *client = m_clients.lockedGetClientNoEx(pkt->getPeerId());
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
for (u16 i = 0; i < count; i++) {
|
||||
v3s16 p;
|
||||
|
@ -566,28 +554,19 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt)
|
|||
{
|
||||
session_t peer_id = pkt->getPeerId();
|
||||
RemotePlayer *player = m_env->getPlayer(peer_id);
|
||||
|
||||
if (player == NULL) {
|
||||
errorstream <<
|
||||
"Server::ProcessData(): Canceling: No player for peer_id=" <<
|
||||
peer_id << " disconnecting peer!" << std::endl;
|
||||
DisconnectPeer(peer_id);
|
||||
if (!player) {
|
||||
warningstream << FUNCTION_NAME << ": player is null" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerSAO *playersao = player->getPlayerSAO();
|
||||
if (playersao == NULL) {
|
||||
errorstream <<
|
||||
"Server::ProcessData(): Canceling: No player object for peer_id=" <<
|
||||
peer_id << " disconnecting peer!" << std::endl;
|
||||
DisconnectPeer(peer_id);
|
||||
if (!playersao) {
|
||||
warningstream << FUNCTION_NAME << ": player SAO is null" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Strip command and create a stream
|
||||
std::string datastring(pkt->getString(0), pkt->getSize());
|
||||
verbosestream << "TOSERVER_INVENTORY_ACTION: data=" << datastring
|
||||
<< std::endl;
|
||||
std::istringstream is(datastring, std::ios_base::binary);
|
||||
// Create an action
|
||||
std::unique_ptr<InventoryAction> a(InventoryAction::deSerialize(is));
|
||||
|
@ -607,6 +586,24 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt)
|
|||
where the client made a bad prediction.
|
||||
*/
|
||||
|
||||
auto mark_player_inv_list_dirty = [this](const InventoryLocation &loc,
|
||||
const std::string &list_name) {
|
||||
|
||||
// Undo the client prediction of the affected list. See `clientApply`.
|
||||
if (loc.type != InventoryLocation::PLAYER)
|
||||
return;
|
||||
|
||||
Inventory *inv = m_inventory_mgr->getInventory(loc);
|
||||
if (!inv)
|
||||
return;
|
||||
|
||||
InventoryList *list = inv->getList(list_name);
|
||||
if (!list)
|
||||
return;
|
||||
|
||||
list->setModified(true);
|
||||
};
|
||||
|
||||
const bool player_has_interact = checkPriv(player->getName(), "interact");
|
||||
|
||||
auto check_inv_access = [player, player_has_interact, this] (
|
||||
|
@ -651,8 +648,12 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt)
|
|||
ma->to_inv.applyCurrentPlayer(player->getName());
|
||||
|
||||
m_inventory_mgr->setInventoryModified(ma->from_inv);
|
||||
if (ma->from_inv != ma->to_inv)
|
||||
mark_player_inv_list_dirty(ma->from_inv, ma->from_list);
|
||||
bool inv_different = ma->from_inv != ma->to_inv;
|
||||
if (inv_different)
|
||||
m_inventory_mgr->setInventoryModified(ma->to_inv);
|
||||
if (inv_different || ma->from_list != ma->to_list)
|
||||
mark_player_inv_list_dirty(ma->to_inv, ma->to_list);
|
||||
|
||||
if (!check_inv_access(ma->from_inv) ||
|
||||
!check_inv_access(ma->to_inv))
|
||||
|
@ -689,6 +690,7 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt)
|
|||
da->from_inv.applyCurrentPlayer(player->getName());
|
||||
|
||||
m_inventory_mgr->setInventoryModified(da->from_inv);
|
||||
mark_player_inv_list_dirty(da->from_inv, da->from_list);
|
||||
|
||||
/*
|
||||
Disable dropping items out of craftpreview
|
||||
|
@ -721,6 +723,7 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt)
|
|||
ca->craft_inv.applyCurrentPlayer(player->getName());
|
||||
|
||||
m_inventory_mgr->setInventoryModified(ca->craft_inv);
|
||||
// Note: `ICraftAction::clientApply` is empty, thus nothing to revert.
|
||||
|
||||
// Disallow crafting if not allowed to interact
|
||||
if (!player_has_interact) {
|
||||
|
@ -747,15 +750,12 @@ void Server::handleCommand_ChatMessage(NetworkPacket* pkt)
|
|||
|
||||
session_t peer_id = pkt->getPeerId();
|
||||
RemotePlayer *player = m_env->getPlayer(peer_id);
|
||||
if (player == NULL) {
|
||||
errorstream <<
|
||||
"Server::ProcessData(): Canceling: No player for peer_id=" <<
|
||||
peer_id << " disconnecting peer!" << std::endl;
|
||||
DisconnectPeer(peer_id);
|
||||
if (!player) {
|
||||
warningstream << FUNCTION_NAME << ": player is null" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string name = player->getName();
|
||||
const auto &name = player->getName();
|
||||
|
||||
std::wstring answer_to_sender = handleChat(name, message, true, player);
|
||||
if (!answer_to_sender.empty()) {
|
||||
|
@ -773,29 +773,22 @@ void Server::handleCommand_Damage(NetworkPacket* pkt)
|
|||
|
||||
session_t peer_id = pkt->getPeerId();
|
||||
RemotePlayer *player = m_env->getPlayer(peer_id);
|
||||
|
||||
if (player == NULL) {
|
||||
errorstream <<
|
||||
"Server::ProcessData(): Canceling: No player for peer_id=" <<
|
||||
peer_id << " disconnecting peer!" << std::endl;
|
||||
DisconnectPeer(peer_id);
|
||||
if (!player) {
|
||||
warningstream << FUNCTION_NAME << ": player is null" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerSAO *playersao = player->getPlayerSAO();
|
||||
if (playersao == NULL) {
|
||||
errorstream <<
|
||||
"Server::ProcessData(): Canceling: No player object for peer_id=" <<
|
||||
peer_id << " disconnecting peer!" << std::endl;
|
||||
DisconnectPeer(peer_id);
|
||||
if (!playersao) {
|
||||
warningstream << FUNCTION_NAME << ": player SAO is null" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!playersao->isImmortal()) {
|
||||
if (playersao->isDead()) {
|
||||
verbosestream << "Server::ProcessData(): Info: "
|
||||
verbosestream << "Server: "
|
||||
"Ignoring damage as player " << player->getName()
|
||||
<< " is already dead." << std::endl;
|
||||
<< " is already dead" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -815,21 +808,14 @@ void Server::handleCommand_PlayerItem(NetworkPacket* pkt)
|
|||
|
||||
session_t peer_id = pkt->getPeerId();
|
||||
RemotePlayer *player = m_env->getPlayer(peer_id);
|
||||
|
||||
if (player == NULL) {
|
||||
errorstream <<
|
||||
"Server::ProcessData(): Canceling: No player for peer_id=" <<
|
||||
peer_id << " disconnecting peer!" << std::endl;
|
||||
DisconnectPeer(peer_id);
|
||||
if (!player) {
|
||||
warningstream << FUNCTION_NAME << ": player is null" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerSAO *playersao = player->getPlayerSAO();
|
||||
if (playersao == NULL) {
|
||||
errorstream <<
|
||||
"Server::ProcessData(): Canceling: No player object for peer_id=" <<
|
||||
peer_id << " disconnecting peer!" << std::endl;
|
||||
DisconnectPeer(peer_id);
|
||||
if (!playersao) {
|
||||
warningstream << FUNCTION_NAME << ": player SAO is null" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -838,7 +824,7 @@ void Server::handleCommand_PlayerItem(NetworkPacket* pkt)
|
|||
*pkt >> item;
|
||||
|
||||
if (item >= player->getMaxHotbarItemcount()) {
|
||||
actionstream << "Player: " << player->getName()
|
||||
actionstream << "Player " << player->getName()
|
||||
<< " tried to access item=" << item
|
||||
<< " out of hotbar_itemcount="
|
||||
<< player->getMaxHotbarItemcount()
|
||||
|
@ -852,8 +838,8 @@ void Server::handleCommand_PlayerItem(NetworkPacket* pkt)
|
|||
bool Server::checkInteractDistance(RemotePlayer *player, const f32 d, const std::string &what)
|
||||
{
|
||||
ItemStack selected_item, hand_item;
|
||||
player->getWieldedItem(&selected_item, &hand_item);
|
||||
f32 max_d = BS * getToolRange(selected_item, hand_item, m_itemdef);
|
||||
const ItemStack &tool_item = player->getWieldedItem(&selected_item, &hand_item);
|
||||
f32 max_d = BS * getToolRange(tool_item, hand_item, m_itemdef);
|
||||
|
||||
// Cube diagonal * 1.5 for maximal supported node extents:
|
||||
// sqrt(3) * 1.5 ≅ 2.6
|
||||
|
@ -903,21 +889,14 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
|
|||
|
||||
session_t peer_id = pkt->getPeerId();
|
||||
RemotePlayer *player = m_env->getPlayer(peer_id);
|
||||
|
||||
if (player == NULL) {
|
||||
errorstream <<
|
||||
"Server::ProcessData(): Canceling: No player for peer_id=" <<
|
||||
peer_id << " disconnecting peer!" << std::endl;
|
||||
DisconnectPeer(peer_id);
|
||||
if (!player) {
|
||||
warningstream << FUNCTION_NAME << ": player is null" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerSAO *playersao = player->getPlayerSAO();
|
||||
if (playersao == NULL) {
|
||||
errorstream <<
|
||||
"Server::ProcessData(): Canceling: No player object for peer_id=" <<
|
||||
peer_id << " disconnecting peer!" << std::endl;
|
||||
DisconnectPeer(peer_id);
|
||||
if (!playersao) {
|
||||
warningstream << FUNCTION_NAME << ": player SAO is null" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -942,7 +921,7 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
|
|||
// Update wielded item
|
||||
|
||||
if (item_i >= player->getMaxHotbarItemcount()) {
|
||||
actionstream << "Player: " << player->getName()
|
||||
actionstream << "Player " << player->getName()
|
||||
<< " tried to access item=" << item_i
|
||||
<< " out of hotbar_itemcount="
|
||||
<< player->getMaxHotbarItemcount()
|
||||
|
@ -1061,7 +1040,7 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
|
|||
ItemStack selected_item, hand_item;
|
||||
ItemStack tool_item = playersao->getWieldedItem(&selected_item, &hand_item);
|
||||
ToolCapabilities toolcap =
|
||||
tool_item.getToolCapabilities(m_itemdef);
|
||||
tool_item.getToolCapabilities(m_itemdef, &hand_item);
|
||||
v3f dir = (pointed_object->getBasePosition() -
|
||||
(playersao->getBasePosition() + playersao->getEyeOffset())
|
||||
).normalize();
|
||||
|
@ -1118,12 +1097,12 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
|
|||
// Get player's wielded item
|
||||
// See also: Game::handleDigging
|
||||
ItemStack selected_item, hand_item;
|
||||
player->getWieldedItem(&selected_item, &hand_item);
|
||||
ItemStack &tool_item = player->getWieldedItem(&selected_item, &hand_item);
|
||||
|
||||
// Get diggability and expected digging time
|
||||
DigParams params = getDigParams(m_nodedef->get(n).groups,
|
||||
&selected_item.getToolCapabilities(m_itemdef),
|
||||
selected_item.wear);
|
||||
&tool_item.getToolCapabilities(m_itemdef, &hand_item),
|
||||
tool_item.wear);
|
||||
// If can't dig, try hand
|
||||
if (!params.diggable) {
|
||||
params = getDigParams(m_nodedef->get(n).groups,
|
||||
|
@ -1333,21 +1312,14 @@ void Server::handleCommand_NodeMetaFields(NetworkPacket* pkt)
|
|||
{
|
||||
session_t peer_id = pkt->getPeerId();
|
||||
RemotePlayer *player = m_env->getPlayer(peer_id);
|
||||
|
||||
if (player == NULL) {
|
||||
errorstream <<
|
||||
"Server::ProcessData(): Canceling: No player for peer_id=" <<
|
||||
peer_id << " disconnecting peer!" << std::endl;
|
||||
DisconnectPeer(peer_id);
|
||||
if (!player) {
|
||||
warningstream << FUNCTION_NAME << ": player is null" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerSAO *playersao = player->getPlayerSAO();
|
||||
if (playersao == NULL) {
|
||||
errorstream <<
|
||||
"Server::ProcessData(): Canceling: No player object for peer_id=" <<
|
||||
peer_id << " disconnecting peer!" << std::endl;
|
||||
DisconnectPeer(peer_id);
|
||||
if (!playersao) {
|
||||
warningstream << FUNCTION_NAME << ": player SAO is null" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1420,25 +1392,26 @@ void Server::handleCommand_InventoryFields(NetworkPacket* pkt)
|
|||
}
|
||||
|
||||
// verify that we displayed the formspec to the user
|
||||
const auto peer_state_iterator = m_formspec_state_data.find(peer_id);
|
||||
if (peer_state_iterator != m_formspec_state_data.end()) {
|
||||
const std::string &server_formspec_name = peer_state_iterator->second;
|
||||
const auto it = m_formspec_state_data.find(peer_id);
|
||||
if (it != m_formspec_state_data.end()) {
|
||||
const auto &server_formspec_name = it->second;
|
||||
if (client_formspec_name == server_formspec_name) {
|
||||
auto it = fields.find("quit");
|
||||
if (it != fields.end() && it->second == "true")
|
||||
m_formspec_state_data.erase(peer_state_iterator);
|
||||
// delete state if formspec was closed
|
||||
auto it2 = fields.find("quit");
|
||||
if (it2 != fields.end() && it2->second == "true")
|
||||
m_formspec_state_data.erase(it);
|
||||
|
||||
m_script->on_playerReceiveFields(playersao, client_formspec_name, fields);
|
||||
return;
|
||||
}
|
||||
actionstream << "'" << player->getName()
|
||||
<< "' submitted formspec ('" << client_formspec_name
|
||||
actionstream << player->getName()
|
||||
<< " submitted formspec ('" << client_formspec_name
|
||||
<< "') but the name of the formspec doesn't match the"
|
||||
" expected name ('" << server_formspec_name << "')";
|
||||
|
||||
} else {
|
||||
actionstream << "'" << player->getName()
|
||||
<< "' submitted formspec ('" << client_formspec_name
|
||||
actionstream << player->getName()
|
||||
<< " submitted formspec ('" << client_formspec_name
|
||||
<< "') but server hasn't sent formspec to client";
|
||||
}
|
||||
actionstream << ", possible exploitation attempt" << std::endl;
|
||||
|
|
|
@ -87,25 +87,16 @@ bool UDPSocket::init(bool ipv6, bool noExceptions)
|
|||
m_handle = socket(m_addr_family, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
if (m_handle < 0) {
|
||||
if (noExceptions) {
|
||||
auto msg = std::string("Failed to create socket: ") +
|
||||
SOCKET_ERR_STR(LAST_SOCKET_ERR());
|
||||
verbosestream << msg << std::endl;
|
||||
if (noExceptions)
|
||||
return false;
|
||||
}
|
||||
|
||||
throw SocketException(std::string("Failed to create socket: error ") +
|
||||
SOCKET_ERR_STR(LAST_SOCKET_ERR()));
|
||||
throw SocketException(msg);
|
||||
}
|
||||
|
||||
setTimeoutMs(0);
|
||||
|
||||
if (m_addr_family == AF_INET6) {
|
||||
// Allow our socket to accept both IPv4 and IPv6 connections
|
||||
// required on Windows:
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/bb513665(v=vs.85).aspx
|
||||
int value = 0;
|
||||
setsockopt(m_handle, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
reinterpret_cast<char *>(&value), sizeof(value));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -129,6 +120,20 @@ void UDPSocket::Bind(Address addr)
|
|||
throw SocketException(errmsg);
|
||||
}
|
||||
|
||||
if (m_addr_family == AF_INET6) {
|
||||
// Allow our socket to accept both IPv4 and IPv6 connections
|
||||
// required on Windows:
|
||||
// <https://msdn.microsoft.com/en-us/library/windows/desktop/bb513665(v=vs.85).aspx>
|
||||
int value = 0;
|
||||
if (setsockopt(m_handle, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
reinterpret_cast<char *>(&value), sizeof(value)) != 0) {
|
||||
auto errmsg = SOCKET_ERR_STR(LAST_SOCKET_ERR());
|
||||
errorstream << "Failed to disable V6ONLY: " << errmsg
|
||||
<< "\nTry disabling ipv6_server to fix this." << std::endl;
|
||||
throw SocketException(errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
|
||||
if (m_addr_family == AF_INET6) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue