summaryrefslogtreecommitdiff
path: root/src/client/game.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/game.cpp')
-rw-r--r--src/client/game.cpp706
1 files changed, 339 insertions, 367 deletions
diff --git a/src/client/game.cpp b/src/client/game.cpp
index 37680dda3..450eb4e32 100644
--- a/src/client/game.cpp
+++ b/src/client/game.cpp
@@ -55,7 +55,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "particles.h"
#include "porting.h"
#include "profiler.h"
-#include "quicktune_shortcutter.h"
#include "raycast.h"
#include "server.h"
#include "settings.h"
@@ -65,6 +64,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/basic_macros.h"
#include "util/directiontables.h"
#include "util/pointedthing.h"
+#include "util/quicktune_shortcutter.h"
#include "irrlicht_changes/static_text.h"
#include "version.h"
#include "script/scripting_client.h"
@@ -184,7 +184,7 @@ struct LocalFormspecHandler : public TextDest
return;
}
- if (m_client && m_client->moddingEnabled())
+ if (m_client && m_client->modsLoaded())
m_client->getScript()->on_formspec_input(m_formname, fields);
}
@@ -413,6 +413,8 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
CachedVertexShaderSetting<float, 3> m_eye_position_vertex;
CachedPixelShaderSetting<float, 3> m_minimap_yaw;
+ CachedPixelShaderSetting<float, 3> m_camera_offset_pixel;
+ CachedPixelShaderSetting<float, 3> m_camera_offset_vertex;
CachedPixelShaderSetting<SamplerLayer_t> m_base_texture;
CachedPixelShaderSetting<SamplerLayer_t> m_normal_texture;
CachedPixelShaderSetting<SamplerLayer_t> m_texture_flags;
@@ -445,6 +447,8 @@ public:
m_eye_position_pixel("eyePosition"),
m_eye_position_vertex("eyePosition"),
m_minimap_yaw("yawVec"),
+ m_camera_offset_pixel("cameraOffset"),
+ m_camera_offset_vertex("cameraOffset"),
m_base_texture("baseTexture"),
m_normal_texture("normalTexture"),
m_texture_flags("textureFlags"),
@@ -493,7 +497,7 @@ public:
sunlight.b };
m_day_light.set(dnc, services);
- u32 animation_timer = porting::getTimeMs() % 100000;
+ u32 animation_timer = porting::getTimeMs() % 1000000;
float animation_timer_f = (float)animation_timer / 100000.f;
m_animation_timer_vertex.set(&animation_timer_f, services);
m_animation_timer_pixel.set(&animation_timer_f, services);
@@ -523,6 +527,18 @@ public:
m_minimap_yaw.set(minimap_yaw_array, services);
}
+ float camera_offset_array[3];
+ v3f offset = intToFloat(m_client->getCamera()->getOffset(), BS);
+#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
+ camera_offset_array[0] = offset.X;
+ camera_offset_array[1] = offset.Y;
+ camera_offset_array[2] = offset.Z;
+#else
+ offset.getAs3Values(camera_offset_array);
+#endif
+ m_camera_offset_pixel.set(camera_offset_array, services);
+ m_camera_offset_vertex.set(camera_offset_array, services);
+
SamplerLayer_t base_tex = 0,
normal_tex = 1,
flags_tex = 2;
@@ -599,7 +615,6 @@ struct GameRunData {
bool dig_instantly;
bool digging_blocked;
bool left_punch;
- bool update_wielded_item_trigger;
bool reset_jump_timer;
float nodig_delay_timer;
float dig_time;
@@ -689,8 +704,8 @@ protected:
bool handleCallbacks();
void processQueues();
void updateProfilers(const RunStats &stats, const FpsControl &draw_times, f32 dtime);
- void addProfilerGraphs(const RunStats &stats, const FpsControl &draw_times, f32 dtime);
void updateStats(RunStats *stats, const FpsControl &draw_times, f32 dtime);
+ void updateProfilerGraphs(ProfilerGraph *graph);
// Input related
void processUserInput(f32 dtime);
@@ -744,15 +759,13 @@ protected:
bool look_for_object, const v3s16 &camera_offset);
void handlePointingAtNothing(const ItemStack &playerItem);
void handlePointingAtNode(const PointedThing &pointed,
- const ItemDefinition &playeritem_def, const ItemStack &playeritem,
- const ToolCapabilities &playeritem_toolcap, f32 dtime);
+ const ItemStack &selected_item, const ItemStack &hand_item, 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,
- const ToolCapabilities &playeritem_toolcap, f32 dtime);
+ const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
const CameraOrientation &cam);
- void updateProfilerGraphs(ProfilerGraph *graph);
// Misc
void limitFps(FpsControl *fps_timings, f32 *dtime);
@@ -804,8 +817,9 @@ private:
void updateChat(f32 dtime, const v2u32 &screensize);
- bool nodePlacementPrediction(const ItemDefinition &playeritem_def,
- const ItemStack &playeritem, const v3s16 &nodepos, const v3s16 &neighbourpos);
+ bool nodePlacement(const ItemDefinition &selected_def, const ItemStack &selected_item,
+ const v3s16 &nodepos, const v3s16 &neighbourpos, const PointedThing &pointed,
+ const NodeMetadata *meta);
static const ClientEventHandler clientEventHandler[CLIENTEVENT_MAX];
InputHandler *input = nullptr;
@@ -827,10 +841,6 @@ private:
ChatBackend *chat_backend = nullptr;
- GUIFormSpecMenu *current_formspec = nullptr;
- //default: "". If other than "", empty show_formspec packets will only close the formspec when the formname matches
- std::string cur_formname;
-
EventManager *eventmgr = nullptr;
QuicktuneShortcutter *quicktune = nullptr;
bool registration_confirmation_shown = false;
@@ -841,7 +851,6 @@ private:
Camera *camera = nullptr;
Clouds *clouds = nullptr; // Free using ->Drop()
Sky *sky = nullptr; // Free using ->Drop()
- Inventory *local_inventory = nullptr;
Hud *hud = nullptr;
Minimap *mapper = nullptr;
@@ -955,7 +964,6 @@ Game::~Game()
delete server; // deleted first to stop all server threads
delete hud;
- delete local_inventory;
delete camera;
delete quicktune;
delete eventmgr;
@@ -1026,7 +1034,6 @@ bool Game::startup(bool *kill,
// Reinit runData
runData = GameRunData();
runData.time_from_last_punch = 10.0;
- runData.update_wielded_item_trigger = true;
m_game_ui->initFlags();
@@ -1089,11 +1096,13 @@ void Game::run()
previous_screen_size = current_screen_size;
}
- /* Must be called immediately after a device->run() call because it
- * uses device->getTimer()->getTime()
- */
+ // Calculate dtime =
+ // RenderingEngine::run() from this iteration
+ // + Sleep time until the wanted FPS are reached
limitFps(&draw_times, &dtime);
+ // Prepare render data for next iteration
+
updateStats(&stats, draw_times, dtime);
updateInteractTimers(dtime);
@@ -1143,8 +1152,9 @@ void Game::shutdown()
driver->setRenderTarget(irr::video::ERT_STEREO_BOTH_BUFFERS);
}
#endif
- if (current_formspec)
- current_formspec->quitMenu();
+ auto formspec = m_game_ui->getFormspecGUI();
+ if (formspec)
+ formspec->quitMenu();
showOverlayMessage(N_("Shutting down..."), 0, 0, false);
@@ -1163,10 +1173,7 @@ void Game::shutdown()
g_menumgr.deletingMenu(g_menumgr.m_stack.front());
}
- if (current_formspec) {
- current_formspec->drop();
- current_formspec = NULL;
- }
+ m_game_ui->deleteFormspec();
chat_backend->addMessage(L"", L"# Disconnected.");
chat_backend->addMessage(L"", L"");
@@ -1355,10 +1362,8 @@ bool Game::createClient(const std::string &playername,
scsf->setSky(sky);
skybox = NULL; // This is used/set later on in the main run loop
- local_inventory = new Inventory(itemdef_manager);
-
- if (!(sky && local_inventory)) {
- *error_message = "Memory allocation error (sky or local inventory)";
+ if (!sky) {
+ *error_message = "Memory allocation error sky";
errorstream << *error_message << std::endl;
return false;
}
@@ -1390,7 +1395,7 @@ bool Game::createClient(const std::string &playername,
player->hurt_tilt_timer = 0;
player->hurt_tilt_strength = 0;
- hud = new Hud(guienv, client, player, local_inventory);
+ hud = new Hud(guienv, client, player, &player->inventory);
if (!hud) {
*error_message = "Memory error: could not create HUD";
@@ -1545,7 +1550,7 @@ bool Game::connectToServer(const std::string &playername,
} else {
registration_confirmation_shown = true;
(new GUIConfirmRegistration(guienv, guienv->getRootGUIElement(), -1,
- &g_menumgr, client, playername, password, *address, connection_aborted))->drop();
+ &g_menumgr, client, playername, password, connection_aborted))->drop();
}
} else {
wait_time += dtime;
@@ -1733,7 +1738,8 @@ void Game::processQueues()
}
-void Game::updateProfilers(const RunStats &stats, const FpsControl &draw_times, f32 dtime)
+void Game::updateProfilers(const RunStats &stats, const FpsControl &draw_times,
+ f32 dtime)
{
float profiler_print_interval =
g_settings->getFloat("profiler_print_interval");
@@ -1741,7 +1747,7 @@ void Game::updateProfilers(const RunStats &stats, const FpsControl &draw_times,
if (profiler_print_interval == 0) {
print_to_log = false;
- profiler_print_interval = 5;
+ profiler_print_interval = 3;
}
if (profiler_interval.step(dtime, profiler_print_interval)) {
@@ -1754,25 +1760,14 @@ void Game::updateProfilers(const RunStats &stats, const FpsControl &draw_times,
g_profiler->clear();
}
- addProfilerGraphs(stats, draw_times, dtime);
-}
-
-
-void Game::addProfilerGraphs(const RunStats &stats,
- const FpsControl &draw_times, f32 dtime)
-{
- g_profiler->graphAdd("mainloop_other",
- draw_times.busy_time / 1000.0f - stats.drawtime / 1000.0f);
-
- if (draw_times.sleep_time != 0)
- g_profiler->graphAdd("mainloop_sleep", draw_times.sleep_time / 1000.0f);
- g_profiler->graphAdd("mainloop_dtime", dtime);
+ // Update update graphs
+ g_profiler->graphAdd("Time non-rendering [ms]",
+ draw_times.busy_time - stats.drawtime);
- g_profiler->add("Elapsed time", dtime);
- g_profiler->avg("FPS", 1. / dtime);
+ g_profiler->graphAdd("Sleep [ms]", draw_times.sleep_time);
+ g_profiler->graphAdd("FPS", 1.0f / dtime);
}
-
void Game::updateStats(RunStats *stats, const FpsControl &draw_times,
f32 dtime)
{
@@ -1853,8 +1848,9 @@ void Game::processUserInput(f32 dtime)
input->step(dtime);
#ifdef __ANDROID__
- if (current_formspec != NULL)
- current_formspec->getAndroidUIInput();
+ auto formspec = m_game_ui->getFormspecGUI();
+ if (formspec)
+ formspec->getAndroidUIInput();
else
handleAndroidChatInput();
#endif
@@ -1880,6 +1876,9 @@ void Game::processKeyInput()
} else if (wasKeyDown(KeyType::INVENTORY)) {
openInventory();
} else if (input->cancelPressed()) {
+#ifdef __ANDROID__
+ m_android_chat_open = false;
+#endif
if (!gui_chat_console->isOpenInhibited()) {
showPauseMenu();
}
@@ -1888,7 +1887,7 @@ void Game::processKeyInput()
} else if (wasKeyDown(KeyType::CMD)) {
openConsole(0.2, L"/");
} else if (wasKeyDown(KeyType::CMD_LOCAL)) {
- if (client->moddingEnabled())
+ if (client->modsLoaded())
openConsole(0.2, L".");
else
m_game_ui->showStatusText(wgettext("Client side scripting is disabled"));
@@ -1979,7 +1978,7 @@ void Game::processItemSelection(u16 *new_playeritem)
/* Item selection using mouse wheel
*/
- *new_playeritem = client->getPlayerItem();
+ *new_playeritem = player->getWieldIndex();
s32 wheel = input->getMouseWheel();
u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE - 1,
@@ -2021,7 +2020,7 @@ void Game::dropSelectedItem(bool single_item)
a->count = single_item ? 1 : 0;
a->from_inv.setCurrentPlayer();
a->from_list = "main";
- a->from_i = client->getPlayerItem();
+ a->from_i = client->getEnv().getLocalPlayer()->getWieldIndex();
client->inventoryAction(a);
}
@@ -2044,13 +2043,14 @@ void Game::openInventory()
InventoryLocation inventoryloc;
inventoryloc.setCurrentPlayer();
- if (!client->moddingEnabled()
+ if (!client->modsLoaded()
|| !client->getScript()->on_inventory_open(fs_src->m_client->getInventory(inventoryloc))) {
TextDest *txt_dst = new TextDestPlayerInventory(client);
- GUIFormSpecMenu::create(current_formspec, client, &input->joystick, fs_src,
+ auto *&formspec = m_game_ui->updateFormspec("");
+ GUIFormSpecMenu::create(formspec, client, &input->joystick, fs_src,
txt_dst, client->getFormspecPrepend());
- cur_formname = "";
- current_formspec->setFormSpec(fs_src->getForm(), inventoryloc);
+
+ formspec->setFormSpec(fs_src->getForm(), inventoryloc);
}
}
@@ -2079,6 +2079,7 @@ void Game::handleAndroidChatInput()
if (m_android_chat_open && porting::getInputDialogState() == 0) {
std::string text = porting::getInputDialogValue();
client->typeChatMessage(utf8_to_wide(text));
+ m_android_chat_open = false;
}
}
#endif
@@ -2348,7 +2349,7 @@ void Game::toggleFullViewRange()
void Game::checkZoomEnabled()
{
LocalPlayer *player = client->getEnv().getLocalPlayer();
- if (player->getZoomFOV() < 0.001f)
+ if (player->getZoomFOV() < 0.001f || player->getFov().fov > 0.0f)
m_game_ui->showTranslatedStatusText("Zoom currently disabled by game or mod");
}
@@ -2479,6 +2480,13 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
keypress_bits |= 1U << 4;
}
+ // autoforward if set: simulate "up" key
+ if (player->getPlayerSettings().continuous_forward &&
+ client->activeObjectsReceived() && !player->isDead()) {
+ control.up = true;
+ keypress_bits |= 1U << 0;
+ }
+
client->setPlayerControl(control);
player->keyPressed = keypress_bits;
@@ -2491,7 +2499,7 @@ inline void Game::step(f32 *dtime)
bool can_be_and_is_paused =
(simple_singleplayer_mode && g_menumgr.pausesGame());
- if (can_be_and_is_paused) { // This is for a singleplayer server
+ if (can_be_and_is_paused) { // This is for a singleplayer server
*dtime = 0; // No time passes
} else {
if (server)
@@ -2526,9 +2534,8 @@ void Game::handleClientEvent_None(ClientEvent *event, CameraOrientation *cam)
void Game::handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam)
{
- if (client->moddingEnabled()) {
+ if (client->modsLoaded())
client->getScript()->on_damage_taken(event->player_damage.amount);
- }
// Damage flash and hurt tilt are not used at death
if (client->getHP() > 0) {
@@ -2556,7 +2563,7 @@ void Game::handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *
{
// If client scripting is enabled, deathscreen is handled by CSM code in
// builtin/client/init.lua
- if (client->moddingEnabled())
+ if (client->modsLoaded())
client->getScript()->on_death();
else
showDeathFormspec();
@@ -2571,9 +2578,10 @@ void Game::handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *
void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam)
{
if (event->show_formspec.formspec->empty()) {
- if (current_formspec && (event->show_formspec.formname->empty()
- || *(event->show_formspec.formname) == cur_formname)) {
- current_formspec->quitMenu();
+ auto formspec = m_game_ui->getFormspecGUI();
+ if (formspec && (event->show_formspec.formname->empty()
+ || *(event->show_formspec.formname) == m_game_ui->getFormspecName())) {
+ formspec->quitMenu();
}
} else {
FormspecFormSource *fs_src =
@@ -2581,9 +2589,9 @@ void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation
TextDestPlayerInventory *txt_dst =
new TextDestPlayerInventory(client, *(event->show_formspec.formname));
- GUIFormSpecMenu::create(current_formspec, client, &input->joystick,
+ auto *&formspec = m_game_ui->updateFormspec(*(event->show_formspec.formname));
+ GUIFormSpecMenu::create(formspec, client, &input->joystick,
fs_src, txt_dst, client->getFormspecPrepend());
- cur_formname = *(event->show_formspec.formname);
}
delete event->show_formspec.formspec;
@@ -2595,7 +2603,7 @@ void Game::handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrienta
FormspecFormSource *fs_src = new FormspecFormSource(*event->show_formspec.formspec);
LocalFormspecHandler *txt_dst =
new LocalFormspecHandler(*event->show_formspec.formname, client);
- GUIFormSpecMenu::create(current_formspec, client, &input->joystick,
+ GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, &input->joystick,
fs_src, txt_dst, client->getFormspecPrepend());
delete event->show_formspec.formspec;
@@ -2840,19 +2848,10 @@ void Game::updateCamera(u32 busy_time, f32 dtime)
*/
ItemStack playeritem;
{
- InventoryList *mlist = local_inventory->getList("main");
-
- 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);
+ ItemStack selected, hand;
+ playeritem = player->getWieldedItem(&selected, &hand);
}
-
ToolCapabilities playeritem_toolcap =
playeritem.getToolCapabilities(itemdef_manager);
@@ -2933,7 +2932,7 @@ void Game::updateSound(f32 dtime)
soundmaker->step(dtime);
ClientMap &map = client->getEnv().getClientMap();
- MapNode n = map.getNodeNoEx(player->getFootstepNodePos());
+ MapNode n = map.getNode(player->getFootstepNodePos());
soundmaker->m_player_step_sound = nodedef_manager->get(n).sound_footstep;
}
@@ -2942,46 +2941,35 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
{
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_eye_position = player->getEyePosition();
v3f camera_position = camera->getPosition();
v3f camera_direction = camera->getDirection();
v3s16 camera_offset = camera->getOffset();
+ if (camera->getCameraMode() == CAMERA_MODE_FIRST)
+ player_eye_position += player->eye_offset_first;
+ else
+ player_eye_position += player->eye_offset_third;
/*
Calculate what block is the crosshair pointing to
*/
- f32 d = playeritem_def.range; // max. distance
- f32 d_hand = hand_def.range;
+ ItemStack selected_item, hand_item;
+ const ItemStack &tool_item = player->getWieldedItem(&selected_item, &hand_item);
- if (d < 0 && d_hand >= 0)
- d = d_hand;
- else if (d < 0)
- d = 4.0;
+ const ItemDefinition &selected_def = selected_item.getDefinition(itemdef_manager);
+ f32 d = getToolRange(selected_def, hand_item.getDefinition(itemdef_manager));
core::line3d<f32> shootline;
if (camera->getCameraMode() != CAMERA_MODE_THIRD_FRONT) {
- shootline = core::line3d<f32>(camera_position,
- camera_position + camera_direction * BS * d);
+ shootline = core::line3d<f32>(player_eye_position,
+ player_eye_position + camera_direction * BS * d);
} else {
- // prevent player pointing anything in front-view
- shootline = core::line3d<f32>(camera_position,camera_position);
+ // prevent player pointing anything in front-view
+ shootline = core::line3d<f32>(camera_position, camera_position);
}
#ifdef HAVE_TOUCHSCREENGUI
@@ -2998,7 +2986,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
#endif
PointedThing pointed = updatePointedThing(shootline,
- playeritem_def.liquids_pointable,
+ selected_def.liquids_pointable,
!runData.ldown_for_dig,
camera_offset);
@@ -3020,7 +3008,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
if (runData.digging) {
if (input->getLeftReleased()) {
infostream << "Left button released"
- << " (stopped digging)" << std::endl;
+ << " (stopped digging)" << std::endl;
runData.digging = false;
} else if (pointed != runData.pointed_old) {
if (pointed.type == POINTEDTHING_NODE
@@ -3031,14 +3019,14 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
// Don't reset.
} else {
infostream << "Pointing away from node"
- << " (stopped digging)" << std::endl;
+ << " (stopped digging)" << std::endl;
runData.digging = false;
hud->updateSelectionMesh(camera_offset);
}
}
if (!runData.digging) {
- client->interact(1, runData.pointed_old);
+ client->interact(INTERACT_STOP_DIGGING, runData.pointed_old);
client->setCrack(-1, v3s16(0, 0, 0));
runData.dig_time = 0.0;
}
@@ -3062,30 +3050,19 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
else
runData.repeat_rightclick_timer = 0;
- if (playeritem_def.usable && input->getLeftState()) {
- if (input->getLeftClicked() && (!client->moddingEnabled()
- || !client->getScript()->on_item_use(playeritem, pointed)))
- client->interact(4, pointed);
+ if (selected_def.usable && input->getLeftState()) {
+ if (input->getLeftClicked() && (!client->modsLoaded()
+ || !client->getScript()->on_item_use(selected_item, pointed)))
+ client->interact(INTERACT_USE, pointed);
} else if (pointed.type == POINTEDTHING_NODE) {
- ToolCapabilities playeritem_toolcap =
- 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);
+ handlePointingAtNode(pointed, selected_item, hand_item, dtime);
} 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()) {
// When button is held down in air, show continuous animation
runData.left_punch = true;
} else if (input->getRightClicked()) {
- handlePointingAtNothing(playeritem);
+ handlePointingAtNothing(selected_item);
}
runData.pointed_old = pointed;
@@ -3133,7 +3110,7 @@ PointedThing Game::updatePointedThing(
}
} else if (result.type == POINTEDTHING_NODE) {
// Update selection boxes
- MapNode n = map.getNodeNoEx(result.node_undersurface);
+ MapNode n = map.getNode(result.node_undersurface);
std::vector<aabb3f> boxes;
n.getSelectionBoxes(nodedef, &boxes,
n.getNeighbors(result.node_undersurface, &map));
@@ -3160,12 +3137,12 @@ PointedThing Game::updatePointedThing(
v3s16 p = floatToInt(pf, BS);
// Get selection mesh light level
- MapNode n = map.getNodeNoEx(p);
+ MapNode n = map.getNode(p);
u16 node_light = getInteriorLight(n, -1, nodedef);
u16 light_level = node_light;
for (const v3s16 &dir : g_6dirs) {
- n = map.getNodeNoEx(p + dir);
+ n = map.getNode(p + dir);
node_light = getInteriorLight(n, -1, nodedef);
if (node_light > light_level)
light_level = node_light;
@@ -3197,13 +3174,12 @@ void Game::handlePointingAtNothing(const ItemStack &playerItem)
infostream << "Right Clicked in Air" << std::endl;
PointedThing fauxPointed;
fauxPointed.type = POINTEDTHING_NOTHING;
- client->interact(5, fauxPointed);
+ client->interact(INTERACT_ACTIVATE, fauxPointed);
}
void Game::handlePointingAtNode(const PointedThing &pointed,
- const ItemDefinition &playeritem_def, const ItemStack &playeritem,
- const ToolCapabilities &playeritem_toolcap, f32 dtime)
+ const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime)
{
v3s16 nodepos = pointed.node_undersurface;
v3s16 neighbourpos = pointed.node_abovesurface;
@@ -3217,7 +3193,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
if (runData.nodig_delay_timer <= 0.0 && input->getLeftState()
&& !runData.digging_blocked
&& client->checkPrivilege("interact")) {
- handleDigging(pointed, nodepos, playeritem_toolcap, dtime);
+ handleDigging(pointed, nodepos, selected_item, hand_item, dtime);
}
// This should be done after digging handling
@@ -3227,7 +3203,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
m_game_ui->setInfoText(unescape_translate(utf8_to_wide(
meta->getString("infotext"))));
} else {
- MapNode n = map.getNodeNoEx(nodepos);
+ MapNode n = map.getNode(nodepos);
if (nodedef_manager->get(n).tiledef[0].name == "unknown_node.png") {
m_game_ui->setInfoText(L"Unknown node: " +
@@ -3241,213 +3217,219 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
runData.repeat_rightclick_timer = 0;
infostream << "Ground right-clicked" << std::endl;
- if (meta && !meta->getString("formspec").empty() && !random_input
- && !isKeyDown(KeyType::SNEAK)) {
- // Report right click to server
- if (nodedef_manager->get(map.getNodeNoEx(nodepos)).rightclickable) {
- client->interact(3, pointed);
- }
-
- infostream << "Launching custom inventory view" << std::endl;
-
- InventoryLocation inventoryloc;
- inventoryloc.setNodeMeta(nodepos);
+ camera->setDigging(1); // right click animation (always shown for feedback)
- NodeMetadataFormSource *fs_src = new NodeMetadataFormSource(
- &client->getEnv().getClientMap(), nodepos);
- TextDest *txt_dst = new TextDestNodeMetadata(nodepos, client);
+ soundmaker->m_player_rightpunch_sound = SimpleSoundSpec();
- GUIFormSpecMenu::create(current_formspec, client, &input->joystick, fs_src,
- txt_dst, client->getFormspecPrepend());
- cur_formname.clear();
+ // If the wielded item has node placement prediction,
+ // make that happen
+ // And also set the sound and send the interact
+ // But first check for meta formspec and rightclickable
+ auto &def = selected_item.getDefinition(itemdef_manager);
+ bool placed = nodePlacement(def, selected_item, nodepos, neighbourpos,
+ pointed, meta);
- current_formspec->setFormSpec(meta->getString("formspec"), inventoryloc);
- } else {
- // Report right click to server
-
- camera->setDigging(1); // right click animation (always shown for feedback)
-
- // If the wielded item has node placement prediction,
- // make that happen
- bool placed = nodePlacementPrediction(playeritem_def, playeritem, nodepos,
- neighbourpos);
-
- if (placed) {
- // Report to server
- client->interact(3, pointed);
- // Read the sound
- soundmaker->m_player_rightpunch_sound =
- playeritem_def.sound_place;
-
- if (client->moddingEnabled())
- client->getScript()->on_placenode(pointed, playeritem_def);
- } else {
- soundmaker->m_player_rightpunch_sound =
- SimpleSoundSpec();
-
- if (playeritem_def.node_placement_prediction.empty() ||
- nodedef_manager->get(map.getNodeNoEx(nodepos)).rightclickable) {
- client->interact(3, pointed); // Report to server
- } else {
- soundmaker->m_player_rightpunch_sound =
- playeritem_def.sound_place_failed;
- }
- }
- }
+ if (placed && client->modsLoaded())
+ client->getScript()->on_placenode(pointed, def);
}
}
-bool Game::nodePlacementPrediction(const ItemDefinition &playeritem_def,
- const ItemStack &playeritem, const v3s16 &nodepos, const v3s16 &neighbourpos)
+bool Game::nodePlacement(const ItemDefinition &selected_def,
+ const ItemStack &selected_item, const v3s16 &nodepos, const v3s16 &neighbourpos,
+ const PointedThing &pointed, const NodeMetadata *meta)
{
- std::string prediction = playeritem_def.node_placement_prediction;
+ std::string prediction = selected_def.node_placement_prediction;
const NodeDefManager *nodedef = client->ndef();
ClientMap &map = client->getEnv().getClientMap();
MapNode node;
bool is_valid_position;
- node = map.getNodeNoEx(nodepos, &is_valid_position);
- if (!is_valid_position)
+ node = map.getNode(nodepos, &is_valid_position);
+ if (!is_valid_position) {
+ soundmaker->m_player_rightpunch_sound = selected_def.sound_place_failed;
+ return false;
+ }
+
+ // formspec in meta
+ if (meta && !meta->getString("formspec").empty() && !random_input
+ && !isKeyDown(KeyType::SNEAK)) {
+ // on_rightclick callbacks are called anyway
+ if (nodedef_manager->get(map.getNode(nodepos)).rightclickable)
+ client->interact(INTERACT_PLACE, pointed);
+
+ infostream << "Launching custom inventory view" << std::endl;
+
+ InventoryLocation inventoryloc;
+ inventoryloc.setNodeMeta(nodepos);
+
+ NodeMetadataFormSource *fs_src = new NodeMetadataFormSource(
+ &client->getEnv().getClientMap(), nodepos);
+ TextDest *txt_dst = new TextDestNodeMetadata(nodepos, client);
+
+ auto *&formspec = m_game_ui->updateFormspec("");
+ GUIFormSpecMenu::create(formspec, client, &input->joystick, fs_src,
+ txt_dst, client->getFormspecPrepend());
+
+ formspec->setFormSpec(meta->getString("formspec"), inventoryloc);
return false;
+ }
+
+ // on_rightclick callback
+ if (prediction.empty() || (nodedef->get(node).rightclickable &&
+ !isKeyDown(KeyType::SNEAK))) {
+ // Report to server
+ client->interact(INTERACT_PLACE, pointed);
+ return false;
+ }
- if (!prediction.empty() && !nodedef->get(node).rightclickable) {
- verbosestream << "Node placement prediction for "
- << playeritem_def.name << " is "
- << prediction << std::endl;
- v3s16 p = neighbourpos;
-
- // Place inside node itself if buildable_to
- MapNode n_under = map.getNodeNoEx(nodepos, &is_valid_position);
- if (is_valid_position)
- {
- if (nodedef->get(n_under).buildable_to)
- p = nodepos;
- else {
- node = map.getNodeNoEx(p, &is_valid_position);
- if (is_valid_position &&!nodedef->get(node).buildable_to)
- return false;
+ verbosestream << "Node placement prediction for "
+ << selected_def.name << " is "
+ << prediction << std::endl;
+ v3s16 p = neighbourpos;
+
+ // Place inside node itself if buildable_to
+ MapNode n_under = map.getNode(nodepos, &is_valid_position);
+ if (is_valid_position) {
+ if (nodedef->get(n_under).buildable_to) {
+ p = nodepos;
+ } else {
+ node = map.getNode(p, &is_valid_position);
+ if (is_valid_position && !nodedef->get(node).buildable_to) {
+ // Report to server
+ client->interact(INTERACT_PLACE, pointed);
+ return false;
}
}
+ }
- // Find id of predicted node
- content_t id;
- bool found = nodedef->getId(prediction, id);
+ // Find id of predicted node
+ content_t id;
+ bool found = nodedef->getId(prediction, id);
- if (!found) {
- errorstream << "Node placement prediction failed for "
- << playeritem_def.name << " (places "
- << prediction
- << ") - Name not known" << std::endl;
- return false;
- }
+ if (!found) {
+ errorstream << "Node placement prediction failed for "
+ << selected_def.name << " (places "
+ << prediction
+ << ") - Name not known" << std::endl;
+ // Handle this as if prediction was empty
+ // Report to server
+ client->interact(INTERACT_PLACE, pointed);
+ return false;
+ }
- const ContentFeatures &predicted_f = nodedef->get(id);
+ const ContentFeatures &predicted_f = nodedef->get(id);
- // Predict param2 for facedir and wallmounted nodes
- u8 param2 = 0;
+ // Predict param2 for facedir and wallmounted nodes
+ u8 param2 = 0;
- if (predicted_f.param_type_2 == CPT2_WALLMOUNTED ||
+ if (predicted_f.param_type_2 == CPT2_WALLMOUNTED ||
predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED) {
- v3s16 dir = nodepos - neighbourpos;
+ v3s16 dir = nodepos - neighbourpos;
- if (abs(dir.Y) > MYMAX(abs(dir.X), abs(dir.Z))) {
- param2 = dir.Y < 0 ? 1 : 0;
- } else if (abs(dir.X) > abs(dir.Z)) {
- param2 = dir.X < 0 ? 3 : 2;
- } else {
- param2 = dir.Z < 0 ? 5 : 4;
- }
+ if (abs(dir.Y) > MYMAX(abs(dir.X), abs(dir.Z))) {
+ param2 = dir.Y < 0 ? 1 : 0;
+ } else if (abs(dir.X) > abs(dir.Z)) {
+ param2 = dir.X < 0 ? 3 : 2;
+ } else {
+ param2 = dir.Z < 0 ? 5 : 4;
}
+ }
- if (predicted_f.param_type_2 == CPT2_FACEDIR ||
+ if (predicted_f.param_type_2 == CPT2_FACEDIR ||
predicted_f.param_type_2 == CPT2_COLORED_FACEDIR) {
- v3s16 dir = nodepos - floatToInt(client->getEnv().getLocalPlayer()->getPosition(), BS);
+ v3s16 dir = nodepos - floatToInt(client->getEnv().getLocalPlayer()->getPosition(), BS);
- if (abs(dir.X) > abs(dir.Z)) {
- param2 = dir.X < 0 ? 3 : 1;
- } else {
- param2 = dir.Z < 0 ? 2 : 0;
- }
+ if (abs(dir.X) > abs(dir.Z)) {
+ param2 = dir.X < 0 ? 3 : 1;
+ } else {
+ param2 = dir.Z < 0 ? 2 : 0;
}
+ }
+
+ assert(param2 <= 5);
- assert(param2 <= 5);
-
- //Check attachment if node is in group attached_node
- if (((ItemGroupList) predicted_f.groups)["attached_node"] != 0) {
- static v3s16 wallmounted_dirs[8] = {
- v3s16(0, 1, 0),
- v3s16(0, -1, 0),
- v3s16(1, 0, 0),
- v3s16(-1, 0, 0),
- v3s16(0, 0, 1),
- v3s16(0, 0, -1),
- };
- v3s16 pp;
-
- if (predicted_f.param_type_2 == CPT2_WALLMOUNTED ||
+ //Check attachment if node is in group attached_node
+ if (((ItemGroupList) predicted_f.groups)["attached_node"] != 0) {
+ static v3s16 wallmounted_dirs[8] = {
+ v3s16(0, 1, 0),
+ v3s16(0, -1, 0),
+ v3s16(1, 0, 0),
+ v3s16(-1, 0, 0),
+ v3s16(0, 0, 1),
+ v3s16(0, 0, -1),
+ };
+ v3s16 pp;
+
+ if (predicted_f.param_type_2 == CPT2_WALLMOUNTED ||
predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED)
- pp = p + wallmounted_dirs[param2];
- else
- pp = p + v3s16(0, -1, 0);
+ pp = p + wallmounted_dirs[param2];
+ else
+ pp = p + v3s16(0, -1, 0);
- if (!nodedef->get(map.getNodeNoEx(pp)).walkable)
- return false;
+ if (!nodedef->get(map.getNode(pp)).walkable) {
+ // Report to server
+ client->interact(INTERACT_PLACE, pointed);
+ return false;
}
+ }
- // Apply color
- if ((predicted_f.param_type_2 == CPT2_COLOR
+ // Apply color
+ if ((predicted_f.param_type_2 == CPT2_COLOR
|| predicted_f.param_type_2 == CPT2_COLORED_FACEDIR
|| predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED)) {
- const std::string &indexstr = playeritem.metadata.getString(
- "palette_index", 0);
- if (!indexstr.empty()) {
- s32 index = mystoi(indexstr);
- if (predicted_f.param_type_2 == CPT2_COLOR) {
- param2 = index;
- } else if (predicted_f.param_type_2
- == CPT2_COLORED_WALLMOUNTED) {
- // param2 = pure palette index + other
- param2 = (index & 0xf8) | (param2 & 0x07);
- } else if (predicted_f.param_type_2
- == CPT2_COLORED_FACEDIR) {
- // param2 = pure palette index + other
- param2 = (index & 0xe0) | (param2 & 0x1f);
- }
+ const std::string &indexstr = selected_item.metadata.getString(
+ "palette_index", 0);
+ if (!indexstr.empty()) {
+ s32 index = mystoi(indexstr);
+ if (predicted_f.param_type_2 == CPT2_COLOR) {
+ param2 = index;
+ } else if (predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED) {
+ // param2 = pure palette index + other
+ param2 = (index & 0xf8) | (param2 & 0x07);
+ } else if (predicted_f.param_type_2 == CPT2_COLORED_FACEDIR) {
+ // param2 = pure palette index + other
+ param2 = (index & 0xe0) | (param2 & 0x1f);
}
}
+ }
- // Add node to client map
- MapNode n(id, 0, param2);
+ // Add node to client map
+ MapNode n(id, 0, param2);
- try {
- LocalPlayer *player = client->getEnv().getLocalPlayer();
+ try {
+ LocalPlayer *player = client->getEnv().getLocalPlayer();
- // Dont place node when player would be inside new node
- // NOTE: This is to be eventually implemented by a mod as client-side Lua
- if (!nodedef->get(n).walkable ||
+ // Dont place node when player would be inside new node
+ // NOTE: This is to be eventually implemented by a mod as client-side Lua
+ if (!nodedef->get(n).walkable ||
g_settings->getBool("enable_build_where_you_stand") ||
(client->checkPrivilege("noclip") && g_settings->getBool("noclip")) ||
(nodedef->get(n).walkable &&
neighbourpos != player->getStandingNodePos() + v3s16(0, 1, 0) &&
neighbourpos != player->getStandingNodePos() + v3s16(0, 2, 0))) {
-
- // This triggers the required mesh update too
- client->addNode(p, n);
- return true;
- }
- } catch (InvalidPositionException &e) {
- errorstream << "Node placement prediction failed for "
- << playeritem_def.name << " (places "
- << prediction
- << ") - Position not loaded" << std::endl;
+ // This triggers the required mesh update too
+ client->addNode(p, n);
+ // Report to server
+ client->interact(INTERACT_PLACE, pointed);
+ // A node is predicted, also play a sound
+ soundmaker->m_player_rightpunch_sound = selected_def.sound_place;
+ return true;
+ } else {
+ soundmaker->m_player_rightpunch_sound = selected_def.sound_place_failed;
+ return false;
}
+ } catch (InvalidPositionException &e) {
+ errorstream << "Node placement prediction failed for "
+ << selected_def.name << " (places "
+ << prediction
+ << ") - Position not loaded" << std::endl;
+ soundmaker->m_player_rightpunch_sound = selected_def.sound_place_failed;
+ return false;
}
-
- return false;
}
-void Game::handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem,
- const v3f &player_position, bool show_debug)
+void Game::handlePointingAtObject(const PointedThing &pointed,
+ const ItemStack &tool_item, const v3f &player_position, bool show_debug)
{
std::wstring infotext = unescape_translate(
utf8_to_wide(runData.selected_object->infoText()));
@@ -3483,50 +3465,39 @@ void Game::handlePointingAtObject(const PointedThing &pointed, const ItemStack &
// Report direct punch
v3f objpos = runData.selected_object->getPosition();
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(
- dir, &item, runData.time_from_last_punch);
+ dir, &tool_item, runData.time_from_last_punch);
runData.time_from_last_punch = 0;
if (!disable_send)
- client->interact(0, pointed);
+ client->interact(INTERACT_START_DIGGING, pointed);
}
} else if (input->getRightClicked()) {
infostream << "Right-clicked object" << std::endl;
- client->interact(3, pointed); // place
+ client->interact(INTERACT_PLACE, pointed); // place
}
}
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();
ClientMap &map = client->getEnv().getClientMap();
- MapNode n = client->getEnv().getClientMap().getNodeNoEx(nodepos);
+ MapNode n = client->getEnv().getClientMap().getNode(nodepos);
// NOTE: Similar piece of code exists on the server side for
// cheat detection.
// Get digging parameters
DigParams params = getDigParams(nodedef_manager->get(n).groups,
- &playeritem_toolcap);
+ &selected_item.getToolCapabilities(itemdef_manager));
// If can't dig, try hand
if (!params.diggable) {
- InventoryList *hlist = local_inventory->getList("hand");
- const ToolCapabilities *tp = hlist
- ? &hlist->getItem(0).getToolCapabilities(itemdef_manager)
- : itemdef_manager->get("").tool_capabilities;
-
- if (tp)
- params = getDigParams(nodedef_manager->get(n).groups, tp);
+ params = getDigParams(nodedef_manager->get(n).groups,
+ &hand_item.getToolCapabilities(itemdef_manager));
}
if (!params.diggable) {
@@ -3545,9 +3516,9 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
if (!runData.digging) {
infostream << "Started digging" << std::endl;
runData.dig_instantly = runData.dig_time_complete == 0;
- if (client->moddingEnabled() && client->getScript()->on_punchnode(nodepos, n))
+ if (client->modsLoaded() && client->getScript()->on_punchnode(nodepos, n))
return;
- client->interact(0, pointed);
+ client->interact(INTERACT_START_DIGGING, pointed);
runData.digging = true;
runData.ldown_for_dig = true;
}
@@ -3603,10 +3574,10 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
runData.nodig_delay_timer = 0.15;
bool is_valid_position;
- MapNode wasnode = map.getNodeNoEx(nodepos, &is_valid_position);
+ MapNode wasnode = map.getNode(nodepos, &is_valid_position);
if (is_valid_position) {
- if (client->moddingEnabled() &&
- client->getScript()->on_dignode(nodepos, wasnode)) {
+ if (client->modsLoaded() &&
+ client->getScript()->on_dignode(nodepos, wasnode)) {
return;
}
@@ -3622,7 +3593,7 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
// implicit else: no prediction
}
- client->interact(2, pointed);
+ client->interact(INTERACT_DIGGING_COMPLETED, pointed);
if (m_cache_enable_particles) {
const ContentFeatures &features =
@@ -3650,6 +3621,7 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
const CameraOrientation &cam)
{
+ TimeTaker tt_update("Game::updateFrame()");
LocalPlayer *player = client->getEnv().getLocalPlayer();
/*
@@ -3674,7 +3646,6 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
direct_brightness = time_brightness;
sunlight_seen = true;
} else {
- ScopeProfiler sp(g_profiler, "Detecting background light", SPT_AVG);
float old_brightness = sky->getBrightness();
direct_brightness = client->getEnv().getClientMap()
.getBackgroundBrightness(MYMIN(runData.fog_range * 1.2, 60 * BS),
@@ -3780,31 +3751,14 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
Inventory
*/
- if (client->getPlayerItem() != runData.new_playeritem)
- client->selectPlayerItem(runData.new_playeritem);
+ if (player->getWieldIndex() != runData.new_playeritem)
+ client->setPlayerItem(runData.new_playeritem);
- // Update local inventory if it has changed
- if (client->getLocalInventoryUpdated()) {
- //infostream<<"Updating local inventory"<<std::endl;
- client->getLocalInventory(*local_inventory);
- runData.update_wielded_item_trigger = true;
- }
-
- if (runData.update_wielded_item_trigger) {
+ if (client->updateWieldedItem()) {
// Update wielded tool
- InventoryList *mlist = local_inventory->getList("main");
-
- if (mlist && (client->getPlayerItem() < mlist->getSize())) {
- 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;
+ ItemStack selected_item, hand_item;
+ ItemStack &tool_item = player->getWieldedItem(&selected_item, &hand_item);
+ camera->wield(tool_item);
}
/*
@@ -3822,28 +3776,42 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
runData.update_draw_list_last_cam_dir = camera_direction;
}
- m_game_ui->update(*stats, client, draw_control, cam, runData.pointed_old, dtime);
+ m_game_ui->update(*stats, client, draw_control, cam, runData.pointed_old, gui_chat_console, dtime);
/*
make sure menu is on top
1. Delete formspec menu reference if menu was removed
2. Else, make sure formspec menu is on top
*/
- if (current_formspec) {
- if (current_formspec->getReferenceCount() == 1) {
- current_formspec->drop();
- current_formspec = NULL;
- } else if (isMenuActive()) {
- guiroot->bringToFront(current_formspec);
+ auto formspec = m_game_ui->getFormspecGUI();
+ do { // breakable. only runs for one iteration
+ if (!formspec)
+ break;
+
+ if (formspec->getReferenceCount() == 1) {
+ m_game_ui->deleteFormspec();
+ break;
}
- }
+
+ auto &loc = formspec->getFormspecLocation();
+ if (loc.type == InventoryLocation::NODEMETA) {
+ NodeMetadata *meta = client->getEnv().getClientMap().getNodeMetadata(loc.p);
+ if (!meta || meta->getString("formspec").empty()) {
+ formspec->quitMenu();
+ break;
+ }
+ }
+
+ if (isMenuActive())
+ guiroot->bringToFront(formspec);
+ } while (false);
/*
Drawing begins
*/
const video::SColor &skycolor = sky->getSkyColor();
- TimeTaker tt_draw("mainloop: draw");
+ TimeTaker tt_draw("Draw scene");
driver->beginScene(true, true, skycolor);
bool draw_wield_tool = (m_game_ui->m_flags.show_hud &&
@@ -3903,7 +3871,8 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
driver->endScene();
stats->drawtime = tt_draw.stop(true);
- g_profiler->graphAdd("mainloop_draw", stats->drawtime / 1000.0f);
+ g_profiler->avg("Game::updateFrame(): draw scene [ms]", stats->drawtime);
+ g_profiler->graphAdd("Update frame [ms]", tt_update.stop(true));
}
/* Log times and stuff for visualization */
@@ -4033,8 +4002,8 @@ void Game::extendedResourceCleanup()
void Game::showDeathFormspec()
{
- static std::string formspec =
- std::string(FORMSPEC_VERSION_STRING) +
+ static std::string formspec_str =
+ std::string("formspec_version[1]") +
SIZE_TAG
"bgcolor[#320000b4;true]"
"label[4.85,1.35;" + gettext("You died") + "]"
@@ -4044,12 +4013,13 @@ void Game::showDeathFormspec()
/* Create menu */
/* Note: FormspecFormSource and LocalFormspecHandler *
* are deleted by guiFormSpecMenu */
- FormspecFormSource *fs_src = new FormspecFormSource(formspec);
+ FormspecFormSource *fs_src = new FormspecFormSource(formspec_str);
LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_DEATH_SCREEN", client);
- GUIFormSpecMenu::create(current_formspec, client, &input->joystick, fs_src,
- txt_dst, client->getFormspecPrepend());
- current_formspec->setFocus("btn_respawn");
+ auto *&formspec = m_game_ui->getFormspecGUI();
+ GUIFormSpecMenu::create(formspec, client, &input->joystick,
+ fs_src, txt_dst, client->getFormspecPrepend());
+ formspec->setFocus("btn_respawn");
}
#define GET_KEY_NAME(KEY) gettext(getKeySetting(#KEY).name())
@@ -4107,7 +4077,7 @@ void Game::showPauseMenu()
float ypos = simple_singleplayer_mode ? 0.7f : 0.1f;
std::ostringstream os;
- os << FORMSPEC_VERSION_STRING << SIZE_TAG
+ os << "formspec_version[1]" << SIZE_TAG
<< "button_exit[4," << (ypos++) << ";3,0.5;btn_continue;"
<< strgettext("Continue") << "]";
@@ -4173,10 +4143,11 @@ void Game::showPauseMenu()
FormspecFormSource *fs_src = new FormspecFormSource(os.str());
LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU");
- GUIFormSpecMenu::create(current_formspec, client, &input->joystick,
+ auto *&formspec = m_game_ui->getFormspecGUI();
+ GUIFormSpecMenu::create(formspec, client, &input->joystick,
fs_src, txt_dst, client->getFormspecPrepend());
- current_formspec->setFocus("btn_continue");
- current_formspec->doPause = true;
+ formspec->setFocus("btn_continue");
+ formspec->doPause = true;
}
/****************************************************************************/
@@ -4227,7 +4198,8 @@ void the_game(bool *kill,
error_message = e.what();
errorstream << "ServerError: " << error_message << std::endl;
} catch (ModError &e) {
- error_message = e.what() + strgettext("\nCheck debug.txt for details.");
- errorstream << "ModError: " << error_message << std::endl;
+ error_message = std::string("ModError: ") + e.what() +
+ strgettext("\nCheck debug.txt for details.");
+ errorstream << error_message << std::endl;
}
}