diff options
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/clientopcodes.cpp | 10 | ||||
-rw-r--r-- | src/network/clientpackethandler.cpp | 37 | ||||
-rw-r--r-- | src/network/connection.cpp | 157 | ||||
-rw-r--r-- | src/network/connection.h | 24 | ||||
-rw-r--r-- | src/network/connectionthreads.cpp | 18 | ||||
-rw-r--r-- | src/network/connectionthreads.h | 25 | ||||
-rw-r--r-- | src/network/networkprotocol.h | 53 | ||||
-rw-r--r-- | src/network/peerhandler.h | 3 | ||||
-rw-r--r-- | src/network/serveropcodes.cpp | 90 | ||||
-rw-r--r-- | src/network/serverpackethandler.cpp | 202 |
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 /* |