*/
#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 "nodemetadata.h"
-#include "main.h" // For g_settings
-#include "itemdef.h"
-#include "client/tile.h" // For TextureSource
-#include "shader.h" // For ShaderSource
+#include "gettext.h"
+#include "guiChatConsole.h"
+#include "guiFormSpecMenu.h"
+#include "guiKeyChangeMenu.h"
+#include "guiPasswordChange.h"
+#include "guiVolumeChange.h"
+#include "hud.h"
#include "logoutputbuffer.h"
-#include "subgame.h"
+#include "mainmenumanager.h"
+#include "mapblock.h"
+#include "nodedef.h" // Needed for determining pointing to nodes
+#include "nodemetadata.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 "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"
-#include "fontengine.h"
#ifdef HAVE_TOUCHSCREENGUI
-#include "touchscreengui.h"
+ #include "touchscreengui.h"
#endif
+extern Settings *g_settings;
+extern Profiler *g_profiler;
+
/*
Text input system
*/
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();
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_os;"
<< wide_to_narrow(wstrgettext("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 "\n"
+ << g_build_info << "\n"
<< "path_user = " << wrap_rows(porting::path_user, 20)
<< "\n;]";
// If address is "", local server is used and address is updated
std::string *address,
u16 port,
- std::wstring *error_message,
+ std::string &error_message,
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(GameRunData *args, f32 dtime);
+ void updateInteractTimers(GameRunData *runData, f32 dtime);
bool checkConnection();
bool handleCallbacks();
void processQueues();
- void updateProfilers(const GameRunData &run_data, const RunStats &stats,
+ 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, GameRunData *interact_args,
+ void processUserInput(VolatileRunFlags *flags, GameRunData *runData,
f32 dtime);
void processKeyboardInput(VolatileRunFlags *flags,
float *statustext_time,
video::IVideoDriver *driver;
scene::ISceneManager *smgr;
bool *kill;
- std::wstring *error_message;
+ std::string *error_message;
IGameDef *gamedef; // Convenience (same as *client)
scene::ISceneNode *skybox;
const std::string &password,
std::string *address, // can change if simple_singleplayer_mode
u16 port,
- std::wstring *error_message,
+ std::string &error_message,
ChatBackend *chat_backend,
const SubgameSpec &gamespec,
bool simple_singleplayer_mode)
// "cache"
this->device = device;
this->kill = kill;
- this->error_message = error_message;
+ this->error_message = &error_message;
this->random_input = random_input;
this->input = input;
this->chat_backend = chat_backend;
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;
}
-
+/****************************************************************************/
/****************************************************************************
Startup
****************************************************************************/
+/****************************************************************************/
bool Game::init(
const std::string &map_dir,
}
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;
}
}
bool Game::createClient(const std::string &playername,
- const std::string &password, std::string *address, u16 port,
- std::wstring *error_message)
+ const std::string &password, std::string *address, u16 port)
{
showOverlayMessage(wgettext("Creating client..."), 0, 10);
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, g_fontengine->getFont());
+ client->afterContentReceived(device);
/* Camera
*/
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;
}
}
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 = narrow_to_wide(PROJECT_NAME);
+ str += L" [";
str += driver->getName();
- str += "]";
+ str += L"]";
device->setWindowCaption(str.c_str());
LocalPlayer *player = client->getEnv().getLocalPlayer();
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;
}
return true;
}
-bool Game::initGui(std::wstring *error_message)
+bool Game::initGui()
{
// First line of debug text
guitext = guienv->addStaticText(
- L"Minetest",
+ narrow_to_wide(PROJECT_NAME).c_str(),
core::rect<s32>(0, 0, 0, 0),
false, false, guiroot);
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;
}
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;
}
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;
+ 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(wgettext("Connecting to server..."), dtime, 20);
}
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;
}
}
-
+/****************************************************************************/
/****************************************************************************
Run
****************************************************************************/
+/****************************************************************************/
-inline void Game::updateInteractTimers(GameRunData *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;
}
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;
+ errorstream << *error_message << std::endl;
return false;
}
}
-void Game::updateProfilers(const GameRunData &run_data, const RunStats &stats,
+void Game::updateProfilers(const GameRunData &runData, const RunStats &stats,
const FpsControl &draw_times, f32 dtime)
{
float profiler_print_interval =
}
update_profiler_gui(guitext_profiler, g_fontengine,
- run_data.profiler_current_page, run_data.profiler_max_page,
+ runData.profiler_current_page, runData.profiler_max_page,
driver->getScreenSize().Height);
g_profiler->clear();
****************************************************************************/
void Game::processUserInput(VolatileRunFlags *flags,
- GameRunData *interact_args, f32 dtime)
+ GameRunData *runData, f32 dtime)
{
// Reset input if window not active or some menu is active
if (device->isWindowActive() == false
#endif
// Increase timer for double tap of "keymap_jump"
- if (m_cache_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->reset_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);
}
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, invert the meaning of holding down the fast button (i.e.
+ * holding down the fast button -- if there is one -- means walk), unless
+ * performing an action, sneaking or jumping.
+ */
+ const u32 autofast_exludebits =
+ (1U << 4) | (1U << 6) // jump, sneak
+ | (1U << 7) | (1U << 8); // left state, right state
+
+ if ((keypress_bits & autofast_exludebits) == 0) {
+ control.aux1 = control.aux1 ^ true;
+ keypress_bits ^= ((u32)(1U << 5));
+ }
+#endif
+
client->setPlayerControl(control);
LocalPlayer *player = client->getEnv().getLocalPlayer();
- player->keyPressed =
- ( (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
- );
+ player->keyPressed = keypress_bits;
//tt.stop();
}
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 {
std::ostringstream os(std::ios_base::binary);
os << std::fixed
- << "Minetest " << minetest_version_hash
+ << PROJECT_NAME " " << g_version_hash
<< " FPS = " << fps
<< " (R: range_all=" << draw_control->range_all << ")"
<< std::setprecision(0)
guitext->setVisible(true);
} else if (flags.show_hud || flags.show_chat) {
std::ostringstream os(std::ios_base::binary);
- os << "Minetest " << minetest_version_hash;
+ os << PROJECT_NAME " " << g_version_hash;
guitext->setText(narrow_to_wide(os.str()).c_str());
guitext->setVisible(true);
} else {
// not using getRealTime is necessary for wine
device->getTimer()->tick(); // Maker sure device time is up-to-date
u32 time = device->getTimer()->getTime();
-
u32 last_time = fps_timings->last_time;
if (time > last_time) // Make sure time hasn't overflowed
fps_timings->last_time = time;
}
-
+// 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)
{
}
+/****************************************************************************/
/****************************************************************************
Shutdown / cleanup
****************************************************************************/
+/****************************************************************************/
void Game::extendedResourceCleanup()
{
}
-
+/****************************************************************************/
/****************************************************************************
extern function for launching the game
****************************************************************************/
+/****************************************************************************/
void the_game(bool *kill,
bool random_input,
const std::string &address, // If empty local server is created
u16 port,
- std::wstring &error_message,
+ std::string &error_message,
ChatBackend &chat_backend,
const SubgameSpec &gamespec, // Used for local game
bool simple_singleplayer_mode)
try {
if (game.startup(kill, random_input, input, device, map_dir,
- playername, password, &server_address, port,
- &error_message, &chat_backend, gamespec,
- simple_singleplayer_mode)) {
-
+ playername, password, &server_address, port,
+ error_message, &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 ".";
+ 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()) + wstrgettext("\nCheck debug.txt for details.");
+ error_message = e.what() + strgettext("\nCheck debug.txt for details.");
+ errorstream << "ModError: " << error_message << std::endl;
}
}
+