diff --git a/doc/lua_api.md b/doc/lua_api.md index 22a3361ed..f892e0a5c 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -8225,7 +8225,9 @@ child will follow movement and rotation of that bone. * See `hud_set_flags` for a list of flags that can be toggled. * `hud_set_hotbar_itemcount(count)`: sets number of items in builtin hotbar * `count`: number of items, must be between `1` and `32` + * If `count` exceeds the `"main"` list size, the list size will be used instead. * `hud_get_hotbar_itemcount()`: returns number of visible items + * This value is also clamped by the `"main"` list size. * `hud_set_hotbar_image(texturename)` * sets background image for hotbar * `hud_get_hotbar_image()`: returns texturename diff --git a/games/devtest/mods/unittests/player.lua b/games/devtest/mods/unittests/player.lua index 70b3b6cae..0dbe450b0 100644 --- a/games/devtest/mods/unittests/player.lua +++ b/games/devtest/mods/unittests/player.lua @@ -84,3 +84,25 @@ local function run_player_add_pos_tests(player) end unittests.register("test_player_add_pos", run_player_add_pos_tests, {player=true}) +-- +-- Hotbar selection clamp +-- +local function run_player_hotbar_clamp_tests(player) + local inv = player:get_inventory() + local old_inv_size = inv:get_size("main") + local old_inv_list = inv:get_list("main") -- Avoid accidentally removing item + local old_bar_size = player:hud_get_hotbar_itemcount() + + inv:set_size("main", 5) + + player:hud_set_hotbar_itemcount(2) + assert(player:hud_get_hotbar_itemcount() == 2) + + player:hud_set_hotbar_itemcount(6) + assert(player:hud_get_hotbar_itemcount() == 5) + + inv:set_size("main", old_inv_size) + inv:set_list("main", old_inv_list) + player:hud_set_hotbar_itemcount(old_bar_size) +end +unittests.register("test_player_hotbar_clamp", run_player_hotbar_clamp_tests, {player=true}) diff --git a/src/client/game.cpp b/src/client/game.cpp index 3dd829d53..0906e9ca9 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -2188,12 +2188,14 @@ void Game::processItemSelection(u16 *new_playeritem) { LocalPlayer *player = client->getEnv().getLocalPlayer(); + *new_playeritem = player->getWieldIndex(); + u16 max_item = player->getMaxHotbarItemcount(); + if (max_item == 0) + return; + max_item -= 1; + /* Item selection using mouse wheel */ - *new_playeritem = player->getWieldIndex(); - u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE - 1, - player->hud_hotbar_itemcount - 1); - s32 wheel = input->getMouseWheel(); if (!m_enable_hotbar_mouse_wheel) wheel = 0; diff --git a/src/client/hud.cpp b/src/client/hud.cpp index c5e71b853..3a0e25a07 100644 --- a/src/client/hud.cpp +++ b/src/client/hud.cpp @@ -783,7 +783,7 @@ void Hud::drawHotbar(u16 playeritem) v2s32 centerlowerpos(m_displaycenter.X, m_screensize.Y); - s32 hotbar_itemcount = player->hud_hotbar_itemcount; + s32 hotbar_itemcount = player->getMaxHotbarItemcount(); s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2); v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3); diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index 2c6f024ee..c1ac821d3 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -852,11 +852,11 @@ void Server::handleCommand_PlayerItem(NetworkPacket* pkt) *pkt >> item; - if (item >= player->getHotbarItemcount()) { + if (item >= player->getMaxHotbarItemcount()) { actionstream << "Player: " << player->getName() << " tried to access item=" << item << " out of hotbar_itemcount=" - << player->getHotbarItemcount() + << player->getMaxHotbarItemcount() << "; ignoring." << std::endl; return; } @@ -983,11 +983,11 @@ void Server::handleCommand_Interact(NetworkPacket *pkt) // Update wielded item - if (item_i >= player->getHotbarItemcount()) { + if (item_i >= player->getMaxHotbarItemcount()) { actionstream << "Player: " << player->getName() << " tried to access item=" << item_i << " out of hotbar_itemcount=" - << player->getHotbarItemcount() + << player->getMaxHotbarItemcount() << "; ignoring." << std::endl; return; } diff --git a/src/player.cpp b/src/player.cpp index c876b6948..282246a6a 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -88,6 +88,11 @@ void Player::setWieldIndex(u16 index) m_wield_index = MYMIN(index, mlist ? mlist->getSize() : 0); } +u16 Player::getWieldIndex() +{ + return std::min(m_wield_index, getMaxHotbarItemcount()); +} + ItemStack &Player::getWieldedItem(ItemStack *selected, ItemStack *hand) const { assert(selected); @@ -157,6 +162,12 @@ void Player::clearHud() } } +u16 Player::getMaxHotbarItemcount() +{ + InventoryList *mainlist = inventory.getList("main"); + return mainlist ? std::min(mainlist->getSize(), (u32) hud_hotbar_itemcount) : 0; +} + #ifndef SERVER u32 PlayerControl::getKeysPressed() const diff --git a/src/player.h b/src/player.h index 373c81780..797b79eb1 100644 --- a/src/player.h +++ b/src/player.h @@ -223,7 +223,7 @@ public: // Returns non-empty `selected` ItemStack. `hand` is a fallback, if specified ItemStack &getWieldedItem(ItemStack *selected, ItemStack *hand) const; void setWieldIndex(u16 index); - u16 getWieldIndex() const { return m_wield_index; } + u16 getWieldIndex(); bool setFov(const PlayerFovSpec &spec) { @@ -247,6 +247,9 @@ public: u32 hud_flags; s32 hud_hotbar_itemcount; + // Get actual usable number of hotbar items (clamped to size of "main" list) + u16 getMaxHotbarItemcount(); + protected: char m_name[PLAYERNAME_SIZE]; v3f m_speed; // velocity; in BS-space diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index f3aa816a5..bdb2d97e5 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -1842,7 +1842,7 @@ int ObjectRef::l_hud_get_hotbar_itemcount(lua_State *L) if (player == nullptr) return 0; - lua_pushinteger(L, player->getHotbarItemcount()); + lua_pushinteger(L, player->getMaxHotbarItemcount()); return 1; }