From d51d0f3a5a60679436bf7d4e1980f3a82f229848 Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Mon, 27 Sep 2021 17:45:44 +0200 Subject: Various code improvements * Camera: Fix division by 0 after view bobbing * Remove ignored constness * Connection: Improve window size range limits --- src/network/connection.cpp | 32 ++++++++++---------------------- src/network/connection.h | 30 +++++++++++++++++------------- src/network/networkpacket.h | 2 +- 3 files changed, 28 insertions(+), 36 deletions(-) (limited to 'src/network') diff --git a/src/network/connection.cpp b/src/network/connection.cpp index a4970954f..548b2e3a0 100644 --- a/src/network/connection.cpp +++ b/src/network/connection.cpp @@ -578,7 +578,7 @@ u16 Channel::getOutgoingSequenceNumber(bool& successful) // ugly cast but this one is required in order to tell compiler we // know about difference of two unsigned may be negative in general // but we already made sure it won't happen in this case - if (((u16)(next_outgoing_seqnum - lowest_unacked_seqnumber)) > window_size) { + if (((u16)(next_outgoing_seqnum - lowest_unacked_seqnumber)) > m_window_size) { successful = false; return 0; } @@ -588,7 +588,7 @@ u16 Channel::getOutgoingSequenceNumber(bool& successful) // know about difference of two unsigned may be negative in general // but we already made sure it won't happen in this case if ((next_outgoing_seqnum + (u16)(SEQNUM_MAX - lowest_unacked_seqnumber)) > - window_size) { + m_window_size) { successful = false; return 0; } @@ -666,7 +666,7 @@ void Channel::UpdateTimers(float dtime) //packet_too_late = current_packet_too_late; packets_successful = current_packet_successful; - if (current_bytes_transfered > (unsigned int) (window_size*512/2)) { + if (current_bytes_transfered > (unsigned int) (m_window_size*512/2)) { reasonable_amount_of_data_transmitted = true; } current_packet_loss = 0; @@ -681,37 +681,25 @@ void Channel::UpdateTimers(float dtime) if (packets_successful > 0) { successful_to_lost_ratio = packet_loss/packets_successful; } else if (packet_loss > 0) { - window_size = std::max( - (window_size - 10), - MIN_RELIABLE_WINDOW_SIZE); + setWindowSize(m_window_size - 10); done = true; } if (!done) { - if ((successful_to_lost_ratio < 0.01f) && - (window_size < MAX_RELIABLE_WINDOW_SIZE)) { + if (successful_to_lost_ratio < 0.01f) { /* don't even think about increasing if we didn't even * use major parts of our window */ if (reasonable_amount_of_data_transmitted) - window_size = std::min( - (window_size + 100), - MAX_RELIABLE_WINDOW_SIZE); - } else if ((successful_to_lost_ratio < 0.05f) && - (window_size < MAX_RELIABLE_WINDOW_SIZE)) { + setWindowSize(m_window_size + 100); + } else if (successful_to_lost_ratio < 0.05f) { /* don't even think about increasing if we didn't even * use major parts of our window */ if (reasonable_amount_of_data_transmitted) - window_size = std::min( - (window_size + 50), - MAX_RELIABLE_WINDOW_SIZE); + setWindowSize(m_window_size + 50); } else if (successful_to_lost_ratio > 0.15f) { - window_size = std::max( - (window_size - 100), - MIN_RELIABLE_WINDOW_SIZE); + setWindowSize(m_window_size - 100); } else if (successful_to_lost_ratio > 0.1f) { - window_size = std::max( - (window_size - 50), - MIN_RELIABLE_WINDOW_SIZE); + setWindowSize(m_window_size - 50); } } } diff --git a/src/network/connection.h b/src/network/connection.h index 49bb65c3e..ea74ffb1c 100644 --- a/src/network/connection.h +++ b/src/network/connection.h @@ -420,34 +420,38 @@ public: void UpdateTimers(float dtime); - const float getCurrentDownloadRateKB() + float getCurrentDownloadRateKB() { MutexAutoLock lock(m_internal_mutex); return cur_kbps; }; - const float getMaxDownloadRateKB() + float getMaxDownloadRateKB() { MutexAutoLock lock(m_internal_mutex); return max_kbps; }; - const float getCurrentLossRateKB() + float getCurrentLossRateKB() { MutexAutoLock lock(m_internal_mutex); return cur_kbps_lost; }; - const float getMaxLossRateKB() + float getMaxLossRateKB() { MutexAutoLock lock(m_internal_mutex); return max_kbps_lost; }; - const float getCurrentIncomingRateKB() + float getCurrentIncomingRateKB() { MutexAutoLock lock(m_internal_mutex); return cur_incoming_kbps; }; - const float getMaxIncomingRateKB() + float getMaxIncomingRateKB() { MutexAutoLock lock(m_internal_mutex); return max_incoming_kbps; }; - const float getAvgDownloadRateKB() + float getAvgDownloadRateKB() { MutexAutoLock lock(m_internal_mutex); return avg_kbps; }; - const float getAvgLossRateKB() + float getAvgLossRateKB() { MutexAutoLock lock(m_internal_mutex); return avg_kbps_lost; }; - const float getAvgIncomingRateKB() + float getAvgIncomingRateKB() { MutexAutoLock lock(m_internal_mutex); return avg_incoming_kbps; }; - const unsigned int getWindowSize() const { return window_size; }; + u16 getWindowSize() const { return m_window_size; }; + + void setWindowSize(long size) + { + m_window_size = (u16)rangelim(size, MIN_RELIABLE_WINDOW_SIZE, MAX_RELIABLE_WINDOW_SIZE); + } - void setWindowSize(unsigned int size) { window_size = size; }; private: std::mutex m_internal_mutex; - int window_size = MIN_RELIABLE_WINDOW_SIZE; + u16 m_window_size = MIN_RELIABLE_WINDOW_SIZE; u16 next_incoming_seqnum = SEQNUM_INITIAL; @@ -765,7 +769,7 @@ public: Address GetPeerAddress(session_t peer_id); float getPeerStat(session_t peer_id, rtt_stat_type type); float getLocalStat(rate_stat_type type); - const u32 GetProtocolID() const { return m_protocol_id; }; + u32 GetProtocolID() const { return m_protocol_id; }; const std::string getDesc(); void DisconnectPeer(session_t peer_id); diff --git a/src/network/networkpacket.h b/src/network/networkpacket.h index b1c44f055..b9c39f332 100644 --- a/src/network/networkpacket.h +++ b/src/network/networkpacket.h @@ -41,7 +41,7 @@ public: u32 getSize() const { return m_datasize; } session_t getPeerId() const { return m_peer_id; } u16 getCommand() { return m_command; } - const u32 getRemainingBytes() const { return m_datasize - m_read_offset; } + u32 getRemainingBytes() const { return m_datasize - m_read_offset; } const char *getRemainingString() { return getString(m_read_offset); } // Returns a c-string without copying. -- cgit v1.2.3 From 6ea558f8ac57a391b6f54c534441f930b0609cea Mon Sep 17 00:00:00 2001 From: savilli <78875209+savilli@users.noreply.github.com> Date: Tue, 12 Oct 2021 21:12:49 +0300 Subject: Fix player HP desync between client and server --- src/network/serverpackethandler.cpp | 3 ++- src/server/player_sao.cpp | 5 +++-- src/server/player_sao.h | 6 +++++- 3 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src/network') diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index 4c609644f..dc7be0e23 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -826,7 +826,8 @@ void Server::handleCommand_Damage(NetworkPacket* pkt) << std::endl; PlayerHPChangeReason reason(PlayerHPChangeReason::FALL); - playersao->setHP((s32)playersao->getHP() - (s32)damage, reason); + playersao->setHP((s32)playersao->getHP() - (s32)damage, reason, false); + SendPlayerHPOrDie(playersao, reason); // correct client side prediction } } diff --git a/src/server/player_sao.cpp b/src/server/player_sao.cpp index d4d036726..690823bb7 100644 --- a/src/server/player_sao.cpp +++ b/src/server/player_sao.cpp @@ -462,7 +462,7 @@ void PlayerSAO::rightClick(ServerActiveObject *clicker) m_env->getScriptIface()->on_rightclickplayer(this, clicker); } -void PlayerSAO::setHP(s32 hp, const PlayerHPChangeReason &reason) +void PlayerSAO::setHP(s32 hp, const PlayerHPChangeReason &reason, bool send) { if (hp == (s32)m_hp) return; // Nothing to do @@ -490,7 +490,8 @@ void PlayerSAO::setHP(s32 hp, const PlayerHPChangeReason &reason) if ((hp == 0) != (oldhp == 0)) m_properties_sent = false; - m_env->getGameDef()->SendPlayerHPOrDie(this, reason); + if (send) + m_env->getGameDef()->SendPlayerHPOrDie(this, reason); } void PlayerSAO::setBreath(const u16 breath, bool send) diff --git a/src/server/player_sao.h b/src/server/player_sao.h index 8e2d8803f..1429d7129 100644 --- a/src/server/player_sao.h +++ b/src/server/player_sao.h @@ -112,7 +112,11 @@ public: u16 punch(v3f dir, const ToolCapabilities *toolcap, ServerActiveObject *puncher, float time_from_last_punch); void rightClick(ServerActiveObject *clicker); - void setHP(s32 hp, const PlayerHPChangeReason &reason); + void setHP(s32 hp, const PlayerHPChangeReason &reason) override + { + return setHP(hp, reason, true); + } + void setHP(s32 hp, const PlayerHPChangeReason &reason, bool send); void setHPRaw(u16 hp) { m_hp = hp; } u16 getBreath() const { return m_breath; } void setBreath(const u16 breath, bool send = true); -- cgit v1.2.3 From fe5cb2cdfb137764d20ca56f17f607ec361e0dcf Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 10 Oct 2021 21:10:52 +0200 Subject: Remove broken timeout behaviour Code that relies on `resend_count` was added in 7ea4a03 and 247a1eb, but never worked. This was fixed in #11607 which caused the problem to surface. Hence undo the first commit entirely and change the logic of the second. --- src/network/connectionthreads.cpp | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) (limited to 'src/network') diff --git a/src/network/connectionthreads.cpp b/src/network/connectionthreads.cpp index 47678dac5..a306ced9b 100644 --- a/src/network/connectionthreads.cpp +++ b/src/network/connectionthreads.cpp @@ -48,9 +48,6 @@ std::mutex log_conthread_mutex; #undef DEBUG_CONNECTION_KBPS #endif -/* maximum number of retries for reliable packets */ -#define MAX_RELIABLE_RETRY 5 - #define WINDOW_SIZE 5 static session_t readPeerId(u8 *packetdata) @@ -212,7 +209,6 @@ void ConnectionSendThread::runTimeouts(float dtime) } float resend_timeout = udpPeer->getResendTimeout(); - bool retry_count_exceeded = false; for (Channel &channel : udpPeer->channels) { // Remove timed out incomplete unreliable split packets @@ -231,24 +227,16 @@ void ConnectionSendThread::runTimeouts(float dtime) m_iteration_packets_avaialble -= timed_outs.size(); for (const auto &k : timed_outs) { - session_t peer_id = readPeerId(*k.data); u8 channelnum = readChannel(*k.data); u16 seqnum = readU16(&(k.data[BASE_HEADER_SIZE + 1])); channel.UpdateBytesLost(k.data.getSize()); - if (k.resend_count > MAX_RELIABLE_RETRY) { - retry_count_exceeded = true; - timeouted_peers.push_back(peer->id); - /* no need to check additional packets if a single one did timeout*/ - break; - } - LOG(derr_con << m_connection->getDesc() << "RE-SENDING timed-out RELIABLE to " << k.address.serializeString() << "(t/o=" << resend_timeout << "): " - << "from_peer_id=" << peer_id + << "count=" << k.resend_count << ", channel=" << ((int) channelnum & 0xff) << ", seqnum=" << seqnum << std::endl); @@ -259,17 +247,9 @@ void ConnectionSendThread::runTimeouts(float dtime) // lost or really takes more time to transmit } - if (retry_count_exceeded) { - break; /* no need to check other channels if we already did timeout */ - } - channel.UpdateTimers(dtime); } - /* skip to next peer if we did timeout */ - if (retry_count_exceeded) - continue; - /* send ping if necessary */ if (udpPeer->Ping(dtime, data)) { LOG(dout_con << m_connection->getDesc() @@ -1153,8 +1133,8 @@ SharedBuffer ConnectionReceiveThread::handlePacketType_Control(Channel *chan try { BufferedPacket p = channel->outgoing_reliables_sent.popSeqnum(seqnum); - // only calculate rtt from straight sent packets - if (p.resend_count == 0) { + // the rtt calculation will be a bit off for re-sent packets but that's okay + { // Get round trip time u64 current_time = porting::getTimeMs(); @@ -1174,6 +1154,7 @@ SharedBuffer ConnectionReceiveThread::handlePacketType_Control(Channel *chan dynamic_cast(peer)->reportRTT(rtt); } } + // put bytes for max bandwidth calculation channel->UpdateBytesSent(p.data.getSize(), 1); if (channel->outgoing_reliables_sent.size() == 0) -- cgit v1.2.3 From 660e63dbae5901f8178b39ab40e6f770b8d7a215 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Mon, 25 Oct 2021 20:30:27 +0200 Subject: Fix item duplication if player dies during interact callback (alternative) (#11662) --- builtin/game/item.lua | 50 +++++++++++++++++++++---------------- doc/lua_api.txt | 11 +++++--- src/network/serverpackethandler.cpp | 44 +++++++++++++++++++------------- src/script/cpp_api/s_item.cpp | 21 +++++++++++----- src/script/cpp_api/s_item.h | 14 ++++++++--- src/script/lua_api/l_env.cpp | 2 +- src/util/Optional.h | 32 ++++++++++++++++++++++-- 7 files changed, 118 insertions(+), 56 deletions(-) (limited to 'src/network') diff --git a/builtin/game/item.lua b/builtin/game/item.lua index c495a67bd..039947584 100644 --- a/builtin/game/item.lua +++ b/builtin/game/item.lua @@ -499,34 +499,40 @@ function core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed return result end end + if itemstack:take_item():is_empty() then + return itemstack + end + local def = itemstack:get_definition() - if itemstack:take_item() ~= nil then - user:set_hp(user:get_hp() + hp_change) - - if def and def.sound and def.sound.eat then - core.sound_play(def.sound.eat, { - pos = user:get_pos(), - max_hear_distance = 16 - }, true) - end + if def and def.sound and def.sound.eat then + core.sound_play(def.sound.eat, { + pos = user:get_pos(), + max_hear_distance = 16 + }, true) + end - if replace_with_item then - if itemstack:is_empty() then - itemstack:add_item(replace_with_item) + -- Changing hp might kill the player causing mods to do who-knows-what to the + -- inventory, so do this before set_hp(). + if replace_with_item then + if itemstack:is_empty() then + itemstack:add_item(replace_with_item) + else + local inv = user:get_inventory() + -- Check if inv is null, since non-players don't have one + if inv and inv:room_for_item("main", {name=replace_with_item}) then + inv:add_item("main", replace_with_item) else - local inv = user:get_inventory() - -- Check if inv is null, since non-players don't have one - if inv and inv:room_for_item("main", {name=replace_with_item}) then - inv:add_item("main", replace_with_item) - else - local pos = user:get_pos() - pos.y = math.floor(pos.y + 0.5) - core.add_item(pos, replace_with_item) - end + local pos = user:get_pos() + pos.y = math.floor(pos.y + 0.5) + core.add_item(pos, replace_with_item) end end end - return itemstack + user:set_wielded_item(itemstack) + + user:set_hp(user:get_hp() + hp_change) + + return nil -- don't overwrite wield item a second time end function core.item_eat(hp_change, replace_with_item) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 69ac55493..e47df4686 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -5421,7 +5421,7 @@ Inventory * `minetest.remove_detached_inventory(name)` * Returns a `boolean` indicating whether the removal succeeded. * `minetest.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing)`: - returns left over ItemStack. + returns leftover ItemStack or nil to indicate no inventory change * See `minetest.item_eat` and `minetest.register_on_item_eat` Formspec @@ -7542,12 +7542,15 @@ Used by `minetest.register_node`, `minetest.register_craftitem`, and on_place = function(itemstack, placer, pointed_thing), -- When the 'place' key was pressed with the item in hand -- and a node was pointed at. - -- Shall place item and return the leftover itemstack. + -- Shall place item and return the leftover itemstack + -- or nil to not modify the inventory. -- The placer may be any ObjectRef or nil. -- default: minetest.item_place on_secondary_use = function(itemstack, user, pointed_thing), -- Same as on_place but called when not pointing at a node. + -- Function must return either nil if inventory shall not be modified, + -- or an itemstack to replace the original itemstack. -- The user may be any ObjectRef or nil. -- default: nil @@ -7559,8 +7562,8 @@ Used by `minetest.register_node`, `minetest.register_craftitem`, and on_use = function(itemstack, user, pointed_thing), -- default: nil -- When user pressed the 'punch/mine' key with the item in hand. - -- Function must return either nil if no item shall be removed from - -- inventory, or an itemstack to replace the original itemstack. + -- Function must return either nil if inventory shall not be modified, + -- or an itemstack to replace the original itemstack. -- e.g. itemstack:take_item(); return itemstack -- Otherwise, the function is free to do what it wants. -- The user may be any ObjectRef or nil. diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index dc7be0e23..d4bef3ca2 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -921,6 +921,13 @@ bool Server::checkInteractDistance(RemotePlayer *player, const f32 d, const std: return true; } +// Tiny helper to retrieve the selected item into an Optional +static inline void getWieldedItem(const PlayerSAO *playersao, Optional &ret) +{ + ret = ItemStack(); + playersao->getWieldedItem(&(*ret)); +} + void Server::handleCommand_Interact(NetworkPacket *pkt) { /* @@ -1228,14 +1235,17 @@ void Server::handleCommand_Interact(NetworkPacket *pkt) // Place block or right-click object case INTERACT_PLACE: { - ItemStack selected_item; - playersao->getWieldedItem(&selected_item, nullptr); + Optional selected_item; + getWieldedItem(playersao, selected_item); // Reset build time counter if (pointed.type == POINTEDTHING_NODE && - selected_item.getDefinition(m_itemdef).type == ITEM_NODE) + selected_item->getDefinition(m_itemdef).type == ITEM_NODE) getClient(peer_id)->m_time_from_building = 0.0; + const bool had_prediction = !selected_item->getDefinition(m_itemdef). + node_placement_prediction.empty(); + if (pointed.type == POINTEDTHING_OBJECT) { // Right click object @@ -1248,11 +1258,9 @@ void Server::handleCommand_Interact(NetworkPacket *pkt) << pointed_object->getDescription() << std::endl; // Do stuff - if (m_script->item_OnSecondaryUse( - selected_item, playersao, pointed)) { - if (playersao->setWieldedItem(selected_item)) { + if (m_script->item_OnSecondaryUse(selected_item, playersao, pointed)) { + if (selected_item.has_value() && playersao->setWieldedItem(*selected_item)) SendInventory(playersao, true); - } } pointed_object->rightClick(playersao); @@ -1260,7 +1268,7 @@ void Server::handleCommand_Interact(NetworkPacket *pkt) // Placement was handled in lua // Apply returned ItemStack - if (playersao->setWieldedItem(selected_item)) + if (selected_item.has_value() && playersao->setWieldedItem(*selected_item)) SendInventory(playersao, true); } @@ -1272,8 +1280,7 @@ void Server::handleCommand_Interact(NetworkPacket *pkt) RemoteClient *client = getClient(peer_id); v3s16 blockpos = getNodeBlockPos(pointed.node_abovesurface); v3s16 blockpos2 = getNodeBlockPos(pointed.node_undersurface); - if (!selected_item.getDefinition(m_itemdef - ).node_placement_prediction.empty()) { + if (had_prediction) { client->SetBlockNotSent(blockpos); if (blockpos2 != blockpos) client->SetBlockNotSent(blockpos2); @@ -1287,15 +1294,15 @@ void Server::handleCommand_Interact(NetworkPacket *pkt) } // action == INTERACT_PLACE case INTERACT_USE: { - ItemStack selected_item; - playersao->getWieldedItem(&selected_item, nullptr); + Optional selected_item; + getWieldedItem(playersao, selected_item); - actionstream << player->getName() << " uses " << selected_item.name + actionstream << player->getName() << " uses " << selected_item->name << ", pointing at " << pointed.dump() << std::endl; if (m_script->item_OnUse(selected_item, playersao, pointed)) { // Apply returned ItemStack - if (playersao->setWieldedItem(selected_item)) + if (selected_item.has_value() && playersao->setWieldedItem(*selected_item)) SendInventory(playersao, true); } @@ -1304,16 +1311,17 @@ void Server::handleCommand_Interact(NetworkPacket *pkt) // Rightclick air case INTERACT_ACTIVATE: { - ItemStack selected_item; - playersao->getWieldedItem(&selected_item, nullptr); + Optional selected_item; + getWieldedItem(playersao, selected_item); actionstream << player->getName() << " activates " - << selected_item.name << std::endl; + << selected_item->name << std::endl; pointed.type = POINTEDTHING_NOTHING; // can only ever be NOTHING if (m_script->item_OnSecondaryUse(selected_item, playersao, pointed)) { - if (playersao->setWieldedItem(selected_item)) + // Apply returned ItemStack + if (selected_item.has_value() && playersao->setWieldedItem(*selected_item)) SendInventory(playersao, true); } diff --git a/src/script/cpp_api/s_item.cpp b/src/script/cpp_api/s_item.cpp index 48dce14f3..b1916070e 100644 --- a/src/script/cpp_api/s_item.cpp +++ b/src/script/cpp_api/s_item.cpp @@ -59,13 +59,14 @@ bool ScriptApiItem::item_OnDrop(ItemStack &item, return true; } -bool ScriptApiItem::item_OnPlace(ItemStack &item, +bool ScriptApiItem::item_OnPlace(Optional &ret_item, ServerActiveObject *placer, const PointedThing &pointed) { SCRIPTAPI_PRECHECKHEADER int error_handler = PUSH_ERROR_HANDLER(L); + const ItemStack &item = *ret_item; // Push callback function on stack if (!getItemCallback(item.name.c_str(), "on_place")) return false; @@ -82,22 +83,25 @@ bool ScriptApiItem::item_OnPlace(ItemStack &item, PCALL_RES(lua_pcall(L, 3, 1, error_handler)); if (!lua_isnil(L, -1)) { try { - item = read_item(L, -1, getServer()->idef()); + ret_item = read_item(L, -1, getServer()->idef()); } catch (LuaError &e) { throw WRAP_LUAERROR(e, "item=" + item.name); } + } else { + ret_item = nullopt; } lua_pop(L, 2); // Pop item and error handler return true; } -bool ScriptApiItem::item_OnUse(ItemStack &item, +bool ScriptApiItem::item_OnUse(Optional &ret_item, ServerActiveObject *user, const PointedThing &pointed) { SCRIPTAPI_PRECHECKHEADER int error_handler = PUSH_ERROR_HANDLER(L); + const ItemStack &item = *ret_item; // Push callback function on stack if (!getItemCallback(item.name.c_str(), "on_use")) return false; @@ -109,22 +113,25 @@ bool ScriptApiItem::item_OnUse(ItemStack &item, PCALL_RES(lua_pcall(L, 3, 1, error_handler)); if(!lua_isnil(L, -1)) { try { - item = read_item(L, -1, getServer()->idef()); + ret_item = read_item(L, -1, getServer()->idef()); } catch (LuaError &e) { throw WRAP_LUAERROR(e, "item=" + item.name); } + } else { + ret_item = nullopt; } lua_pop(L, 2); // Pop item and error handler return true; } -bool ScriptApiItem::item_OnSecondaryUse(ItemStack &item, +bool ScriptApiItem::item_OnSecondaryUse(Optional &ret_item, ServerActiveObject *user, const PointedThing &pointed) { SCRIPTAPI_PRECHECKHEADER int error_handler = PUSH_ERROR_HANDLER(L); + const ItemStack &item = *ret_item; if (!getItemCallback(item.name.c_str(), "on_secondary_use")) return false; @@ -134,10 +141,12 @@ bool ScriptApiItem::item_OnSecondaryUse(ItemStack &item, PCALL_RES(lua_pcall(L, 3, 1, error_handler)); if (!lua_isnil(L, -1)) { try { - item = read_item(L, -1, getServer()->idef()); + ret_item = read_item(L, -1, getServer()->idef()); } catch (LuaError &e) { throw WRAP_LUAERROR(e, "item=" + item.name); } + } else { + ret_item = nullopt; } lua_pop(L, 2); // Pop item and error handler return true; diff --git a/src/script/cpp_api/s_item.h b/src/script/cpp_api/s_item.h index 25a3501f9..5015d8bd4 100644 --- a/src/script/cpp_api/s_item.h +++ b/src/script/cpp_api/s_item.h @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "cpp_api/s_base.h" #include "irr_v3d.h" +#include "util/Optional.h" struct PointedThing; struct ItemStack; @@ -35,13 +36,20 @@ class ScriptApiItem : virtual public ScriptApiBase { public: + /* + * Functions with Optional are for callbacks where Lua may + * want to prevent the engine from modifying the inventory after it's done. + * This has a longer backstory where on_use may need to empty the player's + * inventory without the engine interfering (see issue #6546). + */ + bool item_OnDrop(ItemStack &item, ServerActiveObject *dropper, v3f pos); - bool item_OnPlace(ItemStack &item, + bool item_OnPlace(Optional &item, ServerActiveObject *placer, const PointedThing &pointed); - bool item_OnUse(ItemStack &item, + bool item_OnUse(Optional &item, ServerActiveObject *user, const PointedThing &pointed); - bool item_OnSecondaryUse(ItemStack &item, + bool item_OnSecondaryUse(Optional &item, ServerActiveObject *user, const PointedThing &pointed); bool item_OnCraft(ItemStack &item, ServerActiveObject *user, const InventoryList *old_craft_grid, const InventoryLocation &craft_inv); diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 98f8861fa..2c709d31b 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -477,7 +477,7 @@ int ModApiEnvMod::l_place_node(lua_State *L) return 1; } // Create item to place - ItemStack item(ndef->get(n).name, 1, 0, idef); + Optional item = ItemStack(ndef->get(n).name, 1, 0, idef); // Make pointed position PointedThing pointed; pointed.type = POINTEDTHING_NODE; diff --git a/src/util/Optional.h b/src/util/Optional.h index 9c2842b43..eda7fff89 100644 --- a/src/util/Optional.h +++ b/src/util/Optional.h @@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once +#include #include "debug.h" struct nullopt_t @@ -43,18 +44,38 @@ class Optional public: Optional() noexcept {} Optional(nullopt_t) noexcept {} + Optional(const T &value) noexcept : m_has_value(true), m_value(value) {} + Optional(T &&value) noexcept : m_has_value(true), m_value(std::move(value)) {} + Optional(const Optional &other) noexcept : m_has_value(other.m_has_value), m_value(other.m_value) + {} + Optional(Optional &&other) noexcept : + m_has_value(other.m_has_value), m_value(std::move(other.m_value)) { + other.m_has_value = false; } - void operator=(nullopt_t) noexcept { m_has_value = false; } + Optional &operator=(nullopt_t) noexcept { m_has_value = false; return *this; } - void operator=(const Optional &other) noexcept + Optional &operator=(const Optional &other) noexcept { + if (&other == this) + return *this; m_has_value = other.m_has_value; m_value = other.m_value; + return *this; + } + + Optional &operator=(Optional &&other) noexcept + { + if (&other == this) + return *this; + m_has_value = other.m_has_value; + m_value = std::move(other.m_value); + other.m_has_value = false; + return *this; } T &value() @@ -71,6 +92,13 @@ public: const T &value_or(const T &def) const { return m_has_value ? m_value : def; } + // Unchecked access consistent with std::optional + T* operator->() { return &m_value; } + const T* operator->() const { return &m_value; } + + T& operator*() { return m_value; } + const T& operator*() const { return m_value; } + bool has_value() const noexcept { return m_has_value; } explicit operator bool() const { return m_has_value; } -- cgit v1.2.3 From 6910c8d920acedb3f1df1ac03a5cdf14f5fb6081 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Sun, 31 Oct 2021 22:33:33 +0000 Subject: Fix number of tool uses being off by 1..32767 (#11110) --- builtin/game/item.lua | 2 +- doc/lua_api.txt | 13 +-- games/devtest/mods/basetools/init.lua | 44 +++++---- .../mods/basetools/textures/basetools_dirtpick.png | Bin 307 -> 0 bytes games/devtest/mods/util_commands/init.lua | 53 +++++++++++ src/client/content_cao.cpp | 3 +- src/client/game.cpp | 3 +- src/network/serverpackethandler.cpp | 7 +- src/script/lua_api/l_object.cpp | 2 +- src/script/lua_api/l_util.cpp | 19 ++-- src/script/lua_api/l_util.h | 4 +- src/server/luaentity_sao.cpp | 8 +- src/server/luaentity_sao.h | 5 +- src/server/player_sao.cpp | 7 +- src/server/player_sao.h | 4 +- src/server/serveractiveobject.h | 7 +- src/tool.cpp | 99 ++++++++++++++++++--- src/tool.h | 18 ++-- 18 files changed, 228 insertions(+), 70 deletions(-) delete mode 100644 games/devtest/mods/basetools/textures/basetools_dirtpick.png (limited to 'src/network') diff --git a/builtin/game/item.lua b/builtin/game/item.lua index 039947584..c9ccb8801 100644 --- a/builtin/game/item.lua +++ b/builtin/game/item.lua @@ -613,7 +613,7 @@ function core.node_dig(pos, node, digger) if wielded then local wdef = wielded:get_definition() local tp = wielded:get_tool_capabilities() - local dp = core.get_dig_params(def and def.groups, tp) + local dp = core.get_dig_params(def and def.groups, tp, wielded:get_wear()) if wdef and wdef.after_use then wielded = wdef.after_use(wielded, digger, node, dp) or wielded else diff --git a/doc/lua_api.txt b/doc/lua_api.txt index e47df4686..f3007671b 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -1953,8 +1953,9 @@ to implement this. ### Uses (tools only) Determines how many uses the tool has when it is used for digging a node, -of this group, of the maximum level. For lower leveled nodes, the use count -is multiplied by `3^leveldiff`. +of this group, of the maximum level. The maximum supported number of +uses is 65535. The special number 0 is used for infinite uses. +For lower leveled nodes, the use count is multiplied by `3^leveldiff`. `leveldiff` is the difference of the tool's `maxlevel` `groupcaps` and the node's `level` group. The node cannot be dug if `leveldiff` is less than zero. @@ -3475,8 +3476,8 @@ Helper functions * `minetest.pointed_thing_to_face_pos(placer, pointed_thing)`: returns a position. * returns the exact position on the surface of a pointed node -* `minetest.get_dig_params(groups, tool_capabilities)`: Simulates an item - that digs a node. +* `minetest.get_dig_params(groups, tool_capabilities [, wear])`: + Simulates an item that digs a node. Returns a table with the following fields: * `diggable`: `true` if node can be dug, `false` otherwise. * `time`: Time it would take to dig the node. @@ -3485,7 +3486,8 @@ Helper functions Parameters: * `groups`: Table of the node groups of the node that would be dug * `tool_capabilities`: Tool capabilities table of the item -* `minetest.get_hit_params(groups, tool_capabilities [, time_from_last_punch])`: + * `wear`: Amount of wear the tool starts with (default: 0) +* `minetest.get_hit_params(groups, tool_capabilities [, time_from_last_punch [, wear]])`: Simulates an item that punches an object. Returns a table with the following fields: * `hp`: How much damage the punch would cause. @@ -3494,6 +3496,7 @@ Helper functions * `groups`: Damage groups of the object * `tool_capabilities`: Tool capabilities table of the item * `time_from_last_punch`: time in seconds since last punch action + * `wear`: Amount of wear the item starts with (default: 0) diff --git a/games/devtest/mods/basetools/init.lua b/games/devtest/mods/basetools/init.lua index bd7480030..fd83b82eb 100644 --- a/games/devtest/mods/basetools/init.lua +++ b/games/devtest/mods/basetools/init.lua @@ -16,11 +16,11 @@ Tool types: Tool materials: -* Dirt: dig nodes of rating 3, one use only * Wood: dig nodes of rating 3 * Stone: dig nodes of rating 3 or 2 * Steel: dig nodes of rating 3, 2 or 1 * Mese: dig "everything" instantly +* n-Uses: can be used n times before breaking ]] -- The hand @@ -92,20 +92,6 @@ minetest.register_tool("basetools:pick_mese", { -- Pickaxes: Dig cracky -- --- This should break after only 1 use -minetest.register_tool("basetools:pick_dirt", { - description = "Dirt Pickaxe".."\n".. - "Digs cracky=3".."\n".. - "1 use only", - inventory_image = "basetools_dirtpick.png", - tool_capabilities = { - max_drop_level=0, - groupcaps={ - cracky={times={[3]=2.00}, uses=1, maxlevel=0} - }, - }, -}) - minetest.register_tool("basetools:pick_wood", { description = "Wooden Pickaxe".."\n".. "Digs cracky=3", @@ -348,3 +334,31 @@ minetest.register_tool("basetools:dagger_steel", { damage_groups = {fleshy=2}, } }) + +-- Test tool uses and punch_attack_uses +local uses = { 1, 2, 3, 5, 10, 50, 100, 1000, 10000, 65535 } +for i=1, #uses do + local u = uses[i] + local color = string.format("#FF00%02X", math.floor(((i-1)/#uses) * 255)) + minetest.register_tool("basetools:pick_uses_"..string.format("%05d", u), { + description = u.."-Uses Pickaxe".."\n".. + "Digs cracky=3", + inventory_image = "basetools_steelpick.png^[colorize:"..color..":127", + tool_capabilities = { + max_drop_level=0, + groupcaps={ + cracky={times={[3]=0.1, [2]=0.2, [1]=0.3}, uses=u, maxlevel=0} + }, + }, + }) + + minetest.register_tool("basetools:sword_uses_"..string.format("%05d", u), { + description = u.."-Uses Sword".."\n".. + "Damage: fleshy=1", + inventory_image = "basetools_woodsword.png^[colorize:"..color..":127", + tool_capabilities = { + damage_groups = {fleshy=1}, + punch_attack_uses = u, + }, + }) +end diff --git a/games/devtest/mods/basetools/textures/basetools_dirtpick.png b/games/devtest/mods/basetools/textures/basetools_dirtpick.png deleted file mode 100644 index 20a021d72..000000000 Binary files a/games/devtest/mods/basetools/textures/basetools_dirtpick.png and /dev/null differ diff --git a/games/devtest/mods/util_commands/init.lua b/games/devtest/mods/util_commands/init.lua index ca5dca2d9..79acaa0d0 100644 --- a/games/devtest/mods/util_commands/init.lua +++ b/games/devtest/mods/util_commands/init.lua @@ -114,6 +114,59 @@ minetest.register_chatcommand("detach", { end, }) +minetest.register_chatcommand("use_tool", { + params = "(dig ) | (hit ) []", + description = "Apply tool wear a number of times, as if it were used for digging", + func = function(name, param) + local player = minetest.get_player_by_name(name) + if not player then + return false, "No player." + end + local mode, group, level, uses = string.match(param, "([a-z]+) ([a-z0-9]+) (-?%d+) (%d+)") + if not mode then + mode, group, level = string.match(param, "([a-z]+) ([a-z0-9]+) (-?%d+)") + uses = 1 + end + if not mode or not group or not level then + return false + end + if mode ~= "dig" and mode ~= "hit" then + return false + end + local tool = player:get_wielded_item() + local caps = tool:get_tool_capabilities() + if not caps or tool:get_count() == 0 then + return false, "No tool in hand." + end + local actual_uses = 0 + for u=1, uses do + local wear = tool:get_wear() + local dp + if mode == "dig" then + dp = minetest.get_dig_params({[group]=3, level=level}, caps, wear) + else + dp = minetest.get_hit_params({[group]=100}, caps, level, wear) + end + tool:add_wear(dp.wear) + actual_uses = actual_uses + 1 + if tool:get_count() == 0 then + break + end + end + player:set_wielded_item(tool) + if tool:get_count() == 0 then + return true, string.format("Tool used %d time(s). ".. + "The tool broke after %d use(s).", uses, actual_uses) + else + local wear = tool:get_wear() + return true, string.format("Tool used %d time(s). ".. + "Final wear=%d", uses, wear) + end + end, +}) + + + -- Use this to test waypoint capabilities minetest.register_chatcommand("test_waypoints", { params = "[change_immediate]", diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index 1e79d00c9..5c8465b22 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -1870,7 +1870,8 @@ bool GenericCAO::directReportPunch(v3f dir, const ItemStack *punchitem, m_armor_groups, toolcap, punchitem, - time_from_last_punch); + time_from_last_punch, + punchitem->wear); if(result.did_punch && result.damage != 0) { diff --git a/src/client/game.cpp b/src/client/game.cpp index 57951dc95..7f0aff49c 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -3619,7 +3619,8 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos, // cheat detection. // Get digging parameters DigParams params = getDigParams(nodedef_manager->get(n).groups, - &selected_item.getToolCapabilities(itemdef_manager)); + &selected_item.getToolCapabilities(itemdef_manager), + selected_item.wear); // If can't dig, try hand if (!params.diggable) { diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index d4bef3ca2..c1ddb5005 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -1119,8 +1119,8 @@ void Server::handleCommand_Interact(NetworkPacket *pkt) float time_from_last_punch = playersao->resetTimeFromLastPunch(); - u16 wear = pointed_object->punch(dir, &toolcap, playersao, - time_from_last_punch); + u32 wear = pointed_object->punch(dir, &toolcap, playersao, + time_from_last_punch, tool_item.wear); // Callback may have changed item, so get it again playersao->getWieldedItem(&selected_item); @@ -1173,7 +1173,8 @@ void Server::handleCommand_Interact(NetworkPacket *pkt) // Get diggability and expected digging time DigParams params = getDigParams(m_nodedef->get(n).groups, - &selected_item.getToolCapabilities(m_itemdef)); + &selected_item.getToolCapabilities(m_itemdef), + selected_item.wear); // If can't dig, try hand if (!params.diggable) { params = getDigParams(m_nodedef->get(n).groups, diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index b7185f7ec..072b13d80 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -174,7 +174,7 @@ int ObjectRef::l_punch(lua_State *L) v3f dir = readParam(L, 5, sao->getBasePosition() - puncher->getBasePosition()); dir.normalize(); - u16 wear = sao->punch(dir, &toolcap, puncher, time_from_last_punch); + u32 wear = sao->punch(dir, &toolcap, puncher, time_from_last_punch); lua_pushnumber(L, wear); return 1; diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp index 2405cd90d..53319ccfd 100644 --- a/src/script/lua_api/l_util.cpp +++ b/src/script/lua_api/l_util.cpp @@ -160,28 +160,33 @@ int ModApiUtil::l_write_json(lua_State *L) return 1; } -// get_dig_params(groups, tool_capabilities) +// get_dig_params(groups, tool_capabilities[, wear]) int ModApiUtil::l_get_dig_params(lua_State *L) { NO_MAP_LOCK_REQUIRED; ItemGroupList groups; read_groups(L, 1, groups); ToolCapabilities tp = read_tool_capabilities(L, 2); - push_dig_params(L, getDigParams(groups, &tp)); + if (lua_isnoneornil(L, 3)) { + push_dig_params(L, getDigParams(groups, &tp)); + } else { + u16 wear = readParam(L, 3); + push_dig_params(L, getDigParams(groups, &tp, wear)); + } return 1; } -// get_hit_params(groups, tool_capabilities[, time_from_last_punch]) +// get_hit_params(groups, tool_capabilities[, time_from_last_punch, [, wear]]) int ModApiUtil::l_get_hit_params(lua_State *L) { NO_MAP_LOCK_REQUIRED; std::unordered_map groups; read_groups(L, 1, groups); ToolCapabilities tp = read_tool_capabilities(L, 2); - if(lua_isnoneornil(L, 3)) - push_hit_params(L, getHitParams(groups, &tp)); - else - push_hit_params(L, getHitParams(groups, &tp, readParam(L, 3))); + float time_from_last_punch = readParam(L, 3, 1000000); + int wear = readParam(L, 4, 0); + push_hit_params(L, getHitParams(groups, &tp, + time_from_last_punch, wear)); return 1; } diff --git a/src/script/lua_api/l_util.h b/src/script/lua_api/l_util.h index cc91e8d39..314e92f5c 100644 --- a/src/script/lua_api/l_util.h +++ b/src/script/lua_api/l_util.h @@ -50,10 +50,10 @@ private: // write_json(data[, styled]) static int l_write_json(lua_State *L); - // get_dig_params(groups, tool_capabilities[, time_from_last_punch]) + // get_dig_params(groups, tool_capabilities[, wear]) static int l_get_dig_params(lua_State *L); - // get_hit_params(groups, tool_capabilities[, time_from_last_punch]) + // get_hit_params(groups, tool_capabilities[, time_from_last_punch[, wear]]) static int l_get_hit_params(lua_State *L); // check_password_entry(name, entry, password) diff --git a/src/server/luaentity_sao.cpp b/src/server/luaentity_sao.cpp index 1d65ac306..82f6da231 100644 --- a/src/server/luaentity_sao.cpp +++ b/src/server/luaentity_sao.cpp @@ -305,10 +305,11 @@ void LuaEntitySAO::getStaticData(std::string *result) const *result = os.str(); } -u16 LuaEntitySAO::punch(v3f dir, +u32 LuaEntitySAO::punch(v3f dir, const ToolCapabilities *toolcap, ServerActiveObject *puncher, - float time_from_last_punch) + float time_from_last_punch, + u16 initial_wear) { if (!m_registered) { // Delete unknown LuaEntities when punched @@ -326,7 +327,8 @@ u16 LuaEntitySAO::punch(v3f dir, m_armor_groups, toolcap, &tool_item, - time_from_last_punch); + time_from_last_punch, + initial_wear); bool damage_handled = m_env->getScriptIface()->luaentity_Punch(m_id, puncher, time_from_last_punch, toolcap, dir, result.did_punch ? result.damage : 0); diff --git a/src/server/luaentity_sao.h b/src/server/luaentity_sao.h index 6883ae1b9..87b664a8b 100644 --- a/src/server/luaentity_sao.h +++ b/src/server/luaentity_sao.h @@ -44,9 +44,10 @@ public: bool isStaticAllowed() const { return m_prop.static_save; } bool shouldUnload() const { return true; } void getStaticData(std::string *result) const; - u16 punch(v3f dir, const ToolCapabilities *toolcap = nullptr, + u32 punch(v3f dir, const ToolCapabilities *toolcap = nullptr, ServerActiveObject *puncher = nullptr, - float time_from_last_punch = 1000000.0f); + float time_from_last_punch = 1000000.0f, + u16 initial_wear = 0); void rightClick(ServerActiveObject *clicker); void setPos(const v3f &pos); void moveTo(v3f pos, bool continuous); diff --git a/src/server/player_sao.cpp b/src/server/player_sao.cpp index 690823bb7..83e17f830 100644 --- a/src/server/player_sao.cpp +++ b/src/server/player_sao.cpp @@ -409,10 +409,11 @@ void PlayerSAO::setLookPitchAndSend(const float pitch) m_env->getGameDef()->SendMovePlayer(m_peer_id); } -u16 PlayerSAO::punch(v3f dir, +u32 PlayerSAO::punch(v3f dir, const ToolCapabilities *toolcap, ServerActiveObject *puncher, - float time_from_last_punch) + float time_from_last_punch, + u16 initial_wear) { if (!toolcap) return 0; @@ -430,7 +431,7 @@ u16 PlayerSAO::punch(v3f dir, s32 old_hp = getHP(); HitParams hitparams = getHitParams(m_armor_groups, toolcap, - time_from_last_punch); + time_from_last_punch, initial_wear); PlayerSAO *playersao = m_player->getPlayerSAO(); diff --git a/src/server/player_sao.h b/src/server/player_sao.h index 1429d7129..47fe85413 100644 --- a/src/server/player_sao.h +++ b/src/server/player_sao.h @@ -109,8 +109,8 @@ public: Interaction interface */ - u16 punch(v3f dir, const ToolCapabilities *toolcap, ServerActiveObject *puncher, - float time_from_last_punch); + u32 punch(v3f dir, const ToolCapabilities *toolcap, ServerActiveObject *puncher, + float time_from_last_punch, u16 initial_wear = 0); void rightClick(ServerActiveObject *clicker); void setHP(s32 hp, const PlayerHPChangeReason &reason) override { diff --git a/src/server/serveractiveobject.h b/src/server/serveractiveobject.h index 51f445914..5b0ee2d9b 100644 --- a/src/server/serveractiveobject.h +++ b/src/server/serveractiveobject.h @@ -145,11 +145,12 @@ public: virtual bool shouldUnload() const { return true; } - // Returns tool wear - virtual u16 punch(v3f dir, + // Returns added tool wear + virtual u32 punch(v3f dir, const ToolCapabilities *toolcap = nullptr, ServerActiveObject *puncher = nullptr, - float time_from_last_punch = 1000000.0f) + float time_from_last_punch = 1000000.0f, + u16 initial_wear = 0) { return 0; } virtual void rightClick(ServerActiveObject *clicker) {} diff --git a/src/tool.cpp b/src/tool.cpp index 3f639a69e..b0749286d 100644 --- a/src/tool.cpp +++ b/src/tool.cpp @@ -183,9 +183,74 @@ void ToolCapabilities::deserializeJson(std::istream &is) } } +static u32 calculateResultWear(const u32 uses, const u16 initial_wear) +{ + if (uses == 0) { + // Trivial case: Infinite uses + return 0; + } + /* Finite uses. This is not trivial, + as the maximum wear is not neatly evenly divisible by + most possible uses numbers. For example, for 128 + uses, the calculation of wear is trivial, as + 65536 / 128 uses = 512 wear, + so the tool will get 512 wear 128 times in its lifetime. + But for a number like 130, this does not work: + 65536 / 130 uses = 504.123... wear. + Since wear must be an integer, we will get + 504*130 = 65520, which would lead to the wrong number + of uses. + + Instead, we partition the "wear range" into blocks: + A block represents a single use and can be + of two possible sizes: normal and oversized. + A normal block is equal to floor(65536 / uses). + An oversized block is a normal block plus 1. + Then we determine how many oversized and normal + blocks we need and finally, whether we add + the normal wear or the oversized wear. + + Example for 130 uses: + * Normal wear = 504 + * Number of normal blocks = 114 + * Oversized wear = 505 + * Number of oversized blocks = 16 + + If we add everything together, we get: + 114*504 + 16*505 = 65536 + */ + u32 result_wear; + u32 wear_normal = ((U16_MAX+1) / uses); + // Will be non-zero if its not evenly divisible + u16 blocks_oversize = (U16_MAX+1) % uses; + // Whether to add one extra wear point in case + // of oversized wear. + u16 wear_extra = 0; + if (blocks_oversize > 0) { + u16 blocks_normal = uses - blocks_oversize; + /* When the wear has reached this value, we + know that wear_normal has been applied + for blocks_normal times, therefore, + only oversized blocks remain. + This also implies the raw tool wear number + increases a bit faster after this point, + but this should be barely noticable by the + player. + */ + u16 wear_extra_at = blocks_normal * wear_normal; + if (initial_wear >= wear_extra_at) { + wear_extra = 1; + } + } + result_wear = wear_normal + wear_extra; + return result_wear; +} + DigParams getDigParams(const ItemGroupList &groups, - const ToolCapabilities *tp) + const ToolCapabilities *tp, + const u16 initial_wear) { + // Group dig_immediate defaults to fixed time and no wear if (tp->groupcaps.find("dig_immediate") == tp->groupcaps.cend()) { switch (itemgroup_get(groups, "dig_immediate")) { @@ -201,7 +266,7 @@ DigParams getDigParams(const ItemGroupList &groups, // Values to be returned (with a bit of conversion) bool result_diggable = false; float result_time = 0.0; - float result_wear = 0.0; + u32 result_wear = 0; std::string result_main_group; int level = itemgroup_get(groups, "level"); @@ -224,20 +289,22 @@ DigParams getDigParams(const ItemGroupList &groups, if (!result_diggable || time < result_time) { result_time = time; result_diggable = true; - if (cap.uses != 0) - result_wear = 1.0 / cap.uses / pow(3.0, leveldiff); - else - result_wear = 0; + // The actual number of uses increases + // exponentially with leveldiff. + // If the levels are equal, real_uses equals cap.uses. + u32 real_uses = cap.uses * pow(3.0, leveldiff); + real_uses = MYMIN(real_uses, U16_MAX); + result_wear = calculateResultWear(real_uses, initial_wear); result_main_group = groupname; } } - u16 wear_i = U16_MAX * result_wear; - return DigParams(result_diggable, result_time, wear_i, result_main_group); + return DigParams(result_diggable, result_time, result_wear, result_main_group); } HitParams getHitParams(const ItemGroupList &armor_groups, - const ToolCapabilities *tp, float time_from_last_punch) + const ToolCapabilities *tp, float time_from_last_punch, + u16 initial_wear) { s16 damage = 0; float result_wear = 0.0f; @@ -249,10 +316,12 @@ HitParams getHitParams(const ItemGroupList &armor_groups, damage += damageGroup.second * punch_interval_multiplier * armor / 100.0; } - if (tp->punch_attack_uses > 0) - result_wear = 1.0f / tp->punch_attack_uses * punch_interval_multiplier; + if (tp->punch_attack_uses > 0) { + result_wear = calculateResultWear(tp->punch_attack_uses, initial_wear); + result_wear *= punch_interval_multiplier; + } - u16 wear_i = U16_MAX * result_wear; + u32 wear_i = (u32) result_wear; return {damage, wear_i}; } @@ -266,7 +335,8 @@ PunchDamageResult getPunchDamage( const ItemGroupList &armor_groups, const ToolCapabilities *toolcap, const ItemStack *punchitem, - float time_from_last_punch + float time_from_last_punch, + u16 initial_wear ){ bool do_hit = true; { @@ -286,7 +356,8 @@ PunchDamageResult getPunchDamage( if(do_hit) { HitParams hitparams = getHitParams(armor_groups, toolcap, - time_from_last_punch); + time_from_last_punch, + punchitem->wear); result.did_punch = true; result.wear = hitparams.wear; result.damage = hitparams.hp; diff --git a/src/tool.h b/src/tool.h index 59dd501f5..0e3388485 100644 --- a/src/tool.h +++ b/src/tool.h @@ -88,10 +88,10 @@ struct DigParams // Digging time in seconds float time; // Caused wear - u16 wear; + u32 wear; // u32 because wear could be 65536 (single-use tool) std::string main_group; - DigParams(bool a_diggable = false, float a_time = 0.0f, u16 a_wear = 0, + DigParams(bool a_diggable = false, float a_time = 0.0f, u32 a_wear = 0, const std::string &a_main_group = ""): diggable(a_diggable), time(a_time), @@ -101,21 +101,24 @@ struct DigParams }; DigParams getDigParams(const ItemGroupList &groups, - const ToolCapabilities *tp); + const ToolCapabilities *tp, + const u16 initial_wear = 0); struct HitParams { s16 hp; - u16 wear; + // Caused wear + u32 wear; // u32 because wear could be 65536 (single-use weapon) - HitParams(s16 hp_ = 0, u16 wear_ = 0): + HitParams(s16 hp_ = 0, u32 wear_ = 0): hp(hp_), wear(wear_) {} }; HitParams getHitParams(const ItemGroupList &armor_groups, - const ToolCapabilities *tp, float time_from_last_punch); + const ToolCapabilities *tp, float time_from_last_punch, + u16 initial_wear = 0); HitParams getHitParams(const ItemGroupList &armor_groups, const ToolCapabilities *tp); @@ -135,7 +138,8 @@ PunchDamageResult getPunchDamage( const ItemGroupList &armor_groups, const ToolCapabilities *toolcap, const ItemStack *punchitem, - float time_from_last_punch + float time_from_last_punch, + u16 initial_wear = 0 ); f32 getToolRange(const ItemDefinition &def_selected, const ItemDefinition &def_hand); -- cgit v1.2.3 From 57a59ae92d4bbfa4fdd60d7acd72c6440f63a49c Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Wed, 1 Dec 2021 20:22:33 +0100 Subject: Network: Delete copy constructor and use std::move instead (#11642) This is a follow-up change which disables class copies where possible to avoid unnecessary memory movements. --- src/client/client.cpp | 2 +- src/network/connection.cpp | 445 ++++++++++++++++++++++---------------- src/network/connection.h | 416 ++++++++++++++++------------------- src/network/connectionthreads.cpp | 190 ++++++++-------- src/network/connectionthreads.h | 31 ++- src/unittest/test_connection.cpp | 10 +- src/util/pointer.h | 58 ++--- 7 files changed, 600 insertions(+), 552 deletions(-) (limited to 'src/network') diff --git a/src/client/client.cpp b/src/client/client.cpp index 45cc62a33..3ee1298ff 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -877,7 +877,7 @@ void Client::ProcessData(NetworkPacket *pkt) */ if(sender_peer_id != PEER_ID_SERVER) { infostream << "Client::ProcessData(): Discarding data not " - "coming from server: peer_id=" << sender_peer_id + "coming from server: peer_id=" << sender_peer_id << " command=" << pkt->getCommand() << std::endl; return; } diff --git a/src/network/connection.cpp b/src/network/connection.cpp index 548b2e3a0..2d3cf6e88 100644 --- a/src/network/connection.cpp +++ b/src/network/connection.cpp @@ -62,18 +62,27 @@ namespace con #define PING_TIMEOUT 5.0 -BufferedPacket makePacket(Address &address, const SharedBuffer &data, +u16 BufferedPacket::getSeqnum() const +{ + if (size() < BASE_HEADER_SIZE + 3) + return 0; // should never happen + + return readU16(&data[BASE_HEADER_SIZE + 1]); +} + +BufferedPacketPtr makePacket(Address &address, const SharedBuffer &data, u32 protocol_id, session_t sender_peer_id, u8 channel) { u32 packet_size = data.getSize() + BASE_HEADER_SIZE; - BufferedPacket p(packet_size); - p.address = address; - writeU32(&p.data[0], protocol_id); - writeU16(&p.data[4], sender_peer_id); - writeU8(&p.data[6], channel); + BufferedPacketPtr p(new BufferedPacket(packet_size)); + p->address = address; + + writeU32(&p->data[0], protocol_id); + writeU16(&p->data[4], sender_peer_id); + writeU8(&p->data[6], channel); - memcpy(&p.data[BASE_HEADER_SIZE], *data, data.getSize()); + memcpy(&p->data[BASE_HEADER_SIZE], *data, data.getSize()); return p; } @@ -169,9 +178,8 @@ void ReliablePacketBuffer::print() MutexAutoLock listlock(m_list_mutex); LOG(dout_con<<"Dump of ReliablePacketBuffer:" << std::endl); unsigned int index = 0; - for (BufferedPacket &bufferedPacket : m_list) { - u16 s = readU16(&(bufferedPacket.data[BASE_HEADER_SIZE+1])); - LOG(dout_con<getSeqnum() << std::endl); index++; } } @@ -188,16 +196,13 @@ u32 ReliablePacketBuffer::size() return m_list.size(); } -RPBSearchResult ReliablePacketBuffer::findPacket(u16 seqnum) +RPBSearchResult ReliablePacketBuffer::findPacketNoLock(u16 seqnum) { - std::list::iterator i = m_list.begin(); - for(; i != m_list.end(); ++i) - { - u16 s = readU16(&(i->data[BASE_HEADER_SIZE+1])); - if (s == seqnum) - break; + for (auto it = m_list.begin(); it != m_list.end(); ++it) { + if ((*it)->getSeqnum() == seqnum) + return it; } - return i; + return m_list.end(); } bool ReliablePacketBuffer::getFirstSeqnum(u16& result) @@ -205,54 +210,54 @@ bool ReliablePacketBuffer::getFirstSeqnum(u16& result) MutexAutoLock listlock(m_list_mutex); if (m_list.empty()) return false; - const BufferedPacket &p = m_list.front(); - result = readU16(&p.data[BASE_HEADER_SIZE + 1]); + result = m_list.front()->getSeqnum(); return true; } -BufferedPacket ReliablePacketBuffer::popFirst() +BufferedPacketPtr ReliablePacketBuffer::popFirst() { MutexAutoLock listlock(m_list_mutex); if (m_list.empty()) throw NotFoundException("Buffer is empty"); - BufferedPacket p = std::move(m_list.front()); + + BufferedPacketPtr p(m_list.front()); m_list.pop_front(); if (m_list.empty()) { m_oldest_non_answered_ack = 0; } else { - m_oldest_non_answered_ack = - readU16(&m_list.front().data[BASE_HEADER_SIZE + 1]); + m_oldest_non_answered_ack = m_list.front()->getSeqnum(); } return p; } -BufferedPacket ReliablePacketBuffer::popSeqnum(u16 seqnum) +BufferedPacketPtr ReliablePacketBuffer::popSeqnum(u16 seqnum) { MutexAutoLock listlock(m_list_mutex); - RPBSearchResult r = findPacket(seqnum); - if (r == notFound()) { + RPBSearchResult r = findPacketNoLock(seqnum); + if (r == m_list.end()) { LOG(dout_con<<"Sequence number: " << seqnum << " not found in reliable buffer"<getSeqnum(); } return p; } -void ReliablePacketBuffer::insert(const BufferedPacket &p, u16 next_expected) +void ReliablePacketBuffer::insert(BufferedPacketPtr &p_ptr, u16 next_expected) { MutexAutoLock listlock(m_list_mutex); - if (p.data.getSize() < BASE_HEADER_SIZE + 3) { + const BufferedPacket &p = *p_ptr; + + if (p.size() < BASE_HEADER_SIZE + 3) { errorstream << "ReliablePacketBuffer::insert(): Invalid data size for " "reliable packet" << std::endl; return; @@ -263,7 +268,7 @@ void ReliablePacketBuffer::insert(const BufferedPacket &p, u16 next_expected) << std::endl; return; } - u16 seqnum = readU16(&p.data[BASE_HEADER_SIZE + 1]); + const u16 seqnum = p.getSeqnum(); if (!seqnum_in_window(seqnum, next_expected, MAX_RELIABLE_WINDOW_SIZE)) { errorstream << "ReliablePacketBuffer::insert(): seqnum is outside of " @@ -280,44 +285,44 @@ void ReliablePacketBuffer::insert(const BufferedPacket &p, u16 next_expected) // Find the right place for the packet and insert it there // If list is empty, just add it - if (m_list.empty()) - { - m_list.push_back(p); + if (m_list.empty()) { + m_list.push_back(p_ptr); m_oldest_non_answered_ack = seqnum; // Done. return; } // Otherwise find the right place - std::list::iterator i = m_list.begin(); + auto it = m_list.begin(); // Find the first packet in the list which has a higher seqnum - u16 s = readU16(&(i->data[BASE_HEADER_SIZE+1])); + u16 s = (*it)->getSeqnum(); /* case seqnum is smaller then next_expected seqnum */ /* this is true e.g. on wrap around */ if (seqnum < next_expected) { - while(((s < seqnum) || (s >= next_expected)) && (i != m_list.end())) { - ++i; - if (i != m_list.end()) - s = readU16(&(i->data[BASE_HEADER_SIZE+1])); + while(((s < seqnum) || (s >= next_expected)) && (it != m_list.end())) { + ++it; + if (it != m_list.end()) + s = (*it)->getSeqnum(); } } /* non wrap around case (at least for incoming and next_expected */ else { - while(((s < seqnum) && (s >= next_expected)) && (i != m_list.end())) { - ++i; - if (i != m_list.end()) - s = readU16(&(i->data[BASE_HEADER_SIZE+1])); + while(((s < seqnum) && (s >= next_expected)) && (it != m_list.end())) { + ++it; + if (it != m_list.end()) + s = (*it)->getSeqnum(); } } if (s == seqnum) { /* nothing to do this seems to be a resent packet */ /* for paranoia reason data should be compared */ + auto &i = *it; if ( - (readU16(&(i->data[BASE_HEADER_SIZE+1])) != seqnum) || - (i->data.getSize() != p.data.getSize()) || + (i->getSeqnum() != seqnum) || + (i->size() != p.size()) || (i->address != p.address) ) { @@ -325,51 +330,52 @@ void ReliablePacketBuffer::insert(const BufferedPacket &p, u16 next_expected) fprintf(stderr, "Duplicated seqnum %d non matching packet detected:\n", seqnum); - fprintf(stderr, "Old: seqnum: %05d size: %04d, address: %s\n", - readU16(&(i->data[BASE_HEADER_SIZE+1])),i->data.getSize(), + fprintf(stderr, "Old: seqnum: %05d size: %04zu, address: %s\n", + i->getSeqnum(), i->size(), i->address.serializeString().c_str()); - fprintf(stderr, "New: seqnum: %05d size: %04u, address: %s\n", - readU16(&(p.data[BASE_HEADER_SIZE+1])),p.data.getSize(), + fprintf(stderr, "New: seqnum: %05d size: %04zu, address: %s\n", + p.getSeqnum(), p.size(), p.address.serializeString().c_str()); throw IncomingDataCorruption("duplicated packet isn't same as original one"); } } /* insert or push back */ - else if (i != m_list.end()) { - m_list.insert(i, p); + else if (it != m_list.end()) { + m_list.insert(it, p_ptr); } else { - m_list.push_back(p); + m_list.push_back(p_ptr); } /* update last packet number */ - m_oldest_non_answered_ack = readU16(&m_list.front().data[BASE_HEADER_SIZE+1]); + m_oldest_non_answered_ack = m_list.front()->getSeqnum(); } void ReliablePacketBuffer::incrementTimeouts(float dtime) { MutexAutoLock listlock(m_list_mutex); - for (BufferedPacket &bufferedPacket : m_list) { - bufferedPacket.time += dtime; - bufferedPacket.totaltime += dtime; + for (auto &packet : m_list) { + packet->time += dtime; + packet->totaltime += dtime; } } -std::list +std::list> ReliablePacketBuffer::getTimedOuts(float timeout, u32 max_packets) { MutexAutoLock listlock(m_list_mutex); - std::list timed_outs; - for (BufferedPacket &bufferedPacket : m_list) { - if (bufferedPacket.time >= timeout) { - // caller will resend packet so reset time and increase counter - bufferedPacket.time = 0.0f; - bufferedPacket.resend_count++; + std::list> timed_outs; + for (auto &packet : m_list) { + if (packet->time < timeout) + continue; - timed_outs.push_back(bufferedPacket); + // caller will resend packet so reset time and increase counter + packet->time = 0.0f; + packet->resend_count++; - if (timed_outs.size() >= max_packets) - break; - } + timed_outs.emplace_back(packet); + + if (timed_outs.size() >= max_packets) + break; } return timed_outs; } @@ -428,11 +434,13 @@ IncomingSplitBuffer::~IncomingSplitBuffer() } } -SharedBuffer IncomingSplitBuffer::insert(const BufferedPacket &p, bool reliable) +SharedBuffer IncomingSplitBuffer::insert(BufferedPacketPtr &p_ptr, bool reliable) { MutexAutoLock listlock(m_map_mutex); + const BufferedPacket &p = *p_ptr; + u32 headersize = BASE_HEADER_SIZE + 7; - if (p.data.getSize() < headersize) { + if (p.size() < headersize) { errorstream << "Invalid data size for split packet" << std::endl; return SharedBuffer(); } @@ -473,7 +481,7 @@ SharedBuffer IncomingSplitBuffer::insert(const BufferedPacket &p, bool relia < chunkdata(chunkdatasize); memcpy(*chunkdata, &(p.data[headersize]), chunkdatasize); @@ -520,14 +528,67 @@ void IncomingSplitBuffer::removeUnreliableTimedOuts(float dtime, float timeout) ConnectionCommand */ -void ConnectionCommand::send(session_t peer_id_, u8 channelnum_, NetworkPacket *pkt, - bool reliable_) +ConnectionCommandPtr ConnectionCommand::create(ConnectionCommandType type) +{ + return ConnectionCommandPtr(new ConnectionCommand(type)); +} + +ConnectionCommandPtr ConnectionCommand::serve(Address address) +{ + auto c = create(CONNCMD_SERVE); + c->address = address; + return c; +} + +ConnectionCommandPtr ConnectionCommand::connect(Address address) { - type = CONNCMD_SEND; - peer_id = peer_id_; - channelnum = channelnum_; - data = pkt->oldForgePacket(); - reliable = reliable_; + auto c = create(CONNCMD_CONNECT); + c->address = address; + return c; +} + +ConnectionCommandPtr ConnectionCommand::disconnect() +{ + return create(CONNCMD_DISCONNECT); +} + +ConnectionCommandPtr ConnectionCommand::disconnect_peer(session_t peer_id) +{ + auto c = create(CONNCMD_DISCONNECT_PEER); + c->peer_id = peer_id; + return c; +} + +ConnectionCommandPtr ConnectionCommand::send(session_t peer_id, u8 channelnum, + NetworkPacket *pkt, bool reliable) +{ + auto c = create(CONNCMD_SEND); + c->peer_id = peer_id; + c->channelnum = channelnum; + c->reliable = reliable; + c->data = pkt->oldForgePacket(); + return c; +} + +ConnectionCommandPtr ConnectionCommand::ack(session_t peer_id, u8 channelnum, const Buffer &data) +{ + auto c = create(CONCMD_ACK); + c->peer_id = peer_id; + c->channelnum = channelnum; + c->reliable = false; + data.copyTo(c->data); + return c; +} + +ConnectionCommandPtr ConnectionCommand::createPeer(session_t peer_id, const Buffer &data) +{ + auto c = create(CONCMD_CREATE_PEER); + c->peer_id = peer_id; + c->channelnum = 0; + c->reliable = true; + c->raw = true; + data.copyTo(c->data); + return c; } /* @@ -562,39 +623,38 @@ void Channel::setNextSplitSeqNum(u16 seqnum) u16 Channel::getOutgoingSequenceNumber(bool& successful) { MutexAutoLock internal(m_internal_mutex); + u16 retval = next_outgoing_seqnum; - u16 lowest_unacked_seqnumber; + successful = false; /* shortcut if there ain't any packet in outgoing list */ - if (outgoing_reliables_sent.empty()) - { + if (outgoing_reliables_sent.empty()) { + successful = true; next_outgoing_seqnum++; return retval; } - if (outgoing_reliables_sent.getFirstSeqnum(lowest_unacked_seqnumber)) - { + u16 lowest_unacked_seqnumber; + if (outgoing_reliables_sent.getFirstSeqnum(lowest_unacked_seqnumber)) { if (lowest_unacked_seqnumber < next_outgoing_seqnum) { // ugly cast but this one is required in order to tell compiler we // know about difference of two unsigned may be negative in general // but we already made sure it won't happen in this case if (((u16)(next_outgoing_seqnum - lowest_unacked_seqnumber)) > m_window_size) { - successful = false; return 0; } - } - else { + } else { // ugly cast but this one is required in order to tell compiler we // know about difference of two unsigned may be negative in general // but we already made sure it won't happen in this case if ((next_outgoing_seqnum + (u16)(SEQNUM_MAX - lowest_unacked_seqnumber)) > m_window_size) { - successful = false; return 0; } } } + successful = true; next_outgoing_seqnum++; return retval; } @@ -946,45 +1006,45 @@ bool UDPPeer::Ping(float dtime,SharedBuffer& data) return false; } -void UDPPeer::PutReliableSendCommand(ConnectionCommand &c, +void UDPPeer::PutReliableSendCommand(ConnectionCommandPtr &c, unsigned int max_packet_size) { if (m_pending_disconnect) return; - Channel &chan = channels[c.channelnum]; + Channel &chan = channels[c->channelnum]; if (chan.queued_commands.empty() && /* don't queue more packets then window size */ - (chan.queued_reliables.size() < chan.getWindowSize() / 2)) { + (chan.queued_reliables.size() + 1 < chan.getWindowSize() / 2)) { LOG(dout_con<getDesc() - <<" processing reliable command for peer id: " << c.peer_id - <<" data size: " << c.data.getSize() << std::endl); - if (!processReliableSendCommand(c,max_packet_size)) { - chan.queued_commands.push_back(c); - } - } - else { + <<" processing reliable command for peer id: " << c->peer_id + <<" data size: " << c->data.getSize() << std::endl); + if (processReliableSendCommand(c, max_packet_size)) + return; + } else { LOG(dout_con<getDesc() - <<" Queueing reliable command for peer id: " << c.peer_id - <<" data size: " << c.data.getSize() <= chan.getWindowSize() / 2) { + <<" Queueing reliable command for peer id: " << c->peer_id + <<" data size: " << c->data.getSize() <= chan.getWindowSize() / 2) { LOG(derr_con << m_connection->getDesc() - << "Possible packet stall to peer id: " << c.peer_id + << "Possible packet stall to peer id: " << c->peer_id << " queued_commands=" << chan.queued_commands.size() << std::endl); } } + chan.queued_commands.push_back(c); } bool UDPPeer::processReliableSendCommand( - ConnectionCommand &c, + ConnectionCommandPtr &c_ptr, unsigned int max_packet_size) { if (m_pending_disconnect) return true; + const auto &c = *c_ptr; Channel &chan = channels[c.channelnum]; u32 chunksize_max = max_packet_size @@ -1003,9 +1063,9 @@ bool UDPPeer::processReliableSendCommand( chan.setNextSplitSeqNum(split_sequence_number); } - bool have_sequence_number = true; + bool have_sequence_number = false; bool have_initial_sequence_number = false; - std::queue toadd; + std::queue toadd; volatile u16 initial_sequence_number = 0; for (SharedBuffer &original : originals) { @@ -1024,25 +1084,23 @@ bool UDPPeer::processReliableSendCommand( SharedBuffer reliable = makeReliablePacket(original, seqnum); // Add base headers and make a packet - BufferedPacket p = con::makePacket(address, reliable, + BufferedPacketPtr p = con::makePacket(address, reliable, m_connection->GetProtocolID(), m_connection->GetPeerID(), c.channelnum); - toadd.push(std::move(p)); + toadd.push(p); } if (have_sequence_number) { - volatile u16 pcount = 0; while (!toadd.empty()) { - BufferedPacket p = std::move(toadd.front()); + BufferedPacketPtr p = toadd.front(); toadd.pop(); // LOG(dout_con<getDesc() // << " queuing reliable packet for peer_id: " << c.peer_id // << " channel: " << (c.channelnum&0xFF) // << " seqnum: " << readU16(&p.data[BASE_HEADER_SIZE+1]) // << std::endl) - chan.queued_reliables.push(std::move(p)); - pcount++; + chan.queued_reliables.push(p); } sanity_check(chan.queued_reliables.size() < 0xFFFF); return true; @@ -1051,6 +1109,7 @@ bool UDPPeer::processReliableSendCommand( volatile u16 packets_available = toadd.size(); /* we didn't get a single sequence number no need to fill queue */ if (!have_initial_sequence_number) { + LOG(derr_con << m_connection->getDesc() << "Ran out of sequence numbers!" << std::endl); return false; } @@ -1096,18 +1155,18 @@ void UDPPeer::RunCommandQueues( (channel.queued_reliables.size() < maxtransfer) && (commands_processed < maxcommands)) { try { - ConnectionCommand c = channel.queued_commands.front(); + ConnectionCommandPtr c = channel.queued_commands.front(); LOG(dout_con << m_connection->getDesc() << " processing queued reliable command " << std::endl); // Packet is processed, remove it from queue - if (processReliableSendCommand(c,max_packet_size)) { + if (processReliableSendCommand(c, max_packet_size)) { channel.queued_commands.pop_front(); } else { LOG(dout_con << m_connection->getDesc() - << " Failed to queue packets for peer_id: " << c.peer_id - << ", delaying sending of " << c.data.getSize() + << " Failed to queue packets for peer_id: " << c->peer_id + << ", delaying sending of " << c->data.getSize() << " bytes" << std::endl); } } @@ -1130,13 +1189,70 @@ void UDPPeer::setNextSplitSequenceNumber(u8 channel, u16 seqnum) channels[channel].setNextSplitSeqNum(seqnum); } -SharedBuffer UDPPeer::addSplitPacket(u8 channel, const BufferedPacket &toadd, +SharedBuffer UDPPeer::addSplitPacket(u8 channel, BufferedPacketPtr &toadd, bool reliable) { assert(channel < CHANNEL_COUNT); // Pre-condition return channels[channel].incoming_splits.insert(toadd, reliable); } +/* + ConnectionEvent +*/ + +const char *ConnectionEvent::describe() const +{ + switch(type) { + case CONNEVENT_NONE: + return "CONNEVENT_NONE"; + case CONNEVENT_DATA_RECEIVED: + return "CONNEVENT_DATA_RECEIVED"; + case CONNEVENT_PEER_ADDED: + return "CONNEVENT_PEER_ADDED"; + case CONNEVENT_PEER_REMOVED: + return "CONNEVENT_PEER_REMOVED"; + case CONNEVENT_BIND_FAILED: + return "CONNEVENT_BIND_FAILED"; + } + return "Invalid ConnectionEvent"; +} + + +ConnectionEventPtr ConnectionEvent::create(ConnectionEventType type) +{ + return std::shared_ptr(new ConnectionEvent(type)); +} + +ConnectionEventPtr ConnectionEvent::dataReceived(session_t peer_id, const Buffer &data) +{ + auto e = create(CONNEVENT_DATA_RECEIVED); + e->peer_id = peer_id; + data.copyTo(e->data); + return e; +} + +ConnectionEventPtr ConnectionEvent::peerAdded(session_t peer_id, Address address) +{ + auto e = create(CONNEVENT_PEER_ADDED); + e->peer_id = peer_id; + e->address = address; + return e; +} + +ConnectionEventPtr ConnectionEvent::peerRemoved(session_t peer_id, bool is_timeout, Address address) +{ + auto e = create(CONNEVENT_PEER_REMOVED); + e->peer_id = peer_id; + e->timeout = is_timeout; + e->address = address; + return e; +} + +ConnectionEventPtr ConnectionEvent::bindFailed() +{ + return create(CONNEVENT_BIND_FAILED); +} + /* Connection */ @@ -1186,18 +1302,12 @@ Connection::~Connection() /* Internal stuff */ -void Connection::putEvent(const ConnectionEvent &e) +void Connection::putEvent(ConnectionEventPtr e) { - assert(e.type != CONNEVENT_NONE); // Pre-condition + assert(e->type != CONNEVENT_NONE); // Pre-condition m_event_queue.push_back(e); } -void Connection::putEvent(ConnectionEvent &&e) -{ - assert(e.type != CONNEVENT_NONE); // Pre-condition - m_event_queue.push_back(std::move(e)); -} - void Connection::TriggerSend() { m_sendThread->Trigger(); @@ -1260,11 +1370,9 @@ bool Connection::deletePeer(session_t peer_id, bool timeout) Address peer_address; //any peer has a primary address this never fails! peer->getAddress(MTP_PRIMARY, peer_address); - // Create event - ConnectionEvent e; - e.peerRemoved(peer_id, timeout, peer_address); - putEvent(e); + // Create event + putEvent(ConnectionEvent::peerRemoved(peer_id, timeout, peer_address)); peer->Drop(); return true; @@ -1272,18 +1380,16 @@ bool Connection::deletePeer(session_t peer_id, bool timeout) /* Interface */ -ConnectionEvent Connection::waitEvent(u32 timeout_ms) +ConnectionEventPtr Connection::waitEvent(u32 timeout_ms) { try { return m_event_queue.pop_front(timeout_ms); } catch(ItemNotFoundException &ex) { - ConnectionEvent e; - e.type = CONNEVENT_NONE; - return e; + return ConnectionEvent::create(CONNEVENT_NONE); } } -void Connection::putCommand(const ConnectionCommand &c) +void Connection::putCommand(ConnectionCommandPtr c) { if (!m_shutting_down) { m_command_queue.push_back(c); @@ -1291,26 +1397,14 @@ void Connection::putCommand(const ConnectionCommand &c) } } -void Connection::putCommand(ConnectionCommand &&c) -{ - if (!m_shutting_down) { - m_command_queue.push_back(std::move(c)); - m_sendThread->Trigger(); - } -} - void Connection::Serve(Address bind_addr) { - ConnectionCommand c; - c.serve(bind_addr); - putCommand(c); + putCommand(ConnectionCommand::serve(bind_addr)); } void Connection::Connect(Address address) { - ConnectionCommand c; - c.connect(address); - putCommand(c); + putCommand(ConnectionCommand::connect(address)); } bool Connection::Connected() @@ -1332,9 +1426,7 @@ bool Connection::Connected() void Connection::Disconnect() { - ConnectionCommand c; - c.disconnect(); - putCommand(c); + putCommand(ConnectionCommand::disconnect()); } bool Connection::Receive(NetworkPacket *pkt, u32 timeout) @@ -1345,11 +1437,15 @@ bool Connection::Receive(NetworkPacket *pkt, u32 timeout) This is not considered to be a problem (is it?) */ for(;;) { - ConnectionEvent e = waitEvent(timeout); - if (e.type != CONNEVENT_NONE) + ConnectionEventPtr e_ptr = waitEvent(timeout); + const ConnectionEvent &e = *e_ptr; + + if (e.type != CONNEVENT_NONE) { LOG(dout_con << getDesc() << ": Receive: got event: " << e.describe() << std::endl); - switch(e.type) { + } + + switch (e.type) { case CONNEVENT_NONE: return false; case CONNEVENT_DATA_RECEIVED: @@ -1397,10 +1493,7 @@ void Connection::Send(session_t peer_id, u8 channelnum, { assert(channelnum < CHANNEL_COUNT); // Pre-condition - ConnectionCommand c; - - c.send(peer_id, channelnum, pkt, reliable); - putCommand(std::move(c)); + putCommand(ConnectionCommand::send(peer_id, channelnum, pkt, reliable)); } Address Connection::GetPeerAddress(session_t peer_id) @@ -1499,41 +1592,31 @@ u16 Connection::createPeer(Address& sender, MTProtocols protocol, int fd) LOG(dout_con << getDesc() << "createPeer(): giving peer_id=" << peer_id_new << std::endl); - ConnectionCommand cmd; - Buffer reply(4); - writeU8(&reply[0], PACKET_TYPE_CONTROL); - writeU8(&reply[1], CONTROLTYPE_SET_PEER_ID); - writeU16(&reply[2], peer_id_new); - cmd.createPeer(peer_id_new,reply); - putCommand(std::move(cmd)); + { + Buffer reply(4); + writeU8(&reply[0], PACKET_TYPE_CONTROL); + writeU8(&reply[1], CONTROLTYPE_SET_PEER_ID); + writeU16(&reply[2], peer_id_new); + putCommand(ConnectionCommand::createPeer(peer_id_new, reply)); + } // Create peer addition event - ConnectionEvent e; - e.peerAdded(peer_id_new, sender); - putEvent(e); + putEvent(ConnectionEvent::peerAdded(peer_id_new, sender)); // We're now talking to a valid peer_id return peer_id_new; } -void Connection::PrintInfo(std::ostream &out) -{ - m_info_mutex.lock(); - out< ack(4); writeU8(&ack[0], PACKET_TYPE_CONTROL); writeU8(&ack[1], CONTROLTYPE_ACK); writeU16(&ack[2], seqnum); - c.ack(peer_id, channelnum, ack); - putCommand(std::move(c)); + putCommand(ConnectionCommand::ack(peer_id, channelnum, ack)); m_sendThread->Trigger(); } diff --git a/src/network/connection.h b/src/network/connection.h index ea74ffb1c..1afb4ae84 100644 --- a/src/network/connection.h +++ b/src/network/connection.h @@ -32,6 +32,95 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include +#define MAX_UDP_PEERS 65535 + +/* +=== NOTES === + +A packet is sent through a channel to a peer with a basic header: + Header (7 bytes): + [0] u32 protocol_id + [4] session_t sender_peer_id + [6] u8 channel +sender_peer_id: + Unique to each peer. + value 0 (PEER_ID_INEXISTENT) is reserved for making new connections + value 1 (PEER_ID_SERVER) is reserved for server + these constants are defined in constants.h +channel: + Channel numbers have no intrinsic meaning. Currently only 0, 1, 2 exist. +*/ +#define BASE_HEADER_SIZE 7 +#define CHANNEL_COUNT 3 + +/* +Packet types: + +CONTROL: This is a packet used by the protocol. +- When this is processed, nothing is handed to the user. + Header (2 byte): + [0] u8 type + [1] u8 controltype +controltype and data description: + CONTROLTYPE_ACK + [2] u16 seqnum + CONTROLTYPE_SET_PEER_ID + [2] session_t peer_id_new + CONTROLTYPE_PING + - There is no actual reply, but this can be sent in a reliable + packet to get a reply + CONTROLTYPE_DISCO +*/ +enum ControlType : u8 { + CONTROLTYPE_ACK = 0, + CONTROLTYPE_SET_PEER_ID = 1, + CONTROLTYPE_PING = 2, + CONTROLTYPE_DISCO = 3, +}; + +/* +ORIGINAL: This is a plain packet with no control and no error +checking at all. +- When this is processed, it is directly handed to the user. + Header (1 byte): + [0] u8 type +*/ +//#define TYPE_ORIGINAL 1 +#define ORIGINAL_HEADER_SIZE 1 + +/* +SPLIT: These are sequences of packets forming one bigger piece of +data. +- When processed and all the packet_nums 0...packet_count-1 are + present (this should be buffered), the resulting data shall be + directly handed to the user. +- If the data fails to come up in a reasonable time, the buffer shall + be silently discarded. +- These can be sent as-is or atop of a RELIABLE packet stream. + Header (7 bytes): + [0] u8 type + [1] u16 seqnum + [3] u16 chunk_count + [5] u16 chunk_num +*/ +//#define TYPE_SPLIT 2 + +/* +RELIABLE: Delivery of all RELIABLE packets shall be forced by ACKs, +and they shall be delivered in the same order as sent. This is done +with a buffer in the receiving and transmitting end. +- When this is processed, the contents of each packet is recursively + processed as packets. + Header (3 bytes): + [0] u8 type + [1] u16 seqnum + +*/ +//#define TYPE_RELIABLE 3 +#define RELIABLE_HEADER_SIZE 3 +#define SEQNUM_INITIAL 65500 +#define SEQNUM_MAX 65535 + class NetworkPacket; namespace con @@ -46,9 +135,13 @@ typedef enum MTProtocols { MTP_MINETEST_RELIABLE_UDP } MTProtocols; -#define MAX_UDP_PEERS 65535 - -#define SEQNUM_MAX 65535 +enum PacketType : u8 { + PACKET_TYPE_CONTROL = 0, + PACKET_TYPE_ORIGINAL = 1, + PACKET_TYPE_SPLIT = 2, + PACKET_TYPE_RELIABLE = 3, + PACKET_TYPE_MAX +}; inline bool seqnum_higher(u16 totest, u16 base) { @@ -85,24 +178,40 @@ static inline float CALC_DTIME(u64 lasttime, u64 curtime) return MYMAX(MYMIN(value,0.1),0.0); } -struct BufferedPacket -{ - BufferedPacket(u8 *a_data, u32 a_size): - data(a_data, a_size) - {} - BufferedPacket(u32 a_size): - data(a_size) - {} - Buffer data; // Data of the packet, including headers +/* + Struct for all kinds of packets. Includes following data: + BASE_HEADER + u8[] packet data (usually copied from SharedBuffer) +*/ +struct BufferedPacket { + BufferedPacket(u32 a_size) + { + m_data.resize(a_size); + data = &m_data[0]; + } + + DISABLE_CLASS_COPY(BufferedPacket) + + u16 getSeqnum() const; + + inline const size_t size() const { return m_data.size(); } + + u8 *data; // Direct memory access float time = 0.0f; // Seconds from buffering the packet or re-sending float totaltime = 0.0f; // Seconds from buffering the packet u64 absolute_send_time = -1; Address address; // Sender or destination unsigned int resend_count = 0; + +private: + std::vector m_data; // Data of the packet, including headers }; +typedef std::shared_ptr BufferedPacketPtr; + + // This adds the base headers to the data and makes a packet out of it -BufferedPacket makePacket(Address &address, const SharedBuffer &data, +BufferedPacketPtr makePacket(Address &address, const SharedBuffer &data, u32 protocol_id, session_t sender_peer_id, u8 channel); // Depending on size, make a TYPE_ORIGINAL or TYPE_SPLIT packet @@ -136,101 +245,12 @@ private: std::map> chunks; }; -/* -=== NOTES === - -A packet is sent through a channel to a peer with a basic header: - Header (7 bytes): - [0] u32 protocol_id - [4] session_t sender_peer_id - [6] u8 channel -sender_peer_id: - Unique to each peer. - value 0 (PEER_ID_INEXISTENT) is reserved for making new connections - value 1 (PEER_ID_SERVER) is reserved for server - these constants are defined in constants.h -channel: - Channel numbers have no intrinsic meaning. Currently only 0, 1, 2 exist. -*/ -#define BASE_HEADER_SIZE 7 -#define CHANNEL_COUNT 3 -/* -Packet types: - -CONTROL: This is a packet used by the protocol. -- When this is processed, nothing is handed to the user. - Header (2 byte): - [0] u8 type - [1] u8 controltype -controltype and data description: - CONTROLTYPE_ACK - [2] u16 seqnum - CONTROLTYPE_SET_PEER_ID - [2] session_t peer_id_new - CONTROLTYPE_PING - - There is no actual reply, but this can be sent in a reliable - packet to get a reply - CONTROLTYPE_DISCO -*/ -//#define TYPE_CONTROL 0 -#define CONTROLTYPE_ACK 0 -#define CONTROLTYPE_SET_PEER_ID 1 -#define CONTROLTYPE_PING 2 -#define CONTROLTYPE_DISCO 3 - -/* -ORIGINAL: This is a plain packet with no control and no error -checking at all. -- When this is processed, it is directly handed to the user. - Header (1 byte): - [0] u8 type -*/ -//#define TYPE_ORIGINAL 1 -#define ORIGINAL_HEADER_SIZE 1 -/* -SPLIT: These are sequences of packets forming one bigger piece of -data. -- When processed and all the packet_nums 0...packet_count-1 are - present (this should be buffered), the resulting data shall be - directly handed to the user. -- If the data fails to come up in a reasonable time, the buffer shall - be silently discarded. -- These can be sent as-is or atop of a RELIABLE packet stream. - Header (7 bytes): - [0] u8 type - [1] u16 seqnum - [3] u16 chunk_count - [5] u16 chunk_num -*/ -//#define TYPE_SPLIT 2 -/* -RELIABLE: Delivery of all RELIABLE packets shall be forced by ACKs, -and they shall be delivered in the same order as sent. This is done -with a buffer in the receiving and transmitting end. -- When this is processed, the contents of each packet is recursively - processed as packets. - Header (3 bytes): - [0] u8 type - [1] u16 seqnum - -*/ -//#define TYPE_RELIABLE 3 -#define RELIABLE_HEADER_SIZE 3 -#define SEQNUM_INITIAL 65500 - -enum PacketType: u8 { - PACKET_TYPE_CONTROL = 0, - PACKET_TYPE_ORIGINAL = 1, - PACKET_TYPE_SPLIT = 2, - PACKET_TYPE_RELIABLE = 3, - PACKET_TYPE_MAX -}; /* A buffer which stores reliable packets and sorts them internally for fast access to the smallest one. */ -typedef std::list::iterator RPBSearchResult; +typedef std::list::iterator RPBSearchResult; class ReliablePacketBuffer { @@ -239,12 +259,12 @@ public: bool getFirstSeqnum(u16& result); - BufferedPacket popFirst(); - BufferedPacket popSeqnum(u16 seqnum); - void insert(const BufferedPacket &p, u16 next_expected); + BufferedPacketPtr popFirst(); + BufferedPacketPtr popSeqnum(u16 seqnum); + void insert(BufferedPacketPtr &p_ptr, u16 next_expected); void incrementTimeouts(float dtime); - std::list getTimedOuts(float timeout, u32 max_packets); + std::list> getTimedOuts(float timeout, u32 max_packets); void print(); bool empty(); @@ -252,10 +272,9 @@ public: private: - RPBSearchResult findPacket(u16 seqnum); // does not perform locking - inline RPBSearchResult notFound() { return m_list.end(); } + RPBSearchResult findPacketNoLock(u16 seqnum); - std::list m_list; + std::list m_list; u16 m_oldest_non_answered_ack; @@ -274,7 +293,7 @@ public: Returns a reference counted buffer of length != 0 when a full split packet is constructed. If not, returns one of length 0. */ - SharedBuffer insert(const BufferedPacket &p, bool reliable); + SharedBuffer insert(BufferedPacketPtr &p_ptr, bool reliable); void removeUnreliableTimedOuts(float dtime, float timeout); @@ -285,25 +304,6 @@ private: std::mutex m_map_mutex; }; -struct OutgoingPacket -{ - session_t peer_id; - u8 channelnum; - SharedBuffer data; - bool reliable; - bool ack; - - OutgoingPacket(session_t peer_id_, u8 channelnum_, const SharedBuffer &data_, - bool reliable_,bool ack_=false): - peer_id(peer_id_), - channelnum(channelnum_), - data(data_), - reliable(reliable_), - ack(ack_) - { - } -}; - enum ConnectionCommandType{ CONNCMD_NONE, CONNCMD_SERVE, @@ -316,9 +316,13 @@ enum ConnectionCommandType{ CONCMD_CREATE_PEER }; +struct ConnectionCommand; +typedef std::shared_ptr ConnectionCommandPtr; + +// This is very similar to ConnectionEvent struct ConnectionCommand { - enum ConnectionCommandType type = CONNCMD_NONE; + const ConnectionCommandType type; Address address; session_t peer_id = PEER_ID_INEXISTENT; u8 channelnum = 0; @@ -326,48 +330,21 @@ struct ConnectionCommand bool reliable = false; bool raw = false; - ConnectionCommand() = default; - - void serve(Address address_) - { - type = CONNCMD_SERVE; - address = address_; - } - void connect(Address address_) - { - type = CONNCMD_CONNECT; - address = address_; - } - void disconnect() - { - type = CONNCMD_DISCONNECT; - } - void disconnect_peer(session_t peer_id_) - { - type = CONNCMD_DISCONNECT_PEER; - peer_id = peer_id_; - } + DISABLE_CLASS_COPY(ConnectionCommand); - void send(session_t peer_id_, u8 channelnum_, NetworkPacket *pkt, bool reliable_); + static ConnectionCommandPtr serve(Address address); + static ConnectionCommandPtr connect(Address address); + static ConnectionCommandPtr disconnect(); + static ConnectionCommandPtr disconnect_peer(session_t peer_id); + static ConnectionCommandPtr send(session_t peer_id, u8 channelnum, NetworkPacket *pkt, bool reliable); + static ConnectionCommandPtr ack(session_t peer_id, u8 channelnum, const Buffer &data); + static ConnectionCommandPtr createPeer(session_t peer_id, const Buffer &data); - void ack(session_t peer_id_, u8 channelnum_, const Buffer &data_) - { - type = CONCMD_ACK; - peer_id = peer_id_; - channelnum = channelnum_; - data = data_; - reliable = false; - } +private: + ConnectionCommand(ConnectionCommandType type_) : + type(type_) {} - void createPeer(session_t peer_id_, const Buffer &data_) - { - type = CONCMD_CREATE_PEER; - peer_id = peer_id_; - data = data_; - channelnum = 0; - reliable = true; - raw = true; - } + static ConnectionCommandPtr create(ConnectionCommandType type); }; /* maximum window size to use, 0xFFFF is theoretical maximum. don't think about @@ -402,10 +379,10 @@ public: ReliablePacketBuffer outgoing_reliables_sent; //queued reliable packets - std::queue queued_reliables; + std::queue queued_reliables; //queue commands prior splitting to packets - std::deque queued_commands; + std::deque queued_commands; IncomingSplitBuffer incoming_splits; @@ -514,7 +491,7 @@ class Peer { public: friend class PeerHelper; - Peer(Address address_,u16 id_,Connection* connection) : + Peer(Address address_,session_t id_,Connection* connection) : id(id_), m_connection(connection), address(address_), @@ -528,11 +505,11 @@ class Peer { }; // Unique id of the peer - u16 id; + const session_t id; void Drop(); - virtual void PutReliableSendCommand(ConnectionCommand &c, + virtual void PutReliableSendCommand(ConnectionCommandPtr &c, unsigned int max_packet_size) {}; virtual bool getAddress(MTProtocols type, Address& toset) = 0; @@ -549,7 +526,7 @@ class Peer { virtual u16 getNextSplitSequenceNumber(u8 channel) { return 0; }; virtual void setNextSplitSequenceNumber(u8 channel, u16 seqnum) {}; - virtual SharedBuffer addSplitPacket(u8 channel, const BufferedPacket &toadd, + virtual SharedBuffer addSplitPacket(u8 channel, BufferedPacketPtr &toadd, bool reliable) { errorstream << "Peer::addSplitPacket called," @@ -586,7 +563,7 @@ class Peer { bool IncUseCount(); void DecUseCount(); - std::mutex m_exclusive_access_mutex; + mutable std::mutex m_exclusive_access_mutex; bool m_pending_deletion = false; @@ -634,7 +611,7 @@ public: UDPPeer(u16 a_id, Address a_address, Connection* connection); virtual ~UDPPeer() = default; - void PutReliableSendCommand(ConnectionCommand &c, + void PutReliableSendCommand(ConnectionCommandPtr &c, unsigned int max_packet_size); bool getAddress(MTProtocols type, Address& toset); @@ -642,7 +619,7 @@ public: u16 getNextSplitSequenceNumber(u8 channel); void setNextSplitSequenceNumber(u8 channel, u16 seqnum); - SharedBuffer addSplitPacket(u8 channel, const BufferedPacket &toadd, + SharedBuffer addSplitPacket(u8 channel, BufferedPacketPtr &toadd, bool reliable); protected: @@ -671,7 +648,7 @@ private: float resend_timeout = 0.5; bool processReliableSendCommand( - ConnectionCommand &c, + ConnectionCommandPtr &c_ptr, unsigned int max_packet_size); }; @@ -679,7 +656,7 @@ private: Connection */ -enum ConnectionEventType{ +enum ConnectionEventType { CONNEVENT_NONE, CONNEVENT_DATA_RECEIVED, CONNEVENT_PEER_ADDED, @@ -687,56 +664,32 @@ enum ConnectionEventType{ CONNEVENT_BIND_FAILED, }; +struct ConnectionEvent; +typedef std::shared_ptr ConnectionEventPtr; + +// This is very similar to ConnectionCommand struct ConnectionEvent { - enum ConnectionEventType type = CONNEVENT_NONE; + const ConnectionEventType type; session_t peer_id = 0; Buffer data; bool timeout = false; Address address; - ConnectionEvent() = default; + // We don't want to copy "data" + DISABLE_CLASS_COPY(ConnectionEvent); - const char *describe() const - { - switch(type) { - case CONNEVENT_NONE: - return "CONNEVENT_NONE"; - case CONNEVENT_DATA_RECEIVED: - return "CONNEVENT_DATA_RECEIVED"; - case CONNEVENT_PEER_ADDED: - return "CONNEVENT_PEER_ADDED"; - case CONNEVENT_PEER_REMOVED: - return "CONNEVENT_PEER_REMOVED"; - case CONNEVENT_BIND_FAILED: - return "CONNEVENT_BIND_FAILED"; - } - return "Invalid ConnectionEvent"; - } + static ConnectionEventPtr create(ConnectionEventType type); + static ConnectionEventPtr dataReceived(session_t peer_id, const Buffer &data); + static ConnectionEventPtr peerAdded(session_t peer_id, Address address); + static ConnectionEventPtr peerRemoved(session_t peer_id, bool is_timeout, Address address); + static ConnectionEventPtr bindFailed(); - void dataReceived(session_t peer_id_, const Buffer &data_) - { - type = CONNEVENT_DATA_RECEIVED; - peer_id = peer_id_; - data = data_; - } - void peerAdded(session_t peer_id_, Address address_) - { - type = CONNEVENT_PEER_ADDED; - peer_id = peer_id_; - address = address_; - } - void peerRemoved(session_t peer_id_, bool timeout_, Address address_) - { - type = CONNEVENT_PEER_REMOVED; - peer_id = peer_id_; - timeout = timeout_; - address = address_; - } - void bindFailed() - { - type = CONNEVENT_BIND_FAILED; - } + const char *describe() const; + +private: + ConnectionEvent(ConnectionEventType type_) : + type(type_) {} }; class PeerHandler; @@ -752,10 +705,9 @@ public: ~Connection(); /* Interface */ - ConnectionEvent waitEvent(u32 timeout_ms); - // Warning: creates an unnecessary copy, prefer putCommand(T&&) if possible - void putCommand(const ConnectionCommand &c); - void putCommand(ConnectionCommand &&c); + ConnectionEventPtr waitEvent(u32 timeout_ms); + + void putCommand(ConnectionCommandPtr c); void SetTimeoutMs(u32 timeout) { m_bc_receive_timeout = timeout; } void Serve(Address bind_addr); @@ -785,8 +737,6 @@ protected: void sendAck(session_t peer_id, u8 channelnum, u16 seqnum); - void PrintInfo(std::ostream &out); - std::vector getPeerIDs() { MutexAutoLock peerlock(m_peers_mutex); @@ -795,13 +745,11 @@ protected: UDPSocket m_udpSocket; // Command queue: user -> SendThread - MutexedQueue m_command_queue; + MutexedQueue m_command_queue; bool Receive(NetworkPacket *pkt, u32 timeout); - // Warning: creates an unnecessary copy, prefer putEvent(T&&) if possible - void putEvent(const ConnectionEvent &e); - void putEvent(ConnectionEvent &&e); + void putEvent(ConnectionEventPtr e); void TriggerSend(); @@ -811,7 +759,7 @@ protected: } private: // Event queue: ReceiveThread -> user - MutexedQueue m_event_queue; + MutexedQueue m_event_queue; session_t m_peer_id = 0; u32 m_protocol_id; @@ -823,7 +771,7 @@ private: std::unique_ptr m_sendThread; std::unique_ptr m_receiveThread; - std::mutex m_info_mutex; + mutable std::mutex m_info_mutex; // Backwards compatibility PeerHandler *m_bc_peerhandler; diff --git a/src/network/connectionthreads.cpp b/src/network/connectionthreads.cpp index a306ced9b..dca065ae1 100644 --- a/src/network/connectionthreads.cpp +++ b/src/network/connectionthreads.cpp @@ -50,11 +50,11 @@ std::mutex log_conthread_mutex; #define WINDOW_SIZE 5 -static session_t readPeerId(u8 *packetdata) +static session_t readPeerId(const u8 *packetdata) { return readU16(&packetdata[4]); } -static u8 readChannel(u8 *packetdata) +static u8 readChannel(const u8 *packetdata) { return readU8(&packetdata[6]); } @@ -114,9 +114,9 @@ void *ConnectionSendThread::run() } /* translate commands to packets */ - ConnectionCommand c = m_connection->m_command_queue.pop_frontNoEx(0); - while (c.type != CONNCMD_NONE) { - if (c.reliable) + auto c = m_connection->m_command_queue.pop_frontNoEx(0); + while (c && c->type != CONNCMD_NONE) { + if (c->reliable) processReliableCommand(c); else processNonReliableCommand(c); @@ -227,21 +227,21 @@ void ConnectionSendThread::runTimeouts(float dtime) m_iteration_packets_avaialble -= timed_outs.size(); for (const auto &k : timed_outs) { - u8 channelnum = readChannel(*k.data); - u16 seqnum = readU16(&(k.data[BASE_HEADER_SIZE + 1])); + u8 channelnum = readChannel(k->data); + u16 seqnum = k->getSeqnum(); - channel.UpdateBytesLost(k.data.getSize()); + channel.UpdateBytesLost(k->size()); LOG(derr_con << m_connection->getDesc() << "RE-SENDING timed-out RELIABLE to " - << k.address.serializeString() + << k->address.serializeString() << "(t/o=" << resend_timeout << "): " - << "count=" << k.resend_count + << "count=" << k->resend_count << ", channel=" << ((int) channelnum & 0xff) << ", seqnum=" << seqnum << std::endl); - rawSend(k); + rawSend(k.get()); // do not handle rtt here as we can't decide if this packet was // lost or really takes more time to transmit @@ -274,25 +274,24 @@ void ConnectionSendThread::runTimeouts(float dtime) } } -void ConnectionSendThread::rawSend(const BufferedPacket &packet) +void ConnectionSendThread::rawSend(const BufferedPacket *p) { try { - m_connection->m_udpSocket.Send(packet.address, *packet.data, - packet.data.getSize()); + m_connection->m_udpSocket.Send(p->address, p->data, p->size()); LOG(dout_con << m_connection->getDesc() - << " rawSend: " << packet.data.getSize() + << " rawSend: " << p->size() << " bytes sent" << std::endl); } catch (SendFailedException &e) { LOG(derr_con << m_connection->getDesc() << "Connection::rawSend(): SendFailedException: " - << packet.address.serializeString() << std::endl); + << p->address.serializeString() << std::endl); } } -void ConnectionSendThread::sendAsPacketReliable(BufferedPacket &p, Channel *channel) +void ConnectionSendThread::sendAsPacketReliable(BufferedPacketPtr &p, Channel *channel) { try { - p.absolute_send_time = porting::getTimeMs(); + p->absolute_send_time = porting::getTimeMs(); // Buffer the packet channel->outgoing_reliables_sent.insert(p, (channel->readOutgoingSequenceNumber() - MAX_RELIABLE_WINDOW_SIZE) @@ -305,7 +304,7 @@ void ConnectionSendThread::sendAsPacketReliable(BufferedPacket &p, Channel *chan } // Send the packet - rawSend(p); + rawSend(p.get()); } bool ConnectionSendThread::rawSendAsPacket(session_t peer_id, u8 channelnum, @@ -321,11 +320,10 @@ bool ConnectionSendThread::rawSendAsPacket(session_t peer_id, u8 channelnum, Channel *channel = &(dynamic_cast(&peer)->channels[channelnum]); if (reliable) { - bool have_sequence_number_for_raw_packet = true; - u16 seqnum = - channel->getOutgoingSequenceNumber(have_sequence_number_for_raw_packet); + bool have_seqnum = false; + const u16 seqnum = channel->getOutgoingSequenceNumber(have_seqnum); - if (!have_sequence_number_for_raw_packet) + if (!have_seqnum) return false; SharedBuffer reliable = makeReliablePacket(data, seqnum); @@ -333,13 +331,12 @@ bool ConnectionSendThread::rawSendAsPacket(session_t peer_id, u8 channelnum, peer->getAddress(MTP_MINETEST_RELIABLE_UDP, peer_address); // Add base headers and make a packet - BufferedPacket p = con::makePacket(peer_address, reliable, + BufferedPacketPtr p = con::makePacket(peer_address, reliable, m_connection->GetProtocolID(), m_connection->GetPeerID(), channelnum); // first check if our send window is already maxed out - if (channel->outgoing_reliables_sent.size() - < channel->getWindowSize()) { + if (channel->outgoing_reliables_sent.size() < channel->getWindowSize()) { LOG(dout_con << m_connection->getDesc() << " INFO: sending a reliable packet to peer_id " << peer_id << " channel: " << (u32)channelnum @@ -352,19 +349,19 @@ bool ConnectionSendThread::rawSendAsPacket(session_t peer_id, u8 channelnum, << " INFO: queueing reliable packet for peer_id: " << peer_id << " channel: " << (u32)channelnum << " seqnum: " << seqnum << std::endl); - channel->queued_reliables.push(std::move(p)); + channel->queued_reliables.push(p); return false; } Address peer_address; if (peer->getAddress(MTP_UDP, peer_address)) { // Add base headers and make a packet - BufferedPacket p = con::makePacket(peer_address, data, + BufferedPacketPtr p = con::makePacket(peer_address, data, m_connection->GetProtocolID(), m_connection->GetPeerID(), channelnum); // Send the packet - rawSend(p); + rawSend(p.get()); return true; } @@ -374,11 +371,11 @@ bool ConnectionSendThread::rawSendAsPacket(session_t peer_id, u8 channelnum, return false; } -void ConnectionSendThread::processReliableCommand(ConnectionCommand &c) +void ConnectionSendThread::processReliableCommand(ConnectionCommandPtr &c) { - assert(c.reliable); // Pre-condition + assert(c->reliable); // Pre-condition - switch (c.type) { + switch (c->type) { case CONNCMD_NONE: LOG(dout_con << m_connection->getDesc() << "UDP processing reliable CONNCMD_NONE" << std::endl); @@ -399,7 +396,7 @@ void ConnectionSendThread::processReliableCommand(ConnectionCommand &c) case CONCMD_CREATE_PEER: LOG(dout_con << m_connection->getDesc() << "UDP processing reliable CONCMD_CREATE_PEER" << std::endl); - if (!rawSendAsPacket(c.peer_id, c.channelnum, c.data, c.reliable)) { + if (!rawSendAsPacket(c->peer_id, c->channelnum, c->data, c->reliable)) { /* put to queue if we couldn't send it immediately */ sendReliable(c); } @@ -412,13 +409,14 @@ void ConnectionSendThread::processReliableCommand(ConnectionCommand &c) FATAL_ERROR("Got command that shouldn't be reliable as reliable command"); default: LOG(dout_con << m_connection->getDesc() - << " Invalid reliable command type: " << c.type << std::endl); + << " Invalid reliable command type: " << c->type << std::endl); } } -void ConnectionSendThread::processNonReliableCommand(ConnectionCommand &c) +void ConnectionSendThread::processNonReliableCommand(ConnectionCommandPtr &c_ptr) { + const ConnectionCommand &c = *c_ptr; assert(!c.reliable); // Pre-condition switch (c.type) { @@ -480,9 +478,7 @@ void ConnectionSendThread::serve(Address bind_address) } catch (SocketException &e) { // Create event - ConnectionEvent ce; - ce.bindFailed(); - m_connection->putEvent(ce); + m_connection->putEvent(ConnectionEvent::bindFailed()); } } @@ -495,9 +491,7 @@ void ConnectionSendThread::connect(Address address) UDPPeer *peer = m_connection->createServerPeer(address); // Create event - ConnectionEvent e; - e.peerAdded(peer->id, peer->address); - m_connection->putEvent(e); + m_connection->putEvent(ConnectionEvent::peerAdded(peer->id, peer->address)); Address bind_addr; @@ -586,9 +580,9 @@ void ConnectionSendThread::send(session_t peer_id, u8 channelnum, } } -void ConnectionSendThread::sendReliable(ConnectionCommand &c) +void ConnectionSendThread::sendReliable(ConnectionCommandPtr &c) { - PeerHelper peer = m_connection->getPeerNoEx(c.peer_id); + PeerHelper peer = m_connection->getPeerNoEx(c->peer_id); if (!peer) return; @@ -604,7 +598,7 @@ void ConnectionSendThread::sendToAll(u8 channelnum, const SharedBuffer &data } } -void ConnectionSendThread::sendToAllReliable(ConnectionCommand &c) +void ConnectionSendThread::sendToAllReliable(ConnectionCommandPtr &c) { std::vector peerids = m_connection->getPeerIDs(); @@ -663,8 +657,12 @@ void ConnectionSendThread::sendPackets(float dtime) // first send queued reliable packets for all peers (if possible) for (unsigned int i = 0; i < CHANNEL_COUNT; i++) { Channel &channel = udpPeer->channels[i]; - u16 next_to_ack = 0; + // Reduces logging verbosity + if (channel.queued_reliables.empty()) + continue; + + u16 next_to_ack = 0; channel.outgoing_reliables_sent.getFirstSeqnum(next_to_ack); u16 next_to_receive = 0; channel.incoming_reliables.getFirstSeqnum(next_to_receive); @@ -694,13 +692,13 @@ void ConnectionSendThread::sendPackets(float dtime) channel.outgoing_reliables_sent.size() < channel.getWindowSize() && peer->m_increment_packets_remaining > 0) { - BufferedPacket p = std::move(channel.queued_reliables.front()); + BufferedPacketPtr p = channel.queued_reliables.front(); channel.queued_reliables.pop(); LOG(dout_con << m_connection->getDesc() << " INFO: sending a queued reliable packet " << " channel: " << i - << ", seqnum: " << readU16(&p.data[BASE_HEADER_SIZE + 1]) + << ", seqnum: " << p->getSeqnum() << std::endl); sendAsPacketReliable(p, &channel); @@ -881,17 +879,14 @@ void ConnectionReceiveThread::receive(SharedBuffer &packetdata, try { // First, see if there any buffered packets we can process now if (packet_queued) { - bool data_left = true; session_t peer_id; SharedBuffer resultdata; - while (data_left) { + while (true) { try { - data_left = getFromBuffers(peer_id, resultdata); - if (data_left) { - ConnectionEvent e; - e.dataReceived(peer_id, resultdata); - m_connection->putEvent(std::move(e)); - } + if (!getFromBuffers(peer_id, resultdata)) + break; + + m_connection->putEvent(ConnectionEvent::dataReceived(peer_id, resultdata)); } catch (ProcessedSilentlyException &e) { /* try reading again */ @@ -908,7 +903,7 @@ void ConnectionReceiveThread::receive(SharedBuffer &packetdata, return; if ((received_size < BASE_HEADER_SIZE) || - (readU32(&packetdata[0]) != m_connection->GetProtocolID())) { + (readU32(&packetdata[0]) != m_connection->GetProtocolID())) { LOG(derr_con << m_connection->getDesc() << "Receive(): Invalid incoming packet, " << "size: " << received_size @@ -999,9 +994,7 @@ void ConnectionReceiveThread::receive(SharedBuffer &packetdata, << ", channel: " << (u32)channelnum << ", returned " << resultdata.getSize() << " bytes" << std::endl); - ConnectionEvent e; - e.dataReceived(peer_id, resultdata); - m_connection->putEvent(std::move(e)); + m_connection->putEvent(ConnectionEvent::dataReceived(peer_id, resultdata)); } catch (ProcessedSilentlyException &e) { } @@ -1026,10 +1019,11 @@ bool ConnectionReceiveThread::getFromBuffers(session_t &peer_id, SharedBuffer(&peer) == 0) + UDPPeer *p = dynamic_cast(&peer); + if (!p) continue; - for (Channel &channel : (dynamic_cast(&peer))->channels) { + for (Channel &channel : p->channels) { if (checkIncomingBuffers(&channel, peer_id, dst)) { return true; } @@ -1042,32 +1036,34 @@ bool ConnectionReceiveThread::checkIncomingBuffers(Channel *channel, session_t &peer_id, SharedBuffer &dst) { u16 firstseqnum = 0; - if (channel->incoming_reliables.getFirstSeqnum(firstseqnum)) { - if (firstseqnum == channel->readNextIncomingSeqNum()) { - BufferedPacket p = channel->incoming_reliables.popFirst(); - peer_id = readPeerId(*p.data); - u8 channelnum = readChannel(*p.data); - u16 seqnum = readU16(&p.data[BASE_HEADER_SIZE + 1]); + if (!channel->incoming_reliables.getFirstSeqnum(firstseqnum)) + return false; - LOG(dout_con << m_connection->getDesc() - << "UNBUFFERING TYPE_RELIABLE" - << " seqnum=" << seqnum - << " peer_id=" << peer_id - << " channel=" << ((int) channelnum & 0xff) - << std::endl); + if (firstseqnum != channel->readNextIncomingSeqNum()) + return false; - channel->incNextIncomingSeqNum(); + BufferedPacketPtr p = channel->incoming_reliables.popFirst(); - u32 headers_size = BASE_HEADER_SIZE + RELIABLE_HEADER_SIZE; - // Get out the inside packet and re-process it - SharedBuffer payload(p.data.getSize() - headers_size); - memcpy(*payload, &p.data[headers_size], payload.getSize()); + peer_id = readPeerId(p->data); // Carried over to caller function + u8 channelnum = readChannel(p->data); + u16 seqnum = p->getSeqnum(); - dst = processPacket(channel, payload, peer_id, channelnum, true); - return true; - } - } - return false; + LOG(dout_con << m_connection->getDesc() + << "UNBUFFERING TYPE_RELIABLE" + << " seqnum=" << seqnum + << " peer_id=" << peer_id + << " channel=" << ((int) channelnum & 0xff) + << std::endl); + + channel->incNextIncomingSeqNum(); + + u32 headers_size = BASE_HEADER_SIZE + RELIABLE_HEADER_SIZE; + // Get out the inside packet and re-process it + SharedBuffer payload(p->size() - headers_size); + memcpy(*payload, &p->data[headers_size], payload.getSize()); + + dst = processPacket(channel, payload, peer_id, channelnum, true); + return true; } SharedBuffer ConnectionReceiveThread::processPacket(Channel *channel, @@ -1115,7 +1111,7 @@ SharedBuffer ConnectionReceiveThread::handlePacketType_Control(Channel *chan if (packetdata.getSize() < 2) throw InvalidIncomingDataException("packetdata.getSize() < 2"); - u8 controltype = readU8(&(packetdata[1])); + ControlType controltype = (ControlType)readU8(&(packetdata[1])); if (controltype == CONTROLTYPE_ACK) { assert(channel != NULL); @@ -1131,7 +1127,7 @@ SharedBuffer ConnectionReceiveThread::handlePacketType_Control(Channel *chan << seqnum << " ]" << std::endl); try { - BufferedPacket p = channel->outgoing_reliables_sent.popSeqnum(seqnum); + BufferedPacketPtr p = channel->outgoing_reliables_sent.popSeqnum(seqnum); // the rtt calculation will be a bit off for re-sent packets but that's okay { @@ -1140,14 +1136,14 @@ SharedBuffer ConnectionReceiveThread::handlePacketType_Control(Channel *chan // a overflow is quite unlikely but as it'd result in major // rtt miscalculation we handle it here - if (current_time > p.absolute_send_time) { - float rtt = (current_time - p.absolute_send_time) / 1000.0; + if (current_time > p->absolute_send_time) { + float rtt = (current_time - p->absolute_send_time) / 1000.0; // Let peer calculate stuff according to it // (avg_rtt and resend_timeout) dynamic_cast(peer)->reportRTT(rtt); - } else if (p.totaltime > 0) { - float rtt = p.totaltime; + } else if (p->totaltime > 0) { + float rtt = p->totaltime; // Let peer calculate stuff according to it // (avg_rtt and resend_timeout) @@ -1156,7 +1152,7 @@ SharedBuffer ConnectionReceiveThread::handlePacketType_Control(Channel *chan } // put bytes for max bandwidth calculation - channel->UpdateBytesSent(p.data.getSize(), 1); + channel->UpdateBytesSent(p->size(), 1); if (channel->outgoing_reliables_sent.size() == 0) m_connection->TriggerSend(); } catch (NotFoundException &e) { @@ -1204,7 +1200,7 @@ SharedBuffer ConnectionReceiveThread::handlePacketType_Control(Channel *chan throw ProcessedSilentlyException("Got a DISCO"); } else { LOG(derr_con << m_connection->getDesc() - << "INVALID TYPE_CONTROL: invalid controltype=" + << "INVALID controltype=" << ((int) controltype & 0xff) << std::endl); throw InvalidIncomingDataException("Invalid control type"); } @@ -1232,7 +1228,7 @@ SharedBuffer ConnectionReceiveThread::handlePacketType_Split(Channel *channe if (peer->getAddress(MTP_UDP, peer_address)) { // We have to create a packet again for buffering // This isn't actually too bad an idea. - BufferedPacket packet = makePacket(peer_address, + BufferedPacketPtr packet = con::makePacket(peer_address, packetdata, m_connection->GetProtocolID(), peer->id, @@ -1267,7 +1263,7 @@ SharedBuffer ConnectionReceiveThread::handlePacketType_Reliable(Channel *cha if (packetdata.getSize() < RELIABLE_HEADER_SIZE) throw InvalidIncomingDataException("packetdata.getSize() < RELIABLE_HEADER_SIZE"); - u16 seqnum = readU16(&packetdata[1]); + const u16 seqnum = readU16(&packetdata[1]); bool is_future_packet = false; bool is_old_packet = false; @@ -1311,7 +1307,7 @@ SharedBuffer ConnectionReceiveThread::handlePacketType_Reliable(Channel *cha // This one comes later, buffer it. // Actually we have to make a packet to buffer one. // Well, we have all the ingredients, so just do it. - BufferedPacket packet = con::makePacket( + BufferedPacketPtr packet = con::makePacket( peer_address, packetdata, m_connection->GetProtocolID(), @@ -1328,9 +1324,7 @@ SharedBuffer ConnectionReceiveThread::handlePacketType_Reliable(Channel *cha throw ProcessedQueued("Buffered future reliable packet"); } catch (AlreadyExistsException &e) { } catch (IncomingDataCorruption &e) { - ConnectionCommand discon; - discon.disconnect_peer(peer->id); - m_connection->putCommand(discon); + m_connection->putCommand(ConnectionCommand::disconnect_peer(peer->id)); LOG(derr_con << m_connection->getDesc() << "INVALID, TYPE_RELIABLE peer_id: " << peer->id @@ -1351,7 +1345,7 @@ SharedBuffer ConnectionReceiveThread::handlePacketType_Reliable(Channel *cha u16 queued_seqnum = 0; if (channel->incoming_reliables.getFirstSeqnum(queued_seqnum)) { if (queued_seqnum == seqnum) { - BufferedPacket queued_packet = channel->incoming_reliables.popFirst(); + BufferedPacketPtr queued_packet = channel->incoming_reliables.popFirst(); /** TODO find a way to verify the new against the old packet */ } } diff --git a/src/network/connectionthreads.h b/src/network/connectionthreads.h index 612407c3b..c2e2dae12 100644 --- a/src/network/connectionthreads.h +++ b/src/network/connectionthreads.h @@ -29,6 +29,25 @@ namespace con class Connection; +struct OutgoingPacket +{ + session_t peer_id; + u8 channelnum; + SharedBuffer data; + bool reliable; + bool ack; + + OutgoingPacket(session_t peer_id_, u8 channelnum_, const SharedBuffer &data_, + bool reliable_,bool ack_=false): + peer_id(peer_id_), + channelnum(channelnum_), + data(data_), + reliable(reliable_), + ack(ack_) + { + } +}; + class ConnectionSendThread : public Thread { @@ -51,27 +70,27 @@ public: private: void runTimeouts(float dtime); - void rawSend(const BufferedPacket &packet); + void rawSend(const BufferedPacket *p); bool rawSendAsPacket(session_t peer_id, u8 channelnum, const SharedBuffer &data, bool reliable); - void processReliableCommand(ConnectionCommand &c); - void processNonReliableCommand(ConnectionCommand &c); + void processReliableCommand(ConnectionCommandPtr &c); + void processNonReliableCommand(ConnectionCommandPtr &c); void serve(Address bind_address); void connect(Address address); void disconnect(); void disconnect_peer(session_t peer_id); void send(session_t peer_id, u8 channelnum, const SharedBuffer &data); - void sendReliable(ConnectionCommand &c); + void sendReliable(ConnectionCommandPtr &c); void sendToAll(u8 channelnum, const SharedBuffer &data); - void sendToAllReliable(ConnectionCommand &c); + void sendToAllReliable(ConnectionCommandPtr &c); void sendPackets(float dtime); void sendAsPacket(session_t peer_id, u8 channelnum, const SharedBuffer &data, bool ack = false); - void sendAsPacketReliable(BufferedPacket &p, Channel *channel); + void sendAsPacketReliable(BufferedPacketPtr &p, Channel *channel); bool packetsQueued(); diff --git a/src/unittest/test_connection.cpp b/src/unittest/test_connection.cpp index 23b7e9105..04fea90d6 100644 --- a/src/unittest/test_connection.cpp +++ b/src/unittest/test_connection.cpp @@ -124,7 +124,7 @@ void TestConnection::testHelpers() Address a(127,0,0,1, 10); const u16 seqnum = 34352; - con::BufferedPacket p1 = con::makePacket(a, data1, + con::BufferedPacketPtr p1 = con::makePacket(a, data1, proto_id, peer_id, channel); /* We should now have a packet with this data: @@ -135,10 +135,10 @@ void TestConnection::testHelpers() Data: [7] u8 data1[0] */ - UASSERT(readU32(&p1.data[0]) == proto_id); - UASSERT(readU16(&p1.data[4]) == peer_id); - UASSERT(readU8(&p1.data[6]) == channel); - UASSERT(readU8(&p1.data[7]) == data1[0]); + UASSERT(readU32(&p1->data[0]) == proto_id); + UASSERT(readU16(&p1->data[4]) == peer_id); + UASSERT(readU8(&p1->data[6]) == channel); + UASSERT(readU8(&p1->data[7]) == data1[0]); //infostream<<"initial data1[0]="<<((u32)data1[0]&0xff)< +#include // std::shared_ptr + + +template class ConstSharedPtr { +public: + ConstSharedPtr(T *ptr) : ptr(ptr) {} + ConstSharedPtr(const std::shared_ptr &ptr) : ptr(ptr) {} + + const T* get() const noexcept { return ptr.get(); } + const T& operator*() const noexcept { return *ptr.get(); } + const T* operator->() const noexcept { return ptr.get(); } + +private: + std::shared_ptr ptr; +}; template class Buffer @@ -40,17 +55,11 @@ public: else data = NULL; } - Buffer(const Buffer &buffer) - { - m_size = buffer.m_size; - if(m_size != 0) - { - data = new T[buffer.m_size]; - memcpy(data, buffer.data, buffer.m_size); - } - else - data = NULL; - } + + // Disable class copy + Buffer(const Buffer &) = delete; + Buffer &operator=(const Buffer &) = delete; + Buffer(Buffer &&buffer) { m_size = buffer.m_size; @@ -81,21 +90,6 @@ public: drop(); } - Buffer& operator=(const Buffer &buffer) - { - if(this == &buffer) - return *this; - drop(); - m_size = buffer.m_size; - if(m_size != 0) - { - data = new T[buffer.m_size]; - memcpy(data, buffer.data, buffer.m_size); - } - else - data = NULL; - return *this; - } Buffer& operator=(Buffer &&buffer) { if(this == &buffer) @@ -113,6 +107,18 @@ public: return *this; } + void copyTo(Buffer &buffer) const + { + buffer.drop(); + buffer.m_size = m_size; + if (m_size != 0) { + buffer.data = new T[m_size]; + memcpy(buffer.data, data, m_size); + } else { + buffer.data = nullptr; + } + } + T & operator[](unsigned int i) const { return data[i]; -- cgit v1.2.3 From 7f6306ca964ac5b9245c433e3b688c5d4ee08c35 Mon Sep 17 00:00:00 2001 From: JosiahWI <41302989+JosiahWI@users.noreply.github.com> Date: Tue, 28 Dec 2021 07:05:49 -0600 Subject: Restore GCC 5 compatibility (#11778) --- src/client/client.h | 2 +- src/network/clientpackethandler.cpp | 3 ++- src/util/png.cpp | 8 ++++---- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'src/network') diff --git a/src/client/client.h b/src/client/client.h index b92b456f4..bae40f389 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -548,7 +548,7 @@ private: // Set of media filenames pushed by server at runtime std::unordered_set m_media_pushed_files; // Pending downloads of dynamic media (key: token) - std::vector>> m_pending_media_downloads; + std::vector>> m_pending_media_downloads; // time_of_day speed approximation for old protocol bool m_time_of_day_set = false; diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index d20a80fb7..6aececa7f 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -43,6 +43,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "tileanimation.h" #include "gettext.h" #include "skyparams.h" +#include void Client::handleCommand_Deprecated(NetworkPacket* pkt) { @@ -1559,7 +1560,7 @@ void Client::handleCommand_MediaPush(NetworkPacket *pkt) m_media_pushed_files.insert(filename); // create a downloader for this file - auto downloader = new SingleMediaDownloader(cached); + auto downloader(std::make_shared(cached)); m_pending_media_downloads.emplace_back(token, downloader); downloader->addFile(filename, raw_hash); for (const auto &baseurl : m_remote_media_servers) diff --git a/src/util/png.cpp b/src/util/png.cpp index 7ac2e94a1..698cbc9a5 100755 --- a/src/util/png.cpp +++ b/src/util/png.cpp @@ -37,11 +37,11 @@ static void writeChunk(std::ostringstream &target, const std::string &chunk_str) std::string encodePNG(const u8 *data, u32 width, u32 height, s32 compression) { - auto file = std::ostringstream(std::ios::binary); + std::ostringstream file(std::ios::binary); file << "\x89PNG\r\n\x1a\n"; { - auto IHDR = std::ostringstream(std::ios::binary); + std::ostringstream IHDR(std::ios::binary); IHDR << "IHDR"; writeU32(IHDR, width); writeU32(IHDR, height); @@ -51,9 +51,9 @@ std::string encodePNG(const u8 *data, u32 width, u32 height, s32 compression) } { - auto IDAT = std::ostringstream(std::ios::binary); + std::ostringstream IDAT(std::ios::binary); IDAT << "IDAT"; - auto scanlines = std::ostringstream(std::ios::binary); + std::ostringstream scanlines(std::ios::binary); for(u32 i = 0; i < height; i++) { scanlines.write("\x00", 1); // Null predictor scanlines.write((const char*) data + width * 4 * i, width * 4); -- cgit v1.2.3 From 0fa54531d48eb2fcd09377a6fb8e7c81e09ada63 Mon Sep 17 00:00:00 2001 From: savilli <78875209+savilli@users.noreply.github.com> Date: Tue, 28 Dec 2021 16:08:21 +0300 Subject: Fix check that denies new clients from a singleplayer session --- src/network/serverpackethandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/network') diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index c1ddb5005..e5a1bab1e 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -86,7 +86,7 @@ void Server::handleCommand_Init(NetworkPacket* pkt) // Do not allow multiple players in simple singleplayer mode. // This isn't a perfect way to do it, but will suffice for now - if (m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1) { + if (m_simple_singleplayer_mode && !m_clients.getClientIDs().empty()) { infostream << "Server: Not allowing another client (" << addr_s << ") to connect in simple singleplayer mode" << std::endl; DenyAccess(peer_id, SERVER_ACCESSDENIED_SINGLEPLAYER); -- cgit v1.2.3 From 0ea8df4d64959a7c7ec4e55b4895d6b16dad3000 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Wed, 29 Dec 2021 23:01:26 +0100 Subject: Socket-related cleanups Improve error handling on Windows and reduce the size of the `Address` class --- src/client/game.cpp | 1 - src/filesys.cpp | 2 + src/network/address.cpp | 119 ++++++++++++++++--------------------------- src/network/address.h | 35 +++++++------ src/network/socket.cpp | 74 +++++++++++++-------------- src/network/socket.h | 14 ----- src/server.cpp | 5 +- src/unittest/test_socket.cpp | 18 +++---- 8 files changed, 113 insertions(+), 155 deletions(-) (limited to 'src/network') diff --git a/src/client/game.cpp b/src/client/game.cpp index 853a52ecf..f62d26e8f 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1444,7 +1444,6 @@ bool Game::connectToServer(const GameStartData &start_data, connect_address.Resolve(start_data.address.c_str()); if (connect_address.isZero()) { // i.e. INADDR_ANY, IN6ADDR_ANY - //connect_address.Resolve("localhost"); if (connect_address.isIPv6()) { IPv6AddressBytes addr_bytes; addr_bytes.bytes[15] = 1; diff --git a/src/filesys.cpp b/src/filesys.cpp index 60090c801..ea00def6a 100644 --- a/src/filesys.cpp +++ b/src/filesys.cpp @@ -41,7 +41,9 @@ namespace fs * Windows * ***********/ +#ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0501 +#endif #include #include #include diff --git a/src/network/address.cpp b/src/network/address.cpp index 05678aa62..90e561802 100644 --- a/src/network/address.cpp +++ b/src/network/address.cpp @@ -87,38 +87,31 @@ Address::Address(const IPv6AddressBytes *ipv6_bytes, u16 port) setPort(port); } -// Equality (address family, address and port must be equal) -bool Address::operator==(const Address &address) +// Equality (address family, IP and port must be equal) +bool Address::operator==(const Address &other) { - if (address.m_addr_family != m_addr_family || address.m_port != m_port) + if (other.m_addr_family != m_addr_family || other.m_port != m_port) return false; if (m_addr_family == AF_INET) { - return m_address.ipv4.sin_addr.s_addr == - address.m_address.ipv4.sin_addr.s_addr; + return m_address.ipv4.s_addr == other.m_address.ipv4.s_addr; } if (m_addr_family == AF_INET6) { - return memcmp(m_address.ipv6.sin6_addr.s6_addr, - address.m_address.ipv6.sin6_addr.s6_addr, 16) == 0; + return memcmp(m_address.ipv6.s6_addr, + other.m_address.ipv6.s6_addr, 16) == 0; } return false; } -bool Address::operator!=(const Address &address) -{ - return !(*this == address); -} - void Address::Resolve(const char *name) { if (!name || name[0] == 0) { - if (m_addr_family == AF_INET) { - setAddress((u32)0); - } else if (m_addr_family == AF_INET6) { - setAddress((IPv6AddressBytes *)0); - } + if (m_addr_family == AF_INET) + setAddress(static_cast(0)); + else if (m_addr_family == AF_INET6) + setAddress(static_cast(nullptr)); return; } @@ -126,9 +119,6 @@ void Address::Resolve(const char *name) memset(&hints, 0, sizeof(hints)); // Setup hints - hints.ai_socktype = 0; - hints.ai_protocol = 0; - hints.ai_flags = 0; if (g_settings->getBool("enable_ipv6")) { // AF_UNSPEC allows both IPv6 and IPv4 addresses to be returned hints.ai_family = AF_UNSPEC; @@ -145,14 +135,13 @@ void Address::Resolve(const char *name) if (resolved->ai_family == AF_INET) { struct sockaddr_in *t = (struct sockaddr_in *)resolved->ai_addr; m_addr_family = AF_INET; - m_address.ipv4 = *t; + m_address.ipv4 = t->sin_addr; } else if (resolved->ai_family == AF_INET6) { struct sockaddr_in6 *t = (struct sockaddr_in6 *)resolved->ai_addr; m_addr_family = AF_INET6; - m_address.ipv6 = *t; + m_address.ipv6 = t->sin6_addr; } else { - freeaddrinfo(resolved); - throw ResolveError(""); + m_addr_family = 0; } freeaddrinfo(resolved); } @@ -163,47 +152,37 @@ std::string Address::serializeString() const // windows XP doesnt have inet_ntop, maybe use better func #ifdef _WIN32 if (m_addr_family == AF_INET) { - u8 a, b, c, d; - u32 addr; - addr = ntohl(m_address.ipv4.sin_addr.s_addr); - a = (addr & 0xFF000000) >> 24; - b = (addr & 0x00FF0000) >> 16; - c = (addr & 0x0000FF00) >> 8; - d = (addr & 0x000000FF); - return itos(a) + "." + itos(b) + "." + itos(c) + "." + itos(d); + return inet_ntoa(m_address.ipv4); } else if (m_addr_family == AF_INET6) { std::ostringstream os; + os << std::hex; for (int i = 0; i < 16; i += 2) { - u16 section = (m_address.ipv6.sin6_addr.s6_addr[i] << 8) | - (m_address.ipv6.sin6_addr.s6_addr[i + 1]); - os << std::hex << section; + u16 section = (m_address.ipv6.s6_addr[i] << 8) | + (m_address.ipv6.s6_addr[i + 1]); + os << section; if (i < 14) os << ":"; } return os.str(); - } else - return std::string(""); + } else { + return ""; + } #else char str[INET6_ADDRSTRLEN]; - if (inet_ntop(m_addr_family, - (m_addr_family == AF_INET) - ? (void *)&(m_address.ipv4.sin_addr) - : (void *)&(m_address.ipv6.sin6_addr), - str, INET6_ADDRSTRLEN) == NULL) { - return std::string(""); - } - return std::string(str); + if (inet_ntop(m_addr_family, (void*) &m_address, str, sizeof(str)) == nullptr) + return ""; + return str; #endif } -struct sockaddr_in Address::getAddress() const +struct in_addr Address::getAddress() const { - return m_address.ipv4; // NOTE: NO PORT INCLUDED, use getPort() + return m_address.ipv4; } -struct sockaddr_in6 Address::getAddress6() const +struct in6_addr Address::getAddress6() const { - return m_address.ipv6; // NOTE: NO PORT INCLUDED, use getPort() + return m_address.ipv6; } u16 Address::getPort() const @@ -211,52 +190,39 @@ u16 Address::getPort() const return m_port; } -int Address::getFamily() const -{ - return m_addr_family; -} - -bool Address::isIPv6() const -{ - return m_addr_family == AF_INET6; -} - bool Address::isZero() const { if (m_addr_family == AF_INET) { - return m_address.ipv4.sin_addr.s_addr == 0; + return m_address.ipv4.s_addr == 0; } if (m_addr_family == AF_INET6) { static const char zero[16] = {0}; - return memcmp(m_address.ipv6.sin6_addr.s6_addr, zero, 16) == 0; + return memcmp(m_address.ipv6.s6_addr, zero, 16) == 0; } + return false; } void Address::setAddress(u32 address) { m_addr_family = AF_INET; - m_address.ipv4.sin_family = AF_INET; - m_address.ipv4.sin_addr.s_addr = htonl(address); + m_address.ipv4.s_addr = htonl(address); } void Address::setAddress(u8 a, u8 b, u8 c, u8 d) { - m_addr_family = AF_INET; - m_address.ipv4.sin_family = AF_INET; - u32 addr = htonl((a << 24) | (b << 16) | (c << 8) | d); - m_address.ipv4.sin_addr.s_addr = addr; + u32 addr = (a << 24) | (b << 16) | (c << 8) | d; + setAddress(addr); } void Address::setAddress(const IPv6AddressBytes *ipv6_bytes) { m_addr_family = AF_INET6; - m_address.ipv6.sin6_family = AF_INET6; if (ipv6_bytes) - memcpy(m_address.ipv6.sin6_addr.s6_addr, ipv6_bytes->bytes, 16); + memcpy(m_address.ipv6.s6_addr, ipv6_bytes->bytes, 16); else - memset(m_address.ipv6.sin6_addr.s6_addr, 0, 16); + memset(m_address.ipv6.s6_addr, 0, 16); } void Address::setPort(u16 port) @@ -268,23 +234,26 @@ void Address::print(std::ostream *s) const { if (m_addr_family == AF_INET6) *s << "[" << serializeString() << "]:" << m_port; - else + else if (m_addr_family == AF_INET) *s << serializeString() << ":" << m_port; + else + *s << "(undefined)"; } bool Address::isLocalhost() const { if (isIPv6()) { - static const unsigned char localhost_bytes[] = { + static const u8 localhost_bytes[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; - static const unsigned char mapped_ipv4_localhost[] = { + static const u8 mapped_ipv4_localhost[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 0}; - auto addr = m_address.ipv6.sin6_addr.s6_addr; + auto addr = m_address.ipv6.s6_addr; return memcmp(addr, localhost_bytes, 16) == 0 || memcmp(addr, mapped_ipv4_localhost, 13) == 0; } - return (m_address.ipv4.sin_addr.s_addr & 0xFF) == 0x7f; + auto addr = ntohl(m_address.ipv4.s_addr); + return (addr >> 24) == 0x7f; } diff --git a/src/network/address.h b/src/network/address.h index 4329c84a8..c2f5f2eef 100644 --- a/src/network/address.h +++ b/src/network/address.h @@ -36,9 +36,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "irrlichttypes.h" #include "networkexceptions.h" -class IPv6AddressBytes +struct IPv6AddressBytes { -public: u8 bytes[16]; IPv6AddressBytes() { memset(bytes, 0, 16); } }; @@ -50,30 +49,34 @@ public: Address(u32 address, u16 port); Address(u8 a, u8 b, u8 c, u8 d, u16 port); Address(const IPv6AddressBytes *ipv6_bytes, u16 port); + bool operator==(const Address &address); - bool operator!=(const Address &address); + bool operator!=(const Address &address) { return !(*this == address); } + + struct in_addr getAddress() const; + struct in6_addr getAddress6() const; + u16 getPort() const; + int getFamily() const { return m_addr_family; } + bool isIPv6() const { return m_addr_family == AF_INET6; } + bool isZero() const; + void print(std::ostream *s) const; + std::string serializeString() const; + bool isLocalhost() const; + // Resolve() may throw ResolveError (address is unchanged in this case) void Resolve(const char *name); - struct sockaddr_in getAddress() const; - unsigned short getPort() const; + void setAddress(u32 address); void setAddress(u8 a, u8 b, u8 c, u8 d); void setAddress(const IPv6AddressBytes *ipv6_bytes); - struct sockaddr_in6 getAddress6() const; - int getFamily() const; - bool isIPv6() const; - bool isZero() const; - void setPort(unsigned short port); - void print(std::ostream *s) const; - std::string serializeString() const; - bool isLocalhost() const; + void setPort(u16 port); private: - unsigned int m_addr_family = 0; + unsigned short m_addr_family = 0; union { - struct sockaddr_in ipv4; - struct sockaddr_in6 ipv6; + struct in_addr ipv4; + struct in6_addr ipv6; } m_address; u16 m_port = 0; // Port is separate from sockaddr structures }; diff --git a/src/network/socket.cpp b/src/network/socket.cpp index 94a9f4180..0bb7ea234 100644 --- a/src/network/socket.cpp +++ b/src/network/socket.cpp @@ -23,14 +23,11 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include -#include -#include #include #include "util/string.h" #include "util/numeric.h" #include "constants.h" #include "debug.h" -#include "settings.h" #include "log.h" #ifdef _WIN32 @@ -42,9 +39,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #define LAST_SOCKET_ERR() WSAGetLastError() -typedef SOCKET socket_t; +#define SOCKET_ERR_STR(e) itos(e) typedef int socklen_t; #else +#include #include #include #include @@ -53,7 +51,7 @@ typedef int socklen_t; #include #include #define LAST_SOCKET_ERR() (errno) -typedef int socket_t; +#define SOCKET_ERR_STR(e) strerror(e) #endif // Set to true to enable verbose debug output @@ -113,7 +111,7 @@ bool UDPSocket::init(bool ipv6, bool noExceptions) } throw SocketException(std::string("Failed to create socket: error ") + - itos(LAST_SOCKET_ERR())); + SOCKET_ERR_STR(LAST_SOCKET_ERR())); } setTimeoutMs(0); @@ -153,40 +151,40 @@ void UDPSocket::Bind(Address addr) } if (addr.getFamily() != m_addr_family) { - static const char *errmsg = + const char *errmsg = "Socket and bind address families do not match"; errorstream << "Bind failed: " << errmsg << std::endl; throw SocketException(errmsg); } + int ret = 0; + if (m_addr_family == AF_INET6) { struct sockaddr_in6 address; memset(&address, 0, sizeof(address)); - address = addr.getAddress6(); address.sin6_family = AF_INET6; + address.sin6_addr = addr.getAddress6(); address.sin6_port = htons(addr.getPort()); - if (bind(m_handle, (const struct sockaddr *)&address, - sizeof(struct sockaddr_in6)) < 0) { - dstream << (int)m_handle << ": Bind failed: " << strerror(errno) - << std::endl; - throw SocketException("Failed to bind socket"); - } + ret = bind(m_handle, (const struct sockaddr *) &address, + sizeof(struct sockaddr_in6)); } else { struct sockaddr_in address; memset(&address, 0, sizeof(address)); - address = addr.getAddress(); address.sin_family = AF_INET; + address.sin_addr = addr.getAddress(); address.sin_port = htons(addr.getPort()); - if (bind(m_handle, (const struct sockaddr *)&address, - sizeof(struct sockaddr_in)) < 0) { - dstream << (int)m_handle << ": Bind failed: " << strerror(errno) - << std::endl; - throw SocketException("Failed to bind socket"); - } + ret = bind(m_handle, (const struct sockaddr *) &address, + sizeof(struct sockaddr_in)); + } + + if (ret < 0) { + dstream << (int)m_handle << ": Bind failed: " + << SOCKET_ERR_STR(LAST_SOCKET_ERR()) << std::endl; + throw SocketException("Failed to bind socket"); } } @@ -233,13 +231,19 @@ void UDPSocket::Send(const Address &destination, const void *data, int size) int sent; if (m_addr_family == AF_INET6) { - struct sockaddr_in6 address = destination.getAddress6(); + struct sockaddr_in6 address = {0}; + address.sin6_family = AF_INET6; + address.sin6_addr = destination.getAddress6(); address.sin6_port = htons(destination.getPort()); + sent = sendto(m_handle, (const char *)data, size, 0, (struct sockaddr *)&address, sizeof(struct sockaddr_in6)); } else { - struct sockaddr_in address = destination.getAddress(); + struct sockaddr_in address = {0}; + address.sin_family = AF_INET; + address.sin_addr = destination.getAddress(); address.sin_port = htons(destination.getPort()); + sent = sendto(m_handle, (const char *)data, size, 0, (struct sockaddr *)&address, sizeof(struct sockaddr_in)); } @@ -267,9 +271,9 @@ int UDPSocket::Receive(Address &sender, void *data, int size) return -1; u16 address_port = ntohs(address.sin6_port); - IPv6AddressBytes bytes; - memcpy(bytes.bytes, address.sin6_addr.s6_addr, 16); - sender = Address(&bytes, address_port); + const auto *bytes = reinterpret_cast + (address.sin6_addr.s6_addr); + sender = Address(bytes, address_port); } else { struct sockaddr_in address; memset(&address, 0, sizeof(address)); @@ -341,7 +345,12 @@ bool UDPSocket::WaitData(int timeout_ms) if (result == 0) return false; - if (result < 0 && (errno == EINTR || errno == EBADF)) { + int e = LAST_SOCKET_ERR(); +#ifdef _WIN32 + if (result < 0 && (e == WSAEINTR || e == WSAEBADF)) { +#else + if (result < 0 && (e == EINTR || e == EBADF)) { +#endif // N.B. select() fails when sockets are destroyed on Connection's dtor // with EBADF. Instead of doing tricky synchronization, allow this // thread to exit but don't throw an exception. @@ -349,18 +358,9 @@ bool UDPSocket::WaitData(int timeout_ms) } if (result < 0) { - dstream << m_handle << ": Select failed: " << strerror(errno) + dstream << (int)m_handle << ": Select failed: " << SOCKET_ERR_STR(e) << std::endl; -#ifdef _WIN32 - int e = WSAGetLastError(); - dstream << (int)m_handle << ": WSAGetLastError()=" << e << std::endl; - if (e == 10004 /* WSAEINTR */ || e == 10009 /* WSAEBADF */) { - infostream << "Ignoring WSAEINTR/WSAEBADF." << std::endl; - return false; - } -#endif - throw SocketException("Select failed"); } else if (!FD_ISSET(m_handle, &readset)) { // No data diff --git a/src/network/socket.h b/src/network/socket.h index e0e76f4c2..d34186b44 100644 --- a/src/network/socket.h +++ b/src/network/socket.h @@ -19,18 +19,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once -#ifdef _WIN32 -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 -#endif -#include -#include -#include -#else -#include -#include -#endif - #include #include #include "address.h" @@ -53,8 +41,6 @@ public: bool init(bool ipv6, bool noExceptions = false); - // void Close(); - // bool IsOpen(); void Send(const Address &destination, const void *data, int size); // Returns -1 if there is no data int Receive(Address &sender, void *data, int size); diff --git a/src/server.cpp b/src/server.cpp index c175cbcd2..a910185b9 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -507,8 +507,9 @@ void Server::start() << " \\/ \\/ \\/ \\/ \\/ " << std::endl; actionstream << "World at [" << m_path_world << "]" << std::endl; actionstream << "Server for gameid=\"" << m_gamespec.id - << "\" listening on " << m_bind_addr.serializeString() << ":" - << m_bind_addr.getPort() << "." << std::endl; + << "\" listening on "; + m_bind_addr.print(&actionstream); + actionstream << "." << std::endl; } void Server::stop() diff --git a/src/unittest/test_socket.cpp b/src/unittest/test_socket.cpp index 6d5cf334d..620021b59 100644 --- a/src/unittest/test_socket.cpp +++ b/src/unittest/test_socket.cpp @@ -97,11 +97,11 @@ void TestSocket::testIPv4Socket() UASSERT(strncmp(sendbuffer, rcvbuffer, sizeof(sendbuffer)) == 0); if (address != Address(0, 0, 0, 0, port)) { - UASSERT(sender.getAddress().sin_addr.s_addr == - address.getAddress().sin_addr.s_addr); + UASSERT(sender.getAddress().s_addr == + address.getAddress().s_addr); } else { - UASSERT(sender.getAddress().sin_addr.s_addr == - Address(127, 0, 0, 1, 0).getAddress().sin_addr.s_addr); + UASSERT(sender.getAddress().s_addr == + Address(127, 0, 0, 1, 0).getAddress().s_addr); } } @@ -128,7 +128,7 @@ void TestSocket::testIPv6Socket() socket6.Bind(address6); - try { + { socket6.Send(Address(&bytes, port), sendbuffer, sizeof(sendbuffer)); sleep_ms(50); @@ -142,10 +142,8 @@ void TestSocket::testIPv6Socket() } //FIXME: This fails on some systems UASSERT(strncmp(sendbuffer, rcvbuffer, sizeof(sendbuffer)) == 0); - UASSERT(memcmp(sender.getAddress6().sin6_addr.s6_addr, - Address(&bytes, 0).getAddress6().sin6_addr.s6_addr, 16) == 0); - } catch (SendFailedException &e) { - errorstream << "IPv6 support enabled but not available!" - << std::endl; + + UASSERT(memcmp(sender.getAddress6().s6_addr, + Address(&bytes, 0).getAddress6().s6_addr, 16) == 0); } } -- cgit v1.2.3 From 5eb45e1ea03c6104f007efec6dd9c351f310193d Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 9 Jan 2022 18:46:36 +0100 Subject: Restore pass-through of direction keys (#11924) This moves relevant code into the PlayerControl class and gets rid of separate keyPressed variable. --- src/client/client.cpp | 16 +++++----- src/client/clientlauncher.cpp | 4 +-- src/client/game.cpp | 36 +++------------------- src/client/inputhandler.h | 50 +++++++++++++++++++++--------- src/client/localplayer.cpp | 4 +-- src/client/localplayer.h | 2 +- src/network/serverpackethandler.cpp | 9 +----- src/player.cpp | 59 ++++++++++++++++++++++++++++++++++++ src/player.h | 33 ++++++++++++-------- src/script/lua_api/l_localplayer.cpp | 14 +++++---- src/script/lua_api/l_object.cpp | 36 ++++++++++++++-------- 11 files changed, 165 insertions(+), 98 deletions(-) (limited to 'src/network') diff --git a/src/client/client.cpp b/src/client/client.cpp index 2caa953e4..d4c271bab 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -931,7 +931,7 @@ void writePlayerPos(LocalPlayer *myplayer, ClientMap *clientMap, NetworkPacket * v3f sf = myplayer->getSpeed() * 100; s32 pitch = myplayer->getPitch() * 100; s32 yaw = myplayer->getYaw() * 100; - u32 keyPressed = myplayer->keyPressed; + u32 keyPressed = myplayer->control.getKeysPressed(); // scaled by 80, so that pi can fit into a u8 u8 fov = clientMap->getCameraFov() * 80; u8 wanted_range = MYMIN(255, @@ -1287,22 +1287,24 @@ void Client::sendPlayerPos() if (!player) return; - ClientMap &map = m_env.getClientMap(); - u8 camera_fov = map.getCameraFov(); - u8 wanted_range = map.getControl().wanted_range; - // Save bandwidth by only updating position when // player is not dead and something changed if (m_activeobjects_received && player->isDead()) return; + ClientMap &map = m_env.getClientMap(); + u8 camera_fov = map.getCameraFov(); + u8 wanted_range = map.getControl().wanted_range; + + u32 keyPressed = player->control.getKeysPressed(); + if ( player->last_position == player->getPosition() && player->last_speed == player->getSpeed() && player->last_pitch == player->getPitch() && player->last_yaw == player->getYaw() && - player->last_keyPressed == player->keyPressed && + player->last_keyPressed == keyPressed && player->last_camera_fov == camera_fov && player->last_wanted_range == wanted_range) return; @@ -1311,7 +1313,7 @@ void Client::sendPlayerPos() player->last_speed = player->getSpeed(); player->last_pitch = player->getPitch(); player->last_yaw = player->getYaw(); - player->last_keyPressed = player->keyPressed; + player->last_keyPressed = keyPressed; player->last_camera_fov = camera_fov; player->last_wanted_range = wanted_range; diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp index 95be72ca0..063154316 100644 --- a/src/client/clientlauncher.cpp +++ b/src/client/clientlauncher.cpp @@ -70,10 +70,10 @@ static void dump_start_data(const GameStartData &data) ClientLauncher::~ClientLauncher() { - delete receiver; - delete input; + delete receiver; + delete g_fontengine; delete g_gamecallback; diff --git a/src/client/game.cpp b/src/client/game.cpp index f62d26e8f..182dc3815 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -2481,6 +2481,10 @@ void Game::updatePlayerControl(const CameraOrientation &cam) //TimeTaker tt("update player control", NULL, PRECISION_NANO); PlayerControl control( + isKeyDown(KeyType::FORWARD), + isKeyDown(KeyType::BACKWARD), + isKeyDown(KeyType::LEFT), + isKeyDown(KeyType::RIGHT), isKeyDown(KeyType::JUMP) || player->getAutojump(), isKeyDown(KeyType::AUX1), isKeyDown(KeyType::SNEAK), @@ -2511,39 +2515,7 @@ void Game::updatePlayerControl(const CameraOrientation &cam) } #endif - u32 keypress_bits = ( - ( (u32)(control.jump & 0x1) << 4) | - ( (u32)(control.aux1 & 0x1) << 5) | - ( (u32)(control.sneak & 0x1) << 6) | - ( (u32)(control.dig & 0x1) << 7) | - ( (u32)(control.place & 0x1) << 8) | - ( (u32)(control.zoom & 0x1) << 9) - ); - - // Set direction keys to ensure mod compatibility - if (control.movement_speed > 0.001f) { - float absolute_direction; - - // Check in original orientation (absolute value indicates forward / backward) - absolute_direction = abs(control.movement_direction); - if (absolute_direction < (3.0f / 8.0f * M_PI)) - keypress_bits |= (u32)(0x1 << 0); // Forward - if (absolute_direction > (5.0f / 8.0f * M_PI)) - keypress_bits |= (u32)(0x1 << 1); // Backward - - // Rotate entire coordinate system by 90 degrees (absolute value indicates left / right) - absolute_direction = control.movement_direction + M_PI_2; - if (absolute_direction >= M_PI) - absolute_direction -= 2 * M_PI; - absolute_direction = abs(absolute_direction); - if (absolute_direction < (3.0f / 8.0f * M_PI)) - keypress_bits |= (u32)(0x1 << 2); // Left - if (absolute_direction > (5.0f / 8.0f * M_PI)) - keypress_bits |= (u32)(0x1 << 3); // Right - } - client->setPlayerControl(control); - player->keyPressed = keypress_bits; //tt.stop(); } diff --git a/src/client/inputhandler.h b/src/client/inputhandler.h index e630b860e..3db105c51 100644 --- a/src/client/inputhandler.h +++ b/src/client/inputhandler.h @@ -152,8 +152,14 @@ public: // in the subsequent iteration of Game::processPlayerInteraction bool WasKeyReleased(const KeyPress &keycode) const { return keyWasReleased[keycode]; } - void listenForKey(const KeyPress &keyCode) { keysListenedFor.set(keyCode); } - void dontListenForKeys() { keysListenedFor.clear(); } + void listenForKey(const KeyPress &keyCode) + { + keysListenedFor.set(keyCode); + } + void dontListenForKeys() + { + keysListenedFor.clear(); + } s32 getMouseWheel() { @@ -189,8 +195,6 @@ public: #endif } - s32 mouse_wheel = 0; - JoystickController *joystick = nullptr; #ifdef HAVE_TOUCHSCREENGUI @@ -198,6 +202,8 @@ public: #endif private: + s32 mouse_wheel = 0; + // The current state of keys KeyList keyIsDown; @@ -272,6 +278,12 @@ public: { m_receiver->joystick = &joystick; } + + virtual ~RealInputHandler() + { + m_receiver->joystick = nullptr; + } + virtual bool isKeyDown(GameKeyType k) { return m_receiver->IsKeyDown(keycache.key[k]) || joystick.isKeyDown(k); @@ -288,6 +300,7 @@ public: { return m_receiver->WasKeyReleased(keycache.key[k]) || joystick.wasKeyReleased(k); } + virtual float getMovementSpeed() { bool f = m_receiver->IsKeyDown(keycache.key[KeyType::FORWARD]), @@ -307,6 +320,7 @@ public: } return joystick.getMovementSpeed(); } + virtual float getMovementDirection() { float x = 0, z = 0; @@ -326,10 +340,12 @@ public: else return joystick.getMovementDirection(); } + virtual bool cancelPressed() { return wasKeyDown(KeyType::ESC) || m_receiver->WasKeyDown(CancelKey); } + virtual void clearWasKeyPressed() { m_receiver->clearWasKeyPressed(); @@ -338,17 +354,21 @@ public: { m_receiver->clearWasKeyReleased(); } + virtual void listenForKey(const KeyPress &keyCode) { m_receiver->listenForKey(keyCode); } - virtual void dontListenForKeys() { m_receiver->dontListenForKeys(); } + virtual void dontListenForKeys() + { + m_receiver->dontListenForKeys(); + } + virtual v2s32 getMousePos() { - if (RenderingEngine::get_raw_device()->getCursorControl()) { - return RenderingEngine::get_raw_device() - ->getCursorControl() - ->getPosition(); + auto control = RenderingEngine::get_raw_device()->getCursorControl(); + if (control) { + return control->getPosition(); } return m_mousepos; @@ -356,16 +376,18 @@ public: virtual void setMousePos(s32 x, s32 y) { - if (RenderingEngine::get_raw_device()->getCursorControl()) { - RenderingEngine::get_raw_device() - ->getCursorControl() - ->setPosition(x, y); + auto control = RenderingEngine::get_raw_device()->getCursorControl(); + if (control) { + control->setPosition(x, y); } else { m_mousepos = v2s32(x, y); } } - virtual s32 getMouseWheel() { return m_receiver->getMouseWheel(); } + virtual s32 getMouseWheel() + { + return m_receiver->getMouseWheel(); + } void clear() { diff --git a/src/client/localplayer.cpp b/src/client/localplayer.cpp index 3f78d201d..4f1ea7bda 100644 --- a/src/client/localplayer.cpp +++ b/src/client/localplayer.cpp @@ -1096,10 +1096,8 @@ void LocalPlayer::handleAutojump(f32 dtime, Environment *env, if (m_autojump) return; - bool control_forward = keyPressed & (1 << 0); - bool could_autojump = - m_can_jump && !control.jump && !control.sneak && control_forward; + m_can_jump && !control.jump && !control.sneak && control.isMoving(); if (!could_autojump) return; diff --git a/src/client/localplayer.h b/src/client/localplayer.h index 13b35ae4e..577be2803 100644 --- a/src/client/localplayer.h +++ b/src/client/localplayer.h @@ -86,7 +86,7 @@ public: v3f last_speed; float last_pitch = 0.0f; float last_yaw = 0.0f; - unsigned int last_keyPressed = 0; + u32 last_keyPressed = 0; u8 last_camera_fov = 0; u8 last_wanted_range = 0; diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index e5a1bab1e..37b62c5cb 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -482,7 +482,6 @@ void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao, f32 yaw = (f32)f32yaw / 100.0f; u32 keyPressed = 0; - // default behavior (in case an old client doesn't send these) f32 fov = 0; u8 wanted_range = 0; @@ -508,13 +507,7 @@ void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao, playersao->setFov(fov); playersao->setWantedRange(wanted_range); - player->keyPressed = keyPressed; - player->control.jump = (keyPressed & (0x1 << 4)); - player->control.aux1 = (keyPressed & (0x1 << 5)); - player->control.sneak = (keyPressed & (0x1 << 6)); - player->control.dig = (keyPressed & (0x1 << 7)); - player->control.place = (keyPressed & (0x1 << 8)); - player->control.zoom = (keyPressed & (0x1 << 9)); + player->control.unpackKeysPressed(keyPressed); if (playersao->checkMovementCheat()) { // Call callbacks diff --git a/src/player.cpp b/src/player.cpp index d3ba5c2c2..347be30f1 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "player.h" +#include #include "threading/mutex_auto_lock.h" #include "util/numeric.h" #include "hud.h" @@ -159,6 +160,64 @@ void Player::clearHud() } } +#ifndef SERVER + +u32 PlayerControl::getKeysPressed() const +{ + u32 keypress_bits = + ( (u32)(jump & 1) << 4) | + ( (u32)(aux1 & 1) << 5) | + ( (u32)(sneak & 1) << 6) | + ( (u32)(dig & 1) << 7) | + ( (u32)(place & 1) << 8) | + ( (u32)(zoom & 1) << 9) + ; + + // If any direction keys are pressed pass those through + if (direction_keys != 0) + { + keypress_bits |= direction_keys; + } + // Otherwise set direction keys based on joystick movement (for mod compatibility) + else if (isMoving()) + { + float abs_d; + + // (absolute value indicates forward / backward) + abs_d = abs(movement_direction); + if (abs_d < 3.0f / 8.0f * M_PI) + keypress_bits |= (u32)1; // Forward + if (abs_d > 5.0f / 8.0f * M_PI) + keypress_bits |= (u32)1 << 1; // Backward + + // rotate entire coordinate system by 90 degree + abs_d = movement_direction + M_PI_2; + if (abs_d >= M_PI) + abs_d -= 2 * M_PI; + abs_d = abs(abs_d); + // (value now indicates left / right) + if (abs_d < 3.0f / 8.0f * M_PI) + keypress_bits |= (u32)1 << 2; // Left + if (abs_d > 5.0f / 8.0f * M_PI) + keypress_bits |= (u32)1 << 3; // Right + } + + return keypress_bits; +} + +#endif + +void PlayerControl::unpackKeysPressed(u32 keypress_bits) +{ + direction_keys = keypress_bits & 0xf; + jump = keypress_bits & (1 << 4); + aux1 = keypress_bits & (1 << 5); + sneak = keypress_bits & (1 << 6); + dig = keypress_bits & (1 << 7); + place = keypress_bits & (1 << 8); + zoom = keypress_bits & (1 << 9); +} + void PlayerSettings::readGlobalSettings() { free_move = g_settings->getBool("free_move"); diff --git a/src/player.h b/src/player.h index 3800e1a33..d769acdad 100644 --- a/src/player.h +++ b/src/player.h @@ -49,18 +49,18 @@ struct PlayerControl PlayerControl() = default; PlayerControl( - bool a_jump, - bool a_aux1, - bool a_sneak, + bool a_up, bool a_down, bool a_left, bool a_right, + bool a_jump, bool a_aux1, bool a_sneak, bool a_zoom, - bool a_dig, - bool a_place, - float a_pitch, - float a_yaw, - float a_movement_speed, - float a_movement_direction + bool a_dig, bool a_place, + float a_pitch, float a_yaw, + float a_movement_speed, float a_movement_direction ) { + // Encode direction keys into a single value so nobody uses it accidentally + // as movement_{speed,direction} is supposed to be the source of truth. + direction_keys = (a_up&1) | ((a_down&1) << 1) | + ((a_left&1) << 2) | ((a_right&1) << 3); jump = a_jump; aux1 = a_aux1; sneak = a_sneak; @@ -72,15 +72,26 @@ struct PlayerControl movement_speed = a_movement_speed; movement_direction = a_movement_direction; } + +#ifndef SERVER + // For client use + u32 getKeysPressed() const; + inline bool isMoving() const { return movement_speed > 0.001f; } +#endif + + // For server use + void unpackKeysPressed(u32 keypress_bits); + + u8 direction_keys = 0; bool jump = false; bool aux1 = false; bool sneak = false; bool zoom = false; bool dig = false; bool place = false; + // Note: These four are NOT available on the server float pitch = 0.0f; float yaw = 0.0f; - // Note: These two are NOT available on the server float movement_speed = 0.0f; float movement_direction = 0.0f; }; @@ -189,8 +200,6 @@ public: return m_fov_override_spec; } - u32 keyPressed = 0; - HudElement* getHud(u32 id); u32 addHud(HudElement* hud); HudElement* removeHud(u32 id); diff --git a/src/script/lua_api/l_localplayer.cpp b/src/script/lua_api/l_localplayer.cpp index bdbe98cb0..2efb976c7 100644 --- a/src/script/lua_api/l_localplayer.cpp +++ b/src/script/lua_api/l_localplayer.cpp @@ -230,13 +230,15 @@ int LuaLocalPlayer::l_get_control(lua_State *L) set("dig", c.dig); set("place", c.place); // Player movement in polar coordinates and non-binary speed - set("movement_speed", c.movement_speed); - set("movement_direction", c.movement_direction); + lua_pushnumber(L, c.movement_speed); + lua_setfield(L, -2, "movement_speed"); + lua_pushnumber(L, c.movement_direction); + lua_setfield(L, -2, "movement_direction"); // Provide direction keys to ensure compatibility - set("up", player->keyPressed & (1 << 0)); // Up, down, left, and right were removed in favor of - set("down", player->keyPressed & (1 << 1)); // analog direction indicators and are therefore not - set("left", player->keyPressed & (1 << 2)); // available as booleans anymore. The corresponding values - set("right", player->keyPressed & (1 << 3)); // can still be read from the keyPressed bits though. + set("up", c.direction_keys & (1 << 0)); + set("down", c.direction_keys & (1 << 1)); + set("left", c.direction_keys & (1 << 2)); + set("right", c.direction_keys & (1 << 3)); return 1; } diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 072b13d80..7d937b306 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -1367,20 +1367,18 @@ int ObjectRef::l_get_player_control(lua_State *L) NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); RemotePlayer *player = getplayer(ref); - if (player == nullptr) { - lua_pushlstring(L, "", 0); - return 1; - } + if (player == nullptr) + return 0; const PlayerControl &control = player->getPlayerControl(); lua_newtable(L); - lua_pushboolean(L, player->keyPressed & (1 << 0)); + lua_pushboolean(L, control.direction_keys & (1 << 0)); lua_setfield(L, -2, "up"); - lua_pushboolean(L, player->keyPressed & (1 << 1)); + lua_pushboolean(L, control.direction_keys & (1 << 1)); lua_setfield(L, -2, "down"); - lua_pushboolean(L, player->keyPressed & (1 << 2)); + lua_pushboolean(L, control.direction_keys & (1 << 2)); lua_setfield(L, -2, "left"); - lua_pushboolean(L, player->keyPressed & (1 << 3)); + lua_pushboolean(L, control.direction_keys & (1 << 3)); lua_setfield(L, -2, "right"); lua_pushboolean(L, control.jump); lua_setfield(L, -2, "jump"); @@ -1408,12 +1406,24 @@ int ObjectRef::l_get_player_control_bits(lua_State *L) NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); RemotePlayer *player = getplayer(ref); - if (player == nullptr) { - lua_pushlstring(L, "", 0); - return 1; - } + if (player == nullptr) + return 0; + + const auto &c = player->getPlayerControl(); + + // This is very close to PlayerControl::getKeysPressed() but duplicated + // here so the encoding in the API is not inadvertedly changed. + u32 keypress_bits = + c.direction_keys | + ( (u32)(c.jump & 1) << 4) | + ( (u32)(c.aux1 & 1) << 5) | + ( (u32)(c.sneak & 1) << 6) | + ( (u32)(c.dig & 1) << 7) | + ( (u32)(c.place & 1) << 8) | + ( (u32)(c.zoom & 1) << 9) + ; - lua_pushnumber(L, player->keyPressed); + lua_pushinteger(L, keypress_bits); return 1; } -- cgit v1.2.3 From 72b14bd994659163d4c2ea0d769d329df8a0f937 Mon Sep 17 00:00:00 2001 From: savilli <78875209+savilli@users.noreply.github.com> Date: Sat, 15 Jan 2022 17:44:55 +0100 Subject: Don't call on_dieplayer callback two times (#11874) --- src/network/serverpackethandler.cpp | 3 +-- src/server.cpp | 51 +++++++++++++------------------------ src/server.h | 6 ++--- src/server/player_sao.cpp | 37 +++++++++++++-------------- src/server/player_sao.h | 4 +-- 5 files changed, 41 insertions(+), 60 deletions(-) (limited to 'src/network') diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index 37b62c5cb..12dc24460 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -819,8 +819,7 @@ void Server::handleCommand_Damage(NetworkPacket* pkt) << std::endl; PlayerHPChangeReason reason(PlayerHPChangeReason::FALL); - playersao->setHP((s32)playersao->getHP() - (s32)damage, reason, false); - SendPlayerHPOrDie(playersao, reason); // correct client side prediction + playersao->setHP((s32)playersao->getHP() - (s32)damage, reason, true); } } diff --git a/src/server.cpp b/src/server.cpp index 6cf790de1..45156db61 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1095,11 +1095,12 @@ PlayerSAO* Server::StageTwoClientInit(session_t peer_id) // Send inventory SendInventory(playersao, false); - // Send HP or death screen + // Send HP + SendPlayerHP(playersao); + + // Send death screen if (playersao->isDead()) SendDeathscreen(peer_id, false, v3f(0,0,0)); - else - SendPlayerHP(peer_id); // Send Breath SendPlayerBreath(playersao); @@ -1365,18 +1366,21 @@ void Server::SendMovement(session_t peer_id) Send(&pkt); } -void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason) +void Server::HandlePlayerHPChange(PlayerSAO *playersao, const PlayerHPChangeReason &reason) { - if (playersao->isImmortal()) - return; + m_script->player_event(playersao, "health_changed"); + SendPlayerHP(playersao); - session_t peer_id = playersao->getPeerID(); - bool is_alive = !playersao->isDead(); + // Send to other clients + playersao->sendPunchCommand(); - if (is_alive) - SendPlayerHP(peer_id); - else - DiePlayer(peer_id, reason); + if (playersao->isDead()) + HandlePlayerDeath(playersao, reason); +} + +void Server::SendPlayerHP(PlayerSAO *playersao) +{ + SendHP(playersao->getPeerID(), playersao->getHP()); } void Server::SendHP(session_t peer_id, u16 hp) @@ -1810,18 +1814,6 @@ void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed) } } -void Server::SendPlayerHP(session_t peer_id) -{ - PlayerSAO *playersao = getPlayerSAO(peer_id); - assert(playersao); - - SendHP(peer_id, playersao->getHP()); - m_script->player_event(playersao,"health_changed"); - - // Send to other clients - playersao->sendPunchCommand(); -} - void Server::SendPlayerBreath(PlayerSAO *sao) { assert(sao); @@ -2750,23 +2742,18 @@ void Server::sendDetachedInventories(session_t peer_id, bool incremental) Something random */ -void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason) +void Server::HandlePlayerDeath(PlayerSAO *playersao, const PlayerHPChangeReason &reason) { - PlayerSAO *playersao = getPlayerSAO(peer_id); - assert(playersao); - infostream << "Server::DiePlayer(): Player " << playersao->getPlayer()->getName() << " dies" << std::endl; - playersao->setHP(0, reason); playersao->clearParentAttachment(); // Trigger scripted stuff m_script->on_dieplayer(playersao, reason); - SendPlayerHP(peer_id); - SendDeathscreen(peer_id, false, v3f(0,0,0)); + SendDeathscreen(playersao->getPeerID(), false, v3f(0,0,0)); } void Server::RespawnPlayer(session_t peer_id) @@ -2787,8 +2774,6 @@ void Server::RespawnPlayer(session_t peer_id) // setPos will send the new position to client playersao->setPos(findSpawnPos()); } - - SendPlayerHP(peer_id); } diff --git a/src/server.h b/src/server.h index 12158feb7..2741b3157 100644 --- a/src/server.h +++ b/src/server.h @@ -350,7 +350,8 @@ public: void printToConsoleOnly(const std::string &text); - void SendPlayerHPOrDie(PlayerSAO *player, const PlayerHPChangeReason &reason); + void HandlePlayerHPChange(PlayerSAO *sao, const PlayerHPChangeReason &reason); + void SendPlayerHP(PlayerSAO *sao); void SendPlayerBreath(PlayerSAO *sao); void SendInventory(PlayerSAO *playerSAO, bool incremental); void SendMovePlayer(session_t peer_id); @@ -438,7 +439,6 @@ private: virtual void SendChatMessage(session_t peer_id, const ChatMessage &message); void SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed); - void SendPlayerHP(session_t peer_id); void SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4], f32 animation_speed); @@ -510,7 +510,7 @@ private: Something random */ - void DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason); + void HandlePlayerDeath(PlayerSAO* sao, const PlayerHPChangeReason &reason); void RespawnPlayer(session_t peer_id); void DeleteClient(session_t peer_id, ClientDeletionReason reason); void UpdateCrafting(RemotePlayer *player); diff --git a/src/server/player_sao.cpp b/src/server/player_sao.cpp index 83e17f830..d076d5783 100644 --- a/src/server/player_sao.cpp +++ b/src/server/player_sao.cpp @@ -463,36 +463,33 @@ void PlayerSAO::rightClick(ServerActiveObject *clicker) m_env->getScriptIface()->on_rightclickplayer(this, clicker); } -void PlayerSAO::setHP(s32 hp, const PlayerHPChangeReason &reason, bool send) +void PlayerSAO::setHP(s32 target_hp, const PlayerHPChangeReason &reason, bool from_client) { - if (hp == (s32)m_hp) - return; // Nothing to do + target_hp = rangelim(target_hp, 0, U16_MAX); - if (m_hp <= 0 && hp < (s32)m_hp) - return; // Cannot take more damage + if (target_hp == m_hp) + return; // Nothing to do - { - s32 hp_change = m_env->getScriptIface()->on_player_hpchange(this, hp - m_hp, reason); - if (hp_change == 0) - return; + s32 hp_change = m_env->getScriptIface()->on_player_hpchange(this, target_hp - (s32)m_hp, reason); - hp = m_hp + hp_change; - } + s32 hp = (s32)m_hp + std::min(hp_change, U16_MAX); // Protection against s32 overflow + hp = rangelim(hp, 0, U16_MAX); - s32 oldhp = m_hp; - hp = rangelim(hp, 0, m_prop.hp_max); + if (hp > m_prop.hp_max) + hp = m_prop.hp_max; - if (hp < oldhp && isImmortal()) - return; // Do not allow immortal players to be damaged - - m_hp = hp; + if (hp < m_hp && isImmortal()) + hp = m_hp; // Do not allow immortal players to be damaged // Update properties on death - if ((hp == 0) != (oldhp == 0)) + if ((hp == 0) != (m_hp == 0)) m_properties_sent = false; - if (send) - m_env->getGameDef()->SendPlayerHPOrDie(this, reason); + if (hp != m_hp) { + m_hp = hp; + m_env->getGameDef()->HandlePlayerHPChange(this, reason); + } else if (from_client) + m_env->getGameDef()->SendPlayerHP(this); } void PlayerSAO::setBreath(const u16 breath, bool send) diff --git a/src/server/player_sao.h b/src/server/player_sao.h index 47fe85413..96d8f7189 100644 --- a/src/server/player_sao.h +++ b/src/server/player_sao.h @@ -114,9 +114,9 @@ public: void rightClick(ServerActiveObject *clicker); void setHP(s32 hp, const PlayerHPChangeReason &reason) override { - return setHP(hp, reason, true); + return setHP(hp, reason, false); } - void setHP(s32 hp, const PlayerHPChangeReason &reason, bool send); + void setHP(s32 hp, const PlayerHPChangeReason &reason, bool from_client); void setHPRaw(u16 hp) { m_hp = hp; } u16 getBreath() const { return m_breath; } void setBreath(const u16 breath, bool send = true); -- cgit v1.2.3 From f66ed2c27fa0f351ffb458224af74f3371d6f4ac Mon Sep 17 00:00:00 2001 From: sfan5 Date: Tue, 18 Jan 2022 19:19:40 +0100 Subject: Fix local animation not instantly updating after being set --- src/client/content_cao.cpp | 1 + src/network/clientpackethandler.cpp | 2 ++ 2 files changed, 3 insertions(+) (limited to 'src/network') diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index 9cc40c95f..1d4636a08 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -1815,6 +1815,7 @@ void GenericCAO::processMessage(const std::string &data) { updateAnimation(); } + // FIXME: ^ This code is trash. It's also broken. } } else if (cmd == AO_CMD_SET_ANIMATION_SPEED) { m_animation_speed = readF32(is); diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 6aececa7f..f7c586b80 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -1404,6 +1404,8 @@ void Client::handleCommand_LocalPlayerAnimations(NetworkPacket* pkt) *pkt >> player->local_animations[2]; *pkt >> player->local_animations[3]; *pkt >> player->local_animation_speed; + + player->last_animation = -1; } void Client::handleCommand_EyeOffset(NetworkPacket* pkt) -- cgit v1.2.3 From f8cef52ea07de6a6ccaa6f9a853a8e5ccaaff4ce Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sat, 22 Jan 2022 13:37:26 +0100 Subject: Fix consistency of sky sun/moon texture behaviour Also cleans up related code somewhat. --- doc/lua_api.txt | 4 +- src/client/game.cpp | 2 +- src/client/sky.cpp | 178 +++++++++++++----------------------- src/client/sky.h | 9 +- src/network/clientpackethandler.cpp | 12 +-- src/remoteplayer.cpp | 17 ++-- src/skyparams.h | 2 + 7 files changed, 82 insertions(+), 142 deletions(-) (limited to 'src/network') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 00c29f791..2331736c6 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -6856,7 +6856,7 @@ object you are working with still exists. * `visible`: Boolean for whether the sun is visible. (default: `true`) * `texture`: A regular texture for the sun. Setting to `""` - will re-enable the mesh sun. (default: `"sun.png"`) + will re-enable the mesh sun. (default: "sun.png", if it exists) * `tonemap`: A 512x1 texture containing the tonemap for the sun (default: `"sun_tonemap.png"`) * `sunrise`: A regular texture for the sunrise texture. @@ -6872,7 +6872,7 @@ object you are working with still exists. * `visible`: Boolean for whether the moon is visible. (default: `true`) * `texture`: A regular texture for the moon. Setting to `""` - will re-enable the mesh moon. (default: `"moon.png"`) + will re-enable the mesh moon. (default: "moon.png", if it exists) * `tonemap`: A 512x1 texture containing the tonemap for the moon (default: `"moon_tonemap.png"`) * `scale`: Float controlling the overall size of the moon (default: `1`) diff --git a/src/client/game.cpp b/src/client/game.cpp index 182dc3815..b6052390b 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -2862,7 +2862,7 @@ void Game::handleClientEvent_SetMoon(ClientEvent *event, CameraOrientation *cam) void Game::handleClientEvent_SetStars(ClientEvent *event, CameraOrientation *cam) { sky->setStarsVisible(event->star_params->visible); - sky->setStarCount(event->star_params->count, false); + sky->setStarCount(event->star_params->count); sky->setStarColor(event->star_params->starcolor); sky->setStarScale(event->star_params->scale); delete event->star_params; diff --git a/src/client/sky.cpp b/src/client/sky.cpp index 1cf9a4afc..0ab710eee 100644 --- a/src/client/sky.cpp +++ b/src/client/sky.cpp @@ -18,21 +18,21 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include "sky.h" -#include "ITexture.h" -#include "IVideoDriver.h" -#include "ISceneManager.h" -#include "ICameraSceneNode.h" -#include "S3DVertex.h" +#include +#include +#include +#include +#include #include "client/tile.h" #include "noise.h" // easeCurve #include "profiler.h" #include "util/numeric.h" -#include #include "client/renderingengine.h" #include "settings.h" #include "camera.h" // CameraModes -#include "config.h" + using namespace irr::core; static video::SMaterial baseMaterial() @@ -51,7 +51,14 @@ static video::SMaterial baseMaterial() mat.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE; mat.BackfaceCulling = false; return mat; -}; +} + +static inline void disableTextureFiltering(video::SMaterial &mat) +{ + mat.setFlag(video::E_MATERIAL_FLAG::EMF_BILINEAR_FILTER, false); + mat.setFlag(video::E_MATERIAL_FLAG::EMF_TRILINEAR_FILTER, false); + mat.setFlag(video::E_MATERIAL_FLAG::EMF_ANISOTROPIC_FILTER, false); +} Sky::Sky(s32 id, RenderingEngine *rendering_engine, ITextureSource *tsrc, IShaderSource *ssrc) : scene::ISceneNode(rendering_engine->get_scene_manager()->getRootSceneNode(), @@ -65,6 +72,11 @@ Sky::Sky(s32 id, RenderingEngine *rendering_engine, ITextureSource *tsrc, IShade m_enable_shaders = g_settings->getBool("enable_shaders"); + m_sky_params = SkyboxDefaults::getSkyDefaults(); + m_sun_params = SkyboxDefaults::getSunDefaults(); + m_moon_params = SkyboxDefaults::getMoonDefaults(); + m_star_params = SkyboxDefaults::getStarDefaults(); + // Create materials m_materials[0] = baseMaterial(); @@ -73,49 +85,15 @@ Sky::Sky(s32 id, RenderingEngine *rendering_engine, ITextureSource *tsrc, IShade m_materials[0].ColorMaterial = video::ECM_NONE; m_materials[1] = baseMaterial(); - //m_materials[1].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; m_materials[1].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; m_materials[2] = baseMaterial(); m_materials[2].setTexture(0, tsrc->getTextureForMesh("sunrisebg.png")); m_materials[2].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; - //m_materials[2].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR; - - // Ensures that sun and moon textures and tonemaps are correct. - setSkyDefaults(); - m_sun_texture = tsrc->isKnownSourceImage(m_sun_params.texture) ? - tsrc->getTextureForMesh(m_sun_params.texture) : nullptr; - m_moon_texture = tsrc->isKnownSourceImage(m_moon_params.texture) ? - tsrc->getTextureForMesh(m_moon_params.texture) : nullptr; - m_sun_tonemap = tsrc->isKnownSourceImage(m_sun_params.tonemap) ? - tsrc->getTexture(m_sun_params.tonemap) : nullptr; - m_moon_tonemap = tsrc->isKnownSourceImage(m_moon_params.tonemap) ? - tsrc->getTexture(m_moon_params.tonemap) : nullptr; - if (m_sun_texture) { - m_materials[3] = baseMaterial(); - m_materials[3].setTexture(0, m_sun_texture); - m_materials[3].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; - // Disables texture filtering - m_materials[3].setFlag(video::E_MATERIAL_FLAG::EMF_BILINEAR_FILTER, false); - m_materials[3].setFlag(video::E_MATERIAL_FLAG::EMF_TRILINEAR_FILTER, false); - m_materials[3].setFlag(video::E_MATERIAL_FLAG::EMF_ANISOTROPIC_FILTER, false); - // Use tonemaps if available - if (m_sun_tonemap) - m_materials[3].Lighting = true; - } - if (m_moon_texture) { - m_materials[4] = baseMaterial(); - m_materials[4].setTexture(0, m_moon_texture); - m_materials[4].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; - // Disables texture filtering - m_materials[4].setFlag(video::E_MATERIAL_FLAG::EMF_BILINEAR_FILTER, false); - m_materials[4].setFlag(video::E_MATERIAL_FLAG::EMF_TRILINEAR_FILTER, false); - m_materials[4].setFlag(video::E_MATERIAL_FLAG::EMF_ANISOTROPIC_FILTER, false); - // Use tonemaps if available - if (m_moon_tonemap) - m_materials[4].Lighting = true; - } + setSunTexture(m_sun_params.texture, m_sun_params.tonemap, tsrc); + + setMoonTexture(m_moon_params.texture, m_moon_params.tonemap, tsrc); for (int i = 5; i < 11; i++) { m_materials[i] = baseMaterial(); @@ -130,7 +108,7 @@ Sky::Sky(s32 id, RenderingEngine *rendering_engine, ITextureSource *tsrc, IShade m_sky_body_orbit_tilt = rangelim(val, 0.0f, 60.0f); } - setStarCount(1000, true); + setStarCount(1000); } void Sky::OnRegisterSceneNode() @@ -386,20 +364,6 @@ void Sky::update(float time_of_day, float time_brightness, bool is_dawn = (time_brightness >= 0.20 && time_brightness < 0.35); - /* - Development colours - - video::SColorf bgcolor_bright_normal_f(170. / 255, 200. / 255, 230. / 255, 1.0); - video::SColorf bgcolor_bright_dawn_f(0.666, 200. / 255 * 0.7, 230. / 255 * 0.5, 1.0); - video::SColorf bgcolor_bright_dawn_f(0.666, 0.549, 0.220, 1.0); - video::SColorf bgcolor_bright_dawn_f(0.666 * 1.2, 0.549 * 1.0, 0.220 * 1.0, 1.0); - video::SColorf bgcolor_bright_dawn_f(0.666 * 1.2, 0.549 * 1.0, 0.220 * 1.2, 1.0); - - video::SColorf cloudcolor_bright_dawn_f(1.0, 0.591, 0.4); - video::SColorf cloudcolor_bright_dawn_f(1.0, 0.65, 0.44); - video::SColorf cloudcolor_bright_dawn_f(1.0, 0.7, 0.5); - */ - video::SColorf bgcolor_bright_normal_f = m_sky_params.sky_color.day_horizon; video::SColorf bgcolor_bright_indoor_f = m_sky_params.sky_color.indoors; video::SColorf bgcolor_bright_dawn_f = m_sky_params.sky_color.dawn_horizon; @@ -754,33 +718,29 @@ void Sky::setSunTexture(const std::string &sun_texture, // Ignore matching textures (with modifiers) entirely, // but lets at least update the tonemap before hand. m_sun_params.tonemap = sun_tonemap; - m_sun_tonemap = tsrc->isKnownSourceImage(m_sun_params.tonemap) ? - tsrc->getTexture(m_sun_params.tonemap) : nullptr; + m_sun_tonemap = tsrc->isKnownSourceImage(sun_tonemap) ? + tsrc->getTexture(sun_tonemap) : nullptr; m_materials[3].Lighting = !!m_sun_tonemap; - if (m_sun_params.texture == sun_texture) + if (m_sun_params.texture == sun_texture && !m_first_update) return; m_sun_params.texture = sun_texture; - if (sun_texture != "") { - // We want to ensure the texture exists first. - m_sun_texture = tsrc->getTextureForMesh(m_sun_params.texture); - - if (m_sun_texture) { - m_materials[3] = baseMaterial(); - m_materials[3].setTexture(0, m_sun_texture); - m_materials[3].MaterialType = video:: - EMT_TRANSPARENT_ALPHA_CHANNEL; - // Disables texture filtering - m_materials[3].setFlag( - video::E_MATERIAL_FLAG::EMF_BILINEAR_FILTER, false); - m_materials[3].setFlag( - video::E_MATERIAL_FLAG::EMF_TRILINEAR_FILTER, false); - m_materials[3].setFlag( - video::E_MATERIAL_FLAG::EMF_ANISOTROPIC_FILTER, false); - } - } else { - m_sun_texture = nullptr; + m_sun_texture = nullptr; + if (sun_texture == "sun.png") { + // Dumb compatibility fix: sun.png transparently falls back to no texture + m_sun_texture = tsrc->isKnownSourceImage(sun_texture) ? + tsrc->getTexture(sun_texture) : nullptr; + } else if (!sun_texture.empty()) { + m_sun_texture = tsrc->getTextureForMesh(sun_texture); + } + + if (m_sun_texture) { + m_materials[3] = baseMaterial(); + m_materials[3].setTexture(0, m_sun_texture); + m_materials[3].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + disableTextureFiltering(m_materials[3]); + m_materials[3].Lighting = !!m_sun_tonemap; } } @@ -802,40 +762,36 @@ void Sky::setMoonTexture(const std::string &moon_texture, // Ignore matching textures (with modifiers) entirely, // but lets at least update the tonemap before hand. m_moon_params.tonemap = moon_tonemap; - m_moon_tonemap = tsrc->isKnownSourceImage(m_moon_params.tonemap) ? - tsrc->getTexture(m_moon_params.tonemap) : nullptr; + m_moon_tonemap = tsrc->isKnownSourceImage(moon_tonemap) ? + tsrc->getTexture(moon_tonemap) : nullptr; m_materials[4].Lighting = !!m_moon_tonemap; - if (m_moon_params.texture == moon_texture) + if (m_moon_params.texture == moon_texture && !m_first_update) return; m_moon_params.texture = moon_texture; - if (moon_texture != "") { - // We want to ensure the texture exists first. - m_moon_texture = tsrc->getTextureForMesh(m_moon_params.texture); - - if (m_moon_texture) { - m_materials[4] = baseMaterial(); - m_materials[4].setTexture(0, m_moon_texture); - m_materials[4].MaterialType = video:: - EMT_TRANSPARENT_ALPHA_CHANNEL; - // Disables texture filtering - m_materials[4].setFlag( - video::E_MATERIAL_FLAG::EMF_BILINEAR_FILTER, false); - m_materials[4].setFlag( - video::E_MATERIAL_FLAG::EMF_TRILINEAR_FILTER, false); - m_materials[4].setFlag( - video::E_MATERIAL_FLAG::EMF_ANISOTROPIC_FILTER, false); - } - } else { - m_moon_texture = nullptr; + m_moon_texture = nullptr; + if (moon_texture == "moon.png") { + // Dumb compatibility fix: moon.png transparently falls back to no texture + m_moon_texture = tsrc->isKnownSourceImage(moon_texture) ? + tsrc->getTexture(moon_texture) : nullptr; + } else if (!moon_texture.empty()) { + m_moon_texture = tsrc->getTextureForMesh(moon_texture); + } + + if (m_moon_texture) { + m_materials[4] = baseMaterial(); + m_materials[4].setTexture(0, m_moon_texture); + m_materials[4].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + disableTextureFiltering(m_materials[4]); + m_materials[4].Lighting = !!m_moon_tonemap; } } -void Sky::setStarCount(u16 star_count, bool force_update) +void Sky::setStarCount(u16 star_count) { // Allow force updating star count at game init. - if (m_star_params.count != star_count || force_update) { + if (m_star_params.count != star_count || m_first_update) { m_star_params.count = star_count; updateStars(); } @@ -924,16 +880,6 @@ void Sky::addTextureToSkybox(const std::string &texture, int material_id, m_materials[material_id+5].MaterialType = video::EMT_SOLID; } -// To be called once at game init to setup default values. -void Sky::setSkyDefaults() -{ - SkyboxDefaults sky_defaults; - m_sky_params.sky_color = sky_defaults.getSkyColorDefaults(); - m_sun_params = sky_defaults.getSunDefaults(); - m_moon_params = sky_defaults.getMoonDefaults(); - m_star_params = sky_defaults.getStarDefaults(); -} - float getWickedTimeOfDay(float time_of_day) { float nightlength = 0.415f; diff --git a/src/client/sky.h b/src/client/sky.h index 83106453b..3dc057b70 100644 --- a/src/client/sky.h +++ b/src/client/sky.h @@ -17,6 +17,8 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#pragma once + #include "irrlichttypes_extrabloated.h" #include #include @@ -25,8 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "shader.h" #include "skyparams.h" -#pragma once - #define SKY_MATERIAL_COUNT 12 class ITextureSource; @@ -77,7 +77,7 @@ public: void setMoonScale(f32 moon_scale) { m_moon_params.scale = moon_scale; } void setStarsVisible(bool stars_visible) { m_star_params.visible = stars_visible; } - void setStarCount(u16 star_count, bool force_update); + void setStarCount(u16 star_count); void setStarColor(video::SColor star_color) { m_star_params.starcolor = star_color; } void setStarScale(f32 star_scale) { m_star_params.scale = star_scale; updateStars(); } @@ -150,7 +150,7 @@ private: bool m_visible = true; // Used when m_visible=false video::SColor m_fallback_bg_color = video::SColor(255, 255, 255, 255); - bool m_first_update = true; + bool m_first_update = true; // Set before the sky is updated for the first time float m_time_of_day; float m_time_brightness; bool m_sunlight_seen; @@ -206,7 +206,6 @@ private: void draw_stars(video::IVideoDriver *driver, float wicked_time_of_day); void place_sky_body(std::array &vertices, float horizon_position, float day_position); - void setSkyDefaults(); }; // calculates value for sky body positions for the given observed time of day diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index f7c586b80..47f259b92 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -1242,19 +1242,17 @@ void Client::handleCommand_HudSetSky(NetworkPacket* pkt) } catch (...) {} // Use default skybox settings: - SkyboxDefaults sky_defaults; - SunParams sun = sky_defaults.getSunDefaults(); - MoonParams moon = sky_defaults.getMoonDefaults(); - StarParams stars = sky_defaults.getStarDefaults(); + SunParams sun = SkyboxDefaults::getSunDefaults(); + MoonParams moon = SkyboxDefaults::getMoonDefaults(); + StarParams stars = SkyboxDefaults::getStarDefaults(); // Fix for "regular" skies, as color isn't kept: if (skybox.type == "regular") { - skybox.sky_color = sky_defaults.getSkyColorDefaults(); + skybox.sky_color = SkyboxDefaults::getSkyColorDefaults(); skybox.fog_tint_type = "default"; skybox.fog_moon_tint = video::SColor(255, 255, 255, 255); skybox.fog_sun_tint = video::SColor(255, 255, 255, 255); - } - else { + } else { sun.visible = false; sun.sunrise_visible = false; moon.visible = false; diff --git a/src/remoteplayer.cpp b/src/remoteplayer.cpp index 3f0eae0f0..20be7a8c8 100644 --- a/src/remoteplayer.cpp +++ b/src/remoteplayer.cpp @@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc., /* RemotePlayer */ + // static config cache for remoteplayer bool RemotePlayer::m_setting_cache_loaded = false; float RemotePlayer::m_setting_chat_message_limit_per_10sec = 0.0f; @@ -46,6 +47,7 @@ RemotePlayer::RemotePlayer(const char *name, IItemDefManager *idef): g_settings->getU16("chat_message_limit_trigger_kick"); RemotePlayer::m_setting_cache_loaded = true; } + movement_acceleration_default = g_settings->getFloat("movement_acceleration_default") * BS; movement_acceleration_air = g_settings->getFloat("movement_acceleration_air") * BS; movement_acceleration_fast = g_settings->getFloat("movement_acceleration_fast") * BS; @@ -59,19 +61,12 @@ RemotePlayer::RemotePlayer(const char *name, IItemDefManager *idef): movement_liquid_sink = g_settings->getFloat("movement_liquid_sink") * BS; movement_gravity = g_settings->getFloat("movement_gravity") * BS; - // copy defaults - m_cloud_params.density = 0.4f; - m_cloud_params.color_bright = video::SColor(229, 240, 240, 255); - m_cloud_params.color_ambient = video::SColor(255, 0, 0, 0); - m_cloud_params.height = 120.0f; - m_cloud_params.thickness = 16.0f; - m_cloud_params.speed = v2f(0.0f, -2.0f); - // Skybox defaults: + m_cloud_params = SkyboxDefaults::getCloudDefaults(); m_skybox_params = SkyboxDefaults::getSkyDefaults(); - m_sun_params = SkyboxDefaults::getSunDefaults(); - m_moon_params = SkyboxDefaults::getMoonDefaults(); - m_star_params = SkyboxDefaults::getStarDefaults(); + m_sun_params = SkyboxDefaults::getSunDefaults(); + m_moon_params = SkyboxDefaults::getMoonDefaults(); + m_star_params = SkyboxDefaults::getStarDefaults(); } diff --git a/src/skyparams.h b/src/skyparams.h index cabbf531c..f7f694427 100644 --- a/src/skyparams.h +++ b/src/skyparams.h @@ -82,6 +82,8 @@ struct CloudParams class SkyboxDefaults { public: + SkyboxDefaults() = delete; + static const SkyboxParams getSkyDefaults() { SkyboxParams sky; -- cgit v1.2.3 From 95a775cd3ae5a8281289acb36391b9ef27cc574d Mon Sep 17 00:00:00 2001 From: Vincent Robinson Date: Sat, 22 Jan 2022 15:55:43 -0800 Subject: Bump formspec version (#11980) --- doc/lua_api.txt | 10 ++++++---- src/network/networkprotocol.h | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'src/network') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 2331736c6..e37567ec3 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -2271,18 +2271,20 @@ Examples Version History --------------- -* FORMSPEC VERSION 1: +* Formspec version 1 (pre-5.1.0): * (too much) -* FORMSPEC VERSION 2: +* Formspec version 2 (5.1.0): * Forced real coordinates * background9[]: 9-slice scaling parameters -* FORMSPEC VERSION 3: +* Formspec version 3 (5.2.0): * Formspec elements are drawn in the order of definition * bgcolor[]: use 3 parameters (bgcolor, formspec (now an enum), fbgcolor) * box[] and image[] elements enable clipping by default * new element: scroll_container[] -* FORMSPEC VERSION 4: +* Formspec version 4 (5.4.0): * Allow dropdown indexing events +* Formspec version 5 (5.5.0): + * Added padding[] element Elements -------- diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index 8214cc5b1..7bf5801f5 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -230,7 +230,7 @@ with this program; if not, write to the Free Software Foundation, Inc., // base64-encoded SHA-1 (27+\0). // See also: Formspec Version History in doc/lua_api.txt -#define FORMSPEC_API_VERSION 4 +#define FORMSPEC_API_VERSION 5 #define TEXTURENAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.-" -- cgit v1.2.3 From 5da204f5bcda7a45ce17f04651627fd8a9d70a82 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 30 Jan 2022 21:32:49 +0100 Subject: Get rid of `basic_debug` last minute This isn't a revert but rather just disables the codepaths. also see #12011 --- builtin/game/privileges.lua | 4 ---- src/client/game.cpp | 18 ++++++++---------- src/client/gameui.cpp | 1 - src/network/clientpackethandler.cpp | 5 ----- src/network/networkprotocol.h | 1 - 5 files changed, 8 insertions(+), 21 deletions(-) (limited to 'src/network') diff --git a/builtin/game/privileges.lua b/builtin/game/privileges.lua index 97681655e..2ff4c093c 100644 --- a/builtin/game/privileges.lua +++ b/builtin/game/privileges.lua @@ -97,10 +97,6 @@ core.register_privilege("rollback", { description = S("Can use the rollback functionality"), give_to_singleplayer = false, }) -core.register_privilege("basic_debug", { - description = S("Can view more debug info that might give a gameplay advantage"), - give_to_singleplayer = false, -}) core.register_privilege("debug", { description = S("Can enable wireframe"), give_to_singleplayer = false, diff --git a/src/client/game.cpp b/src/client/game.cpp index 8959b5f15..4337d308e 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1740,7 +1740,7 @@ void Game::processQueues() void Game::updateDebugState() { - bool has_basic_debug = client->checkPrivilege("basic_debug"); + const bool has_basic_debug = true; bool has_debug = client->checkPrivilege("debug"); if (m_game_ui->m_flags.show_basic_debug) { @@ -2211,7 +2211,7 @@ void Game::toggleCinematic() void Game::toggleBlockBounds() { - if (client->checkPrivilege("basic_debug")) { + if (true /* basic_debug */) { enum Hud::BlockBoundsMode newmode = hud->toggleBlockBounds(); switch (newmode) { case Hud::BLOCK_BOUNDS_OFF: @@ -2307,26 +2307,24 @@ void Game::toggleDebug() // The debug text can be in 2 modes: minimal and basic. // * Minimal: Only technical client info that not gameplay-relevant // * Basic: Info that might give gameplay advantage, e.g. pos, angle - // Basic mode is used when player has "basic_debug" priv, - // otherwise the Minimal mode is used. + // Basic mode is always used. + + const bool has_basic_debug = true; if (!m_game_ui->m_flags.show_minimal_debug) { m_game_ui->m_flags.show_minimal_debug = true; - if (client->checkPrivilege("basic_debug")) { + if (has_basic_debug) m_game_ui->m_flags.show_basic_debug = true; - } m_game_ui->m_flags.show_profiler_graph = false; draw_control->show_wireframe = false; m_game_ui->showTranslatedStatusText("Debug info shown"); } else if (!m_game_ui->m_flags.show_profiler_graph && !draw_control->show_wireframe) { - if (client->checkPrivilege("basic_debug")) { + if (has_basic_debug) m_game_ui->m_flags.show_basic_debug = true; - } m_game_ui->m_flags.show_profiler_graph = true; m_game_ui->showTranslatedStatusText("Profiler graph shown"); } else if (!draw_control->show_wireframe && client->checkPrivilege("debug")) { - if (client->checkPrivilege("basic_debug")) { + if (has_basic_debug) m_game_ui->m_flags.show_basic_debug = true; - } m_game_ui->m_flags.show_profiler_graph = false; draw_control->show_wireframe = true; m_game_ui->showTranslatedStatusText("Wireframe shown"); diff --git a/src/client/gameui.cpp b/src/client/gameui.cpp index bae5241b1..8505ea3ae 100644 --- a/src/client/gameui.cpp +++ b/src/client/gameui.cpp @@ -210,7 +210,6 @@ void GameUI::initFlags() { m_flags = GameUI::Flags(); m_flags.show_minimal_debug = g_settings->getBool("show_debug"); - m_flags.show_basic_debug = false; } void GameUI::showMinimap(bool show) diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 47f259b92..48ad60ac6 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -900,11 +900,6 @@ void Client::handleCommand_Privileges(NetworkPacket* pkt) m_privileges.insert(priv); infostream << priv << " "; } - - // Enable basic_debug on server versions before it was added - if (m_proto_ver < 40) - m_privileges.insert("basic_debug"); - infostream << std::endl; } diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index 7bf5801f5..a5ff53216 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -206,7 +206,6 @@ with this program; if not, write to the Free Software Foundation, Inc., Adds new sun, moon and stars packets Minimap modes PROTOCOL VERSION 40: - Added 'basic_debug' privilege TOCLIENT_MEDIA_PUSH changed, TOSERVER_HAVE_MEDIA added */ -- cgit v1.2.3 From 1c73902005bb5c7a40be5571bff9c232d8c69536 Mon Sep 17 00:00:00 2001 From: Jude Melton-Houghton Date: Tue, 1 Feb 2022 20:49:19 -0500 Subject: Clean up ClientInterface locking --- src/clientiface.h | 11 +- src/network/serverpackethandler.cpp | 3 +- src/server.cpp | 255 +++++++++++++++++------------------- 3 files changed, 128 insertions(+), 141 deletions(-) (limited to 'src/network') diff --git a/src/clientiface.h b/src/clientiface.h index b1591ddb0..1be9c972a 100644 --- a/src/clientiface.h +++ b/src/clientiface.h @@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "network/networkprotocol.h" #include "network/address.h" #include "porting.h" +#include "threading/mutex_auto_lock.h" #include #include @@ -503,9 +504,13 @@ public: static std::string state2Name(ClientState state); protected: - //TODO find way to avoid this functions - void lock() { m_clients_mutex.lock(); } - void unlock() { m_clients_mutex.unlock(); } + class AutoLock { + public: + AutoLock(ClientInterface &iface): m_lock(iface.m_clients_mutex) {} + + private: + RecursiveMutexAutoLock m_lock; + }; RemoteClientMap& getClientList() { return m_clients; } diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index 12dc24460..a983424ba 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -452,7 +452,7 @@ void Server::handleCommand_GotBlocks(NetworkPacket* pkt) ("GOTBLOCKS length is too short"); } - m_clients.lock(); + ClientInterface::AutoLock lock(m_clients); RemoteClient *client = m_clients.lockedGetClientNoEx(pkt->getPeerId()); for (u16 i = 0; i < count; i++) { @@ -460,7 +460,6 @@ void Server::handleCommand_GotBlocks(NetworkPacket* pkt) *pkt >> p; client->GotBlock(p); } - m_clients.unlock(); } void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao, diff --git a/src/server.cpp b/src/server.cpp index 23a7dc5a0..df7083b68 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -723,28 +723,29 @@ void Server::AsyncRunStep(bool initial_step) //infostream<<"Server: Checking added and deleted active objects"<set(clients.size()); - for (const auto &client_it : clients) { - RemoteClient *client = client_it.second; + m_player_gauge->set(clients.size()); + for (const auto &client_it : clients) { + RemoteClient *client = client_it.second; - if (client->getState() < CS_DefinitionsSent) - continue; + if (client->getState() < CS_DefinitionsSent) + continue; - // This can happen if the client times out somehow - if (!m_env->getPlayer(client->peer_id)) - continue; + // This can happen if the client times out somehow + if (!m_env->getPlayer(client->peer_id)) + continue; - PlayerSAO *playersao = getPlayerSAO(client->peer_id); - if (!playersao) - continue; + PlayerSAO *playersao = getPlayerSAO(client->peer_id); + if (!playersao) + continue; - SendActiveObjectRemoveAdd(client, playersao); + SendActiveObjectRemoveAdd(client, playersao); + } } - m_clients.unlock(); // Write changes to the mod storage m_mod_storage_save_timer -= dtime; @@ -787,63 +788,64 @@ void Server::AsyncRunStep(bool initial_step) m_aom_buffer_counter->increment(aom_count); - m_clients.lock(); - const RemoteClientMap &clients = m_clients.getClientList(); - // Route data to every client - std::string reliable_data, unreliable_data; - for (const auto &client_it : clients) { - reliable_data.clear(); - unreliable_data.clear(); - RemoteClient *client = client_it.second; - PlayerSAO *player = getPlayerSAO(client->peer_id); - // Go through all objects in message buffer - for (const auto &buffered_message : buffered_messages) { - // If object does not exist or is not known by client, skip it - u16 id = buffered_message.first; - ServerActiveObject *sao = m_env->getActiveObject(id); - if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end()) - continue; + { + ClientInterface::AutoLock clientlock(m_clients); + const RemoteClientMap &clients = m_clients.getClientList(); + // Route data to every client + std::string reliable_data, unreliable_data; + for (const auto &client_it : clients) { + reliable_data.clear(); + unreliable_data.clear(); + RemoteClient *client = client_it.second; + PlayerSAO *player = getPlayerSAO(client->peer_id); + // Go through all objects in message buffer + for (const auto &buffered_message : buffered_messages) { + // If object does not exist or is not known by client, skip it + u16 id = buffered_message.first; + ServerActiveObject *sao = m_env->getActiveObject(id); + if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end()) + continue; - // Get message list of object - std::vector* list = buffered_message.second; - // Go through every message - for (const ActiveObjectMessage &aom : *list) { - // Send position updates to players who do not see the attachment - if (aom.datastring[0] == AO_CMD_UPDATE_POSITION) { - if (sao->getId() == player->getId()) - continue; - - // Do not send position updates for attached players - // as long the parent is known to the client - ServerActiveObject *parent = sao->getParent(); - if (parent && client->m_known_objects.find(parent->getId()) != - client->m_known_objects.end()) - continue; + // Get message list of object + std::vector* list = buffered_message.second; + // Go through every message + for (const ActiveObjectMessage &aom : *list) { + // Send position updates to players who do not see the attachment + if (aom.datastring[0] == AO_CMD_UPDATE_POSITION) { + if (sao->getId() == player->getId()) + continue; + + // Do not send position updates for attached players + // as long the parent is known to the client + ServerActiveObject *parent = sao->getParent(); + if (parent && client->m_known_objects.find(parent->getId()) != + client->m_known_objects.end()) + continue; + } + + // Add full new data to appropriate buffer + std::string &buffer = aom.reliable ? reliable_data : unreliable_data; + char idbuf[2]; + writeU16((u8*) idbuf, aom.id); + // u16 id + // std::string data + buffer.append(idbuf, sizeof(idbuf)); + buffer.append(serializeString16(aom.datastring)); } - - // Add full new data to appropriate buffer - std::string &buffer = aom.reliable ? reliable_data : unreliable_data; - char idbuf[2]; - writeU16((u8*) idbuf, aom.id); - // u16 id - // std::string data - buffer.append(idbuf, sizeof(idbuf)); - buffer.append(serializeString16(aom.datastring)); } - } - /* - reliable_data and unreliable_data are now ready. - Send them. - */ - if (!reliable_data.empty()) { - SendActiveObjectMessages(client->peer_id, reliable_data); - } + /* + reliable_data and unreliable_data are now ready. + Send them. + */ + if (!reliable_data.empty()) { + SendActiveObjectMessages(client->peer_id, reliable_data); + } - if (!unreliable_data.empty()) { - SendActiveObjectMessages(client->peer_id, unreliable_data, false); + if (!unreliable_data.empty()) { + SendActiveObjectMessages(client->peer_id, unreliable_data, false); + } } } - m_clients.unlock(); // Clear buffered_messages for (auto &buffered_message : buffered_messages) { @@ -1050,18 +1052,14 @@ PlayerSAO* Server::StageTwoClientInit(session_t peer_id) { std::string playername; PlayerSAO *playersao = NULL; - m_clients.lock(); - try { + { + ClientInterface::AutoLock clientlock(m_clients); RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone); if (client) { playername = client->getName(); playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version); } - } catch (std::exception &e) { - m_clients.unlock(); - throw; } - m_clients.unlock(); RemotePlayer *player = m_env->getPlayer(playername.c_str()); @@ -1233,13 +1231,12 @@ void Server::onMapEditEvent(const MapEditEvent &event) void Server::SetBlocksNotSent(std::map& block) { std::vector clients = m_clients.getClientIDs(); - m_clients.lock(); + ClientInterface::AutoLock clientlock(m_clients); // Set the modified blocks unsent for all the clients for (const session_t client_id : clients) { if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id)) client->SetBlocksNotSent(block); } - m_clients.unlock(); } void Server::peerAdded(con::Peer *peer) @@ -1267,13 +1264,11 @@ bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* bool Server::getClientInfo(session_t peer_id, ClientInfo &ret) { - m_clients.lock(); + ClientInterface::AutoLock clientlock(m_clients); RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid); - if (!client) { - m_clients.unlock(); + if (!client) return false; - } ret.state = client->getState(); ret.addr = client->getAddress(); @@ -1288,8 +1283,6 @@ bool Server::getClientInfo(session_t peer_id, ClientInfo &ret) ret.lang_code = client->getLangCode(); - m_clients.unlock(); - return true; } @@ -2218,7 +2211,7 @@ void Server::sendRemoveNode(v3s16 p, std::unordered_set *far_players, pkt << p; std::vector clients = m_clients.getClientIDs(); - m_clients.lock(); + ClientInterface::AutoLock clientlock(m_clients); for (session_t client_id : clients) { RemoteClient *client = m_clients.lockedGetClientNoEx(client_id); @@ -2241,8 +2234,6 @@ void Server::sendRemoveNode(v3s16 p, std::unordered_set *far_players, // Send as reliable m_clients.send(client_id, 0, &pkt, true); } - - m_clients.unlock(); } void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set *far_players, @@ -2257,7 +2248,7 @@ void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set *far_player << (u8) (remove_metadata ? 0 : 1); std::vector clients = m_clients.getClientIDs(); - m_clients.lock(); + ClientInterface::AutoLock clientlock(m_clients); for (session_t client_id : clients) { RemoteClient *client = m_clients.lockedGetClientNoEx(client_id); @@ -2280,8 +2271,6 @@ void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set *far_player // Send as reliable m_clients.send(client_id, 0, &pkt, true); } - - m_clients.unlock(); } void Server::sendMetadataChanged(const std::list &meta_updates, float far_d_nodes) @@ -2290,7 +2279,7 @@ void Server::sendMetadataChanged(const std::list &meta_updates, float far NodeMetadataList meta_updates_list(false); std::vector clients = m_clients.getClientIDs(); - m_clients.lock(); + ClientInterface::AutoLock clientlock(m_clients); for (session_t i : clients) { RemoteClient *client = m_clients.lockedGetClientNoEx(i); @@ -2331,8 +2320,6 @@ void Server::sendMetadataChanged(const std::list &meta_updates, float far meta_updates_list.clear(); } - - m_clients.unlock(); } void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver, @@ -2368,7 +2355,7 @@ void Server::SendBlocks(float dtime) std::vector clients = m_clients.getClientIDs(); - m_clients.lock(); + ClientInterface::AutoLock clientlock(m_clients); for (const session_t client_id : clients) { RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active); @@ -2378,7 +2365,6 @@ void Server::SendBlocks(float dtime) total_sending += client->getSendingCount(); client->GetNextBlocks(m_env,m_emerge, dtime, queue); } - m_clients.unlock(); } // Sort. @@ -2386,7 +2372,7 @@ void Server::SendBlocks(float dtime) // Lowest is most important. std::sort(queue.begin(), queue.end()); - m_clients.lock(); + ClientInterface::AutoLock clientlock(m_clients); // Maximal total count calculation // The per-client block sends is halved with the maximal online users @@ -2415,7 +2401,6 @@ void Server::SendBlocks(float dtime) client->SentBlock(block_to_send.pos); total_sending++; } - m_clients.unlock(); } bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos) @@ -2424,15 +2409,12 @@ bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos) if (!block) return false; - m_clients.lock(); + ClientInterface::AutoLock clientlock(m_clients); RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active); - if (!client || client->isBlockSent(blockpos)) { - m_clients.unlock(); + if (!client || client->isBlockSent(blockpos)) return false; - } SendBlockNoLock(peer_id, block, client->serialization_version, client->net_proto_version); - m_clients.unlock(); return true; } @@ -3534,48 +3516,49 @@ bool Server::dynamicAddMedia(std::string filepath, legacy_pkt.putLongString(filedata); std::unordered_set delivered, waiting; - m_clients.lock(); - for (auto &pair : m_clients.getClientList()) { - if (pair.second->getState() == CS_DefinitionsSent && !ephemeral) { - /* - If a client is in the DefinitionsSent state it is too late to - transfer the file via sendMediaAnnouncement() but at the same - time the client cannot accept a media push yet. - Short of artificially delaying the joining process there is no - way for the server to resolve this so we (currently) opt not to. - */ - warningstream << "The media \"" << filename << "\" (dynamic) could " - "not be delivered to " << pair.second->getName() - << " due to a race condition." << std::endl; - continue; - } - if (pair.second->getState() < CS_Active) - continue; + { + ClientInterface::AutoLock clientlock(m_clients); + for (auto &pair : m_clients.getClientList()) { + if (pair.second->getState() == CS_DefinitionsSent && !ephemeral) { + /* + If a client is in the DefinitionsSent state it is too late to + transfer the file via sendMediaAnnouncement() but at the same + time the client cannot accept a media push yet. + Short of artificially delaying the joining process there is no + way for the server to resolve this so we (currently) opt not to. + */ + warningstream << "The media \"" << filename << "\" (dynamic) could " + "not be delivered to " << pair.second->getName() + << " due to a race condition." << std::endl; + continue; + } + if (pair.second->getState() < CS_Active) + continue; - const auto proto_ver = pair.second->net_proto_version; - if (proto_ver < 39) - continue; + const auto proto_ver = pair.second->net_proto_version; + if (proto_ver < 39) + continue; - const session_t peer_id = pair.second->peer_id; - if (!to_player.empty() && getPlayerName(peer_id) != to_player) - continue; + const session_t peer_id = pair.second->peer_id; + if (!to_player.empty() && getPlayerName(peer_id) != to_player) + continue; - if (proto_ver < 40) { - delivered.emplace(peer_id); - /* - The network layer only guarantees ordered delivery inside a channel. - Since the very next packet could be one that uses the media, we have - to push the media over ALL channels to ensure it is processed before - it is used. In practice this means channels 1 and 0. - */ - m_clients.send(peer_id, 1, &legacy_pkt, true); - m_clients.send(peer_id, 0, &legacy_pkt, true); - } else { - waiting.emplace(peer_id); - Send(peer_id, &pkt); + if (proto_ver < 40) { + delivered.emplace(peer_id); + /* + The network layer only guarantees ordered delivery inside a channel. + Since the very next packet could be one that uses the media, we have + to push the media over ALL channels to ensure it is processed before + it is used. In practice this means channels 1 and 0. + */ + m_clients.send(peer_id, 1, &legacy_pkt, true); + m_clients.send(peer_id, 0, &legacy_pkt, true); + } else { + waiting.emplace(peer_id); + Send(peer_id, &pkt); + } } } - m_clients.unlock(); // Run callback for players that already had the file delivered (legacy-only) for (session_t peer_id : delivered) { -- cgit v1.2.3 From c31b3017222edd6e93bdeb02f05a3df7b6b23a1a Mon Sep 17 00:00:00 2001 From: sfan5 Date: Mon, 14 Feb 2022 21:01:42 +0100 Subject: Clean up ClientReady packet handling fixes #12073 --- src/network/serverpackethandler.cpp | 56 ++++++++++++++++--------------------- src/remoteplayer.h | 4 +-- src/server.cpp | 19 +++++++------ 3 files changed, 35 insertions(+), 44 deletions(-) (limited to 'src/network') diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index a983424ba..8163cb820 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -380,55 +380,47 @@ void Server::handleCommand_ClientReady(NetworkPacket* pkt) { session_t peer_id = pkt->getPeerId(); - PlayerSAO* playersao = StageTwoClientInit(peer_id); - - if (playersao == NULL) { - errorstream << "TOSERVER_CLIENT_READY stage 2 client init failed " - "peer_id=" << peer_id << std::endl; - DisconnectPeer(peer_id); - return; - } - - - if (pkt->getSize() < 8) { - errorstream << "TOSERVER_CLIENT_READY client sent inconsistent data, " - "disconnecting peer_id: " << peer_id << std::endl; - DisconnectPeer(peer_id); - return; - } - + // decode all information first u8 major_ver, minor_ver, patch_ver, reserved; + u16 formspec_ver = 1; // v1 for clients older than 5.1.0-dev std::string full_ver; + *pkt >> major_ver >> minor_ver >> patch_ver >> reserved >> full_ver; + if (pkt->getRemainingBytes() >= 2) + *pkt >> formspec_ver; m_clients.setClientVersion(peer_id, major_ver, minor_ver, patch_ver, full_ver); - if (pkt->getRemainingBytes() >= 2) - *pkt >> playersao->getPlayer()->formspec_version; - - const std::vector &players = m_clients.getPlayerNames(); - NetworkPacket list_pkt(TOCLIENT_UPDATE_PLAYER_LIST, 0, peer_id); - list_pkt << (u8) PLAYER_LIST_INIT << (u16) players.size(); - for (const std::string &player: players) { - list_pkt << player; + // Emerge player + PlayerSAO* playersao = StageTwoClientInit(peer_id); + if (!playersao) { + errorstream << "Server: stage 2 client init failed " + "peer_id=" << peer_id << std::endl; + DisconnectPeer(peer_id); + return; } - m_clients.send(peer_id, 0, &list_pkt, true); - NetworkPacket notice_pkt(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT); - // (u16) 1 + std::string represents a pseudo vector serialization representation - notice_pkt << (u8) PLAYER_LIST_ADD << (u16) 1 << std::string(playersao->getPlayer()->getName()); - m_clients.sendToAll(¬ice_pkt); + playersao->getPlayer()->formspec_version = formspec_ver; m_clients.event(peer_id, CSE_SetClientReady); + // Send player list to this client + { + const std::vector &players = m_clients.getPlayerNames(); + NetworkPacket list_pkt(TOCLIENT_UPDATE_PLAYER_LIST, 0, peer_id); + list_pkt << (u8) PLAYER_LIST_INIT << (u16) players.size(); + for (const auto &player : players) + list_pkt << player; + Send(peer_id, &list_pkt); + } + s64 last_login; m_script->getAuth(playersao->getPlayer()->getName(), nullptr, nullptr, &last_login); m_script->on_joinplayer(playersao, last_login); // Send shutdown timer if shutdown has been scheduled - if (m_shutdown_state.isTimerRunning()) { + if (m_shutdown_state.isTimerRunning()) SendChatMessage(peer_id, m_shutdown_state.getShutdownTimerMessage()); - } } void Server::handleCommand_GotBlocks(NetworkPacket* pkt) diff --git a/src/remoteplayer.h b/src/remoteplayer.h index c8991480b..e33630841 100644 --- a/src/remoteplayer.h +++ b/src/remoteplayer.h @@ -128,9 +128,7 @@ public: void setDirty(bool dirty) { m_dirty = true; } u16 protocol_version = 0; - - // v1 for clients older than 5.1.0-dev - u16 formspec_version = 1; + u16 formspec_version = 0; session_t getPeerId() const { return m_peer_id; } diff --git a/src/server.cpp b/src/server.cpp index 76345686a..685d8bb25 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1104,20 +1104,21 @@ PlayerSAO* Server::StageTwoClientInit(session_t peer_id) SendPlayerBreath(playersao); /* - Print out action + Update player list and print action */ { - Address addr = getPeerAddress(player->getPeerId()); - std::string ip_str = addr.serializeString(); - const std::vector &names = m_clients.getPlayerNames(); + NetworkPacket notice_pkt(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT); + notice_pkt << (u8) PLAYER_LIST_ADD << (u16) 1 << std::string(player->getName()); + m_clients.sendToAll(¬ice_pkt); + } + { + std::string ip_str = getPeerAddress(player->getPeerId()).serializeString(); + const auto &names = m_clients.getPlayerNames(); actionstream << player->getName() << " [" << ip_str << "] joins game. List of players: "; - - for (const std::string &name : names) { + for (const std::string &name : names) actionstream << name << " "; - } - - actionstream << player->getName() <getName() << std::endl; } return playersao; } -- cgit v1.2.3 From 0f25fa7af655b98fa401176a523f269c843d1943 Mon Sep 17 00:00:00 2001 From: x2048 Date: Sat, 26 Mar 2022 16:58:26 +0100 Subject: Add API to control shadow intensity from the game/mod (#11944) * Also Disable shadows when sun/moon is hidden. Fixes #11972. --- builtin/settingtypes.txt | 5 +- client/shaders/nodes_shader/opengl_fragment.glsl | 85 ++++++++++---------- client/shaders/nodes_shader/opengl_vertex.glsl | 57 +++++++------- client/shaders/object_shader/opengl_fragment.glsl | 84 ++++++++++---------- client/shaders/object_shader/opengl_vertex.glsl | 56 ++++++------- doc/lua_api.txt | 7 ++ games/devtest/mods/experimental/init.lua | 1 + games/devtest/mods/experimental/lighting.lua | 8 ++ src/client/client.h | 1 + src/client/game.cpp | 7 +- src/client/localplayer.h | 4 + src/client/shadows/dynamicshadowsrender.cpp | 95 ++++++++++++++++------- src/client/shadows/dynamicshadowsrender.h | 10 ++- src/client/sky.h | 2 + src/defaultsettings.cpp | 2 +- src/lighting.h | 27 +++++++ src/network/clientopcodes.cpp | 1 + src/network/clientpackethandler.cpp | 8 ++ src/network/networkprotocol.h | 7 +- src/remoteplayer.h | 7 ++ src/script/lua_api/l_object.cpp | 43 ++++++++++ src/script/lua_api/l_object.h | 6 ++ src/server.cpp | 17 ++++ src/server.h | 4 + 24 files changed, 375 insertions(+), 169 deletions(-) create mode 100644 games/devtest/mods/experimental/lighting.lua create mode 100644 src/lighting.h (limited to 'src/network') diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index ff2d72927..3dc165bd1 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -592,9 +592,10 @@ enable_waving_plants (Waving plants) bool false # Requires shaders to be enabled. enable_dynamic_shadows (Dynamic shadows) bool false -# Set the shadow strength. +# Set the shadow strength gamma. +# Adjusts the intensity of in-game dynamic shadows. # Lower value means lighter shadows, higher value means darker shadows. -shadow_strength (Shadow strength) float 0.2 0.05 1.0 +shadow_strength_gamma (Shadow strength gamma) float 1.0 0.1 10.0 # Maximum distance to render shadows. shadow_map_max_distance (Shadow map max distance in nodes to render shadows) float 120.0 10.0 1000.0 diff --git a/client/shaders/nodes_shader/opengl_fragment.glsl b/client/shaders/nodes_shader/opengl_fragment.glsl index e5f5c703a..adc8adccb 100644 --- a/client/shaders/nodes_shader/opengl_fragment.glsl +++ b/client/shaders/nodes_shader/opengl_fragment.glsl @@ -16,6 +16,7 @@ uniform float animationTimer; uniform float f_textureresolution; uniform mat4 m_ShadowViewProj; uniform float f_shadowfar; + uniform float f_shadow_strength; varying float normalOffsetScale; varying float adj_shadow_strength; varying float cosLight; @@ -483,55 +484,57 @@ void main(void) vec4 col = vec4(color.rgb * varColor.rgb, 1.0); #ifdef ENABLE_DYNAMIC_SHADOWS - float shadow_int = 0.0; - vec3 shadow_color = vec3(0.0, 0.0, 0.0); - vec3 posLightSpace = getLightSpacePosition(); + if (f_shadow_strength > 0.0) { + float shadow_int = 0.0; + vec3 shadow_color = vec3(0.0, 0.0, 0.0); + vec3 posLightSpace = getLightSpacePosition(); - float distance_rate = (1 - pow(clamp(2.0 * length(posLightSpace.xy - 0.5),0.0,1.0), 20.0)); - float f_adj_shadow_strength = max(adj_shadow_strength-mtsmoothstep(0.9,1.1, posLightSpace.z ),0.0); + float distance_rate = (1 - pow(clamp(2.0 * length(posLightSpace.xy - 0.5),0.0,1.0), 20.0)); + float f_adj_shadow_strength = max(adj_shadow_strength-mtsmoothstep(0.9,1.1, posLightSpace.z ),0.0); - if (distance_rate > 1e-7) { - + if (distance_rate > 1e-7) { + #ifdef COLORED_SHADOWS - vec4 visibility; - if (cosLight > 0.0) - visibility = getShadowColor(ShadowMapSampler, posLightSpace.xy, posLightSpace.z); - else - visibility = vec4(1.0, 0.0, 0.0, 0.0); - shadow_int = visibility.r; - shadow_color = visibility.gba; + vec4 visibility; + if (cosLight > 0.0) + visibility = getShadowColor(ShadowMapSampler, posLightSpace.xy, posLightSpace.z); + else + visibility = vec4(1.0, 0.0, 0.0, 0.0); + shadow_int = visibility.r; + shadow_color = visibility.gba; #else - if (cosLight > 0.0) - shadow_int = getShadow(ShadowMapSampler, posLightSpace.xy, posLightSpace.z); - else - shadow_int = 1.0; + if (cosLight > 0.0) + shadow_int = getShadow(ShadowMapSampler, posLightSpace.xy, posLightSpace.z); + else + shadow_int = 1.0; #endif - shadow_int *= distance_rate; - shadow_int = clamp(shadow_int, 0.0, 1.0); + shadow_int *= distance_rate; + shadow_int = clamp(shadow_int, 0.0, 1.0); - } + } - // turns out that nightRatio falls off much faster than - // actual brightness of artificial light in relation to natual light. - // Power ratio was measured on torches in MTG (brightness = 14). - float adjusted_night_ratio = pow(max(0.0, nightRatio), 0.6); - - // Apply self-shadowing when light falls at a narrow angle to the surface - // Cosine of the cut-off angle. - const float self_shadow_cutoff_cosine = 0.035; - if (f_normal_length != 0 && cosLight < self_shadow_cutoff_cosine) { - shadow_int = max(shadow_int, 1 - clamp(cosLight, 0.0, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine); - shadow_color = mix(vec3(0.0), shadow_color, min(cosLight, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine); - } + // turns out that nightRatio falls off much faster than + // actual brightness of artificial light in relation to natual light. + // Power ratio was measured on torches in MTG (brightness = 14). + float adjusted_night_ratio = pow(max(0.0, nightRatio), 0.6); + + // Apply self-shadowing when light falls at a narrow angle to the surface + // Cosine of the cut-off angle. + const float self_shadow_cutoff_cosine = 0.035; + if (f_normal_length != 0 && cosLight < self_shadow_cutoff_cosine) { + shadow_int = max(shadow_int, 1 - clamp(cosLight, 0.0, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine); + shadow_color = mix(vec3(0.0), shadow_color, min(cosLight, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine); + } - shadow_int *= f_adj_shadow_strength; - - // calculate fragment color from components: - col.rgb = - adjusted_night_ratio * col.rgb + // artificial light - (1.0 - adjusted_night_ratio) * ( // natural light - col.rgb * (1.0 - shadow_int * (1.0 - shadow_color)) + // filtered texture color - dayLight * shadow_color * shadow_int); // reflected filtered sunlight/moonlight + shadow_int *= f_adj_shadow_strength; + + // calculate fragment color from components: + col.rgb = + adjusted_night_ratio * col.rgb + // artificial light + (1.0 - adjusted_night_ratio) * ( // natural light + col.rgb * (1.0 - shadow_int * (1.0 - shadow_color)) + // filtered texture color + dayLight * shadow_color * shadow_int); // reflected filtered sunlight/moonlight + } #endif #if ENABLE_TONE_MAPPING diff --git a/client/shaders/nodes_shader/opengl_vertex.glsl b/client/shaders/nodes_shader/opengl_vertex.glsl index 95cd138a8..5e77ac719 100644 --- a/client/shaders/nodes_shader/opengl_vertex.glsl +++ b/client/shaders/nodes_shader/opengl_vertex.glsl @@ -195,34 +195,35 @@ void main(void) varColor = clamp(color, 0.0, 1.0); #ifdef ENABLE_DYNAMIC_SHADOWS - vec3 nNormal = normalize(vNormal); - cosLight = dot(nNormal, -v_LightDirection); - - // Calculate normal offset scale based on the texel size adjusted for - // curvature of the SM texture. This code must be change together with - // getPerspectiveFactor or any light-space transformation. - vec3 eyeToVertex = worldPosition - eyePosition + cameraOffset; - // Distance from the vertex to the player - float distanceToPlayer = length(eyeToVertex - v_LightDirection * dot(eyeToVertex, v_LightDirection)) / f_shadowfar; - // perspective factor estimation according to the - float perspectiveFactor = distanceToPlayer * bias0 + bias1; - float texelSize = f_shadowfar * perspectiveFactor * perspectiveFactor / - (f_textureresolution * bias1 - perspectiveFactor * bias0); - float slopeScale = clamp(pow(1.0 - cosLight*cosLight, 0.5), 0.0, 1.0); - normalOffsetScale = texelSize * slopeScale; - - if (f_timeofday < 0.2) { - adj_shadow_strength = f_shadow_strength * 0.5 * - (1.0 - mtsmoothstep(0.18, 0.2, f_timeofday)); - } else if (f_timeofday >= 0.8) { - adj_shadow_strength = f_shadow_strength * 0.5 * - mtsmoothstep(0.8, 0.83, f_timeofday); - } else { - adj_shadow_strength = f_shadow_strength * - mtsmoothstep(0.20, 0.25, f_timeofday) * - (1.0 - mtsmoothstep(0.7, 0.8, f_timeofday)); + if (f_shadow_strength > 0.0) { + vec3 nNormal = normalize(vNormal); + cosLight = dot(nNormal, -v_LightDirection); + + // Calculate normal offset scale based on the texel size adjusted for + // curvature of the SM texture. This code must be change together with + // getPerspectiveFactor or any light-space transformation. + vec3 eyeToVertex = worldPosition - eyePosition + cameraOffset; + // Distance from the vertex to the player + float distanceToPlayer = length(eyeToVertex - v_LightDirection * dot(eyeToVertex, v_LightDirection)) / f_shadowfar; + // perspective factor estimation according to the + float perspectiveFactor = distanceToPlayer * bias0 + bias1; + float texelSize = f_shadowfar * perspectiveFactor * perspectiveFactor / + (f_textureresolution * bias1 - perspectiveFactor * bias0); + float slopeScale = clamp(pow(1.0 - cosLight*cosLight, 0.5), 0.0, 1.0); + normalOffsetScale = texelSize * slopeScale; + + if (f_timeofday < 0.2) { + adj_shadow_strength = f_shadow_strength * 0.5 * + (1.0 - mtsmoothstep(0.18, 0.2, f_timeofday)); + } else if (f_timeofday >= 0.8) { + adj_shadow_strength = f_shadow_strength * 0.5 * + mtsmoothstep(0.8, 0.83, f_timeofday); + } else { + adj_shadow_strength = f_shadow_strength * + mtsmoothstep(0.20, 0.25, f_timeofday) * + (1.0 - mtsmoothstep(0.7, 0.8, f_timeofday)); + } + f_normal_length = length(vNormal); } - f_normal_length = length(vNormal); #endif - } diff --git a/client/shaders/object_shader/opengl_fragment.glsl b/client/shaders/object_shader/opengl_fragment.glsl index fdfcec0c8..edb9d2bb1 100644 --- a/client/shaders/object_shader/opengl_fragment.glsl +++ b/client/shaders/object_shader/opengl_fragment.glsl @@ -34,6 +34,8 @@ const float fogShadingParameter = 1.0 / (1.0 - fogStart); uniform float f_textureresolution; uniform mat4 m_ShadowViewProj; uniform float f_shadowfar; + uniform float f_timeofday; + uniform float f_shadow_strength; varying float normalOffsetScale; varying float adj_shadow_strength; varying float cosLight; @@ -470,55 +472,57 @@ void main(void) col.rgb *= vIDiff; #ifdef ENABLE_DYNAMIC_SHADOWS - float shadow_int = 0.0; - vec3 shadow_color = vec3(0.0, 0.0, 0.0); - vec3 posLightSpace = getLightSpacePosition(); + if (f_shadow_strength > 0.0) { + float shadow_int = 0.0; + vec3 shadow_color = vec3(0.0, 0.0, 0.0); + vec3 posLightSpace = getLightSpacePosition(); - float distance_rate = (1 - pow(clamp(2.0 * length(posLightSpace.xy - 0.5),0.0,1.0), 20.0)); - float f_adj_shadow_strength = max(adj_shadow_strength-mtsmoothstep(0.9,1.1, posLightSpace.z ),0.0); + float distance_rate = (1 - pow(clamp(2.0 * length(posLightSpace.xy - 0.5),0.0,1.0), 20.0)); + float f_adj_shadow_strength = max(adj_shadow_strength-mtsmoothstep(0.9,1.1, posLightSpace.z ),0.0); - if (distance_rate > 1e-7) { + if (distance_rate > 1e-7) { #ifdef COLORED_SHADOWS - vec4 visibility; - if (cosLight > 0.0) - visibility = getShadowColor(ShadowMapSampler, posLightSpace.xy, posLightSpace.z); - else - visibility = vec4(1.0, 0.0, 0.0, 0.0); - shadow_int = visibility.r; - shadow_color = visibility.gba; + vec4 visibility; + if (cosLight > 0.0) + visibility = getShadowColor(ShadowMapSampler, posLightSpace.xy, posLightSpace.z); + else + visibility = vec4(1.0, 0.0, 0.0, 0.0); + shadow_int = visibility.r; + shadow_color = visibility.gba; #else - if (cosLight > 0.0) - shadow_int = getShadow(ShadowMapSampler, posLightSpace.xy, posLightSpace.z); - else - shadow_int = 1.0; + if (cosLight > 0.0) + shadow_int = getShadow(ShadowMapSampler, posLightSpace.xy, posLightSpace.z); + else + shadow_int = 1.0; #endif - shadow_int *= distance_rate; - shadow_int = clamp(shadow_int, 0.0, 1.0); + shadow_int *= distance_rate; + shadow_int = clamp(shadow_int, 0.0, 1.0); - } + } - // turns out that nightRatio falls off much faster than - // actual brightness of artificial light in relation to natual light. - // Power ratio was measured on torches in MTG (brightness = 14). - float adjusted_night_ratio = pow(max(0.0, nightRatio), 0.6); - - // cosine of the normal-to-light angle when - // we start to apply self-shadowing - const float self_shadow_cutoff_cosine = 0.14; - if (f_normal_length != 0 && cosLight < self_shadow_cutoff_cosine) { - shadow_int = max(shadow_int, 1 - clamp(cosLight, 0.0, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine); - shadow_color = mix(vec3(0.0), shadow_color, min(cosLight, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine); - } + // turns out that nightRatio falls off much faster than + // actual brightness of artificial light in relation to natual light. + // Power ratio was measured on torches in MTG (brightness = 14). + float adjusted_night_ratio = pow(max(0.0, nightRatio), 0.6); + + // cosine of the normal-to-light angle when + // we start to apply self-shadowing + const float self_shadow_cutoff_cosine = 0.14; + if (f_normal_length != 0 && cosLight < self_shadow_cutoff_cosine) { + shadow_int = max(shadow_int, 1 - clamp(cosLight, 0.0, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine); + shadow_color = mix(vec3(0.0), shadow_color, min(cosLight, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine); + } - shadow_int *= f_adj_shadow_strength; - - // calculate fragment color from components: - col.rgb = - adjusted_night_ratio * col.rgb + // artificial light - (1.0 - adjusted_night_ratio) * ( // natural light - col.rgb * (1.0 - shadow_int * (1.0 - shadow_color)) + // filtered texture color - dayLight * shadow_color * shadow_int); // reflected filtered sunlight/moonlight + shadow_int *= f_adj_shadow_strength; + + // calculate fragment color from components: + col.rgb = + adjusted_night_ratio * col.rgb + // artificial light + (1.0 - adjusted_night_ratio) * ( // natural light + col.rgb * (1.0 - shadow_int * (1.0 - shadow_color)) + // filtered texture color + dayLight * shadow_color * shadow_int); // reflected filtered sunlight/moonlight + } #endif #if ENABLE_TONE_MAPPING diff --git a/client/shaders/object_shader/opengl_vertex.glsl b/client/shaders/object_shader/opengl_vertex.glsl index 185551c58..ff0067302 100644 --- a/client/shaders/object_shader/opengl_vertex.glsl +++ b/client/shaders/object_shader/opengl_vertex.glsl @@ -105,33 +105,35 @@ void main(void) #ifdef ENABLE_DYNAMIC_SHADOWS - vec3 nNormal = normalize(vNormal); - cosLight = dot(nNormal, -v_LightDirection); - - // Calculate normal offset scale based on the texel size adjusted for - // curvature of the SM texture. This code must be change together with - // getPerspectiveFactor or any light-space transformation. - vec3 eyeToVertex = worldPosition - eyePosition + cameraOffset; - // Distance from the vertex to the player - float distanceToPlayer = length(eyeToVertex - v_LightDirection * dot(eyeToVertex, v_LightDirection)) / f_shadowfar; - // perspective factor estimation according to the - float perspectiveFactor = distanceToPlayer * bias0 + bias1; - float texelSize = f_shadowfar * perspectiveFactor * perspectiveFactor / - (f_textureresolution * bias1 - perspectiveFactor * bias0); - float slopeScale = clamp(pow(1.0 - cosLight*cosLight, 0.5), 0.0, 1.0); - normalOffsetScale = texelSize * slopeScale; - - if (f_timeofday < 0.2) { - adj_shadow_strength = f_shadow_strength * 0.5 * - (1.0 - mtsmoothstep(0.18, 0.2, f_timeofday)); - } else if (f_timeofday >= 0.8) { - adj_shadow_strength = f_shadow_strength * 0.5 * - mtsmoothstep(0.8, 0.83, f_timeofday); - } else { - adj_shadow_strength = f_shadow_strength * - mtsmoothstep(0.20, 0.25, f_timeofday) * - (1.0 - mtsmoothstep(0.7, 0.8, f_timeofday)); + if (f_shadow_strength > 0.0) { + vec3 nNormal = normalize(vNormal); + cosLight = dot(nNormal, -v_LightDirection); + + // Calculate normal offset scale based on the texel size adjusted for + // curvature of the SM texture. This code must be change together with + // getPerspectiveFactor or any light-space transformation. + vec3 eyeToVertex = worldPosition - eyePosition + cameraOffset; + // Distance from the vertex to the player + float distanceToPlayer = length(eyeToVertex - v_LightDirection * dot(eyeToVertex, v_LightDirection)) / f_shadowfar; + // perspective factor estimation according to the + float perspectiveFactor = distanceToPlayer * bias0 + bias1; + float texelSize = f_shadowfar * perspectiveFactor * perspectiveFactor / + (f_textureresolution * bias1 - perspectiveFactor * bias0); + float slopeScale = clamp(pow(1.0 - cosLight*cosLight, 0.5), 0.0, 1.0); + normalOffsetScale = texelSize * slopeScale; + + if (f_timeofday < 0.2) { + adj_shadow_strength = f_shadow_strength * 0.5 * + (1.0 - mtsmoothstep(0.18, 0.2, f_timeofday)); + } else if (f_timeofday >= 0.8) { + adj_shadow_strength = f_shadow_strength * 0.5 * + mtsmoothstep(0.8, 0.83, f_timeofday); + } else { + adj_shadow_strength = f_shadow_strength * + mtsmoothstep(0.20, 0.25, f_timeofday) * + (1.0 - mtsmoothstep(0.7, 0.8, f_timeofday)); + } + f_normal_length = length(vNormal); } - f_normal_length = length(vNormal); #endif } diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 52da17e9c..029c53616 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -7019,6 +7019,13 @@ object you are working with still exists. * Returns `false` if failed. * Resource intensive - use sparsely * To get blockpos, integer divide pos by 16 +* `set_lighting(light_definition)`: sets lighting for the player + * `light_definition` is a table with the following optional fields: + * `shadows` is a table that controls ambient shadows + * `intensity` sets the intensity of the shadows from 0 (no shadows, default) to 1 (blackness) + * Returns true on success. +* `get_lighting()`: returns the current state of lighting for the player. + * Result is a table with the same fields as `light_definition` in `set_lighting`. `PcgRandom` ----------- diff --git a/games/devtest/mods/experimental/init.lua b/games/devtest/mods/experimental/init.lua index b292f792e..70091179c 100644 --- a/games/devtest/mods/experimental/init.lua +++ b/games/devtest/mods/experimental/init.lua @@ -7,6 +7,7 @@ experimental = {} dofile(minetest.get_modpath("experimental").."/detached.lua") dofile(minetest.get_modpath("experimental").."/items.lua") dofile(minetest.get_modpath("experimental").."/commands.lua") +dofile(minetest.get_modpath("experimental").."/lighting.lua") function experimental.print_to_everything(msg) minetest.log("action", msg) diff --git a/games/devtest/mods/experimental/lighting.lua b/games/devtest/mods/experimental/lighting.lua new file mode 100644 index 000000000..2b350550f --- /dev/null +++ b/games/devtest/mods/experimental/lighting.lua @@ -0,0 +1,8 @@ +core.register_chatcommand("set_lighting", { + params = "shadow_intensity", + description = "Set lighting parameters.", + func = function(player_name, param) + local shadow_intensity = tonumber(param) + minetest.get_player_by_name(player_name):set_lighting({shadows = { intensity = shadow_intensity} }) + end +}) \ No newline at end of file diff --git a/src/client/client.h b/src/client/client.h index 84c85471d..0e29fdbe2 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -227,6 +227,7 @@ public: void handleCommand_PlayerSpeed(NetworkPacket *pkt); void handleCommand_MediaPush(NetworkPacket *pkt); void handleCommand_MinimapModes(NetworkPacket *pkt); + void handleCommand_SetLighting(NetworkPacket *pkt); void ProcessData(NetworkPacket *pkt); diff --git a/src/client/game.cpp b/src/client/game.cpp index 7450fb91c..edc69dcc2 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -4037,7 +4037,12 @@ void Game::updateShadows() float in_timeofday = fmod(runData.time_of_day_smooth, 1.0f); - float timeoftheday = fmod(getWickedTimeOfDay(in_timeofday) + 0.75f, 0.5f) + 0.25f; + float timeoftheday = getWickedTimeOfDay(in_timeofday); + bool is_day = timeoftheday > 0.25 && timeoftheday < 0.75; + bool is_shadow_visible = is_day ? sky->getSunVisible() : sky->getMoonVisible(); + shadow->setShadowIntensity(is_shadow_visible ? client->getEnv().getLocalPlayer()->getLighting().shadow_intensity : 0.0f); + + timeoftheday = fmod(timeoftheday + 0.75f, 0.5f) + 0.25f; const float offset_constant = 10000.0f; v3f light(0.0f, 0.0f, -1.0f); diff --git a/src/client/localplayer.h b/src/client/localplayer.h index 577be2803..3d0072fc1 100644 --- a/src/client/localplayer.h +++ b/src/client/localplayer.h @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "environment.h" #include "constants.h" #include "settings.h" +#include "lighting.h" #include class Client; @@ -158,6 +159,8 @@ public: added_velocity += vel; } + inline Lighting& getLighting() { return m_lighting; } + private: void accelerate(const v3f &target_speed, const f32 max_increase_H, const f32 max_increase_V, const bool use_pitch); @@ -209,4 +212,5 @@ private: GenericCAO *m_cao = nullptr; Client *m_client; + Lighting m_lighting; }; diff --git a/src/client/shadows/dynamicshadowsrender.cpp b/src/client/shadows/dynamicshadowsrender.cpp index 528415aaf..24adb21e2 100644 --- a/src/client/shadows/dynamicshadowsrender.cpp +++ b/src/client/shadows/dynamicshadowsrender.cpp @@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include +#include #include "client/shadows/dynamicshadowsrender.h" #include "client/shadows/shadowsScreenQuad.h" #include "client/shadows/shadowsshadercallbacks.h" @@ -33,9 +34,13 @@ ShadowRenderer::ShadowRenderer(IrrlichtDevice *device, Client *client) : m_device(device), m_smgr(device->getSceneManager()), m_driver(device->getVideoDriver()), m_client(client), m_current_frame(0) { + m_shadows_supported = true; // assume shadows supported. We will check actual support in initialize m_shadows_enabled = true; - m_shadow_strength = g_settings->getFloat("shadow_strength"); + m_shadow_strength_gamma = g_settings->getFloat("shadow_strength_gamma"); + if (std::isnan(m_shadow_strength_gamma)) + m_shadow_strength_gamma = 1.0f; + m_shadow_strength_gamma = core::clamp(m_shadow_strength_gamma, 0.1f, 10.0f); m_shadow_map_max_distance = g_settings->getFloat("shadow_map_max_distance"); @@ -49,6 +54,9 @@ ShadowRenderer::ShadowRenderer(IrrlichtDevice *device, Client *client) : ShadowRenderer::~ShadowRenderer() { + // call to disable releases dynamically allocated resources + disable(); + if (m_shadow_depth_cb) delete m_shadow_depth_cb; if (m_shadow_mix_cb) @@ -72,15 +80,25 @@ ShadowRenderer::~ShadowRenderer() m_driver->removeTexture(shadowMapClientMapFuture); } +void ShadowRenderer::disable() +{ + m_shadows_enabled = false; + if (shadowMapTextureFinal) { + m_driver->setRenderTarget(shadowMapTextureFinal, true, true, + video::SColor(255, 255, 255, 255)); + m_driver->setRenderTarget(0, true, true); + } +} + void ShadowRenderer::initialize() { auto *gpu = m_driver->getGPUProgrammingServices(); // we need glsl - if (m_shadows_enabled && gpu && m_driver->queryFeature(video::EVDF_ARB_GLSL)) { + if (m_shadows_supported && gpu && m_driver->queryFeature(video::EVDF_ARB_GLSL)) { createShaders(); } else { - m_shadows_enabled = false; + m_shadows_supported = false; warningstream << "Shadows: GLSL Shader not supported on this system." << std::endl; @@ -94,6 +112,8 @@ void ShadowRenderer::initialize() m_texture_format_color = m_shadow_map_texture_32bit ? video::ECOLOR_FORMAT::ECF_G32R32F : video::ECOLOR_FORMAT::ECF_G16R16F; + + m_shadows_enabled &= m_shadows_supported; } @@ -124,6 +144,16 @@ f32 ShadowRenderer::getMaxShadowFar() const return 0.0f; } +void ShadowRenderer::setShadowIntensity(float shadow_intensity) +{ + m_shadow_strength = pow(shadow_intensity, 1.0f / m_shadow_strength_gamma); + if (m_shadow_strength > 1E-2) + enable(); + else + disable(); +} + + void ShadowRenderer::addNodeToShadowList( scene::ISceneNode *node, E_SHADOW_MODE shadowMode) { @@ -153,6 +183,7 @@ void ShadowRenderer::updateSMTextures() shadowMapTextureDynamicObjects = getSMTexture( std::string("shadow_dynamic_") + itos(m_shadow_map_texture_size), m_texture_format, true); + assert(shadowMapTextureDynamicObjects != nullptr); } if (!shadowMapClientMap) { @@ -161,6 +192,7 @@ void ShadowRenderer::updateSMTextures() std::string("shadow_clientmap_") + itos(m_shadow_map_texture_size), m_shadow_map_colored ? m_texture_format_color : m_texture_format, true); + assert(shadowMapClientMap != nullptr); } if (!shadowMapClientMapFuture && m_map_shadow_update_frames > 1) { @@ -168,6 +200,7 @@ void ShadowRenderer::updateSMTextures() std::string("shadow_clientmap_bb_") + itos(m_shadow_map_texture_size), m_shadow_map_colored ? m_texture_format_color : m_texture_format, true); + assert(shadowMapClientMapFuture != nullptr); } if (m_shadow_map_colored && !shadowMapTextureColors) { @@ -175,6 +208,7 @@ void ShadowRenderer::updateSMTextures() std::string("shadow_colored_") + itos(m_shadow_map_texture_size), m_shadow_map_colored ? m_texture_format_color : m_texture_format, true); + assert(shadowMapTextureColors != nullptr); } // The merge all shadowmaps texture @@ -194,6 +228,7 @@ void ShadowRenderer::updateSMTextures() shadowMapTextureFinal = getSMTexture( std::string("shadowmap_final_") + itos(m_shadow_map_texture_size), frt, true); + assert(shadowMapTextureFinal != nullptr); } if (!m_shadow_node_array.empty() && !m_light_list.empty()) { @@ -270,6 +305,10 @@ void ShadowRenderer::update(video::ITexture *outputTarget) updateSMTextures(); + if (shadowMapTextureFinal == nullptr) { + return; + } + if (!m_shadow_node_array.empty() && !m_light_list.empty()) { for (DirectionalLight &light : m_light_list) { @@ -307,19 +346,23 @@ void ShadowRenderer::drawDebug() /* this code just shows shadows textures in screen and in ONLY for debugging*/ #if 0 // this is debug, ignore for now. - m_driver->draw2DImage(shadowMapTextureFinal, - core::rect(0, 50, 128, 128 + 50), - core::rect({0, 0}, shadowMapTextureFinal->getSize())); + if (shadowMapTextureFinal) + m_driver->draw2DImage(shadowMapTextureFinal, + core::rect(0, 50, 128, 128 + 50), + core::rect({0, 0}, shadowMapTextureFinal->getSize())); - m_driver->draw2DImage(shadowMapClientMap, - core::rect(0, 50 + 128, 128, 128 + 50 + 128), - core::rect({0, 0}, shadowMapTextureFinal->getSize())); - m_driver->draw2DImage(shadowMapTextureDynamicObjects, - core::rect(0, 128 + 50 + 128, 128, - 128 + 50 + 128 + 128), - core::rect({0, 0}, shadowMapTextureDynamicObjects->getSize())); + if (shadowMapClientMap) + m_driver->draw2DImage(shadowMapClientMap, + core::rect(0, 50 + 128, 128, 128 + 50 + 128), + core::rect({0, 0}, shadowMapTextureFinal->getSize())); + + if (shadowMapTextureDynamicObjects) + m_driver->draw2DImage(shadowMapTextureDynamicObjects, + core::rect(0, 128 + 50 + 128, 128, + 128 + 50 + 128 + 128), + core::rect({0, 0}, shadowMapTextureDynamicObjects->getSize())); - if (m_shadow_map_colored) { + if (m_shadow_map_colored && shadowMapTextureColors) { m_driver->draw2DImage(shadowMapTextureColors, core::rect(128,128 + 50 + 128 + 128, @@ -469,13 +512,13 @@ void ShadowRenderer::createShaders() if (depth_shader == -1) { std::string depth_shader_vs = getShaderPath("shadow_shaders", "pass1_vertex.glsl"); if (depth_shader_vs.empty()) { - m_shadows_enabled = false; + m_shadows_supported = false; errorstream << "Error shadow mapping vs shader not found." << std::endl; return; } std::string depth_shader_fs = getShaderPath("shadow_shaders", "pass1_fragment.glsl"); if (depth_shader_fs.empty()) { - m_shadows_enabled = false; + m_shadows_supported = false; errorstream << "Error shadow mapping fs shader not found." << std::endl; return; } @@ -490,7 +533,7 @@ void ShadowRenderer::createShaders() if (depth_shader == -1) { // upsi, something went wrong loading shader. delete m_shadow_depth_cb; - m_shadows_enabled = false; + m_shadows_supported = false; errorstream << "Error compiling shadow mapping shader." << std::endl; return; } @@ -506,13 +549,13 @@ void ShadowRenderer::createShaders() if (depth_shader_entities == -1) { std::string depth_shader_vs = getShaderPath("shadow_shaders", "pass1_vertex.glsl"); if (depth_shader_vs.empty()) { - m_shadows_enabled = false; + m_shadows_supported = false; errorstream << "Error shadow mapping vs shader not found." << std::endl; return; } std::string depth_shader_fs = getShaderPath("shadow_shaders", "pass1_fragment.glsl"); if (depth_shader_fs.empty()) { - m_shadows_enabled = false; + m_shadows_supported = false; errorstream << "Error shadow mapping fs shader not found." << std::endl; return; } @@ -525,7 +568,7 @@ void ShadowRenderer::createShaders() if (depth_shader_entities == -1) { // upsi, something went wrong loading shader. - m_shadows_enabled = false; + m_shadows_supported = false; errorstream << "Error compiling shadow mapping shader (dynamic)." << std::endl; return; } @@ -539,14 +582,14 @@ void ShadowRenderer::createShaders() if (mixcsm_shader == -1) { std::string depth_shader_vs = getShaderPath("shadow_shaders", "pass2_vertex.glsl"); if (depth_shader_vs.empty()) { - m_shadows_enabled = false; + m_shadows_supported = false; errorstream << "Error cascade shadow mapping fs shader not found." << std::endl; return; } std::string depth_shader_fs = getShaderPath("shadow_shaders", "pass2_fragment.glsl"); if (depth_shader_fs.empty()) { - m_shadows_enabled = false; + m_shadows_supported = false; errorstream << "Error cascade shadow mapping fs shader not found." << std::endl; return; } @@ -565,7 +608,7 @@ void ShadowRenderer::createShaders() // upsi, something went wrong loading shader. delete m_shadow_mix_cb; delete m_screen_quad; - m_shadows_enabled = false; + m_shadows_supported = false; errorstream << "Error compiling cascade shadow mapping shader." << std::endl; return; } @@ -579,13 +622,13 @@ void ShadowRenderer::createShaders() if (m_shadow_map_colored && depth_shader_trans == -1) { std::string depth_shader_vs = getShaderPath("shadow_shaders", "pass1_trans_vertex.glsl"); if (depth_shader_vs.empty()) { - m_shadows_enabled = false; + m_shadows_supported = false; errorstream << "Error shadow mapping vs shader not found." << std::endl; return; } std::string depth_shader_fs = getShaderPath("shadow_shaders", "pass1_trans_fragment.glsl"); if (depth_shader_fs.empty()) { - m_shadows_enabled = false; + m_shadows_supported = false; errorstream << "Error shadow mapping fs shader not found." << std::endl; return; } @@ -601,7 +644,7 @@ void ShadowRenderer::createShaders() // upsi, something went wrong loading shader. delete m_shadow_depth_trans_cb; m_shadow_map_colored = false; - m_shadows_enabled = false; + m_shadows_supported = false; errorstream << "Error compiling colored shadow mapping shader." << std::endl; return; } diff --git a/src/client/shadows/dynamicshadowsrender.h b/src/client/shadows/dynamicshadowsrender.h index e4b3c3e22..dc8f79c56 100644 --- a/src/client/shadows/dynamicshadowsrender.h +++ b/src/client/shadows/dynamicshadowsrender.h @@ -82,11 +82,12 @@ public: } - bool is_active() const { return m_shadows_enabled; } + bool is_active() const { return m_shadows_enabled && shadowMapTextureFinal != nullptr; } void setTimeOfDay(float isDay) { m_time_day = isDay; }; + void setShadowIntensity(float shadow_intensity); s32 getShadowSamples() const { return m_shadow_samples; } - float getShadowStrength() const { return m_shadow_strength; } + float getShadowStrength() const { return m_shadows_enabled ? m_shadow_strength : 0.0f; } float getTimeOfDay() const { return m_time_day; } private: @@ -101,6 +102,9 @@ private: void mixShadowsQuad(); void updateSMTextures(); + void disable(); + void enable() { m_shadows_enabled = m_shadows_supported; } + // a bunch of variables IrrlichtDevice *m_device{nullptr}; scene::ISceneManager *m_smgr{nullptr}; @@ -116,12 +120,14 @@ private: std::vector m_shadow_node_array; float m_shadow_strength; + float m_shadow_strength_gamma; float m_shadow_map_max_distance; float m_shadow_map_texture_size; float m_time_day{0.0f}; int m_shadow_samples; bool m_shadow_map_texture_32bit; bool m_shadows_enabled; + bool m_shadows_supported; bool m_shadow_map_colored; u8 m_map_shadow_update_frames; /* Use this number of frames to update map shaodw */ u8 m_current_frame{0}; /* Current frame */ diff --git a/src/client/sky.h b/src/client/sky.h index 3dc057b70..e03683f12 100644 --- a/src/client/sky.h +++ b/src/client/sky.h @@ -65,6 +65,7 @@ public: } void setSunVisible(bool sun_visible) { m_sun_params.visible = sun_visible; } + bool getSunVisible() const { return m_sun_params.visible; } void setSunTexture(const std::string &sun_texture, const std::string &sun_tonemap, ITextureSource *tsrc); void setSunScale(f32 sun_scale) { m_sun_params.scale = sun_scale; } @@ -72,6 +73,7 @@ public: void setSunriseTexture(const std::string &sunglow_texture, ITextureSource* tsrc); void setMoonVisible(bool moon_visible) { m_moon_params.visible = moon_visible; } + bool getMoonVisible() const { return m_moon_params.visible; } void setMoonTexture(const std::string &moon_texture, const std::string &moon_tonemap, ITextureSource *tsrc); void setMoonScale(f32 moon_scale) { m_moon_params.scale = moon_scale; } diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index b935c0e21..2e9a19199 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -266,7 +266,7 @@ void set_default_settings() // Effects Shadows settings->setDefault("enable_dynamic_shadows", "false"); - settings->setDefault("shadow_strength", "0.2"); + settings->setDefault("shadow_strength_gamma", "1.0"); settings->setDefault("shadow_map_max_distance", "200.0"); settings->setDefault("shadow_map_texture_size", "2048"); settings->setDefault("shadow_map_texture_32bit", "true"); diff --git a/src/lighting.h b/src/lighting.h new file mode 100644 index 000000000..e0d9cee09 --- /dev/null +++ b/src/lighting.h @@ -0,0 +1,27 @@ +/* +Minetest +Copyright (C) 2021 x2048, Dmitry Kostenko + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#pragma once + +/** Describes ambient light settings for a player + */ +struct Lighting +{ + float shadow_intensity {0.0f}; +}; diff --git a/src/network/clientopcodes.cpp b/src/network/clientopcodes.cpp index a98a5e7d1..6a78b4652 100644 --- a/src/network/clientopcodes.cpp +++ b/src/network/clientopcodes.cpp @@ -123,6 +123,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] = { "TOCLIENT_SRP_BYTES_S_B", TOCLIENT_STATE_NOT_CONNECTED, &Client::handleCommand_SrpBytesSandB }, // 0x60 { "TOCLIENT_FORMSPEC_PREPEND", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_FormspecPrepend }, // 0x61, { "TOCLIENT_MINIMAP_MODES", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_MinimapModes }, // 0x62, + { "TOCLIENT_SET_LIGHTING", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_SetLighting }, // 0x63, }; const static ServerCommandFactory null_command_factory = { "TOSERVER_NULL", 0, false }; diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 48ad60ac6..15b576640 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -1682,3 +1682,11 @@ void Client::handleCommand_MinimapModes(NetworkPacket *pkt) if (m_minimap) m_minimap->setModeIndex(mode); } + +void Client::handleCommand_SetLighting(NetworkPacket *pkt) +{ + Lighting& lighting = m_env.getLocalPlayer()->getLighting(); + + if (pkt->getRemainingBytes() >= 4) + *pkt >> lighting.shadow_intensity; +} diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index a5ff53216..f98a829ba 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -762,7 +762,12 @@ enum ToClientCommand std::string extra */ - TOCLIENT_NUM_MSG_TYPES = 0x63, + TOCLIENT_SET_LIGHTING = 0x63, + /* + f32 shadow_intensity + */ + + TOCLIENT_NUM_MSG_TYPES = 0x64, }; enum ToServerCommand diff --git a/src/remoteplayer.h b/src/remoteplayer.h index e33630841..0ab33adfe 100644 --- a/src/remoteplayer.h +++ b/src/remoteplayer.h @@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "player.h" #include "skyparams.h" +#include "lighting.h" class PlayerSAO; @@ -125,6 +126,10 @@ public: *frame_speed = local_animation_speed; } + void setLighting(const Lighting &lighting) { m_lighting = lighting; } + + const Lighting& getLighting() const { return m_lighting; } + void setDirty(bool dirty) { m_dirty = true; } u16 protocol_version = 0; @@ -160,5 +165,7 @@ private: MoonParams m_moon_params; StarParams m_star_params; + Lighting m_lighting; + session_t m_peer_id = PEER_ID_INEXISTENT; }; diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 1ed6b0d5c..6153a0399 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -2295,6 +2295,47 @@ int ObjectRef::l_set_minimap_modes(lua_State *L) return 0; } +// set_lighting(self, lighting) +int ObjectRef::l_set_lighting(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + RemotePlayer *player = getplayer(ref); + if (player == nullptr) + return 0; + + luaL_checktype(L, 2, LUA_TTABLE); + Lighting lighting = player->getLighting(); + lua_getfield(L, 2, "shadows"); + if (lua_istable(L, -1)) { + lighting.shadow_intensity = getfloatfield_default(L, -1, "intensity", lighting.shadow_intensity); + } + lua_pop(L, -1); + + getServer(L)->setLighting(player, lighting); + lua_pushboolean(L, true); + return 1; +} + +// get_lighting(self) +int ObjectRef::l_get_lighting(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + RemotePlayer *player = getplayer(ref); + if (player == nullptr) + return 0; + + const Lighting &lighting = player->getLighting(); + + lua_newtable(L); // result + lua_newtable(L); // "shadows" + lua_pushnumber(L, lighting.shadow_intensity); + lua_setfield(L, -2, "intensity"); + lua_setfield(L, -2, "shadows"); + return 1; +} + ObjectRef::ObjectRef(ServerActiveObject *object): m_object(object) {} @@ -2448,5 +2489,7 @@ luaL_Reg ObjectRef::methods[] = { luamethod(ObjectRef, get_eye_offset), luamethod(ObjectRef, send_mapblock), luamethod(ObjectRef, set_minimap_modes), + luamethod(ObjectRef, set_lighting), + luamethod(ObjectRef, get_lighting), {0,0} }; diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h index 084d40c05..3e4e6681a 100644 --- a/src/script/lua_api/l_object.h +++ b/src/script/lua_api/l_object.h @@ -376,4 +376,10 @@ private: // set_minimap_modes(self, modes, wanted_mode) static int l_set_minimap_modes(lua_State *L); + + // set_lighting(self, lighting) + static int l_set_lighting(lua_State *L); + + // get_lighting(self) + static int l_get_lighting(lua_State *L); }; diff --git a/src/server.cpp b/src/server.cpp index d9205c895..4bc049e32 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1795,6 +1795,16 @@ void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override, Send(&pkt); } +void Server::SendSetLighting(session_t peer_id, const Lighting &lighting) +{ + NetworkPacket pkt(TOCLIENT_SET_LIGHTING, + 4, peer_id); + + pkt << lighting.shadow_intensity; + + Send(&pkt); +} + void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed) { NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id); @@ -3386,6 +3396,13 @@ void Server::overrideDayNightRatio(RemotePlayer *player, bool do_override, SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio); } +void Server::setLighting(RemotePlayer *player, const Lighting &lighting) +{ + sanity_check(player); + player->setLighting(lighting); + SendSetLighting(player->getPeerId(), lighting); +} + void Server::notifyPlayers(const std::wstring &msg) { SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg)); diff --git a/src/server.h b/src/server.h index 2741b3157..c05393291 100644 --- a/src/server.h +++ b/src/server.h @@ -69,6 +69,7 @@ struct SkyboxParams; struct SunParams; struct MoonParams; struct StarParams; +struct Lighting; class ServerThread; class ServerModManager; class ServerInventoryManager; @@ -333,6 +334,8 @@ public: void overrideDayNightRatio(RemotePlayer *player, bool do_override, float brightness); + void setLighting(RemotePlayer *player, const Lighting &lighting); + /* con::PeerHandler implementation. */ void peerAdded(con::Peer *peer); void deletingPeer(con::Peer *peer, bool timeout); @@ -459,6 +462,7 @@ private: void SendSetStars(session_t peer_id, const StarParams ¶ms); void SendCloudParams(session_t peer_id, const CloudParams ¶ms); void SendOverrideDayNightRatio(session_t peer_id, bool do_override, float ratio); + void SendSetLighting(session_t peer_id, const Lighting &lighting); void broadcastModChannelMessage(const std::string &channel, const std::string &message, session_t from_peer); -- cgit v1.2.3 From 7993909fabce4f796ca67b5a8139936667de25df Mon Sep 17 00:00:00 2001 From: ShadowNinja Date: Wed, 1 Dec 2021 18:54:12 -0500 Subject: Spacing fixes --- CMakeLists.txt | 2 +- client/shaders/nodes_shader/opengl_fragment.glsl | 2 +- client/shaders/nodes_shader/opengl_vertex.glsl | 4 +- clientmods/preview/mod.conf | 2 +- cmake/Modules/FindSQLite3.cmake | 2 +- cmake/Modules/FindVorbis.cmake | 17 ++++--- doc/lgpl-2.1.txt | 18 ++++---- minetest.conf.example | 58 ++++++++++++------------ src/CMakeLists.txt | 2 +- src/client/CMakeLists.txt | 4 +- src/client/clientmap.cpp | 4 +- src/client/imagefilters.cpp | 2 +- src/client/render/core.cpp | 2 +- src/clientiface.h | 2 +- src/collision.cpp | 4 +- src/config.h | 2 +- src/database/database-leveldb.cpp | 2 +- src/inventorymanager.cpp | 2 +- src/irrlicht_changes/CGUITTFont.cpp | 2 +- src/mapgen/dungeongen.cpp | 2 +- src/mapgen/mapgen_flat.cpp | 2 +- src/mapgen/mg_biome.cpp | 2 +- src/mapgen/mg_ore.cpp | 4 +- src/network/connection.h | 4 +- src/script/cpp_api/s_env.cpp | 4 +- src/script/lua_api/l_env.cpp | 4 +- src/script/lua_api/l_env.h | 2 +- src/serverenvironment.cpp | 2 +- src/util/ieee_float.cpp | 2 +- src/util/string.h | 2 +- util/generate-texture-normals.sh | 2 +- 31 files changed, 82 insertions(+), 83 deletions(-) (limited to 'src/network') diff --git a/CMakeLists.txt b/CMakeLists.txt index 827191835..5dfc857d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,7 +69,7 @@ if(NOT "${IRRLICHTMT_BUILD_DIR}" STREQUAL "") find_package(IrrlichtMt QUIET PATHS "${IRRLICHTMT_BUILD_DIR}" NO_DEFAULT_PATH -) + ) if(NOT TARGET IrrlichtMt::IrrlichtMt) # find_package() searches certain subdirectories. ${PATH}/cmake is not diff --git a/client/shaders/nodes_shader/opengl_fragment.glsl b/client/shaders/nodes_shader/opengl_fragment.glsl index 4d0d107d1..fea350788 100644 --- a/client/shaders/nodes_shader/opengl_fragment.glsl +++ b/client/shaders/nodes_shader/opengl_fragment.glsl @@ -557,6 +557,6 @@ void main(void) - fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0); col = mix(skyBgColor, col, clarity); col = vec4(col.rgb, base.a); - + gl_FragColor = col; } diff --git a/client/shaders/nodes_shader/opengl_vertex.glsl b/client/shaders/nodes_shader/opengl_vertex.glsl index 935fbf043..8c7e27459 100644 --- a/client/shaders/nodes_shader/opengl_vertex.glsl +++ b/client/shaders/nodes_shader/opengl_vertex.glsl @@ -199,13 +199,13 @@ void main(void) vec3 nNormal = normalize(vNormal); cosLight = dot(nNormal, -v_LightDirection); - // Calculate normal offset scale based on the texel size adjusted for + // Calculate normal offset scale based on the texel size adjusted for // curvature of the SM texture. This code must be change together with // getPerspectiveFactor or any light-space transformation. vec3 eyeToVertex = worldPosition - eyePosition + cameraOffset; // Distance from the vertex to the player float distanceToPlayer = length(eyeToVertex - v_LightDirection * dot(eyeToVertex, v_LightDirection)) / f_shadowfar; - // perspective factor estimation according to the + // perspective factor estimation according to the float perspectiveFactor = distanceToPlayer * xyPerspectiveBias0 + xyPerspectiveBias1; float texelSize = f_shadowfar * perspectiveFactor * perspectiveFactor / (f_textureresolution * xyPerspectiveBias1 - perspectiveFactor * xyPerspectiveBias0); diff --git a/clientmods/preview/mod.conf b/clientmods/preview/mod.conf index 4e56ec293..23a5c3e90 100644 --- a/clientmods/preview/mod.conf +++ b/clientmods/preview/mod.conf @@ -1 +1 @@ -name = preview +name = preview diff --git a/cmake/Modules/FindSQLite3.cmake b/cmake/Modules/FindSQLite3.cmake index b23553a80..8a66cb241 100644 --- a/cmake/Modules/FindSQLite3.cmake +++ b/cmake/Modules/FindSQLite3.cmake @@ -1,4 +1,4 @@ -mark_as_advanced(SQLITE3_LIBRARY SQLITE3_INCLUDE_DIR) +mark_as_advanced(SQLITE3_LIBRARY SQLITE3_INCLUDE_DIR) find_path(SQLITE3_INCLUDE_DIR sqlite3.h) diff --git a/cmake/Modules/FindVorbis.cmake b/cmake/Modules/FindVorbis.cmake index e5fe7f25e..222ddd9d5 100644 --- a/cmake/Modules/FindVorbis.cmake +++ b/cmake/Modules/FindVorbis.cmake @@ -29,18 +29,17 @@ else(NOT GP2XWIZ) find_package_handle_standard_args(Vorbis DEFAULT_MSG VORBIS_INCLUDE_DIR VORBIS_LIBRARY) endif(NOT GP2XWIZ) - + if(VORBIS_FOUND) - if(NOT GP2XWIZ) - set(VORBIS_LIBRARIES ${VORBISFILE_LIBRARY} ${VORBIS_LIBRARY} - ${OGG_LIBRARY}) - else(NOT GP2XWIZ) - set(VORBIS_LIBRARIES ${VORBIS_LIBRARY}) - endif(NOT GP2XWIZ) + if(NOT GP2XWIZ) + set(VORBIS_LIBRARIES ${VORBISFILE_LIBRARY} ${VORBIS_LIBRARY} + ${OGG_LIBRARY}) + else(NOT GP2XWIZ) + set(VORBIS_LIBRARIES ${VORBIS_LIBRARY}) + endif(NOT GP2XWIZ) else(VORBIS_FOUND) - set(VORBIS_LIBRARIES) + set(VORBIS_LIBRARIES) endif(VORBIS_FOUND) mark_as_advanced(OGG_INCLUDE_DIR VORBIS_INCLUDE_DIR) mark_as_advanced(OGG_LIBRARY VORBIS_LIBRARY VORBISFILE_LIBRARY) - diff --git a/doc/lgpl-2.1.txt b/doc/lgpl-2.1.txt index 4362b4915..e5ab03e12 100644 --- a/doc/lgpl-2.1.txt +++ b/doc/lgpl-2.1.txt @@ -55,7 +55,7 @@ modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. - + Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a @@ -111,7 +111,7 @@ modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. - + GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION @@ -158,7 +158,7 @@ Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. - + 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 @@ -216,7 +216,7 @@ instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. - + Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. @@ -267,7 +267,7 @@ Library will still fall under Section 6.) distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. - + 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work @@ -329,7 +329,7 @@ restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. - + 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined @@ -370,7 +370,7 @@ subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. - + 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or @@ -422,7 +422,7 @@ conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. - + 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is @@ -456,7 +456,7 @@ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS - + How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest diff --git a/minetest.conf.example b/minetest.conf.example index ed2ebc969..21aeb3546 100644 --- a/minetest.conf.example +++ b/minetest.conf.example @@ -1385,7 +1385,7 @@ # ask_reconnect_on_crash = false # From how far clients know about objects, stated in mapblocks (16 nodes). -# +# # Setting this larger than active_block_range will also cause the server # to maintain active objects up to this distance in the direction the # player is looking. (This can avoid mobs suddenly disappearing from view) @@ -1938,7 +1938,7 @@ # octaves = 3, # persistence = 0.5, # lacunarity = 2.0, -# flags = +# flags = # } # Second of two 3D noises that together define tunnels. @@ -1951,7 +1951,7 @@ # octaves = 3, # persistence = 0.5, # lacunarity = 2.0, -# flags = +# flags = # } # 3D noise defining giant caverns. @@ -1964,7 +1964,7 @@ # octaves = 5, # persistence = 0.63, # lacunarity = 2.0, -# flags = +# flags = # } # 3D noise defining terrain. @@ -1990,7 +1990,7 @@ # octaves = 2, # persistence = 0.8, # lacunarity = 2.0, -# flags = +# flags = # } ## Mapgen V6 @@ -2377,7 +2377,7 @@ # octaves = 5, # persistence = 0.63, # lacunarity = 2.0, -# flags = +# flags = # } # 3D noise defining structure of river canyon walls. @@ -2390,7 +2390,7 @@ # octaves = 4, # persistence = 0.75, # lacunarity = 2.0, -# flags = +# flags = # } # 3D noise defining structure of floatlands. @@ -2406,7 +2406,7 @@ # octaves = 4, # persistence = 0.75, # lacunarity = 1.618, -# flags = +# flags = # } # 3D noise defining giant caverns. @@ -2419,7 +2419,7 @@ # octaves = 5, # persistence = 0.63, # lacunarity = 2.0, -# flags = +# flags = # } # First of two 3D noises that together define tunnels. @@ -2432,7 +2432,7 @@ # octaves = 3, # persistence = 0.5, # lacunarity = 2.0, -# flags = +# flags = # } # Second of two 3D noises that together define tunnels. @@ -2445,7 +2445,7 @@ # octaves = 3, # persistence = 0.5, # lacunarity = 2.0, -# flags = +# flags = # } # 3D noise that determines number of dungeons per mapchunk. @@ -2458,7 +2458,7 @@ # octaves = 2, # persistence = 0.8, # lacunarity = 2.0, -# flags = +# flags = # } ## Mapgen Carpathian @@ -2701,7 +2701,7 @@ # octaves = 5, # persistence = 0.55, # lacunarity = 2.0, -# flags = +# flags = # } # First of two 3D noises that together define tunnels. @@ -2714,7 +2714,7 @@ # octaves = 3, # persistence = 0.5, # lacunarity = 2.0, -# flags = +# flags = # } # Second of two 3D noises that together define tunnels. @@ -2727,7 +2727,7 @@ # octaves = 3, # persistence = 0.5, # lacunarity = 2.0, -# flags = +# flags = # } # 3D noise defining giant caverns. @@ -2740,7 +2740,7 @@ # octaves = 5, # persistence = 0.63, # lacunarity = 2.0, -# flags = +# flags = # } # 3D noise that determines number of dungeons per mapchunk. @@ -2753,7 +2753,7 @@ # octaves = 2, # persistence = 0.8, # lacunarity = 2.0, -# flags = +# flags = # } ## Mapgen Flat @@ -2875,7 +2875,7 @@ # octaves = 3, # persistence = 0.5, # lacunarity = 2.0, -# flags = +# flags = # } # Second of two 3D noises that together define tunnels. @@ -2888,7 +2888,7 @@ # octaves = 3, # persistence = 0.5, # lacunarity = 2.0, -# flags = +# flags = # } # 3D noise defining giant caverns. @@ -2901,7 +2901,7 @@ # octaves = 5, # persistence = 0.63, # lacunarity = 2.0, -# flags = +# flags = # } # 3D noise that determines number of dungeons per mapchunk. @@ -2914,7 +2914,7 @@ # octaves = 2, # persistence = 0.8, # lacunarity = 2.0, -# flags = +# flags = # } ## Mapgen Fractal @@ -3088,7 +3088,7 @@ # octaves = 3, # persistence = 0.5, # lacunarity = 2.0, -# flags = +# flags = # } # Second of two 3D noises that together define tunnels. @@ -3101,7 +3101,7 @@ # octaves = 3, # persistence = 0.5, # lacunarity = 2.0, -# flags = +# flags = # } # 3D noise that determines number of dungeons per mapchunk. @@ -3114,7 +3114,7 @@ # octaves = 2, # persistence = 0.8, # lacunarity = 2.0, -# flags = +# flags = # } ## Mapgen Valleys @@ -3204,7 +3204,7 @@ # octaves = 3, # persistence = 0.5, # lacunarity = 2.0, -# flags = +# flags = # } # Second of two 3D noises that together define tunnels. @@ -3217,7 +3217,7 @@ # octaves = 3, # persistence = 0.5, # lacunarity = 2.0, -# flags = +# flags = # } # The depth of dirt or other biome filler node. @@ -3243,7 +3243,7 @@ # octaves = 6, # persistence = 0.63, # lacunarity = 2.0, -# flags = +# flags = # } # Defines large-scale river channel structure. @@ -3295,7 +3295,7 @@ # octaves = 6, # persistence = 0.8, # lacunarity = 2.0, -# flags = +# flags = # } # Amplifies the valleys. @@ -3334,7 +3334,7 @@ # octaves = 2, # persistence = 0.8, # lacunarity = 2.0, -# flags = +# flags = # } ## Advanced diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2de68a8f0..0323603fc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -711,7 +711,7 @@ else() # Move text segment below LuaJIT's 47-bit limit (see issue #9367) if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") # FreeBSD uses lld, and lld does not support -Ttext-segment, suggesting - # --image-base instead. Not sure if it's equivalent change for the purpose + # --image-base instead. Not sure if it's equivalent change for the purpose # but at least if fixes build on FreeBSD/aarch64 # XXX: the condition should also be changed to check for lld regardless of # os, bit CMake doesn't have anything like CMAKE_LINKER_IS_LLD yet diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index 8d058852a..656ad45ce 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -60,7 +60,7 @@ set(client_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/wieldmesh.cpp ${CMAKE_CURRENT_SOURCE_DIR}/shadows/dynamicshadows.cpp ${CMAKE_CURRENT_SOURCE_DIR}/shadows/dynamicshadowsrender.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/shadows/shadowsshadercallbacks.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/shadows/shadowsScreenQuad.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/shadows/shadowsshadercallbacks.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/shadows/shadowsScreenQuad.cpp PARENT_SCOPE ) diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp index 99ff0aefb..10967c0cb 100644 --- a/src/client/clientmap.cpp +++ b/src/client/clientmap.cpp @@ -847,12 +847,12 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver, vertex_count += buf->getIndexCount(); } - // restore the driver material state + // restore the driver material state video::SMaterial clean; clean.BlendOperation = video::EBO_ADD; driver->setMaterial(clean); // reset material to defaults driver->draw3DLine(v3f(), v3f(), video::SColor(0)); - + g_profiler->avg(prefix + "draw meshes [ms]", draw.stop(true)); g_profiler->avg(prefix + "vertices drawn [#]", vertex_count); g_profiler->avg(prefix + "drawcalls [#]", drawcall_count); diff --git a/src/client/imagefilters.cpp b/src/client/imagefilters.cpp index b62e336f7..c9d1504ad 100644 --- a/src/client/imagefilters.cpp +++ b/src/client/imagefilters.cpp @@ -124,7 +124,7 @@ void imageCleanTransparent(video::IImage *src, u32 threshold) // Ignore pixels we haven't processed if (!bitmap.get(sx, sy)) continue; - + // Add RGB values weighted by alpha IF the pixel is opaque, otherwise // use full weight since we want to propagate colors. video::SColor d = src->getPixel(sx, sy); diff --git a/src/client/render/core.cpp b/src/client/render/core.cpp index f151832f3..c67f297c4 100644 --- a/src/client/render/core.cpp +++ b/src/client/render/core.cpp @@ -103,7 +103,7 @@ void RenderingCore::drawHUD() if (show_hud) { if (draw_crosshair) hud->drawCrosshair(); - + hud->drawHotbar(client->getEnv().getLocalPlayer()->getWieldIndex()); hud->drawLuaElements(camera->getOffset()); camera->drawNametags(); diff --git a/src/clientiface.h b/src/clientiface.h index 1be9c972a..947952e82 100644 --- a/src/clientiface.h +++ b/src/clientiface.h @@ -341,7 +341,7 @@ public: u8 getMinor() const { return m_version_minor; } u8 getPatch() const { return m_version_patch; } const std::string &getFullVer() const { return m_full_version; } - + void setLangCode(const std::string &code) { m_lang_code = code; } const std::string &getLangCode() const { return m_lang_code; } diff --git a/src/collision.cpp b/src/collision.cpp index ccc3a058d..be135a225 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -153,7 +153,7 @@ CollisionAxis axisAlignedCollision( (std::max(movingbox.MaxEdge.Z + speed.Z * time, staticbox.MaxEdge.Z) - std::min(movingbox.MinEdge.Z + speed.Z * time, staticbox.MinEdge.Z) - relbox.MinEdge.Z < 0) - ) + ) return COLLISION_AXIS_X; } } else { @@ -180,7 +180,7 @@ CollisionAxis axisAlignedCollision( (std::max(movingbox.MaxEdge.Y + speed.Y * time, staticbox.MaxEdge.Y) - std::min(movingbox.MinEdge.Y + speed.Y * time, staticbox.MinEdge.Y) - relbox.MinEdge.Y < 0) - ) + ) return COLLISION_AXIS_Z; } } diff --git a/src/config.h b/src/config.h index 5e1164642..8d920b150 100644 --- a/src/config.h +++ b/src/config.h @@ -16,7 +16,7 @@ #define PROJECT_NAME_C "Minetest" #define STATIC_SHAREDIR "" #define VERSION_STRING STR(VERSION_MAJOR) "." STR(VERSION_MINOR) "." STR(VERSION_PATCH) STR(VERSION_EXTRA) -#ifdef NDEBUG + #ifdef NDEBUG #define BUILD_TYPE "Release" #else #define BUILD_TYPE "Debug" diff --git a/src/database/database-leveldb.cpp b/src/database/database-leveldb.cpp index 39f4c8442..6e59daab3 100644 --- a/src/database/database-leveldb.cpp +++ b/src/database/database-leveldb.cpp @@ -74,7 +74,7 @@ void Database_LevelDB::loadBlock(const v3s16 &pos, std::string *block) i64tos(getBlockAsInteger(pos)), block); if (!status.ok()) - block->clear(); + block->clear(); } bool Database_LevelDB::deleteBlock(const v3s16 &pos) diff --git a/src/inventorymanager.cpp b/src/inventorymanager.cpp index a159bf786..ecdb56a97 100644 --- a/src/inventorymanager.cpp +++ b/src/inventorymanager.cpp @@ -172,7 +172,7 @@ void IMoveAction::onPutAndOnTake(const ItemStack &src_item, ServerActiveObject * sa->player_inventory_OnPut(*this, src_item, player); else assert(false); - + if (from_inv.type == InventoryLocation::DETACHED) sa->detached_inventory_OnTake(*this, src_item, player); else if (from_inv.type == InventoryLocation::NODEMETA) diff --git a/src/irrlicht_changes/CGUITTFont.cpp b/src/irrlicht_changes/CGUITTFont.cpp index e785ea837..787f4cd5a 100644 --- a/src/irrlicht_changes/CGUITTFont.cpp +++ b/src/irrlicht_changes/CGUITTFont.cpp @@ -478,7 +478,7 @@ CGUITTGlyphPage* CGUITTFont::getLastGlyphPage() const CGUITTGlyphPage* CGUITTFont::createGlyphPage(const u8& pixel_mode) { CGUITTGlyphPage* page = 0; - + // Name of our page. io::path name("TTFontGlyphPage_"); name += tt_face->family_name; diff --git a/src/mapgen/dungeongen.cpp b/src/mapgen/dungeongen.cpp index acdb1a0f0..1d439abeb 100644 --- a/src/mapgen/dungeongen.cpp +++ b/src/mapgen/dungeongen.cpp @@ -71,7 +71,7 @@ DungeonGen::DungeonGen(const NodeDefManager *ndef, dp.num_dungeons = 1; dp.notifytype = GENNOTIFY_DUNGEON; - dp.np_alt_wall = + dp.np_alt_wall = NoiseParams(-0.4, 1.0, v3f(40.0, 40.0, 40.0), 32474, 6, 1.1, 2.0); } } diff --git a/src/mapgen/mapgen_flat.cpp b/src/mapgen/mapgen_flat.cpp index 342455029..6b249ea1f 100644 --- a/src/mapgen/mapgen_flat.cpp +++ b/src/mapgen/mapgen_flat.cpp @@ -177,7 +177,7 @@ void MapgenFlatParams::setDefaultSettings(Settings *settings) int MapgenFlat::getSpawnLevelAtPoint(v2s16 p) { s16 stone_level = ground_level; - float n_terrain = + float n_terrain = ((spflags & MGFLAT_LAKES) || (spflags & MGFLAT_HILLS)) ? NoisePerlin2D(&noise_terrain->np, p.X, p.Y, seed) : 0.0f; diff --git a/src/mapgen/mg_biome.cpp b/src/mapgen/mg_biome.cpp index f08cc190f..8b4c96cd5 100644 --- a/src/mapgen/mg_biome.cpp +++ b/src/mapgen/mg_biome.cpp @@ -273,7 +273,7 @@ Biome *BiomeGenOriginal::calcBiomeFromNoise(float heat, float humidity, v3s16 po pos.Y - biome_closest_blend->max_pos.Y) return biome_closest_blend; - return (biome_closest) ? biome_closest : (Biome *)m_bmgr->getRaw(BIOME_NONE); + return (biome_closest) ? biome_closest : (Biome *)m_bmgr->getRaw(BIOME_NONE); } diff --git a/src/mapgen/mg_ore.cpp b/src/mapgen/mg_ore.cpp index 5814f433a..4f0c35548 100644 --- a/src/mapgen/mg_ore.cpp +++ b/src/mapgen/mg_ore.cpp @@ -498,8 +498,8 @@ void OreVein::generate(MMVManip *vm, int mapseed, u32 blockseed, } // randval ranges from -1..1 - /* - Note: can generate values slightly larger than 1 + /* + Note: can generate values slightly larger than 1 but this can't be changed as mapgen must be deterministic accross versions. */ float randval = (float)pr.next() / float(pr.RANDOM_RANGE / 2) - 1.f; diff --git a/src/network/connection.h b/src/network/connection.h index 1afb4ae84..88e323bb1 100644 --- a/src/network/connection.h +++ b/src/network/connection.h @@ -752,8 +752,8 @@ protected: void putEvent(ConnectionEventPtr e); void TriggerSend(); - - bool ConnectedToServer() + + bool ConnectedToServer() { return getPeerNoEx(PEER_ID_SERVER) != nullptr; } diff --git a/src/script/cpp_api/s_env.cpp b/src/script/cpp_api/s_env.cpp index 874c37b6e..af68f689f 100644 --- a/src/script/cpp_api/s_env.cpp +++ b/src/script/cpp_api/s_env.cpp @@ -140,10 +140,10 @@ void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env) bool simple_catch_up = true; getboolfield(L, current_abm, "catch_up", simple_catch_up); - + s16 min_y = INT16_MIN; getintfield(L, current_abm, "min_y", min_y); - + s16 max_y = INT16_MAX; getintfield(L, current_abm, "max_y", max_y); diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 54821df24..7640f2782 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -757,7 +757,7 @@ int ModApiEnvMod::l_get_objects_in_area(lua_State *L) { GET_ENV_PTR; ScriptApiBase *script = getScriptApiBase(L); - + v3f minp = read_v3f(L, 1) * BS; v3f maxp = read_v3f(L, 2) * BS; aabb3f box(minp, maxp); @@ -1409,7 +1409,7 @@ int ModApiEnvMod::l_compare_block_status(lua_State *L) v3s16 nodepos = check_v3s16(L, 1); std::string condition_s = luaL_checkstring(L, 2); auto status = env->getBlockStatus(getNodeBlockPos(nodepos)); - + int condition_i = -1; if (!string_to_enum(es_BlockStatusType, condition_i, condition_s)) return 0; // Unsupported diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h index 67c76faae..a7d406d2a 100644 --- a/src/script/lua_api/l_env.h +++ b/src/script/lua_api/l_env.h @@ -114,7 +114,7 @@ private: // get_objects_inside_radius(pos, radius) static int l_get_objects_inside_radius(lua_State *L); - + // get_objects_in_area(pos, minp, maxp) static int l_get_objects_in_area(lua_State *L); diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index f3711652c..34a1e33e5 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -892,7 +892,7 @@ public: for (ActiveABM &aabm : *m_aabms[c]) { if ((p.Y < aabm.min_y) || (p.Y > aabm.max_y)) continue; - + if (myrand() % aabm.chance != 0) continue; diff --git a/src/util/ieee_float.cpp b/src/util/ieee_float.cpp index 887258921..b73763c55 100644 --- a/src/util/ieee_float.cpp +++ b/src/util/ieee_float.cpp @@ -39,7 +39,7 @@ f32 u32Tof32Slow(u32 i) if (exp == 0xFF) { // Inf/NaN if (imant == 0) { - if (std::numeric_limits::has_infinity) + if (std::numeric_limits::has_infinity) return sign ? -std::numeric_limits::infinity() : std::numeric_limits::infinity(); return sign ? std::numeric_limits::max() : diff --git a/src/util/string.h b/src/util/string.h index 8a9e83f22..f4ca1a7de 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -410,7 +410,7 @@ DEFINE_STD_TOSTRING_FLOATINGPOINT(long double) template inline wstring to_wstring(T val) { - return utf8_to_wide(to_string(val)); + return utf8_to_wide(to_string(val)); } } #endif diff --git a/util/generate-texture-normals.sh b/util/generate-texture-normals.sh index 6279dfa69..b2fcbf77b 100755 --- a/util/generate-texture-normals.sh +++ b/util/generate-texture-normals.sh @@ -197,7 +197,7 @@ normalMap() (gimp-convert-rgb image) () ) - (plug-in-normalmap + (plug-in-normalmap RUN-NONINTERACTIVE image drawable -- cgit v1.2.3 From 391eec9ee78fc9dfdc476ad2a8ed7755009e4a2f Mon Sep 17 00:00:00 2001 From: sfan5 Date: Wed, 27 Apr 2022 19:00:49 +0200 Subject: Fix race condition in registration leading to duplicate create_auth calls --- src/network/serverpackethandler.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'src/network') diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index 8163cb820..6d951c416 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -1495,8 +1495,19 @@ void Server::handleCommand_FirstSrp(NetworkPacket* pkt) } std::string initial_ver_key; - initial_ver_key = encode_srp_verifier(verification_key, salt); + + // It is possible for multiple connections to get this far with the same + // player name. In the end only one player with a given name will be emerged + // (see Server::StateTwoClientInit) but we still have to be careful here. + if (m_script->getAuth(playername, nullptr, nullptr)) { + // Another client beat us to it + actionstream << "Server: Client from " << addr_s + << " tried to register " << playername << " a second time." + << std::endl; + DenyAccess(peer_id, SERVER_ACCESSDENIED_ALREADY_CONNECTED); + return; + } m_script->createAuth(playername, initial_ver_key); m_script->on_authplayer(playername, addr_s, true); -- cgit v1.2.3 From 3d2bf8fb021ea839944830e212789532ba3f0370 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Wed, 27 Apr 2022 19:10:03 +0200 Subject: Apply disallow_empty_password to password changes too --- builtin/settingtypes.txt | 2 +- src/network/serverpackethandler.cpp | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'src/network') diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index babb89481..a983a8f6b 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -1186,7 +1186,7 @@ enable_mod_channels (Mod channels) bool false # If this is set, players will always (re)spawn at the given position. static_spawnpoint (Static spawnpoint) string -# If enabled, new players cannot join with an empty password. +# If enabled, players cannot join without a password or change theirs to an empty password. disallow_empty_password (Disallow empty passwords) bool false # If enabled, disable cheat prevention in multiplayer. diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index 6d951c416..51061f57b 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -1475,6 +1475,9 @@ void Server::handleCommand_FirstSrp(NetworkPacket* pkt) verbosestream << "Server: Got TOSERVER_FIRST_SRP from " << addr_s << ", with is_empty=" << (is_empty == 1) << std::endl; + const bool empty_disallowed = !isSingleplayer() && is_empty == 1 && + g_settings->getBool("disallow_empty_password"); + // Either this packet is sent because the user is new or to change the password if (cstate == CS_HelloSent) { if (!client->isMechAllowed(AUTH_MECHANISM_FIRST_SRP)) { @@ -1485,9 +1488,7 @@ void Server::handleCommand_FirstSrp(NetworkPacket* pkt) return; } - if (!isSingleplayer() && - g_settings->getBool("disallow_empty_password") && - is_empty == 1) { + if (empty_disallowed) { actionstream << "Server: " << playername << " supplied empty password from " << addr_s << std::endl; DenyAccess(peer_id, SERVER_ACCESSDENIED_EMPTY_PASSWORD); @@ -1520,6 +1521,15 @@ void Server::handleCommand_FirstSrp(NetworkPacket* pkt) return; } m_clients.event(peer_id, CSE_SudoLeave); + + if (empty_disallowed) { + actionstream << "Server: " << playername + << " supplied empty password" << std::endl; + SendChatMessage(peer_id, ChatMessage(CHATMESSAGE_TYPE_SYSTEM, + L"Changing to an empty password is not allowed.")); + return; + } + std::string pw_db_field = encode_srp_verifier(verification_key, salt); bool success = m_script->setPassword(playername, pw_db_field); if (success) { -- cgit v1.2.3 From 00f71c3b9d35e1cdd5aa62491a46068358aa8b2a Mon Sep 17 00:00:00 2001 From: sfan5 Date: Wed, 27 Apr 2022 19:32:51 +0200 Subject: Fix password changing getting stuck if wrong password is entered once --- src/clientiface.cpp | 9 +++++++++ src/clientiface.h | 2 ++ src/network/serverpackethandler.cpp | 2 ++ 3 files changed, 13 insertions(+) (limited to 'src/network') diff --git a/src/clientiface.cpp b/src/clientiface.cpp index a1c3e1187..a4bfb8242 100644 --- a/src/clientiface.cpp +++ b/src/clientiface.cpp @@ -596,6 +596,15 @@ void RemoteClient::notifyEvent(ClientStateEvent event) } } +void RemoteClient::resetChosenMech() +{ + if (chosen_mech == AUTH_MECHANISM_SRP) { + srp_verifier_delete((SRPVerifier *) auth_data); + auth_data = nullptr; + } + chosen_mech = AUTH_MECHANISM_NONE; +} + u64 RemoteClient::uptime() const { return porting::getTimeS() - m_connection_time; diff --git a/src/clientiface.h b/src/clientiface.h index 947952e82..3e7ba4793 100644 --- a/src/clientiface.h +++ b/src/clientiface.h @@ -243,6 +243,8 @@ public: u32 allowed_auth_mechs = 0; u32 allowed_sudo_mechs = 0; + void resetChosenMech(); + bool isSudoMechAllowed(AuthMechanism mech) { return allowed_sudo_mechs & mech; } bool isMechAllowed(AuthMechanism mech) diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index 51061f57b..125e85cab 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -1639,6 +1639,7 @@ void Server::handleCommand_SrpBytesA(NetworkPacket* pkt) << std::endl; if (wantSudo) { DenySudoAccess(peer_id); + client->resetChosenMech(); return; } @@ -1705,6 +1706,7 @@ void Server::handleCommand_SrpBytesM(NetworkPacket* pkt) << " tried to change their password, but supplied wrong" << " (SRP) password for authentication." << std::endl; DenySudoAccess(peer_id); + client->resetChosenMech(); return; } -- cgit v1.2.3 From a65f6f07f3a5601207b790edcc8cc945133112f7 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Wed, 27 Apr 2022 19:55:13 +0200 Subject: Clean up some auth packet handling related code --- src/clientiface.cpp | 16 +++------- src/network/clientpackethandler.cpp | 11 ++++--- src/network/networkprotocol.h | 18 +++++------ src/network/serveropcodes.cpp | 2 +- src/network/serverpackethandler.cpp | 24 +++++++-------- src/script/lua_api/l_server.cpp | 9 ++++-- src/server.cpp | 59 +++++++++---------------------------- src/server.h | 5 +--- src/serverenvironment.cpp | 6 ++-- 9 files changed, 52 insertions(+), 98 deletions(-) (limited to 'src/network') diff --git a/src/clientiface.cpp b/src/clientiface.cpp index a4bfb8242..5733b05de 100644 --- a/src/clientiface.cpp +++ b/src/clientiface.cpp @@ -472,20 +472,14 @@ void RemoteClient::notifyEvent(ClientStateEvent event) { case CSE_AuthAccept: m_state = CS_AwaitingInit2; - if (chosen_mech == AUTH_MECHANISM_SRP || - chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD) - srp_verifier_delete((SRPVerifier *) auth_data); - chosen_mech = AUTH_MECHANISM_NONE; + resetChosenMech(); break; case CSE_Disconnect: m_state = CS_Disconnecting; break; case CSE_SetDenied: m_state = CS_Denied; - if (chosen_mech == AUTH_MECHANISM_SRP || - chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD) - srp_verifier_delete((SRPVerifier *) auth_data); - chosen_mech = AUTH_MECHANISM_NONE; + resetChosenMech(); break; default: myerror << "HelloSent: Invalid client state transition! " << event; @@ -561,9 +555,7 @@ void RemoteClient::notifyEvent(ClientStateEvent event) break; case CSE_SudoSuccess: m_state = CS_SudoMode; - if (chosen_mech == AUTH_MECHANISM_SRP) - srp_verifier_delete((SRPVerifier *) auth_data); - chosen_mech = AUTH_MECHANISM_NONE; + resetChosenMech(); break; /* Init GotInit2 SetDefinitionsSent SetMediaSent SetDenied */ default: @@ -598,7 +590,7 @@ void RemoteClient::notifyEvent(ClientStateEvent event) void RemoteClient::resetChosenMech() { - if (chosen_mech == AUTH_MECHANISM_SRP) { + if (auth_data) { srp_verifier_delete((SRPVerifier *) auth_data); auth_data = nullptr; } diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 15b576640..55d20d673 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -183,7 +183,7 @@ void Client::handleCommand_AccessDenied(NetworkPacket* pkt) m_access_denied_reason = "Unknown"; if (pkt->getCommand() != TOCLIENT_ACCESS_DENIED) { - // 13/03/15 Legacy code from 0.4.12 and lesser but is still used + // Legacy code from 0.4.12 and older but is still used // in some places of the server code if (pkt->getSize() >= 2) { std::wstring wide_reason; @@ -196,14 +196,14 @@ void Client::handleCommand_AccessDenied(NetworkPacket* pkt) if (pkt->getSize() < 1) return; - u8 denyCode = SERVER_ACCESSDENIED_UNEXPECTED_DATA; + u8 denyCode; *pkt >> denyCode; + if (denyCode == SERVER_ACCESSDENIED_SHUTDOWN || denyCode == SERVER_ACCESSDENIED_CRASH) { *pkt >> m_access_denied_reason; - if (m_access_denied_reason.empty()) { + if (m_access_denied_reason.empty()) m_access_denied_reason = accessDeniedStrings[denyCode]; - } u8 reconnect; *pkt >> reconnect; m_access_denied_reconnect = reconnect & 1; @@ -220,9 +220,8 @@ void Client::handleCommand_AccessDenied(NetworkPacket* pkt) // Until then (which may be never), this is outside // of the defined protocol. *pkt >> m_access_denied_reason; - if (m_access_denied_reason.empty()) { + if (m_access_denied_reason.empty()) m_access_denied_reason = "Unknown"; - } } } diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index f98a829ba..3923cb858 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -1006,7 +1006,7 @@ enum AuthMechanism AUTH_MECHANISM_FIRST_SRP = 1 << 2, }; -enum AccessDeniedCode { +enum AccessDeniedCode : u8 { SERVER_ACCESSDENIED_WRONG_PASSWORD, SERVER_ACCESSDENIED_UNEXPECTED_DATA, SERVER_ACCESSDENIED_SINGLEPLAYER, @@ -1029,18 +1029,18 @@ enum NetProtoCompressionMode { const static std::string accessDeniedStrings[SERVER_ACCESSDENIED_MAX] = { "Invalid password", - "Your client sent something the server didn't expect. Try reconnecting or updating your client", + "Your client sent something the server didn't expect. Try reconnecting or updating your client.", "The server is running in simple singleplayer mode. You cannot connect.", - "Your client's version is not supported.\nPlease contact server administrator.", - "Player name contains disallowed characters.", - "Player name not allowed.", - "Too many users.", + "Your client's version is not supported.\nPlease contact the server administrator.", + "Player name contains disallowed characters", + "Player name not allowed", + "Too many users", "Empty passwords are disallowed. Set a password and try again.", "Another client is connected with this name. If your client closed unexpectedly, try again in a minute.", - "Server authentication failed. This is likely a server error.", + "Internal server error", "", - "Server shutting down.", - "This server has experienced an internal error. You will now be disconnected." + "Server shutting down", + "The server has experienced an internal error. You will now be disconnected." }; enum PlayerListModifer : u8 diff --git a/src/network/serveropcodes.cpp b/src/network/serveropcodes.cpp index 44b65e8da..12665e7f1 100644 --- a/src/network/serveropcodes.cpp +++ b/src/network/serveropcodes.cpp @@ -176,7 +176,7 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] = { "TOCLIENT_ACTIVE_OBJECT_MESSAGES", 0, true }, // 0x32 (may be sent as unrel over channel 1 too) { "TOCLIENT_HP", 0, true }, // 0x33 { "TOCLIENT_MOVE_PLAYER", 0, true }, // 0x34 - { "TOCLIENT_ACCESS_DENIED_LEGACY", 0, true }, // 0x35 + null_command_factory, // 0x35 { "TOCLIENT_FOV", 0, true }, // 0x36 { "TOCLIENT_DEATHSCREEN", 0, true }, // 0x37 { "TOCLIENT_MEDIA", 2, true }, // 0x38 diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index 125e85cab..4b9de488c 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -227,7 +227,7 @@ void Server::handleCommand_Init(NetworkPacket* pkt) Compose auth methods for answer */ std::string encpwd; // encrypted Password field for the user - bool has_auth = m_script->getAuth(playername, &encpwd, NULL); + bool has_auth = m_script->getAuth(playername, &encpwd, nullptr); u32 auth_mechs = 0; client->chosen_mech = AUTH_MECHANISM_NONE; @@ -1461,11 +1461,9 @@ void Server::handleCommand_FirstSrp(NetworkPacket* pkt) session_t peer_id = pkt->getPeerId(); RemoteClient *client = getClient(peer_id, CS_Invalid); ClientState cstate = client->getState(); + const std::string playername = client->getName(); - std::string playername = client->getName(); - - std::string salt; - std::string verification_key; + std::string salt, verification_key; std::string addr_s = getPeerAddress(peer_id).serializeString(); u8 is_empty; @@ -1551,8 +1549,6 @@ void Server::handleCommand_SrpBytesA(NetworkPacket* pkt) RemoteClient *client = getClient(peer_id, CS_Invalid); ClientState cstate = client->getState(); - bool wantSudo = (cstate == CS_Active); - if (!((cstate == CS_HelloSent) || (cstate == CS_Active))) { actionstream << "Server: got SRP _A packet in wrong state " << cstate << " from " << getPeerAddress(peer_id).serializeString() << @@ -1560,6 +1556,8 @@ void Server::handleCommand_SrpBytesA(NetworkPacket* pkt) return; } + const bool wantSudo = (cstate == CS_Active); + if (client->chosen_mech != AUTH_MECHANISM_NONE) { actionstream << "Server: got SRP _A packet, while auth is already " "going on with mech " << client->chosen_mech << " from " << @@ -1606,8 +1604,7 @@ void Server::handleCommand_SrpBytesA(NetworkPacket* pkt) client->chosen_mech = chosen; - std::string salt; - std::string verifier; + std::string salt, verifier; if (based_on == 0) { @@ -1657,10 +1654,10 @@ void Server::handleCommand_SrpBytesM(NetworkPacket* pkt) session_t peer_id = pkt->getPeerId(); RemoteClient *client = getClient(peer_id, CS_Invalid); ClientState cstate = client->getState(); - std::string addr_s = getPeerAddress(pkt->getPeerId()).serializeString(); - std::string playername = client->getName(); + const std::string addr_s = client->getAddress().serializeString(); + const std::string playername = client->getName(); - bool wantSudo = (cstate == CS_Active); + const bool wantSudo = (cstate == CS_Active); verbosestream << "Server: Received TOSERVER_SRP_BYTES_M." << std::endl; @@ -1720,8 +1717,7 @@ void Server::handleCommand_SrpBytesM(NetworkPacket* pkt) if (client->create_player_on_auth_success) { m_script->createAuth(playername, client->enc_pwd); - std::string checkpwd; // not used, but needed for passing something - if (!m_script->getAuth(playername, &checkpwd, NULL)) { + if (!m_script->getAuth(playername, nullptr, nullptr)) { errorstream << "Server: " << playername << " cannot be authenticated (auth handler does not work?)" << std::endl; diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp index 88ab5e16b..5b3054d17 100644 --- a/src/script/lua_api/l_server.cpp +++ b/src/script/lua_api/l_server.cpp @@ -325,12 +325,15 @@ int ModApiServer::l_disconnect_player(lua_State *L) else message.append("Disconnected."); - RemotePlayer *player = dynamic_cast(getEnv(L))->getPlayer(name); - if (player == NULL) { + Server *server = getServer(L); + + RemotePlayer *player = server->getEnv().getPlayer(name); + if (!player) { lua_pushboolean(L, false); // No such player return 1; } - getServer(L)->DenyAccess_Legacy(player->getPeerId(), utf8_to_wide(message)); + + server->DenyAccess(player->getPeerId(), SERVER_ACCESSDENIED_CUSTOM_STRING, message); lua_pushboolean(L, true); return 1; } diff --git a/src/server.cpp b/src/server.cpp index 8ca8a9bda..9d7e8e563 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1038,8 +1038,7 @@ void Server::Receive() } catch (const ClientStateError &e) { errorstream << "ProcessData: peer=" << peer_id << " what()=" << e.what() << std::endl; - DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect." - L"Try reconnecting or updating your client"); + DenyAccess(peer_id, SERVER_ACCESSDENIED_UNEXPECTED_DATA); } catch (const con::PeerNotFoundException &e) { // Do nothing } catch (const con::NoIncomingDataException &e) { @@ -1068,15 +1067,13 @@ PlayerSAO* Server::StageTwoClientInit(session_t peer_id) if (player && player->getPeerId() != PEER_ID_INEXISTENT) { actionstream << "Server: Failed to emerge player \"" << playername << "\" (player allocated to an another client)" << std::endl; - DenyAccess_Legacy(peer_id, L"Another client is connected with this " - L"name. If your client closed unexpectedly, try again in " - L"a minute."); + DenyAccess(peer_id, SERVER_ACCESSDENIED_ALREADY_CONNECTED); } else { errorstream << "Server: " << playername << ": Failed to emerge player" << std::endl; - DenyAccess_Legacy(peer_id, L"Could not allocate player."); + DenyAccess(peer_id, SERVER_ACCESSDENIED_SERVER_FAIL); } - return NULL; + return nullptr; } /* @@ -1141,18 +1138,16 @@ void Server::ProcessData(NetworkPacket *pkt) Address address = getPeerAddress(peer_id); std::string addr_s = address.serializeString(); - if(m_banmanager->isIpBanned(addr_s)) { + // FIXME: Isn't it a bit excessive to check this for every packet? + if (m_banmanager->isIpBanned(addr_s)) { std::string ban_name = m_banmanager->getBanName(addr_s); infostream << "Server: A banned client tried to connect from " - << addr_s << "; banned name was " - << ban_name << std::endl; - // This actually doesn't seem to transfer to the client - DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was " - + utf8_to_wide(ban_name)); + << addr_s << "; banned name was " << ban_name << std::endl; + DenyAccess(peer_id, SERVER_ACCESSDENIED_CUSTOM_STRING, + "Your IP is banned. Banned name was " + ban_name); return; } - } - catch(con::PeerNotFoundException &e) { + } catch (con::PeerNotFoundException &e) { /* * no peer for this packet found * most common reason is peer timeout, e.g. peer didn't @@ -1406,13 +1401,6 @@ void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason, Send(&pkt); } -void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason) -{ - NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id); - pkt << reason; - Send(&pkt); -} - void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target, v3f camera_point_target) { @@ -2777,29 +2765,10 @@ void Server::DenySudoAccess(session_t peer_id) } -void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason, - const std::string &str_reason, bool reconnect) -{ - SendAccessDenied(peer_id, reason, str_reason, reconnect); - - m_clients.event(peer_id, CSE_SetDenied); - DisconnectPeer(peer_id); -} - - void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason, - const std::string &custom_reason) -{ - SendAccessDenied(peer_id, reason, custom_reason); - m_clients.event(peer_id, CSE_SetDenied); - DisconnectPeer(peer_id); -} - -// 13/03/15: remove this function when protocol version 25 will become -// the minimum version for MT users, maybe in 1 year -void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason) + const std::string &custom_reason, bool reconnect) { - SendAccessDenied_Legacy(peer_id, reason); + SendAccessDenied(peer_id, reason, custom_reason, reconnect); m_clients.event(peer_id, CSE_SetDenied); DisconnectPeer(peer_id); } @@ -2985,8 +2954,8 @@ std::wstring Server::handleChat(const std::string &name, return ws.str(); } case RPLAYER_CHATRESULT_KICK: - DenyAccess_Legacy(player->getPeerId(), - L"You have been kicked due to message flooding."); + DenyAccess(player->getPeerId(), SERVER_ACCESSDENIED_CUSTOM_STRING, + "You have been kicked due to message flooding."); return L""; case RPLAYER_CHATRESULT_OK: break; diff --git a/src/server.h b/src/server.h index c05393291..008213c5d 100644 --- a/src/server.h +++ b/src/server.h @@ -341,12 +341,9 @@ public: void deletingPeer(con::Peer *peer, bool timeout); void DenySudoAccess(session_t peer_id); - void DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason, - const std::string &str_reason = "", bool reconnect = false); void DenyAccess(session_t peer_id, AccessDeniedCode reason, - const std::string &custom_reason = ""); + const std::string &custom_reason = "", bool reconnect = false); void acceptAuth(session_t peer_id, bool forSudoMode); - void DenyAccess_Legacy(session_t peer_id, const std::wstring &reason); void DisconnectPeer(session_t peer_id); bool getClientConInfo(session_t peer_id, con::rtt_stat_type type, float *retval); bool getClientInfo(session_t peer_id, ClientInfo &ret); diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index 34a1e33e5..f8d84604b 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -552,10 +552,8 @@ bool ServerEnvironment::removePlayerFromDatabase(const std::string &name) void ServerEnvironment::kickAllPlayers(AccessDeniedCode reason, const std::string &str_reason, bool reconnect) { - for (RemotePlayer *player : m_players) { - m_server->DenyAccessVerCompliant(player->getPeerId(), - player->protocol_version, reason, str_reason, reconnect); - } + for (RemotePlayer *player : m_players) + m_server->DenyAccess(player->getPeerId(), reason, str_reason, reconnect); } void ServerEnvironment::saveLoadedPlayers(bool force) -- cgit v1.2.3 From a89afe1229e327da3c397a3912b2d43d2196ea2b Mon Sep 17 00:00:00 2001 From: sfan5 Date: Thu, 28 Apr 2022 20:53:15 +0200 Subject: Deal with compiler warnings --- src/client/client.h | 2 +- src/client/clientmap.h | 16 +++++++--------- src/client/content_cao.cpp | 2 +- src/client/content_cao.h | 2 +- src/client/game.cpp | 6 +++--- src/client/minimap.cpp | 2 +- src/client/shadows/dynamicshadowsrender.cpp | 6 ++++-- src/client/shadows/dynamicshadowsrender.h | 1 - src/database/database-postgresql.h | 3 ++- src/map.h | 14 +++++++------- src/network/connection.h | 2 +- src/network/socket.cpp | 4 ++-- 12 files changed, 30 insertions(+), 30 deletions(-) (limited to 'src/network') diff --git a/src/client/client.h b/src/client/client.h index 0e29fdbe2..cb1227768 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -407,7 +407,7 @@ public: } ClientScripting *getScript() { return m_script; } - const bool modsLoaded() const { return m_mods_loaded; } + bool modsLoaded() const { return m_mods_loaded; } void pushToEventQueue(ClientEvent *event); diff --git a/src/client/clientmap.h b/src/client/clientmap.h index 7bd7af266..6d57f1911 100644 --- a/src/client/clientmap.h +++ b/src/client/clientmap.h @@ -81,9 +81,9 @@ public: return false; } - void drop() + void drop() override { - ISceneNode::drop(); + ISceneNode::drop(); // calls destructor } void updateCamera(v3f pos, v3f dir, f32 fov, v3s16 offset); @@ -91,24 +91,22 @@ public: /* Forcefully get a sector from somewhere */ - MapSector * emergeSector(v2s16 p); - - //void deSerializeSector(v2s16 p2d, std::istream &is); + MapSector * emergeSector(v2s16 p) override; /* ISceneNode methods */ - virtual void OnRegisterSceneNode(); + virtual void OnRegisterSceneNode() override; - virtual void render() + virtual void render() override { video::IVideoDriver* driver = SceneManager->getVideoDriver(); driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); renderMap(driver, SceneManager->getSceneNodeRenderPass()); } - virtual const aabb3f &getBoundingBox() const + virtual const aabb3f &getBoundingBox() const override { return m_box; } @@ -130,7 +128,7 @@ public: void renderPostFx(CameraMode cam_mode); // For debug printing - virtual void PrintInfo(std::ostream &out); + void PrintInfo(std::ostream &out) override; const MapDrawControl & getControl() const { return m_control; } f32 getWantedRange() const { return m_control.wanted_range; } diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index 3c31d4a36..d89bb53b3 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -435,7 +435,7 @@ const v3f GenericCAO::getPosition() const return m_position; } -const bool GenericCAO::isImmortal() +bool GenericCAO::isImmortal() const { return itemgroup_get(getGroups(), "immortal"); } diff --git a/src/client/content_cao.h b/src/client/content_cao.h index 70f1557e1..783aa4199 100644 --- a/src/client/content_cao.h +++ b/src/client/content_cao.h @@ -172,7 +172,7 @@ public: inline const v3f &getRotation() const { return m_rotation; } - const bool isImmortal(); + bool isImmortal() const; inline const ObjectProperties &getProperties() const { return m_prop; } diff --git a/src/client/game.cpp b/src/client/game.cpp index 1290534eb..d21bdbe99 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1063,9 +1063,9 @@ bool Game::startup(bool *kill, void Game::run() { ProfilerGraph graph; - RunStats stats = { 0 }; - CameraOrientation cam_view_target = { 0 }; - CameraOrientation cam_view = { 0 }; + RunStats stats; + CameraOrientation cam_view_target = {}; + CameraOrientation cam_view = {}; FpsControl draw_times; f32 dtime; // in seconds diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp index f26aa1c70..320621d91 100644 --- a/src/client/minimap.cpp +++ b/src/client/minimap.cpp @@ -304,7 +304,7 @@ void Minimap::setModeIndex(size_t index) data->mode = m_modes[index]; m_current_mode_index = index; } else { - data->mode = MinimapModeDef{MINIMAP_TYPE_OFF, gettext("Minimap hidden"), 0, 0, ""}; + data->mode = {MINIMAP_TYPE_OFF, gettext("Minimap hidden"), 0, 0, "", 0}; m_current_mode_index = 0; } diff --git a/src/client/shadows/dynamicshadowsrender.cpp b/src/client/shadows/dynamicshadowsrender.cpp index a008c3e06..07dc6daf2 100644 --- a/src/client/shadows/dynamicshadowsrender.cpp +++ b/src/client/shadows/dynamicshadowsrender.cpp @@ -31,10 +31,12 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "profiler.h" ShadowRenderer::ShadowRenderer(IrrlichtDevice *device, Client *client) : - m_device(device), m_smgr(device->getSceneManager()), - m_driver(device->getVideoDriver()), m_client(client), m_current_frame(0), + m_smgr(device->getSceneManager()), m_driver(device->getVideoDriver()), + m_client(client), m_current_frame(0), m_perspective_bias_xy(0.8), m_perspective_bias_z(0.5) { + (void) m_client; + m_shadows_supported = true; // assume shadows supported. We will check actual support in initialize m_shadows_enabled = true; diff --git a/src/client/shadows/dynamicshadowsrender.h b/src/client/shadows/dynamicshadowsrender.h index bbeb254b0..0e4ef6b70 100644 --- a/src/client/shadows/dynamicshadowsrender.h +++ b/src/client/shadows/dynamicshadowsrender.h @@ -109,7 +109,6 @@ private: void enable() { m_shadows_enabled = m_shadows_supported; } // a bunch of variables - IrrlichtDevice *m_device{nullptr}; scene::ISceneManager *m_smgr{nullptr}; video::IVideoDriver *m_driver{nullptr}; Client *m_client{nullptr}; diff --git a/src/database/database-postgresql.h b/src/database/database-postgresql.h index 81b4a2b10..0a9ead01e 100644 --- a/src/database/database-postgresql.h +++ b/src/database/database-postgresql.h @@ -94,7 +94,8 @@ protected: checkResults(PQprepare(m_conn, name.c_str(), sql.c_str(), 0, NULL)); } - const int getPGVersion() const { return m_pgversion; } + int getPGVersion() const { return m_pgversion; } + private: // Database connectivity checks void ping(); diff --git a/src/map.h b/src/map.h index 9dc7a101c..d8ed29106 100644 --- a/src/map.h +++ b/src/map.h @@ -327,7 +327,7 @@ public: - Create blank filled with CONTENT_IGNORE */ - MapBlock *emergeBlock(v3s16 p, bool create_blank=true); + MapBlock *emergeBlock(v3s16 p, bool create_blank=true) override; /* Try to get a block. @@ -349,27 +349,27 @@ public: static MapDatabase *createDatabase(const std::string &name, const std::string &savedir, Settings &conf); // Call these before and after saving of blocks - void beginSave(); - void endSave(); + void beginSave() override; + void endSave() override; - void save(ModifiedState save_level); + void save(ModifiedState save_level) override; void listAllLoadableBlocks(std::vector &dst); void listAllLoadedBlocks(std::vector &dst); MapgenParams *getMapgenParams(); - bool saveBlock(MapBlock *block); + bool saveBlock(MapBlock *block) override; static bool saveBlock(MapBlock *block, MapDatabase *db, int compression_level = -1); MapBlock* loadBlock(v3s16 p); // Database version void loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load=false); - bool deleteBlock(v3s16 blockpos); + bool deleteBlock(v3s16 blockpos) override; void updateVManip(v3s16 pos); // For debug printing - virtual void PrintInfo(std::ostream &out); + void PrintInfo(std::ostream &out) override; bool isSavingEnabled(){ return m_map_saving_enabled; } diff --git a/src/network/connection.h b/src/network/connection.h index 88e323bb1..b5ae24882 100644 --- a/src/network/connection.h +++ b/src/network/connection.h @@ -194,7 +194,7 @@ struct BufferedPacket { u16 getSeqnum() const; - inline const size_t size() const { return m_data.size(); } + inline size_t size() const { return m_data.size(); } u8 *data; // Direct memory access float time = 0.0f; // Seconds from buffering the packet or re-sending diff --git a/src/network/socket.cpp b/src/network/socket.cpp index 0bb7ea234..97a5f19f7 100644 --- a/src/network/socket.cpp +++ b/src/network/socket.cpp @@ -231,7 +231,7 @@ void UDPSocket::Send(const Address &destination, const void *data, int size) int sent; if (m_addr_family == AF_INET6) { - struct sockaddr_in6 address = {0}; + struct sockaddr_in6 address = {}; address.sin6_family = AF_INET6; address.sin6_addr = destination.getAddress6(); address.sin6_port = htons(destination.getPort()); @@ -239,7 +239,7 @@ void UDPSocket::Send(const Address &destination, const void *data, int size) sent = sendto(m_handle, (const char *)data, size, 0, (struct sockaddr *)&address, sizeof(struct sockaddr_in6)); } else { - struct sockaddr_in address = {0}; + struct sockaddr_in address = {}; address.sin_family = AF_INET; address.sin_addr = destination.getAddress(); address.sin_port = htons(destination.getPort()); -- cgit v1.2.3 From 0704ca055059088bdd53e15be672e6b5663b8f50 Mon Sep 17 00:00:00 2001 From: paradust7 <102263465+paradust7@users.noreply.github.com> Date: Wed, 4 May 2022 11:55:01 -0700 Subject: Make logging cost free when there is no output target (#12247) The logging streams now do almost no work when there is no output target for them. For example, if LL_VERBOSE has no output targets, then `verbosestream << x` will return a StreamProxy with a null target. Any further `<<` operations applied to it will do nothing. --- builtin/settingtypes.txt | 5 +- minetest.conf.example | 5 +- src/client/game.cpp | 2 +- src/client/renderingengine.cpp | 2 +- src/log.cpp | 187 ++++++++++++----------------------- src/log.h | 202 +++++++++++++++++++++++++++++++++----- src/main.cpp | 16 ++- src/network/address.cpp | 8 +- src/network/address.h | 2 +- src/network/connection.cpp | 17 +--- src/network/connectionthreads.cpp | 10 +- src/network/socket.cpp | 4 +- src/server.cpp | 2 +- src/util/stream.h | 70 +++++++++++++ 14 files changed, 338 insertions(+), 194 deletions(-) create mode 100644 src/util/stream.h (limited to 'src/network') diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index a983a8f6b..e3589d76f 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -1468,7 +1468,8 @@ language (Language) enum ,be,bg,ca,cs,da,de,el,en,eo,es,et,eu,fi,fr,gd,gl,hu,i # - action # - info # - verbose -debug_log_level (Debug log level) enum action ,none,error,warning,action,info,verbose +# - trace +debug_log_level (Debug log level) enum action ,none,error,warning,action,info,verbose,trace # If the file size of debug.txt exceeds the number of megabytes specified in # this setting when it is opened, the file is moved to debug.txt.1, @@ -1477,7 +1478,7 @@ debug_log_level (Debug log level) enum action ,none,error,warning,action,info,ve debug_log_size_max (Debug log file size threshold) int 50 # Minimal level of logging to be written to chat. -chat_log_level (Chat log level) enum error ,none,error,warning,action,info,verbose +chat_log_level (Chat log level) enum error ,none,error,warning,action,info,verbose,trace # Enable IPv6 support (for both client and server). # Required for IPv6 connections to work at all. diff --git a/minetest.conf.example b/minetest.conf.example index 3cdb15026..68757680c 100644 --- a/minetest.conf.example +++ b/minetest.conf.example @@ -1768,7 +1768,8 @@ # - action # - info # - verbose -# type: enum values: , none, error, warning, action, info, verbose +# - trace +# type: enum values: , none, error, warning, action, info, verbose, trace # debug_log_level = action # If the file size of debug.txt exceeds the number of megabytes specified in @@ -1779,7 +1780,7 @@ # debug_log_size_max = 50 # Minimal level of logging to be written to chat. -# type: enum values: , none, error, warning, action, info, verbose +# type: enum values: , none, error, warning, action, info, verbose, trace # chat_log_level = error # Enable IPv6 support (for both client and server). diff --git a/src/client/game.cpp b/src/client/game.cpp index e0e60eb2c..1e34ca286 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1491,7 +1491,7 @@ bool Game::connectToServer(const GameStartData &start_data, client->m_simple_singleplayer_mode = simple_singleplayer_mode; infostream << "Connecting to server at "; - connect_address.print(&infostream); + connect_address.print(infostream); infostream << std::endl; client->connect(connect_address, diff --git a/src/client/renderingengine.cpp b/src/client/renderingengine.cpp index 723865db4..455d5e538 100644 --- a/src/client/renderingengine.cpp +++ b/src/client/renderingengine.cpp @@ -116,7 +116,7 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver) } SIrrlichtCreationParameters params = SIrrlichtCreationParameters(); - if (g_logger.getTraceEnabled()) + if (tracestream) params.LoggingLevel = irr::ELL_DEBUG; params.DriverType = driverType; params.WindowSize = core::dimension2d(screen_w, screen_h); diff --git a/src/log.cpp b/src/log.cpp index 3c61414e9..51652fe0a 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -35,43 +35,30 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include -const int BUFFER_LENGTH = 256; - -class StringBuffer : public std::streambuf { +class LevelTarget : public LogTarget { public: - StringBuffer() { - buffer_index = 0; - } - - int overflow(int c); - virtual void flush(const std::string &buf) = 0; - std::streamsize xsputn(const char *s, std::streamsize n); - void push_back(char c); - -private: - char buffer[BUFFER_LENGTH]; - int buffer_index; -}; - - -class LogBuffer : public StringBuffer { -public: - LogBuffer(Logger &logger, LogLevel lev) : - logger(logger), - level(lev) + LevelTarget(Logger &logger, LogLevel level, bool raw = false) : + m_logger(logger), + m_level(level), + m_raw(raw) {} - void flush(const std::string &buffer); - -private: - Logger &logger; - LogLevel level; -}; + virtual bool hasOutput() override { + return m_logger.hasOutput(m_level); + } + virtual void log(const std::string &buf) override { + if (!m_raw) { + m_logger.log(m_level, buf); + } else { + m_logger.logRaw(m_level, buf); + } + } -class RawLogBuffer : public StringBuffer { -public: - void flush(const std::string &buffer); +private: + Logger &m_logger; + LogLevel m_level; + bool m_raw; }; //// @@ -80,31 +67,33 @@ public: Logger g_logger; +#ifdef __ANDROID__ +AndroidLogOutput stdout_output; +AndroidLogOutput stderr_output; +#else StreamLogOutput stdout_output(std::cout); StreamLogOutput stderr_output(std::cerr); -std::ostream null_stream(NULL); - -RawLogBuffer raw_buf; - -LogBuffer none_buf(g_logger, LL_NONE); -LogBuffer error_buf(g_logger, LL_ERROR); -LogBuffer warning_buf(g_logger, LL_WARNING); -LogBuffer action_buf(g_logger, LL_ACTION); -LogBuffer info_buf(g_logger, LL_INFO); -LogBuffer verbose_buf(g_logger, LL_VERBOSE); - -// Connection -std::ostream *dout_con_ptr = &null_stream; -std::ostream *derr_con_ptr = &verbosestream; - -// Common streams -std::ostream rawstream(&raw_buf); -std::ostream dstream(&none_buf); -std::ostream errorstream(&error_buf); -std::ostream warningstream(&warning_buf); -std::ostream actionstream(&action_buf); -std::ostream infostream(&info_buf); -std::ostream verbosestream(&verbose_buf); +#endif + +LevelTarget none_target_raw(g_logger, LL_NONE, true); +LevelTarget none_target(g_logger, LL_NONE); +LevelTarget error_target(g_logger, LL_ERROR); +LevelTarget warning_target(g_logger, LL_WARNING); +LevelTarget action_target(g_logger, LL_ACTION); +LevelTarget info_target(g_logger, LL_INFO); +LevelTarget verbose_target(g_logger, LL_VERBOSE); +LevelTarget trace_target(g_logger, LL_TRACE); + +thread_local LogStream dstream(none_target); +thread_local LogStream rawstream(none_target_raw); +thread_local LogStream errorstream(error_target); +thread_local LogStream warningstream(warning_target); +thread_local LogStream actionstream(action_target); +thread_local LogStream infostream(info_target); +thread_local LogStream verbosestream(verbose_target); +thread_local LogStream tracestream(trace_target); +thread_local LogStream derr_con(verbose_target); +thread_local LogStream dout_con(trace_target); // Android #ifdef __ANDROID__ @@ -118,29 +107,15 @@ static unsigned int g_level_to_android[] = { //ANDROID_LOG_INFO, ANDROID_LOG_DEBUG, // LL_INFO ANDROID_LOG_VERBOSE, // LL_VERBOSE + ANDROID_LOG_VERBOSE, // LL_TRACE }; -class AndroidSystemLogOutput : public ICombinedLogOutput { - public: - AndroidSystemLogOutput() - { - g_logger.addOutput(this); - } - ~AndroidSystemLogOutput() - { - g_logger.removeOutput(this); - } - void logRaw(LogLevel lev, const std::string &line) - { - STATIC_ASSERT(ARRLEN(g_level_to_android) == LL_MAX, - mismatch_between_android_and_internal_loglevels); - __android_log_print(g_level_to_android[lev], - PROJECT_NAME_C, "%s", line.c_str()); - } -}; - -AndroidSystemLogOutput g_android_log_output; - +void AndroidLogOutput::logRaw(LogLevel lev, const std::string &line) { + STATIC_ASSERT(ARRLEN(g_level_to_android) == LL_MAX, + mismatch_between_android_and_internal_loglevels); + __android_log_print(g_level_to_android[lev], + PROJECT_NAME_C, "%s", line.c_str()); +} #endif /////////////////////////////////////////////////////////////////////////////// @@ -164,6 +139,8 @@ LogLevel Logger::stringToLevel(const std::string &name) return LL_INFO; else if (name == "verbose") return LL_VERBOSE; + else if (name == "trace") + return LL_TRACE; else return LL_MAX; } @@ -176,21 +153,26 @@ void Logger::addOutput(ILogOutput *out) void Logger::addOutput(ILogOutput *out, LogLevel lev) { m_outputs[lev].push_back(out); + m_has_outputs[lev] = true; } void Logger::addOutputMasked(ILogOutput *out, LogLevelMask mask) { for (size_t i = 0; i < LL_MAX; i++) { - if (mask & LOGLEVEL_TO_MASKLEVEL(i)) + if (mask & LOGLEVEL_TO_MASKLEVEL(i)) { m_outputs[i].push_back(out); + m_has_outputs[i] = true; + } } } void Logger::addOutputMaxLevel(ILogOutput *out, LogLevel lev) { assert(lev < LL_MAX); - for (size_t i = 0; i <= lev; i++) + for (size_t i = 0; i <= lev; i++) { m_outputs[i].push_back(out); + m_has_outputs[i] = true; + } } LogLevelMask Logger::removeOutput(ILogOutput *out) @@ -203,6 +185,7 @@ LogLevelMask Logger::removeOutput(ILogOutput *out) if (it != m_outputs[i].end()) { ret_mask |= LOGLEVEL_TO_MASKLEVEL(i); m_outputs[i].erase(it); + m_has_outputs[i] = !m_outputs[i].empty(); } } return ret_mask; @@ -236,6 +219,7 @@ const std::string Logger::getLevelLabel(LogLevel lev) "ACTION", "INFO", "VERBOSE", + "TRACE", }; assert(lev < LL_MAX && lev >= 0); STATIC_ASSERT(ARRLEN(names) == LL_MAX, @@ -297,7 +281,6 @@ void Logger::logToOutputs(LogLevel lev, const std::string &combined, m_outputs[lev][i]->log(lev, combined, time, thread_name, payload_text); } - //// //// *LogOutput methods //// @@ -349,6 +332,7 @@ void StreamLogOutput::logRaw(LogLevel lev, const std::string &line) m_stream << "\033[37m"; break; case LL_VERBOSE: + case LL_TRACE: // verbose is darker than info m_stream << "\033[2m"; break; @@ -396,6 +380,7 @@ void LogOutputBuffer::logRaw(LogLevel lev, const std::string &line) color = "\x1b(c@#BBB)"; break; case LL_VERBOSE: // dark grey + case LL_TRACE: color = "\x1b(c@#888)"; break; default: break; @@ -404,47 +389,3 @@ void LogOutputBuffer::logRaw(LogLevel lev, const std::string &line) m_buffer.push(color.append(line)); } - -//// -//// *Buffer methods -//// - -int StringBuffer::overflow(int c) -{ - push_back(c); - return c; -} - - -std::streamsize StringBuffer::xsputn(const char *s, std::streamsize n) -{ - for (int i = 0; i < n; ++i) - push_back(s[i]); - return n; -} - -void StringBuffer::push_back(char c) -{ - if (c == '\n' || c == '\r') { - if (buffer_index) - flush(std::string(buffer, buffer_index)); - buffer_index = 0; - } else { - buffer[buffer_index++] = c; - if (buffer_index >= BUFFER_LENGTH) { - flush(std::string(buffer, buffer_index)); - buffer_index = 0; - } - } -} - - -void LogBuffer::flush(const std::string &buffer) -{ - logger.log(level, buffer); -} - -void RawLogBuffer::flush(const std::string &buffer) -{ - g_logger.logRaw(LL_NONE, buffer); -} diff --git a/src/log.h b/src/log.h index 6ed6b1fb7..5c6ba7d64 100644 --- a/src/log.h +++ b/src/log.h @@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once +#include #include #include #include @@ -28,6 +29,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #if !defined(_WIN32) // POSIX #include #endif +#include "util/basic_macros.h" +#include "util/stream.h" #include "irrlichttypes.h" class ILogOutput; @@ -39,6 +42,7 @@ enum LogLevel { LL_ACTION, // In-game actions LL_INFO, LL_VERBOSE, + LL_TRACE, LL_MAX, }; @@ -67,12 +71,13 @@ public: // Logs without a prefix void logRaw(LogLevel lev, const std::string &text); - void setTraceEnabled(bool enable) { m_trace_enabled = enable; } - bool getTraceEnabled() { return m_trace_enabled; } - static LogLevel stringToLevel(const std::string &name); static const std::string getLevelLabel(LogLevel lev); + bool hasOutput(LogLevel level) { + return m_has_outputs[level].load(std::memory_order_relaxed); + } + static LogColor color_mode; private: @@ -84,6 +89,7 @@ private: const std::string getThreadName(); std::vector m_outputs[LL_MAX]; + std::atomic m_has_outputs[LL_MAX]; // Should implement atomic loads and stores (even though it's only // written to when one thread has access currently). @@ -91,7 +97,6 @@ private: volatile bool m_silenced_levels[LL_MAX]; std::map m_thread_names; mutable std::mutex m_mutex; - bool m_trace_enabled; }; class ILogOutput { @@ -185,35 +190,178 @@ private: Logger &m_logger; }; +#ifdef __ANDROID__ +class AndroidLogOutput : public ICombinedLogOutput { +public: + void logRaw(LogLevel lev, const std::string &line); +}; +#endif -extern StreamLogOutput stdout_output; -extern StreamLogOutput stderr_output; -extern std::ostream null_stream; +/* + * LogTarget + * + * This is the interface that sits between the LogStreams and the global logger. + * Primarily used to route streams to log levels, but could also enable other + * custom behavior. + * + */ +class LogTarget { +public: + // Must be thread-safe. These can be called from any thread. + virtual bool hasOutput() = 0; + virtual void log(const std::string &buf) = 0; +}; -extern std::ostream *dout_con_ptr; -extern std::ostream *derr_con_ptr; -extern std::ostream *derr_server_ptr; -extern Logger g_logger; +/* + * StreamProxy + * + * An ostream-like object that can proxy to a real ostream or do nothing, + * depending on how it is configured. See LogStream below. + * + */ +class StreamProxy { +public: + StreamProxy(std::ostream *os) : m_os(os) { } + + template + StreamProxy& operator<<(T&& arg) { + if (m_os) { + *m_os << std::forward(arg); + } + return *this; + } -// Writes directly to all LL_NONE log outputs for g_logger with no prefix. -extern std::ostream rawstream; + StreamProxy& operator<<(std::ostream& (*manip)(std::ostream&)) { + if (m_os) { + *m_os << manip; + } + return *this; + } -extern std::ostream errorstream; -extern std::ostream warningstream; -extern std::ostream actionstream; -extern std::ostream infostream; -extern std::ostream verbosestream; -extern std::ostream dstream; +private: + std::ostream *m_os; +}; -#define TRACEDO(x) do { \ - if (g_logger.getTraceEnabled()) { \ - x; \ - } \ -} while (0) -#define TRACESTREAM(x) TRACEDO(verbosestream x) +/* + * LogStream + * + * The public interface for log streams (infostream, verbosestream, etc). + * + * LogStream minimizes the work done when a given stream is off. (meaning + * it has no output targets, so it goes to /dev/null) + * + * For example, consider: + * + * verbosestream << "hello world" << 123 << std::endl; + * + * The compiler evaluates this as: + * + * (((verbosestream << "hello world") << 123) << std::endl) + * ^ ^ + * + * If `verbosestream` is on, the innermost expression (marked by ^) will return + * a StreamProxy that forwards to a real ostream, that feeds into the logger. + * However, if `verbosestream` is off, it will return a StreamProxy that does + * nothing on all later operations. Specifically, CPU time won't be wasted + * writing "hello world" and 123 into a buffer, or formatting the log entry. + * + * It is also possible to directly check if the stream is on/off: + * + * if (verbosestream) { + * auto data = ComputeExpensiveDataForTheLog(); + * verbosestream << data << endl; + * } + * +*/ -#define dout_con (*dout_con_ptr) -#define derr_con (*derr_con_ptr) +class LogStream { +public: + LogStream() = delete; + DISABLE_CLASS_COPY(LogStream); + + LogStream(LogTarget &target) : + m_target(target), + m_buffer(std::bind(&LogStream::internalFlush, this, std::placeholders::_1)), + m_dummy_buffer(), + m_stream(&m_buffer), + m_dummy_stream(&m_dummy_buffer), + m_proxy(&m_stream), + m_dummy_proxy(nullptr) { } + + template + StreamProxy& operator<<(T&& arg) { + StreamProxy& sp = m_target.hasOutput() ? m_proxy : m_dummy_proxy; + sp << std::forward(arg); + return sp; + } + StreamProxy& operator<<(std::ostream& (*manip)(std::ostream&)) { + StreamProxy& sp = m_target.hasOutput() ? m_proxy : m_dummy_proxy; + sp << manip; + return sp; + } + + operator bool() { + return m_target.hasOutput(); + } + + void internalFlush(const std::string &buf) { + m_target.log(buf); + } + + operator std::ostream&() { + return m_target.hasOutput() ? m_stream : m_dummy_stream; + } + +private: + // 10 streams per thread x (256 + overhead) ~ 3K per thread + static const int BUFFER_LENGTH = 256; + LogTarget &m_target; + StringStreamBuffer m_buffer; + DummyStreamBuffer m_dummy_buffer; + std::ostream m_stream; + std::ostream m_dummy_stream; + StreamProxy m_proxy; + StreamProxy m_dummy_proxy; + +}; + +#ifdef __ANDROID__ +extern AndroidLogOutput stdout_output; +extern AndroidLogOutput stderr_output; +#else +extern StreamLogOutput stdout_output; +extern StreamLogOutput stderr_output; +#endif + +extern Logger g_logger; + +/* + * By making the streams thread_local, each thread has its own + * private buffer. Two or more threads can write to the same stream + * simultaneously (lock-free), and there won't be any interference. + * + * The finished lines are sent to a LogTarget which is a global (not thread-local) + * object, and from there relayed to g_logger. The final writes are serialized + * by the mutex in g_logger. +*/ + +extern thread_local LogStream dstream; +extern thread_local LogStream rawstream; // Writes directly to all LL_NONE log outputs with no prefix. +extern thread_local LogStream errorstream; +extern thread_local LogStream warningstream; +extern thread_local LogStream actionstream; +extern thread_local LogStream infostream; +extern thread_local LogStream verbosestream; +extern thread_local LogStream tracestream; +// TODO: Search/replace these with verbose/tracestream +extern thread_local LogStream derr_con; +extern thread_local LogStream dout_con; + +#define TRACESTREAM(x) do { \ + if (tracestream) { \ + tracestream x; \ + } \ +} while (0) diff --git a/src/main.cpp b/src/main.cpp index 5ea212d8a..ddd725134 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -453,14 +453,6 @@ static bool setup_log_params(const Settings &cmd_args) } } - // If trace is enabled, enable logging of certain things - if (cmd_args.getFlag("trace")) { - dstream << _("Enabling trace level debug output") << std::endl; - g_logger.setTraceEnabled(true); - dout_con_ptr = &verbosestream; // This is somewhat old - socket_enable_debug_output = true; // Sockets doesn't use log.h - } - // In certain cases, output info level on stderr if (cmd_args.getFlag("info") || cmd_args.getFlag("verbose") || cmd_args.getFlag("trace") || cmd_args.getFlag("speedtests")) @@ -470,6 +462,12 @@ static bool setup_log_params(const Settings &cmd_args) if (cmd_args.getFlag("verbose") || cmd_args.getFlag("trace")) g_logger.addOutput(&stderr_output, LL_VERBOSE); + if (cmd_args.getFlag("trace")) { + dstream << _("Enabling trace level debug output") << std::endl; + g_logger.addOutput(&stderr_output, LL_TRACE); + socket_enable_debug_output = true; + } + return true; } @@ -599,7 +597,7 @@ static void init_log_streams(const Settings &cmd_args) warningstream << "Deprecated use of debug_log_level with an " "integer value; please update your configuration." << std::endl; static const char *lev_name[] = - {"", "error", "action", "info", "verbose"}; + {"", "error", "action", "info", "verbose", "trace"}; int lev_i = atoi(conf_loglev.c_str()); if (lev_i < 0 || lev_i >= (int)ARRLEN(lev_name)) { warningstream << "Supplied invalid debug_log_level!" diff --git a/src/network/address.cpp b/src/network/address.cpp index 90e561802..cf2e6208d 100644 --- a/src/network/address.cpp +++ b/src/network/address.cpp @@ -230,14 +230,14 @@ void Address::setPort(u16 port) m_port = port; } -void Address::print(std::ostream *s) const +void Address::print(std::ostream& s) const { if (m_addr_family == AF_INET6) - *s << "[" << serializeString() << "]:" << m_port; + s << "[" << serializeString() << "]:" << m_port; else if (m_addr_family == AF_INET) - *s << serializeString() << ":" << m_port; + s << serializeString() << ":" << m_port; else - *s << "(undefined)"; + s << "(undefined)"; } bool Address::isLocalhost() const diff --git a/src/network/address.h b/src/network/address.h index c2f5f2eef..692bf82c5 100644 --- a/src/network/address.h +++ b/src/network/address.h @@ -59,7 +59,7 @@ public: int getFamily() const { return m_addr_family; } bool isIPv6() const { return m_addr_family == AF_INET6; } bool isZero() const; - void print(std::ostream *s) const; + void print(std::ostream &s) const; std::string serializeString() const; bool isLocalhost() const; diff --git a/src/network/connection.cpp b/src/network/connection.cpp index 2d3cf6e88..6fb676f25 100644 --- a/src/network/connection.cpp +++ b/src/network/connection.cpp @@ -41,25 +41,14 @@ namespace con /* defines used for debugging and profiling */ /******************************************************************************/ #ifdef NDEBUG - #define LOG(a) a #define PROFILE(a) #else - #if 0 - /* this mutex is used to achieve log message consistency */ - std::mutex log_message_mutex; - #define LOG(a) \ - { \ - MutexAutoLock loglock(log_message_mutex); \ - a; \ - } - #else - // Prevent deadlocks until a solution is found after 5.2.0 (TODO) - #define LOG(a) a - #endif - #define PROFILE(a) a #endif +// TODO: Clean this up. +#define LOG(a) a + #define PING_TIMEOUT 5.0 u16 BufferedPacket::getSeqnum() const diff --git a/src/network/connectionthreads.cpp b/src/network/connectionthreads.cpp index dca065ae1..90936b43d 100644 --- a/src/network/connectionthreads.cpp +++ b/src/network/connectionthreads.cpp @@ -32,22 +32,18 @@ namespace con /* defines used for debugging and profiling */ /******************************************************************************/ #ifdef NDEBUG -#define LOG(a) a #define PROFILE(a) #undef DEBUG_CONNECTION_KBPS #else /* this mutex is used to achieve log message consistency */ -std::mutex log_conthread_mutex; -#define LOG(a) \ - { \ - MutexAutoLock loglock(log_conthread_mutex); \ - a; \ - } #define PROFILE(a) a //#define DEBUG_CONNECTION_KBPS #undef DEBUG_CONNECTION_KBPS #endif +// TODO: Clean this up. +#define LOG(a) a + #define WINDOW_SIZE 5 static session_t readPeerId(const u8 *packetdata) diff --git a/src/network/socket.cpp b/src/network/socket.cpp index 97a5f19f7..df15c89ba 100644 --- a/src/network/socket.cpp +++ b/src/network/socket.cpp @@ -198,7 +198,7 @@ void UDPSocket::Send(const Address &destination, const void *data, int size) if (socket_enable_debug_output) { // Print packet destination and size dstream << (int)m_handle << " -> "; - destination.print(&dstream); + destination.print(dstream); dstream << ", size=" << size; // Print packet contents @@ -295,7 +295,7 @@ int UDPSocket::Receive(Address &sender, void *data, int size) if (socket_enable_debug_output) { // Print packet sender and size dstream << (int)m_handle << " <- "; - sender.print(&dstream); + sender.print(dstream); dstream << ", size=" << received; // Print packet contents diff --git a/src/server.cpp b/src/server.cpp index c9cd4e398..6a4349ba5 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -525,7 +525,7 @@ void Server::start() actionstream << "World at [" << m_path_world << "]" << std::endl; actionstream << "Server for gameid=\"" << m_gamespec.id << "\" listening on "; - m_bind_addr.print(&actionstream); + m_bind_addr.print(actionstream); actionstream << "." << std::endl; } diff --git a/src/util/stream.h b/src/util/stream.h new file mode 100644 index 000000000..2e61b46d2 --- /dev/null +++ b/src/util/stream.h @@ -0,0 +1,70 @@ +/* +Minetest +Copyright (C) 2022 Minetest Authors + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#pragma once + +#include +#include +#include + +template > +class StringStreamBuffer : public std::streambuf { +public: + StringStreamBuffer(Emitter emitter) : m_emitter(emitter) { + buffer_index = 0; + } + + int overflow(int c) { + push_back(c); + return c; + } + + void push_back(char c) { + if (c == '\n' || c == '\r') { + if (buffer_index) + m_emitter(std::string(buffer, buffer_index)); + buffer_index = 0; + } else { + buffer[buffer_index++] = c; + if (buffer_index >= BufferLength) { + m_emitter(std::string(buffer, buffer_index)); + buffer_index = 0; + } + } + } + + std::streamsize xsputn(const char *s, std::streamsize n) { + for (int i = 0; i < n; ++i) + push_back(s[i]); + return n; + } +private: + Emitter m_emitter; + char buffer[BufferLength]; + int buffer_index; +}; + +class DummyStreamBuffer : public std::streambuf { + int overflow(int c) { + return c; + } + std::streamsize xsputn(const char *s, std::streamsize n) { + return n; + } +}; -- cgit v1.2.3