aboutsummaryrefslogtreecommitdiff
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/clientopcodes.cpp10
-rw-r--r--src/network/clientpackethandler.cpp37
-rw-r--r--src/network/connection.cpp157
-rw-r--r--src/network/connection.h24
-rw-r--r--src/network/connectionthreads.cpp18
-rw-r--r--src/network/connectionthreads.h25
-rw-r--r--src/network/networkprotocol.h53
-rw-r--r--src/network/peerhandler.h3
-rw-r--r--src/network/serveropcodes.cpp90
-rw-r--r--src/network/serverpackethandler.cpp202
10 files changed, 349 insertions, 270 deletions
diff --git a/src/network/clientopcodes.cpp b/src/network/clientopcodes.cpp
index 7f3ab50ed..498583df9 100644
--- a/src/network/clientopcodes.cpp
+++ b/src/network/clientopcodes.cpp
@@ -67,7 +67,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
null_command_handler,
{ "TOCLIENT_TIME_OF_DAY", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_TimeOfDay }, // 0x29
{ "TOCLIENT_CSM_RESTRICTION_FLAGS", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_CSMRestrictionFlags }, // 0x2A
- null_command_handler,
+ { "TOCLIENT_PLAYER_SPEED", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_PlayerSpeed }, // 0x2B
null_command_handler,
null_command_handler,
null_command_handler,
@@ -78,7 +78,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
{ "TOCLIENT_HP", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_HP }, // 0x33
{ "TOCLIENT_MOVE_PLAYER", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_MovePlayer }, // 0x34
{ "TOCLIENT_ACCESS_DENIED_LEGACY", TOCLIENT_STATE_NOT_CONNECTED, &Client::handleCommand_AccessDenied }, // 0x35
- null_command_handler,
+ { "TOCLIENT_FOV", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_Fov }, // 0x36
{ "TOCLIENT_DEATHSCREEN", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_DeathScreen }, // 0x37
{ "TOCLIENT_MEDIA", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_Media }, // 0x38
null_command_handler,
@@ -151,9 +151,9 @@ const ServerCommandFactory serverCommandFactoryTable[TOSERVER_NUM_MSG_TYPES] =
null_command_factory, // 0x14
null_command_factory, // 0x15
null_command_factory, // 0x16
- { "TOSERVER_MODCHANNEL_JOIN", 0, true }, // 0x17
- { "TOSERVER_MODCHANNEL_LEAVE", 0, true }, // 0x18
- { "TOSERVER_MODCHANNEL_MSG", 0, true }, // 0x19
+ { "TOSERVER_MODCHANNEL_JOIN", 0, true }, // 0x17
+ { "TOSERVER_MODCHANNEL_LEAVE", 0, true }, // 0x18
+ { "TOSERVER_MODCHANNEL_MSG", 0, true }, // 0x19
null_command_factory, // 0x1a
null_command_factory, // 0x1b
null_command_factory, // 0x1c
diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp
index 2f5deae2a..b6e9defb0 100644
--- a/src/network/clientpackethandler.cpp
+++ b/src/network/clientpackethandler.cpp
@@ -333,7 +333,7 @@ void Client::handleCommand_Inventory(NetworkPacket* pkt)
player->inventory.deSerialize(is);
- m_inventory_updated = true;
+ m_update_wielded_item = true;
delete m_inventory_from_server;
m_inventory_from_server = new Inventory(player->inventory);
@@ -415,7 +415,7 @@ void Client::handleCommand_ChatMessage(NetworkPacket *pkt)
chatMessage->type = (ChatMessageType) message_type;
// @TODO send this to CSM using ChatMessage object
- if (moddingEnabled() && m_script->on_receiving_message(
+ if (modsLoaded() && m_script->on_receiving_message(
wide_to_utf8(chatMessage->message))) {
// Message was consumed by CSM and should not be handled by client
delete chatMessage;
@@ -463,6 +463,10 @@ void Client::handleCommand_ActiveObjectRemoveAdd(NetworkPacket* pkt)
infostream << "handleCommand_ActiveObjectRemoveAdd: " << e.what()
<< ". The packet is unreliable, ignoring" << std::endl;
}
+
+ // m_activeobjects_received is false before the first
+ // TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD packet is received
+ m_activeobjects_received = true;
}
void Client::handleCommand_ActiveObjectMessages(NetworkPacket* pkt)
@@ -519,22 +523,30 @@ void Client::handleCommand_Movement(NetworkPacket* pkt)
player->movement_gravity = g * BS;
}
-void Client::handleCommand_HP(NetworkPacket* pkt)
+void Client::handleCommand_Fov(NetworkPacket *pkt)
{
+ f32 fov;
+ bool is_multiplier;
+ *pkt >> fov >> is_multiplier;
LocalPlayer *player = m_env.getLocalPlayer();
+ player->setFov({ fov, is_multiplier });
+}
+
+void Client::handleCommand_HP(NetworkPacket *pkt)
+{
+ LocalPlayer *player = m_env.getLocalPlayer();
assert(player != NULL);
- u16 oldhp = player->hp;
+ u16 oldhp = player->hp;
u16 hp;
*pkt >> hp;
player->hp = hp;
- if (moddingEnabled()) {
+ if (modsLoaded())
m_script->on_hp_modification(hp);
- }
if (hp < oldhp) {
// Add to ClientEvent queue
@@ -900,7 +912,7 @@ void Client::handleCommand_DetachedInventory(NetworkPacket* pkt)
u16 ignore;
*pkt >> ignore; // this used to be the length of the following string, ignore it
- std::string contents = pkt->getRemainingString();
+ std::string contents(pkt->getRemainingString(), pkt->getRemainingBytes());
std::istringstream is(contents, std::ios::binary);
inv->deSerialize(is);
}
@@ -1383,6 +1395,17 @@ void Client::handleCommand_CSMRestrictionFlags(NetworkPacket *pkt)
loadMods();
}
+void Client::handleCommand_PlayerSpeed(NetworkPacket *pkt)
+{
+ v3f added_vel;
+
+ *pkt >> added_vel;
+
+ LocalPlayer *player = m_env.getLocalPlayer();
+ assert(player != NULL);
+ player->addVelocity(added_vel);
+}
+
/*
* Mod channels
*/
diff --git a/src/network/connection.cpp b/src/network/connection.cpp
index 28084c921..0bc13a2f0 100644
--- a/src/network/connection.cpp
+++ b/src/network/connection.cpp
@@ -56,7 +56,7 @@ std::mutex log_message_mutex;
#define PING_TIMEOUT 5.0
-BufferedPacket makePacket(Address &address, SharedBuffer<u8> data,
+BufferedPacket makePacket(Address &address, const SharedBuffer<u8> &data,
u32 protocol_id, session_t sender_peer_id, u8 channel)
{
u32 packet_size = data.getSize() + BASE_HEADER_SIZE;
@@ -126,7 +126,7 @@ void makeSplitPacket(const SharedBuffer<u8> &data, u32 chunksize_max, u16 seqnum
}
}
-void makeAutoSplitPacket(SharedBuffer<u8> data, u32 chunksize_max,
+void makeAutoSplitPacket(const SharedBuffer<u8> &data, u32 chunksize_max,
u16 &split_seqnum, std::list<SharedBuffer<u8>> *list)
{
u32 original_header_size = 1;
@@ -140,7 +140,7 @@ void makeAutoSplitPacket(SharedBuffer<u8> data, u32 chunksize_max,
list->push_back(makeOriginalPacket(data));
}
-SharedBuffer<u8> makeReliablePacket(SharedBuffer<u8> data, u16 seqnum)
+SharedBuffer<u8> makeReliablePacket(const SharedBuffer<u8> &data, u16 seqnum)
{
u32 header_size = 3;
u32 packet_size = data.getSize() + header_size;
@@ -169,6 +169,7 @@ void ReliablePacketBuffer::print()
index++;
}
}
+
bool ReliablePacketBuffer::empty()
{
MutexAutoLock listlock(m_list_mutex);
@@ -177,12 +178,8 @@ bool ReliablePacketBuffer::empty()
u32 ReliablePacketBuffer::size()
{
- return m_list_size;
-}
-
-bool ReliablePacketBuffer::containsPacket(u16 seqnum)
-{
- return !(findPacket(seqnum) == m_list.end());
+ MutexAutoLock listlock(m_list_mutex);
+ return m_list.size();
}
RPBSearchResult ReliablePacketBuffer::findPacket(u16 seqnum)
@@ -191,24 +188,24 @@ RPBSearchResult ReliablePacketBuffer::findPacket(u16 seqnum)
for(; i != m_list.end(); ++i)
{
u16 s = readU16(&(i->data[BASE_HEADER_SIZE+1]));
- /*dout_con<<"findPacket(): finding seqnum="<<seqnum
- <<", comparing to s="<<s<<std::endl;*/
if (s == seqnum)
break;
}
return i;
}
+
RPBSearchResult ReliablePacketBuffer::notFound()
{
return m_list.end();
}
+
bool ReliablePacketBuffer::getFirstSeqnum(u16& result)
{
MutexAutoLock listlock(m_list_mutex);
if (m_list.empty())
return false;
- BufferedPacket p = *m_list.begin();
- result = readU16(&p.data[BASE_HEADER_SIZE+1]);
+ const BufferedPacket &p = *m_list.begin();
+ result = readU16(&p.data[BASE_HEADER_SIZE + 1]);
return true;
}
@@ -219,16 +216,16 @@ BufferedPacket ReliablePacketBuffer::popFirst()
throw NotFoundException("Buffer is empty");
BufferedPacket p = *m_list.begin();
m_list.erase(m_list.begin());
- --m_list_size;
- if (m_list_size == 0) {
+ if (m_list.empty()) {
m_oldest_non_answered_ack = 0;
} else {
m_oldest_non_answered_ack =
- readU16(&(*m_list.begin()).data[BASE_HEADER_SIZE+1]);
+ readU16(&m_list.begin()->data[BASE_HEADER_SIZE + 1]);
}
return p;
}
+
BufferedPacket ReliablePacketBuffer::popSeqnum(u16 seqnum)
{
MutexAutoLock listlock(m_list_mutex);
@@ -249,15 +246,17 @@ BufferedPacket ReliablePacketBuffer::popSeqnum(u16 seqnum)
}
m_list.erase(r);
- --m_list_size;
- if (m_list_size == 0)
- { m_oldest_non_answered_ack = 0; }
- else
- { m_oldest_non_answered_ack = readU16(&(*m_list.begin()).data[BASE_HEADER_SIZE+1]); }
+ if (m_list.empty()) {
+ m_oldest_non_answered_ack = 0;
+ } else {
+ m_oldest_non_answered_ack =
+ readU16(&m_list.begin()->data[BASE_HEADER_SIZE + 1]);
+ }
return p;
}
-void ReliablePacketBuffer::insert(BufferedPacket &p,u16 next_expected)
+
+void ReliablePacketBuffer::insert(BufferedPacket &p, u16 next_expected)
{
MutexAutoLock listlock(m_list_mutex);
if (p.data.getSize() < BASE_HEADER_SIZE + 3) {
@@ -284,8 +283,7 @@ void ReliablePacketBuffer::insert(BufferedPacket &p,u16 next_expected)
return;
}
- ++m_list_size;
- sanity_check(m_list_size <= SEQNUM_MAX+1); // FIXME: Handle the error?
+ sanity_check(m_list.size() <= SEQNUM_MAX); // FIXME: Handle the error?
// Find the right place for the packet and insert it there
// If list is empty, just add it
@@ -322,6 +320,8 @@ void ReliablePacketBuffer::insert(BufferedPacket &p,u16 next_expected)
}
if (s == seqnum) {
+ /* nothing to do this seems to be a resent packet */
+ /* for paranoia reason data should be compared */
if (
(readU16(&(i->data[BASE_HEADER_SIZE+1])) != seqnum) ||
(i->data.getSize() != p.data.getSize()) ||
@@ -340,16 +340,11 @@ void ReliablePacketBuffer::insert(BufferedPacket &p,u16 next_expected)
p.address.serializeString().c_str());
throw IncomingDataCorruption("duplicated packet isn't same as original one");
}
-
- /* nothing to do this seems to be a resent packet */
- /* for paranoia reason data should be compared */
- --m_list_size;
}
/* insert or push back */
else if (i != m_list.end()) {
m_list.insert(i, p);
- }
- else {
+ } else {
m_list.push_back(p);
}
@@ -385,6 +380,48 @@ std::list<BufferedPacket> ReliablePacketBuffer::getTimedOuts(float timeout,
}
/*
+ IncomingSplitPacket
+*/
+
+bool IncomingSplitPacket::insert(u32 chunk_num, SharedBuffer<u8> &chunkdata)
+{
+ sanity_check(chunk_num < chunk_count);
+
+ // If chunk already exists, ignore it.
+ // Sometimes two identical packets may arrive when there is network
+ // lag and the server re-sends stuff.
+ if (chunks.find(chunk_num) != chunks.end())
+ return false;
+
+ // Set chunk data in buffer
+ chunks[chunk_num] = chunkdata;
+
+ return true;
+}
+
+SharedBuffer<u8> IncomingSplitPacket::reassemble()
+{
+ sanity_check(allReceived());
+
+ // Calculate total size
+ u32 totalsize = 0;
+ for (const auto &chunk : chunks)
+ totalsize += chunk.second.getSize();
+
+ SharedBuffer<u8> fulldata(totalsize);
+
+ // Copy chunks to data buffer
+ u32 start = 0;
+ for (u32 chunk_i = 0; chunk_i < chunk_count; chunk_i++) {
+ const SharedBuffer<u8> &buf = chunks[chunk_i];
+ memcpy(&fulldata[start], *buf, buf.getSize());
+ start += buf.getSize();
+ }
+
+ return fulldata;
+}
+
+/*
IncomingSplitBuffer
*/
@@ -395,10 +432,7 @@ IncomingSplitBuffer::~IncomingSplitBuffer()
delete i.second;
}
}
-/*
- This will throw a GotSplitPacketException when a full
- split packet is constructed.
-*/
+
SharedBuffer<u8> IncomingSplitBuffer::insert(const BufferedPacket &p, bool reliable)
{
MutexAutoLock listlock(m_map_mutex);
@@ -417,57 +451,45 @@ SharedBuffer<u8> IncomingSplitBuffer::insert(const BufferedPacket &p, bool relia
<< std::endl;
return SharedBuffer<u8>();
}
+ if (chunk_num >= chunk_count) {
+ errorstream << "IncomingSplitBuffer::insert(): chunk_num=" << chunk_num
+ << " >= chunk_count=" << chunk_count << std::endl;
+ return SharedBuffer<u8>();
+ }
// Add if doesn't exist
+ IncomingSplitPacket *sp;
if (m_buf.find(seqnum) == m_buf.end()) {
- m_buf[seqnum] = new IncomingSplitPacket(chunk_count, reliable);
+ sp = new IncomingSplitPacket(chunk_count, reliable);
+ m_buf[seqnum] = sp;
+ } else {
+ sp = m_buf[seqnum];
}
- IncomingSplitPacket *sp = m_buf[seqnum];
-
- if (chunk_count != sp->chunk_count)
- LOG(derr_con<<"Connection: WARNING: chunk_count="<<chunk_count
- <<" != sp->chunk_count="<<sp->chunk_count
- <<std::endl);
+ if (chunk_count != sp->chunk_count) {
+ errorstream << "IncomingSplitBuffer::insert(): chunk_count="
+ << chunk_count << " != sp->chunk_count=" << sp->chunk_count
+ << std::endl;
+ return SharedBuffer<u8>();
+ }
if (reliable != sp->reliable)
LOG(derr_con<<"Connection: WARNING: reliable="<<reliable
<<" != sp->reliable="<<sp->reliable
<<std::endl);
- // If chunk already exists, ignore it.
- // Sometimes two identical packets may arrive when there is network
- // lag and the server re-sends stuff.
- if (sp->chunks.find(chunk_num) != sp->chunks.end())
- return SharedBuffer<u8>();
-
// Cut chunk data out of packet
u32 chunkdatasize = p.data.getSize() - headersize;
SharedBuffer<u8> chunkdata(chunkdatasize);
memcpy(*chunkdata, &(p.data[headersize]), chunkdatasize);
- // Set chunk data in buffer
- sp->chunks[chunk_num] = chunkdata;
+ if (!sp->insert(chunk_num, chunkdata))
+ return SharedBuffer<u8>();
// If not all chunks are received, return empty buffer
if (!sp->allReceived())
return SharedBuffer<u8>();
- // Calculate total size
- u32 totalsize = 0;
- for (const auto &chunk : sp->chunks) {
- totalsize += chunk.second.getSize();
- }
-
- SharedBuffer<u8> fulldata(totalsize);
-
- // Copy chunks to data buffer
- u32 start = 0;
- for (u32 chunk_i=0; chunk_i<sp->chunk_count; chunk_i++) {
- const SharedBuffer<u8> &buf = sp->chunks[chunk_i];
- u16 buf_chunkdatasize = buf.getSize();
- memcpy(&fulldata[start], *buf, buf_chunkdatasize);
- start += buf_chunkdatasize;
- }
+ SharedBuffer<u8> fulldata = sp->reassemble();
// Remove sp from buffer
m_buf.erase(seqnum);
@@ -475,6 +497,7 @@ SharedBuffer<u8> IncomingSplitBuffer::insert(const BufferedPacket &p, bool relia
return fulldata;
}
+
void IncomingSplitBuffer::removeUnreliableTimedOuts(float dtime, float timeout)
{
std::deque<u16> remove_queue;
@@ -849,8 +872,8 @@ void Peer::RTTStatistics(float rtt, const std::string &profiler_id,
jitter * (1/num_samples);
if (!profiler_id.empty()) {
- g_profiler->graphAdd(profiler_id + "_rtt", rtt);
- g_profiler->graphAdd(profiler_id + "_jitter", jitter);
+ g_profiler->graphAdd(profiler_id + " RTT [ms]", rtt * 1000.f);
+ g_profiler->graphAdd(profiler_id + " jitter [ms]", jitter * 1000.f);
}
}
/* save values required for next loop */
diff --git a/src/network/connection.h b/src/network/connection.h
index 346c7f886..057bd39f6 100644
--- a/src/network/connection.h
+++ b/src/network/connection.h
@@ -103,16 +103,16 @@ struct BufferedPacket
};
// This adds the base headers to the data and makes a packet out of it
-BufferedPacket makePacket(Address &address, SharedBuffer<u8> data,
+BufferedPacket makePacket(Address &address, const SharedBuffer<u8> &data,
u32 protocol_id, session_t sender_peer_id, u8 channel);
// Depending on size, make a TYPE_ORIGINAL or TYPE_SPLIT packet
// Increments split_seqnum if a split packet is made
-void makeAutoSplitPacket(SharedBuffer<u8> data, u32 chunksize_max,
+void makeAutoSplitPacket(const SharedBuffer<u8> &data, u32 chunksize_max,
u16 &split_seqnum, std::list<SharedBuffer<u8>> *list);
// Add the TYPE_RELIABLE header to the data
-SharedBuffer<u8> makeReliablePacket(SharedBuffer<u8> data, u16 seqnum);
+SharedBuffer<u8> makeReliablePacket(const SharedBuffer<u8> &data, u16 seqnum);
struct IncomingSplitPacket
{
@@ -121,16 +121,20 @@ struct IncomingSplitPacket
IncomingSplitPacket() = delete;
- // Key is chunk number, value is data without headers
- std::map<u16, SharedBuffer<u8>> chunks;
- u32 chunk_count;
float time = 0.0f; // Seconds from adding
- bool reliable = false; // If true, isn't deleted on timeout
+ u32 chunk_count;
+ bool reliable; // If true, isn't deleted on timeout
bool allReceived() const
{
return (chunks.size() == chunk_count);
}
+ bool insert(u32 chunk_num, SharedBuffer<u8> &chunkdata);
+ SharedBuffer<u8> reassemble();
+
+private:
+ // Key is chunk number, value is data without headers
+ std::map<u16, SharedBuffer<u8>> chunks;
};
/*
@@ -240,7 +244,7 @@ public:
BufferedPacket popFirst();
BufferedPacket popSeqnum(u16 seqnum);
- void insert(BufferedPacket &p,u16 next_expected);
+ void insert(BufferedPacket &p, u16 next_expected);
void incrementTimeouts(float dtime);
std::list<BufferedPacket> getTimedOuts(float timeout,
@@ -248,16 +252,14 @@ public:
void print();
bool empty();
- bool containsPacket(u16 seqnum);
RPBSearchResult notFound();
u32 size();
private:
- RPBSearchResult findPacket(u16 seqnum);
+ RPBSearchResult findPacket(u16 seqnum); // does not perform locking
std::list<BufferedPacket> m_list;
- u32 m_list_size = 0;
u16 m_oldest_non_answered_ack;
diff --git a/src/network/connectionthreads.cpp b/src/network/connectionthreads.cpp
index 63a9064e7..f8b58c025 100644
--- a/src/network/connectionthreads.cpp
+++ b/src/network/connectionthreads.cpp
@@ -327,7 +327,7 @@ void ConnectionSendThread::sendAsPacketReliable(BufferedPacket &p, Channel *chan
}
bool ConnectionSendThread::rawSendAsPacket(session_t peer_id, u8 channelnum,
- SharedBuffer<u8> data, bool reliable)
+ const SharedBuffer<u8> &data, bool reliable)
{
PeerHelper peer = m_connection->getPeerNoEx(peer_id);
if (!peer) {
@@ -575,7 +575,7 @@ void ConnectionSendThread::disconnect_peer(session_t peer_id)
}
void ConnectionSendThread::send(session_t peer_id, u8 channelnum,
- SharedBuffer<u8> data)
+ const SharedBuffer<u8> &data)
{
assert(channelnum < CHANNEL_COUNT); // Pre-condition
@@ -615,7 +615,7 @@ void ConnectionSendThread::sendReliable(ConnectionCommand &c)
peer->PutReliableSendCommand(c, m_max_packet_size);
}
-void ConnectionSendThread::sendToAll(u8 channelnum, SharedBuffer<u8> data)
+void ConnectionSendThread::sendToAll(u8 channelnum, const SharedBuffer<u8> &data)
{
std::list<session_t> peerids = m_connection->getPeerIDs();
@@ -776,7 +776,7 @@ void ConnectionSendThread::sendPackets(float dtime)
}
void ConnectionSendThread::sendAsPacket(session_t peer_id, u8 channelnum,
- SharedBuffer<u8> data, bool ack)
+ const SharedBuffer<u8> &data, bool ack)
{
OutgoingPacket packet(peer_id, channelnum, data, false, ack);
m_outgoing_queue.push(packet);
@@ -1086,7 +1086,7 @@ bool ConnectionReceiveThread::checkIncomingBuffers(Channel *channel,
}
SharedBuffer<u8> ConnectionReceiveThread::processPacket(Channel *channel,
- SharedBuffer<u8> packetdata, session_t peer_id, u8 channelnum, bool reliable)
+ const SharedBuffer<u8> &packetdata, session_t peer_id, u8 channelnum, bool reliable)
{
PeerHelper peer = m_connection->getPeerNoEx(peer_id);
@@ -1125,7 +1125,7 @@ const ConnectionReceiveThread::PacketTypeHandler
};
SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Control(Channel *channel,
- SharedBuffer<u8> packetdata, Peer *peer, u8 channelnum, bool reliable)
+ const SharedBuffer<u8> &packetdata, Peer *peer, u8 channelnum, bool reliable)
{
if (packetdata.getSize() < 2)
throw InvalidIncomingDataException("packetdata.getSize() < 2");
@@ -1224,7 +1224,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Control(Channel *chan
}
SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Original(Channel *channel,
- SharedBuffer<u8> packetdata, Peer *peer, u8 channelnum, bool reliable)
+ const SharedBuffer<u8> &packetdata, Peer *peer, u8 channelnum, bool reliable)
{
if (packetdata.getSize() <= ORIGINAL_HEADER_SIZE)
throw InvalidIncomingDataException
@@ -1238,7 +1238,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Original(Channel *cha
}
SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Split(Channel *channel,
- SharedBuffer<u8> packetdata, Peer *peer, u8 channelnum, bool reliable)
+ const SharedBuffer<u8> &packetdata, Peer *peer, u8 channelnum, bool reliable)
{
Address peer_address;
@@ -1269,7 +1269,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Split(Channel *channe
}
SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Reliable(Channel *channel,
- SharedBuffer<u8> packetdata, Peer *peer, u8 channelnum, bool reliable)
+ const SharedBuffer<u8> &packetdata, Peer *peer, u8 channelnum, bool reliable)
{
assert(channel != NULL);
diff --git a/src/network/connectionthreads.h b/src/network/connectionthreads.h
index ddac4ae20..da4ea92f5 100644
--- a/src/network/connectionthreads.h
+++ b/src/network/connectionthreads.h
@@ -52,8 +52,8 @@ public:
private:
void runTimeouts(float dtime);
void rawSend(const BufferedPacket &packet);
- bool rawSendAsPacket(session_t peer_id, u8 channelnum, SharedBuffer<u8> data,
- bool reliable);
+ bool rawSendAsPacket(session_t peer_id, u8 channelnum,
+ const SharedBuffer<u8> &data, bool reliable);
void processReliableCommand(ConnectionCommand &c);
void processNonReliableCommand(ConnectionCommand &c);
@@ -61,14 +61,14 @@ private:
void connect(Address address);
void disconnect();
void disconnect_peer(session_t peer_id);
- void send(session_t peer_id, u8 channelnum, SharedBuffer<u8> data);
+ void send(session_t peer_id, u8 channelnum, const SharedBuffer<u8> &data);
void sendReliable(ConnectionCommand &c);
- void sendToAll(u8 channelnum, SharedBuffer<u8> data);
+ void sendToAll(u8 channelnum, const SharedBuffer<u8> &data);
void sendToAllReliable(ConnectionCommand &c);
void sendPackets(float dtime);
- void sendAsPacket(session_t peer_id, u8 channelnum, SharedBuffer<u8> data,
+ void sendAsPacket(session_t peer_id, u8 channelnum, const SharedBuffer<u8> &data,
bool ack = false);
void sendAsPacketReliable(BufferedPacket &p, Channel *channel);
@@ -119,26 +119,27 @@ private:
channelnum: channel on which the packet was sent
reliable: true if recursing into a reliable packet
*/
- SharedBuffer<u8> processPacket(Channel *channel, SharedBuffer<u8> packetdata,
- session_t peer_id, u8 channelnum, bool reliable);
+ SharedBuffer<u8> processPacket(Channel *channel,
+ const SharedBuffer<u8> &packetdata, session_t peer_id,
+ u8 channelnum, bool reliable);
SharedBuffer<u8> handlePacketType_Control(Channel *channel,
- SharedBuffer<u8> packetdata, Peer *peer, u8 channelnum,
+ const SharedBuffer<u8> &packetdata, Peer *peer, u8 channelnum,
bool reliable);
SharedBuffer<u8> handlePacketType_Original(Channel *channel,
- SharedBuffer<u8> packetdata, Peer *peer, u8 channelnum,
+ const SharedBuffer<u8> &packetdata, Peer *peer, u8 channelnum,
bool reliable);
SharedBuffer<u8> handlePacketType_Split(Channel *channel,
- SharedBuffer<u8> packetdata, Peer *peer, u8 channelnum,
+ const SharedBuffer<u8> &packetdata, Peer *peer, u8 channelnum,
bool reliable);
SharedBuffer<u8> handlePacketType_Reliable(Channel *channel,
- SharedBuffer<u8> packetdata, Peer *peer, u8 channelnum,
+ const SharedBuffer<u8> &packetdata, Peer *peer, u8 channelnum,
bool reliable);
struct PacketTypeHandler
{
SharedBuffer<u8> (ConnectionReceiveThread::*handler)(Channel *channel,
- SharedBuffer<u8> packet, Peer *peer, u8 channelnum,
+ const SharedBuffer<u8> &packet, Peer *peer, u8 channelnum,
bool reliable);
};
diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h
index 85436068f..5a13c1353 100644
--- a/src/network/networkprotocol.h
+++ b/src/network/networkprotocol.h
@@ -194,9 +194,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
New network float format
ContentFeatures version 13
Add full Euler rotations instead of just yaw
+ Add TOCLIENT_PLAYER_SPEED
+ PROTOCOL VERSION 38:
+ Incremental inventory sending mode
+ Unknown inventory serialization fields no longer throw an error
+ Mod-specific formspec version
+ Player FOV override API
*/
-#define LATEST_PROTOCOL_VERSION 37
+#define LATEST_PROTOCOL_VERSION 38
#define LATEST_PROTOCOL_VERSION_STRING TOSTRING(LATEST_PROTOCOL_VERSION)
// Server's supported network protocol range
@@ -215,8 +221,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define PASSWORD_SIZE 28 // Maximum password length. Allows for
// base64-encoded SHA-1 (27+\0).
-#define FORMSPEC_API_VERSION 1
-#define FORMSPEC_VERSION_STRING "formspec_version[" TOSTRING(FORMSPEC_API_VERSION) "]"
+/*
+ Changes by FORMSPEC_API_VERSION:
+
+ FORMSPEC VERSION 1:
+ (too much)
+ FORMSPEC VERSION 2:
+ Forced real coordinates
+ background[]: 9-slice scaling parameters
+*/
+#define FORMSPEC_API_VERSION 2
#define TEXTURENAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.-"
@@ -295,6 +309,11 @@ enum ToClientCommand
u32 CSMRestrictionFlags byteflag
*/
+ TOCLIENT_PLAYER_SPEED = 0x2B,
+ /*
+ v3f added_vel
+ */
+
// (oops, there is some gap here)
TOCLIENT_CHAT_MESSAGE = 0x2F,
@@ -352,7 +371,13 @@ enum ToClientCommand
wstring reason
*/
- TOCLIENT_PLAYERITEM = 0x36, // Obsolete
+ TOCLIENT_FOV = 0x36,
+ /*
+ Sends an FOV override/multiplier to client.
+
+ float fov
+ bool is_multiplier
+ */
TOCLIENT_DEATHSCREEN = 0x37,
/*
@@ -954,10 +979,20 @@ enum CSMRestrictionFlags : u64 {
// When those are complete, this should return to only being a restriction on the
// loading of client mods.
CSM_RF_LOAD_CLIENT_MODS = 0x00000001, // Don't load client-provided mods or 'builtin'
- CSM_RF_CHAT_MESSAGES = 0x00000002, // Disable chat message sending from CSM
- CSM_RF_READ_ITEMDEFS = 0x00000004, // Disable itemdef lookups
- CSM_RF_READ_NODEDEFS = 0x00000008, // Disable nodedef lookups
- CSM_RF_LOOKUP_NODES = 0x00000010, // Limit node lookups
- CSM_RF_READ_PLAYERINFO = 0x00000020, // Disable player info lookups
+ CSM_RF_CHAT_MESSAGES = 0x00000002, // Disable chat message sending from CSM
+ CSM_RF_READ_ITEMDEFS = 0x00000004, // Disable itemdef lookups
+ CSM_RF_READ_NODEDEFS = 0x00000008, // Disable nodedef lookups
+ CSM_RF_LOOKUP_NODES = 0x00000010, // Limit node lookups
+ CSM_RF_READ_PLAYERINFO = 0x00000020, // Disable player info lookups
CSM_RF_ALL = 0xFFFFFFFF,
};
+
+enum InteractAction : u8
+{
+ INTERACT_START_DIGGING, // 0: start digging (from undersurface) or use
+ INTERACT_STOP_DIGGING, // 1: stop digging (all parameters ignored)
+ INTERACT_DIGGING_COMPLETED, // 2: digging completed
+ INTERACT_PLACE, // 3: place block or item (to abovesurface)
+ INTERACT_USE, // 4: use item
+ INTERACT_ACTIVATE // 5: rightclick air ("activate")
+};
diff --git a/src/network/peerhandler.h b/src/network/peerhandler.h
index 208ab801e..da65483ef 100644
--- a/src/network/peerhandler.h
+++ b/src/network/peerhandler.h
@@ -24,7 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
namespace con
{
-typedef enum {
+typedef enum
+{
MIN_RTT,
MAX_RTT,
AVG_RTT,
diff --git a/src/network/serveropcodes.cpp b/src/network/serveropcodes.cpp
index 013b549c6..8c8d49955 100644
--- a/src/network/serveropcodes.cpp
+++ b/src/network/serveropcodes.cpp
@@ -104,9 +104,9 @@ const ToServerCommandHandler toServerCommandTable[TOSERVER_NUM_MSG_TYPES] =
null_command_handler, // 0x4d
null_command_handler, // 0x4e
null_command_handler, // 0x4f
- { "TOSERVER_FIRST_SRP", TOSERVER_STATE_NOT_CONNECTED, &Server::handleCommand_FirstSrp }, // 0x50
- { "TOSERVER_SRP_BYTES_A", TOSERVER_STATE_NOT_CONNECTED, &Server::handleCommand_SrpBytesA }, // 0x51
- { "TOSERVER_SRP_BYTES_M", TOSERVER_STATE_NOT_CONNECTED, &Server::handleCommand_SrpBytesM }, // 0x52
+ { "TOSERVER_FIRST_SRP", TOSERVER_STATE_NOT_CONNECTED, &Server::handleCommand_FirstSrp }, // 0x50
+ { "TOSERVER_SRP_BYTES_A", TOSERVER_STATE_NOT_CONNECTED, &Server::handleCommand_SrpBytesA }, // 0x51
+ { "TOSERVER_SRP_BYTES_M", TOSERVER_STATE_NOT_CONNECTED, &Server::handleCommand_SrpBytesM }, // 0x52
};
const static ClientCommandFactory null_command_factory = { "TOCLIENT_NULL", 0, false };
@@ -115,51 +115,51 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] =
{
null_command_factory, // 0x00
null_command_factory, // 0x01
- { "TOCLIENT_HELLO", 0, true }, // 0x02
- { "TOCLIENT_AUTH_ACCEPT", 0, true }, // 0x03
- { "TOCLIENT_ACCEPT_SUDO_MODE", 0, true }, // 0x04
- { "TOCLIENT_DENY_SUDO_MODE", 0, true }, // 0x05
+ { "TOCLIENT_HELLO", 0, true }, // 0x02
+ { "TOCLIENT_AUTH_ACCEPT", 0, true }, // 0x03
+ { "TOCLIENT_ACCEPT_SUDO_MODE", 0, true }, // 0x04
+ { "TOCLIENT_DENY_SUDO_MODE", 0, true }, // 0x05
null_command_factory, // 0x06
null_command_factory, // 0x07
null_command_factory, // 0x08
null_command_factory, // 0x09
- { "TOCLIENT_ACCESS_DENIED", 0, true }, // 0x0A
+ { "TOCLIENT_ACCESS_DENIED", 0, true }, // 0x0A
null_command_factory, // 0x0B
null_command_factory, // 0x0C
null_command_factory, // 0x0D
null_command_factory, // 0x0E
null_command_factory, // 0x0F
- { "TOCLIENT_INIT", 0, true }, // 0x10
- null_command_factory,
- null_command_factory,
- null_command_factory,
- null_command_factory,
- null_command_factory,
- null_command_factory,
- null_command_factory,
- null_command_factory,
- null_command_factory,
- null_command_factory,
- null_command_factory,
- null_command_factory,
- null_command_factory,
- null_command_factory,
- null_command_factory,
+ { "TOCLIENT_INIT", 0, true }, // 0x10
+ null_command_factory, // 0x11
+ null_command_factory, // 0x12
+ null_command_factory, // 0x13
+ null_command_factory, // 0x14
+ null_command_factory, // 0x15
+ null_command_factory, // 0x16
+ null_command_factory, // 0x17
+ null_command_factory, // 0x18
+ null_command_factory, // 0x19
+ null_command_factory, // 0x1A
+ null_command_factory, // 0x1B
+ null_command_factory, // 0x1C
+ null_command_factory, // 0x1D
+ null_command_factory, // 0x1E
+ null_command_factory, // 0x1F
{ "TOCLIENT_BLOCKDATA", 2, true }, // 0x20
{ "TOCLIENT_ADDNODE", 0, true }, // 0x21
{ "TOCLIENT_REMOVENODE", 0, true }, // 0x22
- null_command_factory,
- null_command_factory,
- null_command_factory,
- null_command_factory,
+ null_command_factory, // 0x23
+ null_command_factory, // 0x24
+ null_command_factory, // 0x25
+ null_command_factory, // 0x26
{ "TOCLIENT_INVENTORY", 0, true }, // 0x27
- null_command_factory,
+ null_command_factory, // 0x28
{ "TOCLIENT_TIME_OF_DAY", 0, true }, // 0x29
{ "TOCLIENT_CSM_RESTRICTION_FLAGS", 0, true }, // 0x2A
- null_command_factory,
- null_command_factory,
- null_command_factory,
- null_command_factory,
+ { "TOCLIENT_PLAYER_SPEED", 0, true }, // 0x2B
+ null_command_factory, // 0x2C
+ null_command_factory, // 0x2D
+ null_command_factory, // 0x2E
{ "TOCLIENT_CHAT_MESSAGE", 0, true }, // 0x2F
null_command_factory, // 0x30
{ "TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD", 0, true }, // 0x31
@@ -167,15 +167,15 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] =
{ "TOCLIENT_HP", 0, true }, // 0x33
{ "TOCLIENT_MOVE_PLAYER", 0, true }, // 0x34
{ "TOCLIENT_ACCESS_DENIED_LEGACY", 0, true }, // 0x35
- null_command_factory, // 0x36
+ { "TOCLIENT_FOV", 0, true }, // 0x36
{ "TOCLIENT_DEATHSCREEN", 0, true }, // 0x37
{ "TOCLIENT_MEDIA", 2, true }, // 0x38
null_command_factory, // 0x39
- { "TOCLIENT_NODEDEF", 0, true }, // 0x3a
- null_command_factory, // 0x3b
- { "TOCLIENT_ANNOUNCE_MEDIA", 0, true }, // 0x3c
- { "TOCLIENT_ITEMDEF", 0, true }, // 0x3d
- null_command_factory,
+ { "TOCLIENT_NODEDEF", 0, true }, // 0x3A
+ null_command_factory, // 0x3B
+ { "TOCLIENT_ANNOUNCE_MEDIA", 0, true }, // 0x3C
+ { "TOCLIENT_ITEMDEF", 0, true }, // 0x3D
+ null_command_factory, // 0x3E
{ "TOCLIENT_PLAY_SOUND", 0, true }, // 0x3f
{ "TOCLIENT_STOP_SOUND", 0, true }, // 0x40
{ "TOCLIENT_PRIVILEGES", 0, true }, // 0x41
@@ -203,12 +203,12 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] =
{ "TOCLIENT_MODCHANNEL_MSG", 0, true }, // 0x57
{ "TOCLIENT_MODCHANNEL_SIGNAL", 0, true }, // 0x58
{ "TOCLIENT_NODEMETA_CHANGED", 0, true }, // 0x59
- null_command_factory,
- null_command_factory,
- null_command_factory,
- null_command_factory,
- null_command_factory,
- null_command_factory,
+ null_command_factory, // 0x5A
+ null_command_factory, // 0x5B
+ null_command_factory, // 0x5C
+ null_command_factory, // 0x5D
+ null_command_factory, // 0x5E
+ null_command_factory, // 0x5F
{ "TOSERVER_SRP_BYTES_S_B", 0, true }, // 0x60
{ "TOCLIENT_FORMSPEC_PREPEND", 0, true }, // 0x61
};
diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp
index 6f17d666a..d8fbeebd5 100644
--- a/src/network/serverpackethandler.cpp
+++ b/src/network/serverpackethandler.cpp
@@ -298,9 +298,6 @@ void Server::handleCommand_Init2(NetworkPacket* pkt)
infostream << "Server: Sending content to "
<< getPlayerName(pkt->getPeerId()) << std::endl;
- // Send player movement settings
- SendMovement(pkt->getPeerId());
-
// Send item definitions
SendItemDef(pkt->getPeerId(), m_itemdef, protocol_version);
@@ -312,8 +309,20 @@ void Server::handleCommand_Init2(NetworkPacket* pkt)
// Send media announcement
sendMediaAnnouncement(pkt->getPeerId(), lang);
+ RemoteClient *client = getClient(pkt->getPeerId(), CS_InitDone);
+
+ // Send active objects
+ {
+ PlayerSAO *sao = getPlayerSAO(pkt->getPeerId());
+ if (client && sao)
+ SendActiveObjectRemoveAdd(client, sao);
+ }
+
// Send detached inventories
- sendDetachedInventories(pkt->getPeerId());
+ sendDetachedInventories(pkt->getPeerId(), false);
+
+ // Send player movement settings
+ SendMovement(pkt->getPeerId());
// Send time of day
u16 time = m_env->getTimeOfDay();
@@ -323,11 +332,10 @@ void Server::handleCommand_Init2(NetworkPacket* pkt)
SendCSMRestrictionFlags(pkt->getPeerId());
// Warnings about protocol version can be issued here
- if (getClient(pkt->getPeerId())->net_proto_version < LATEST_PROTOCOL_VERSION) {
+ if (client->net_proto_version < LATEST_PROTOCOL_VERSION) {
SendChatMessage(pkt->getPeerId(), ChatMessage(CHATMESSAGE_TYPE_SYSTEM,
- L"# Server: WARNING: YOUR CLIENT'S VERSION MAY NOT BE FULLY COMPATIBLE "
- L"WITH THIS SERVER!"));
-
+ L"# Server: WARNING: YOUR CLIENT'S VERSION MAY NOT BE FULLY COMPATIBLE "
+ L"WITH THIS SERVER!"));
}
}
@@ -386,6 +394,9 @@ void Server::handleCommand_ClientReady(NetworkPacket* pkt)
peer_id, major_ver, minor_ver, patch_ver,
full_ver);
+ if (pkt->getRemainingBytes() >= 2)
+ *pkt >> playersao->getPlayer()->formspec_version;
+
const std::vector<std::string> &players = m_clients.getPlayerNames();
NetworkPacket list_pkt(TOCLIENT_UPDATE_PLAYER_LIST, 0, peer_id);
list_pkt << (u8) PLAYER_LIST_INIT << (u16) players.size();
@@ -608,10 +619,9 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt)
ma->from_inv.applyCurrentPlayer(player->getName());
ma->to_inv.applyCurrentPlayer(player->getName());
- setInventoryModified(ma->from_inv, false);
- if (ma->from_inv != ma->to_inv) {
- setInventoryModified(ma->to_inv, false);
- }
+ setInventoryModified(ma->from_inv);
+ if (ma->from_inv != ma->to_inv)
+ setInventoryModified(ma->to_inv);
bool from_inv_is_current_player =
(ma->from_inv.type == InventoryLocation::PLAYER) &&
@@ -676,7 +686,7 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt)
da->from_inv.applyCurrentPlayer(player->getName());
- setInventoryModified(da->from_inv, false);
+ setInventoryModified(da->from_inv);
/*
Disable dropping items out of craftpreview
@@ -712,7 +722,7 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt)
ca->craft_inv.applyCurrentPlayer(player->getName());
- setInventoryModified(ca->craft_inv, false);
+ setInventoryModified(ca->craft_inv);
//bool craft_inv_is_current_player =
// (ca->craft_inv.type == InventoryLocation::PLAYER) &&
@@ -731,8 +741,6 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt)
a->apply(this, playersao, this);
// Eat the action
delete a;
-
- SendInventory(playersao);
}
void Server::handleCommand_ChatMessage(NetworkPacket* pkt)
@@ -799,7 +807,7 @@ void Server::handleCommand_Damage(NetworkPacket* pkt)
return;
}
- if (g_settings->getBool("enable_damage")) {
+ if (!playersao->isImmortal()) {
if (playersao->isDead()) {
verbosestream << "Server::ProcessData(): Info: "
"Ignoring damage as player " << player->getName()
@@ -923,7 +931,7 @@ void Server::handleCommand_PlayerItem(NetworkPacket* pkt)
*pkt >> item;
- playersao->setWieldIndex(item);
+ playersao->getPlayer()->setWieldIndex(item);
}
void Server::handleCommand_Respawn(NetworkPacket* pkt)
@@ -952,22 +960,12 @@ void Server::handleCommand_Respawn(NetworkPacket* pkt)
// the previous addition has been successfully removed
}
-bool Server::checkInteractDistance(RemotePlayer *player, const f32 d, const std::string what)
+bool Server::checkInteractDistance(RemotePlayer *player, const f32 d, const std::string &what)
{
- PlayerSAO *playersao = player->getPlayerSAO();
- const InventoryList *hlist = playersao->getInventory()->getList("hand");
- const ItemDefinition &playeritem_def =
- playersao->getWieldedItem().getDefinition(m_itemdef);
- const ItemDefinition &hand_def =
- hlist ? hlist->getItem(0).getDefinition(m_itemdef) : m_itemdef->get("");
-
- float max_d = BS * playeritem_def.range;
- float max_d_hand = BS * hand_def.range;
-
- if (max_d < 0 && max_d_hand >= 0)
- max_d = max_d_hand;
- else if (max_d < 0)
- max_d = BS * 4.0f;
+ ItemStack selected_item, hand_item;
+ player->getWieldedItem(&selected_item, &hand_item);
+ f32 max_d = BS * getToolRange(selected_item.getDefinition(m_itemdef),
+ hand_item.getDefinition(m_itemdef));
// Cube diagonal * 1.5 for maximal supported node extents:
// sqrt(3) * 1.5 ≅ 2.6
@@ -978,13 +976,13 @@ bool Server::checkInteractDistance(RemotePlayer *player, const f32 d, const std:
<< "d=" << d <<", max_d=" << max_d
<< ". ignoring." << std::endl;
// Call callbacks
- m_script->on_cheat(playersao, "interacted_too_far");
+ m_script->on_cheat(player->getPlayerSAO(), "interacted_too_far");
return false;
}
return true;
}
-void Server::handleCommand_Interact(NetworkPacket* pkt)
+void Server::handleCommand_Interact(NetworkPacket *pkt)
{
/*
[0] u16 command
@@ -993,18 +991,14 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
[5] u32 length of the next item (plen)
[9] serialized PointedThing
[9 + plen] player position information
- 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
- 5: rightclick air ("activate")
*/
- u8 action;
+
+ InteractAction action;
u16 item_i;
- *pkt >> action;
+
+ *pkt >> (u8 &)action;
*pkt >> item_i;
+
std::istringstream tmp_is(pkt->readLongString(), std::ios::binary);
PointedThing pointed;
pointed.deSerialize(tmp_is);
@@ -1050,7 +1044,7 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
v3f player_pos = playersao->getLastGoodPosition();
// Update wielded item
- playersao->setWieldIndex(item_i);
+ playersao->getPlayer()->setWieldIndex(item_i);
// Get pointed to node (undefined if not POINTEDTYPE_NODE)
v3s16 p_under = pointed.node_undersurface;
@@ -1083,18 +1077,18 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
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;
+ 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(pkt->getPeerId());
// Digging completed -> under
- if (action == 2) {
+ if (action == INTERACT_DIGGING_COMPLETED) {
v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
client->SetBlockNotSent(blockpos);
}
// Placement -> above
- else if (action == 3) {
+ else if (action == INTERACT_PLACE) {
v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
client->SetBlockNotSent(blockpos);
}
@@ -1108,10 +1102,10 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
static thread_local const bool enable_anticheat =
!g_settings->getBool("disable_anticheat");
- if ((action == 0 || action == 2 || action == 3 || action == 4) &&
+ if ((action == INTERACT_START_DIGGING || action == INTERACT_DIGGING_COMPLETED ||
+ action == INTERACT_PLACE || action == INTERACT_USE) &&
enable_anticheat && !isSingleplayer()) {
- float d = playersao->getEyePosition()
- .getDistanceFrom(pointed_pos_under);
+ float d = playersao->getEyePosition().getDistanceFrom(pointed_pos_under);
if (!checkInteractDistance(player, d, pointed.dump())) {
// Re-send block to revert change on client-side
@@ -1131,12 +1125,12 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
/*
0: start digging or punch object
*/
- if (action == 0) {
+ if (action == INTERACT_START_DIGGING) {
if (pointed.type == POINTEDTHING_NODE) {
MapNode n(CONTENT_IGNORE);
bool pos_ok;
- n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
+ n = m_env->getMap().getNode(p_under, &pos_ok);
if (!pos_ok) {
infostream << "Server: Not punching: Node not found."
<< " Adding block to emerge queue."
@@ -1156,13 +1150,10 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
if (pointed_object->isGone())
return;
- actionstream<<player->getName()<<" punches object "
- <<pointed.object_id<<": "
- <<pointed_object->getDescription()<<std::endl;
-
- ItemStack punchitem = playersao->getWieldedItemOrHand();
+ ItemStack selected_item, hand_item;
+ ItemStack tool_item = playersao->getWieldedItem(&selected_item, &hand_item);
ToolCapabilities toolcap =
- punchitem.getToolCapabilities(m_itemdef);
+ tool_item.getToolCapabilities(m_itemdef);
v3f dir = (pointed_object->getBasePosition() -
(playersao->getBasePosition() + playersao->getEyeOffset())
).normalize();
@@ -1172,9 +1163,13 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
u16 src_original_hp = pointed_object->getHP();
u16 dst_origin_hp = playersao->getHP();
- pointed_object->punch(dir, &toolcap, playersao,
+ u16 wear = pointed_object->punch(dir, &toolcap, playersao,
time_from_last_punch);
+ bool changed = selected_item.addWear(wear, m_itemdef);
+ if (changed)
+ playersao->setWieldedItem(selected_item);
+
// If the object is a player and its HP changed
if (src_original_hp != pointed_object->getHP() &&
pointed_object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
@@ -1188,22 +1183,22 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, pointed_object));
}
- } // action == 0
+ } // action == INTERACT_START_DIGGING
/*
1: stop digging
*/
- else if (action == 1) {
- } // action == 1
+ else if (action == INTERACT_STOP_DIGGING) {
+ } // action == INTERACT_STOP_DIGGING
/*
2: Digging completed
*/
- else if (action == 2) {
+ else if (action == INTERACT_DIGGING_COMPLETED) {
// Only digging of nodes
if (pointed.type == POINTEDTHING_NODE) {
bool pos_ok;
- MapNode n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
+ MapNode n = m_env->getMap().getNode(p_under, &pos_ok);
if (!pos_ok) {
infostream << "Server: Not finishing digging: Node not found."
<< " Adding block to emerge queue."
@@ -1228,22 +1223,19 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
// Call callbacks
m_script->on_cheat(playersao, "finished_unknown_dig");
}
+
// Get player's wielded item
- ItemStack playeritem = playersao->getWieldedItemOrHand();
- ToolCapabilities playeritem_toolcap =
- playeritem.getToolCapabilities(m_itemdef);
+ // See also: Game::handleDigging
+ ItemStack selected_item, hand_item;
+ playersao->getPlayer()->getWieldedItem(&selected_item, &hand_item);
+
// Get diggability and expected digging time
DigParams params = getDigParams(m_nodedef->get(n).groups,
- &playeritem_toolcap);
+ &selected_item.getToolCapabilities(m_itemdef));
// If can't dig, try hand
if (!params.diggable) {
- InventoryList *hlist = playersao->getInventory()->getList("hand");
- const ToolCapabilities *tp = hlist
- ? &hlist->getItem(0).getToolCapabilities(m_itemdef)
- : m_itemdef->get("").tool_capabilities;
-
- if (tp)
- params = getDigParams(m_nodedef->get(n).groups, tp);
+ params = getDigParams(m_nodedef->get(n).groups,
+ &hand_item.getToolCapabilities(m_itemdef));
}
// If can't dig, ignore dig
if (!params.diggable) {
@@ -1290,7 +1282,7 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
RemoteClient *client = getClient(pkt->getPeerId());
// Send unusual result (that is, node not being removed)
- if (m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR) {
+ if (m_env->getMap().getNode(p_under).getContent() != CONTENT_AIR) {
// Re-send block to revert change on client-side
client->SetBlockNotSent(blockpos);
}
@@ -1298,17 +1290,18 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
client->ResendBlockIfOnWire(blockpos);
}
}
- } // action == 2
+ } // action == INTERACT_DIGGING_COMPLETED
/*
3: place block or right-click object
*/
- else if (action == 3) {
- ItemStack item = playersao->getWieldedItem();
+ else if (action == INTERACT_PLACE) {
+ ItemStack selected_item;
+ playersao->getWieldedItem(&selected_item, nullptr);
// Reset build time counter
if (pointed.type == POINTEDTHING_NODE &&
- item.getDefinition(m_itemdef).type == ITEM_NODE)
+ selected_item.getDefinition(m_itemdef).type == ITEM_NODE)
getClient(pkt->getPeerId())->m_time_from_building = 0.0;
if (pointed.type == POINTEDTHING_OBJECT) {
@@ -1324,14 +1317,13 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
// Do stuff
pointed_object->rightClick(playersao);
- }
- else if (m_script->item_OnPlace(
- item, playersao, pointed)) {
+ } else if (m_script->item_OnPlace(
+ selected_item, playersao, pointed)) {
// Placement was handled in lua
// Apply returned ItemStack
- if (playersao->setWieldedItem(item)) {
- SendInventory(playersao);
+ if (playersao->setWieldedItem(selected_item)) {
+ SendInventory(playersao, true);
}
}
@@ -1340,7 +1332,7 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
RemoteClient *client = getClient(pkt->getPeerId());
v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
- if (!item.getDefinition(m_itemdef).node_placement_prediction.empty()) {
+ if (!selected_item.getDefinition(m_itemdef).node_placement_prediction.empty()) {
client->SetBlockNotSent(blockpos);
if (blockpos2 != blockpos) {
client->SetBlockNotSent(blockpos2);
@@ -1352,43 +1344,45 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
client->ResendBlockIfOnWire(blockpos2);
}
}
- } // action == 3
+ } // action == INTERACT_PLACE
/*
4: use
*/
- else if (action == 4) {
- ItemStack item = playersao->getWieldedItem();
+ else if (action == INTERACT_USE) {
+ ItemStack selected_item;
+ playersao->getWieldedItem(&selected_item, nullptr);
- actionstream << player->getName() << " uses " << item.name
+ actionstream << player->getName() << " uses " << selected_item.name
<< ", pointing at " << pointed.dump() << std::endl;
if (m_script->item_OnUse(
- item, playersao, pointed)) {
+ selected_item, playersao, pointed)) {
// Apply returned ItemStack
- if (playersao->setWieldedItem(item)) {
- SendInventory(playersao);
+ if (playersao->setWieldedItem(selected_item)) {
+ SendInventory(playersao, true);
}
}
- } // action == 4
+ } // action == INTERACT_USE
/*
5: rightclick air
*/
- else if (action == 5) {
- ItemStack item = playersao->getWieldedItem();
+ else if (action == INTERACT_ACTIVATE) {
+ ItemStack selected_item;
+ playersao->getWieldedItem(&selected_item, nullptr);
actionstream << player->getName() << " activates "
- << item.name << std::endl;
+ << selected_item.name << std::endl;
if (m_script->item_OnSecondaryUse(
- item, playersao)) {
- if( playersao->setWieldedItem(item)) {
- SendInventory(playersao);
+ selected_item, playersao)) {
+ if (playersao->setWieldedItem(selected_item)) {
+ SendInventory(playersao, true);
}
}
- }
+ } // action == INTERACT_ACTIVATE
/*