*/
#include "game.h"
-#include "irrlichttypes_extrabloated.h"
-#include <IGUICheckBox.h>
-#include <IGUIEditBox.h>
-#include <IGUIButton.h>
-#include <IGUIStaticText.h>
-#include <IGUIFont.h>
-#include <IMaterialRendererServices.h>
-#include "IMeshCache.h"
+
+#include <iomanip>
+#include "camera.h"
#include "client.h"
-#include "server.h"
-#include "guiPasswordChange.h"
-#include "guiVolumeChange.h"
-#include "guiKeyChangeMenu.h"
-#include "guiFormSpecMenu.h"
-#include "tool.h"
-#include "guiChatConsole.h"
-#include "config.h"
-#include "version.h"
+#include "client/tile.h" // For TextureSource
+#include "clientmap.h"
#include "clouds.h"
-#include "particles.h"
-#include "camera.h"
-#include "mapblock.h"
-#include "settings.h"
-#include "profiler.h"
-#include "mainmenumanager.h"
-#include "gettext.h"
+#include "config.h"
+#include "content_cao.h"
+#include "drawscene.h"
+#include "event_manager.h"
+#include "fontengine.h"
+#include "itemdef.h"
#include "log.h"
#include "filesys.h"
-// Needed for determining pointing to nodes
-#include "nodedef.h"
+#include "gettext.h"
+#include "guiChatConsole.h"
+#include "guiFormSpecMenu.h"
+#include "guiKeyChangeMenu.h"
+#include "guiPasswordChange.h"
+#include "guiVolumeChange.h"
+#include "hud.h"
+#include "mainmenumanager.h"
+#include "mapblock.h"
+#include "nodedef.h" // Needed for determining pointing to nodes
#include "nodemetadata.h"
-#include "main.h" // For g_settings
-#include "itemdef.h"
-#include "tile.h" // For TextureSource
-#include "shader.h" // For ShaderSource
-#include "logoutputbuffer.h"
-#include "subgame.h"
+#include "particles.h"
+#include "profiler.h"
#include "quicktune_shortcutter.h"
-#include "clientmap.h"
-#include "hud.h"
+#include "server.h"
+#include "settings.h"
+#include "shader.h" // For ShaderSource
#include "sky.h"
+#include "subgame.h"
+#include "tool.h"
+#include "util/directiontables.h"
+#include "util/pointedthing.h"
+#include "version.h"
+#include "minimap.h"
+#include "mapblock_mesh.h"
+
#include "sound.h"
+
#if USE_SOUND
-#include "sound_openal.h"
+ #include "sound_openal.h"
#endif
-#include "event_manager.h"
-#include <iomanip>
-#include <list>
-#include "util/directiontables.h"
-#include "util/pointedthing.h"
-#include "drawscene.h"
-#include "content_cao.h"
#ifdef HAVE_TOUCHSCREENGUI
-#include "touchscreengui.h"
+ #include "touchscreengui.h"
#endif
+extern Settings *g_settings;
+extern Profiler *g_profiler;
+
/*
Text input system
*/
// This is deprecated I guess? -celeron55
void gotText(std::wstring text)
{
- std::string ntext = wide_to_narrow(text);
+ std::string ntext = wide_to_utf8(text);
infostream << "Submitting 'text' field of node at (" << m_p.X << ","
<< m_p.Y << "," << m_p.Z << "): " << ntext << std::endl;
- std::map<std::string, std::string> fields;
+ StringMap fields;
fields["text"] = ntext;
m_client->sendNodemetaFields(m_p, "", fields);
}
- void gotText(std::map<std::string, std::string> fields)
+ void gotText(const StringMap &fields)
{
m_client->sendNodemetaFields(m_p, "", fields);
}
m_client = client;
m_formname = formname;
}
- void gotText(std::map<std::string, std::string> fields)
+ void gotText(const StringMap &fields)
{
m_client->sendInventoryFields(m_formname, fields);
}
errorstream << "LocalFormspecHandler::gotText old style message received" << std::endl;
}
- void gotText(std::map<std::string, std::string> fields)
+ void gotText(const StringMap &fields)
{
if (m_formname == "MT_PAUSE_MENU") {
if (fields.find("btn_sound") != fields.end()) {
if ((fields.find("btn_send") != fields.end()) ||
(fields.find("quit") != fields.end())) {
- if (fields.find("f_text") != fields.end()) {
- m_client->typeChatMessage(narrow_to_wide(fields["f_text"]));
- }
+ StringMap::const_iterator it = fields.find("f_text");
+ if (it != fields.end())
+ m_client->typeChatMessage(utf8_to_wide(it->second));
return;
}
return;
}
- errorstream << "LocalFormspecHandler::gotText unhandled >" << m_formname << "< event" << std::endl;
- int i = 0;
+ errorstream << "LocalFormspecHandler::gotText unhandled >"
+ << m_formname << "< event" << std::endl;
- for (std::map<std::string, std::string>::iterator iter = fields.begin();
- iter != fields.end(); iter++) {
- errorstream << "\t" << i << ": " << iter->first << "=" << iter->second << std::endl;
+ int i = 0;
+ StringMap::const_iterator it;
+ for (it = fields.begin(); it != fields.end(); ++it) {
+ errorstream << "\t" << i << ": " << it->first
+ << "=" << it->second << std::endl;
i++;
}
}
/*
Find what the player is pointing at
*/
-PointedThing getPointedThing(Client *client, v3f player_position,
- v3f camera_direction, v3f camera_position, core::line3d<f32> shootline,
- f32 d, bool liquids_pointable, bool look_for_object, v3s16 camera_offset,
- std::vector<aabb3f> &hilightboxes, ClientActiveObject *&selected_object)
+PointedThing getPointedThing(Client *client, Hud *hud, const v3f &player_position,
+ const v3f &camera_direction, const v3f &camera_position,
+ core::line3d<f32> shootline, f32 d, bool liquids_pointable,
+ bool look_for_object, const v3s16 &camera_offset,
+ ClientActiveObject *&selected_object)
{
PointedThing result;
- hilightboxes.clear();
+ std::vector<aabb3f> *selectionboxes = hud->getSelectionBoxes();
+ selectionboxes->clear();
selected_object = NULL;
INodeDefManager *nodedef = client->getNodeDefManager();
assert(selection_box);
v3f pos = selected_object->getPosition();
- hilightboxes.push_back(aabb3f(
- selection_box->MinEdge + pos - intToFloat(camera_offset, BS),
- selection_box->MaxEdge + pos - intToFloat(camera_offset, BS)));
+ selectionboxes->push_back(aabb3f(
+ selection_box->MinEdge, selection_box->MaxEdge));
+ hud->setSelectionPos(pos, camera_offset);
}
mindistance = (selected_object->getPosition() - camera_position).getLength();
for (s16 z = zstart; z <= zend; z++)
for (s16 x = xstart; x <= xend; x++) {
MapNode n;
+ bool is_valid_position;
- try {
- n = map.getNode(v3s16(x, y, z));
- } catch (InvalidPositionException &e) {
+ n = map.getNodeNoEx(v3s16(x, y, z), &is_valid_position);
+ if (!is_valid_position)
continue;
- }
if (!isPointableNode(n, client, liquids_pointable))
continue;
for (std::vector<aabb3f>::const_iterator
i = boxes.begin();
- i != boxes.end(); i++) {
+ i != boxes.end(); ++i) {
aabb3f box = *i;
box.MinEdge += npf;
box.MaxEdge += npf;
result.node_abovesurface = np_above;
mindistance = distance;
- hilightboxes.clear();
-
- if (!g_settings->getBool("enable_node_highlighting")) {
- for (std::vector<aabb3f>::const_iterator
- i2 = boxes.begin();
- i2 != boxes.end(); i2++) {
- aabb3f box = *i2;
- box.MinEdge += npf + v3f(-d, -d, -d) - intToFloat(camera_offset, BS);
- box.MaxEdge += npf + v3f(d, d, d) - intToFloat(camera_offset, BS);
- hilightboxes.push_back(box);
- }
+ selectionboxes->clear();
+ for (std::vector<aabb3f>::const_iterator
+ i2 = boxes.begin();
+ i2 != boxes.end(); ++i2) {
+ aabb3f box = *i2;
+ box.MinEdge += v3f(-d, -d, -d);
+ box.MaxEdge += v3f(d, d, d);
+ selectionboxes->push_back(box);
}
+ hud->setSelectionPos(npf, camera_offset);
}
}
} // for coords
+ // Update selection mesh light level and vertex colors
+ if (selectionboxes->size() > 0) {
+ v3f pf = hud->getSelectionPos();
+ v3s16 p = floatToInt(pf, BS);
+
+ // Get selection mesh light level
+ MapNode n = map.getNodeNoEx(p);
+ u16 node_light = getInteriorLight(n, -1, nodedef);
+ u16 light_level = node_light;
+
+ for (u8 i = 0; i < 6; i++) {
+ n = map.getNodeNoEx(p + g_6dirs[i]);
+ node_light = getInteriorLight(n, -1, nodedef);
+ if (node_light > light_level)
+ light_level = node_light;
+ }
+
+ video::SColor c = MapBlock_LightColor(255, light_level, 0);
+ u8 day = c.getRed();
+ u8 night = c.getGreen();
+ u32 daynight_ratio = client->getEnv().getDayNightRatio();
+ finalColorBlend(c, day, night, daynight_ratio);
+
+ // Modify final color a bit with time
+ u32 timer = porting::getTimeMs() % 5000;
+ float timerf = (float)(irr::core::PI * ((timer / 2500.0) - 0.5));
+ float sin_r = 0.08 * sin(timerf);
+ float sin_g = 0.08 * sin(timerf + irr::core::PI * 0.5);
+ float sin_b = 0.08 * sin(timerf + irr::core::PI);
+ c.setRed(core::clamp(core::round32(c.getRed() * (0.8 + sin_r)), 0, 255));
+ c.setGreen(core::clamp(core::round32(c.getGreen() * (0.8 + sin_g)), 0, 255));
+ c.setBlue(core::clamp(core::round32(c.getBlue() * (0.8 + sin_b)), 0, 255));
+
+ // Set mesh final color
+ hud->setSelectionMeshColor(c);
+ }
return result;
}
/* Profiler display */
-void update_profiler_gui(gui::IGUIStaticText *guitext_profiler,
- gui::IGUIFont *font, u32 text_height, u32 show_profiler,
- u32 show_profiler_max)
+void update_profiler_gui(gui::IGUIStaticText *guitext_profiler, FontEngine *fe,
+ u32 show_profiler, u32 show_profiler_max, s32 screen_height)
{
if (show_profiler == 0) {
guitext_profiler->setVisible(false);
std::ostringstream os(std::ios_base::binary);
g_profiler->printPage(os, show_profiler, show_profiler_max);
- std::wstring text = narrow_to_wide(os.str());
+ std::wstring text = utf8_to_wide(os.str());
guitext_profiler->setText(text.c_str());
guitext_profiler->setVisible(true);
- s32 w = font->getDimension(text.c_str()).Width;
+ s32 w = fe->getTextWidth(text.c_str());
if (w < 400)
w = 400;
- core::rect<s32> rect(6, 4 + (text_height + 5) * 2, 12 + w,
- 8 + (text_height + 5) * 2 +
- font->getDimension(text.c_str()).Height);
+ unsigned text_height = fe->getTextHeight();
+
+ core::position2di upper_left, lower_right;
+
+ upper_left.X = 6;
+ upper_left.Y = (text_height + 5) * 2;
+ lower_right.X = 12 + w;
+ lower_right.Y = upper_left.Y + (text_height + 1) * MAX_PROFILER_TEXT_ROWS;
+
+ if (lower_right.Y > screen_height * 2 / 3)
+ lower_right.Y = screen_height * 2 / 3;
+
+ core::rect<s32> rect(upper_left, lower_right);
+
guitext_profiler->setRelativePosition(rect);
guitext_profiler->setVisible(true);
}
color(color)
{}
};
- std::list<Piece> m_log;
+ std::deque<Piece> m_log;
public:
u32 m_log_max_size;
{
std::map<std::string, Meta> m_meta;
- for (std::list<Piece>::const_iterator k = m_log.begin();
- k != m_log.end(); k++) {
+ for (std::deque<Piece>::const_iterator k = m_log.begin();
+ k != m_log.end(); ++k) {
const Piece &piece = *k;
for (Profiler::GraphValues::const_iterator i = piece.values.begin();
- i != piece.values.end(); i++) {
+ i != piece.values.end(); ++i) {
const std::string &id = i->first;
const float &value = i->second;
std::map<std::string, Meta>::iterator j =
u32 next_color_i = 0;
for (std::map<std::string, Meta>::iterator i = m_meta.begin();
- i != m_meta.end(); i++) {
+ i != m_meta.end(); ++i) {
Meta &meta = i->second;
video::SColor color(255, 200, 200, 200);
s32 graphh = 50;
s32 textx = x_left + m_log_max_size + 15;
s32 textx2 = textx + 200 - 15;
-
- // Draw background
- /*{
- u32 num_graphs = m_meta.size();
- core::rect<s32> rect(x_left, y_bottom - num_graphs*graphh,
- textx2, y_bottom);
- video::SColor bgcolor(120,0,0,0);
- driver->draw2DRectangle(bgcolor, rect, NULL);
- }*/
-
s32 meta_i = 0;
for (std::map<std::string, Meta>::const_iterator i = m_meta.begin();
- i != m_meta.end(); i++) {
+ i != m_meta.end(); ++i) {
const std::string &id = i->first;
const Meta &meta = i->second;
s32 x = x_left;
s32 texth = 15;
char buf[10];
snprintf(buf, 10, "%.3g", show_max);
- font->draw(narrow_to_wide(buf).c_str(),
+ font->draw(utf8_to_wide(buf).c_str(),
core::rect<s32>(textx, y - graphh,
textx2, y - graphh + texth),
meta.color);
snprintf(buf, 10, "%.3g", show_min);
- font->draw(narrow_to_wide(buf).c_str(),
+ font->draw(utf8_to_wide(buf).c_str(),
core::rect<s32>(textx, y - texth,
textx2, y),
meta.color);
- font->draw(narrow_to_wide(id).c_str(),
+ font->draw(utf8_to_wide(id).c_str(),
core::rect<s32>(textx, y - graphh / 2 - texth / 2,
textx2, y - graphh / 2 + texth / 2),
meta.color);
float lastscaledvalue = 0.0;
bool lastscaledvalue_exists = false;
- for (std::list<Piece>::const_iterator j = m_log.begin();
- j != m_log.end(); j++) {
+ for (std::deque<Piece>::const_iterator j = m_log.begin();
+ j != m_log.end(); ++j) {
const Piece &piece = *j;
float value = 0;
bool value_exists = false;
bool *m_force_fog_off;
f32 *m_fog_range;
Client *m_client;
+ bool m_fogEnabled;
public:
+ void onSettingsChange(const std::string &name)
+ {
+ if (name == "enable_fog")
+ m_fogEnabled = g_settings->getBool("enable_fog");
+ }
+
+ static void SettingsCallback(const std::string &name, void *userdata)
+ {
+ reinterpret_cast<GameGlobalShaderConstantSetter*>(userdata)->onSettingsChange(name);
+ }
+
GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off,
f32 *fog_range, Client *client) :
m_sky(sky),
m_force_fog_off(force_fog_off),
m_fog_range(fog_range),
m_client(client)
- {}
- ~GameGlobalShaderConstantSetter() {}
+ {
+ g_settings->registerChangedCallback("enable_fog", SettingsCallback, this);
+ m_fogEnabled = g_settings->getBool("enable_fog");
+ }
+
+ ~GameGlobalShaderConstantSetter()
+ {
+ g_settings->deregisterChangedCallback("enable_fog", SettingsCallback, this);
+ }
virtual void onSetConstants(video::IMaterialRendererServices *services,
bool is_highlevel)
// Fog distance
float fog_distance = 10000 * BS;
- if (g_settings->getBool("enable_fog") && !*m_force_fog_off)
+ if (m_fogEnabled && !*m_force_fog_off)
fog_distance = *m_fog_range;
services->setPixelShaderConstant("fogDistance", &fog_distance, 1);
services->setPixelShaderConstant("eyePosition", (irr::f32 *)&eye_position, 3);
services->setVertexShaderConstant("eyePosition", (irr::f32 *)&eye_position, 3);
+ v3f minimap_yaw_vec = m_client->getMapper()->getYawVec();
+ services->setPixelShaderConstant("yawVec", (irr::f32 *)&minimap_yaw_vec, 3);
+
// Uniform sampler layers
int layer0 = 0;
int layer1 = 1;
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
services->setPixelShaderConstant("baseTexture" , (irr::f32 *)&layer0, 1);
services->setPixelShaderConstant("normalTexture" , (irr::f32 *)&layer1, 1);
- services->setPixelShaderConstant("useNormalmap" , (irr::f32 *)&layer2, 1);
+ services->setPixelShaderConstant("textureFlags" , (irr::f32 *)&layer2, 1);
#else
services->setPixelShaderConstant("baseTexture" , (irr::s32 *)&layer0, 1);
services->setPixelShaderConstant("normalTexture" , (irr::s32 *)&layer1, 1);
- services->setPixelShaderConstant("useNormalmap" , (irr::s32 *)&layer2, 1);
+ services->setPixelShaderConstant("textureFlags" , (irr::s32 *)&layer2, 1);
#endif
}
};
std::string prediction = playeritem_def.node_placement_prediction;
INodeDefManager *nodedef = client.ndef();
ClientMap &map = client.getEnv().getClientMap();
+ MapNode node;
+ bool is_valid_position;
+
+ node = map.getNodeNoEx(nodepos, &is_valid_position);
+ if (!is_valid_position)
+ return false;
- if (prediction != "" && !nodedef->get(map.getNode(nodepos)).rightclickable) {
+ if (prediction != "" && !nodedef->get(node).rightclickable) {
verbosestream << "Node placement prediction for "
<< playeritem_def.name << " is "
<< prediction << std::endl;
v3s16 p = neighbourpos;
// Place inside node itself if buildable_to
- try {
- MapNode n_under = map.getNode(nodepos);
-
+ MapNode n_under = map.getNodeNoEx(nodepos, &is_valid_position);
+ if (is_valid_position)
+ {
if (nodedef->get(n_under).buildable_to)
p = nodepos;
- else if (!nodedef->get(map.getNode(p)).buildable_to)
- return false;
- } catch (InvalidPositionException &e) {}
+ else {
+ node = map.getNodeNoEx(p, &is_valid_position);
+ if (is_valid_position &&!nodedef->get(node).buildable_to)
+ return false;
+ }
+ }
// Find id of predicted node
content_t id;
else
pp = p + v3s16(0, -1, 0);
- if (!nodedef->get(map.getNode(pp)).walkable)
+ if (!nodedef->get(map.getNodeNoEx(pp)).walkable)
return false;
}
// Dont place node when player would be inside new node
// NOTE: This is to be eventually implemented by a mod as client-side Lua
if (!nodedef->get(n).walkable ||
+ g_settings->getBool("enable_build_where_you_stand") ||
(client.checkPrivilege("noclip") && g_settings->getBool("noclip")) ||
(nodedef->get(n).walkable &&
neighbourpos != player->getStandingNodePos() + v3s16(0, 1, 0) &&
#ifdef __ANDROID__
#define SIZE_TAG "size[11,5.5]"
#else
-#define SIZE_TAG "size[11,5.5,true]"
+#define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop
#endif
static void show_chat_menu(GUIFormSpecMenu **cur_formspec,
FORMSPEC_VERSION_STRING
SIZE_TAG
"field[3,2.35;6,0.5;f_text;;" + text + "]"
- "button_exit[4,3;3,0.5;btn_send;" + wide_to_narrow(wstrgettext("Proceed")) + "]"
+ "button_exit[4,3;3,0.5;btn_send;" + strgettext("Proceed") + "]"
;
/* Create menu */
std::string(FORMSPEC_VERSION_STRING) +
SIZE_TAG
"bgcolor[#320000b4;true]"
- "label[4.85,1.35;You died.]"
+ "label[4.85,1.35;" + gettext("You died.") + "]"
"button_exit[4,3;3,0.5;btn_respawn;" + gettext("Respawn") + "]"
;
bool singleplayermode)
{
#ifdef __ANDROID__
- std::string control_text = wide_to_narrow(wstrgettext("Default Controls:\n"
- "No menu visible:\n"
- "- single tap: button activate\n"
- "- double tap: place/use\n"
- "- slide finger: look around\n"
- "Menu/Inventory visible:\n"
- "- double tap (outside):\n"
- " -->close\n"
- "- touch stack, touch slot:\n"
- " --> move stack\n"
- "- touch&drag, tap 2nd finger\n"
- " --> place single item to slot\n"
- ));
+ std::string control_text = strgettext("Default Controls:\n"
+ "No menu visible:\n"
+ "- single tap: button activate\n"
+ "- double tap: place/use\n"
+ "- slide finger: look around\n"
+ "Menu/Inventory visible:\n"
+ "- double tap (outside):\n"
+ " -->close\n"
+ "- touch stack, touch slot:\n"
+ " --> move stack\n"
+ "- touch&drag, tap 2nd finger\n"
+ " --> place single item to slot\n"
+ );
#else
- std::string control_text = wide_to_narrow(wstrgettext("Default Controls:\n"
- "- WASD: move\n"
- "- Space: jump/climb\n"
- "- Shift: sneak/go down\n"
- "- Q: drop item\n"
- "- I: inventory\n"
- "- Mouse: turn/look\n"
- "- Mouse left: dig/punch\n"
- "- Mouse right: place/use\n"
- "- Mouse wheel: select item\n"
- "- T: chat\n"
- ));
+ std::string control_text = strgettext("Default Controls:\n"
+ "- WASD: move\n"
+ "- Space: jump/climb\n"
+ "- Shift: sneak/go down\n"
+ "- Q: drop item\n"
+ "- I: inventory\n"
+ "- Mouse: turn/look\n"
+ "- Mouse left: dig/punch\n"
+ "- Mouse right: place/use\n"
+ "- Mouse wheel: select item\n"
+ "- T: chat\n"
+ );
#endif
float ypos = singleplayermode ? 0.5 : 0.1;
os << FORMSPEC_VERSION_STRING << SIZE_TAG
<< "button_exit[4," << (ypos++) << ";3,0.5;btn_continue;"
- << wide_to_narrow(wstrgettext("Continue")) << "]";
+ << strgettext("Continue") << "]";
if (!singleplayermode) {
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_change_password;"
- << wide_to_narrow(wstrgettext("Change Password")) << "]";
+ << strgettext("Change Password") << "]";
}
+#ifndef __ANDROID__
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;"
- << wide_to_narrow(wstrgettext("Sound Volume")) << "]";
+ << strgettext("Sound Volume") << "]";
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_key_config;"
- << wide_to_narrow(wstrgettext("Change Keys")) << "]";
+ << strgettext("Change Keys") << "]";
+#endif
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_menu;"
- << wide_to_narrow(wstrgettext("Exit to Menu")) << "]";
+ << strgettext("Exit to Menu") << "]";
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_os;"
- << wide_to_narrow(wstrgettext("Exit to OS")) << "]"
+ << strgettext("Exit to OS") << "]"
<< "textarea[7.5,0.25;3.9,6.25;;" << control_text << ";]"
- << "textarea[0.4,0.25;3.5,6;;" << "Minetest\n"
- << minetest_build_info << "\n"
+ << "textarea[0.4,0.25;3.5,6;;" << PROJECT_NAME_C "\n"
+ << g_build_info << "\n"
<< "path_user = " << wrap_rows(porting::path_user, 20)
<< "\n;]";
LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU");
create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device, fs_src, txt_dst, NULL);
-
+ std::string con("btn_continue");
+ (*cur_formspec)->setFocus(con);
(*cur_formspec)->doPause = true;
}
/******************************************************************************/
static void updateChat(Client &client, f32 dtime, bool show_debug,
const v2u32 &screensize, bool show_chat, u32 show_profiler,
- ChatBackend &chat_backend, gui::IGUIStaticText *guitext_chat,
- gui::IGUIFont *font)
+ ChatBackend &chat_backend, gui::IGUIStaticText *guitext_chat)
{
// Add chat log output for errors to be shown in chat
- static LogOutputBuffer chat_log_error_buf(LMT_ERROR);
+ static LogOutputBuffer chat_log_error_buf(g_logger, LL_ERROR);
// Get new messages from error log buffer
while (!chat_log_error_buf.empty()) {
- chat_backend.addMessage(L"", narrow_to_wide(chat_log_error_buf.get()));
+ chat_backend.addMessage(L"", utf8_to_wide(chat_log_error_buf.get()));
}
// Get new messages from client
// Display all messages in a static text element
unsigned int recent_chat_count = chat_backend.getRecentBuffer().getLineCount();
std::wstring recent_chat = chat_backend.getRecentChat();
-
- // TODO replace by fontengine fcts
- unsigned int line_height = font->getDimension(L"Ay").Height + font->getKerningHeight();
+ unsigned int line_height = g_fontengine->getLineHeight();
guitext_chat->setText(recent_chat.c_str());
chat_y += line_height;
// first pass to calculate height of text to be set
- s32 width = std::min(font->getDimension(recent_chat.c_str()).Width + 10,
+ s32 width = std::min(g_fontengine->getTextWidth(recent_chat) + 10,
porting::getWindowSize().X - 20);
core::rect<s32> rect(10, chat_y, width, chat_y + porting::getWindowSize().Y);
guitext_chat->setRelativePosition(rect);
}
+/****************************************************************************
+ Fast key cache for main game loop
+ ****************************************************************************/
+
+/* This is faster than using getKeySetting with the tradeoff that functions
+ * using it must make sure that it's initialised before using it and there is
+ * no error handling (for example bounds checking). This is really intended for
+ * use only in the main running loop of the client (the_game()) where the faster
+ * (up to 10x faster) key lookup is an asset. Other parts of the codebase
+ * (e.g. formspecs) should continue using getKeySetting().
+ */
+struct KeyCache {
+
+ KeyCache() { populate(); }
+
+ enum {
+ // Player movement
+ KEYMAP_ID_FORWARD,
+ KEYMAP_ID_BACKWARD,
+ KEYMAP_ID_LEFT,
+ KEYMAP_ID_RIGHT,
+ KEYMAP_ID_JUMP,
+ KEYMAP_ID_SPECIAL1,
+ KEYMAP_ID_SNEAK,
+ KEYMAP_ID_AUTORUN,
+
+ // Other
+ KEYMAP_ID_DROP,
+ KEYMAP_ID_INVENTORY,
+ KEYMAP_ID_CHAT,
+ KEYMAP_ID_CMD,
+ KEYMAP_ID_CONSOLE,
+ KEYMAP_ID_MINIMAP,
+ KEYMAP_ID_FREEMOVE,
+ KEYMAP_ID_FASTMOVE,
+ KEYMAP_ID_NOCLIP,
+ KEYMAP_ID_CINEMATIC,
+ KEYMAP_ID_SCREENSHOT,
+ KEYMAP_ID_TOGGLE_HUD,
+ KEYMAP_ID_TOGGLE_CHAT,
+ KEYMAP_ID_TOGGLE_FORCE_FOG_OFF,
+ KEYMAP_ID_TOGGLE_UPDATE_CAMERA,
+ KEYMAP_ID_TOGGLE_DEBUG,
+ KEYMAP_ID_TOGGLE_PROFILER,
+ KEYMAP_ID_CAMERA_MODE,
+ KEYMAP_ID_INCREASE_VIEWING_RANGE,
+ KEYMAP_ID_DECREASE_VIEWING_RANGE,
+ KEYMAP_ID_RANGESELECT,
+
+ KEYMAP_ID_QUICKTUNE_NEXT,
+ KEYMAP_ID_QUICKTUNE_PREV,
+ KEYMAP_ID_QUICKTUNE_INC,
+ KEYMAP_ID_QUICKTUNE_DEC,
+
+ KEYMAP_ID_DEBUG_STACKS,
+
+ // Fake keycode for array size and internal checks
+ KEYMAP_INTERNAL_ENUM_COUNT
+
+
+ };
+
+ void populate();
+
+ KeyPress key[KEYMAP_INTERNAL_ENUM_COUNT];
+};
+
+void KeyCache::populate()
+{
+ key[KEYMAP_ID_FORWARD] = getKeySetting("keymap_forward");
+ key[KEYMAP_ID_BACKWARD] = getKeySetting("keymap_backward");
+ key[KEYMAP_ID_LEFT] = getKeySetting("keymap_left");
+ key[KEYMAP_ID_RIGHT] = getKeySetting("keymap_right");
+ key[KEYMAP_ID_JUMP] = getKeySetting("keymap_jump");
+ key[KEYMAP_ID_SPECIAL1] = getKeySetting("keymap_special1");
+ key[KEYMAP_ID_SNEAK] = getKeySetting("keymap_sneak");
+
+ key[KEYMAP_ID_AUTORUN] = getKeySetting("keymap_autorun");
+
+ key[KEYMAP_ID_DROP] = getKeySetting("keymap_drop");
+ key[KEYMAP_ID_INVENTORY] = getKeySetting("keymap_inventory");
+ key[KEYMAP_ID_CHAT] = getKeySetting("keymap_chat");
+ key[KEYMAP_ID_CMD] = getKeySetting("keymap_cmd");
+ key[KEYMAP_ID_CONSOLE] = getKeySetting("keymap_console");
+ key[KEYMAP_ID_MINIMAP] = getKeySetting("keymap_minimap");
+ key[KEYMAP_ID_FREEMOVE] = getKeySetting("keymap_freemove");
+ key[KEYMAP_ID_FASTMOVE] = getKeySetting("keymap_fastmove");
+ key[KEYMAP_ID_NOCLIP] = getKeySetting("keymap_noclip");
+ key[KEYMAP_ID_CINEMATIC] = getKeySetting("keymap_cinematic");
+ key[KEYMAP_ID_SCREENSHOT] = getKeySetting("keymap_screenshot");
+ key[KEYMAP_ID_TOGGLE_HUD] = getKeySetting("keymap_toggle_hud");
+ key[KEYMAP_ID_TOGGLE_CHAT] = getKeySetting("keymap_toggle_chat");
+ key[KEYMAP_ID_TOGGLE_FORCE_FOG_OFF]
+ = getKeySetting("keymap_toggle_force_fog_off");
+ key[KEYMAP_ID_TOGGLE_UPDATE_CAMERA]
+ = getKeySetting("keymap_toggle_update_camera");
+ key[KEYMAP_ID_TOGGLE_DEBUG]
+ = getKeySetting("keymap_toggle_debug");
+ key[KEYMAP_ID_TOGGLE_PROFILER]
+ = getKeySetting("keymap_toggle_profiler");
+ key[KEYMAP_ID_CAMERA_MODE]
+ = getKeySetting("keymap_camera_mode");
+ key[KEYMAP_ID_INCREASE_VIEWING_RANGE]
+ = getKeySetting("keymap_increase_viewing_range_min");
+ key[KEYMAP_ID_DECREASE_VIEWING_RANGE]
+ = getKeySetting("keymap_decrease_viewing_range_min");
+ key[KEYMAP_ID_RANGESELECT]
+ = getKeySetting("keymap_rangeselect");
+
+ key[KEYMAP_ID_QUICKTUNE_NEXT] = getKeySetting("keymap_quicktune_next");
+ key[KEYMAP_ID_QUICKTUNE_PREV] = getKeySetting("keymap_quicktune_prev");
+ key[KEYMAP_ID_QUICKTUNE_INC] = getKeySetting("keymap_quicktune_inc");
+ key[KEYMAP_ID_QUICKTUNE_DEC] = getKeySetting("keymap_quicktune_dec");
+
+ key[KEYMAP_ID_DEBUG_STACKS] = getKeySetting("keymap_print_debug_stacks");
+}
+
/****************************************************************************
- THE GAME
+
****************************************************************************/
const float object_hit_delay = 0.2;
* many functions that do require objects of thse types do not modify them
* (so they can be passed as a const qualified parameter)
*/
-
struct CameraOrientation {
f32 camera_yaw; // "right/left"
f32 camera_pitch; // "up/down"
};
-//TODO: Needs a better name because fog_range etc are included
-struct InteractParams {
+struct GameRunData {
u16 dig_index;
u16 new_playeritem;
PointedThing pointed_old;
bool digging;
bool ldown_for_dig;
bool left_punch;
+ bool update_wielded_item_trigger;
+ bool reset_jump_timer;
float nodig_delay_timer;
float dig_time;
float dig_time_complete;
u32 profiler_current_page;
u32 profiler_max_page; // Number of pages
+
+ float time_of_day;
+ float time_of_day_smooth;
};
struct Jitter {
bool invert_mouse;
bool show_chat;
bool show_hud;
+ bool show_minimap;
bool force_fog_off;
bool show_debug;
bool show_profiler_graph;
};
+/****************************************************************************
+ THE GAME
+ ****************************************************************************/
+
/* This is not intended to be a public class. If a public class becomes
* desirable then it may be better to create another 'wrapper' class that
* hides most of the stuff in this class (nothing in this class is required
* by any other file) but exposes the public methods/data only.
*/
-class MinetestApp
-{
+class Game {
public:
- MinetestApp();
- ~MinetestApp();
+ Game();
+ ~Game();
bool startup(bool *kill,
bool random_input,
InputHandler *input,
IrrlichtDevice *device,
- gui::IGUIFont *font,
const std::string &map_dir,
const std::string &playername,
const std::string &password,
// If address is "", local server is used and address is updated
std::string *address,
u16 port,
- std::wstring *error_message,
+ std::string &error_message,
+ bool *reconnect,
ChatBackend *chat_backend,
const SubgameSpec &gamespec, // Used for local game
bool simple_singleplayer_mode);
// Client creation
bool createClient(const std::string &playername,
- const std::string &password, std::string *address, u16 port,
- std::wstring *error_message);
- bool initGui(std::wstring *error_message);
+ const std::string &password, std::string *address, u16 port);
+ bool initGui();
// Client connection
bool connectToServer(const std::string &playername,
// Main loop
- void updateInteractTimers(InteractParams *args, f32 dtime);
+ void updateInteractTimers(GameRunData *runData, f32 dtime);
bool checkConnection();
bool handleCallbacks();
void processQueues();
+ void updateProfilers(const GameRunData &runData, const RunStats &stats,
+ const FpsControl &draw_times, f32 dtime);
void addProfilerGraphs(const RunStats &stats, const FpsControl &draw_times,
f32 dtime);
void updateStats(RunStats *stats, const FpsControl &draw_times, f32 dtime);
- void processUserInput(VolatileRunFlags *flags, InteractParams *interact_args,
+ void processUserInput(VolatileRunFlags *flags, GameRunData *runData,
f32 dtime);
void processKeyboardInput(VolatileRunFlags *flags,
float *statustext_time,
float *jump_timer,
+ bool *reset_jump_timer,
u32 *profiler_current_page,
u32 profiler_max_page);
void processItemSelection(u16 *new_playeritem);
void toggleFreeMoveAlt(float *statustext_time, float *jump_timer);
void toggleFast(float *statustext_time);
void toggleNoClip(float *statustext_time);
+ void toggleCinematic(float *statustext_time);
+ void toggleAutorun(float *statustext_time);
void toggleChat(float *statustext_time, bool *flag);
void toggleHud(float *statustext_time, bool *flag);
+ void toggleMinimap(float *statustext_time, bool *flag, bool show_hud,
+ bool shift_pressed);
void toggleFog(float *statustext_time, bool *flag);
void toggleDebug(float *statustext_time, bool *show_debug,
bool *show_profiler_graph);
void toggleFullViewRange(float *statustext_time);
void updateCameraDirection(CameraOrientation *cam, VolatileRunFlags *flags);
+ void updateCameraOrientation(CameraOrientation *cam,
+ const VolatileRunFlags &flags);
void updatePlayerControl(const CameraOrientation &cam);
void step(f32 *dtime);
void processClientEvents(CameraOrientation *cam, float *damage_flash);
void updateCamera(VolatileRunFlags *flags, u32 busy_time, f32 dtime,
float time_from_last_punch);
void updateSound(f32 dtime);
- void processPlayerInteraction(std::vector<aabb3f> &highlight_boxes,
- InteractParams *interactArgs, f32 dtime, bool show_hud,
+ void processPlayerInteraction(GameRunData *runData, f32 dtime, bool show_hud,
bool show_debug);
- void handlePointingAtNode(InteractParams *interactArgs,
+ void handlePointingAtNothing(GameRunData *runData, const ItemStack &playerItem);
+ void handlePointingAtNode(GameRunData *runData,
const PointedThing &pointed, const ItemDefinition &playeritem_def,
const ToolCapabilities &playeritem_toolcap, f32 dtime);
- void handlePointingAtObject(InteractParams *interactArgs,
+ void handlePointingAtObject(GameRunData *runData,
const PointedThing &pointed, const ItemStack &playeritem,
const v3f &player_position, bool show_debug);
- void handleDigging(InteractParams *interactArgs, const PointedThing &pointed,
+ void handleDigging(GameRunData *runData, const PointedThing &pointed,
const v3s16 &nodepos, const ToolCapabilities &playeritem_toolcap,
f32 dtime);
- void updateFrame(std::vector<aabb3f> &highlight_boxes, ProfilerGraph *graph,
- RunStats *stats, InteractParams *interactArgs,
+ void updateFrame(ProfilerGraph *graph, RunStats *stats, GameRunData *runData,
f32 dtime, const VolatileRunFlags &flags, const CameraOrientation &cam);
- void updateGui(float *statustext_time, const RunStats &stats, f32 dtime,
- const VolatileRunFlags &flags, const CameraOrientation &cam);
+ void updateGui(float *statustext_time, const RunStats &stats,
+ const GameRunData& runData, f32 dtime, const VolatileRunFlags &flags,
+ const CameraOrientation &cam);
void updateProfilerGraphs(ProfilerGraph *graph);
// Misc
- void limitFps(FpsControl *params, f32 *dtime);
+ void limitFps(FpsControl *fps_timings, f32 *dtime);
- void showOverlayMessage(const char *msg, float dtime, int percent,
+ void showOverlayMessage(const wchar_t *msg, float dtime, int percent,
bool draw_clouds = true);
+ static void settingChangedCallback(const std::string &setting_name, void *data);
+ void readSettings();
+
private:
InputHandler *input;
Client *client;
Server *server;
- gui::IGUIFont *font;
-
IWritableTextureSource *texture_src;
IWritableShaderSource *shader_src;
Sky *sky; // Free using ->Drop()
Inventory *local_inventory;
Hud *hud;
+ Mapper *mapper;
/* 'cache'
This class does take ownership/responsibily for cleaning up etc of any of
IrrlichtDevice *device;
video::IVideoDriver *driver;
scene::ISceneManager *smgr;
- u32 text_height;
bool *kill;
- std::wstring *error_message;
+ std::string *error_message;
+ bool *reconnect_requested;
IGameDef *gamedef; // Convenience (same as *client)
scene::ISceneNode *skybox;
std::wstring infotext;
std::wstring statustext;
+
+ KeyCache keycache;
+
+ IntervalLimiter profiler_interval;
+
+ /*
+ * TODO: Local caching of settings is not optimal and should at some stage
+ * be updated to use a global settings object for getting thse values
+ * (as opposed to the this local caching). This can be addressed in
+ * a later release.
+ */
+ bool m_cache_doubletap_jump;
+ bool m_cache_enable_clouds;
+ bool m_cache_enable_particles;
+ bool m_cache_enable_fog;
+ f32 m_cache_mouse_sensitivity;
+ f32 m_repeat_right_click_time;
+
+#ifdef __ANDROID__
+ bool m_cache_hold_aux1;
+#endif
+
};
-MinetestApp::MinetestApp() :
+Game::Game() :
client(NULL),
server(NULL),
- font(NULL),
texture_src(NULL),
shader_src(NULL),
itemdef_manager(NULL),
clouds(NULL),
sky(NULL),
local_inventory(NULL),
- hud(NULL)
+ hud(NULL),
+ mapper(NULL)
{
+ g_settings->registerChangedCallback("doubletap_jump",
+ &settingChangedCallback, this);
+ g_settings->registerChangedCallback("enable_clouds",
+ &settingChangedCallback, this);
+ g_settings->registerChangedCallback("enable_particles",
+ &settingChangedCallback, this);
+ g_settings->registerChangedCallback("enable_fog",
+ &settingChangedCallback, this);
+ g_settings->registerChangedCallback("mouse_sensitivity",
+ &settingChangedCallback, this);
+ g_settings->registerChangedCallback("repeat_rightclick_time",
+ &settingChangedCallback, this);
+
+ readSettings();
+
+#ifdef __ANDROID__
+ m_cache_hold_aux1 = false; // This is initialised properly later
+#endif
}
MinetestApp Public
****************************************************************************/
-MinetestApp::~MinetestApp()
+Game::~Game()
{
delete client;
delete soundmaker;
delete draw_control;
extendedResourceCleanup();
+
+ g_settings->deregisterChangedCallback("doubletap_jump",
+ &settingChangedCallback, this);
+ g_settings->deregisterChangedCallback("enable_clouds",
+ &settingChangedCallback, this);
+ g_settings->deregisterChangedCallback("enable_particles",
+ &settingChangedCallback, this);
+ g_settings->deregisterChangedCallback("enable_fog",
+ &settingChangedCallback, this);
+ g_settings->deregisterChangedCallback("mouse_sensitivity",
+ &settingChangedCallback, this);
+ g_settings->deregisterChangedCallback("repeat_rightclick_time",
+ &settingChangedCallback, this);
}
-bool MinetestApp::startup(bool *kill,
+bool Game::startup(bool *kill,
bool random_input,
InputHandler *input,
IrrlichtDevice *device,
- gui::IGUIFont *font,
const std::string &map_dir,
const std::string &playername,
const std::string &password,
std::string *address, // can change if simple_singleplayer_mode
u16 port,
- std::wstring *error_message,
+ std::string &error_message,
+ bool *reconnect,
ChatBackend *chat_backend,
const SubgameSpec &gamespec,
bool simple_singleplayer_mode)
{
// "cache"
- this->device = device;
- this->font = font;
- this->kill = kill;
- this->error_message = error_message;
- this->random_input = random_input;
- this->input = input;
- this->chat_backend = chat_backend;
+ this->device = device;
+ this->kill = kill;
+ this->error_message = &error_message;
+ this->reconnect_requested = reconnect;
+ this->random_input = random_input;
+ this->input = input;
+ this->chat_backend = chat_backend;
this->simple_singleplayer_mode = simple_singleplayer_mode;
driver = device->getVideoDriver();
smgr = device->getSceneManager();
- text_height = font->getDimension(L"Random test string").Height;
+
+ smgr->getParameters()->setAttribute(scene::OBJ_LOADER_IGNORE_MATERIAL_FILES, true);
if (!init(map_dir, address, port, gamespec))
return false;
- if (!createClient(playername, password, address, port, error_message))
+ if (!createClient(playername, password, address, port))
return false;
return true;
}
-void MinetestApp::run()
+void Game::run()
{
ProfilerGraph graph;
RunStats stats = { 0 };
+ CameraOrientation cam_view_target = { 0 };
CameraOrientation cam_view = { 0 };
- InteractParams interactArgs = { 0 };
+ GameRunData runData = { 0 };
FpsControl draw_times = { 0 };
VolatileRunFlags flags = { 0 };
f32 dtime; // in seconds
- interactArgs.time_from_last_punch = 10.0;
- interactArgs.profiler_max_page = 3;
+ runData.time_from_last_punch = 10.0;
+ runData.profiler_max_page = 3;
+ runData.update_wielded_item_trigger = true;
flags.show_chat = true;
flags.show_hud = true;
-
- /* FIXME: This should be updated every iteration, or not stored locally
- now that key settings can be changed in-game */
+ flags.show_minimap = g_settings->getBool("enable_minimap");
+ flags.show_debug = g_settings->getBool("show_debug");
flags.invert_mouse = g_settings->getBool("invert_mouse");
+ flags.first_loop_after_window_activation = true;
/* Clear the profiler */
Profiler::GraphValues dummyvalues;
shader_src->addGlobalConstantSetter(new GameGlobalShaderConstantSetter(
sky,
&flags.force_fog_off,
- &interactArgs.fog_range,
+ &runData.fog_range,
client));
- while (device->run() && !(*kill || g_gamecallback->shutdown_requested)) {
+ set_light_table(g_settings->getFloat("display_gamma"));
+
+#ifdef __ANDROID__
+ m_cache_hold_aux1 = g_settings->getBool("fast_move")
+ && client->checkPrivilege("fast");
+#endif
+
+ while (device->run()
+ && !(*kill || g_gamecallback->shutdown_requested
+ || (server && server->getShutdownRequested()))) {
/* Must be called immediately after a device->run() call because it
* uses device->getTimer()->getTime()
limitFps(&draw_times, &dtime);
updateStats(&stats, draw_times, dtime);
- updateInteractTimers(&interactArgs, dtime);
+ updateInteractTimers(&runData, dtime);
if (!checkConnection())
break;
processQueues();
- std::vector<aabb3f> highlight_boxes;
-
infotext = L"";
hud->resizeHotbar();
- addProfilerGraphs(stats, draw_times, dtime);
- processUserInput(&flags, &interactArgs, dtime);
+
+ updateProfilers(runData, stats, draw_times, dtime);
+ processUserInput(&flags, &runData, dtime);
// Update camera before player movement to avoid camera lag of one frame
- updateCameraDirection(&cam_view, &flags);
+ updateCameraDirection(&cam_view_target, &flags);
+ float cam_smoothing = 0;
+ if (g_settings->getBool("cinematic"))
+ cam_smoothing = 1 - g_settings->getFloat("cinematic_camera_smoothing");
+ else
+ cam_smoothing = 1 - g_settings->getFloat("camera_smoothing");
+ cam_smoothing = rangelim(cam_smoothing, 0.01f, 1.0f);
+ cam_view.camera_yaw += (cam_view_target.camera_yaw -
+ cam_view.camera_yaw) * cam_smoothing;
+ cam_view.camera_pitch += (cam_view_target.camera_pitch -
+ cam_view.camera_pitch) * cam_smoothing;
updatePlayerControl(cam_view);
step(&dtime);
- processClientEvents(&cam_view, &interactArgs.damage_flash);
+ processClientEvents(&cam_view_target, &runData.damage_flash);
updateCamera(&flags, draw_times.busy_time, dtime,
- interactArgs.time_from_last_punch);
+ runData.time_from_last_punch);
updateSound(dtime);
- processPlayerInteraction(highlight_boxes, &interactArgs, dtime,
- flags.show_hud, flags.show_debug);
- updateFrame(highlight_boxes, &graph, &stats, &interactArgs, dtime,
- flags, cam_view);
+ processPlayerInteraction(&runData, dtime, flags.show_hud,
+ flags.show_debug);
+ updateFrame(&graph, &stats, &runData, dtime, flags, cam_view);
updateProfilerGraphs(&graph);
+
+ // Update if minimap has been disabled by the server
+ flags.show_minimap &= !client->isMinimapDisabledByServer();
}
}
-void MinetestApp::shutdown()
+void Game::shutdown()
{
- showOverlayMessage("Shutting down...", 0, 0, false);
+ if (g_settings->get("3d_mode") == "pageflip") {
+ driver->setRenderTarget(irr::video::ERT_STEREO_BOTH_BUFFERS);
+ }
+
+ showOverlayMessage(wgettext("Shutting down..."), 0, 0, false);
if (clouds)
clouds->drop();
if (sky)
sky->drop();
- clear_particles();
-
/* cleanup menus */
while (g_menumgr.menuCount() > 0) {
g_menumgr.m_stack.front()->setVisible(false);
}
-
+/****************************************************************************/
/****************************************************************************
Startup
****************************************************************************/
+/****************************************************************************/
-bool MinetestApp::init(
+bool Game::init(
const std::string &map_dir,
std::string *address,
u16 port,
const SubgameSpec &gamespec)
{
- showOverlayMessage("Loading...", 0, 0);
+ showOverlayMessage(wgettext("Loading..."), 0, 0);
texture_src = createTextureSource(device);
shader_src = createShaderSource(device);
return true;
}
-bool MinetestApp::initSound()
+bool Game::initSound()
{
#if USE_SOUND
if (g_settings->getBool("enable_sound")) {
return true;
}
-bool MinetestApp::createSingleplayerServer(const std::string map_dir,
+bool Game::createSingleplayerServer(const std::string map_dir,
const SubgameSpec &gamespec, u16 port, std::string *address)
{
- showOverlayMessage("Creating server...", 0, 25);
+ showOverlayMessage(wgettext("Creating server..."), 0, 5);
std::string bind_str = g_settings->get("bind_address");
Address bind_addr(0, 0, 0, 0, port);
try {
bind_addr.Resolve(bind_str.c_str());
- *address = bind_str;
} catch (ResolveError &e) {
infostream << "Resolving bind address \"" << bind_str
<< "\" failed: " << e.what()
}
if (bind_addr.isIPv6() && !g_settings->getBool("enable_ipv6")) {
- *error_message = L"Unable to listen on " +
- narrow_to_wide(bind_addr.serializeString()) +
- L" because IPv6 is disabled";
- errorstream << wide_to_narrow(*error_message) << std::endl;
+ *error_message = "Unable to listen on " +
+ bind_addr.serializeString() +
+ " because IPv6 is disabled";
+ errorstream << *error_message << std::endl;
return false;
}
return true;
}
-bool MinetestApp::createClient(const std::string &playername,
- const std::string &password, std::string *address, u16 port,
- std::wstring *error_message)
+bool Game::createClient(const std::string &playername,
+ const std::string &password, std::string *address, u16 port)
{
- showOverlayMessage("Creating client...", 0, 50);
+ showOverlayMessage(wgettext("Creating client..."), 0, 10);
draw_control = new MapDrawControl;
if (!draw_control)
return false;
if (!could_connect) {
- if (*error_message == L"" && !connect_aborted) {
+ if (error_message->empty() && !connect_aborted) {
// Should not happen if error messages are set properly
- *error_message = L"Connection failed for unknown reason";
- errorstream << wide_to_narrow(*error_message) << std::endl;
+ *error_message = "Connection failed for unknown reason";
+ errorstream << *error_message << std::endl;
}
return false;
}
if (!getServerContent(&connect_aborted)) {
- if (*error_message == L"" && !connect_aborted) {
+ if (error_message->empty() && !connect_aborted) {
// Should not happen if error messages are set properly
- *error_message = L"Connection failed for unknown reason";
- errorstream << wide_to_narrow(*error_message) << std::endl;
+ *error_message = "Connection failed for unknown reason";
+ errorstream << *error_message << std::endl;
}
return false;
}
// Update cached textures, meshes and materials
- client->afterContentReceived(device, font);
+ client->afterContentReceived(device);
/* Camera
*/
/* Clouds
*/
- if (g_settings->getBool("enable_clouds")) {
+ if (m_cache_enable_clouds) {
clouds = new Clouds(smgr->getRootSceneNode(), smgr, -1, time(0));
if (!clouds) {
- *error_message = L"Memory allocation error";
- *error_message += narrow_to_wide(" (clouds)");
- errorstream << wide_to_narrow(*error_message) << std::endl;
+ *error_message = "Memory allocation error (clouds)";
+ errorstream << *error_message << std::endl;
return false;
}
}
/* Skybox
*/
- sky = new Sky(smgr->getRootSceneNode(), smgr, -1);
+ sky = new Sky(smgr->getRootSceneNode(), smgr, -1, texture_src);
skybox = NULL; // This is used/set later on in the main run loop
local_inventory = new Inventory(itemdef_manager);
if (!(sky && local_inventory)) {
- *error_message = L"Memory allocation error";
- *error_message += narrow_to_wide(" (sky or local inventory)");
- errorstream << wide_to_narrow(*error_message) << std::endl;
+ *error_message = "Memory allocation error (sky or local inventory)";
+ errorstream << *error_message << std::endl;
return false;
}
crack_animation_length = 5;
}
- if (!initGui(error_message))
+ if (!initGui())
return false;
/* Set window caption
*/
- core::stringw str = L"Minetest [";
+ std::wstring str = utf8_to_wide(PROJECT_NAME_C);
+ str += L" [";
str += driver->getName();
- str += "]";
+ str += L"]";
device->setWindowCaption(str.c_str());
LocalPlayer *player = client->getEnv().getLocalPlayer();
player->hurt_tilt_timer = 0;
player->hurt_tilt_strength = 0;
- hud = new Hud(driver, smgr, guienv, font, text_height, gamedef,
- player, local_inventory);
+ hud = new Hud(driver, smgr, guienv, gamedef, player, local_inventory);
if (!hud) {
- *error_message = L"Memory error: could not create HUD";
- errorstream << wide_to_narrow(*error_message) << std::endl;
+ *error_message = "Memory error: could not create HUD";
+ errorstream << *error_message << std::endl;
return false;
}
+ mapper = client->getMapper();
+ mapper->setMinimapMode(MINIMAP_MODE_OFF);
+
return true;
}
-bool MinetestApp::initGui(std::wstring *error_message)
+bool Game::initGui()
{
// First line of debug text
guitext = guienv->addStaticText(
- L"Minetest",
+ utf8_to_wide(PROJECT_NAME_C).c_str(),
core::rect<s32>(0, 0, 0, 0),
false, false, guiroot);
// Object infos are shown in this
guitext_info = guienv->addStaticText(
L"",
- core::rect<s32>(0, 0, 400, text_height * 5 + 5) + v2s32(100, 200),
+ core::rect<s32>(0, 0, 400, g_fontengine->getTextHeight() * 5 + 5) + v2s32(100, 200),
false, true, guiroot);
// Status text (displays info when showing and hiding GUI stuff, etc.)
gui_chat_console = new GUIChatConsole(guienv, guienv->getRootGUIElement(),
-1, chat_backend, client);
if (!gui_chat_console) {
- *error_message = L"Could not allocate memory for chat console";
- errorstream << wide_to_narrow(*error_message) << std::endl;
+ *error_message = "Could not allocate memory for chat console";
+ errorstream << *error_message << std::endl;
return false;
}
#ifdef HAVE_TOUCHSCREENGUI
if (g_touchscreengui)
- g_touchscreengui->init(tsrc, porting::getDisplayDensity());
+ g_touchscreengui->init(texture_src);
#endif
return true;
}
-bool MinetestApp::connectToServer(const std::string &playername,
+bool Game::connectToServer(const std::string &playername,
const std::string &password, std::string *address, u16 port,
bool *connect_ok, bool *aborted)
{
- showOverlayMessage("Resolving address...", 0, 75);
+ *connect_ok = false; // Let's not be overly optimistic
+ *aborted = false;
+ bool local_server_mode = false;
+
+ showOverlayMessage(wgettext("Resolving address..."), 0, 15);
Address connect_address(0, 0, 0, 0, port);
} else {
connect_address.setAddress(127, 0, 0, 1);
}
+ local_server_mode = true;
}
} catch (ResolveError &e) {
- *error_message = L"Couldn't resolve address: " + narrow_to_wide(e.what());
- errorstream << wide_to_narrow(*error_message) << std::endl;
+ *error_message = std::string("Couldn't resolve address: ") + e.what();
+ errorstream << *error_message << std::endl;
return false;
}
if (connect_address.isIPv6() && !g_settings->getBool("enable_ipv6")) {
- *error_message = L"Unable to connect to " +
- narrow_to_wide(connect_address.serializeString()) +
- L" because IPv6 is disabled";
- errorstream << wide_to_narrow(*error_message) << std::endl;
+ *error_message = "Unable to connect to " +
+ connect_address.serializeString() +
+ " because IPv6 is disabled";
+ errorstream << *error_message << std::endl;
return false;
}
- client = new Client(device, playername.c_str(), password, *draw_control,
- texture_src, shader_src, itemdef_manager, nodedef_manager, sound,
- eventmgr, connect_address.isIPv6());
+ client = new Client(device,
+ playername.c_str(), password,
+ *draw_control, texture_src, shader_src,
+ itemdef_manager, nodedef_manager, sound, eventmgr,
+ connect_address.isIPv6());
if (!client)
return false;
gamedef = client; // Client acts as our GameDef
-
infostream << "Connecting to server at ";
connect_address.print(&infostream);
infostream << std::endl;
- client->connect(connect_address);
-
+ client->connect(connect_address, *address,
+ simple_singleplayer_mode || local_server_mode);
/*
Wait for server to accept connection
input->clear();
FpsControl fps_control = { 0 };
- f32 dtime; // in seconds
+ f32 dtime;
+ f32 wait_time = 0; // in seconds
+
+ fps_control.last_time = device->getTimer()->getTime();
while (device->run()) {
// Break conditions
if (client->accessDenied()) {
- *error_message = L"Access denied. Reason: "
+ *error_message = "Access denied. Reason: "
+ client->accessDeniedReason();
- errorstream << wide_to_narrow(*error_message) << std::endl;
+ *reconnect_requested = client->reconnectRequested();
+ errorstream << *error_message << std::endl;
break;
}
break;
}
+ wait_time += dtime;
+ // Only time out if we aren't waiting for the server we started
+ if ((*address != "") && (wait_time > 10)) {
+ *error_message = "Connection timed out.";
+ errorstream << *error_message << std::endl;
+ break;
+ }
+
// Update status
- showOverlayMessage("Connecting to server...", dtime, 100);
+ showOverlayMessage(wgettext("Connecting to server..."), dtime, 20);
}
} catch (con::PeerNotFoundException &e) {
// TODO: Should something be done here? At least an info/error
return true;
}
-bool MinetestApp::getServerContent(bool *aborted)
+bool Game::getServerContent(bool *aborted)
{
input->clear();
FpsControl fps_control = { 0 };
f32 dtime; // in seconds
+ fps_control.last_time = device->getTimer()->getTime();
+
while (device->run()) {
limitFps(&fps_control, &dtime);
}
// Error conditions
- if (client->accessDenied()) {
- *error_message = L"Access denied. Reason: "
- + client->accessDeniedReason();
- errorstream << wide_to_narrow(*error_message) << std::endl;
+ if (!checkConnection())
return false;
- }
if (client->getState() < LC_Init) {
- *error_message = L"Client disconnected";
- errorstream << wide_to_narrow(*error_message) << std::endl;
+ *error_message = "Client disconnected";
+ errorstream << *error_message << std::endl;
return false;
}
}
// Display status
- int progress = 0;
+ int progress = 25;
if (!client->itemdefReceived()) {
- wchar_t *text = wgettext("Item definitions...");
- progress = 0;
- draw_load_screen(text, device, guienv, font, dtime, progress);
+ const wchar_t *text = wgettext("Item definitions...");
+ progress = 25;
+ draw_load_screen(text, device, guienv, dtime, progress);
delete[] text;
} else if (!client->nodedefReceived()) {
- wchar_t *text = wgettext("Node definitions...");
- progress = 25;
- draw_load_screen(text, device, guienv, font, dtime, progress);
+ const wchar_t *text = wgettext("Node definitions...");
+ progress = 30;
+ draw_load_screen(text, device, guienv, dtime, progress);
delete[] text;
} else {
std::stringstream message;
if ((USE_CURL == 0) ||
(!g_settings->getBool("enable_remote_media_server"))) {
float cur = client->getCurRate();
- std::string cur_unit = gettext(" KB/s");
+ std::string cur_unit = gettext("KiB/s");
if (cur > 900) {
cur /= 1024.0;
- cur_unit = gettext(" MB/s");
+ cur_unit = gettext("MiB/s");
}
- message << " ( " << cur << cur_unit << " )";
+ message << " (" << cur << ' ' << cur_unit << ")";
}
- progress = 50 + client->mediaReceiveProgress() * 50 + 0.5;
- draw_load_screen(narrow_to_wide(message.str().c_str()), device,
- guienv, font, dtime, progress);
+ progress = 30 + client->mediaReceiveProgress() * 35 + 0.5;
+ draw_load_screen(utf8_to_wide(message.str()), device,
+ guienv, dtime, progress);
}
}
}
-
+/****************************************************************************/
/****************************************************************************
Run
****************************************************************************/
+/****************************************************************************/
-inline void MinetestApp::updateInteractTimers(InteractParams *args, f32 dtime)
+inline void Game::updateInteractTimers(GameRunData *runData, f32 dtime)
{
- if (args->nodig_delay_timer >= 0)
- args->nodig_delay_timer -= dtime;
+ if (runData->nodig_delay_timer >= 0)
+ runData->nodig_delay_timer -= dtime;
- if (args->object_hit_delay_timer >= 0)
- args->object_hit_delay_timer -= dtime;
+ if (runData->object_hit_delay_timer >= 0)
+ runData->object_hit_delay_timer -= dtime;
- args->time_from_last_punch += dtime;
+ runData->time_from_last_punch += dtime;
}
-/* returns false if app should exit, otherwise true
+/* returns false if game should exit, otherwise true
*/
-inline bool MinetestApp::checkConnection()
+inline bool Game::checkConnection()
{
if (client->accessDenied()) {
- *error_message = L"Access denied. Reason: "
+ *error_message = "Access denied. Reason: "
+ client->accessDeniedReason();
- errorstream << wide_to_narrow(*error_message) << std::endl;
+ *reconnect_requested = client->reconnectRequested();
+ errorstream << *error_message << std::endl;
return false;
}
}
-/* returns false if app should exit, otherwise true
+/* returns false if game should exit, otherwise true
*/
-inline bool MinetestApp::handleCallbacks()
+inline bool Game::handleCallbacks()
{
if (g_gamecallback->disconnect_requested) {
g_gamecallback->disconnect_requested = false;
g_gamecallback->keyconfig_requested = false;
}
+ if (g_gamecallback->keyconfig_changed) {
+ keycache.populate(); // update the cache with new settings
+ g_gamecallback->keyconfig_changed = false;
+ }
+
return true;
}
-void MinetestApp::processQueues()
+void Game::processQueues()
{
texture_src->processQueue();
itemdef_manager->processQueue(gamedef);
}
-void MinetestApp::addProfilerGraphs(const RunStats &stats,
+void Game::updateProfilers(const GameRunData &runData, const RunStats &stats,
+ const FpsControl &draw_times, f32 dtime)
+{
+ float profiler_print_interval =
+ g_settings->getFloat("profiler_print_interval");
+ bool print_to_log = true;
+
+ if (profiler_print_interval == 0) {
+ print_to_log = false;
+ profiler_print_interval = 5;
+ }
+
+ if (profiler_interval.step(dtime, profiler_print_interval)) {
+ if (print_to_log) {
+ infostream << "Profiler:" << std::endl;
+ g_profiler->print(infostream);
+ }
+
+ update_profiler_gui(guitext_profiler, g_fontengine,
+ runData.profiler_current_page, runData.profiler_max_page,
+ driver->getScreenSize().Height);
+
+ g_profiler->clear();
+ }
+
+ addProfilerGraphs(stats, draw_times, dtime);
+}
+
+
+void Game::addProfilerGraphs(const RunStats &stats,
const FpsControl &draw_times, f32 dtime)
{
g_profiler->graphAdd("mainloop_other",
}
-void MinetestApp::updateStats(RunStats *stats, const FpsControl &draw_times,
+void Game::updateStats(RunStats *stats, const FpsControl &draw_times,
f32 dtime)
{
Input handling
****************************************************************************/
-void MinetestApp::processUserInput(VolatileRunFlags *flags,
- InteractParams *interact_args, f32 dtime)
+void Game::processUserInput(VolatileRunFlags *flags,
+ GameRunData *runData, f32 dtime)
{
// Reset input if window not active or some menu is active
if (device->isWindowActive() == false
|| noMenuActive() == false
|| guienv->hasFocus(gui_chat_console)) {
input->clear();
+#ifdef HAVE_TOUCHSCREENGUI
+ g_touchscreengui->hide();
+#endif
+ }
+#ifdef HAVE_TOUCHSCREENGUI
+ 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->step(dtime);
}
+#endif
if (!guienv->hasFocus(gui_chat_console) && gui_chat_console->isOpen()) {
gui_chat_console->closeConsoleAtOnce();
// Input handler step() (used by the random input generator)
input->step(dtime);
-#ifdef HAVE_TOUCHSCREENGUI
-
- if (g_touchscreengui) {
- g_touchscreengui->step(dtime);
- }
-
-#endif
#ifdef __ANDROID__
if (current_formspec != 0)
#endif
// Increase timer for double tap of "keymap_jump"
- if (g_settings->getBool("doubletap_jump") && interact_args->jump_timer <= 0.2)
- interact_args->jump_timer += dtime;
+ if (m_cache_doubletap_jump && runData->jump_timer <= 0.2)
+ runData->jump_timer += dtime;
processKeyboardInput(
flags,
- &interact_args->statustext_time,
- &interact_args->jump_timer,
- &interact_args->profiler_current_page,
- interact_args->profiler_max_page);
+ &runData->statustext_time,
+ &runData->jump_timer,
+ &runData->reset_jump_timer,
+ &runData->profiler_current_page,
+ runData->profiler_max_page);
- processItemSelection(&interact_args->new_playeritem);
+ processItemSelection(&runData->new_playeritem);
}
-void MinetestApp::processKeyboardInput(VolatileRunFlags *flags,
+void Game::processKeyboardInput(VolatileRunFlags *flags,
float *statustext_time,
float *jump_timer,
+ bool *reset_jump_timer,
u32 *profiler_current_page,
u32 profiler_max_page)
{
- if (input->wasKeyDown(getKeySetting("keymap_drop"))) {
+
+ //TimeTaker tt("process kybd input", NULL, PRECISION_NANO);
+
+ if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_DROP])) {
dropSelectedItem();
- } else if (input->wasKeyDown(getKeySetting("keymap_inventory"))) {
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_AUTORUN])) {
+ toggleAutorun(statustext_time);
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_INVENTORY])) {
openInventory();
} else if (input->wasKeyDown(EscapeKey) || input->wasKeyDown(CancelKey)) {
show_pause_menu(¤t_formspec, client, gamedef, texture_src, device,
simple_singleplayer_mode);
- } else if (input->wasKeyDown(getKeySetting("keymap_chat"))) {
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CHAT])) {
show_chat_menu(¤t_formspec, client, gamedef, texture_src, device,
client, "");
- } else if (input->wasKeyDown(getKeySetting("keymap_cmd"))) {
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CMD])) {
show_chat_menu(¤t_formspec, client, gamedef, texture_src, device,
client, "/");
- } else if (input->wasKeyDown(getKeySetting("keymap_console"))) {
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CONSOLE])) {
openConsole();
- } else if (input->wasKeyDown(getKeySetting("keymap_freemove"))) {
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_FREEMOVE])) {
toggleFreeMove(statustext_time);
- } else if (input->wasKeyDown(getKeySetting("keymap_jump"))) {
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_JUMP])) {
toggleFreeMoveAlt(statustext_time, jump_timer);
- } else if (input->wasKeyDown(getKeySetting("keymap_fastmove"))) {
+ *reset_jump_timer = true;
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_FASTMOVE])) {
toggleFast(statustext_time);
- } else if (input->wasKeyDown(getKeySetting("keymap_noclip"))) {
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_NOCLIP])) {
toggleNoClip(statustext_time);
- } else if (input->wasKeyDown(getKeySetting("keymap_screenshot"))) {
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CINEMATIC])) {
+ toggleCinematic(statustext_time);
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_SCREENSHOT])) {
client->makeScreenshot(device);
- } else if (input->wasKeyDown(getKeySetting("keymap_toggle_hud"))) {
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_HUD])) {
toggleHud(statustext_time, &flags->show_hud);
- } else if (input->wasKeyDown(getKeySetting("keymap_toggle_chat"))) {
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_MINIMAP])) {
+ toggleMinimap(statustext_time, &flags->show_minimap, flags->show_hud,
+ input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_SNEAK]));
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_CHAT])) {
toggleChat(statustext_time, &flags->show_chat);
- } else if (input->wasKeyDown(getKeySetting("keymap_toggle_force_fog_off"))) {
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_FORCE_FOG_OFF])) {
toggleFog(statustext_time, &flags->force_fog_off);
- } else if (input->wasKeyDown(getKeySetting("keymap_toggle_update_camera"))) {
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_UPDATE_CAMERA])) {
toggleUpdateCamera(statustext_time, &flags->disable_camera_update);
- } else if (input->wasKeyDown(getKeySetting("keymap_toggle_debug"))) {
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_DEBUG])) {
toggleDebug(statustext_time, &flags->show_debug, &flags->show_profiler_graph);
- } else if (input->wasKeyDown(getKeySetting("keymap_toggle_profiler"))) {
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_TOGGLE_PROFILER])) {
toggleProfiler(statustext_time, profiler_current_page, profiler_max_page);
- } else if (input->wasKeyDown(getKeySetting("keymap_increase_viewing_range_min"))) {
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_INCREASE_VIEWING_RANGE])) {
increaseViewRange(statustext_time);
- } else if (input->wasKeyDown(getKeySetting("keymap_decrease_viewing_range_min"))) {
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_DECREASE_VIEWING_RANGE])) {
decreaseViewRange(statustext_time);
- } else if (input->wasKeyDown(getKeySetting("keymap_rangeselect"))) {
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_RANGESELECT])) {
toggleFullViewRange(statustext_time);
- }
-
- // Handle QuicktuneShortcutter
- if (input->wasKeyDown(getKeySetting("keymap_quicktune_next")))
+ } else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_NEXT]))
quicktune->next();
- else if (input->wasKeyDown(getKeySetting("keymap_quicktune_prev")))
+ else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_PREV]))
quicktune->prev();
- else if (input->wasKeyDown(getKeySetting("keymap_quicktune_inc")))
+ else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_INC]))
quicktune->inc();
- else if (input->wasKeyDown(getKeySetting("keymap_quicktune_dec")))
+ else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_DEC]))
quicktune->dec();
-
- std::string msg = quicktune->getMessage();
- if (msg != "") {
- statustext = narrow_to_wide(msg);
- *statustext_time = 0;
- }
-
- // Print debug stacks
- if (input->wasKeyDown(getKeySetting("keymap_print_debug_stacks"))) {
+ else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_DEBUG_STACKS])) {
+ // Print debug stacks
dstream << "-----------------------------------------"
<< std::endl;
- dstream << DTIME << "Printing debug stacks:" << std::endl;
+ dstream << "Printing debug stacks:" << std::endl;
dstream << "-----------------------------------------"
<< std::endl;
debug_stacks_print();
}
+
+ if (!input->isKeyDown(getKeySetting("keymap_jump")) && *reset_jump_timer) {
+ *reset_jump_timer = false;
+ *jump_timer = 0.0;
+ }
+
+ //tt.stop();
+
+ if (quicktune->hasMessage()) {
+ std::string msg = quicktune->getMessage();
+ statustext = utf8_to_wide(msg);
+ *statustext_time = 0;
+ }
}
-void MinetestApp::processItemSelection(u16 *new_playeritem)
+void Game::processItemSelection(u16 *new_playeritem)
{
LocalPlayer *player = client->getEnv().getLocalPlayer();
player->hud_hotbar_itemcount - 1);
if (wheel < 0)
- *new_playeritem = *new_playeritem < max_item ? *new_playeritem + 1 : max_item;
+ *new_playeritem = *new_playeritem < max_item ? *new_playeritem + 1 : 0;
else if (wheel > 0)
*new_playeritem = *new_playeritem > 0 ? *new_playeritem - 1 : max_item;
// else wheel == 0
}
-void MinetestApp::dropSelectedItem()
+void Game::dropSelectedItem()
{
IDropAction *a = new IDropAction();
a->count = 0;
}
-void MinetestApp::openInventory()
+void Game::openInventory()
{
+ /*
+ * Don't permit to open inventory is CAO or player doesn't exists.
+ * This prevent showing an empty inventory at player load
+ */
+
+ LocalPlayer *player = client->getEnv().getLocalPlayer();
+ if (player == NULL || player->getCAO() == NULL)
+ return;
+
infostream << "the_game: " << "Launching inventory" << std::endl;
PlayerInventoryFormSource *fs_src = new PlayerInventoryFormSource(client);
}
-void MinetestApp::openConsole()
+void Game::openConsole()
{
if (!gui_chat_console->isOpenInhibited()) {
// Open up to over half of the screen
}
-void MinetestApp::toggleFreeMove(float *statustext_time)
+void Game::toggleFreeMove(float *statustext_time)
{
static const wchar_t *msg[] = { L"free_move disabled", L"free_move enabled" };
}
-void MinetestApp::toggleFreeMoveAlt(float *statustext_time, float *jump_timer)
+void Game::toggleFreeMoveAlt(float *statustext_time, float *jump_timer)
{
- if (g_settings->getBool("doubletap_jump") && *jump_timer < 0.2f) {
+ if (m_cache_doubletap_jump && *jump_timer < 0.2f)
toggleFreeMove(statustext_time);
- *jump_timer = 0;
- }
}
-void MinetestApp::toggleFast(float *statustext_time)
+void Game::toggleFast(float *statustext_time)
{
static const wchar_t *msg[] = { L"fast_move disabled", L"fast_move enabled" };
bool fast_move = !g_settings->getBool("fast_move");
*statustext_time = 0;
statustext = msg[fast_move];
- if (fast_move && !client->checkPrivilege("fast"))
+ bool has_fast_privs = client->checkPrivilege("fast");
+
+ if (fast_move && !has_fast_privs)
statustext += L" (note: no 'fast' privilege)";
+
+#ifdef __ANDROID__
+ m_cache_hold_aux1 = fast_move && has_fast_privs;
+#endif
}
-void MinetestApp::toggleNoClip(float *statustext_time)
+void Game::toggleNoClip(float *statustext_time)
{
static const wchar_t *msg[] = { L"noclip disabled", L"noclip enabled" };
bool noclip = !g_settings->getBool("noclip");
statustext += L" (note: no 'noclip' privilege)";
}
+void Game::toggleCinematic(float *statustext_time)
+{
+ static const wchar_t *msg[] = { L"cinematic disabled", L"cinematic enabled" };
+ bool cinematic = !g_settings->getBool("cinematic");
+ g_settings->set("cinematic", bool_to_cstr(cinematic));
-void MinetestApp::toggleChat(float *statustext_time, bool *flag)
+ *statustext_time = 0;
+ statustext = msg[cinematic];
+}
+
+// Add WoW-style autorun by toggling continuous forward.
+void Game::toggleAutorun(float *statustext_time)
+{
+ static const wchar_t *msg[] = { L"autorun disabled", L"autorun enabled" };
+ bool autorun_enabled = !g_settings->getBool("continuous_forward");
+ g_settings->set("continuous_forward", bool_to_cstr(autorun_enabled));
+
+ *statustext_time = 0;
+ statustext = msg[autorun_enabled ? 1 : 0];
+}
+
+void Game::toggleChat(float *statustext_time, bool *flag)
{
static const wchar_t *msg[] = { L"Chat hidden", L"Chat shown" };
}
-void MinetestApp::toggleHud(float *statustext_time, bool *flag)
+void Game::toggleHud(float *statustext_time, bool *flag)
{
static const wchar_t *msg[] = { L"HUD hidden", L"HUD shown" };
*flag = !*flag;
*statustext_time = 0;
statustext = msg[*flag];
- client->setHighlighted(client->getHighlighted(), *flag);
}
+void Game::toggleMinimap(float *statustext_time, bool *flag,
+ bool show_hud, bool shift_pressed)
+{
+ if (!show_hud || !g_settings->getBool("enable_minimap"))
+ return;
+
+ if (shift_pressed) {
+ mapper->toggleMinimapShape();
+ return;
+ }
+
+ u32 hud_flags = client->getEnv().getLocalPlayer()->hud_flags;
+
+ MinimapMode mode = MINIMAP_MODE_OFF;
+ if (hud_flags & HUD_FLAG_MINIMAP_VISIBLE) {
+ mode = mapper->getMinimapMode();
+ mode = (MinimapMode)((int)mode + 1);
+ }
-void MinetestApp::toggleFog(float *statustext_time, bool *flag)
+ *flag = true;
+ switch (mode) {
+ case MINIMAP_MODE_SURFACEx1:
+ statustext = L"Minimap in surface mode, Zoom x1";
+ break;
+ case MINIMAP_MODE_SURFACEx2:
+ statustext = L"Minimap in surface mode, Zoom x2";
+ break;
+ case MINIMAP_MODE_SURFACEx4:
+ statustext = L"Minimap in surface mode, Zoom x4";
+ break;
+ case MINIMAP_MODE_RADARx1:
+ statustext = L"Minimap in radar mode, Zoom x1";
+ break;
+ case MINIMAP_MODE_RADARx2:
+ statustext = L"Minimap in radar mode, Zoom x2";
+ break;
+ case MINIMAP_MODE_RADARx4:
+ statustext = L"Minimap in radar mode, Zoom x4";
+ break;
+ default:
+ mode = MINIMAP_MODE_OFF;
+ *flag = false;
+ statustext = (hud_flags & HUD_FLAG_MINIMAP_VISIBLE) ?
+ L"Minimap hidden" : L"Minimap disabled by server";
+ }
+
+ *statustext_time = 0;
+ mapper->setMinimapMode(mode);
+}
+
+void Game::toggleFog(float *statustext_time, bool *flag)
{
static const wchar_t *msg[] = { L"Fog enabled", L"Fog disabled" };
}
-void MinetestApp::toggleDebug(float *statustext_time, bool *show_debug,
+void Game::toggleDebug(float *statustext_time, bool *show_debug,
bool *show_profiler_graph)
{
// Initial / 3x toggle: Chat only
}
-void MinetestApp::toggleUpdateCamera(float *statustext_time, bool *flag)
+void Game::toggleUpdateCamera(float *statustext_time, bool *flag)
{
static const wchar_t *msg[] = {
L"Camera update enabled",
}
-void MinetestApp::toggleProfiler(float *statustext_time, u32 *profiler_current_page,
+void Game::toggleProfiler(float *statustext_time, u32 *profiler_current_page,
u32 profiler_max_page)
{
*profiler_current_page = (*profiler_current_page + 1) % (profiler_max_page + 1);
// FIXME: This updates the profiler with incomplete values
- update_profiler_gui(guitext_profiler, font, text_height,
- *profiler_current_page, profiler_max_page);
+ update_profiler_gui(guitext_profiler, g_fontengine, *profiler_current_page,
+ profiler_max_page, driver->getScreenSize().Height);
if (*profiler_current_page != 0) {
std::wstringstream sstr;
}
-void MinetestApp::increaseViewRange(float *statustext_time)
+void Game::increaseViewRange(float *statustext_time)
{
s16 range = g_settings->getS16("viewing_range_nodes_min");
s16 range_new = range + 10;
g_settings->set("viewing_range_nodes_min", itos(range_new));
- statustext = narrow_to_wide("Minimum viewing range changed to "
+ statustext = utf8_to_wide("Minimum viewing range changed to "
+ itos(range_new));
*statustext_time = 0;
}
-void MinetestApp::decreaseViewRange(float *statustext_time)
+void Game::decreaseViewRange(float *statustext_time)
{
s16 range = g_settings->getS16("viewing_range_nodes_min");
s16 range_new = range - 10;
range_new = range;
g_settings->set("viewing_range_nodes_min", itos(range_new));
- statustext = narrow_to_wide("Minimum viewing range changed to "
+ statustext = utf8_to_wide("Minimum viewing range changed to "
+ itos(range_new));
*statustext_time = 0;
}
-void MinetestApp::toggleFullViewRange(float *statustext_time)
+void Game::toggleFullViewRange(float *statustext_time)
{
static const wchar_t *msg[] = {
L"Disabled full viewing range",
}
-void MinetestApp::updateCameraDirection(CameraOrientation *cam,
+void Game::updateCameraDirection(CameraOrientation *cam,
VolatileRunFlags *flags)
{
- // float turn_amount = 0; // Deprecated?
+ if ((device->isWindowActive() && noMenuActive()) || random_input) {
+
+#ifndef __ANDROID__
+ if (!random_input) {
+ // Mac OSX gets upset if this is set every frame
+ if (device->getCursorControl()->isVisible())
+ device->getCursorControl()->setVisible(false);
+ }
+#endif
- if (!(device->isWindowActive() && noMenuActive()) || random_input) {
+ if (flags->first_loop_after_window_activation)
+ flags->first_loop_after_window_activation = false;
+ else
+ updateCameraOrientation(cam, *flags);
- // FIXME: Clean this up
+ input->setMousePos((driver->getScreenSize().Width / 2),
+ (driver->getScreenSize().Height / 2));
+ } else {
#ifndef ANDROID
// Mac OSX gets upset if this is set every frame
device->getCursorControl()->setVisible(true);
#endif
- //infostream<<"window inactive"<<std::endl;
- flags->first_loop_after_window_activation = true;
- return;
- }
+ if (!flags->first_loop_after_window_activation)
+ flags->first_loop_after_window_activation = true;
-#ifndef __ANDROID__
- if (!random_input) {
- // Mac OSX gets upset if this is set every frame
- if (device->getCursorControl()->isVisible())
- device->getCursorControl()->setVisible(false);
}
-#endif
+}
- if (flags->first_loop_after_window_activation) {
- //infostream<<"window active, first loop"<<std::endl;
- flags->first_loop_after_window_activation = false;
- } else {
+void Game::updateCameraOrientation(CameraOrientation *cam,
+ const VolatileRunFlags &flags)
+{
#ifdef HAVE_TOUCHSCREENGUI
-
- if (g_touchscreengui) {
- camera_yaw = g_touchscreengui->getYaw();
- camera_pitch = g_touchscreengui->getPitch();
- } else {
+ if (g_touchscreengui) {
+ cam->camera_yaw = g_touchscreengui->getYaw();
+ cam->camera_pitch = g_touchscreengui->getPitch();
+ } else {
#endif
- s32 dx = input->getMousePos().X - (driver->getScreenSize().Width / 2);
- s32 dy = input->getMousePos().Y - (driver->getScreenSize().Height / 2);
+ s32 dx = input->getMousePos().X - (driver->getScreenSize().Width / 2);
+ s32 dy = input->getMousePos().Y - (driver->getScreenSize().Height / 2);
- if (flags->invert_mouse
- || (camera->getCameraMode() == CAMERA_MODE_THIRD_FRONT)) {
- dy = -dy;
- }
-
- //infostream<<"window active, pos difference "<<dx<<","<<dy<<std::endl;
+ if (flags.invert_mouse
+ || camera->getCameraMode() == CAMERA_MODE_THIRD_FRONT) {
+ dy = -dy;
+ }
- float d = g_settings->getFloat("mouse_sensitivity");
- d = rangelim(d, 0.01, 100.0);
- cam->camera_yaw -= dx * d;
- cam->camera_pitch += dy * d;
- // turn_amount = v2f(dx, dy).getLength() * d; // deprecated?
+ cam->camera_yaw -= dx * m_cache_mouse_sensitivity;
+ cam->camera_pitch += dy * m_cache_mouse_sensitivity;
#ifdef HAVE_TOUCHSCREENGUI
- }
-#endif
-
- if (cam->camera_pitch < -89.5)
- cam->camera_pitch = -89.5;
- else if (cam->camera_pitch > 89.5)
- cam->camera_pitch = 89.5;
}
+#endif
- input->setMousePos(driver->getScreenSize().Width / 2,
- driver->getScreenSize().Height / 2);
-
- // Deprecated? Not used anywhere else
- // recent_turn_speed = recent_turn_speed * 0.9 + turn_amount * 0.1;
- // std::cerr<<"recent_turn_speed = "<<recent_turn_speed<<std::endl;
+ cam->camera_pitch = rangelim(cam->camera_pitch, -89.5, 89.5);
}
-void MinetestApp::updatePlayerControl(const CameraOrientation &cam)
+void Game::updatePlayerControl(const CameraOrientation &cam)
{
+ //TimeTaker tt("update player control", NULL, PRECISION_NANO);
+
PlayerControl control(
- input->isKeyDown(getKeySetting("keymap_forward")),
- input->isKeyDown(getKeySetting("keymap_backward")),
- input->isKeyDown(getKeySetting("keymap_left")),
- input->isKeyDown(getKeySetting("keymap_right")),
- input->isKeyDown(getKeySetting("keymap_jump")),
- input->isKeyDown(getKeySetting("keymap_special1")),
- input->isKeyDown(getKeySetting("keymap_sneak")),
+ input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_FORWARD]),
+ input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_BACKWARD]),
+ input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_LEFT]),
+ input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_RIGHT]),
+ input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_JUMP]),
+ input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_SPECIAL1]),
+ input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_SNEAK]),
input->getLeftState(),
input->getRightState(),
cam.camera_pitch,
cam.camera_yaw
);
+
+ u32 keypress_bits =
+ ( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_FORWARD]) & 0x1) << 0) |
+ ( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_BACKWARD]) & 0x1) << 1) |
+ ( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_LEFT]) & 0x1) << 2) |
+ ( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_RIGHT]) & 0x1) << 3) |
+ ( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_JUMP]) & 0x1) << 4) |
+ ( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_SPECIAL1]) & 0x1) << 5) |
+ ( (u32)(input->isKeyDown(keycache.key[KeyCache::KEYMAP_ID_SNEAK]) & 0x1) << 6) |
+ ( (u32)(input->getLeftState() & 0x1) << 7) |
+ ( (u32)(input->getRightState() & 0x1) << 8
+ );
+
+#ifdef ANDROID
+ /* For Android, 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
+ * not fast)
+ */
+ if (m_cache_hold_aux1) {
+ control.aux1 = control.aux1 ^ true;
+ keypress_bits ^= ((u32)(1U << 5));
+ }
+#endif
+
client->setPlayerControl(control);
LocalPlayer *player = client->getEnv().getLocalPlayer();
- player->keyPressed =
- ( (u32)(input->isKeyDown(getKeySetting("keymap_forward")) & 0x1) << 0) |
- ( (u32)(input->isKeyDown(getKeySetting("keymap_backward")) & 0x1) << 1) |
- ( (u32)(input->isKeyDown(getKeySetting("keymap_left")) & 0x1) << 2) |
- ( (u32)(input->isKeyDown(getKeySetting("keymap_right")) & 0x1) << 3) |
- ( (u32)(input->isKeyDown(getKeySetting("keymap_jump")) & 0x1) << 4) |
- ( (u32)(input->isKeyDown(getKeySetting("keymap_special1")) & 0x1) << 5) |
- ( (u32)(input->isKeyDown(getKeySetting("keymap_sneak")) & 0x1) << 6) |
- ( (u32)(input->getLeftState() & 0x1) << 7) |
- ( (u32)(input->getRightState() & 0x1) << 8
- );
+ player->keyPressed = keypress_bits;
+ //tt.stop();
}
-inline void MinetestApp::step(f32 *dtime)
+inline void Game::step(f32 *dtime)
{
bool can_be_and_is_paused =
(simple_singleplayer_mode && g_menumgr.pausesGame());
}
-void MinetestApp::processClientEvents(CameraOrientation *cam, float *damage_flash)
+void Game::processClientEvents(CameraOrientation *cam, float *damage_flash)
{
ClientEvent event = client->getClientEvent();
delete(event.show_formspec.formspec);
delete(event.show_formspec.formname);
- } else if (event.type == CE_SPAWN_PARTICLE) {
- video::ITexture *texture =
- gamedef->tsrc()->getTexture(*(event.spawn_particle.texture));
-
- new Particle(gamedef, smgr, player, client->getEnv(),
- *event.spawn_particle.pos,
- *event.spawn_particle.vel,
- *event.spawn_particle.acc,
- event.spawn_particle.expirationtime,
- event.spawn_particle.size,
- event.spawn_particle.collisiondetection,
- event.spawn_particle.vertical,
- texture,
- v2f(0.0, 0.0),
- v2f(1.0, 1.0));
- } else if (event.type == CE_ADD_PARTICLESPAWNER) {
- video::ITexture *texture =
- gamedef->tsrc()->getTexture(*(event.add_particlespawner.texture));
-
- new ParticleSpawner(gamedef, smgr, player,
- event.add_particlespawner.amount,
- event.add_particlespawner.spawntime,
- *event.add_particlespawner.minpos,
- *event.add_particlespawner.maxpos,
- *event.add_particlespawner.minvel,
- *event.add_particlespawner.maxvel,
- *event.add_particlespawner.minacc,
- *event.add_particlespawner.maxacc,
- event.add_particlespawner.minexptime,
- event.add_particlespawner.maxexptime,
- event.add_particlespawner.minsize,
- event.add_particlespawner.maxsize,
- event.add_particlespawner.collisiondetection,
- event.add_particlespawner.vertical,
- texture,
- event.add_particlespawner.id);
- } else if (event.type == CE_DELETE_PARTICLESPAWNER) {
- delete_particlespawner(event.delete_particlespawner.id);
+ } else if ((event.type == CE_SPAWN_PARTICLE) ||
+ (event.type == CE_ADD_PARTICLESPAWNER) ||
+ (event.type == CE_DELETE_PARTICLESPAWNER)) {
+ client->getParticleManager()->handleParticleEvent(&event, gamedef,
+ smgr, player);
} else if (event.type == CE_HUDADD) {
u32 id = event.hudadd.id;
u32 new_id = player->addHud(e);
//if this isn't true our huds aren't consistent
- assert(new_id == id);
+ sanity_check(new_id == id);
delete event.hudadd.pos;
delete event.hudadd.name;
event.set_sky.params->size() == 6) {
sky->setFallbackBgColor(*event.set_sky.bgcolor);
skybox = smgr->addSkyBoxSceneNode(
- texture_src->getTexture((*event.set_sky.params)[0]),
- texture_src->getTexture((*event.set_sky.params)[1]),
- texture_src->getTexture((*event.set_sky.params)[2]),
- texture_src->getTexture((*event.set_sky.params)[3]),
- texture_src->getTexture((*event.set_sky.params)[4]),
- texture_src->getTexture((*event.set_sky.params)[5]));
+ texture_src->getTextureForMesh((*event.set_sky.params)[0]),
+ texture_src->getTextureForMesh((*event.set_sky.params)[1]),
+ texture_src->getTextureForMesh((*event.set_sky.params)[2]),
+ texture_src->getTextureForMesh((*event.set_sky.params)[3]),
+ texture_src->getTextureForMesh((*event.set_sky.params)[4]),
+ texture_src->getTextureForMesh((*event.set_sky.params)[5]));
}
// Handle everything else as plain color
else {
}
-void MinetestApp::updateCamera(VolatileRunFlags *flags, u32 busy_time,
+void Game::updateCamera(VolatileRunFlags *flags, u32 busy_time,
f32 dtime, float time_from_last_punch)
{
LocalPlayer *player = client->getEnv().getLocalPlayer();
v3s16 old_camera_offset = camera->getOffset();
- if (input->wasKeyDown(getKeySetting("keymap_camera_mode"))) {
- camera->toggleCameraMode();
+ if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CAMERA_MODE])) {
GenericCAO *playercao = player->getCAO();
- assert(playercao != NULL);
+ // If playercao not loaded, don't change camera
+ if (playercao == NULL)
+ return;
+
+ camera->toggleCameraMode();
playercao->setVisible(camera->getCameraMode() > CAMERA_MODE_FIRST);
+ playercao->setChildrenVisible(camera->getCameraMode() > CAMERA_MODE_FIRST);
}
float full_punch_interval = playeritem_toolcap.full_punch_interval;
}
-void MinetestApp::updateSound(f32 dtime)
+void Game::updateSound(f32 dtime)
{
// Update sound listener
v3s16 camera_offset = camera->getOffset();
}
-void MinetestApp::processPlayerInteraction(std::vector<aabb3f> &highlight_boxes,
- InteractParams *interactArgs, f32 dtime, bool show_hud, bool show_debug)
+void Game::processPlayerInteraction(GameRunData *runData,
+ f32 dtime, bool show_hud, bool show_debug)
{
LocalPlayer *player = client->getEnv().getLocalPlayer();
PointedThing pointed = getPointedThing(
// input
- client, player_position, camera_direction,
+ client, hud, player_position, camera_direction,
camera_position, shootline, d,
playeritem_def.liquids_pointable,
- !interactArgs->ldown_for_dig,
+ !runData->ldown_for_dig,
camera_offset,
// output
- highlight_boxes,
- interactArgs->selected_object);
+ runData->selected_object);
- if (pointed != interactArgs->pointed_old) {
+ if (pointed != runData->pointed_old) {
infostream << "Pointing at " << pointed.dump() << std::endl;
-
- if (g_settings->getBool("enable_node_highlighting")) {
- if (pointed.type == POINTEDTHING_NODE) {
- client->setHighlighted(pointed.node_undersurface, show_hud);
- } else {
- client->setHighlighted(pointed.node_undersurface, false);
- }
- }
+ hud->updateSelectionMesh(camera_offset);
}
/*
- releasing left mouse button
- pointing away from node
*/
- if (interactArgs->digging) {
+ if (runData->digging) {
if (input->getLeftReleased()) {
infostream << "Left button released"
<< " (stopped digging)" << std::endl;
- interactArgs->digging = false;
- } else if (pointed != interactArgs->pointed_old) {
+ runData->digging = false;
+ } else if (pointed != runData->pointed_old) {
if (pointed.type == POINTEDTHING_NODE
- && interactArgs->pointed_old.type == POINTEDTHING_NODE
+ && runData->pointed_old.type == POINTEDTHING_NODE
&& pointed.node_undersurface
- == interactArgs->pointed_old.node_undersurface) {
+ == runData->pointed_old.node_undersurface) {
// Still pointing to the same node, but a different face.
// Don't reset.
} else {
infostream << "Pointing away from node"
<< " (stopped digging)" << std::endl;
- interactArgs->digging = false;
+ runData->digging = false;
+ hud->updateSelectionMesh(camera_offset);
}
}
- if (!interactArgs->digging) {
- client->interact(1, interactArgs->pointed_old);
+ if (!runData->digging) {
+ client->interact(1, runData->pointed_old);
client->setCrack(-1, v3s16(0, 0, 0));
- interactArgs->dig_time = 0.0;
+ runData->dig_time = 0.0;
}
}
- if (!interactArgs->digging && interactArgs->ldown_for_dig && !input->getLeftState()) {
- interactArgs->ldown_for_dig = false;
+ if (!runData->digging && runData->ldown_for_dig && !input->getLeftState()) {
+ runData->ldown_for_dig = false;
}
- interactArgs->left_punch = false;
+ runData->left_punch = false;
soundmaker->m_player_leftpunch_sound.name = "";
if (input->getRightState())
- interactArgs->repeat_rightclick_timer += dtime;
+ runData->repeat_rightclick_timer += dtime;
else
- interactArgs->repeat_rightclick_timer = 0;
+ runData->repeat_rightclick_timer = 0;
if (playeritem_def.usable && input->getLeftState()) {
if (input->getLeftClicked())
} else if (pointed.type == POINTEDTHING_NODE) {
ToolCapabilities playeritem_toolcap =
playeritem.getToolCapabilities(itemdef_manager);
- handlePointingAtNode(interactArgs, pointed, playeritem_def,
+ handlePointingAtNode(runData, pointed, playeritem_def,
playeritem_toolcap, dtime);
} else if (pointed.type == POINTEDTHING_OBJECT) {
- handlePointingAtObject(interactArgs, pointed, playeritem,
+ handlePointingAtObject(runData, pointed, playeritem,
player_position, show_debug);
} else if (input->getLeftState()) {
// When button is held down in air, show continuous animation
- interactArgs->left_punch = true;
+ runData->left_punch = true;
+ } else if (input->getRightClicked()) {
+ handlePointingAtNothing(runData, playeritem);
}
- interactArgs->pointed_old = pointed;
+ runData->pointed_old = pointed;
- if (interactArgs->left_punch || input->getLeftClicked())
+ if (runData->left_punch || input->getLeftClicked())
camera->setDigging(0); // left click animation
input->resetLeftClicked();
}
-void MinetestApp::handlePointingAtNode(InteractParams *interactArgs,
+void Game::handlePointingAtNothing(GameRunData *runData, const ItemStack &playerItem)
+{
+ infostream << "Right Clicked in Air" << std::endl;
+ PointedThing fauxPointed;
+ fauxPointed.type = POINTEDTHING_NOTHING;
+ client->interact(5, fauxPointed);
+}
+
+
+void Game::handlePointingAtNode(GameRunData *runData,
const PointedThing &pointed, const ItemDefinition &playeritem_def,
const ToolCapabilities &playeritem_toolcap, f32 dtime)
{
NodeMetadata *meta = map.getNodeMetadata(nodepos);
if (meta) {
- infotext = narrow_to_wide(meta->getString("infotext"));
+ infotext = utf8_to_wide(meta->getString("infotext"));
} else {
- MapNode n = map.getNode(nodepos);
+ MapNode n = map.getNodeNoEx(nodepos);
if (nodedef_manager->get(n).tiledef[0].name == "unknown_node.png") {
infotext = L"Unknown node: ";
- infotext += narrow_to_wide(nodedef_manager->get(n).name);
+ infotext += utf8_to_wide(nodedef_manager->get(n).name);
}
}
- if (interactArgs->nodig_delay_timer <= 0.0 && input->getLeftState()
+ if (runData->nodig_delay_timer <= 0.0 && input->getLeftState()
&& client->checkPrivilege("interact")) {
- handleDigging(interactArgs, pointed, nodepos, playeritem_toolcap, dtime);
+ handleDigging(runData, pointed, nodepos, playeritem_toolcap, dtime);
}
if ((input->getRightClicked() ||
- interactArgs->repeat_rightclick_timer >=
- g_settings->getFloat("repeat_rightclick_time")) &&
+ runData->repeat_rightclick_timer >= m_repeat_right_click_time) &&
client->checkPrivilege("interact")) {
- interactArgs->repeat_rightclick_timer = 0;
+ runData->repeat_rightclick_timer = 0;
infostream << "Ground right-clicked" << std::endl;
if (meta && meta->getString("formspec") != "" && !random_input
} else {
soundmaker->m_player_rightpunch_sound =
SimpleSoundSpec();
- }
- if (playeritem_def.node_placement_prediction == "" ||
- nodedef_manager->get(map.getNode(nodepos)).rightclickable)
- client->interact(3, pointed); // Report to server
+ if (playeritem_def.node_placement_prediction == "" ||
+ nodedef_manager->get(map.getNodeNoEx(nodepos)).rightclickable) {
+ client->interact(3, pointed); // Report to server
+ } else {
+ soundmaker->m_player_rightpunch_sound =
+ playeritem_def.sound_place_failed;
+ }
+ }
}
}
}
-void MinetestApp::handlePointingAtObject(InteractParams *interactArgs,
+void Game::handlePointingAtObject(GameRunData *runData,
const PointedThing &pointed,
const ItemStack &playeritem,
const v3f &player_position,
bool show_debug)
{
- infotext = narrow_to_wide(interactArgs->selected_object->infoText());
+ infotext = utf8_to_wide(runData->selected_object->infoText());
- if (infotext == L"" && show_debug) {
- infotext = narrow_to_wide(interactArgs->selected_object->debugInfoText());
+ if (show_debug) {
+ if (infotext != L"") {
+ infotext += L"\n";
+ }
+ infotext += utf8_to_wide(runData->selected_object->debugInfoText());
}
if (input->getLeftState()) {
bool do_punch = false;
bool do_punch_damage = false;
- if (interactArgs->object_hit_delay_timer <= 0.0) {
+ if (runData->object_hit_delay_timer <= 0.0) {
do_punch = true;
do_punch_damage = true;
- interactArgs->object_hit_delay_timer = object_hit_delay;
+ runData->object_hit_delay_timer = object_hit_delay;
}
if (input->getLeftClicked())
if (do_punch) {
infostream << "Left-clicked object" << std::endl;
- interactArgs->left_punch = true;
+ runData->left_punch = true;
}
if (do_punch_damage) {
// Report direct punch
- v3f objpos = interactArgs->selected_object->getPosition();
+ v3f objpos = runData->selected_object->getPosition();
v3f dir = (objpos - player_position).normalize();
- bool disable_send = interactArgs->selected_object->directReportPunch(
- dir, &playeritem, interactArgs->time_from_last_punch);
- interactArgs->time_from_last_punch = 0;
+ bool disable_send = runData->selected_object->directReportPunch(
+ dir, &playeritem, runData->time_from_last_punch);
+ runData->time_from_last_punch = 0;
if (!disable_send)
client->interact(0, pointed);
}
-void MinetestApp::handleDigging(InteractParams *interactArgs,
+void Game::handleDigging(GameRunData *runData,
const PointedThing &pointed, const v3s16 &nodepos,
const ToolCapabilities &playeritem_toolcap, f32 dtime)
{
- if (!interactArgs->digging) {
+ if (!runData->digging) {
infostream << "Started digging" << std::endl;
client->interact(0, pointed);
- interactArgs->digging = true;
- interactArgs->ldown_for_dig = true;
+ runData->digging = true;
+ runData->ldown_for_dig = true;
}
LocalPlayer *player = client->getEnv().getLocalPlayer();
ClientMap &map = client->getEnv().getClientMap();
- MapNode n = client->getEnv().getClientMap().getNode(nodepos);
+ MapNode n = client->getEnv().getClientMap().getNodeNoEx(nodepos);
// NOTE: Similar piece of code exists on the server side for
// cheat detection.
if (params.diggable == false) {
// I guess nobody will wait for this long
- interactArgs->dig_time_complete = 10000000.0;
+ runData->dig_time_complete = 10000000.0;
} else {
- interactArgs->dig_time_complete = params.time;
+ runData->dig_time_complete = params.time;
- if (g_settings->getBool("enable_particles")) {
+ if (m_cache_enable_particles) {
const ContentFeatures &features =
client->getNodeDefManager()->get(n);
- addPunchingParticles(gamedef, smgr, player,
- client->getEnv(), nodepos, features.tiles);
+ client->getParticleManager()->addPunchingParticles(gamedef, smgr,
+ player, nodepos, features.tiles);
}
}
- if (interactArgs->dig_time_complete >= 0.001) {
- interactArgs->dig_index = (float)crack_animation_length
- * interactArgs->dig_time
- / interactArgs->dig_time_complete;
+ if (runData->dig_time_complete >= 0.001) {
+ runData->dig_index = (float)crack_animation_length
+ * runData->dig_time
+ / runData->dig_time_complete;
} else {
// This is for torches
- interactArgs->dig_index = crack_animation_length;
+ runData->dig_index = crack_animation_length;
}
SimpleSoundSpec sound_dig = nodedef_manager->get(n).sound_dig;
}
// Don't show cracks if not diggable
- if (interactArgs->dig_time_complete >= 100000.0) {
- } else if (interactArgs->dig_index < crack_animation_length) {
+ if (runData->dig_time_complete >= 100000.0) {
+ } else if (runData->dig_index < crack_animation_length) {
//TimeTaker timer("client.setTempMod");
//infostream<<"dig_index="<<dig_index<<std::endl;
- client->setCrack(interactArgs->dig_index, nodepos);
+ client->setCrack(runData->dig_index, nodepos);
} else {
infostream << "Digging completed" << std::endl;
client->interact(2, pointed);
client->setCrack(-1, v3s16(0, 0, 0));
- MapNode wasnode = map.getNode(nodepos);
- client->removeNode(nodepos);
+ bool is_valid_position;
+ MapNode wasnode = map.getNodeNoEx(nodepos, &is_valid_position);
+ if (is_valid_position)
+ client->removeNode(nodepos);
- if (g_settings->getBool("enable_particles")) {
+ if (m_cache_enable_particles) {
const ContentFeatures &features =
client->getNodeDefManager()->get(wasnode);
- addDiggingParticles
- (gamedef, smgr, player, client->getEnv(),
- nodepos, features.tiles);
+ client->getParticleManager()->addDiggingParticles(gamedef, smgr,
+ player, nodepos, features.tiles);
}
- interactArgs->dig_time = 0;
- interactArgs->digging = false;
+ runData->dig_time = 0;
+ runData->digging = false;
- interactArgs->nodig_delay_timer =
- interactArgs->dig_time_complete / (float)crack_animation_length;
+ runData->nodig_delay_timer =
+ runData->dig_time_complete / (float)crack_animation_length;
// We don't want a corresponding delay to
// very time consuming nodes
- if (interactArgs->nodig_delay_timer > 0.3)
- interactArgs->nodig_delay_timer = 0.3;
+ if (runData->nodig_delay_timer > 0.3)
+ runData->nodig_delay_timer = 0.3;
// We want a slight delay to very little
// time consuming nodes
const float mindelay = 0.15;
- if (interactArgs->nodig_delay_timer < mindelay)
- interactArgs->nodig_delay_timer = mindelay;
+ if (runData->nodig_delay_timer < mindelay)
+ runData->nodig_delay_timer = mindelay;
// Send event to trigger sound
MtEvent *e = new NodeDugEvent(nodepos, wasnode);
gamedef->event()->put(e);
}
- if (interactArgs->dig_time_complete < 100000.0) {
- interactArgs->dig_time += dtime;
+ if (runData->dig_time_complete < 100000.0) {
+ runData->dig_time += dtime;
} else {
- interactArgs->dig_time = 0;
+ runData->dig_time = 0;
client->setCrack(-1, nodepos);
}
}
-void MinetestApp::updateFrame(std::vector<aabb3f> &highlight_boxes,
- ProfilerGraph *graph, RunStats *stats, InteractParams *interactArgs,
- f32 dtime, const VolatileRunFlags &flags, const CameraOrientation &cam)
+void Game::updateFrame(ProfilerGraph *graph, RunStats *stats,
+ GameRunData *runData, f32 dtime, const VolatileRunFlags &flags,
+ const CameraOrientation &cam)
{
LocalPlayer *player = client->getEnv().getLocalPlayer();
*/
if (draw_control->range_all) {
- interactArgs->fog_range = 100000 * BS;
+ runData->fog_range = 100000 * BS;
} else {
- interactArgs->fog_range = draw_control->wanted_range * BS
+ runData->fog_range = draw_control->wanted_range * BS
+ 0.0 * MAP_BLOCKSIZE * BS;
- interactArgs->fog_range = MYMIN(
- interactArgs->fog_range,
+ runData->fog_range = MYMIN(
+ runData->fog_range,
(draw_control->farthest_drawn + 20) * BS);
- interactArgs->fog_range *= 0.9;
+ runData->fog_range *= 0.9;
}
/*
*/
u32 daynight_ratio = client->getEnv().getDayNightRatio();
float time_brightness = decode_light_f((float)daynight_ratio / 1000.0);
- float direct_brightness = 0;
- bool sunlight_seen = false;
+ float direct_brightness;
+ bool sunlight_seen;
if (g_settings->getBool("free_move")) {
direct_brightness = time_brightness;
ScopeProfiler sp(g_profiler, "Detecting background light", SPT_AVG);
float old_brightness = sky->getBrightness();
direct_brightness = client->getEnv().getClientMap()
- .getBackgroundBrightness(MYMIN(interactArgs->fog_range * 1.2, 60 * BS),
+ .getBackgroundBrightness(MYMIN(runData->fog_range * 1.2, 60 * BS),
daynight_ratio, (int)(old_brightness * 255.5), &sunlight_seen)
/ 255.0;
}
- float time_of_day = 0;
- float time_of_day_smooth = 0;
+ float time_of_day = runData->time_of_day;
+ float time_of_day_smooth = runData->time_of_day_smooth;
time_of_day = client->getEnv().getTimeOfDayF();
const float maxsm = 0.05;
+ const float todsm = 0.05;
if (fabs(time_of_day - time_of_day_smooth) > maxsm &&
fabs(time_of_day - time_of_day_smooth + 1.0) > maxsm &&
fabs(time_of_day - time_of_day_smooth - 1.0) > maxsm)
time_of_day_smooth = time_of_day;
- const float todsm = 0.05;
-
if (time_of_day_smooth > 0.8 && time_of_day < 0.2)
time_of_day_smooth = time_of_day_smooth * (1.0 - todsm)
+ (time_of_day + 1.0) * todsm;
time_of_day_smooth = time_of_day_smooth * (1.0 - todsm)
+ time_of_day * todsm;
+ runData->time_of_day = time_of_day;
+ runData->time_of_day_smooth = time_of_day_smooth;
+
sky->update(time_of_day_smooth, time_brightness, direct_brightness,
sunlight_seen, camera->getCameraMode(), player->getYaw(),
player->getPitch());
/*
Update particles
*/
-
- allparticles_step(dtime);
- allparticlespawners_step(dtime, client->getEnv());
+ client->getParticleManager()->step(dtime);
/*
Fog
*/
- if (g_settings->getBool("enable_fog") && !flags.force_fog_off) {
+ if (m_cache_enable_fog && !flags.force_fog_off) {
driver->setFog(
sky->getBgColor(),
video::EFT_FOG_LINEAR,
- interactArgs->fog_range * 0.4,
- interactArgs->fog_range * 1.0,
+ runData->fog_range * 0.4,
+ runData->fog_range * 1.0,
0.01,
false, // pixel fog
false // range fog
v2u32 screensize = driver->getScreenSize();
updateChat(*client, dtime, flags.show_debug, screensize,
- flags.show_chat, interactArgs->profiler_current_page,
- *chat_backend, guitext_chat, font);
+ flags.show_chat, runData->profiler_current_page,
+ *chat_backend, guitext_chat);
/*
Inventory
*/
- bool update_wielded_item_trigger = true;
-
- if (client->getPlayerItem() != interactArgs->new_playeritem) {
- client->selectPlayerItem(interactArgs->new_playeritem);
- }
+ if (client->getPlayerItem() != runData->new_playeritem)
+ client->selectPlayerItem(runData->new_playeritem);
+ // Update local inventory if it has changed
if (client->getLocalInventoryUpdated()) {
//infostream<<"Updating local inventory"<<std::endl;
client->getLocalInventory(*local_inventory);
-
- update_wielded_item_trigger = true;
+ runData->update_wielded_item_trigger = true;
}
- if (update_wielded_item_trigger) {
- update_wielded_item_trigger = false;
+ if (runData->update_wielded_item_trigger) {
// Update wielded tool
InventoryList *mlist = local_inventory->getList("main");
- ItemStack item;
- if (mlist && (client->getPlayerItem() < mlist->getSize()))
- item = mlist->getItem(client->getPlayerItem());
-
- camera->wield(item, client->getPlayerItem());
+ if (mlist && (client->getPlayerItem() < mlist->getSize())) {
+ ItemStack item = mlist->getItem(client->getPlayerItem());
+ camera->wield(item);
+ }
+ runData->update_wielded_item_trigger = false;
}
/*
Update block draw list every 200ms or when camera direction has
changed much
*/
- interactArgs->update_draw_list_timer += dtime;
+ runData->update_draw_list_timer += dtime;
v3f camera_direction = camera->getDirection();
- if (interactArgs->update_draw_list_timer >= 0.2
- || interactArgs->update_draw_list_last_cam_dir.getDistanceFrom(camera_direction) > 0.2
+ if (runData->update_draw_list_timer >= 0.2
+ || runData->update_draw_list_last_cam_dir.getDistanceFrom(camera_direction) > 0.2
|| flags.camera_offset_changed) {
- interactArgs->update_draw_list_timer = 0;
+ runData->update_draw_list_timer = 0;
client->getEnv().getClientMap().updateDrawList(driver);
- interactArgs->update_draw_list_last_cam_dir = camera_direction;
+ runData->update_draw_list_last_cam_dir = camera_direction;
}
- updateGui(&interactArgs->statustext_time, *stats, dtime, flags, cam);
+ updateGui(&runData->statustext_time, *stats, *runData, dtime, flags, cam);
/*
make sure menu is on top
stats->beginscenetime = timer.stop(true);
}
- draw_scene(driver, smgr, *camera, *client, player, *hud, guienv,
- highlight_boxes, screensize, skycolor, flags.show_hud);
+ draw_scene(driver, smgr, *camera, *client, player, *hud, *mapper,
+ guienv, screensize, skycolor, flags.show_hud,
+ flags.show_minimap);
/*
Profiler graph
*/
if (flags.show_profiler_graph)
- graph->draw(10, screensize.Y - 10, driver, font);
+ graph->draw(10, screensize.Y - 10, driver, g_fontengine->getFont());
/*
Damage flash
*/
- if (interactArgs->damage_flash > 0.0) {
- video::SColor color(std::min(interactArgs->damage_flash, 180.0f),
+ if (runData->damage_flash > 0.0) {
+ video::SColor color(std::min(runData->damage_flash, 180.0f),
180,
0,
0);
core::rect<s32>(0, 0, screensize.X, screensize.Y),
NULL);
- interactArgs->damage_flash -= 100.0 * dtime;
+ runData->damage_flash -= 100.0 * dtime;
}
/*
player->hurt_tilt_strength = 0;
}
+ /*
+ Update minimap pos and rotation
+ */
+ if (flags.show_minimap && flags.show_hud) {
+ mapper->setPos(floatToInt(player->getPosition(), BS));
+ mapper->setAngle(player->getYaw());
+ }
+
/*
End scene
*/
}
-void MinetestApp::updateGui(float *statustext_time, const RunStats& stats,
- f32 dtime, const VolatileRunFlags &flags, const CameraOrientation &cam)
+inline static const char *yawToDirectionString(int yaw)
+{
+ // NOTE: TODO: This can be done mathematically without the else/else-if
+ // cascade.
+
+ const char *player_direction;
+
+ yaw = wrapDegrees_0_360(yaw);
+
+ if (yaw >= 45 && yaw < 135)
+ player_direction = "West [-X]";
+ else if (yaw >= 135 && yaw < 225)
+ player_direction = "South [-Z]";
+ else if (yaw >= 225 && yaw < 315)
+ player_direction = "East [+X]";
+ else
+ player_direction = "North [+Z]";
+
+ return player_direction;
+}
+
+
+void Game::updateGui(float *statustext_time, const RunStats &stats,
+ const GameRunData& runData, f32 dtime, const VolatileRunFlags &flags,
+ const CameraOrientation &cam)
{
v2u32 screensize = driver->getScreenSize();
LocalPlayer *player = client->getEnv().getLocalPlayer();
drawtime_avg = drawtime_avg * 0.95 + stats.drawtime * 0.05;
u16 fps = 1.0 / stats.dtime_jitter.avg;
+ //s32 fps = driver->getFPS();
std::ostringstream os(std::ios_base::binary);
os << std::fixed
- << "Minetest " << minetest_version_hash
+ << PROJECT_NAME_C " " << g_version_hash
<< " FPS = " << fps
<< " (R: range_all=" << draw_control->range_all << ")"
<< std::setprecision(0)
<< ", v_range = " << draw_control->wanted_range
<< std::setprecision(3)
<< ", RTT = " << client->getRTT();
- guitext->setText(narrow_to_wide(os.str()).c_str());
+ guitext->setText(utf8_to_wide(os.str()).c_str());
guitext->setVisible(true);
} else if (flags.show_hud || flags.show_chat) {
std::ostringstream os(std::ios_base::binary);
- os << "Minetest " << minetest_version_hash;
- guitext->setText(narrow_to_wide(os.str()).c_str());
+ os << PROJECT_NAME_C " " << g_version_hash;
+ guitext->setText(utf8_to_wide(os.str()).c_str());
guitext->setVisible(true);
} else {
guitext->setVisible(false);
if (guitext->isVisible()) {
core::rect<s32> rect(
5, 5,
- screensize.X, 5 + text_height
+ screensize.X, 5 + g_fontengine->getTextHeight()
);
guitext->setRelativePosition(rect);
}
<< ", " << (player_position.Y / BS)
<< ", " << (player_position.Z / BS)
<< ") (yaw=" << (wrapDegrees_0_360(cam.camera_yaw))
+ << " " << yawToDirectionString(cam.camera_yaw)
<< ") (seed = " << ((u64)client->getMapSeed())
<< ")";
- guitext2->setText(narrow_to_wide(os.str()).c_str());
+
+ if (runData.pointed_old.type == POINTEDTHING_NODE) {
+ ClientMap &map = client->getEnv().getClientMap();
+ const INodeDefManager *nodedef = client->getNodeDefManager();
+ MapNode n = map.getNodeNoEx(runData.pointed_old.node_undersurface);
+ if (n.getContent() != CONTENT_IGNORE && nodedef->get(n).name != "unknown") {
+ const ContentFeatures &features = nodedef->get(n);
+ os << " (pointing_at = " << nodedef->get(n).name
+ << " - " << features.tiledef[0].name.c_str()
+ << ")";
+ }
+ }
+
+ guitext2->setText(utf8_to_wide(os.str()).c_str());
guitext2->setVisible(true);
core::rect<s32> rect(
- 5, 5 + text_height,
- screensize.X, 5 + text_height * 2
+ 5, 5 + g_fontengine->getTextHeight(),
+ screensize.X, 5 + g_fontengine->getTextHeight() * 2
);
guitext2->setRelativePosition(rect);
} else {
guitext_status->setVisible(!statustext.empty());
if (!statustext.empty()) {
- s32 status_y = screensize.Y - 130;
+ s32 status_width = guitext_status->getTextWidth();
+ s32 status_height = guitext_status->getTextHeight();
+ s32 status_y = screensize.Y - 150;
+ s32 status_x = (screensize.X - status_width) / 2;
core::rect<s32> rect(
- 10, status_y - guitext_status->getTextHeight(),
- 10 + guitext_status->getTextWidth(), status_y
+ status_x , status_y - status_height,
+ status_x + status_width, status_y
);
guitext_status->setRelativePosition(rect);
/* Log times and stuff for visualization */
-inline void MinetestApp::updateProfilerGraphs(ProfilerGraph *graph)
+inline void Game::updateProfilerGraphs(ProfilerGraph *graph)
{
Profiler::GraphValues values;
g_profiler->graphGet(values);
****************************************************************************/
/* On some computers framerate doesn't seem to be automatically limited
- *
- * *Must* be called after device->run() so that device->getTimer()->getTime();
- * is correct
*/
-inline void MinetestApp::limitFps(FpsControl *params, f32 *dtime)
+inline void Game::limitFps(FpsControl *fps_timings, f32 *dtime)
{
// 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;
- u32 last_time = params->last_time;
-
- if (time > last_time) // Make sure time hasn't overflowed
- params->busy_time = time - last_time;
+ if (time > last_time) // Make sure time hasn't overflowed
+ fps_timings->busy_time = time - last_time;
else
- params->busy_time = 0;
+ fps_timings->busy_time = 0;
u32 frametime_min = 1000 / (g_menumgr.pausesGame()
? g_settings->getFloat("pause_fps_max")
: g_settings->getFloat("fps_max"));
- if (params->busy_time < frametime_min) {
- params->sleep_time = frametime_min - params->busy_time;
- device->sleep(params->sleep_time);
- time += params->sleep_time;
+ if (fps_timings->busy_time < frametime_min) {
+ fps_timings->sleep_time = frametime_min - fps_timings->busy_time;
+ device->sleep(fps_timings->sleep_time);
} else {
- params->sleep_time = 0;
+ fps_timings->sleep_time = 0;
}
- if (time > last_time) // Checking for overflow
- *dtime = (time - last_time) / 1000.0;
- else
- *dtime = 0.03; // Choose 30fps as fallback in overflow case
-
- params->last_time = time;
-
-#if 0
-
- /* This is the old method for calculating new_time and dtime, and seems
- * like overkill considering timings are messed up by expected variation
- * in execution speed in other places anyway. (This has nothing to do with
- * WINE... the new method above calculates dtime based on sleep_time)
+ /* 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.
*/
- // Necessary for device->getTimer()->getTime()
- device->run();
+ device->getTimer()->tick(); // Update device timer
time = device->getTimer()->getTime();
- if (time > last_time) // Make sure last_time hasn't overflowed
+ if (time > last_time) // Make sure last_time hasn't overflowed
*dtime = (time - last_time) / 1000.0;
else
- *dtime = 0.033;
+ *dtime = 0;
- params->last_time = time;
-#endif
+ fps_timings->last_time = time;
}
-
-void MinetestApp::showOverlayMessage(const char *msg, float dtime,
+// Note: This will free (using delete[])! \p msg. If you want to use it later,
+// pass a copy of it to this function
+// Note: \p msg must be allocated using new (not malloc())
+void Game::showOverlayMessage(const wchar_t *msg, float dtime,
int percent, bool draw_clouds)
{
- wchar_t *text = wgettext(msg);
- draw_load_screen(text, device, guienv, font, dtime, percent, draw_clouds);
- delete[] text;
+ draw_load_screen(msg, device, guienv, dtime, percent, draw_clouds);
+ delete[] msg;
}
+void Game::settingChangedCallback(const std::string &setting_name, void *data)
+{
+ ((Game *)data)->readSettings();
+}
+void Game::readSettings()
+{
+ m_cache_doubletap_jump = g_settings->getBool("doubletap_jump");
+ m_cache_enable_clouds = g_settings->getBool("enable_clouds");
+ m_cache_enable_particles = g_settings->getBool("enable_particles");
+ m_cache_enable_fog = g_settings->getBool("enable_fog");
+ m_cache_mouse_sensitivity = g_settings->getFloat("mouse_sensitivity");
+ m_repeat_right_click_time = g_settings->getFloat("repeat_rightclick_time");
+
+ m_cache_mouse_sensitivity = rangelim(m_cache_mouse_sensitivity, 0.001, 100.0);
+}
+/****************************************************************************/
/****************************************************************************
Shutdown / cleanup
****************************************************************************/
+/****************************************************************************/
-void MinetestApp::extendedResourceCleanup()
+void Game::extendedResourceCleanup()
{
// Extended resource accounting
infostream << "Irrlicht resources after cleanup:" << std::endl;
}
-
+/****************************************************************************/
/****************************************************************************
extern function for launching the game
****************************************************************************/
+/****************************************************************************/
void the_game(bool *kill,
bool random_input,
InputHandler *input,
IrrlichtDevice *device,
- gui::IGUIFont *font,
const std::string &map_dir,
const std::string &playername,
const std::string &address, // If empty local server is created
u16 port,
- std::wstring &error_message,
+ std::string &error_message,
ChatBackend &chat_backend,
+ bool *reconnect_requested,
const SubgameSpec &gamespec, // Used for local game
bool simple_singleplayer_mode)
{
- MinetestApp app;
+ Game game;
/* Make a copy of the server address because if a local singleplayer server
* is created then this is updated and we don't want to change the value
try {
- if (app.startup(kill, random_input, input, device, font, map_dir,
- playername, password, &server_address, port,
- &error_message, &chat_backend, gamespec,
- simple_singleplayer_mode)) {
-
- //std::cout << "App started" << std::endl;
- app.run();
- app.shutdown();
+ if (game.startup(kill, random_input, input, device, map_dir,
+ playername, password, &server_address, port, error_message,
+ reconnect_requested, &chat_backend, gamespec,
+ simple_singleplayer_mode)) {
+ game.run();
+ game.shutdown();
}
} catch (SerializationError &e) {
- error_message = L"A serialization error occurred:\n"
- + narrow_to_wide(e.what()) + L"\n\nThe server is probably "
- L" running a different version of Minetest.";
- errorstream << wide_to_narrow(error_message) << std::endl;
+ error_message = std::string("A serialization error occurred:\n")
+ + e.what() + "\n\nThe server is probably "
+ " running a different version of " PROJECT_NAME_C ".";
+ errorstream << error_message << std::endl;
} catch (ServerError &e) {
- error_message = narrow_to_wide(e.what());
- errorstream << "ServerError: " << e.what() << std::endl;
+ error_message = e.what();
+ errorstream << "ServerError: " << error_message << std::endl;
} catch (ModError &e) {
- errorstream << "ModError: " << e.what() << std::endl;
- error_message = narrow_to_wide(e.what()) + wgettext("\nCheck debug.txt for details.");
+ error_message = e.what() + strgettext("\nCheck debug.txt for details.");
+ errorstream << "ModError: " << error_message << std::endl;
}
}