X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;ds=sidebyside;f=src%2Fclient%2Fgame.cpp;h=edd0039e9240c259f7254b911164bf94dc6842fa;hb=d6be6682ec69706b765ab51863bcd5805a7cbd7d;hp=b4926d9bf6a80b1d3cd99b36f677f22e6ecba60f;hpb=1d04903c1973591e795d3275b900d76d7cb7877a;p=minetest.git diff --git a/src/client/game.cpp b/src/client/game.cpp index b4926d9bf..edd0039e9 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -71,6 +71,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "version.h" #include "script/scripting_client.h" #include "hud.h" +#include "clientdynamicinfo.h" #if USE_SOUND #include "client/sound_openal.h" @@ -239,7 +240,7 @@ class PlayerInventoryFormSource: public IFormSource Client *m_client; }; -class NodeDugEvent: public MtEvent +class NodeDugEvent : public MtEvent { public: v3s16 p; @@ -249,16 +250,14 @@ class NodeDugEvent: public MtEvent p(p), n(n) {} - MtEvent::Type getType() const - { - return MtEvent::NODE_DUG; - } + Type getType() const { return NODE_DUG; } }; class SoundMaker { ISoundManager *m_sound; const NodeDefManager *m_ndef; + public: bool makes_footstep_sound; float m_player_step_timer; @@ -266,6 +265,8 @@ class SoundMaker SimpleSoundSpec m_player_step_sound; SimpleSoundSpec m_player_leftpunch_sound; + // Second sound made on left punch, currently used for item 'use' sound + SimpleSoundSpec m_player_leftpunch_sound2; SimpleSoundSpec m_player_rightpunch_sound; SoundMaker(ISoundManager *sound, const NodeDefManager *ndef): @@ -316,6 +317,7 @@ class SoundMaker { SoundMaker *sm = (SoundMaker *)data; sm->m_sound->playSound(sm->m_player_leftpunch_sound); + sm->m_sound->playSound(sm->m_player_leftpunch_sound2); } static void cameraPunchRight(MtEvent *e, void *data) @@ -405,6 +407,7 @@ typedef s32 SamplerLayer_t; class GameGlobalShaderConstantSetter : public IShaderConstantSetter { Sky *m_sky; + Client *m_client; bool *m_force_fog_off; f32 *m_fog_range; bool m_fog_enabled; @@ -412,6 +415,8 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter CachedPixelShaderSetting m_fog_distance; CachedVertexShaderSetting m_animation_timer_vertex; CachedPixelShaderSetting m_animation_timer_pixel; + CachedVertexShaderSetting m_animation_timer_delta_vertex; + CachedPixelShaderSetting m_animation_timer_delta_pixel; CachedPixelShaderSetting m_day_light; CachedPixelShaderSetting m_star_color; CachedPixelShaderSetting m_eye_position_pixel; @@ -419,16 +424,36 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter CachedPixelShaderSetting m_minimap_yaw; CachedPixelShaderSetting m_camera_offset_pixel; CachedPixelShaderSetting m_camera_offset_vertex; - CachedPixelShaderSetting m_base_texture; - CachedPixelShaderSetting m_normal_texture; - CachedPixelShaderSetting m_texture_flags; - Client *m_client; + CachedPixelShaderSetting m_texture0; + CachedPixelShaderSetting m_texture1; + CachedPixelShaderSetting m_texture2; + CachedPixelShaderSetting m_texture3; + CachedPixelShaderSetting m_texel_size0; + std::array m_texel_size0_values; + CachedStructPixelShaderSetting m_exposure_params_pixel; + float m_user_exposure_compensation; + bool m_bloom_enabled; + CachedPixelShaderSetting m_bloom_intensity_pixel; + float m_bloom_intensity; + CachedPixelShaderSetting m_bloom_strength_pixel; + float m_bloom_strength; + CachedPixelShaderSetting m_bloom_radius_pixel; + float m_bloom_radius; + CachedPixelShaderSetting m_saturation_pixel; public: void onSettingsChange(const std::string &name) { if (name == "enable_fog") m_fog_enabled = g_settings->getBool("enable_fog"); + if (name == "exposure_compensation") + m_user_exposure_compensation = g_settings->getFloat("exposure_compensation", -1.0f, 1.0f); + if (name == "bloom_intensity") + m_bloom_intensity = g_settings->getFloat("bloom_intensity", 0.01f, 1.0f); + if (name == "bloom_strength_factor") + m_bloom_strength = RenderingEngine::BASE_BLOOM_STRENGTH * g_settings->getFloat("bloom_strength_factor", 0.1f, 10.0f); + if (name == "bloom_radius") + m_bloom_radius = g_settings->getFloat("bloom_radius", 0.1f, 8.0f); } static void settingsCallback(const std::string &name, void *userdata) @@ -441,12 +466,15 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off, f32 *fog_range, Client *client) : m_sky(sky), + m_client(client), m_force_fog_off(force_fog_off), m_fog_range(fog_range), m_sky_bg_color("skyBgColor"), m_fog_distance("fogDistance"), m_animation_timer_vertex("animationTimer"), m_animation_timer_pixel("animationTimer"), + m_animation_timer_delta_vertex("animationTimerDelta"), + m_animation_timer_delta_pixel("animationTimerDelta"), m_day_light("dayLight"), m_star_color("starColor"), m_eye_position_pixel("eyePosition"), @@ -454,13 +482,33 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter 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"), - m_client(client) + m_texture0("texture0"), + m_texture1("texture1"), + m_texture2("texture2"), + m_texture3("texture3"), + m_texel_size0("texelSize0"), + m_exposure_params_pixel("exposureParams", + std::array { + "luminanceMin", "luminanceMax", "exposureCorrection", + "speedDarkBright", "speedBrightDark", "centerWeightPower", "compensationFactor" + }), + m_bloom_intensity_pixel("bloomIntensity"), + m_bloom_strength_pixel("bloomStrength"), + m_bloom_radius_pixel("bloomRadius"), + m_saturation_pixel("saturation") { g_settings->registerChangedCallback("enable_fog", settingsCallback, this); + g_settings->registerChangedCallback("exposure_compensation", settingsCallback, this); + g_settings->registerChangedCallback("bloom_intensity", settingsCallback, this); + g_settings->registerChangedCallback("bloom_strength_factor", settingsCallback, this); + g_settings->registerChangedCallback("bloom_radius", settingsCallback, this); + g_settings->registerChangedCallback("saturation", settingsCallback, this); m_fog_enabled = g_settings->getBool("enable_fog"); + m_user_exposure_compensation = g_settings->getFloat("exposure_compensation", -1.0f, 1.0f); + m_bloom_enabled = g_settings->getBool("enable_bloom"); + m_bloom_intensity = g_settings->getFloat("bloom_intensity", 0.01f, 1.0f); + m_bloom_strength = RenderingEngine::BASE_BLOOM_STRENGTH * g_settings->getFloat("bloom_strength_factor", 0.1f, 10.0f); + m_bloom_radius = g_settings->getFloat("bloom_radius", 0.1f, 8.0f); } ~GameGlobalShaderConstantSetter() @@ -507,6 +555,10 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter m_animation_timer_vertex.set(&animation_timer_f, services); m_animation_timer_pixel.set(&animation_timer_f, services); + float animation_timer_delta_f = (float)m_client->getEnv().getFrameTimeDelta() / 100000.f; + m_animation_timer_delta_vertex.set(&animation_timer_delta_f, services); + m_animation_timer_delta_pixel.set(&animation_timer_delta_f, services); + float eye_position_array[3]; v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition(); epos.getAs3Values(eye_position_array); @@ -526,12 +578,51 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter 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; - m_base_texture.set(&base_tex, services); - m_normal_texture.set(&normal_tex, services); - m_texture_flags.set(&flags_tex, services); + SamplerLayer_t tex_id; + tex_id = 0; + m_texture0.set(&tex_id, services); + tex_id = 1; + m_texture1.set(&tex_id, services); + tex_id = 2; + m_texture2.set(&tex_id, services); + tex_id = 3; + m_texture3.set(&tex_id, services); + + m_texel_size0.set(m_texel_size0_values.data(), services); + + const AutoExposure &exposure_params = m_client->getEnv().getLocalPlayer()->getLighting().exposure; + std::array exposure_buffer = { + std::pow(2.0f, exposure_params.luminance_min), + std::pow(2.0f, exposure_params.luminance_max), + exposure_params.exposure_correction, + exposure_params.speed_dark_bright, + exposure_params.speed_bright_dark, + exposure_params.center_weight_power, + powf(2.f, m_user_exposure_compensation) + }; + m_exposure_params_pixel.set(exposure_buffer.data(), services); + + if (m_bloom_enabled) { + m_bloom_intensity_pixel.set(&m_bloom_intensity, services); + m_bloom_radius_pixel.set(&m_bloom_radius, services); + m_bloom_strength_pixel.set(&m_bloom_strength, services); + } + float saturation = m_client->getEnv().getLocalPlayer()->getLighting().saturation; + m_saturation_pixel.set(&saturation, services); + } + + void onSetMaterial(const video::SMaterial &material) + { + video::ITexture *texture = material.getTexture(0); + if (texture) { + core::dimension2du size = texture->getSize(); + m_texel_size0_values[0] = 1.f / size.Width; + m_texel_size0_values[1] = 1.f / size.Height; + } + else { + m_texel_size0_values[0] = 0.f; + m_texel_size0_values[1] = 0.f; + } } }; @@ -619,9 +710,13 @@ struct GameRunData { float time_from_last_punch; ClientActiveObject *selected_object; - float jump_timer; + float jump_timer_up; // from key up until key down + float jump_timer_down; // since last key down + float jump_timer_down_before; // from key down until key down again + float damage_flash; float update_draw_list_timer; + float touch_blocks_timer; f32 fog_range; @@ -723,7 +818,7 @@ class Game { void updateCameraDirection(CameraOrientation *cam, float dtime); void updateCameraOrientation(CameraOrientation *cam, float dtime); void updatePlayerControl(const CameraOrientation &cam); - void step(f32 *dtime); + void step(f32 dtime); void processClientEvents(CameraOrientation *cam); void updateCamera(f32 dtime); void updateSound(f32 dtime); @@ -818,17 +913,21 @@ class Game { void updateChat(f32 dtime); bool nodePlacement(const ItemDefinition &selected_def, const ItemStack &selected_item, - const v3s16 &nodepos, const v3s16 &neighbourpos, const PointedThing &pointed, + const v3s16 &nodepos, const v3s16 &neighborpos, const PointedThing &pointed, const NodeMetadata *meta); static const ClientEventHandler clientEventHandler[CLIENTEVENT_MAX]; f32 getSensitivityScaleFactor() const; + ClientDynamicInfo getCurrentDynamicInfo() const; InputHandler *input = nullptr; Client *client = nullptr; Server *server = nullptr; + ClientDynamicInfo client_display_info{}; + float dynamic_info_send_timer = 0; + IWritableTextureSource *texture_src = nullptr; IWritableShaderSource *shader_src = nullptr; @@ -910,12 +1009,16 @@ class Game { bool m_does_lost_focus_pause_game = false; -#if IRRLICHT_VERSION_MT_REVISION < 5 - int m_reset_HW_buffer_counter = 0; -#endif + // if true, (almost) the whole game is paused + // this happens in pause menu in singleplayer + bool m_is_paused = false; #ifdef HAVE_TOUCHSCREENGUI bool m_cache_hold_aux1; + bool m_touch_use_crosshair; + inline bool isNoCrosshairAllowed() { + return !m_touch_use_crosshair && camera->getCameraMode() == CAMERA_MODE_FIRST; + } #endif #ifdef __ANDROID__ bool m_android_chat_open; @@ -1047,6 +1150,10 @@ bool Game::startup(bool *kill, m_invert_mouse = g_settings->getBool("invert_mouse"); m_first_loop_after_window_activation = true; +#ifdef HAVE_TOUCHSCREENGUI + m_touch_use_crosshair = g_settings->getBool("touch_use_crosshair"); +#endif + g_client_translations->clear(); // address can change if simple_singleplayer_mode @@ -1085,31 +1192,44 @@ void Game::run() && client->checkPrivilege("fast"); #endif - irr::core::dimension2d previous_screen_size(g_settings->getU16("screen_w"), + v2u32 previous_screen_size(g_settings->getU16("screen_w"), g_settings->getU16("screen_h")); while (m_rendering_engine->run() && !(*kill || g_gamecallback->shutdown_requested || (server && server->isShutdownRequested()))) { - const irr::core::dimension2d ¤t_screen_size = - m_rendering_engine->get_video_driver()->getScreenSize(); + // Calculate dtime = + // m_rendering_engine->run() from this iteration + // + Sleep time until the wanted FPS are reached + draw_times.limit(device, &dtime); + + const auto current_dynamic_info = getCurrentDynamicInfo(); + if (!current_dynamic_info.equal(client_display_info)) { + client_display_info = current_dynamic_info; + dynamic_info_send_timer = 0.2f; + } + + if (dynamic_info_send_timer > 0) { + dynamic_info_send_timer -= dtime; + if (dynamic_info_send_timer <= 0) { + client->sendUpdateClientInfo(current_dynamic_info); + } + } + + const auto ¤t_screen_size = current_dynamic_info.render_target_size; + // Verify if window size has changed and save it if it's the case // Ensure evaluating settings->getBool after verifying screensize // First condition is cheaper if (previous_screen_size != current_screen_size && current_screen_size != irr::core::dimension2d(0,0) && g_settings->getBool("autosave_screensize")) { - g_settings->setU16("screen_w", current_screen_size.Width); - g_settings->setU16("screen_h", current_screen_size.Height); + g_settings->setU16("screen_w", current_screen_size.X); + g_settings->setU16("screen_h", current_screen_size.Y); previous_screen_size = current_screen_size; } - // Calculate dtime = - // m_rendering_engine->run() from this iteration - // + Sleep time until the wanted FPS are reached - draw_times.limit(device, &dtime); - // Prepare render data for next iteration updateStats(&stats, draw_times, dtime); @@ -1123,8 +1243,6 @@ void Game::run() processQueues(); m_game_ui->clearInfoText(); - hud->resizeHotbar(); - updateProfilers(stats, draw_times, dtime); processUserInput(dtime); @@ -1135,7 +1253,21 @@ void Game::run() cam_view.camera_pitch += (cam_view_target.camera_pitch - cam_view.camera_pitch) * m_cache_cam_smoothing; updatePlayerControl(cam_view); - step(&dtime); + + { + bool was_paused = m_is_paused; + m_is_paused = simple_singleplayer_mode && g_menumgr.pausesGame(); + if (m_is_paused) + dtime = 0.0f; + + if (!was_paused && m_is_paused) + pauseAnimation(); + else if (was_paused && !m_is_paused) + resumeAnimation(); + } + + if (!m_is_paused) + step(dtime); processClientEvents(&cam_view_target); updateDebugState(); updateCamera(dtime); @@ -1157,11 +1289,7 @@ void Game::run() void Game::shutdown() { m_rendering_engine->finalize(); -#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 8 - if (g_settings->get("3d_mode") == "pageflip") { - driver->setRenderTarget(irr::video::ERT_STEREO_BOTH_BUFFERS); - } -#endif + auto formspec = m_game_ui->getFormspecGUI(); if (formspec) formspec->quitMenu(); @@ -1356,6 +1484,11 @@ bool Game::createClient(const GameStartData &start_data) if (client->modsLoaded()) client->getScript()->on_camera_ready(camera); client->setCamera(camera); +#ifdef HAVE_TOUCHSCREENGUI + if (g_touchscreengui) { + g_touchscreengui->setUseCrosshair(!isNoCrosshairAllowed()); + } +#endif /* Clouds */ @@ -1875,8 +2008,10 @@ void Game::processUserInput(f32 dtime) #endif // Increase timer for double tap of "keymap_jump" - if (m_cache_doubletap_jump && runData.jump_timer <= 0.2f) - runData.jump_timer += dtime; + if (m_cache_doubletap_jump && runData.jump_timer_up <= 0.2f) + runData.jump_timer_up += dtime; + if (m_cache_doubletap_jump && runData.jump_timer_down <= 0.4f) + runData.jump_timer_down += dtime; processKeyInput(); processItemSelection(&runData.new_playeritem); @@ -1968,7 +2103,7 @@ void Game::processKeyInput() } else if (wasKeyDown(KeyType::MINIMAP)) { toggleMinimap(isKeyDown(KeyType::SNEAK)); } else if (wasKeyDown(KeyType::TOGGLE_CHAT)) { - m_game_ui->toggleChat(); + m_game_ui->toggleChat(client); } else if (wasKeyDown(KeyType::TOGGLE_FOG)) { toggleFog(); } else if (wasKeyDown(KeyType::TOGGLE_UPDATE_CAMERA)) { @@ -1997,7 +2132,7 @@ void Game::processKeyInput() if (!isKeyDown(KeyType::JUMP) && runData.reset_jump_timer) { runData.reset_jump_timer = false; - runData.jump_timer = 0.0f; + runData.jump_timer_up = 0.0f; } if (quicktune->hasMessage()) { @@ -2012,7 +2147,6 @@ void Game::processItemSelection(u16 *new_playeritem) /* Item selection using mouse wheel */ *new_playeritem = player->getWieldIndex(); - s32 wheel = input->getMouseWheel(); u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE - 1, player->hud_hotbar_itemcount - 1); @@ -2039,6 +2173,9 @@ void Game::processItemSelection(u16 *new_playeritem) break; } } + + // Clamp selection again in case it wasn't changed but max_item was + *new_playeritem = MYMIN(*new_playeritem, max_item); } @@ -2138,7 +2275,14 @@ void Game::toggleFreeMove() void Game::toggleFreeMoveAlt() { - if (m_cache_doubletap_jump && runData.jump_timer < 0.2f) + if (!runData.reset_jump_timer) { + runData.jump_timer_down_before = runData.jump_timer_down; + runData.jump_timer_down = 0.0f; + } + + // key down (0.2 s max.), then key up (0.2 s max.), then key down + if (m_cache_doubletap_jump && runData.jump_timer_up < 0.2f && + runData.jump_timer_down_before < 0.4f) // 0.2 + 0.2 toggleFreeMove(); runData.reset_jump_timer = true; @@ -2405,6 +2549,13 @@ void Game::checkZoomEnabled() void Game::updateCameraDirection(CameraOrientation *cam, float dtime) { +#ifndef __ANDROID__ + if (isMenuActive()) + device->getCursorControl()->setRelativeMode(false); + else + device->getCursorControl()->setRelativeMode(true); +#endif + if ((device->isWindowActive() && device->isWindowFocused() && !isMenuActive()) || input->isRandom()) { @@ -2450,6 +2601,19 @@ f32 Game::getSensitivityScaleFactor() const return tan(fov_y / 2.0f) * 1.3763818698f; } +ClientDynamicInfo Game::getCurrentDynamicInfo() const +{ + v2u32 screen_size = RenderingEngine::getWindowSize(); + f32 density = RenderingEngine::getDisplayDensity(); + f32 gui_scaling = g_settings->getFloat("gui_scaling") * density; + f32 hud_scaling = g_settings->getFloat("hud_scaling") * density; + + return { + screen_size, gui_scaling, hud_scaling, + ClientDynamicInfo::calculateMaxFSSize(screen_size) + }; +} + void Game::updateCameraOrientation(CameraOrientation *cam, float dtime) { #ifdef HAVE_TOUCHSCREENGUI @@ -2535,22 +2699,12 @@ void Game::updatePlayerControl(const CameraOrientation &cam) } -inline void Game::step(f32 *dtime) +inline void Game::step(f32 dtime) { - bool can_be_and_is_paused = - (simple_singleplayer_mode && g_menumgr.pausesGame()); + if (server) + server->step(dtime); - if (can_be_and_is_paused) { // This is for a singleplayer server - *dtime = 0; // No time passes - } else { - if (simple_singleplayer_mode && !paused_animated_nodes.empty()) - resumeAnimation(); - - if (server) - server->step(*dtime); - - client->step(*dtime); - } + client->step(dtime); } static void pauseNodeAnimation(PausedNodesList &paused, scene::ISceneNode *node) { @@ -2853,6 +3007,9 @@ void Game::handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam) ); } + // Orbit Tilt: + sky->setBodyOrbitTilt(event->set_sky->body_orbit_tilt); + delete event->set_sky; } @@ -2973,6 +3130,11 @@ void Game::updateCamera(f32 dtime) camera->toggleCameraMode(); +#ifdef HAVE_TOUCHSCREENGUI + if (g_touchscreengui) + g_touchscreengui->setUseCrosshair(!isNoCrosshairAllowed()); +#endif + // Make the player visible depending on camera mode. playercao->updateMeshCulling(); playercao->setChildrenVisible(camera->getCameraMode() > CAMERA_MODE_FIRST); @@ -3083,16 +3245,14 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud) shootline.end = shootline.start + camera_direction * BS * d; #ifdef HAVE_TOUCHSCREENGUI - - if ((g_settings->getBool("touchtarget")) && (g_touchscreengui)) { + if (g_touchscreengui && isNoCrosshairAllowed()) { shootline = g_touchscreengui->getShootline(); // Scale shootline to the acual distance the player can reach - shootline.end = shootline.start - + shootline.getVector().normalize() * BS * d; + shootline.end = shootline.start + + shootline.getVector().normalize() * BS * d; shootline.start += intToFloat(camera_offset, BS); shootline.end += intToFloat(camera_offset, BS); } - #endif PointedThing pointed = updatePointedThing(shootline, @@ -3150,7 +3310,9 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud) runData.punching = false; - soundmaker->m_player_leftpunch_sound.name.clear(); + soundmaker->m_player_leftpunch_sound = SimpleSoundSpec(); + soundmaker->m_player_leftpunch_sound2 = pointed.type != POINTEDTHING_NOTHING ? + selected_def.sound_use : selected_def.sound_use_air; // Prepare for repeating, unless we're not supposed to if (isKeyDown(KeyType::PLACE) && !g_settings->getBool("safe_dig_and_place")) @@ -3206,7 +3368,7 @@ PointedThing Game::updatePointedThing( { std::vector *selectionboxes = hud->getSelectionBoxes(); selectionboxes->clear(); - hud->setSelectedFaceNormal(v3f(0.0, 0.0, 0.0)); + hud->setSelectedFaceNormal(v3f()); static thread_local const bool show_entity_selectionbox = g_settings->getBool( "show_entity_selectionbox"); @@ -3230,7 +3392,13 @@ PointedThing Game::updatePointedThing( v3f pos = runData.selected_object->getPosition(); selectionboxes->push_back(aabb3f(selection_box)); hud->setSelectionPos(pos, camera_offset); + GenericCAO* gcao = dynamic_cast(runData.selected_object); + if (gcao != nullptr && gcao->getProperties().rotate_selectionbox) + hud->setSelectionRotation(gcao->getSceneNode()->getAbsoluteTransformation().getRotationDegrees()); + else + hud->setSelectionRotation(v3f()); } + hud->setSelectedFaceNormal(result.raw_intersection_normal); } else if (result.type == POINTEDTHING_NODE) { // Update selection boxes MapNode n = map.getNode(result.node_undersurface); @@ -3248,10 +3416,8 @@ PointedThing Game::updatePointedThing( } hud->setSelectionPos(intToFloat(result.node_undersurface, BS), camera_offset); - hud->setSelectedFaceNormal(v3f( - result.intersection_normal.X, - result.intersection_normal.Y, - result.intersection_normal.Z)); + hud->setSelectionRotation(v3f()); + hud->setSelectedFaceNormal(result.intersection_normal); } // Update selection mesh light level and vertex colors @@ -3305,7 +3471,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed, const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime) { v3s16 nodepos = pointed.node_undersurface; - v3s16 neighbourpos = pointed.node_abovesurface; + v3s16 neighborpos = pointed.node_abovesurface; /* Check information text of node @@ -3349,7 +3515,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed, // 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, + bool placed = nodePlacement(def, selected_item, nodepos, neighborpos, pointed, meta); if (placed && client->modsLoaded()) @@ -3358,7 +3524,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed, } bool Game::nodePlacement(const ItemDefinition &selected_def, - const ItemStack &selected_item, const v3s16 &nodepos, const v3s16 &neighbourpos, + const ItemStack &selected_item, const v3s16 &nodepos, const v3s16 &neighborpos, const PointedThing &pointed, const NodeMetadata *meta) { const auto &prediction = selected_def.node_placement_prediction; @@ -3408,7 +3574,7 @@ bool Game::nodePlacement(const ItemDefinition &selected_def, verbosestream << "Node placement prediction for " << selected_def.name << " is " << prediction << std::endl; - v3s16 p = neighbourpos; + v3s16 p = neighborpos; // Place inside node itself if buildable_to MapNode n_under = map.getNode(nodepos, &is_valid_position); @@ -3442,24 +3608,23 @@ bool Game::nodePlacement(const ItemDefinition &selected_def, const ContentFeatures &predicted_f = nodedef->get(id); - // Predict param2 for facedir and wallmounted nodes - // Compare core.item_place_node() for what the server does - u8 param2 = 0; + // Compare core.item_place_node() for what the server does with param2 + MapNode predicted_node(id, 0, 0); const u8 place_param2 = selected_def.place_param2; if (place_param2) { - param2 = place_param2; + predicted_node.setParam2(place_param2); } else if (predicted_f.param_type_2 == CPT2_WALLMOUNTED || predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED) { - v3s16 dir = nodepos - neighbourpos; + v3s16 dir = nodepos - neighborpos; if (abs(dir.Y) > MYMAX(abs(dir.X), abs(dir.Z))) { - param2 = dir.Y < 0 ? 1 : 0; + predicted_node.setParam2(dir.Y < 0 ? 1 : 0); } else if (abs(dir.X) > abs(dir.Z)) { - param2 = dir.X < 0 ? 3 : 2; + predicted_node.setParam2(dir.X < 0 ? 3 : 2); } else { - param2 = dir.Z < 0 ? 5 : 4; + predicted_node.setParam2(dir.Z < 0 ? 5 : 4); } } else if (predicted_f.param_type_2 == CPT2_FACEDIR || predicted_f.param_type_2 == CPT2_COLORED_FACEDIR || @@ -3468,29 +3633,36 @@ bool Game::nodePlacement(const ItemDefinition &selected_def, v3s16 dir = nodepos - floatToInt(client->getEnv().getLocalPlayer()->getPosition(), BS); if (abs(dir.X) > abs(dir.Z)) { - param2 = dir.X < 0 ? 3 : 1; + predicted_node.setParam2(dir.X < 0 ? 3 : 1); } else { - param2 = dir.Z < 0 ? 2 : 0; + predicted_node.setParam2(dir.Z < 0 ? 2 : 0); } } // Check attachment if node is in group attached_node - if (itemgroup_get(predicted_f.groups, "attached_node") != 0) { - const 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), - }; + int an = itemgroup_get(predicted_f.groups, "attached_node"); + if (an != 0) { v3s16 pp; - if (predicted_f.param_type_2 == CPT2_WALLMOUNTED || - predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED) - pp = p + wallmounted_dirs[param2]; - else + if (an == 3) { pp = p + v3s16(0, -1, 0); + } else if (an == 4) { + pp = p + v3s16(0, 1, 0); + } else if (an == 2) { + if (predicted_f.param_type_2 == CPT2_FACEDIR || + predicted_f.param_type_2 == CPT2_COLORED_FACEDIR || + predicted_f.param_type_2 == CPT2_4DIR || + predicted_f.param_type_2 == CPT2_COLORED_4DIR) { + pp = p + facedir_dirs[predicted_node.getFaceDir(nodedef)]; + } else { + pp = p; + } + } else if (predicted_f.param_type_2 == CPT2_WALLMOUNTED || + predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED) { + pp = p + predicted_node.getWallMountedDir(nodedef); + } else { + pp = p + v3s16(0, -1, 0); + } if (!nodedef->get(map.getNode(pp)).walkable) { soundmaker->m_player_rightpunch_sound = selected_def.sound_place_failed; @@ -3510,36 +3682,34 @@ bool Game::nodePlacement(const ItemDefinition &selected_def, if (!indexstr.empty()) { s32 index = mystoi(indexstr); if (predicted_f.param_type_2 == CPT2_COLOR) { - param2 = index; + predicted_node.setParam2(index); } else if (predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED) { // param2 = pure palette index + other - param2 = (index & 0xf8) | (param2 & 0x07); + predicted_node.setParam2((index & 0xf8) | (predicted_node.getParam2() & 0x07)); } else if (predicted_f.param_type_2 == CPT2_COLORED_FACEDIR) { // param2 = pure palette index + other - param2 = (index & 0xe0) | (param2 & 0x1f); + predicted_node.setParam2((index & 0xe0) | (predicted_node.getParam2() & 0x1f)); } else if (predicted_f.param_type_2 == CPT2_COLORED_4DIR) { // param2 = pure palette index + other - param2 = (index & 0xfc) | (param2 & 0x03); + predicted_node.setParam2((index & 0xfc) | (predicted_node.getParam2() & 0x03)); } } } // Add node to client map - MapNode n(id, 0, param2); - try { LocalPlayer *player = client->getEnv().getLocalPlayer(); - // Dont place node when player would be inside new node + // Don't 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 || + if (!predicted_f.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))) { + (predicted_f.walkable && + neighborpos != player->getStandingNodePos() + v3s16(0, 1, 0) && + neighborpos != player->getStandingNodePos() + v3s16(0, 2, 0))) { // This triggers the required mesh update too - client->addNode(p, n); + client->addNode(p, predicted_node); // Report to server client->interact(INTERACT_PLACE, pointed); // A node is predicted, also play a sound @@ -3616,18 +3786,19 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos, // See also: serverpackethandle.cpp, action == 2 LocalPlayer *player = client->getEnv().getLocalPlayer(); ClientMap &map = client->getEnv().getClientMap(); - MapNode n = client->getEnv().getClientMap().getNode(nodepos); + MapNode n = map.getNode(nodepos); + const auto &features = nodedef_manager->get(n); // NOTE: Similar piece of code exists on the server side for // cheat detection. // Get digging parameters - DigParams params = getDigParams(nodedef_manager->get(n).groups, + DigParams params = getDigParams(features.groups, &selected_item.getToolCapabilities(itemdef_manager), selected_item.wear); // If can't dig, try hand if (!params.diggable) { - params = getDigParams(nodedef_manager->get(n).groups, + params = getDigParams(features.groups, &hand_item.getToolCapabilities(itemdef_manager)); } @@ -3638,7 +3809,6 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos, runData.dig_time_complete = params.time; if (m_cache_enable_particles) { - const ContentFeatures &features = client->getNodeDefManager()->get(n); client->getParticleManager()->addNodeParticle(client, player, nodepos, n, features); } @@ -3649,6 +3819,7 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos, runData.dig_instantly = runData.dig_time_complete == 0; if (client->modsLoaded() && client->getScript()->on_punchnode(nodepos, n)) return; + client->interact(INTERACT_START_DIGGING, pointed); runData.digging = true; runData.btn_down_for_dig = true; @@ -3663,7 +3834,7 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos, runData.dig_index = crack_animation_length; } - SimpleSoundSpec sound_dig = nodedef_manager->get(n).sound_dig; + const auto &sound_dig = features.sound_dig; if (sound_dig.exists() && params.diggable) { if (sound_dig.name == "__group") { @@ -3681,8 +3852,6 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos, // Don't show cracks if not diggable if (runData.dig_time_complete >= 100000.0) { } else if (runData.dig_index < crack_animation_length) { - //TimeTaker timer("client.setTempMod"); - //infostream<<"dig_index="<setCrack(runData.dig_index, nodepos); } else { infostream << "Digging completed" << std::endl; @@ -3704,38 +3873,31 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos, else if (runData.dig_instantly) runData.nodig_delay_timer = 0.15; - bool is_valid_position; - MapNode wasnode = map.getNode(nodepos, &is_valid_position); - if (is_valid_position) { - if (client->modsLoaded() && - client->getScript()->on_dignode(nodepos, wasnode)) { - return; - } + if (client->modsLoaded() && + client->getScript()->on_dignode(nodepos, n)) { + return; + } - const ContentFeatures &f = client->ndef()->get(wasnode); - if (f.node_dig_prediction == "air") { - client->removeNode(nodepos); - } else if (!f.node_dig_prediction.empty()) { - content_t id; - bool found = client->ndef()->getId(f.node_dig_prediction, id); - if (found) - client->addNode(nodepos, id, true); - } - // implicit else: no prediction + if (features.node_dig_prediction == "air") { + client->removeNode(nodepos); + } else if (!features.node_dig_prediction.empty()) { + content_t id; + bool found = nodedef_manager->getId(features.node_dig_prediction, id); + if (found) + client->addNode(nodepos, id, true); } + // implicit else: no prediction client->interact(INTERACT_DIGGING_COMPLETED, pointed); if (m_cache_enable_particles) { - const ContentFeatures &features = - client->getNodeDefManager()->get(wasnode); client->getParticleManager()->addDiggingParticles(client, - player, nodepos, wasnode, features); + player, nodepos, n, features); } // Send event to trigger sound - client->getEventManager()->put(new NodeDugEvent(nodepos, wasnode)); + client->getEventManager()->put(new NodeDugEvent(nodepos, n)); } if (runData.dig_time_complete < 100000.0) { @@ -3758,7 +3920,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, Frame time */ - client->getEnv().updateFrameTime(); + client->getEnv().updateFrameTime(m_is_paused); /* Fog range @@ -3921,6 +4083,9 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, changed much */ runData.update_draw_list_timer += dtime; + runData.touch_blocks_timer += dtime; + + bool draw_list_updated = false; float update_draw_list_delta = 0.2f; @@ -3932,6 +4097,12 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, runData.update_draw_list_timer = 0; client->getEnv().getClientMap().updateDrawList(); runData.update_draw_list_last_cam_dir = camera_direction; + draw_list_updated = true; + } + + if (runData.touch_blocks_timer > update_draw_list_delta && !draw_list_updated) { + client->getEnv().getClientMap().touchMapBlocks(); + runData.touch_blocks_timer = 0; } if (RenderingEngine::get_shadow_renderer()) { @@ -3983,10 +4154,8 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, (player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE) && (camera->getCameraMode() != CAMERA_MODE_THIRD_FRONT)); #ifdef HAVE_TOUCHSCREENGUI - try { - draw_crosshair = !g_settings->getBool("touchtarget"); - } catch (SettingNotFoundException) { - } + if (isNoCrosshairAllowed()) + draw_crosshair = false; #endif m_rendering_engine->draw_scene(skycolor, m_game_ui->m_flags.show_hud, m_game_ui->m_flags.show_minimap, draw_wield_tool, draw_crosshair); @@ -4014,29 +4183,6 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, /* ==================== End scene ==================== */ -#if IRRLICHT_VERSION_MT_REVISION < 5 - if (++m_reset_HW_buffer_counter > 500) { - /* - Periodically remove all mesh HW buffers. - - Work around for a quirk in Irrlicht where a HW buffer is only - released after 20000 iterations (triggered from endScene()). - - Without this, all loaded but unused meshes will retain their HW - buffers for at least 5 minutes, at which point looking up the HW buffers - becomes a bottleneck and the framerate drops (as much as 30%). - - Tests showed that numbers between 50 and 1000 are good, so picked 500. - There are no other public Irrlicht APIs that allow interacting with the - HW buffers without tracking the status of every individual mesh. - - The HW buffers for _visible_ meshes will be reinitialized in the next frame. - */ - infostream << "Game::updateFrame(): Removing all HW buffers." << std::endl; - driver->removeAllHardwareBuffers(); - m_reset_HW_buffer_counter = 0; - } -#endif driver->endScene(); @@ -4152,7 +4298,7 @@ void Game::readSettings() m_cache_enable_fog = g_settings->getBool("enable_fog"); m_cache_mouse_sensitivity = g_settings->getFloat("mouse_sensitivity", 0.001f, 10.0f); m_cache_joystick_frustum_sensitivity = std::max(g_settings->getFloat("joystick_frustum_sensitivity"), 0.001f); - m_repeat_place_time = g_settings->getFloat("repeat_place_time", 0.25f, 2.0); + m_repeat_place_time = g_settings->getFloat("repeat_place_time", 0.16f, 2.0); m_cache_enable_noclip = g_settings->getBool("noclip"); m_cache_enable_free_move = g_settings->getBool("free_move"); @@ -4334,10 +4480,8 @@ void Game::showPauseMenu() GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(), &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound); formspec->setFocus("btn_continue"); + // game will be paused in next step, if in singleplayer (see m_is_paused) formspec->doPause = true; - - if (simple_singleplayer_mode) - pauseAnimation(); } /****************************************************************************/