Unify wield item handling (#8677)

This moves the wield item functions to Player and the tool utils for range calculation
Also 'local_inventory' was removed due to redundancy in Client
This commit is contained in:
SmallJoker 2019-08-07 19:16:31 +02:00 committed by GitHub
parent 003af74213
commit e462a9a5ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 154 additions and 249 deletions

@ -940,7 +940,7 @@ void Client::interact(u8 action, const PointedThing& pointed)
NetworkPacket pkt(TOSERVER_INTERACT, 1 + 2 + 0); NetworkPacket pkt(TOSERVER_INTERACT, 1 + 2 + 0);
pkt << action; pkt << action;
pkt << (u16)getPlayerItem(); pkt << myplayer->getWieldIndex();
std::ostringstream tmp_os(std::ios::binary); std::ostringstream tmp_os(std::ios::binary);
pointed.serialize(tmp_os); pointed.serialize(tmp_os);
@ -1277,19 +1277,6 @@ void Client::sendPlayerPos()
Send(&pkt); Send(&pkt);
} }
void Client::sendPlayerItem(u16 item)
{
LocalPlayer *myplayer = m_env.getLocalPlayer();
if (!myplayer)
return;
NetworkPacket pkt(TOSERVER_PLAYERITEM, 2);
pkt << item;
Send(&pkt);
}
void Client::removeNode(v3s16 p) void Client::removeNode(v3s16 p)
{ {
std::map<v3s16, MapBlock*> modified_blocks; std::map<v3s16, MapBlock*> modified_blocks;
@ -1349,11 +1336,14 @@ void Client::setPlayerControl(PlayerControl &control)
player->control = control; player->control = control;
} }
void Client::selectPlayerItem(u16 item) void Client::setPlayerItem(u16 item)
{ {
m_playeritem = item; m_env.getLocalPlayer()->setWieldIndex(item);
m_inventory_updated = true; m_inventory_updated = true;
sendPlayerItem(item);
NetworkPacket pkt(TOSERVER_PLAYERITEM, 2);
pkt << item;
Send(&pkt);
} }
// Returns true if the inventory of the local player has been // Returns true if the inventory of the local player has been

