From 8167c04b83aa3cdc19da11003769eb8776b3b817 Mon Sep 17 00:00:00 2001 From: Andrey2470T Date: Sat, 9 Mar 2024 16:50:28 +0300 Subject: [PATCH] Force set/get_wielded_item() to access to itemstack of current used hand --- src/client/camera.h | 3 +- src/client/game.cpp | 36 ++++++++++++------- src/network/serverpackethandler.cpp | 55 ++++++++++++++++++++--------- src/player.cpp | 51 +++++++++++++++++++++++--- src/player.h | 9 +++-- src/server/player_sao.cpp | 26 +++++++++++--- src/server/player_sao.h | 4 ++- 7 files changed, 140 insertions(+), 44 deletions(-) diff --git a/src/client/camera.h b/src/client/camera.h index d67b67992..ee646aabb 100644 --- a/src/client/camera.h +++ b/src/client/camera.h @@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include +#include "player.h" class LocalPlayer; struct MapDrawControl; @@ -72,8 +73,6 @@ struct Nametag } }; -enum HandIndex { MAINHAND = 0, OFFHAND = 1 }; - class WieldNode { public: diff --git a/src/client/game.cpp b/src/client/game.cpp index 0a2120a4c..1bfe0a296 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -776,10 +776,10 @@ protected: const core::line3d &shootline, bool liquids_pointable, const std::optional &pointabilities, bool look_for_object, const v3s16 &camera_offset); - void handlePointingAtNothing(const ItemStack &playerItem); + void handlePointingAtNothing(HandIndex used_hand); void handlePointingAtNode(const PointedThing &pointed, const ItemStack &selected_item, const ItemStack &hand_item, - const ItemStack &place_item, f32 dtime); + HandIndex used_hand, f32 dtime); void handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem, const v3f &player_position, bool show_debug); void handleDigging(const PointedThing &pointed, const v3s16 &nodepos, @@ -3342,8 +3342,6 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud) !runData.btn_down_for_dig, camera_offset); - player->getOffhandWieldedItem(&offhand_item, &place_item, itemdef_manager, pointed); - if (pointed != runData.pointed_old) infostream << "Pointing at " << pointed.dump() << std::endl; @@ -3409,12 +3407,14 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud) else runData.repeat_place_timer = 0; + HandIndex cur_used_hand = player->getCurrentUsedHand(itemdef_manager, pointed); + if (selected_def.usable && isKeyDown(KeyType::DIG)) { if (wasKeyPressed(KeyType::DIG) && (!client->modsLoaded() || !client->getScript()->on_item_use(selected_item, pointed))) client->interact(INTERACT_USE, pointed); } else if (pointed.type == POINTEDTHING_NODE) { - handlePointingAtNode(pointed, selected_item, hand_item, place_item, dtime); + handlePointingAtNode(pointed, selected_item, hand_item, cur_used_hand, dtime); } else if (pointed.type == POINTEDTHING_OBJECT) { v3f player_position = player->getPosition(); bool basic_debug_allowed = client->checkPrivilege("debug") || (player->hud_flags & HUD_FLAG_BASIC_DEBUG); @@ -3427,7 +3427,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud) if (wasKeyPressed(KeyType::DIG) && client->modsLoaded()) client->getScript()->on_item_use(selected_item, pointed); } else if (wasKeyPressed(KeyType::PLACE)) { - handlePointingAtNothing(place_item); + handlePointingAtNothing(cur_used_hand); } runData.pointed_old = pointed; @@ -3548,7 +3548,7 @@ PointedThing Game::updatePointedThing( } -void Game::handlePointingAtNothing(const ItemStack &playerItem) +void Game::handlePointingAtNothing(HandIndex used_hand) { infostream << "Attempted to place item while pointing at nothing" << std::endl; PointedThing fauxPointed; @@ -3559,7 +3559,7 @@ void Game::handlePointingAtNothing(const ItemStack &playerItem) void Game::handlePointingAtNode(const PointedThing &pointed, const ItemStack &selected_item, const ItemStack &hand_item, - const ItemStack &place_item, f32 dtime) + HandIndex used_hand, f32 dtime) { v3s16 nodepos = pointed.node_undersurface; v3s16 neighborpos = pointed.node_abovesurface; @@ -3593,14 +3593,14 @@ void Game::handlePointingAtNode(const PointedThing &pointed, if ((wasKeyPressed(KeyType::PLACE) || runData.repeat_place_timer >= m_repeat_place_time) && client->checkPrivilege("interact")) { + LocalPlayer *player = client->getEnv().getLocalPlayer(); + player->current_used_hand = used_hand; + runData.repeat_place_timer = 0; infostream << "Place button pressed while looking at ground" << std::endl; // Placing animation (always shown for feedback) - if (place_item == selected_item) - camera->setDigging(1, MAINHAND); - else - camera->setDigging(1, OFFHAND); + camera->setDigging(1, used_hand); soundmaker->m_player_rightpunch_sound = SoundSpec(); @@ -3608,12 +3608,22 @@ void Game::handlePointingAtNode(const PointedThing &pointed, // make that happen // And also set the sound and send the interact // But first check for meta formspec and rightclickable + ItemStack place_item; + + if (used_hand == MAINHAND) + player->getWieldedItem(&place_item, nullptr); + else + player->getOffhandWieldedItem(&place_item); + auto &def = place_item.getDefinition(itemdef_manager); bool placed = nodePlacement(def, place_item, nodepos, neighborpos, pointed, meta); if (placed && client->modsLoaded()) client->getScript()->on_placenode(pointed, def); + + // Resets the hand index after 'on_place' callback run. + player->current_used_hand = MAINHAND; } } @@ -4154,7 +4164,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, ItemStack selected_item, hand_item, offhand_item; ItemStack &tool_item = player->getWieldedItem(&selected_item, &hand_item); camera->wield(tool_item, MAINHAND); - player->getOffhandWieldedItem(&offhand_item, nullptr, itemdef_manager, PointedThing()); + player->getOffhandWieldedItem(&offhand_item); camera->wield(offhand_item, OFFHAND); } diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index 1489d84c1..db66cc339 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -919,12 +919,10 @@ static inline void getWieldedItem(const PlayerSAO *playersao, std::optionalgetWieldedItem(&(*ret)); } -static inline bool getOffhandWieldedItem(const PlayerSAO *playersao, std::optional &offhand, - std::optional &place, IItemDefManager *idef, const PointedThing &pointed) +static inline void getOffhandWieldedItem(const PlayerSAO *playersao, std::optional &offhand) { offhand = ItemStack(); - place = ItemStack(); - return playersao->getOffhandWieldedItem(&(*offhand), &(*place), idef, pointed); + playersao->getOffhandWieldedItem(&(*offhand)); } void Server::handleCommand_Interact(NetworkPacket *pkt) @@ -1237,7 +1235,14 @@ void Server::handleCommand_Interact(NetworkPacket *pkt) case INTERACT_PLACE: { std::optional main_item, offhand_item, place_item; getWieldedItem(playersao, main_item); - bool use_offhand = getOffhandWieldedItem(playersao, offhand_item, place_item, m_itemdef, pointed); + getOffhandWieldedItem(playersao, offhand_item); + + HandIndex used_hand = playersao->getCurrentUsedHand(m_itemdef, pointed); + + if (used_hand == MAINHAND) + place_item = main_item; + else + place_item = offhand_item; // Reset build time counter if (pointed.type == POINTEDTHING_NODE && @@ -1259,22 +1264,30 @@ void Server::handleCommand_Interact(NetworkPacket *pkt) << pointed_object->getDescription() << std::endl; // Do stuff - if (m_script->item_OnSecondaryUse(use_offhand ? offhand_item : main_item, playersao, pointed)) { - if (use_offhand + playersao->getPlayer()->current_used_hand = used_hand; + if (m_script->item_OnSecondaryUse(used_hand == MAINHAND ? main_item : offhand_item, playersao, pointed)) { + if (used_hand == OFFHAND ? (offhand_item.has_value() && playersao->setOffhandWieldedItem(*offhand_item)) : (main_item.has_value() && playersao->setWieldedItem(*main_item))) SendInventory(player, true); } - pointed_object->rightClick(playersao); - } else if (m_script->item_OnPlace(use_offhand ? offhand_item : main_item, playersao, pointed)) { - // Placement was handled in lua + playersao->getPlayer()->current_used_hand = MAINHAND; - // Apply returned ItemStack - if (use_offhand - ? (offhand_item.has_value() && playersao->setOffhandWieldedItem(*offhand_item)) - : (main_item.has_value() && playersao->setWieldedItem(*main_item))) + pointed_object->rightClick(playersao); + } + else { + playersao->getPlayer()->current_used_hand = used_hand; + if (m_script->item_OnPlace(used_hand == MAINHAND ? main_item : offhand_item, playersao, pointed)) { + // Placement was handled in lua + + // Apply returned ItemStack + if (used_hand == OFFHAND + ? (offhand_item.has_value() && playersao->setOffhandWieldedItem(*offhand_item)) + : (main_item.has_value() && playersao->setWieldedItem(*main_item))) SendInventory(player, true); + } + playersao->getPlayer()->current_used_hand = MAINHAND; } if (pointed.type != POINTEDTHING_NODE) @@ -1318,20 +1331,28 @@ void Server::handleCommand_Interact(NetworkPacket *pkt) case INTERACT_ACTIVATE: { std::optional main_item, offhand_item, place_item; getWieldedItem(playersao, main_item); - bool use_offhand = getOffhandWieldedItem(playersao, offhand_item, place_item, m_itemdef, pointed); + getOffhandWieldedItem(playersao, offhand_item); + HandIndex used_hand = playersao->getCurrentUsedHand(m_itemdef, pointed); + + if (used_hand == MAINHAND) + place_item = main_item; + else + place_item = offhand_item; actionstream << player->getName() << " activates " << place_item->name << std::endl; pointed.type = POINTEDTHING_NOTHING; // can only ever be NOTHING - if (m_script->item_OnSecondaryUse(use_offhand ? offhand_item : main_item, playersao, pointed)) { + playersao->getPlayer()->current_used_hand = used_hand; + if (m_script->item_OnSecondaryUse(used_hand == MAINHAND ? main_item : offhand_item, playersao, pointed)) { // Apply returned ItemStack - if (use_offhand + if (used_hand == OFFHAND ? (offhand_item.has_value() && playersao->setOffhandWieldedItem(*offhand_item)) : (main_item.has_value() && playersao->setWieldedItem(*main_item))) SendInventory(player, true); } + playersao->getPlayer()->current_used_hand = MAINHAND; return; } diff --git a/src/player.cpp b/src/player.cpp index 2079bfea3..5b7edea90 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -41,6 +41,7 @@ Player::Player(const char *name, IItemDefManager *idef): craft->setWidth(3); inventory.addList("craftpreview", 1); inventory.addList("craftresult", 1); + inventory.addList("offhand", 1); inventory.setModified(false); // Can be redefined via Lua @@ -95,8 +96,12 @@ ItemStack &Player::getWieldedItem(ItemStack *selected, ItemStack *hand) const const InventoryList *mlist = inventory.getList("main"); // TODO: Make this generic const InventoryList *hlist = inventory.getList("hand"); - if (mlist && m_wield_index < mlist->getSize()) - *selected = mlist->getItem(m_wield_index); + if (current_used_hand == MAINHAND) { + if (mlist && m_wield_index < mlist->getSize()) + *selected = mlist->getItem(m_wield_index); + } + else + getOffhandWieldedItem(selected); if (hand && hlist) *hand = hlist->getItem(0); @@ -105,7 +110,45 @@ ItemStack &Player::getWieldedItem(ItemStack *selected, ItemStack *hand) const return (hand && selected->name.empty()) ? *hand : *selected; } -bool Player::getOffhandWieldedItem(ItemStack *offhand, ItemStack *place, IItemDefManager *idef, const PointedThing &pointed) const +void Player::getOffhandWieldedItem(ItemStack *offhand) const +{ + assert(offhand); + + const InventoryList *olist = inventory.getList("offhand"); + + if (olist) + *offhand = olist->getItem(0); +} + +HandIndex Player::getCurrentUsedHand(IItemDefManager *idef, const PointedThing &pointed) const +{ + ItemStack main, offhand; + + getWieldedItem(&main, nullptr); + getOffhandWieldedItem(&offhand); + + const ItemDefinition &main_def = main.getDefinition(idef); + const ItemDefinition &offhand_def = offhand.getDefinition(idef); + + bool main_usable, offhand_usable; + + // figure out which item to use for placements + + if (pointed.type == POINTEDTHING_NODE) { + // an item can be used on nodes if it has a place handler or prediction + main_usable = main_def.has_on_place || main_def.node_placement_prediction != ""; + offhand_usable = offhand_def.has_on_place || offhand_def.node_placement_prediction != ""; + } else { + // an item can be used on anything else if it has a secondary use handler + main_usable = main_def.has_on_secondary_use; + offhand_usable = offhand_def.has_on_secondary_use; + } + + // main hand has priority + return (HandIndex)(offhand_usable && !main_usable); +} + +/*bool Player::getOffhandWieldedItem(ItemStack *offhand, ItemStack *place, IItemDefManager *idef, const PointedThing &pointed) const { assert(offhand); @@ -143,7 +186,7 @@ bool Player::getOffhandWieldedItem(ItemStack *offhand, ItemStack *place, IItemDe *place = use_offhand ? *offhand : main; return use_offhand; -} +}*/ u32 Player::addHud(HudElement *toadd) { diff --git a/src/player.h b/src/player.h index 791b6c999..c73a95925 100644 --- a/src/player.h +++ b/src/player.h @@ -35,6 +35,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_" #define PLAYERNAME_ALLOWED_CHARS_USER_EXPL "'a' to 'z', 'A' to 'Z', '0' to '9', '-', '_'" +enum HandIndex { MAINHAND = 0, OFFHAND = 1 }; + struct PlayerFovSpec { f32 fov; @@ -224,8 +226,9 @@ public: // item currently in secondary hand is returned in `offhand` // item to use for place / secondary_use (either main or offhand) is (optionally) returned in `place` // return value: whether to use main or offhand for placing - bool getOffhandWieldedItem(ItemStack *offhand, ItemStack *place, - IItemDefManager *idef, const PointedThing &pointed) const; + void getOffhandWieldedItem(ItemStack *offhand) const; + + HandIndex getCurrentUsedHand(IItemDefManager *idef, const PointedThing &pointed) const; void setWieldIndex(u16 index); u16 getWieldIndex() const { return m_wield_index; } @@ -252,6 +255,8 @@ public: u32 hud_flags; s32 hud_hotbar_itemcount; + HandIndex current_used_hand { MAINHAND }; + protected: char m_name[PLAYERNAME_SIZE]; v3f m_speed; // velocity; in BS-space diff --git a/src/server/player_sao.cpp b/src/server/player_sao.cpp index fadd3ef3f..21f2a2c54 100644 --- a/src/server/player_sao.cpp +++ b/src/server/player_sao.cpp @@ -570,16 +570,32 @@ ItemStack PlayerSAO::getWieldedItem(ItemStack *selected, ItemStack *hand) const return m_player->getWieldedItem(selected, hand); } -bool PlayerSAO::getOffhandWieldedItem(ItemStack *offhand, ItemStack *place, IItemDefManager *itemdef_manager, PointedThing pointed) const +void PlayerSAO::getOffhandWieldedItem(ItemStack *offhand) const { - return m_player->getOffhandWieldedItem(offhand, place, itemdef_manager, pointed); + m_player->getOffhandWieldedItem(offhand); +} + +HandIndex PlayerSAO::getCurrentUsedHand(IItemDefManager *idef, const PointedThing &pointed) const +{ + return m_player->getCurrentUsedHand(idef, pointed); } bool PlayerSAO::setWieldedItem(const ItemStack &item) { - InventoryList *mlist = m_player->inventory.getList(getWieldList()); - if (mlist) { - mlist->changeItem(m_player->getWieldIndex(), item); + InventoryList *list; + u16 list_index; + + if (m_player->current_used_hand == MAINHAND) { + list = m_player->inventory.getList(getWieldList()); + list_index = m_player->getWieldIndex(); + } + else { + list = m_player->inventory.getList("offhand"); + list_index = 0; + } + + if (list) { + list->changeItem(list_index, item); return true; } return false; diff --git a/src/server/player_sao.h b/src/server/player_sao.h index cde1ab77e..16b6d9044 100644 --- a/src/server/player_sao.h +++ b/src/server/player_sao.h @@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "unit_sao.h" #include "util/numeric.h" #include "util/pointedthing.h" +#include "player.h" class IItemDefManager; @@ -137,7 +138,8 @@ public: std::string getWieldList() const override { return "main"; } u16 getWieldIndex() const override; ItemStack getWieldedItem(ItemStack *selected, ItemStack *hand = nullptr) const override; - bool getOffhandWieldedItem(ItemStack *offhand, ItemStack *place, IItemDefManager *itemdef_manager, PointedThing pointed) const; + void getOffhandWieldedItem(ItemStack *offhand) const; + HandIndex getCurrentUsedHand(IItemDefManager *idef, const PointedThing &pointed) const; bool setWieldedItem(const ItemStack &item) override; bool setOffhandWieldedItem(const ItemStack &item);