This commit is contained in:
Bruno Rybársky 2024-02-27 14:16:37 +01:00
parent dd460bfbb3
commit 206d9eebfa

@ -3,19 +3,19 @@ Minetest
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "game.h"
@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "client/mapblock_mesh.h"
#include "client/sound.h"
#include "clientmap.h"
#include "clientmedia.h" // For clientMediaUpdateCacheCopy
#include "clouds.h"
#include "config.h"
#include "content_cao.h"
@ -77,15 +78,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <IAnimatedMeshSceneNode.h>
#if USE_SOUND
#include "client/sound/sound_openal.h"
#include "client/sound/sound_openal.h"
#endif
/*
/*
Text input system
*/
*/
struct TextDestNodeMetadata : public TextDest
{
struct TextDestNodeMetadata : public TextDest
{
TextDestNodeMetadata(v3s16 p, Client *client)
{
m_p = p;
@ -108,7 +109,7 @@ struct TextDestNodeMetadata : public TextDest
v3s16 m_p;
Client *m_client;
};
};
struct TextDestPlayerInventory : public TextDest
{
@ -663,11 +664,7 @@ public:
}
};
#ifdef HAVE_TOUCHSCREENGUI
#define SIZE_TAG "size[11,5.5]"
#else
#define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop
#endif
#define SIZE_TAG "size[11,5.5,true]" // Fixed size (ignored in touchscreen mode)
/****************************************************************************
****************************************************************************/
@ -769,6 +766,7 @@ protected:
bool initSound();
bool createSingleplayerServer(const std::string &map_dir,
const SubgameSpec &gamespec, u16 port);
void copyServerClientCache();
// Client creation
bool createClient(const GameStartData &start_data);
@ -1019,13 +1017,11 @@ private:
// this happens in pause menu in singleplayer
bool m_is_paused = false;
#ifdef HAVE_TOUCHSCREENGUI
bool m_cache_hold_aux1;
bool m_touch_simulate_aux1 = false;
bool m_touch_use_crosshair;
inline bool isNoCrosshairAllowed() {
inline bool isTouchCrosshairDisabled() {
return !m_touch_use_crosshair && camera->getCameraMode() == CAMERA_MODE_FIRST;
}
#endif
#ifdef __ANDROID__
bool m_android_chat_open;
#endif
@ -1073,11 +1069,6 @@ Game::Game() :
&settingChangedCallback, this);
readSettings();
#ifdef HAVE_TOUCHSCREENGUI
m_cache_hold_aux1 = false; // This is initialised properly later
#endif
}
@ -1180,9 +1171,7 @@ bool Game::startup(bool *kill,
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();
@ -1217,10 +1206,8 @@ void Game::run()
set_light_table(g_settings->getFloat("display_gamma"));
#ifdef HAVE_TOUCHSCREENGUI
m_cache_hold_aux1 = g_settings->getBool("fast_move")
m_touch_simulate_aux1 = g_settings->getBool("fast_move")
&& client->checkPrivilege("fast");
#endif
const irr::core::dimension2du initial_screen_size(
g_settings->getU16("screen_w"),
@ -1288,9 +1275,6 @@ void Game::run()
updateFrame(&graph, &stats, dtime, cam_view);
updateProfilerGraphs(&graph);
// Update if minimap has been disabled by the server
m_game_ui->m_flags.show_minimap &= client->shouldShowMinimap();
if (m_does_lost_focus_pause_game && !device->isWindowFocused() && !isMenuActive()) {
showPauseMenu();
}
@ -1309,9 +1293,8 @@ void Game::shutdown()
// Clear text when exiting.
m_game_ui->clearText();
#ifdef HAVE_TOUCHSCREENGUI
if (g_touchscreengui)
g_touchscreengui->hide();
#endif
showOverlayMessage(N_("Shutting down..."), 0, 0, false);
@ -1453,9 +1436,31 @@ bool Game::createSingleplayerServer(const std::string &map_dir,
false, nullptr, error_message);
server->start();
copyServerClientCache();
return true;
}
void Game::copyServerClientCache()
{
// It would be possible to let the client directly read the media files
// from where the server knows they are. But aside from being more complicated
// it would also *not* fill the media cache and cause slower joining of
// remote servers.
// (Imagine that you launch a game once locally and then connect to a server.)
assert(server);
auto map = server->getMediaList();
u32 n = 0;
for (auto &it : map) {
assert(it.first.size() == 20); // SHA1
if (clientMediaUpdateCacheCopy(it.first, it.second))
n++;
}
infostream << "Copied " << n << " files directly from server to client cache"
<< std::endl;
}
bool Game::createClient(const GameStartData &start_data)
{
showOverlayMessage(N_("Creating client..."), 0, 10);
@ -1499,11 +1504,10 @@ 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());
g_touchscreengui->setUseCrosshair(!isTouchCrosshairDisabled());
}
#endif
/* Clouds
*/
@ -1530,18 +1534,20 @@ bool Game::createClient(const GameStartData &start_data)
/* Set window caption
*/
std::wstring str = utf8_to_wide(PROJECT_NAME_C);
str += L" ";
str += utf8_to_wide(g_version_hash);
str += L" [";
str += simple_singleplayer_mode ? wstrgettext("Singleplayer")
: wstrgettext("Multiplayer");
str += L"]";
str += L" [";
str += driver->getName();
str += L"]";
#if IRRLICHT_VERSION_MT_REVISION >= 15
auto driver_name = driver->getName();
#else
auto driver_name = wide_to_utf8(driver->getName());
#endif
std::string str = std::string(PROJECT_NAME_C) +
" " + g_version_hash + " [";
str += simple_singleplayer_mode ? gettext("Singleplayer")
: gettext("Multiplayer");
str += "] [";
str += driver_name;
str += "]";
device->setWindowCaption(str.c_str());
device->setWindowCaption(utf8_to_wide(str).c_str());
LocalPlayer *player = client->getEnv().getLocalPlayer();
player->hurt_tilt_timer = 0;
@ -1571,10 +1577,8 @@ bool Game::initGui()
gui_chat_console = new GUIChatConsole(guienv, guienv->getRootGUIElement(),
-1, chat_backend, client, &g_menumgr);
#ifdef HAVE_TOUCHSCREENGUI
if (g_touchscreengui)
g_touchscreengui->init(texture_src);
#endif
return true;
}
@ -1888,13 +1892,8 @@ void Game::updateDebugState()
LocalPlayer *player = client->getEnv().getLocalPlayer();
// debug UI and wireframe
bool force_debug = g_settings->getBool("force_debug");
bool has_debug = client->checkPrivilege("debug");
bool has_basic_debug = has_debug || (player->hud_flags & HUD_FLAG_BASIC_DEBUG);
if(force_debug){
has_debug = true;
has_basic_debug = true;
}
if (m_game_ui->m_flags.show_basic_debug) {
if (!has_basic_debug)
@ -2008,18 +2007,17 @@ void Game::processUserInput(f32 dtime)
} else {
input->clear();
}
#ifdef HAVE_TOUCHSCREENGUI
if (g_touchscreengui)
g_touchscreengui->hide();
#endif
} else {
#ifdef HAVE_TOUCHSCREENGUI
if (g_touchscreengui) {
/* on touchscreengui step may generate own input events which ain't
* what we want in case we just did clear them */
g_touchscreengui->show();
g_touchscreengui->step(dtime);
}
#endif
m_game_focused = true;
}
@ -2211,13 +2209,11 @@ void Game::processItemSelection(u16 *new_playeritem)
}
}
#ifdef HAVE_TOUCHSCREENGUI
if (g_touchscreengui) {
std::optional<u16> selection = g_touchscreengui->getHotbarSelection();
if (selection)
*new_playeritem = *selection;
}
#endif
// Clamp selection again in case it wasn't changed but max_item was
*new_playeritem = MYMIN(*new_playeritem, max_item);
@ -2368,9 +2364,7 @@ void Game::toggleFast()
m_game_ui->showTranslatedStatusText("Fast mode disabled");
}
#ifdef HAVE_TOUCHSCREENGUI
m_cache_hold_aux1 = fast_move && has_fast_privs;
#endif
m_touch_simulate_aux1 = fast_move && has_fast_privs;
}
@ -2455,26 +2449,19 @@ void Game::toggleMinimap(bool shift_pressed)
// -->
u32 hud_flags = client->getEnv().getLocalPlayer()->hud_flags;
if (!(hud_flags & HUD_FLAG_MINIMAP_VISIBLE)) {
m_game_ui->m_flags.show_minimap = false;
} else {
if (hud_flags & HUD_FLAG_MINIMAP_VISIBLE) {
// If radar is disabled, try to find a non radar mode or fall back to 0
if (!(hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE))
while (mapper->getModeIndex() &&
mapper->getModeDef().type == MINIMAP_TYPE_RADAR)
mapper->nextMode();
m_game_ui->m_flags.show_minimap = mapper->getModeDef().type != MINIMAP_TYPE_OFF;
}
// <--
// End of 'not so satifying code'
if ((hud_flags & HUD_FLAG_MINIMAP_VISIBLE) ||
(hud && hud->hasElementOfType(HUD_ELEM_MINIMAP)))
if (hud && hud->hasElementOfType(HUD_ELEM_MINIMAP))
m_game_ui->showStatusText(utf8_to_wide(mapper->getModeDef().label));
else
m_game_ui->showTranslatedStatusText(
"Minimap currently disabled by game or mod");
}
m_game_ui->showTranslatedStatusText("Minimap currently disabled by game or mod");
}
void Game::toggleFog()
@ -2491,13 +2478,8 @@ void Game::toggleFog()
void Game::toggleDebug()
{
LocalPlayer *player = client->getEnv().getLocalPlayer();
bool force_debug = g_settings->getBool("force_debug");
bool has_debug = client->checkPrivilege("debug");
bool has_basic_debug = has_debug || (player->hud_flags & HUD_FLAG_BASIC_DEBUG);
if(force_debug){
has_debug = true;
has_basic_debug = true;
}
// Initial: No debug info
// 1x toggle: Debug text
// 2x toggle: Debug text with profiler graph
@ -2521,7 +2503,7 @@ void Game::toggleDebug()
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 && has_debug) {
} else if (!draw_control->show_wireframe && client->checkPrivilege("debug")) {
if (has_basic_debug)
m_game_ui->m_flags.show_basic_debug = true;
m_game_ui->m_flags.show_profiler_graph = false;
@ -2627,10 +2609,8 @@ void Game::updateCameraDirection(CameraOrientation *cam, float dtime)
Since Minetest has its own code to synthesize mouse events from touch events,
this results in duplicated input. To avoid that, we don't enable relative
mouse mode if we're in touchscreen mode. */
#ifndef HAVE_TOUCHSCREENGUI
if (cur_control)
cur_control->setRelativeMode(!isMenuActive());
#endif
cur_control->setRelativeMode(!g_touchscreengui && !isMenuActive());
if ((device->isWindowActive() && device->isWindowFocused()
&& !isMenuActive()) || input->isRandom()) {
@ -2668,17 +2648,15 @@ f32 Game::getSensitivityScaleFactor() const
// Multiply by a constant such that it becomes 1.0 at 72 degree FOV and
// 16:9 aspect ratio to minimize disruption of existing sensitivity
// settings.
return tan(fov_y / 2.0f) * 1.3763818698f;
return std::tan(fov_y / 2.0f) * 1.3763819f;
}
void Game::updateCameraOrientation(CameraOrientation *cam, float dtime)
{
#ifdef HAVE_TOUCHSCREENGUI
if (g_touchscreengui) {
cam->camera_yaw += g_touchscreengui->getYawChange();
cam->camera_pitch += g_touchscreengui->getPitchChange();
} else {
#endif
v2s32 center(driver->getScreenSize().Width / 2, driver->getScreenSize().Height / 2);
v2s32 dist = input->getMousePos() - center;
@ -2692,9 +2670,7 @@ void Game::updateCameraOrientation(CameraOrientation *cam, float dtime)
if (dist.X != 0 || dist.Y != 0)
input->setMousePos(center.X, center.Y);
#ifdef HAVE_TOUCHSCREENGUI
}
#endif
if (m_cache_enable_joysticks) {
f32 sens_scale = getSensitivityScaleFactor();
@ -2735,20 +2711,18 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
client->activeObjectsReceived() && !player->isDead()) {
control.movement_speed = 1.0f;
// sideways movement only
float dx = sin(control.movement_direction);
control.movement_direction = atan2(dx, 1.0f);
float dx = std::sin(control.movement_direction);
control.movement_direction = std::atan2(dx, 1.0f);
}
#ifdef HAVE_TOUCHSCREENGUI
/* For touch, simulate holding down AUX1 (fast move) if the user has
* the fast_move setting toggled on. If there is an aux1 key defined for
* touch then its meaning is inverted (i.e. holding aux1 means walk and
* not fast)
*/
if (m_cache_hold_aux1) {
if (g_touchscreengui && m_touch_simulate_aux1) {
control.aux1 = control.aux1 ^ true;
}
#endif
client->setPlayerControl(control);
@ -2777,10 +2751,16 @@ inline void Game::step(f32 dtime)
g_settings->getFloat("fps_max_unfocused") :
g_settings->getFloat("fps_max");
fps_max = std::max(fps_max, 1.0f);
float steplen = 1.0f / fps_max;
/*
* Unless you have a barebones game, running the server at more than 60Hz
* is hardly realistic and you're at the point of diminishing returns.
* fps_max is also not necessarily anywhere near the FPS actually achieved
* (also due to vsync).
*/
fps_max = std::min(fps_max, 60.0f);
server->setStepSettings(Server::StepSettings{
steplen,
1.0f / fps_max,
m_is_paused
});
@ -3229,10 +3209,8 @@ void Game::updateCamera(f32 dtime)
camera->toggleCameraMode();
#ifdef HAVE_TOUCHSCREENGUI
if (g_touchscreengui)
g_touchscreengui->setUseCrosshair(!isNoCrosshairAllowed());
#endif
g_touchscreengui->setUseCrosshair(!isTouchCrosshairDisabled());
// Make the player visible depending on camera mode.
playercao->updateMeshCulling();
@ -3333,8 +3311,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud)
}
shootline.end = shootline.start + camera_direction * BS * d;
#ifdef HAVE_TOUCHSCREENGUI
if (g_touchscreengui && isNoCrosshairAllowed()) {
if (g_touchscreengui && isTouchCrosshairDisabled()) {
shootline = g_touchscreengui->getShootline();
// Scale shootline to the acual distance the player can reach
shootline.end = shootline.start +
@ -3342,7 +3319,6 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud)
shootline.start += intToFloat(camera_offset, BS);
shootline.end += intToFloat(camera_offset, BS);
}
#endif
PointedThing pointed = updatePointedThing(shootline,
selected_def.liquids_pointable,
@ -3353,10 +3329,8 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud)
if (pointed != runData.pointed_old)
infostream << "Pointing at " << pointed.dump() << std::endl;
#ifdef HAVE_TOUCHSCREENGUI
if (g_touchscreengui)
g_touchscreengui->applyContextControls(selected_def.touch_interaction.getMode(pointed));
#endif
// Note that updating the selection mesh every frame is not particularly efficient,
// but the halo rendering code is already inefficient so there's no point in optimizing it here
@ -3734,11 +3708,11 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
break;
};
case NDT_SIGNLIKE: {
rotate90 = abs(pdir.X) < abs(pdir.Z);
rotate90 = std::abs(pdir.X) < std::abs(pdir.Z);
break;
}
default: {
rotate90 = abs(pdir.X) > abs(pdir.Z);
rotate90 = std::abs(pdir.X) > std::abs(pdir.Z);
break;
}
}
@ -4276,14 +4250,14 @@ void Game::updateShadows()
if (!shadow)
return;
float in_timeofday = fmod(runData.time_of_day_smooth, 1.0f);
float in_timeofday = std::fmod(runData.time_of_day_smooth, 1.0f);
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;
timeoftheday = std::fmod(timeoftheday + 0.75f, 0.5f) + 0.25f;
const float offset_constant = 10000.0f;
v3f light = is_day ? sky->getSunDirection() : sky->getMoonDirection();
@ -4339,12 +4313,12 @@ void Game::drawScene(ProfilerGraph *graph, RunStats *stats)
bool draw_crosshair = (
(player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE) &&
(this->camera->getCameraMode() != CAMERA_MODE_THIRD_FRONT));
#ifdef HAVE_TOUCHSCREENGUI
if (this->isNoCrosshairAllowed())
if (g_touchscreengui && isTouchCrosshairDisabled())
draw_crosshair = false;
#endif
this->m_rendering_engine->draw_scene(sky_color, this->m_game_ui->m_flags.show_hud,
this->m_game_ui->m_flags.show_minimap, draw_wield_tool, draw_crosshair);
draw_wield_tool, draw_crosshair);
/*
Profiler graph
@ -4490,8 +4464,10 @@ void Game::showDeathFormspec()
#define GET_KEY_NAME(KEY) gettext(getKeySetting(#KEY).name())
void Game::showPauseMenu()
{
#ifdef HAVE_TOUCHSCREENGUI
static const std::string control_text = strgettext("Controls:\n"
std::string control_text;
if (g_touchscreengui) {
control_text = strgettext("Controls:\n"
"No menu open:\n"
"- slide finger: look around\n"
"- tap: place/punch/use (default)\n"
@ -4504,7 +4480,7 @@ void Game::showPauseMenu()
"- touch&drag, tap 2nd finger\n"
" --> place single item to slot\n"
);
#endif
}
float ypos = simple_singleplayer_mode ? 0.7f : 0.1f;
std::ostringstream os;
@ -4534,9 +4510,9 @@ void Game::showPauseMenu()
<< strgettext("Exit to Menu") << "]";
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_os;"
<< strgettext("Exit to OS") << "]";
#ifdef HAVE_TOUCHSCREENGUI
if (!control_text.empty()) {
os << "textarea[7.5,0.25;3.9,6.25;;" << control_text << ";]";
#endif
}
os << "textarea[0.4,0.25;3.9,6.25;;" << PROJECT_NAME_C " " VERSION_STRING "\n"
<< "\n"
<< strgettext("Game info:") << "\n";