@ -271,10 +271,6 @@ public:
void setPlayerControl(PlayerControl &control); void setPlayerControl(PlayerControl &control);
void selectPlayerItem(u16 item);
u16 getPlayerItem() const
{ return m_playeritem; }
// Returns true if the inventory of the local player has been // Returns true if the inventory of the local player has been
// updated from the server. If it is true, it is set to false. // updated from the server. If it is true, it is set to false.
bool getLocalInventoryUpdated(); bool getLocalInventoryUpdated();
@ -285,6 +281,9 @@ public:
Inventory* getInventory(const InventoryLocation &loc) override; Inventory* getInventory(const InventoryLocation &loc) override;
void inventoryAction(InventoryAction *a) override; void inventoryAction(InventoryAction *a) override;
// Send the item number 'item' as player item to the server
void setPlayerItem(u16 item);
const std::list<std::string> &getConnectedPlayerNames() const std::list<std::string> &getConnectedPlayerNames()
{ {
return m_env.getPlayerNames(); return m_env.getPlayerNames();
@ -454,8 +453,6 @@ private:
void Receive(); void Receive();
void sendPlayerPos(); void sendPlayerPos();
// Send the item number 'item' as player item to the server
void sendPlayerItem(u16 item);
void deleteAuthData(); void deleteAuthData();
// helper method shared with clientpackethandler // helper method shared with clientpackethandler
@ -506,7 +503,6 @@ private:
// If 0, server init hasn't been received yet. // If 0, server init hasn't been received yet.
u16 m_proto_ver = 0; u16 m_proto_ver = 0;
u16 m_playeritem = 0;
bool m_inventory_updated = false; bool m_inventory_updated = false;
Inventory *m_inventory_from_server = nullptr; Inventory *m_inventory_from_server = nullptr;
float m_inventory_from_server_age = 0.0f; float m_inventory_from_server_age = 0.0f;

@ -744,12 +744,11 @@ protected:
bool look_for_object, const v3s16 &camera_offset); bool look_for_object, const v3s16 &camera_offset);
void handlePointingAtNothing(const ItemStack &playerItem); void handlePointingAtNothing(const ItemStack &playerItem);
void handlePointingAtNode(const PointedThing &pointed, void handlePointingAtNode(const PointedThing &pointed,
const ItemDefinition &playeritem_def, const ItemStack &playeritem, const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
const ToolCapabilities &playeritem_toolcap, f32 dtime);
void handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem, void handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem,
const v3f &player_position, bool show_debug); const v3f &player_position, bool show_debug);
void handleDigging(const PointedThing &pointed, const v3s16 &nodepos, void handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
const ToolCapabilities &playeritem_toolcap, f32 dtime); const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
const CameraOrientation &cam); const CameraOrientation &cam);
void updateProfilerGraphs(ProfilerGraph *graph); void updateProfilerGraphs(ProfilerGraph *graph);
@ -804,8 +803,8 @@ private:
void updateChat(f32 dtime, const v2u32 &screensize); void updateChat(f32 dtime, const v2u32 &screensize);
bool nodePlacementPrediction(const ItemDefinition &playeritem_def, bool nodePlacementPrediction(const ItemDefinition &selected_def,
const ItemStack &playeritem, const v3s16 &nodepos, const v3s16 &neighbourpos); const ItemStack &selected_item, const v3s16 &nodepos, const v3s16 &neighbourpos);
static const ClientEventHandler clientEventHandler[CLIENTEVENT_MAX]; static const ClientEventHandler clientEventHandler[CLIENTEVENT_MAX];
InputHandler *input = nullptr; InputHandler *input = nullptr;
@ -837,7 +836,6 @@ private:
Camera *camera = nullptr; Camera *camera = nullptr;
Clouds *clouds = nullptr; // Free using ->Drop() Clouds *clouds = nullptr; // Free using ->Drop()
Sky *sky = nullptr; // Free using ->Drop() Sky *sky = nullptr; // Free using ->Drop()
Inventory *local_inventory = nullptr;
Hud *hud = nullptr; Hud *hud = nullptr;
Minimap *mapper = nullptr; Minimap *mapper = nullptr;
@ -951,7 +949,6 @@ Game::~Game()
delete server; // deleted first to stop all server threads delete server; // deleted first to stop all server threads
delete hud; delete hud;
delete local_inventory;
delete camera; delete camera;
delete quicktune; delete quicktune;
delete eventmgr; delete eventmgr;
@ -1349,10 +1346,8 @@ bool Game::createClient(const std::string &playername,
scsf->setSky(sky); scsf->setSky(sky);
skybox = NULL; // This is used/set later on in the main run loop skybox = NULL; // This is used/set later on in the main run loop
local_inventory = new Inventory(itemdef_manager); if (!sky) {
*error_message = "Memory allocation error sky";
if (!(sky && local_inventory)) {
*error_message = "Memory allocation error (sky or local inventory)";
errorstream << *error_message << std::endl; errorstream << *error_message << std::endl;
return false; return false;
} }
@ -1384,7 +1379,7 @@ bool Game::createClient(const std::string &playername,
player->hurt_tilt_timer = 0; player->hurt_tilt_timer = 0;
player->hurt_tilt_strength = 0; player->hurt_tilt_strength = 0;
hud = new Hud(guienv, client, player, local_inventory); hud = new Hud(guienv, client, player, &player->inventory);
if (!hud) { if (!hud) {
*error_message = "Memory error: could not create HUD"; *error_message = "Memory error: could not create HUD";
@ -1977,7 +1972,7 @@ void Game::processItemSelection(u16 *new_playeritem)
/* Item selection using mouse wheel /* Item selection using mouse wheel
*/ */
*new_playeritem = client->getPlayerItem(); *new_playeritem = player->getWieldIndex();
s32 wheel = input->getMouseWheel(); s32 wheel = input->getMouseWheel();
u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE - 1, u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE - 1,
@ -2019,7 +2014,7 @@ void Game::dropSelectedItem(bool single_item)
a->count = single_item ? 1 : 0; a->count = single_item ? 1 : 0;
a->from_inv.setCurrentPlayer(); a->from_inv.setCurrentPlayer();
a->from_list = "main"; a->from_list = "main";
a->from_i = client->getPlayerItem(); a->from_i = client->getEnv().getLocalPlayer()->getWieldIndex();
client->inventoryAction(a); client->inventoryAction(a);
} }
@ -2847,19 +2842,10 @@ void Game::updateCamera(u32 busy_time, f32 dtime)
*/ */
ItemStack playeritem; ItemStack playeritem;
{ {
InventoryList *mlist = local_inventory->getList("main"); ItemStack selected, hand;
playeritem = player->getWieldedItem(&selected, &hand);
if (mlist && client->getPlayerItem() < mlist->getSize())
playeritem = mlist->getItem(client->getPlayerItem());
} }
if (playeritem.getDefinition(itemdef_manager).name.empty()) { // override the hand
InventoryList *hlist = local_inventory->getList("hand");
if (hlist)
playeritem = hlist->getItem(0);
}
ToolCapabilities playeritem_toolcap = ToolCapabilities playeritem_toolcap =
playeritem.getToolCapabilities(itemdef_manager); playeritem.getToolCapabilities(itemdef_manager);
@ -2949,20 +2935,6 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
{ {
LocalPlayer *player = client->getEnv().getLocalPlayer(); LocalPlayer *player = client->getEnv().getLocalPlayer();
ItemStack playeritem;
{
InventoryList *mlist = local_inventory->getList("main");
if (mlist && client->getPlayerItem() < mlist->getSize())
playeritem = mlist->getItem(client->getPlayerItem());
}
const ItemDefinition &playeritem_def =
playeritem.getDefinition(itemdef_manager);
InventoryList *hlist = local_inventory->getList("hand");
const ItemDefinition &hand_def =
hlist ? hlist->getItem(0).getDefinition(itemdef_manager) : itemdef_manager->get("");
v3f player_position = player->getPosition(); v3f player_position = player->getPosition();
v3f player_eye_position = player->getEyePosition(); v3f player_eye_position = player->getEyePosition();
v3f camera_position = camera->getPosition(); v3f camera_position = camera->getPosition();
@ -2978,13 +2950,11 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
Calculate what block is the crosshair pointing to Calculate what block is the crosshair pointing to
*/ */
f32 d = playeritem_def.range; // max. distance ItemStack selected_item, hand_item;
f32 d_hand = hand_def.range; const ItemStack &tool_item = player->getWieldedItem(&selected_item, &hand_item);
if (d < 0 && d_hand >= 0) const ItemDefinition &selected_def = selected_item.getDefinition(itemdef_manager);
d = d_hand; f32 d = BS * getToolRange(selected_def, hand_item.getDefinition(itemdef_manager));
else if (d < 0)
d = 4.0;
core::line3d<f32> shootline; core::line3d<f32> shootline;
@ -3010,7 +2980,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
#endif #endif
PointedThing pointed = updatePointedThing(shootline, PointedThing pointed = updatePointedThing(shootline,
playeritem_def.liquids_pointable, selected_def.liquids_pointable,
!runData.ldown_for_dig, !runData.ldown_for_dig,
camera_offset); camera_offset);
@ -3074,30 +3044,20 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
else else
runData.repeat_rightclick_timer = 0; runData.repeat_rightclick_timer = 0;
if (playeritem_def.usable && input->getLeftState()) {
if (selected_def.usable && input->getLeftState()) {
if (input->getLeftClicked() && (!client->moddingEnabled() if (input->getLeftClicked() && (!client->moddingEnabled()
|| !client->getScript()->on_item_use(playeritem, pointed))) || !client->getScript()->on_item_use(selected_item, pointed)))
client->interact(4, pointed); client->interact(4, pointed);
} else if (pointed.type == POINTEDTHING_NODE) { } else if (pointed.type == POINTEDTHING_NODE) {
ToolCapabilities playeritem_toolcap = handlePointingAtNode(pointed, selected_item, hand_item, dtime);
playeritem.getToolCapabilities(itemdef_manager);
if (playeritem.name.empty()) {
const ToolCapabilities *handToolcap = hlist
? &hlist->getItem(0).getToolCapabilities(itemdef_manager)
: itemdef_manager->get("").tool_capabilities;
if (handToolcap != nullptr)
playeritem_toolcap = *handToolcap;
}
handlePointingAtNode(pointed, playeritem_def, playeritem,
playeritem_toolcap, dtime);
} else if (pointed.type == POINTEDTHING_OBJECT) { } else if (pointed.type == POINTEDTHING_OBJECT) {
handlePointingAtObject(pointed, playeritem, player_position, show_debug); handlePointingAtObject(pointed, tool_item, player_position, show_debug);
} else if (input->getLeftState()) { } else if (input->getLeftState()) {
// When button is held down in air, show continuous animation // When button is held down in air, show continuous animation
runData.left_punch = true; runData.left_punch = true;
} else if (input->getRightClicked()) { } else if (input->getRightClicked()) {
handlePointingAtNothing(playeritem); handlePointingAtNothing(selected_item);
} }
runData.pointed_old = pointed; runData.pointed_old = pointed;
@ -3214,8 +3174,7 @@ void Game::handlePointingAtNothing(const ItemStack &playerItem)
void Game::handlePointingAtNode(const PointedThing &pointed, void Game::handlePointingAtNode(const PointedThing &pointed,
const ItemDefinition &playeritem_def, const ItemStack &playeritem, const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime)
const ToolCapabilities &playeritem_toolcap, f32 dtime)
{ {
v3s16 nodepos = pointed.node_undersurface; v3s16 nodepos = pointed.node_undersurface;
v3s16 neighbourpos = pointed.node_abovesurface; v3s16 neighbourpos = pointed.node_abovesurface;
@ -3229,7 +3188,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
if (runData.nodig_delay_timer <= 0.0 && input->getLeftState() if (runData.nodig_delay_timer <= 0.0 && input->getLeftState()
&& !runData.digging_blocked && !runData.digging_blocked
&& client->checkPrivilege("interact")) { && client->checkPrivilege("interact")) {
handleDigging(pointed, nodepos, playeritem_toolcap, dtime); handleDigging(pointed, nodepos, selected_item, hand_item, dtime);
} }
// This should be done after digging handling // This should be done after digging handling
@ -3281,7 +3240,8 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
// If the wielded item has node placement prediction, // If the wielded item has node placement prediction,
// make that happen // make that happen
bool placed = nodePlacementPrediction(playeritem_def, playeritem, nodepos, auto &def = selected_item.getDefinition(itemdef_manager);
bool placed = nodePlacementPrediction(def, selected_item, nodepos,
neighbourpos); neighbourpos);
if (placed) { if (placed) {
@ -3289,30 +3249,30 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
client->interact(3, pointed); client->interact(3, pointed);
// Read the sound // Read the sound
soundmaker->m_player_rightpunch_sound = soundmaker->m_player_rightpunch_sound =
playeritem_def.sound_place; def.sound_place;
if (client->moddingEnabled()) if (client->moddingEnabled())
client->getScript()->on_placenode(pointed, playeritem_def); client->getScript()->on_placenode(pointed, def);
} else { } else {
soundmaker->m_player_rightpunch_sound = soundmaker->m_player_rightpunch_sound =
SimpleSoundSpec(); SimpleSoundSpec();
if (playeritem_def.node_placement_prediction.empty() || if (def.node_placement_prediction.empty() ||
nodedef_manager->get(map.getNodeNoEx(nodepos)).rightclickable) { nodedef_manager->get(map.getNodeNoEx(nodepos)).rightclickable) {
client->interact(3, pointed); // Report to server client->interact(3, pointed); // Report to server
} else { } else {
soundmaker->m_player_rightpunch_sound = soundmaker->m_player_rightpunch_sound =
playeritem_def.sound_place_failed; def.sound_place_failed;
} }
} }
} }
} }
} }
bool Game::nodePlacementPrediction(const ItemDefinition &playeritem_def, bool Game::nodePlacementPrediction(const ItemDefinition &selected_def,
const ItemStack &playeritem, const v3s16 &nodepos, const v3s16 &neighbourpos) const ItemStack &selected_item, const v3s16 &nodepos, const v3s16 &neighbourpos)
{ {
std::string prediction = playeritem_def.node_placement_prediction; std::string prediction = selected_def.node_placement_prediction;
const NodeDefManager *nodedef = client->ndef(); const NodeDefManager *nodedef = client->ndef();
ClientMap &map = client->getEnv().getClientMap(); ClientMap &map = client->getEnv().getClientMap();
MapNode node; MapNode node;
@ -3325,7 +3285,7 @@ bool Game::nodePlacementPrediction(const ItemDefinition &playeritem_def,
if (!prediction.empty() && !(nodedef->get(node).rightclickable && if (!prediction.empty() && !(nodedef->get(node).rightclickable &&
!isKeyDown(KeyType::SNEAK))) { !isKeyDown(KeyType::SNEAK))) {
verbosestream << "Node placement prediction for " verbosestream << "Node placement prediction for "
<< playeritem_def.name << " is " << selected_item.name << " is "
<< prediction << std::endl; << prediction << std::endl;
v3s16 p = neighbourpos; v3s16 p = neighbourpos;
@ -3348,7 +3308,7 @@ bool Game::nodePlacementPrediction(const ItemDefinition &playeritem_def,
if (!found) { if (!found) {
errorstream << "Node placement prediction failed for " errorstream << "Node placement prediction failed for "
<< playeritem_def.name << " (places " << selected_item.name << " (places "
<< prediction << prediction
<< ") - Name not known" << std::endl; << ") - Name not known" << std::endl;
return false; return false;
@ -3411,7 +3371,7 @@ bool Game::nodePlacementPrediction(const ItemDefinition &playeritem_def,
if ((predicted_f.param_type_2 == CPT2_COLOR if ((predicted_f.param_type_2 == CPT2_COLOR
|| predicted_f.param_type_2 == CPT2_COLORED_FACEDIR || predicted_f.param_type_2 == CPT2_COLORED_FACEDIR
|| predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED)) { || predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED)) {
const std::string &indexstr = playeritem.metadata.getString( const std::string &indexstr = selected_item.metadata.getString(
"palette_index", 0); "palette_index", 0);
if (!indexstr.empty()) { if (!indexstr.empty()) {
s32 index = mystoi(indexstr); s32 index = mystoi(indexstr);
@ -3450,7 +3410,7 @@ bool Game::nodePlacementPrediction(const ItemDefinition &playeritem_def,
} }
} catch (InvalidPositionException &e) { } catch (InvalidPositionException &e) {
errorstream << "Node placement prediction failed for " errorstream << "Node placement prediction failed for "
<< playeritem_def.name << " (places " << selected_item.name << " (places "
<< prediction << prediction
<< ") - Position not loaded" << std::endl; << ") - Position not loaded" << std::endl;
} }
@ -3459,8 +3419,8 @@ bool Game::nodePlacementPrediction(const ItemDefinition &playeritem_def,
return false; return false;
} }
void Game::handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem, void Game::handlePointingAtObject(const PointedThing &pointed,
const v3f &player_position, bool show_debug) const ItemStack &tool_item, const v3f &player_position, bool show_debug)
{ {
std::wstring infotext = unescape_translate( std::wstring infotext = unescape_translate(
utf8_to_wide(runData.selected_object->infoText())); utf8_to_wide(runData.selected_object->infoText()));
@ -3496,16 +3456,9 @@ void Game::handlePointingAtObject(const PointedThing &pointed, const ItemStack &
// Report direct punch // Report direct punch
v3f objpos = runData.selected_object->getPosition(); v3f objpos = runData.selected_object->getPosition();
v3f dir = (objpos - player_position).normalize(); v3f dir = (objpos - player_position).normalize();
ItemStack item = playeritem;
if (playeritem.name.empty()) {
InventoryList *hlist = local_inventory->getList("hand");
if (hlist) {
item = hlist->getItem(0);
}
}
bool disable_send = runData.selected_object->directReportPunch( bool disable_send = runData.selected_object->directReportPunch(
dir, &item, runData.time_from_last_punch); dir, &tool_item, runData.time_from_last_punch);
runData.time_from_last_punch = 0; runData.time_from_last_punch = 0;
if (!disable_send) if (!disable_send)
@ -3519,8 +3472,9 @@ void Game::handlePointingAtObject(const PointedThing &pointed, const ItemStack &
void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos, void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
const ToolCapabilities &playeritem_toolcap, f32 dtime) const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime)
{ {
// See also: serverpackethandle.cpp, action == 2
LocalPlayer *player = client->getEnv().getLocalPlayer(); LocalPlayer *player = client->getEnv().getLocalPlayer();
ClientMap &map = client->getEnv().getClientMap(); ClientMap &map = client->getEnv().getClientMap();
MapNode n = client->getEnv().getClientMap().getNodeNoEx(nodepos); MapNode n = client->getEnv().getClientMap().getNodeNoEx(nodepos);
@ -3529,17 +3483,12 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
// cheat detection. // cheat detection.
// Get digging parameters // Get digging parameters
DigParams params = getDigParams(nodedef_manager->get(n).groups, DigParams params = getDigParams(nodedef_manager->get(n).groups,
&playeritem_toolcap); &selected_item.getToolCapabilities(itemdef_manager));
// If can't dig, try hand // If can't dig, try hand
if (!params.diggable) { if (!params.diggable) {
InventoryList *hlist = local_inventory->getList("hand"); params = getDigParams(nodedef_manager->get(n).groups,
const ToolCapabilities *tp = hlist &hand_item.getToolCapabilities(itemdef_manager));
? &hlist->getItem(0).getToolCapabilities(itemdef_manager)
: itemdef_manager->get("").tool_capabilities;
if (tp)
params = getDigParams(nodedef_manager->get(n).groups, tp);
} }
if (!params.diggable) { if (!params.diggable) {
@ -3793,29 +3742,20 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
Inventory Inventory
*/ */
if (client->getPlayerItem() != runData.new_playeritem) if (player->getWieldIndex() != runData.new_playeritem)
client->selectPlayerItem(runData.new_playeritem); client->setPlayerItem(runData.new_playeritem);
// Update local inventory if it has changed // Update local inventory if it has changed
if (client->getLocalInventoryUpdated()) { if (client->getLocalInventoryUpdated()) {
//infostream<<"Updating local inventory"<<std::endl; //infostream<<"Updating local inventory"<<std::endl;
client->getLocalInventory(*local_inventory);
runData.update_wielded_item_trigger = true; runData.update_wielded_item_trigger = true;
} }
if (runData.update_wielded_item_trigger) { if (runData.update_wielded_item_trigger) {
// Update wielded tool // Update wielded tool
InventoryList *mlist = local_inventory->getList("main"); ItemStack selected_item, hand_item;
ItemStack &tool_item = player->getWieldedItem(&selected_item, &hand_item);
if (mlist && (client->getPlayerItem() < mlist->getSize())) { camera->wield(tool_item);
ItemStack item = mlist->getItem(client->getPlayerItem());
if (item.getDefinition(itemdef_manager).name.empty()) { // override the hand
InventoryList *hlist = local_inventory->getList("hand");
if (hlist)
item = hlist->getItem(0);
}
camera->wield(item);
}
runData.update_wielded_item_trigger = false; runData.update_wielded_item_trigger = false;
} }

@ -86,7 +86,7 @@ void RenderingCore::drawHUD()
if (show_hud) { if (show_hud) {
if (draw_crosshair) if (draw_crosshair)
hud->drawCrosshair(); hud->drawCrosshair();
hud->drawHotbar(client->getPlayerItem()); hud->drawHotbar(client->getEnv().getLocalPlayer()->getWieldIndex());
hud->drawLuaElements(camera->getOffset()); hud->drawLuaElements(camera->getOffset());
camera->drawNametags(); camera->drawNametags();
if (mapper && show_minimap) if (mapper && show_minimap)

@ -896,18 +896,11 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, session_t p
m_armor_groups["immortal"] = 1; m_armor_groups["immortal"] = 1;
} }
PlayerSAO::~PlayerSAO()
{
if(m_inventory != &m_player->inventory)
delete m_inventory;
}
void PlayerSAO::finalize(RemotePlayer *player, const std::set<std::string> &privs) void PlayerSAO::finalize(RemotePlayer *player, const std::set<std::string> &privs)
{ {
assert(player); assert(player);
m_player = player; m_player = player;
m_privs = privs; m_privs = privs;
m_inventory = &m_player->inventory;
} }
v3f PlayerSAO::getEyeOffset() const v3f PlayerSAO::getEyeOffset() const
@ -1365,13 +1358,9 @@ void PlayerSAO::setBreath(const u16 breath, bool send)
m_env->getGameDef()->SendPlayerBreath(this); m_env->getGameDef()->SendPlayerBreath(this);
} }
Inventory* PlayerSAO::getInventory() Inventory *PlayerSAO::getInventory() const
{ {
return m_inventory; return m_player ? &m_player->inventory : nullptr;
}
const Inventory* PlayerSAO::getInventory() const
{
return m_inventory;
} }
InventoryLocation PlayerSAO::getInventoryLocation() const InventoryLocation PlayerSAO::getInventoryLocation() const
@ -1381,61 +1370,27 @@ InventoryLocation PlayerSAO::getInventoryLocation() const
return loc; return loc;
} }
std::string PlayerSAO::getWieldList() const u16 PlayerSAO::getWieldIndex() const
{ {
return "main"; return m_player->getWieldIndex();
} }
ItemStack PlayerSAO::getWieldedItem() const ItemStack PlayerSAO::getWieldedItem() const
{ {
const Inventory *inv = getInventory(); ItemStack selected_item, hand_item;
ItemStack ret; return m_player->getWieldedItem(&selected_item, &hand_item);
const InventoryList *mlist = inv->getList(getWieldList());
if (mlist && getWieldIndex() < (s32)mlist->getSize())
ret = mlist->getItem(getWieldIndex());
return ret;
}
ItemStack PlayerSAO::getWieldedItemOrHand() const
{
const Inventory *inv = getInventory();
ItemStack ret;
const InventoryList *mlist = inv->getList(getWieldList());
if (mlist && getWieldIndex() < (s32)mlist->getSize())
ret = mlist->getItem(getWieldIndex());
if (ret.name.empty()) {
const InventoryList *hlist = inv->getList("hand");
if (hlist)
ret = hlist->getItem(0);
}
return ret;
} }
bool PlayerSAO::setWieldedItem(const ItemStack &item) bool PlayerSAO::setWieldedItem(const ItemStack &item)
{ {
Inventory *inv = getInventory(); InventoryList *mlist = m_player->inventory.getList(getWieldList());
if (inv) { if (mlist) {
InventoryList *mlist = inv->getList(getWieldList()); mlist->changeItem(m_player->getWieldIndex(), item);
if (mlist) { return true;
mlist->changeItem(getWieldIndex(), item);
return true;
}
} }
return false; return false;
} }
int PlayerSAO::getWieldIndex() const
{
return m_wield_index;
}
void PlayerSAO::setWieldIndex(int i)
{
if(i != m_wield_index) {
m_wield_index = i;
}
}
void PlayerSAO::disconnected() void PlayerSAO::disconnected()
{ {
m_peer_id = 0; m_peer_id = 0;

@ -219,7 +219,7 @@ class PlayerSAO : public UnitSAO
public: public:
PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, session_t peer_id_, PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, session_t peer_id_,
bool is_singleplayer); bool is_singleplayer);
~PlayerSAO();
ActiveObjectType getType() const ActiveObjectType getType() const
{ return ACTIVEOBJECT_TYPE_PLAYER; } { return ACTIVEOBJECT_TYPE_PLAYER; }
ActiveObjectType getSendType() const ActiveObjectType getSendType() const
@ -272,16 +272,13 @@ public:
/* /*
Inventory interface Inventory interface
*/ */
Inventory *getInventory() const;
Inventory* getInventory();
const Inventory* getInventory() const;
InventoryLocation getInventoryLocation() const; InventoryLocation getInventoryLocation() const;
std::string getWieldList() const; void setInventoryModified() {}
std::string getWieldList() const { return "main"; }
u16 getWieldIndex() const;
ItemStack getWieldedItem() const; ItemStack getWieldedItem() const;
ItemStack getWieldedItemOrHand() const;
bool setWieldedItem(const ItemStack &item); bool setWieldedItem(const ItemStack &item);
int getWieldIndex() const;
void setWieldIndex(int i);
/* /*
PlayerSAO-specific PlayerSAO-specific
@ -355,7 +352,6 @@ private:
RemotePlayer *m_player = nullptr; RemotePlayer *m_player = nullptr;
session_t m_peer_id = 0; session_t m_peer_id = 0;
Inventory *m_inventory = nullptr;
// Cheat prevention // Cheat prevention
LagPool m_dig_pool; LagPool m_dig_pool;
@ -371,7 +367,6 @@ private:
IntervalLimiter m_drowning_interval; IntervalLimiter m_drowning_interval;
IntervalLimiter m_node_hurt_interval; IntervalLimiter m_node_hurt_interval;
int m_wield_index = 0;
bool m_position_not_sent = false; bool m_position_not_sent = false;
// Cached privileges for enforcement // Cached privileges for enforcement

@ -923,7 +923,7 @@ void Server::handleCommand_PlayerItem(NetworkPacket* pkt)
*pkt >> item; *pkt >> item;
playersao->setWieldIndex(item); playersao->getPlayer()->setWieldIndex(item);
} }
void Server::handleCommand_Respawn(NetworkPacket* pkt) void Server::handleCommand_Respawn(NetworkPacket* pkt)
@ -954,20 +954,10 @@ void Server::handleCommand_Respawn(NetworkPacket* pkt)
bool Server::checkInteractDistance(RemotePlayer *player, const f32 d, const std::string &what) bool Server::checkInteractDistance(RemotePlayer *player, const f32 d, const std::string &what)
{ {
PlayerSAO *playersao = player->getPlayerSAO(); ItemStack selected_item, hand_item;
const InventoryList *hlist = playersao->getInventory()->getList("hand"); player->getWieldedItem(&selected_item, &hand_item);
const ItemDefinition &playeritem_def = f32 max_d = BS * getToolRange(selected_item.getDefinition(m_itemdef),
playersao->getWieldedItem().getDefinition(m_itemdef); hand_item.getDefinition(m_itemdef));
const ItemDefinition &hand_def =
hlist ? hlist->getItem(0).getDefinition(m_itemdef) : m_itemdef->get("");
float max_d = BS * playeritem_def.range;
float max_d_hand = BS * hand_def.range;
if (max_d < 0 && max_d_hand >= 0)
max_d = max_d_hand;
else if (max_d < 0)
max_d = BS * 4.0f;
// Cube diagonal * 1.5 for maximal supported node extents: // Cube diagonal * 1.5 for maximal supported node extents:
// sqrt(3) * 1.5 ≅ 2.6 // sqrt(3) * 1.5 ≅ 2.6
@ -978,7 +968,7 @@ bool Server::checkInteractDistance(RemotePlayer *player, const f32 d, const std:
<< "d=" << d <<", max_d=" << max_d << "d=" << d <<", max_d=" << max_d
<< ". ignoring." << std::endl; << ". ignoring." << std::endl;
// Call callbacks // Call callbacks
m_script->on_cheat(playersao, "interacted_too_far"); m_script->on_cheat(player->getPlayerSAO(), "interacted_too_far");
return false; return false;
} }
return true; return true;
@ -1050,7 +1040,7 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
v3f player_pos = playersao->getLastGoodPosition(); v3f player_pos = playersao->getLastGoodPosition();
// Update wielded item // Update wielded item
playersao->setWieldIndex(item_i); playersao->getPlayer()->setWieldIndex(item_i);
// Get pointed to node (undefined if not POINTEDTYPE_NODE) // Get pointed to node (undefined if not POINTEDTYPE_NODE)
v3s16 p_under = pointed.node_undersurface; v3s16 p_under = pointed.node_undersurface;
@ -1156,7 +1146,7 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
if (pointed_object->isGone()) if (pointed_object->isGone())
return; return;
ItemStack punchitem = playersao->getWieldedItemOrHand(); ItemStack punchitem = playersao->getWieldedItem();
ToolCapabilities toolcap = ToolCapabilities toolcap =
punchitem.getToolCapabilities(m_itemdef); punchitem.getToolCapabilities(m_itemdef);
v3f dir = (pointed_object->getBasePosition() - v3f dir = (pointed_object->getBasePosition() -
@ -1224,22 +1214,19 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
// Call callbacks // Call callbacks
m_script->on_cheat(playersao, "finished_unknown_dig"); m_script->on_cheat(playersao, "finished_unknown_dig");
} }
// Get player's wielded item // Get player's wielded item
ItemStack playeritem = playersao->getWieldedItemOrHand(); // See also: Game::handleDigging
ToolCapabilities playeritem_toolcap = ItemStack selected_item, hand_item;
playeritem.getToolCapabilities(m_itemdef); playersao->getPlayer()->getWieldedItem(&selected_item, &hand_item);
// Get diggability and expected digging time // Get diggability and expected digging time
DigParams params = getDigParams(m_nodedef->get(n).groups, DigParams params = getDigParams(m_nodedef->get(n).groups,
&playeritem_toolcap); &selected_item.getToolCapabilities(m_itemdef));
// If can't dig, try hand // If can't dig, try hand
if (!params.diggable) { if (!params.diggable) {
InventoryList *hlist = playersao->getInventory()->getList("hand"); params = getDigParams(m_nodedef->get(n).groups,
const ToolCapabilities *tp = hlist &hand_item.getToolCapabilities(m_itemdef));
? &hlist->getItem(0).getToolCapabilities(m_itemdef)
: m_itemdef->get("").tool_capabilities;
if (tp)
params = getDigParams(m_nodedef->get(n).groups, tp);
} }
// If can't dig, ignore dig // If can't dig, ignore dig
if (!params.diggable) { if (!params.diggable) {

@ -90,6 +90,29 @@ Player::~Player()
clearHud(); clearHud();
} }
void Player::setWieldIndex(u16 index)
{
const InventoryList *mlist = inventory.getList("main");
m_wield_index = MYMIN(index, mlist ? mlist->getSize() : 0);
}
ItemStack &Player::getWieldedItem(ItemStack *selected, ItemStack *hand) const
{
assert(selected);
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 (hand && hlist)
*hand = hlist->getItem(0);
// Return effective tool item
return (hand && selected->name.empty()) ? *hand : *selected;
}
u32 Player::addHud(HudElement *toadd) u32 Player::addHud(HudElement *toadd)
{ {
MutexAutoLock lock(m_mutex); MutexAutoLock lock(m_mutex);

@ -173,6 +173,11 @@ public:
PlayerSettings &getPlayerSettings() { return m_player_settings; } PlayerSettings &getPlayerSettings() { return m_player_settings; }
static void settingsChangedCallback(const std::string &name, void *data); static void settingsChangedCallback(const std::string &name, void *data);
// 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; }
u32 keyPressed = 0; u32 keyPressed = 0;
HudElement* getHud(u32 id); HudElement* getHud(u32 id);
@ -185,6 +190,7 @@ public:
protected: protected:
char m_name[PLAYERNAME_SIZE]; char m_name[PLAYERNAME_SIZE];
v3f m_speed; v3f m_speed;
u16 m_wield_index = 0;
std::vector<HudElement *> hud; std::vector<HudElement *> hud;
private: private:

@ -210,17 +210,13 @@ int ModApiClient::l_get_language(lua_State *L)
int ModApiClient::l_get_wielded_item(lua_State *L) int ModApiClient::l_get_wielded_item(lua_State *L)
{ {
Client *client = getClient(L); Client *client = getClient(L);
LocalPlayer *player = client->getEnv().getLocalPlayer();
if (!player)
return 0;
Inventory local_inventory(client->idef()); ItemStack selected_item;
client->getLocalInventory(local_inventory); player->getWieldedItem(&selected_item, nullptr);
LuaItemStack::create(L, selected_item);
InventoryList *mlist = local_inventory.getList("main");
if (mlist && client->getPlayerItem() < mlist->getSize()) {
LuaItemStack::create(L, mlist->getItem(client->getPlayerItem()));
} else {
LuaItemStack::create(L, ItemStack());
}
return 1; return 1;
} }

@ -308,8 +308,9 @@ int ObjectRef::l_get_wield_list(lua_State *L)
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1); ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref); ServerActiveObject *co = getobject(ref);
if (co == NULL) return 0; if (!co)
// Do it return 0;
lua_pushstring(L, co->getWieldList().c_str()); lua_pushstring(L, co->getWieldList().c_str());
return 1; return 1;
} }
@ -320,8 +321,9 @@ int ObjectRef::l_get_wield_index(lua_State *L)
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1); ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref); ServerActiveObject *co = getobject(ref);
if (co == NULL) return 0; if (!co)
// Do it return 0;
lua_pushinteger(L, co->getWieldIndex() + 1); lua_pushinteger(L, co->getWieldIndex() + 1);
return 1; return 1;
} }
@ -332,12 +334,12 @@ int ObjectRef::l_get_wielded_item(lua_State *L)
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1); ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref); ServerActiveObject *co = getobject(ref);
if (co == NULL) { if (!co) {
// Empty ItemStack // Empty ItemStack
LuaItemStack::create(L, ItemStack()); LuaItemStack::create(L, ItemStack());
return 1; return 1;
} }
// Do it
LuaItemStack::create(L, co->getWieldedItem()); LuaItemStack::create(L, co->getWieldedItem());
return 1; return 1;
} }

@ -170,9 +170,7 @@ public:
{} {}
// Inventory and wielded item // Inventory and wielded item
virtual Inventory* getInventory() virtual Inventory *getInventory() const
{ return NULL; }
virtual const Inventory* getInventory() const
{ return NULL; } { return NULL; }
virtual InventoryLocation getInventoryLocation() const virtual InventoryLocation getInventoryLocation() const
{ return InventoryLocation(); } { return InventoryLocation(); }
@ -180,7 +178,7 @@ public:
{} {}
virtual std::string getWieldList() const virtual std::string getWieldList() const
{ return ""; } { return ""; }
virtual int getWieldIndex() const virtual u16 getWieldIndex() const
{ return 0; } { return 0; }
virtual ItemStack getWieldedItem() const; virtual ItemStack getWieldedItem() const;
virtual bool setWieldedItem(const ItemStack &item); virtual bool setWieldedItem(const ItemStack &item);

@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/ */
#include "tool.h" #include "tool.h"
#include "itemdef.h"
#include "itemgroup.h" #include "itemgroup.h"
#include "log.h" #include "log.h"
#include "inventory.h" #include "inventory.h"
@ -277,4 +278,16 @@ PunchDamageResult getPunchDamage(
return result; return result;
} }
f32 getToolRange(const ItemDefinition &def_selected, const ItemDefinition &def_hand)
{
float max_d = def_selected.range;
float max_d_hand = def_hand.range;
if (max_d < 0 && max_d_hand >= 0)
max_d = max_d_hand;
else if (max_d < 0)
max_d = 4.0f;
return max_d;
}

@ -25,6 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "itemgroup.h" #include "itemgroup.h"
#include <json/json.h> #include <json/json.h>
struct ItemDefinition;
struct ToolGroupCap struct ToolGroupCap
{ {
std::unordered_map<int, float> times; std::unordered_map<int, float> times;
@ -132,3 +134,5 @@ PunchDamageResult getPunchDamage(
const ItemStack *punchitem, const ItemStack *punchitem,
float time_from_last_punch float time_from_last_punch
); );
f32 getToolRange(const ItemDefinition &def_selected, const ItemDefinition &def_hand);