readSettings();
-#ifdef __ANDROID__
+#ifdef HAVE_TOUCHSCREENGUI
m_cache_hold_aux1 = false; // This is initialised properly later
#endif
void Game::run()
{
ProfilerGraph graph;
- RunStats stats = { 0 };
- FpsControl draw_times = { 0 };
+ RunStats stats = {};
+ 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"));
-#ifdef __ANDROID__
+#ifdef HAVE_TOUCHSCREENGUI
m_cache_hold_aux1 = g_settings->getBool("fast_move")
&& client->checkPrivilege("fast");
#endif
// 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
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);
}
if (bind_addr.isIPv6() && !g_settings->getBool("enable_ipv6")) {
- *error_message = "Unable to listen on " +
- bind_addr.serializeString() +
- " because IPv6 is disabled";
+ *error_message = fmtgettext("Unable to listen on %s because IPv6 is disabled",
+ bind_addr.serializeString().c_str());
errorstream << *error_message << std::endl;
return false;
}
if (!could_connect) {
if (error_message->empty() && !connect_aborted) {
// Should not happen if error messages are set properly
- *error_message = "Connection failed for unknown reason";
+ *error_message = gettext("Connection failed for unknown reason");
errorstream << *error_message << std::endl;
}
return false;
if (!getServerContent(&connect_aborted)) {
if (error_message->empty() && !connect_aborted) {
// Should not happen if error messages are set properly
- *error_message = "Connection failed for unknown reason";
+ *error_message = gettext("Connection failed for unknown reason");
errorstream << *error_message << std::endl;
}
return false;
/* Camera
*/
camera = new Camera(*draw_control, client, m_rendering_engine);
- if (!camera->successfullyCreated(*error_message))
- return false;
+ if (client->modsLoaded())
+ client->getScript()->on_camera_ready(camera);
client->setCamera(camera);
/* Clouds
str += L" [";
str += text;
str += L"]";
- delete text;
+ delete[] text;
}
str += L" [";
str += L"Minetest Hackclient";
connect_address.Resolve(start_data.address.c_str());
if (connect_address.isZero()) { // i.e. INADDR_ANY, IN6ADDR_ANY
- //connect_address.Resolve("localhost");
if (connect_address.isIPv6()) {
IPv6AddressBytes addr_bytes;
addr_bytes.bytes[15] = 1;
local_server_mode = true;
}
} catch (ResolveError &e) {
- *error_message = std::string("Couldn't resolve address: ") + e.what();
+ *error_message = fmtgettext("Couldn't resolve address: %s", e.what());
+
errorstream << *error_message << std::endl;
return false;
}
if (connect_address.isIPv6() && !g_settings->getBool("enable_ipv6")) {
- *error_message = "Unable to connect to " +
- connect_address.serializeString() +
- " because IPv6 is disabled";
+ *error_message = fmtgettext("Unable to connect to %s because IPv6 is disabled", connect_address.serializeString().c_str());
errorstream << *error_message << std::endl;
return false;
}
- client = new Client(start_data.name.c_str(),
- start_data.password, start_data.address,
- *draw_control, texture_src, shader_src,
- itemdef_manager, nodedef_manager, sound, eventmgr,
- m_rendering_engine, connect_address.isIPv6(), m_game_ui.get());
+ try {
+ client = new Client(start_data.name.c_str(),
+ start_data.password, start_data.address,
+ *draw_control, texture_src, shader_src,
+ itemdef_manager, nodedef_manager, sound, eventmgr,
+ m_rendering_engine, connect_address.isIPv6(), m_game_ui.get());
+ client->migrateModStorage();
+ } catch (const BaseException &e) {
+ *error_message = fmtgettext("Error creating client: %s", e.what());
+ errorstream << *error_message << std::endl;
+ return false;
+ }
client->m_simple_singleplayer_mode = simple_singleplayer_mode;
infostream << "Connecting to server at ";
- connect_address.print(&infostream);
+ connect_address.print(infostream);
infostream << std::endl;
client->connect(connect_address,
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);
break;
if (client->accessDenied()) {
- *error_message = "Access denied. Reason: "
- + client->accessDeniedReason();
+ *error_message = fmtgettext("Access denied. Reason: %s", client->accessDeniedReason().c_str());
*reconnect_requested = client->reconnectRequested();
errorstream << *error_message << std::endl;
break;
wait_time += dtime;
// Only time out if we aren't waiting for the server we started
if (!start_data.address.empty() && wait_time > 10) {
- *error_message = "Connection timed out.";
+ *error_message = gettext("Connection timed out.");
errorstream << *error_message << std::endl;
break;
}
{
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);
return false;
if (client->getState() < LC_Init) {
- *error_message = "Client disconnected";
+ *error_message = gettext("Client disconnected");
errorstream << *error_message << std::endl;
return false;
}
inline bool Game::checkConnection()
{
if (client->accessDenied()) {
- *error_message = "Access denied. Reason: "
- + client->accessDeniedReason();
+ *error_message = fmtgettext("Access denied. Reason: %s", client->accessDeniedReason().c_str());
*reconnect_requested = client->reconnectRequested();
errorstream << *error_message << std::endl;
return false;
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();
}
// 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);
}
/* 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;
else 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
InventoryLocation inventoryloc;
inventoryloc.setCurrentPlayer();
- if (!client->modsLoaded()
- || !client->getScript()->on_inventory_open(fs_src->m_client->getInventory(inventoryloc))) {
- TextDest *txt_dst = new TextDestPlayerInventory(client);
- auto *&formspec = m_game_ui->updateFormspec("");
- GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(),
- &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
+ if (client->modsLoaded() && client->getScript()->on_inventory_open(fs_src->m_client->getInventory(inventoryloc))) {
+ delete fs_src;
+ return;
+ }
- formspec->setFormSpec(fs_src->getForm(), inventoryloc);
+ if (fs_src->getForm().empty()) {
+ delete fs_src;
+ return;
}
+
+ TextDest *txt_dst = new TextDestPlayerInventory(client);
+ auto *&formspec = m_game_ui->updateFormspec("");
+ GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(),
+ &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
+
+ formspec->setFormSpec(fs_src->getForm(), inventoryloc);
}
void Game::openEnderchest()
m_game_ui->showTranslatedStatusText("Fast mode disabled");
}
-#ifdef __ANDROID__
+#ifdef HAVE_TOUCHSCREENGUI
m_cache_hold_aux1 = fast_move && has_fast_privs;
#endif
}
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;
}
}
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
// 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");
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");
//TimeTaker tt("update player control", NULL, PRECISION_NANO);
PlayerControl control(
+ isKeyDown(KeyType::FORWARD),
+ isKeyDown(KeyType::BACKWARD),
+ isKeyDown(KeyType::LEFT),
+ isKeyDown(KeyType::RIGHT),
isKeyDown(KeyType::JUMP) || player->getAutojump(),
isKeyDown(KeyType::AUX1),
isKeyDown(KeyType::SNEAK),
control.movement_direction = 0.0f;
}
-#ifdef ANDROID
- /* For Android, simulate holding down AUX1 (fast move) if the user has
+#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
- * Android then its meaning is inverted (i.e. holding aux1 means walk and
+ * touch then its meaning is inverted (i.e. holding aux1 means walk and
* not fast)
*/
if (m_cache_hold_aux1) {
}
#endif
- u32 keypress_bits = (
- ( (u32)(control.jump & 0x1) << 4) |
- ( (u32)(control.aux1 & 0x1) << 5) |
- ( (u32)(control.sneak & 0x1) << 6) |
- ( (u32)(control.dig & 0x1) << 7) |
- ( (u32)(control.place & 0x1) << 8) |
- ( (u32)(control.zoom & 0x1) << 9)
- );
-
- // Set direction keys to ensure mod compatibility
- if (control.movement_speed > 0.001f) {
- float absolute_direction;
-
- // Check in original orientation (absolute value indicates forward / backward)
- absolute_direction = abs(control.movement_direction);
- if (absolute_direction < (3.0f / 8.0f * M_PI))
- keypress_bits |= (u32)(0x1 << 0); // Forward
- if (absolute_direction > (5.0f / 8.0f * M_PI))
- keypress_bits |= (u32)(0x1 << 1); // Backward
-
- // Rotate entire coordinate system by 90 degrees (absolute value indicates left / right)
- absolute_direction = control.movement_direction + M_PI_2;
- if (absolute_direction >= M_PI)
- absolute_direction -= 2 * M_PI;
- absolute_direction = abs(absolute_direction);
- if (absolute_direction < (3.0f / 8.0f * M_PI))
- keypress_bits |= (u32)(0x1 << 2); // Left
- if (absolute_direction > (5.0f / 8.0f * M_PI))
- keypress_bits |= (u32)(0x1 << 3); // Right
- }
-
client->setPlayerControl(control);
- player->keyPressed = keypress_bits;
//tt.stop();
}
void Game::handleClientEvent_SetStars(ClientEvent *event, CameraOrientation *cam)
{
sky->setStarsVisible(event->star_params->visible);
- sky->setStarCount(event->star_params->count, false);
+ sky->setStarCount(event->star_params->count);
sky->setStarColor(event->star_params->starcolor);
sky->setStarScale(event->star_params->scale);
delete event->star_params;
}
}
-void Game::updateChat(f32 dtime, const v2u32 &screensize)
+void Game::updateChat(f32 dtime)
{
// Get new messages from error log buffer
while (!m_chat_log_buf.empty())
chat_backend->step(dtime);
// Display all messages in a static text element
- m_game_ui->setChatText(chat_backend->getRecentChat(),
- chat_backend->getRecentBuffer().getLineCount());
+ auto &buf = chat_backend->getRecentBuffer();
+ if (buf.getLinesModified()) {
+ buf.resetLinesModified();
+ m_game_ui->setChatText(chat_backend->getRecentChat(), buf.getLineCount());
+ }
+
+ // Make sure that the size is still correct
+ m_game_ui->updateChatSize();
}
-void Game::updateCamera(u32 busy_time, f32 dtime)
+void Game::updateCamera(f32 dtime)
{
LocalPlayer *player = client->getEnv().getLocalPlayer();
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();
}
-void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
+void Game::processPlayerInteraction(f32 dtime, bool show_hud)
{
LocalPlayer *player = client->getEnv().getLocalPlayer();
!runData.btn_down_for_dig,
camera_offset);
- if (pointed != runData.pointed_old) {
+ if (pointed != runData.pointed_old)
infostream << "Pointing at " << pointed.dump() << std::endl;
- hud->updateSelectionMesh(camera_offset);
- }
+
+ // 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
+ hud->updateSelectionMesh(camera_offset);
// Allow digging again if button is not pressed
if (runData.digging_blocked && !isKeyDown(KeyType::DIG))
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;
} else {
MapNode n = map.getNode(nodepos);
- if (nodedef_manager->get(n).tiledef[0].name == "unknown_node.png") {
- m_game_ui->setInfoText(L"Unknown node: " +
- utf8_to_wide(nodedef_manager->get(n).name));
+ if (nodedef_manager->get(n).name == "unknown") {
+ m_game_ui->setInfoText(L"Unknown node");
}
}
// cheat detection.
// Get digging parameters
DigParams params = getDigParams(nodedef_manager->get(n).groups,
- &selected_item.getToolCapabilities(itemdef_manager));
+ &selected_item.getToolCapabilities(itemdef_manager),
+ selected_item.wear);
// If can't dig, try hand
if (!params.diggable) {
}
/*
- Get chat messages from client
+ Damage camera tilt
*/
+ if (player->hurt_tilt_timer > 0.0f) {
+ player->hurt_tilt_timer -= dtime * 6.0f;
- v2u32 screensize = driver->getScreenSize();
+ if (player->hurt_tilt_timer < 0.0f || g_settings->getBool("no_hurt_cam"))
+ 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
+ */
- updateChat(dtime, screensize);
+ updateChat(dtime);
/*
Inventory
v3f camera_direction = camera->getDirection();
if (runData.update_draw_list_timer >= update_draw_list_delta
|| runData.update_draw_list_last_cam_dir.getDistanceFrom(camera_direction) > 0.2
- || m_camera_offset_changed) {
-
+ || m_camera_offset_changed
+ || client->getEnv().getClientMap().needsUpdateDrawList()) {
runData.update_draw_list_timer = 0;
client->getEnv().getClientMap().updateDrawList();
runData.update_draw_list_last_cam_dir = camera_direction;
} 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 &&
/*
Profiler graph
*/
+ v2u32 screensize = driver->getScreenSize();
+
if (m_game_ui->m_flags.show_profiler_graph)
graph->draw(10, screensize.Y - 10, driver, g_fontengine->getFont());
runData.damage_flash -= 384.0f * 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 || g_settings->getBool("no_hurt_cam"))
- 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
*/
+#if IRRLICHT_VERSION_MT_REVISION < 5
if (++m_reset_HW_buffer_counter > 500) {
/*
Periodically remove all mesh HW buffers.
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 */
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);
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)
#define GET_KEY_NAME(KEY) gettext(getKeySetting(#KEY).name())
void Game::showPauseMenu()
{
-#ifdef __ANDROID__
+#ifdef HAVE_TOUCHSCREENGUI
static const std::string control_text = strgettext("Default Controls:\n"
"No menu visible:\n"
"- single tap: button activate\n"
if (simple_singleplayer_mode || address.empty()) {
static const std::string on = strgettext("On");
static const std::string off = strgettext("Off");
- const std::string &damage = g_settings->getBool("enable_damage") ? on : off;
- const std::string &creative = g_settings->getBool("creative_mode") ? on : off;
+ // Note: Status of enable_damage and creative_mode settings is intentionally
+ // NOT shown here because the game might roll its own damage system and/or do
+ // a per-player Creative Mode, in which case writing it here would mislead.
+ bool damage = g_settings->getBool("enable_damage");
const std::string &announced = g_settings->getBool("server_announce") ? on : off;
- os << strgettext("- Damage: ") << damage << "\n"
- << strgettext("- Creative Mode: ") << creative << "\n";
if (!simple_singleplayer_mode) {
- const std::string &pvp = g_settings->getBool("enable_pvp") ? on : off;
- //~ PvP = Player versus Player
- os << strgettext("- PvP: ") << pvp << "\n"
- << strgettext("- Public: ") << announced << "\n";
+ if (damage) {
+ const std::string &pvp = g_settings->getBool("enable_pvp") ? on : off;
+ //~ PvP = Player versus Player
+ os << strgettext("- PvP: ") << pvp << "\n";
+ }
+ os << strgettext("- Public: ") << announced << "\n";
std::string server_name = g_settings->get("server_name");
str_formspec_escape(server_name);
if (announced == on && !server_name.empty())
}
} catch (SerializationError &e) {
- error_message = std::string("A serialization error occurred:\n")
- + e.what() + "\n\nThe server is probably "
- " running a different version of " PROJECT_NAME_C ".";
+ const std::string ver_err = fmtgettext("The server is probably running a different version of %s.", PROJECT_NAME_C);
+ error_message = strgettext("A serialization error occurred:") +"\n"
+ + e.what() + "\n\n" + ver_err;
errorstream << error_message << std::endl;
} catch (ServerError &e) {
error_message = e.what();
errorstream << "ServerError: " << error_message << std::endl;
} catch (ModError &e) {
+ // DO NOT TRANSLATE the `ModError`, it's used by ui.lua
error_message = std::string("ModError: ") + e.what() +
strgettext("\nCheck debug.txt for details.");
errorstream << error_message << std::endl;