]> git.lizzy.rs Git - minetest.git/blobdiff - src/client/game.cpp
Initialize wield mesh colors when changing item. (#12254)
[minetest.git] / src / client / game.cpp
index 7478e225fa5acc0d0215040a1aac81273c16122c..d21bdbe991b1a7576a62090339183f2f5ab3ca7a 100644 (file)
@@ -575,10 +575,19 @@ class GameGlobalShaderConstantSetterFactory : public IShaderConstantSetterFactor
 /****************************************************************************
  ****************************************************************************/
 
-const float object_hit_delay = 0.2;
+const static float object_hit_delay = 0.2;
 
 struct FpsControl {
-       u32 last_time, busy_time, sleep_time;
+       FpsControl() : last_time(0), busy_time(0), sleep_time(0) {}
+
+       void reset();
+
+       void limit(IrrlichtDevice *device, f32 *dtime);
+
+       u32 getBusyMs() const { return busy_time / 1000; }
+
+       // all values in microseconds (us)
+       u64 last_time, busy_time, sleep_time;
 };
 
 
@@ -712,9 +721,9 @@ class Game {
        void updatePlayerControl(const CameraOrientation &cam);
        void step(f32 *dtime);
        void processClientEvents(CameraOrientation *cam);
-       void updateCamera(u32 busy_time, f32 dtime);
+       void updateCamera(f32 dtime);
        void updateSound(f32 dtime);
-       void processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug);
+       void processPlayerInteraction(f32 dtime, bool show_hud);
        /*!
         * Returns the object or node the player is pointing at.
         * Also updates the selected thing in the Hud.
@@ -743,8 +752,6 @@ class Game {
        void updateShadows();
 
        // Misc
-       void limitFps(FpsControl *fps_timings, f32 *dtime);
-
        void showOverlayMessage(const char *msg, float dtime, int percent,
                        bool draw_clouds = true);
 
@@ -900,7 +907,10 @@ class Game {
 
        bool m_does_lost_focus_pause_game = false;
 
+#if IRRLICHT_VERSION_MT_REVISION < 5
        int m_reset_HW_buffer_counter = 0;
+#endif
+
 #ifdef HAVE_TOUCHSCREENGUI
        bool m_cache_hold_aux1;
 #endif
@@ -1053,17 +1063,17 @@ bool Game::startup(bool *kill,
 void Game::run()
 {
        ProfilerGraph graph;
-       RunStats stats              = { 0 };
-       CameraOrientation cam_view_target  = { 0 };
-       CameraOrientation cam_view  = { 0 };
-       FpsControl draw_times       = { 0 };
+       RunStats stats;
+       CameraOrientation cam_view_target = {};
+       CameraOrientation cam_view = {};
+       FpsControl draw_times;
        f32 dtime; // in seconds
 
        /* Clear the profiler */
        Profiler::GraphValues dummyvalues;
        g_profiler->graphGet(dummyvalues);
 
-       draw_times.last_time = m_rendering_engine->get_timer_time();
+       draw_times.reset();
 
        set_light_table(g_settings->getFloat("display_gamma"));
 
@@ -1095,7 +1105,7 @@ void Game::run()
                // Calculate dtime =
                //    m_rendering_engine->run() from this iteration
                //  + Sleep time until the wanted FPS are reached
-               limitFps(&draw_times, &dtime);
+               draw_times.limit(device, &dtime);
 
                // Prepare render data for next iteration
 
@@ -1125,10 +1135,9 @@ void Game::run()
                step(&dtime);
                processClientEvents(&cam_view_target);
                updateDebugState();
-               updateCamera(draw_times.busy_time, dtime);
+               updateCamera(dtime);
                updateSound(dtime);
-               processPlayerInteraction(dtime, m_game_ui->m_flags.show_hud,
-                       m_game_ui->m_flags.show_basic_debug);
+               processPlayerInteraction(dtime, m_game_ui->m_flags.show_hud);
                updateFrame(&graph, &stats, dtime, cam_view);
                updateProfilerGraphs(&graph);
 
@@ -1495,15 +1504,15 @@ bool Game::connectToServer(const GameStartData &start_data,
        try {
                input->clear();
 
-               FpsControl fps_control = { 0 };
+               FpsControl fps_control;
                f32 dtime;
                f32 wait_time = 0; // in seconds
 
-               fps_control.last_time = m_rendering_engine->get_timer_time();
+               fps_control.reset();
 
                while (m_rendering_engine->run()) {
 
-                       limitFps(&fps_control, &dtime);
+                       fps_control.limit(device, &dtime);
 
                        // Update client and server
                        client->step(dtime);
@@ -1570,14 +1579,14 @@ bool Game::getServerContent(bool *aborted)
 {
        input->clear();
 
-       FpsControl fps_control = { 0 };
+       FpsControl fps_control;
        f32 dtime; // in seconds
 
-       fps_control.last_time = m_rendering_engine->get_timer_time();
+       fps_control.reset();
 
        while (m_rendering_engine->run()) {
 
-               limitFps(&fps_control, &dtime);
+               fps_control.limit(device, &dtime);
 
                // Update client and server
                client->step(dtime);
@@ -1733,17 +1742,16 @@ void Game::processQueues()
 
 void Game::updateDebugState()
 {
-       bool has_basic_debug = client->checkPrivilege("basic_debug");
+       LocalPlayer *player = client->getEnv().getLocalPlayer();
        bool has_debug = client->checkPrivilege("debug");
+       bool has_basic_debug = has_debug || (player->hud_flags & HUD_FLAG_BASIC_DEBUG);
 
        if (m_game_ui->m_flags.show_basic_debug) {
-               if (!has_basic_debug) {
+               if (!has_basic_debug)
                        m_game_ui->m_flags.show_basic_debug = false;
-               }
        } else if (m_game_ui->m_flags.show_minimal_debug) {
-               if (has_basic_debug) {
+               if (has_basic_debug)
                        m_game_ui->m_flags.show_basic_debug = true;
-               }
        }
        if (!has_basic_debug)
                hud->disableBlockBounds();
@@ -1774,10 +1782,10 @@ void Game::updateProfilers(const RunStats &stats, const FpsControl &draw_times,
        }
 
        // Update update graphs
-       g_profiler->graphAdd("Time non-rendering [ms]",
+       g_profiler->graphAdd("Time non-rendering [us]",
                draw_times.busy_time - stats.drawtime);
 
-       g_profiler->graphAdd("Sleep [ms]", draw_times.sleep_time);
+       g_profiler->graphAdd("Sleep [us]", draw_times.sleep_time);
        g_profiler->graphAdd("FPS", 1.0f / dtime);
 }
 
@@ -1810,9 +1818,9 @@ void Game::updateStats(RunStats *stats, const FpsControl &draw_times,
        /* Busytime average and jitter calculation
         */
        jp = &stats->busy_time_jitter;
-       jp->avg = jp->avg + draw_times.busy_time * 0.02;
+       jp->avg = jp->avg + draw_times.getBusyMs() * 0.02;
 
-       jitter = draw_times.busy_time - jp->avg;
+       jitter = draw_times.getBusyMs() - jp->avg;
 
        if (jitter > jp->max)
                jp->max = jitter;
@@ -2204,27 +2212,27 @@ void Game::toggleCinematic()
 
 void Game::toggleBlockBounds()
 {
-       if (client->checkPrivilege("basic_debug")) {
-               enum Hud::BlockBoundsMode newmode = hud->toggleBlockBounds();
-               switch (newmode) {
-                       case Hud::BLOCK_BOUNDS_OFF:
-                               m_game_ui->showTranslatedStatusText("Block bounds hidden");
-                               break;
-                       case Hud::BLOCK_BOUNDS_CURRENT:
-                               m_game_ui->showTranslatedStatusText("Block bounds shown for current block");
-                               break;
-                       case Hud::BLOCK_BOUNDS_NEAR:
-                               m_game_ui->showTranslatedStatusText("Block bounds shown for nearby blocks");
-                               break;
-                       case Hud::BLOCK_BOUNDS_MAX:
-                               m_game_ui->showTranslatedStatusText("Block bounds shown for all blocks");
-                               break;
-                       default:
-                               break;
-               }
-
-       } else {
-               m_game_ui->showTranslatedStatusText("Can't show block bounds (need 'basic_debug' privilege)");
+       LocalPlayer *player = client->getEnv().getLocalPlayer();
+       if (!(client->checkPrivilege("debug") || (player->hud_flags & HUD_FLAG_BASIC_DEBUG))) {
+               m_game_ui->showTranslatedStatusText("Can't show block bounds (disabled by mod or game)");
+               return;
+       }
+       enum Hud::BlockBoundsMode newmode = hud->toggleBlockBounds();
+       switch (newmode) {
+               case Hud::BLOCK_BOUNDS_OFF:
+                       m_game_ui->showTranslatedStatusText("Block bounds hidden");
+                       break;
+               case Hud::BLOCK_BOUNDS_CURRENT:
+                       m_game_ui->showTranslatedStatusText("Block bounds shown for current block");
+                       break;
+               case Hud::BLOCK_BOUNDS_NEAR:
+                       m_game_ui->showTranslatedStatusText("Block bounds shown for nearby blocks");
+                       break;
+               case Hud::BLOCK_BOUNDS_MAX:
+                       m_game_ui->showTranslatedStatusText("Block bounds shown for all blocks");
+                       break;
+               default:
+                       break;
        }
 }
 
@@ -2291,6 +2299,9 @@ void Game::toggleFog()
 
 void Game::toggleDebug()
 {
+       LocalPlayer *player = client->getEnv().getLocalPlayer();
+       bool has_debug = client->checkPrivilege("debug");
+       bool has_basic_debug = has_debug || (player->hud_flags & HUD_FLAG_BASIC_DEBUG);
        // Initial: No debug info
        // 1x toggle: Debug text
        // 2x toggle: Debug text with profiler graph
@@ -2300,26 +2311,23 @@ void Game::toggleDebug()
        // The debug text can be in 2 modes: minimal and basic.
        // * Minimal: Only technical client info that not gameplay-relevant
        // * Basic: Info that might give gameplay advantage, e.g. pos, angle
-       // Basic mode is used when player has "basic_debug" priv,
+       // Basic mode is used when player has the debug HUD flag set,
        // otherwise the Minimal mode is used.
        if (!m_game_ui->m_flags.show_minimal_debug) {
                m_game_ui->m_flags.show_minimal_debug = true;
-               if (client->checkPrivilege("basic_debug")) {
+               if (has_basic_debug)
                        m_game_ui->m_flags.show_basic_debug = true;
-               }
                m_game_ui->m_flags.show_profiler_graph = false;
                draw_control->show_wireframe = false;
                m_game_ui->showTranslatedStatusText("Debug info shown");
        } else if (!m_game_ui->m_flags.show_profiler_graph && !draw_control->show_wireframe) {
-               if (client->checkPrivilege("basic_debug")) {
+               if (has_basic_debug)
                        m_game_ui->m_flags.show_basic_debug = true;
-               }
                m_game_ui->m_flags.show_profiler_graph = true;
                m_game_ui->showTranslatedStatusText("Profiler graph shown");
        } else if (!draw_control->show_wireframe && client->checkPrivilege("debug")) {
-               if (client->checkPrivilege("basic_debug")) {
+               if (has_basic_debug)
                        m_game_ui->m_flags.show_basic_debug = true;
-               }
                m_game_ui->m_flags.show_profiler_graph = false;
                draw_control->show_wireframe = true;
                m_game_ui->showTranslatedStatusText("Wireframe shown");
@@ -2328,7 +2336,7 @@ void Game::toggleDebug()
                m_game_ui->m_flags.show_basic_debug = false;
                m_game_ui->m_flags.show_profiler_graph = false;
                draw_control->show_wireframe = false;
-               if (client->checkPrivilege("debug")) {
+               if (has_debug) {
                        m_game_ui->showTranslatedStatusText("Debug info, profiler graph, and wireframe hidden");
                } else {
                        m_game_ui->showTranslatedStatusText("Debug info and profiler graph hidden");
@@ -2932,7 +2940,7 @@ void Game::updateChat(f32 dtime)
        m_game_ui->updateChatSize();
 }
 
-void Game::updateCamera(u32 busy_time, f32 dtime)
+void Game::updateCamera(f32 dtime)
 {
        LocalPlayer *player = client->getEnv().getLocalPlayer();
 
@@ -2971,7 +2979,7 @@ void Game::updateCamera(u32 busy_time, f32 dtime)
        float tool_reload_ratio = runData.time_from_last_punch / full_punch_interval;
 
        tool_reload_ratio = MYMIN(tool_reload_ratio, 1.0);
-       camera->update(player, dtime, busy_time / 1000.0f, tool_reload_ratio);
+       camera->update(player, dtime, tool_reload_ratio);
        camera->step(dtime);
 
        v3f camera_position = camera->getPosition();
@@ -3034,7 +3042,7 @@ void Game::updateSound(f32 dtime)
 }
 
 
-void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
+void Game::processPlayerInteraction(f32 dtime, bool show_hud)
 {
        LocalPlayer *player = client->getEnv().getLocalPlayer();
 
@@ -3152,7 +3160,9 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
                handlePointingAtNode(pointed, selected_item, hand_item, dtime);
        } else if (pointed.type == POINTEDTHING_OBJECT) {
                v3f player_position  = player->getPosition();
-               handlePointingAtObject(pointed, tool_item, player_position, show_debug);
+               bool basic_debug_allowed = client->checkPrivilege("debug") || (player->hud_flags & HUD_FLAG_BASIC_DEBUG);
+               handlePointingAtObject(pointed, tool_item, player_position,
+                               m_game_ui->m_flags.show_basic_debug && basic_debug_allowed);
        } else if (isKeyDown(KeyType::DIG)) {
                // When button is held down in air, show continuous animation
                runData.punching = true;
@@ -3847,6 +3857,24 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
                );
        }
 
+       /*
+               Damage camera tilt
+       */
+       if (player->hurt_tilt_timer > 0.0f) {
+               player->hurt_tilt_timer -= dtime * 6.0f;
+
+               if (player->hurt_tilt_timer < 0.0f)
+                       player->hurt_tilt_strength = 0.0f;
+       }
+
+       /*
+               Update minimap pos and rotation
+       */
+       if (mapper && m_game_ui->m_flags.show_hud) {
+               mapper->setPos(floatToInt(player->getPosition(), BS));
+               mapper->setAngle(player->getYaw());
+       }
+
        /*
                Get chat messages from client
        */
@@ -3920,11 +3948,11 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
        } while (false);
 
        /*
-               Drawing begins
+               ==================== Drawing begins ====================
        */
-       const video::SColor &skycolor = sky->getSkyColor();
+       const video::SColor skycolor = sky->getSkyColor();
 
-       TimeTaker tt_draw("Draw scene");
+       TimeTaker tt_draw("Draw scene", nullptr, PRECISION_MICRO);
        driver->beginScene(true, true, skycolor);
 
        bool draw_wield_tool = (m_game_ui->m_flags.show_hud &&
@@ -3963,26 +3991,9 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
        }
 
        /*
-               Damage camera tilt
-       */
-       if (player->hurt_tilt_timer > 0.0f) {
-               player->hurt_tilt_timer -= dtime * 6.0f;
-
-               if (player->hurt_tilt_timer < 0.0f)
-                       player->hurt_tilt_strength = 0.0f;
-       }
-
-       /*
-               Update minimap pos and rotation
-       */
-       if (mapper && m_game_ui->m_flags.show_hud) {
-               mapper->setPos(floatToInt(player->getPosition(), BS));
-               mapper->setAngle(player->getYaw());
-       }
-
-       /*
-               End scene
+               ==================== End scene ====================
        */
+#if IRRLICHT_VERSION_MT_REVISION < 5
        if (++m_reset_HW_buffer_counter > 500) {
                /*
                  Periodically remove all mesh HW buffers.
@@ -4004,11 +4015,13 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
                driver->removeAllHardwareBuffers();
                m_reset_HW_buffer_counter = 0;
        }
+#endif
+
        driver->endScene();
 
        stats->drawtime = tt_draw.stop(true);
-       g_profiler->avg("Game::updateFrame(): draw scene [ms]", stats->drawtime);
-       g_profiler->graphAdd("Update frame [ms]", tt_update.stop(true));
+       g_profiler->graphAdd("Draw scene [us]", stats->drawtime);
+       g_profiler->avg("Game::updateFrame(): update frame [ms]", tt_update.stop(true));
 }
 
 /* Log times and stuff for visualization */
@@ -4030,7 +4043,12 @@ void Game::updateShadows()
 
        float in_timeofday = fmod(runData.time_of_day_smooth, 1.0f);
 
-       float timeoftheday = fmod(getWickedTimeOfDay(in_timeofday) + 0.75f, 0.5f) + 0.25f;
+       float timeoftheday = getWickedTimeOfDay(in_timeofday);
+       bool is_day = timeoftheday > 0.25 && timeoftheday < 0.75;
+       bool is_shadow_visible = is_day ? sky->getSunVisible() : sky->getMoonVisible();
+       shadow->setShadowIntensity(is_shadow_visible ? client->getEnv().getLocalPlayer()->getLighting().shadow_intensity : 0.0f);
+
+       timeoftheday = fmod(timeoftheday + 0.75f, 0.5f) + 0.25f;
        const float offset_constant = 10000.0f;
 
        v3f light(0.0f, 0.0f, -1.0f);
@@ -4052,47 +4070,46 @@ void Game::updateShadows()
  Misc
  ****************************************************************************/
 
-/* On some computers framerate doesn't seem to be automatically limited
- */
-inline void Game::limitFps(FpsControl *fps_timings, f32 *dtime)
+void FpsControl::reset()
 {
-       // not using getRealTime is necessary for wine
-       device->getTimer()->tick(); // Maker sure device time is up-to-date
-       u32 time = device->getTimer()->getTime();
-       u32 last_time = fps_timings->last_time;
-
-       if (time > last_time)  // Make sure time hasn't overflowed
-               fps_timings->busy_time = time - last_time;
-       else
-               fps_timings->busy_time = 0;
+       last_time = porting::getTimeUs();
+}
 
-       u32 frametime_min = 1000 / (
+/*
+ * On some computers framerate doesn't seem to be automatically limited
+ */
+void FpsControl::limit(IrrlichtDevice *device, f32 *dtime)
+{
+       const u64 frametime_min = 1000000.0f / (
                device->isWindowFocused() && !g_menumgr.pausesGame()
                        ? g_settings->getFloat("fps_max")
                        : g_settings->getFloat("fps_max_unfocused"));
 
-       if (fps_timings->busy_time < frametime_min) {
-               fps_timings->sleep_time = frametime_min - fps_timings->busy_time;
-               device->sleep(fps_timings->sleep_time);
+       u64 time = porting::getTimeUs();
+
+       if (time > last_time) // Make sure time hasn't overflowed
+               busy_time = time - last_time;
+       else
+               busy_time = 0;
+
+       if (busy_time < frametime_min) {
+               sleep_time = frametime_min - busy_time;
+               if (sleep_time > 1000)
+                       sleep_ms(sleep_time / 1000);
        } else {
-               fps_timings->sleep_time = 0;
+               sleep_time = 0;
        }
 
-       /* Get the new value of the device timer. Note that device->sleep() may
-        * not sleep for the entire requested time as sleep may be interrupted and
-        * therefore it is arguably more accurate to get the new time from the
-        * device rather than calculating it by adding sleep_time to time.
-        */
-
-       device->getTimer()->tick(); // Update device timer
-       time = device->getTimer()->getTime();
+       // Read the timer again to accurately determine how long we actually slept,
+       // rather than calculating it by adding sleep_time to time.
+       time = porting::getTimeUs();
 
-       if (time > last_time)  // Make sure last_time hasn't overflowed
-               *dtime = (time - last_time) / 1000.0;
+       if (time > last_time) // Make sure last_time hasn't overflowed
+               *dtime = (time - last_time) / 1000000.0f;
        else
                *dtime = 0;
 
-       fps_timings->last_time = time;
+       last_time = time;
 }
 
 void Game::showOverlayMessage(const char *msg, float dtime, int percent, bool draw_clouds)