2011-07-23 18:17:39 +02:00
|
|
|
/*
|
2013-02-24 18:40:43 +01:00
|
|
|
Minetest
|
2013-02-24 19:38:45 +01:00
|
|
|
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
2011-07-23 18:17:39 +02:00
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
2012-06-05 16:56:56 +02:00
|
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
2011-07-23 18:17:39 +02:00
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2012-06-05 16:56:56 +02:00
|
|
|
GNU Lesser General Public License for more details.
|
2011-07-23 18:17:39 +02:00
|
|
|
|
2012-06-05 16:56:56 +02:00
|
|
|
You should have received a copy of the GNU Lesser General Public License along
|
2011-07-23 18:17:39 +02:00
|
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef NDEBUG
|
2011-11-13 23:19:48 +01:00
|
|
|
/*#ifdef _WIN32
|
2011-07-23 18:17:39 +02:00
|
|
|
#pragma message ("Disabling unit tests")
|
|
|
|
#else
|
|
|
|
#warning "Disabling unit tests"
|
2011-11-13 23:19:48 +01:00
|
|
|
#endif*/
|
2011-07-23 18:17:39 +02:00
|
|
|
// Disable unit tests
|
|
|
|
#define ENABLE_TESTS 0
|
|
|
|
#else
|
|
|
|
// Enable unit tests
|
|
|
|
#define ENABLE_TESTS 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef _MSC_VER
|
2012-03-10 15:46:19 +01:00
|
|
|
#ifndef SERVER // Dedicated server isn't linked with Irrlicht
|
2011-07-23 18:17:39 +02:00
|
|
|
#pragma comment(lib, "Irrlicht.lib")
|
|
|
|
// This would get rid of the console window
|
|
|
|
//#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
|
|
|
|
#endif
|
2012-03-10 15:46:19 +01:00
|
|
|
#pragma comment(lib, "zlibwapi.lib")
|
|
|
|
#pragma comment(lib, "Shell32.lib")
|
|
|
|
#endif
|
2011-07-23 18:17:39 +02:00
|
|
|
|
2011-10-12 12:53:38 +02:00
|
|
|
#include "irrlicht.h" // createDevice
|
|
|
|
|
|
|
|
#include "main.h"
|
|
|
|
#include "mainmenumanager.h"
|
2011-07-23 18:17:39 +02:00
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
|
|
|
#include <locale.h>
|
2012-06-17 03:00:31 +02:00
|
|
|
#include "irrlichttypes_extrabloated.h"
|
2011-07-23 18:17:39 +02:00
|
|
|
#include "debug.h"
|
|
|
|
#include "test.h"
|
2013-03-05 23:23:03 +01:00
|
|
|
#include "clouds.h"
|
2011-07-23 18:17:39 +02:00
|
|
|
#include "server.h"
|
|
|
|
#include "constants.h"
|
|
|
|
#include "porting.h"
|
|
|
|
#include "gettime.h"
|
|
|
|
#include "filesys.h"
|
|
|
|
#include "config.h"
|
2013-09-25 04:29:07 +02:00
|
|
|
#include "version.h"
|
2011-07-23 18:17:39 +02:00
|
|
|
#include "guiMainMenu.h"
|
|
|
|
#include "game.h"
|
|
|
|
#include "keycode.h"
|
|
|
|
#include "tile.h"
|
2011-12-03 09:01:14 +01:00
|
|
|
#include "chat.h"
|
2011-10-12 12:53:38 +02:00
|
|
|
#include "defaultsettings.h"
|
2011-07-23 18:17:39 +02:00
|
|
|
#include "gettext.h"
|
2011-10-12 12:53:38 +02:00
|
|
|
#include "settings.h"
|
|
|
|
#include "profiler.h"
|
2011-10-16 13:57:53 +02:00
|
|
|
#include "log.h"
|
2011-12-03 02:23:14 +01:00
|
|
|
#include "mods.h"
|
2013-02-03 13:19:09 +01:00
|
|
|
#if USE_FREETYPE
|
|
|
|
#include "xCGUITTFont.h"
|
|
|
|
#endif
|
2012-06-17 00:29:13 +02:00
|
|
|
#include "util/string.h"
|
2012-03-11 13:54:23 +01:00
|
|
|
#include "subgame.h"
|
2012-03-12 20:27:29 +01:00
|
|
|
#include "quicktune.h"
|
2012-12-25 12:20:51 +01:00
|
|
|
#include "serverlist.h"
|
2013-08-29 05:04:56 +02:00
|
|
|
#include "httpfetch.h"
|
2013-06-23 18:30:21 +02:00
|
|
|
#include "guiEngine.h"
|
2013-09-10 17:49:53 +02:00
|
|
|
#include "mapsector.h"
|
2014-08-22 14:03:04 +02:00
|
|
|
#include "player.h"
|
2011-07-23 18:17:39 +02:00
|
|
|
|
2012-10-22 23:18:44 +02:00
|
|
|
#include "database-sqlite3.h"
|
2013-09-10 18:29:51 +02:00
|
|
|
#ifdef USE_LEVELDB
|
2012-10-22 23:18:44 +02:00
|
|
|
#include "database-leveldb.h"
|
|
|
|
#endif
|
2014-04-21 14:10:59 +02:00
|
|
|
|
2014-04-08 21:39:21 +02:00
|
|
|
#if USE_REDIS
|
|
|
|
#include "database-redis.h"
|
|
|
|
#endif
|
2012-10-22 23:18:44 +02:00
|
|
|
|
2014-04-21 14:10:59 +02:00
|
|
|
#ifdef HAVE_TOUCHSCREENGUI
|
|
|
|
#include "touchscreengui.h"
|
|
|
|
#endif
|
2011-07-23 18:17:39 +02:00
|
|
|
/*
|
|
|
|
Settings.
|
|
|
|
These are loaded from the config file.
|
|
|
|
*/
|
2011-10-12 12:53:38 +02:00
|
|
|
Settings main_settings;
|
|
|
|
Settings *g_settings = &main_settings;
|
2013-08-11 04:09:45 +02:00
|
|
|
std::string g_settings_path;
|
2011-07-23 18:17:39 +02:00
|
|
|
|
|
|
|
// Global profiler
|
2011-10-12 12:53:38 +02:00
|
|
|
Profiler main_profiler;
|
|
|
|
Profiler *g_profiler = &main_profiler;
|
2011-07-23 18:17:39 +02:00
|
|
|
|
2013-05-09 18:23:48 +02:00
|
|
|
// Menu clouds are created later
|
|
|
|
Clouds *g_menuclouds = 0;
|
|
|
|
irr::scene::ISceneManager *g_menucloudsmgr = 0;
|
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
/*
|
2012-03-10 15:46:19 +01:00
|
|
|
Debug streams
|
2011-07-23 18:17:39 +02:00
|
|
|
*/
|
|
|
|
|
2012-03-10 15:46:19 +01:00
|
|
|
// Connection
|
|
|
|
std::ostream *dout_con_ptr = &dummyout;
|
|
|
|
std::ostream *derr_con_ptr = &verbosestream;
|
|
|
|
|
|
|
|
// Server
|
|
|
|
std::ostream *dout_server_ptr = &infostream;
|
|
|
|
std::ostream *derr_server_ptr = &errorstream;
|
|
|
|
|
|
|
|
// Client
|
|
|
|
std::ostream *dout_client_ptr = &infostream;
|
|
|
|
std::ostream *derr_client_ptr = &errorstream;
|
|
|
|
|
|
|
|
#ifndef SERVER
|
2011-07-23 18:17:39 +02:00
|
|
|
/*
|
2012-03-10 15:46:19 +01:00
|
|
|
Random stuff
|
2011-07-23 18:17:39 +02:00
|
|
|
*/
|
|
|
|
|
2012-03-10 15:46:19 +01:00
|
|
|
/* mainmenumanager.h */
|
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
gui::IGUIEnvironment* guienv = NULL;
|
|
|
|
gui::IGUIStaticText *guiroot = NULL;
|
|
|
|
MainMenuManager g_menumgr;
|
|
|
|
|
|
|
|
bool noMenuActive()
|
|
|
|
{
|
|
|
|
return (g_menumgr.menuCount() == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Passed to menus to allow disconnecting and exiting
|
|
|
|
MainGameCallback *g_gamecallback = NULL;
|
2012-03-10 15:46:19 +01:00
|
|
|
#endif
|
2011-07-23 18:17:39 +02:00
|
|
|
|
|
|
|
/*
|
2012-03-10 15:46:19 +01:00
|
|
|
gettime.h implementation
|
2011-07-23 18:17:39 +02:00
|
|
|
*/
|
|
|
|
|
2012-03-10 15:46:19 +01:00
|
|
|
#ifdef SERVER
|
2011-07-23 18:17:39 +02:00
|
|
|
|
2012-03-10 15:46:19 +01:00
|
|
|
u32 getTimeMs()
|
|
|
|
{
|
|
|
|
/* Use imprecise system calls directly (from porting.h) */
|
2013-03-29 21:51:57 +01:00
|
|
|
return porting::getTime(PRECISION_MILLI);
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 getTime(TimePrecision prec)
|
|
|
|
{
|
|
|
|
return porting::getTime(prec);
|
2012-03-10 15:46:19 +01:00
|
|
|
}
|
2011-07-23 18:17:39 +02:00
|
|
|
|
2012-03-10 15:46:19 +01:00
|
|
|
#else
|
2011-07-23 18:17:39 +02:00
|
|
|
|
|
|
|
// A small helper class
|
|
|
|
class TimeGetter
|
|
|
|
{
|
|
|
|
public:
|
2013-03-29 21:51:57 +01:00
|
|
|
virtual u32 getTime(TimePrecision prec) = 0;
|
2011-07-23 18:17:39 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
// A precise irrlicht one
|
|
|
|
class IrrlichtTimeGetter: public TimeGetter
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
IrrlichtTimeGetter(IrrlichtDevice *device):
|
|
|
|
m_device(device)
|
|
|
|
{}
|
2013-03-29 21:51:57 +01:00
|
|
|
u32 getTime(TimePrecision prec)
|
|
|
|
{
|
|
|
|
if (prec == PRECISION_MILLI) {
|
2014-06-01 00:55:23 +02:00
|
|
|
if (m_device == NULL)
|
2013-03-29 21:51:57 +01:00
|
|
|
return 0;
|
|
|
|
return m_device->getTimer()->getRealTime();
|
|
|
|
} else {
|
|
|
|
return porting::getTime(prec);
|
|
|
|
}
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
|
|
|
private:
|
|
|
|
IrrlichtDevice *m_device;
|
|
|
|
};
|
|
|
|
// Not so precise one which works without irrlicht
|
|
|
|
class SimpleTimeGetter: public TimeGetter
|
|
|
|
{
|
|
|
|
public:
|
2013-03-29 21:51:57 +01:00
|
|
|
u32 getTime(TimePrecision prec)
|
2011-07-23 18:17:39 +02:00
|
|
|
{
|
2013-03-29 21:51:57 +01:00
|
|
|
return porting::getTime(prec);
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// A pointer to a global instance of the time getter
|
|
|
|
// TODO: why?
|
|
|
|
TimeGetter *g_timegetter = NULL;
|
|
|
|
|
|
|
|
u32 getTimeMs()
|
|
|
|
{
|
2014-06-01 00:55:23 +02:00
|
|
|
if (g_timegetter == NULL)
|
2011-07-23 18:17:39 +02:00
|
|
|
return 0;
|
2013-03-29 21:51:57 +01:00
|
|
|
return g_timegetter->getTime(PRECISION_MILLI);
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 getTime(TimePrecision prec) {
|
|
|
|
if (g_timegetter == NULL)
|
|
|
|
return 0;
|
|
|
|
return g_timegetter->getTime(prec);
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
2013-05-01 13:09:10 +02:00
|
|
|
#endif
|
|
|
|
|
2012-03-10 15:46:19 +01:00
|
|
|
class StderrLogOutput: public ILogOutput
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
/* line: Full line with timestamp, level and thread */
|
|
|
|
void printLog(const std::string &line)
|
|
|
|
{
|
2014-06-01 00:55:23 +02:00
|
|
|
std::cerr << line << std::endl;
|
2012-03-10 15:46:19 +01:00
|
|
|
}
|
|
|
|
} main_stderr_log_out;
|
|
|
|
|
|
|
|
class DstreamNoStderrLogOutput: public ILogOutput
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
/* line: Full line with timestamp, level and thread */
|
|
|
|
void printLog(const std::string &line)
|
|
|
|
{
|
2014-06-01 00:55:23 +02:00
|
|
|
dstream_no_stderr << line << std::endl;
|
2012-03-10 15:46:19 +01:00
|
|
|
}
|
|
|
|
} main_dstream_no_stderr_log_out;
|
|
|
|
|
|
|
|
#ifndef SERVER
|
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
/*
|
|
|
|
Event handler for Irrlicht
|
|
|
|
|
|
|
|
NOTE: Everything possible should be moved out from here,
|
|
|
|
probably to InputHandler and the_game
|
|
|
|
*/
|
|
|
|
|
|
|
|
class MyEventReceiver : public IEventReceiver
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
// This is the one method that we have to implement
|
|
|
|
virtual bool OnEvent(const SEvent& event)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
React to nothing here if a menu is active
|
|
|
|
*/
|
2014-06-01 00:55:23 +02:00
|
|
|
if (noMenuActive() == false) {
|
2014-04-21 14:10:59 +02:00
|
|
|
#ifdef HAVE_TOUCHSCREENGUI
|
|
|
|
if (m_touchscreengui != 0) {
|
|
|
|
m_touchscreengui->Toggle(false);
|
|
|
|
}
|
|
|
|
#endif
|
2013-08-19 11:26:51 +02:00
|
|
|
return g_menumgr.preprocessEvent(event);
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Remember whether each key is down or up
|
2014-06-01 00:55:23 +02:00
|
|
|
if (event.EventType == irr::EET_KEY_INPUT_EVENT) {
|
|
|
|
if (event.KeyInput.PressedDown) {
|
2011-08-13 22:44:31 +02:00
|
|
|
keyIsDown.set(event.KeyInput);
|
|
|
|
keyWasDown.set(event.KeyInput);
|
|
|
|
} else {
|
|
|
|
keyIsDown.unset(event.KeyInput);
|
|
|
|
}
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
|
|
|
|
2014-04-21 14:10:59 +02:00
|
|
|
#ifdef HAVE_TOUCHSCREENGUI
|
|
|
|
// case of touchscreengui we have to handle different events
|
|
|
|
if ((m_touchscreengui != 0) &&
|
|
|
|
(event.EventType == irr::EET_TOUCH_INPUT_EVENT)) {
|
|
|
|
m_touchscreengui->translateEvent(event);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
// handle mouse events
|
|
|
|
if(event.EventType == irr::EET_MOUSE_INPUT_EVENT) {
|
2014-06-01 00:55:23 +02:00
|
|
|
if (noMenuActive() == false) {
|
2011-07-23 18:17:39 +02:00
|
|
|
left_active = false;
|
|
|
|
middle_active = false;
|
|
|
|
right_active = false;
|
2014-06-01 00:55:23 +02:00
|
|
|
} else {
|
2011-07-23 18:17:39 +02:00
|
|
|
left_active = event.MouseInput.isLeftPressed();
|
|
|
|
middle_active = event.MouseInput.isMiddlePressed();
|
|
|
|
right_active = event.MouseInput.isRightPressed();
|
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) {
|
2011-07-23 18:17:39 +02:00
|
|
|
leftclicked = true;
|
|
|
|
}
|
2014-06-01 00:55:23 +02:00
|
|
|
if (event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN) {
|
2011-07-23 18:17:39 +02:00
|
|
|
rightclicked = true;
|
|
|
|
}
|
2014-06-01 00:55:23 +02:00
|
|
|
if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) {
|
2011-07-23 18:17:39 +02:00
|
|
|
leftreleased = true;
|
|
|
|
}
|
2014-06-01 00:55:23 +02:00
|
|
|
if (event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP) {
|
2011-07-23 18:17:39 +02:00
|
|
|
rightreleased = true;
|
|
|
|
}
|
2014-06-01 00:55:23 +02:00
|
|
|
if (event.MouseInput.Event == EMIE_MOUSE_WHEEL) {
|
2011-07-23 18:17:39 +02:00
|
|
|
mouse_wheel += event.MouseInput.Wheel;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-04-21 14:10:59 +02:00
|
|
|
if(event.EventType == irr::EET_LOG_TEXT_EVENT) {
|
|
|
|
dstream<< std::string("Irrlicht log: ") + std::string(event.LogEvent.Text)<<std::endl;
|
2014-05-08 00:58:00 +02:00
|
|
|
return true;
|
|
|
|
}
|
2014-04-20 10:55:08 +02:00
|
|
|
/* always return false in order to continue processing events */
|
2011-07-23 18:17:39 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-08-13 22:44:31 +02:00
|
|
|
bool IsKeyDown(const KeyPress &keyCode) const
|
2011-07-23 18:17:39 +02:00
|
|
|
{
|
|
|
|
return keyIsDown[keyCode];
|
|
|
|
}
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
// Checks whether a key was down and resets the state
|
2011-08-13 22:44:31 +02:00
|
|
|
bool WasKeyDown(const KeyPress &keyCode)
|
2011-07-23 18:17:39 +02:00
|
|
|
{
|
|
|
|
bool b = keyWasDown[keyCode];
|
2011-08-13 22:44:31 +02:00
|
|
|
if (b)
|
|
|
|
keyWasDown.unset(keyCode);
|
2011-07-23 18:17:39 +02:00
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
s32 getMouseWheel()
|
|
|
|
{
|
|
|
|
s32 a = mouse_wheel;
|
|
|
|
mouse_wheel = 0;
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
void clearInput()
|
|
|
|
{
|
2011-08-13 22:44:31 +02:00
|
|
|
keyIsDown.clear();
|
|
|
|
keyWasDown.clear();
|
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
leftclicked = false;
|
|
|
|
rightclicked = false;
|
|
|
|
leftreleased = false;
|
|
|
|
rightreleased = false;
|
|
|
|
|
|
|
|
left_active = false;
|
|
|
|
middle_active = false;
|
|
|
|
right_active = false;
|
|
|
|
|
|
|
|
mouse_wheel = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
MyEventReceiver()
|
|
|
|
{
|
|
|
|
clearInput();
|
2014-04-21 14:10:59 +02:00
|
|
|
#ifdef HAVE_TOUCHSCREENGUI
|
|
|
|
m_touchscreengui = NULL;
|
|
|
|
#endif
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool leftclicked;
|
|
|
|
bool rightclicked;
|
|
|
|
bool leftreleased;
|
|
|
|
bool rightreleased;
|
|
|
|
|
|
|
|
bool left_active;
|
|
|
|
bool middle_active;
|
|
|
|
bool right_active;
|
|
|
|
|
|
|
|
s32 mouse_wheel;
|
|
|
|
|
2014-04-21 14:10:59 +02:00
|
|
|
#ifdef HAVE_TOUCHSCREENGUI
|
|
|
|
TouchScreenGUI* m_touchscreengui;
|
|
|
|
#endif
|
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
private:
|
|
|
|
// The current state of keys
|
2011-08-13 22:44:31 +02:00
|
|
|
KeyList keyIsDown;
|
2011-07-23 18:17:39 +02:00
|
|
|
// Whether a key has been pressed or not
|
2011-08-13 22:44:31 +02:00
|
|
|
KeyList keyWasDown;
|
2011-07-23 18:17:39 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
Separated input handler
|
|
|
|
*/
|
|
|
|
|
|
|
|
class RealInputHandler : public InputHandler
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
RealInputHandler(IrrlichtDevice *device, MyEventReceiver *receiver):
|
|
|
|
m_device(device),
|
2014-04-21 14:10:59 +02:00
|
|
|
m_receiver(receiver),
|
|
|
|
m_mousepos(0,0)
|
2011-07-23 18:17:39 +02:00
|
|
|
{
|
|
|
|
}
|
2011-08-13 22:44:31 +02:00
|
|
|
virtual bool isKeyDown(const KeyPress &keyCode)
|
2011-07-23 18:17:39 +02:00
|
|
|
{
|
|
|
|
return m_receiver->IsKeyDown(keyCode);
|
|
|
|
}
|
2011-08-13 22:44:31 +02:00
|
|
|
virtual bool wasKeyDown(const KeyPress &keyCode)
|
2011-07-23 18:17:39 +02:00
|
|
|
{
|
|
|
|
return m_receiver->WasKeyDown(keyCode);
|
|
|
|
}
|
|
|
|
virtual v2s32 getMousePos()
|
|
|
|
{
|
2014-04-21 14:10:59 +02:00
|
|
|
if (m_device->getCursorControl()) {
|
|
|
|
return m_device->getCursorControl()->getPosition();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return m_mousepos;
|
|
|
|
}
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
|
|
|
virtual void setMousePos(s32 x, s32 y)
|
|
|
|
{
|
2014-04-21 14:10:59 +02:00
|
|
|
if (m_device->getCursorControl()) {
|
|
|
|
m_device->getCursorControl()->setPosition(x, y);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_mousepos = v2s32(x,y);
|
|
|
|
}
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool getLeftState()
|
|
|
|
{
|
|
|
|
return m_receiver->left_active;
|
|
|
|
}
|
|
|
|
virtual bool getRightState()
|
|
|
|
{
|
|
|
|
return m_receiver->right_active;
|
|
|
|
}
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
virtual bool getLeftClicked()
|
|
|
|
{
|
|
|
|
return m_receiver->leftclicked;
|
|
|
|
}
|
|
|
|
virtual bool getRightClicked()
|
|
|
|
{
|
|
|
|
return m_receiver->rightclicked;
|
|
|
|
}
|
|
|
|
virtual void resetLeftClicked()
|
|
|
|
{
|
|
|
|
m_receiver->leftclicked = false;
|
|
|
|
}
|
|
|
|
virtual void resetRightClicked()
|
|
|
|
{
|
|
|
|
m_receiver->rightclicked = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool getLeftReleased()
|
|
|
|
{
|
|
|
|
return m_receiver->leftreleased;
|
|
|
|
}
|
|
|
|
virtual bool getRightReleased()
|
|
|
|
{
|
|
|
|
return m_receiver->rightreleased;
|
|
|
|
}
|
|
|
|
virtual void resetLeftReleased()
|
|
|
|
{
|
|
|
|
m_receiver->leftreleased = false;
|
|
|
|
}
|
|
|
|
virtual void resetRightReleased()
|
|
|
|
{
|
|
|
|
m_receiver->rightreleased = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual s32 getMouseWheel()
|
|
|
|
{
|
|
|
|
return m_receiver->getMouseWheel();
|
|
|
|
}
|
|
|
|
|
|
|
|
void clear()
|
|
|
|
{
|
|
|
|
m_receiver->clearInput();
|
|
|
|
}
|
|
|
|
private:
|
2014-04-21 14:10:59 +02:00
|
|
|
IrrlichtDevice *m_device;
|
2011-07-23 18:17:39 +02:00
|
|
|
MyEventReceiver *m_receiver;
|
2014-04-21 14:10:59 +02:00
|
|
|
v2s32 m_mousepos;
|
2011-07-23 18:17:39 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
class RandomInputHandler : public InputHandler
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
RandomInputHandler()
|
|
|
|
{
|
|
|
|
leftdown = false;
|
|
|
|
rightdown = false;
|
|
|
|
leftclicked = false;
|
|
|
|
rightclicked = false;
|
|
|
|
leftreleased = false;
|
|
|
|
rightreleased = false;
|
2011-08-13 22:44:31 +02:00
|
|
|
keydown.clear();
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
2011-08-13 22:44:31 +02:00
|
|
|
virtual bool isKeyDown(const KeyPress &keyCode)
|
2011-07-23 18:17:39 +02:00
|
|
|
{
|
|
|
|
return keydown[keyCode];
|
|
|
|
}
|
2011-08-13 22:44:31 +02:00
|
|
|
virtual bool wasKeyDown(const KeyPress &keyCode)
|
2011-07-23 18:17:39 +02:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
virtual v2s32 getMousePos()
|
|
|
|
{
|
|
|
|
return mousepos;
|
|
|
|
}
|
|
|
|
virtual void setMousePos(s32 x, s32 y)
|
|
|
|
{
|
2014-06-01 00:55:23 +02:00
|
|
|
mousepos = v2s32(x, y);
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool getLeftState()
|
|
|
|
{
|
|
|
|
return leftdown;
|
|
|
|
}
|
|
|
|
virtual bool getRightState()
|
|
|
|
{
|
|
|
|
return rightdown;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool getLeftClicked()
|
|
|
|
{
|
|
|
|
return leftclicked;
|
|
|
|
}
|
|
|
|
virtual bool getRightClicked()
|
|
|
|
{
|
|
|
|
return rightclicked;
|
|
|
|
}
|
|
|
|
virtual void resetLeftClicked()
|
|
|
|
{
|
|
|
|
leftclicked = false;
|
|
|
|
}
|
|
|
|
virtual void resetRightClicked()
|
|
|
|
{
|
|
|
|
rightclicked = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool getLeftReleased()
|
|
|
|
{
|
|
|
|
return leftreleased;
|
|
|
|
}
|
|
|
|
virtual bool getRightReleased()
|
|
|
|
{
|
|
|
|
return rightreleased;
|
|
|
|
}
|
|
|
|
virtual void resetLeftReleased()
|
|
|
|
{
|
|
|
|
leftreleased = false;
|
|
|
|
}
|
|
|
|
virtual void resetRightReleased()
|
|
|
|
{
|
|
|
|
rightreleased = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual s32 getMouseWheel()
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void step(float dtime)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
static float counter1 = 0;
|
|
|
|
counter1 -= dtime;
|
2014-06-01 00:55:23 +02:00
|
|
|
if (counter1 < 0.0) {
|
|
|
|
counter1 = 0.1 * Rand(1, 40);
|
2011-08-13 22:44:31 +02:00
|
|
|
keydown.toggle(getKeySetting("keymap_jump"));
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
static float counter1 = 0;
|
|
|
|
counter1 -= dtime;
|
2014-06-01 00:55:23 +02:00
|
|
|
if (counter1 < 0.0) {
|
|
|
|
counter1 = 0.1 * Rand(1, 40);
|
2011-08-13 22:44:31 +02:00
|
|
|
keydown.toggle(getKeySetting("keymap_special1"));
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
static float counter1 = 0;
|
|
|
|
counter1 -= dtime;
|
2014-06-01 00:55:23 +02:00
|
|
|
if (counter1 < 0.0) {
|
|
|
|
counter1 = 0.1 * Rand(1, 40);
|
2011-08-13 22:44:31 +02:00
|
|
|
keydown.toggle(getKeySetting("keymap_forward"));
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
static float counter1 = 0;
|
|
|
|
counter1 -= dtime;
|
2014-06-01 00:55:23 +02:00
|
|
|
if (counter1 < 0.0) {
|
|
|
|
counter1 = 0.1 * Rand(1, 40);
|
2011-08-13 22:44:31 +02:00
|
|
|
keydown.toggle(getKeySetting("keymap_left"));
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
static float counter1 = 0;
|
|
|
|
counter1 -= dtime;
|
2014-06-01 00:55:23 +02:00
|
|
|
if (counter1 < 0.0) {
|
|
|
|
counter1 = 0.1 * Rand(1, 20);
|
|
|
|
mousespeed = v2s32(Rand(-20, 20), Rand(-15, 20));
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
static float counter1 = 0;
|
|
|
|
counter1 -= dtime;
|
2014-06-01 00:55:23 +02:00
|
|
|
if (counter1 < 0.0) {
|
|
|
|
counter1 = 0.1 * Rand(1, 30);
|
2011-07-23 18:17:39 +02:00
|
|
|
leftdown = !leftdown;
|
2014-06-01 00:55:23 +02:00
|
|
|
if (leftdown)
|
2011-07-23 18:17:39 +02:00
|
|
|
leftclicked = true;
|
2014-06-01 00:55:23 +02:00
|
|
|
if (!leftdown)
|
2011-07-23 18:17:39 +02:00
|
|
|
leftreleased = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
static float counter1 = 0;
|
|
|
|
counter1 -= dtime;
|
2014-06-01 00:55:23 +02:00
|
|
|
if (counter1 < 0.0) {
|
|
|
|
counter1 = 0.1 * Rand(1, 15);
|
2011-07-23 18:17:39 +02:00
|
|
|
rightdown = !rightdown;
|
2014-06-01 00:55:23 +02:00
|
|
|
if (rightdown)
|
2011-07-23 18:17:39 +02:00
|
|
|
rightclicked = true;
|
2014-06-01 00:55:23 +02:00
|
|
|
if (!rightdown)
|
2011-07-23 18:17:39 +02:00
|
|
|
rightreleased = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mousepos += mousespeed;
|
|
|
|
}
|
|
|
|
|
|
|
|
s32 Rand(s32 min, s32 max)
|
|
|
|
{
|
|
|
|
return (myrand()%(max-min+1))+min;
|
|
|
|
}
|
|
|
|
private:
|
2011-08-13 22:44:31 +02:00
|
|
|
KeyList keydown;
|
2011-07-23 18:17:39 +02:00
|
|
|
v2s32 mousepos;
|
|
|
|
v2s32 mousespeed;
|
|
|
|
bool leftdown;
|
|
|
|
bool rightdown;
|
|
|
|
bool leftclicked;
|
|
|
|
bool rightclicked;
|
|
|
|
bool leftreleased;
|
|
|
|
bool rightreleased;
|
|
|
|
};
|
|
|
|
|
2013-02-15 20:13:53 +01:00
|
|
|
#endif // !SERVER
|
2012-03-10 15:46:19 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
// These are defined global so that they're not optimized too much.
|
|
|
|
// Can't change them to volatile.
|
|
|
|
s16 temp16;
|
|
|
|
f32 tempf;
|
|
|
|
v3f tempv3f1;
|
|
|
|
v3f tempv3f2;
|
|
|
|
std::string tempstring;
|
|
|
|
std::string tempstring2;
|
|
|
|
|
|
|
|
void SpeedTests()
|
|
|
|
{
|
|
|
|
{
|
2014-06-01 00:55:23 +02:00
|
|
|
infostream << "The following test should take around 20ms." << std::endl;
|
2011-07-23 18:17:39 +02:00
|
|
|
TimeTaker timer("Testing std::string speed");
|
|
|
|
const u32 jj = 10000;
|
2014-06-01 00:55:23 +02:00
|
|
|
for(u32 j = 0; j < jj; j++) {
|
2011-07-23 18:17:39 +02:00
|
|
|
tempstring = "";
|
|
|
|
tempstring2 = "";
|
|
|
|
const u32 ii = 10;
|
2014-06-01 00:55:23 +02:00
|
|
|
for(u32 i = 0; i < ii; i++) {
|
2011-07-23 18:17:39 +02:00
|
|
|
tempstring2 += "asd";
|
|
|
|
}
|
2014-06-01 00:55:23 +02:00
|
|
|
for(u32 i = 0; i < ii+1; i++) {
|
2011-07-23 18:17:39 +02:00
|
|
|
tempstring += "asd";
|
2014-06-01 00:55:23 +02:00
|
|
|
if (tempstring == tempstring2)
|
2011-07-23 18:17:39 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
infostream << "All of the following tests should take around 100ms each."
|
|
|
|
<< std::endl;
|
2011-07-23 18:17:39 +02:00
|
|
|
|
|
|
|
{
|
|
|
|
TimeTaker timer("Testing floating-point conversion speed");
|
|
|
|
tempf = 0.001;
|
2014-06-01 00:55:23 +02:00
|
|
|
for(u32 i = 0; i < 4000000; i++) {
|
2011-07-23 18:17:39 +02:00
|
|
|
temp16 += tempf;
|
|
|
|
tempf += 0.001;
|
|
|
|
}
|
|
|
|
}
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
{
|
|
|
|
TimeTaker timer("Testing floating-point vector speed");
|
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
tempv3f1 = v3f(1, 2, 3);
|
|
|
|
tempv3f2 = v3f(4, 5, 6);
|
|
|
|
for(u32 i = 0; i < 10000000; i++) {
|
2011-07-23 18:17:39 +02:00
|
|
|
tempf += tempv3f1.dotProduct(tempv3f2);
|
2014-06-01 00:55:23 +02:00
|
|
|
tempv3f2 += v3f(7, 8, 9);
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2012-12-20 18:19:49 +01:00
|
|
|
TimeTaker timer("Testing std::map speed");
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2012-12-20 18:19:49 +01:00
|
|
|
std::map<v2s16, f32> map1;
|
2011-07-23 18:17:39 +02:00
|
|
|
tempf = -324;
|
2014-06-01 00:55:23 +02:00
|
|
|
const s16 ii = 300;
|
|
|
|
for(s16 y = 0; y < ii; y++) {
|
|
|
|
for(s16 x = 0; x < ii; x++) {
|
|
|
|
map1[v2s16(x, y)] = tempf;
|
2011-07-23 18:17:39 +02:00
|
|
|
tempf += 1;
|
|
|
|
}
|
|
|
|
}
|
2014-06-01 00:55:23 +02:00
|
|
|
for(s16 y = ii - 1; y >= 0; y--) {
|
|
|
|
for(s16 x = 0; x < ii; x++) {
|
|
|
|
tempf = map1[v2s16(x, y)];
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2014-06-01 00:55:23 +02:00
|
|
|
infostream << "Around 5000/ms should do well here." << std::endl;
|
2011-07-23 18:17:39 +02:00
|
|
|
TimeTaker timer("Testing mutex speed");
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
JMutex m;
|
|
|
|
u32 n = 0;
|
|
|
|
u32 i = 0;
|
2014-06-01 00:55:23 +02:00
|
|
|
do {
|
2011-07-23 18:17:39 +02:00
|
|
|
n += 10000;
|
2014-06-01 00:55:23 +02:00
|
|
|
for(; i < n; i++) {
|
2011-07-23 18:17:39 +02:00
|
|
|
m.Lock();
|
|
|
|
m.Unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Do at least 10ms
|
2013-03-29 21:51:57 +01:00
|
|
|
while(timer.getTimerTime() < 10);
|
2011-07-23 18:17:39 +02:00
|
|
|
|
|
|
|
u32 dtime = timer.stop();
|
|
|
|
u32 per_ms = n / dtime;
|
2014-06-01 00:55:23 +02:00
|
|
|
infostream << "Done. " << dtime << "ms, " << per_ms << "/ms" << std::endl;
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
static void print_worldspecs(const std::vector<WorldSpec> &worldspecs, std::ostream &os)
|
2012-03-25 19:29:56 +02:00
|
|
|
{
|
2014-06-01 00:55:23 +02:00
|
|
|
for(u32 i = 0; i < worldspecs.size(); i++) {
|
2012-03-25 19:29:56 +02:00
|
|
|
std::string name = worldspecs[i].name;
|
|
|
|
std::string path = worldspecs[i].path;
|
2014-06-01 00:55:23 +02:00
|
|
|
if (name.find(" ") != std::string::npos)
|
2012-03-25 19:29:56 +02:00
|
|
|
name = std::string("'") + name + "'";
|
|
|
|
path = std::string("'") + path + "'";
|
|
|
|
name = padStringRight(name, 14);
|
2014-06-01 00:55:23 +02:00
|
|
|
os << " " << name << " " << path << std::endl;
|
2012-03-25 19:29:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2012-03-11 11:06:59 +01:00
|
|
|
int retval = 0;
|
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
/*
|
|
|
|
Initialization
|
|
|
|
*/
|
|
|
|
|
2011-10-17 09:46:16 +02:00
|
|
|
log_add_output_maxlev(&main_stderr_log_out, LMT_ACTION);
|
2011-10-16 13:57:53 +02:00
|
|
|
log_add_output_all_levs(&main_dstream_no_stderr_log_out);
|
|
|
|
|
|
|
|
log_register_thread("main");
|
2011-07-23 18:17:39 +02:00
|
|
|
/*
|
|
|
|
Parse command line
|
|
|
|
*/
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
// List all allowed options
|
2012-12-20 18:19:49 +01:00
|
|
|
std::map<std::string, ValueSpec> allowed_options;
|
|
|
|
allowed_options.insert(std::make_pair("help", ValueSpec(VALUETYPE_FLAG,
|
|
|
|
_("Show allowed options"))));
|
2013-09-25 04:47:44 +02:00
|
|
|
allowed_options.insert(std::make_pair("version", ValueSpec(VALUETYPE_FLAG,
|
|
|
|
_("Show version information"))));
|
2012-12-20 18:19:49 +01:00
|
|
|
allowed_options.insert(std::make_pair("config", ValueSpec(VALUETYPE_STRING,
|
|
|
|
_("Load configuration from specified file"))));
|
|
|
|
allowed_options.insert(std::make_pair("port", ValueSpec(VALUETYPE_STRING,
|
|
|
|
_("Set network port (UDP)"))));
|
|
|
|
allowed_options.insert(std::make_pair("disable-unittests", ValueSpec(VALUETYPE_FLAG,
|
|
|
|
_("Disable unit tests"))));
|
|
|
|
allowed_options.insert(std::make_pair("enable-unittests", ValueSpec(VALUETYPE_FLAG,
|
|
|
|
_("Enable unit tests"))));
|
|
|
|
allowed_options.insert(std::make_pair("map-dir", ValueSpec(VALUETYPE_STRING,
|
|
|
|
_("Same as --world (deprecated)"))));
|
|
|
|
allowed_options.insert(std::make_pair("world", ValueSpec(VALUETYPE_STRING,
|
|
|
|
_("Set world path (implies local game) ('list' lists all)"))));
|
|
|
|
allowed_options.insert(std::make_pair("worldname", ValueSpec(VALUETYPE_STRING,
|
|
|
|
_("Set world by name (implies local game)"))));
|
2014-05-08 00:58:00 +02:00
|
|
|
allowed_options.insert(std::make_pair("quiet", ValueSpec(VALUETYPE_FLAG,
|
|
|
|
_("Print to console errors only"))));
|
2012-12-20 18:19:49 +01:00
|
|
|
allowed_options.insert(std::make_pair("info", ValueSpec(VALUETYPE_FLAG,
|
|
|
|
_("Print more information to console"))));
|
|
|
|
allowed_options.insert(std::make_pair("verbose", ValueSpec(VALUETYPE_FLAG,
|
|
|
|
_("Print even more information to console"))));
|
|
|
|
allowed_options.insert(std::make_pair("trace", ValueSpec(VALUETYPE_FLAG,
|
|
|
|
_("Print enormous amounts of information to log and console"))));
|
|
|
|
allowed_options.insert(std::make_pair("logfile", ValueSpec(VALUETYPE_STRING,
|
|
|
|
_("Set logfile path ('' = no logging)"))));
|
|
|
|
allowed_options.insert(std::make_pair("gameid", ValueSpec(VALUETYPE_STRING,
|
|
|
|
_("Set gameid (\"--gameid list\" prints available ones)"))));
|
2013-09-06 18:22:12 +02:00
|
|
|
allowed_options.insert(std::make_pair("migrate", ValueSpec(VALUETYPE_STRING,
|
2013-09-09 19:40:02 +02:00
|
|
|
_("Migrate from current map backend to another (Only works when using minetestserver or with --server)"))));
|
2012-03-10 15:46:19 +01:00
|
|
|
#ifndef SERVER
|
2013-05-09 15:53:29 +02:00
|
|
|
allowed_options.insert(std::make_pair("videomodes", ValueSpec(VALUETYPE_FLAG,
|
|
|
|
_("Show available video modes"))));
|
2012-12-20 18:19:49 +01:00
|
|
|
allowed_options.insert(std::make_pair("speedtests", ValueSpec(VALUETYPE_FLAG,
|
|
|
|
_("Run speed tests"))));
|
|
|
|
allowed_options.insert(std::make_pair("address", ValueSpec(VALUETYPE_STRING,
|
|
|
|
_("Address to connect to. ('' = local game)"))));
|
|
|
|
allowed_options.insert(std::make_pair("random-input", ValueSpec(VALUETYPE_FLAG,
|
|
|
|
_("Enable random user input, for testing"))));
|
|
|
|
allowed_options.insert(std::make_pair("server", ValueSpec(VALUETYPE_FLAG,
|
|
|
|
_("Run dedicated server"))));
|
|
|
|
allowed_options.insert(std::make_pair("name", ValueSpec(VALUETYPE_STRING,
|
|
|
|
_("Set player name"))));
|
|
|
|
allowed_options.insert(std::make_pair("password", ValueSpec(VALUETYPE_STRING,
|
|
|
|
_("Set password"))));
|
|
|
|
allowed_options.insert(std::make_pair("go", ValueSpec(VALUETYPE_FLAG,
|
|
|
|
_("Disable main menu"))));
|
2012-03-10 15:46:19 +01:00
|
|
|
#endif
|
2011-07-23 18:17:39 +02:00
|
|
|
|
|
|
|
Settings cmd_args;
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
bool ret = cmd_args.parseCommandLine(argc, argv, allowed_options);
|
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
if (ret == false || cmd_args.getFlag("help") || cmd_args.exists("nonopt1")) {
|
|
|
|
dstream << _("Allowed options:") << std::endl;
|
2012-12-20 18:19:49 +01:00
|
|
|
for(std::map<std::string, ValueSpec>::iterator
|
|
|
|
i = allowed_options.begin();
|
2014-06-01 00:55:23 +02:00
|
|
|
i != allowed_options.end(); ++i) {
|
2012-03-11 10:02:22 +01:00
|
|
|
std::ostringstream os1(std::ios::binary);
|
2014-06-01 00:55:23 +02:00
|
|
|
os1 << " --"<<i->first;
|
|
|
|
if (i->second.type == VALUETYPE_FLAG) {
|
|
|
|
} else
|
|
|
|
os1 << _(" <value>");
|
|
|
|
dstream << padStringRight(os1.str(), 24);
|
|
|
|
|
|
|
|
if (i->second.help != NULL)
|
|
|
|
dstream << i->second.help;
|
|
|
|
dstream << std::endl;
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return cmd_args.getFlag("help") ? 0 : 1;
|
|
|
|
}
|
2013-09-25 04:47:44 +02:00
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
if (cmd_args.getFlag("version")) {
|
2013-09-25 04:47:44 +02:00
|
|
|
#ifdef SERVER
|
2014-06-01 00:55:23 +02:00
|
|
|
dstream << "minetestserver " << minetest_version_hash << std::endl;
|
2013-09-25 04:47:44 +02:00
|
|
|
#else
|
2014-06-01 00:55:23 +02:00
|
|
|
dstream << "Minetest " << minetest_version_hash << std::endl;
|
|
|
|
dstream << "Using Irrlicht " << IRRLICHT_SDK_VERSION << std::endl;
|
2013-09-25 04:47:44 +02:00
|
|
|
#endif
|
2014-06-01 00:55:23 +02:00
|
|
|
dstream << "Build info: " << minetest_build_info << std::endl;
|
2013-09-25 04:47:44 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
/*
|
|
|
|
Low-level initialization
|
|
|
|
*/
|
2014-05-20 19:04:57 +02:00
|
|
|
|
2014-05-08 00:58:00 +02:00
|
|
|
// Quiet mode, print errors only
|
2014-06-01 00:55:23 +02:00
|
|
|
if (cmd_args.getFlag("quiet")) {
|
2014-05-08 00:58:00 +02:00
|
|
|
log_remove_output(&main_stderr_log_out);
|
|
|
|
log_add_output_maxlev(&main_stderr_log_out, LMT_ERROR);
|
|
|
|
}
|
2012-03-22 13:10:24 +01:00
|
|
|
// If trace is enabled, enable logging of certain things
|
2014-06-01 00:55:23 +02:00
|
|
|
if (cmd_args.getFlag("trace")) {
|
|
|
|
dstream << _("Enabling trace level debug output") << std::endl;
|
2012-05-20 17:30:30 +02:00
|
|
|
log_trace_level_enabled = true;
|
|
|
|
dout_con_ptr = &verbosestream; // this is somewhat old crap
|
|
|
|
socket_enable_debug_output = true; // socket doesn't use log.h
|
2012-03-22 13:10:24 +01:00
|
|
|
}
|
2012-03-11 11:06:59 +01:00
|
|
|
// In certain cases, output info level on stderr
|
2014-06-01 00:55:23 +02:00
|
|
|
if (cmd_args.getFlag("info") || cmd_args.getFlag("verbose") ||
|
2012-03-22 13:10:24 +01:00
|
|
|
cmd_args.getFlag("trace") || cmd_args.getFlag("speedtests"))
|
2011-10-17 09:46:16 +02:00
|
|
|
log_add_output(&main_stderr_log_out, LMT_INFO);
|
2012-03-22 13:10:24 +01:00
|
|
|
// In certain cases, output verbose level on stderr
|
2014-06-01 00:55:23 +02:00
|
|
|
if (cmd_args.getFlag("verbose") || cmd_args.getFlag("trace"))
|
2012-03-22 13:10:24 +01:00
|
|
|
log_add_output(&main_stderr_log_out, LMT_VERBOSE);
|
2011-07-23 18:17:39 +02:00
|
|
|
|
|
|
|
porting::signal_handler_init();
|
|
|
|
bool &kill = *porting::signal_handler_killstatus();
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
porting::initializePaths();
|
|
|
|
|
2014-04-21 14:10:59 +02:00
|
|
|
#ifdef __ANDROID__
|
|
|
|
porting::initAndroid();
|
|
|
|
|
|
|
|
porting::setExternalStorageDir(porting::jnienv);
|
|
|
|
if (!fs::PathExists(porting::path_user)) {
|
|
|
|
fs::CreateDir(porting::path_user);
|
|
|
|
}
|
|
|
|
porting::copyAssets();
|
|
|
|
#else
|
2011-07-23 18:17:39 +02:00
|
|
|
// Create user data directory
|
2012-03-10 14:56:24 +01:00
|
|
|
fs::CreateDir(porting::path_user);
|
2014-04-21 14:10:59 +02:00
|
|
|
#endif
|
2011-07-23 18:17:39 +02:00
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
infostream << "path_share = " << porting::path_share << std::endl;
|
|
|
|
infostream << "path_user = " << porting::path_user << std::endl;
|
2011-07-23 18:17:39 +02:00
|
|
|
|
2012-03-11 14:28:35 +01:00
|
|
|
// Initialize debug stacks
|
|
|
|
debug_stacks_init();
|
|
|
|
DSTACK(__FUNCTION_NAME);
|
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
// Debug handler
|
|
|
|
BEGIN_DEBUG_EXCEPTION_HANDLER
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2012-03-11 14:20:42 +01:00
|
|
|
// List gameids if requested
|
2014-06-01 00:55:23 +02:00
|
|
|
if (cmd_args.exists("gameid") && cmd_args.get("gameid") == "list") {
|
2012-03-11 14:20:42 +01:00
|
|
|
std::set<std::string> gameids = getAvailableGameIds();
|
|
|
|
for(std::set<std::string>::const_iterator i = gameids.begin();
|
|
|
|
i != gameids.end(); i++)
|
|
|
|
dstream<<(*i)<<std::endl;
|
|
|
|
return 0;
|
|
|
|
}
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2012-05-20 16:09:46 +02:00
|
|
|
// List worlds if requested
|
2014-06-01 00:55:23 +02:00
|
|
|
if (cmd_args.exists("world") && cmd_args.get("world") == "list") {
|
|
|
|
dstream << _("Available worlds:") << std::endl;
|
2012-05-20 16:09:46 +02:00
|
|
|
std::vector<WorldSpec> worldspecs = getAvailableWorlds();
|
|
|
|
print_worldspecs(worldspecs, dstream);
|
|
|
|
return 0;
|
|
|
|
}
|
2013-05-09 15:53:29 +02:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
// Print startup message
|
2014-06-01 00:55:23 +02:00
|
|
|
infostream<<PROJECT_NAME << " "<< _("with") << " SER_FMT_VER_HIGHEST_READ="
|
|
|
|
<< (int)SER_FMT_VER_HIGHEST_READ << ", " << minetest_build_info << std::endl;
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
/*
|
|
|
|
Basic initialization
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Initialize default settings
|
2011-10-12 12:53:38 +02:00
|
|
|
set_default_settings(g_settings);
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
// Initialize sockets
|
|
|
|
sockets_init();
|
|
|
|
atexit(sockets_cleanup);
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
/*
|
|
|
|
Read config file
|
|
|
|
*/
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
// Path of configuration file in use
|
2013-08-11 04:09:45 +02:00
|
|
|
g_settings_path = "";
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
if (cmd_args.exists("config")) {
|
2011-10-12 12:53:38 +02:00
|
|
|
bool r = g_settings->readConfigFile(cmd_args.get("config").c_str());
|
2014-06-01 00:55:23 +02:00
|
|
|
if (r == false) {
|
|
|
|
errorstream << "Could not read configuration from \""
|
|
|
|
<< cmd_args.get("config") << "\"" << std::endl;
|
2011-07-23 18:17:39 +02:00
|
|
|
return 1;
|
|
|
|
}
|
2013-08-11 04:09:45 +02:00
|
|
|
g_settings_path = cmd_args.get("config");
|
2014-06-01 00:55:23 +02:00
|
|
|
} else {
|
2012-12-20 18:19:49 +01:00
|
|
|
std::vector<std::string> filenames;
|
2012-03-10 14:56:24 +01:00
|
|
|
filenames.push_back(porting::path_user +
|
2011-10-16 15:16:47 +02:00
|
|
|
DIR_DELIM + "minetest.conf");
|
2012-03-10 15:10:26 +01:00
|
|
|
// Legacy configuration file location
|
|
|
|
filenames.push_back(porting::path_user +
|
|
|
|
DIR_DELIM + ".." + DIR_DELIM + "minetest.conf");
|
2012-07-23 14:23:33 +02:00
|
|
|
#if RUN_IN_PLACE
|
2012-03-10 14:56:24 +01:00
|
|
|
// Try also from a lower level (to aid having the same configuration
|
|
|
|
// for many RUN_IN_PLACE installs)
|
|
|
|
filenames.push_back(porting::path_user +
|
2012-03-10 15:10:26 +01:00
|
|
|
DIR_DELIM + ".." + DIR_DELIM + ".." + DIR_DELIM + "minetest.conf");
|
2011-07-23 18:17:39 +02:00
|
|
|
#endif
|
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
for(u32 i = 0; i < filenames.size(); i++) {
|
2011-10-12 12:53:38 +02:00
|
|
|
bool r = g_settings->readConfigFile(filenames[i].c_str());
|
2014-06-01 00:55:23 +02:00
|
|
|
if (r) {
|
2013-08-11 04:09:45 +02:00
|
|
|
g_settings_path = filenames[i];
|
2011-07-23 18:17:39 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
// If no path found, use the first one (menu creates the file)
|
2014-06-01 00:55:23 +02:00
|
|
|
if (g_settings_path == "")
|
2013-08-11 04:09:45 +02:00
|
|
|
g_settings_path = filenames[0];
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2013-02-09 03:52:23 +01:00
|
|
|
// Initialize debug streams
|
|
|
|
#define DEBUGFILE "debug.txt"
|
|
|
|
#if RUN_IN_PLACE
|
|
|
|
std::string logfile = DEBUGFILE;
|
|
|
|
#else
|
|
|
|
std::string logfile = porting::path_user+DIR_DELIM+DEBUGFILE;
|
|
|
|
#endif
|
2014-06-01 00:55:23 +02:00
|
|
|
if (cmd_args.exists("logfile"))
|
2013-02-09 03:52:23 +01:00
|
|
|
logfile = cmd_args.get("logfile");
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2013-02-09 03:52:23 +01:00
|
|
|
log_remove_output(&main_dstream_no_stderr_log_out);
|
|
|
|
int loglevel = g_settings->getS32("debug_log_level");
|
|
|
|
|
|
|
|
if (loglevel == 0) //no logging
|
|
|
|
logfile = "";
|
|
|
|
else if (loglevel > 0 && loglevel <= LMT_NUM_VALUES)
|
2014-06-01 00:55:23 +02:00
|
|
|
log_add_output_maxlev(&main_dstream_no_stderr_log_out,
|
|
|
|
(LogMessageLevel)(loglevel - 1));
|
2013-02-09 03:52:23 +01:00
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
if (logfile != "")
|
2013-02-09 03:52:23 +01:00
|
|
|
debugstreams_init(false, logfile.c_str());
|
|
|
|
else
|
|
|
|
debugstreams_init(false, NULL);
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
infostream << "logfile = " << logfile << std::endl;
|
2011-07-23 18:17:39 +02:00
|
|
|
|
|
|
|
// Initialize random seed
|
|
|
|
srand(time(0));
|
|
|
|
mysrand(time(0));
|
|
|
|
|
2013-08-29 05:04:56 +02:00
|
|
|
// Initialize HTTP fetcher
|
|
|
|
httpfetch_init(g_settings->getS32("curl_parallel_limit"));
|
|
|
|
|
2014-04-21 14:10:59 +02:00
|
|
|
#ifndef __ANDROID__
|
2011-07-23 18:17:39 +02:00
|
|
|
/*
|
|
|
|
Run unit tests
|
|
|
|
*/
|
2014-06-01 00:55:23 +02:00
|
|
|
if ((ENABLE_TESTS && cmd_args.getFlag("disable-unittests") == false)
|
|
|
|
|| cmd_args.getFlag("enable-unittests") == true) {
|
|
|
|
run_tests();
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
2014-04-21 14:10:59 +02:00
|
|
|
#endif
|
2013-11-03 17:28:16 +01:00
|
|
|
#ifdef _MSC_VER
|
2014-06-01 00:55:23 +02:00
|
|
|
init_gettext((porting::path_share + DIR_DELIM + "locale").c_str(),
|
|
|
|
g_settings->get("language"), argc, argv);
|
2013-09-07 18:06:00 +02:00
|
|
|
#else
|
2014-06-01 00:55:23 +02:00
|
|
|
init_gettext((porting::path_share + DIR_DELIM + "locale").c_str(),
|
|
|
|
g_settings->get("language"));
|
2013-09-07 18:06:00 +02:00
|
|
|
#endif
|
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
/*
|
|
|
|
Game parameters
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Port
|
|
|
|
u16 port = 30000;
|
2014-06-01 00:55:23 +02:00
|
|
|
if (cmd_args.exists("port"))
|
2011-07-23 18:17:39 +02:00
|
|
|
port = cmd_args.getU16("port");
|
2014-06-01 00:55:23 +02:00
|
|
|
else if (g_settings->exists("port"))
|
2011-10-12 12:53:38 +02:00
|
|
|
port = g_settings->getU16("port");
|
2014-06-01 00:55:23 +02:00
|
|
|
if (port == 0)
|
2011-07-23 18:17:39 +02:00
|
|
|
port = 30000;
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2012-03-11 19:45:14 +01:00
|
|
|
// World directory
|
|
|
|
std::string commanded_world = "";
|
2014-06-01 00:55:23 +02:00
|
|
|
if (cmd_args.exists("world"))
|
2012-03-11 19:45:14 +01:00
|
|
|
commanded_world = cmd_args.get("world");
|
2014-06-01 00:55:23 +02:00
|
|
|
else if (cmd_args.exists("map-dir"))
|
2012-03-11 19:45:14 +01:00
|
|
|
commanded_world = cmd_args.get("map-dir");
|
2014-06-01 00:55:23 +02:00
|
|
|
else if (cmd_args.exists("nonopt0")) // First nameless argument
|
2012-03-13 00:32:21 +01:00
|
|
|
commanded_world = cmd_args.get("nonopt0");
|
2014-06-01 00:55:23 +02:00
|
|
|
else if (g_settings->exists("map-dir"))
|
2012-03-11 19:45:14 +01:00
|
|
|
commanded_world = g_settings->get("map-dir");
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2012-03-25 19:29:56 +02:00
|
|
|
// World name
|
|
|
|
std::string commanded_worldname = "";
|
2014-06-01 00:55:23 +02:00
|
|
|
if (cmd_args.exists("worldname"))
|
2012-03-25 19:29:56 +02:00
|
|
|
commanded_worldname = cmd_args.get("worldname");
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2012-03-13 00:32:21 +01:00
|
|
|
// Strip world.mt from commanded_world
|
|
|
|
{
|
|
|
|
std::string worldmt = "world.mt";
|
2014-06-01 00:55:23 +02:00
|
|
|
if (commanded_world.size() > worldmt.size() &&
|
|
|
|
commanded_world.substr(commanded_world.size() - worldmt.size())
|
|
|
|
== worldmt) {
|
|
|
|
dstream << _("Supplied world.mt file - stripping it off.") << std::endl;
|
2014-05-20 19:04:57 +02:00
|
|
|
commanded_world = commanded_world.substr(0,
|
2014-06-01 00:55:23 +02:00
|
|
|
commanded_world.size() - worldmt.size());
|
2012-03-13 00:32:21 +01:00
|
|
|
}
|
|
|
|
}
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2012-05-20 16:41:40 +02:00
|
|
|
// If a world name was specified, convert it to a path
|
2014-06-01 00:55:23 +02:00
|
|
|
if (commanded_worldname != "") {
|
2012-05-20 16:41:40 +02:00
|
|
|
// Get information about available worlds
|
|
|
|
std::vector<WorldSpec> worldspecs = getAvailableWorlds();
|
|
|
|
bool found = false;
|
2014-06-01 00:55:23 +02:00
|
|
|
for(u32 i = 0; i < worldspecs.size(); i++) {
|
2012-05-20 16:41:40 +02:00
|
|
|
std::string name = worldspecs[i].name;
|
2014-06-01 00:55:23 +02:00
|
|
|
if (name == commanded_worldname) {
|
|
|
|
if (commanded_world != "") {
|
|
|
|
dstream << _("--worldname takes precedence over previously "
|
|
|
|
"selected world.") << std::endl;
|
2012-05-20 16:41:40 +02:00
|
|
|
}
|
|
|
|
commanded_world = worldspecs[i].path;
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-06-01 00:55:23 +02:00
|
|
|
if (!found) {
|
|
|
|
dstream << _("World") << " '"<<commanded_worldname << _("' not "
|
|
|
|
"available. Available worlds:") << std::endl;
|
2012-05-20 16:41:40 +02:00
|
|
|
print_worldspecs(worldspecs, dstream);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-11 19:45:14 +01:00
|
|
|
// Gamespec
|
|
|
|
SubgameSpec commanded_gamespec;
|
2014-06-01 00:55:23 +02:00
|
|
|
if (cmd_args.exists("gameid")) {
|
2012-03-11 19:45:14 +01:00
|
|
|
std::string gameid = cmd_args.get("gameid");
|
|
|
|
commanded_gamespec = findSubgame(gameid);
|
2014-06-01 00:55:23 +02:00
|
|
|
if (!commanded_gamespec.isValid()) {
|
|
|
|
errorstream << "Game \"" << gameid << "\" not found" << std::endl;
|
2012-03-11 13:54:23 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-22 23:18:44 +02:00
|
|
|
|
2012-03-11 19:45:14 +01:00
|
|
|
/*
|
|
|
|
Run dedicated server if asked to or no other option
|
|
|
|
*/
|
2012-03-10 15:46:19 +01:00
|
|
|
#ifdef SERVER
|
|
|
|
bool run_dedicated_server = true;
|
|
|
|
#else
|
|
|
|
bool run_dedicated_server = cmd_args.getFlag("server");
|
|
|
|
#endif
|
2013-02-21 23:00:44 +01:00
|
|
|
g_settings->set("server_dedicated", run_dedicated_server ? "true" : "false");
|
2014-06-01 00:55:23 +02:00
|
|
|
if (run_dedicated_server)
|
2011-07-23 18:17:39 +02:00
|
|
|
{
|
|
|
|
DSTACK("Dedicated server branch");
|
2012-03-10 15:46:19 +01:00
|
|
|
// Create time getter if built with Irrlicht
|
|
|
|
#ifndef SERVER
|
2011-07-23 18:17:39 +02:00
|
|
|
g_timegetter = new SimpleTimeGetter();
|
2012-03-10 15:46:19 +01:00
|
|
|
#endif
|
2012-03-11 19:45:14 +01:00
|
|
|
|
|
|
|
// World directory
|
|
|
|
std::string world_path;
|
2014-06-01 00:55:23 +02:00
|
|
|
verbosestream << _("Determining world path") << std::endl;
|
2012-03-11 19:45:14 +01:00
|
|
|
bool is_legacy_world = false;
|
2012-03-25 19:29:56 +02:00
|
|
|
// If a world was commanded, use it
|
2014-06-01 00:55:23 +02:00
|
|
|
if (commanded_world != "") {
|
2012-03-11 19:45:14 +01:00
|
|
|
world_path = commanded_world;
|
2014-06-01 00:55:23 +02:00
|
|
|
infostream << "Using commanded world path [" << world_path << "]"
|
|
|
|
<< std::endl;
|
|
|
|
} else { // No world was specified; try to select it automatically
|
2012-03-25 19:29:56 +02:00
|
|
|
// Get information about available worlds
|
|
|
|
std::vector<WorldSpec> worldspecs = getAvailableWorlds();
|
|
|
|
// If a world name was specified, select it
|
2014-06-01 00:55:23 +02:00
|
|
|
if (commanded_worldname != "") {
|
2012-03-25 19:29:56 +02:00
|
|
|
world_path = "";
|
2014-06-01 00:55:23 +02:00
|
|
|
for(u32 i = 0; i < worldspecs.size(); i++) {
|
2012-03-25 19:29:56 +02:00
|
|
|
std::string name = worldspecs[i].name;
|
2014-06-01 00:55:23 +02:00
|
|
|
if (name == commanded_worldname) {
|
2012-03-25 19:29:56 +02:00
|
|
|
world_path = worldspecs[i].path;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-06-01 00:55:23 +02:00
|
|
|
if (world_path == "") {
|
|
|
|
dstream << _("World") << " '" << commanded_worldname << "' " << _("not "
|
|
|
|
"available. Available worlds:") << std::endl;
|
2012-03-25 19:29:56 +02:00
|
|
|
print_worldspecs(worldspecs, dstream);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// If there is only a single world, use it
|
2014-06-01 00:55:23 +02:00
|
|
|
if (worldspecs.size() == 1) {
|
2012-03-25 19:29:56 +02:00
|
|
|
world_path = worldspecs[0].path;
|
2014-06-01 00:55:23 +02:00
|
|
|
dstream <<_("Automatically selecting world at") << " ["
|
|
|
|
<< world_path << "]" << std::endl;
|
2012-03-25 19:29:56 +02:00
|
|
|
// If there are multiple worlds, list them
|
2014-06-01 00:55:23 +02:00
|
|
|
} else if (worldspecs.size() > 1) {
|
|
|
|
dstream << _("Multiple worlds are available.") << std::endl;
|
|
|
|
dstream << _("Please select one using --worldname <name>"
|
|
|
|
" or --world <path>") << std::endl;
|
2012-03-25 19:29:56 +02:00
|
|
|
print_worldspecs(worldspecs, dstream);
|
|
|
|
return 1;
|
|
|
|
// If there are no worlds, automatically create a new one
|
|
|
|
} else {
|
|
|
|
// This is the ultimate default world path
|
|
|
|
world_path = porting::path_user + DIR_DELIM + "worlds" +
|
|
|
|
DIR_DELIM + "world";
|
2014-06-01 00:55:23 +02:00
|
|
|
infostream << "Creating default world at ["
|
|
|
|
<< world_path << "]" << std::endl;
|
2012-03-11 19:45:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
if (world_path == "") {
|
|
|
|
errorstream << "No world path specified or found." << std::endl;
|
2012-03-15 17:15:12 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2014-06-01 00:55:23 +02:00
|
|
|
verbosestream << _("Using world path") << " [" << world_path << "]" << std::endl;
|
2012-03-15 17:15:12 +01:00
|
|
|
|
2012-04-08 22:15:50 +02:00
|
|
|
// We need a gamespec.
|
|
|
|
SubgameSpec gamespec;
|
2014-06-01 00:55:23 +02:00
|
|
|
verbosestream << _("Determining gameid/gamespec") << std::endl;
|
2012-03-25 19:29:56 +02:00
|
|
|
// If world doesn't exist
|
2014-06-01 00:55:23 +02:00
|
|
|
if (!getWorldExists(world_path)) {
|
2012-03-25 19:29:56 +02:00
|
|
|
// Try to take gamespec from command line
|
2014-06-01 00:55:23 +02:00
|
|
|
if (commanded_gamespec.isValid()) {
|
2012-04-08 22:15:50 +02:00
|
|
|
gamespec = commanded_gamespec;
|
2014-06-01 00:55:23 +02:00
|
|
|
infostream << "Using commanded gameid [" << gamespec.id << "]" << std::endl;
|
|
|
|
} else { // Otherwise we will be using "minetest"
|
2012-04-08 22:15:50 +02:00
|
|
|
gamespec = findSubgame(g_settings->get("default_game"));
|
2014-06-01 00:55:23 +02:00
|
|
|
infostream << "Using default gameid [" << gamespec.id << "]" << std::endl;
|
2012-03-25 19:29:56 +02:00
|
|
|
}
|
2014-06-01 00:55:23 +02:00
|
|
|
} else { // World exists
|
2012-03-25 19:29:56 +02:00
|
|
|
std::string world_gameid = getWorldGameId(world_path, is_legacy_world);
|
2012-04-08 22:15:50 +02:00
|
|
|
// If commanded to use a gameid, do so
|
2014-06-01 00:55:23 +02:00
|
|
|
if (commanded_gamespec.isValid()) {
|
2012-04-08 22:15:50 +02:00
|
|
|
gamespec = commanded_gamespec;
|
2014-06-01 00:55:23 +02:00
|
|
|
if (commanded_gamespec.id != world_gameid) {
|
|
|
|
errorstream << "WARNING: Using commanded gameid ["
|
|
|
|
<< gamespec.id << "]" << " instead of world gameid ["
|
|
|
|
<< world_gameid << "]" << std::endl;
|
2012-04-08 22:15:50 +02:00
|
|
|
}
|
2014-06-01 00:55:23 +02:00
|
|
|
} else {
|
2012-04-08 22:15:50 +02:00
|
|
|
// If world contains an embedded game, use it;
|
|
|
|
// Otherwise find world from local system.
|
|
|
|
gamespec = findWorldSubgame(world_path);
|
2014-06-01 00:55:23 +02:00
|
|
|
infostream << "Using world gameid [" << gamespec.id << "]" << std::endl;
|
2012-03-25 19:29:56 +02:00
|
|
|
}
|
|
|
|
}
|
2014-06-01 00:55:23 +02:00
|
|
|
if (!gamespec.isValid()) {
|
|
|
|
errorstream << "Subgame [" << gamespec.id << "] could not be found."
|
|
|
|
<< std::endl;
|
2012-03-11 19:45:14 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2014-06-01 00:55:23 +02:00
|
|
|
verbosestream << _("Using gameid") << " [" << gamespec.id<<"]" << std::endl;
|
2012-03-11 19:45:14 +01:00
|
|
|
|
2014-03-07 01:00:03 +01:00
|
|
|
// Bind address
|
|
|
|
std::string bind_str = g_settings->get("bind_address");
|
2014-06-01 00:55:23 +02:00
|
|
|
Address bind_addr(0, 0, 0, 0, port);
|
2014-03-07 01:00:03 +01:00
|
|
|
|
|
|
|
if (g_settings->getBool("ipv6_server")) {
|
|
|
|
bind_addr.setAddress((IPv6AddressBytes*) NULL);
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
bind_addr.Resolve(bind_str.c_str());
|
|
|
|
} catch (ResolveError &e) {
|
|
|
|
infostream << "Resolving bind address \"" << bind_str
|
|
|
|
<< "\" failed: " << e.what()
|
|
|
|
<< " -- Listening on all addresses." << std::endl;
|
|
|
|
}
|
2014-06-01 00:55:23 +02:00
|
|
|
if (bind_addr.isIPv6() && !g_settings->getBool("enable_ipv6")) {
|
2014-03-07 01:00:03 +01:00
|
|
|
errorstream << "Unable to listen on "
|
|
|
|
<< bind_addr.serializeString()
|
|
|
|
<< L" because IPv6 is disabled" << std::endl;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
// Create server
|
2014-03-07 01:00:03 +01:00
|
|
|
Server server(world_path, gamespec, false, bind_addr.isIPv6());
|
2012-10-22 23:18:44 +02:00
|
|
|
|
|
|
|
// Database migration
|
|
|
|
if (cmd_args.exists("migrate")) {
|
|
|
|
std::string migrate_to = cmd_args.get("migrate");
|
|
|
|
Settings world_mt;
|
2014-05-20 19:04:57 +02:00
|
|
|
bool success = world_mt.readConfigFile((world_path + DIR_DELIM
|
2014-06-01 00:55:23 +02:00
|
|
|
+ "world.mt").c_str());
|
2012-10-22 23:18:44 +02:00
|
|
|
if (!success) {
|
|
|
|
errorstream << "Cannot read world.mt" << std::endl;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (!world_mt.exists("backend")) {
|
|
|
|
errorstream << "Please specify your current backend in world.mt file:"
|
2014-04-08 21:39:21 +02:00
|
|
|
<< std::endl << " backend = {sqlite3|leveldb|redis|dummy}" << std::endl;
|
2012-10-22 23:18:44 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
std::string backend = world_mt.get("backend");
|
|
|
|
Database *new_db;
|
|
|
|
if (backend == migrate_to) {
|
2014-06-01 00:55:23 +02:00
|
|
|
errorstream << "Cannot migrate: new backend is same"
|
|
|
|
<<" as the old one" << std::endl;
|
2012-10-22 23:18:44 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (migrate_to == "sqlite3")
|
|
|
|
new_db = new Database_SQLite3(&(ServerMap&)server.getMap(), world_path);
|
2013-09-10 18:29:51 +02:00
|
|
|
#if USE_LEVELDB
|
2012-10-22 23:18:44 +02:00
|
|
|
else if (migrate_to == "leveldb")
|
|
|
|
new_db = new Database_LevelDB(&(ServerMap&)server.getMap(), world_path);
|
2013-09-10 18:29:51 +02:00
|
|
|
#endif
|
2014-04-08 21:39:21 +02:00
|
|
|
#if USE_REDIS
|
|
|
|
else if (migrate_to == "redis")
|
|
|
|
new_db = new Database_Redis(&(ServerMap&)server.getMap(), world_path);
|
|
|
|
#endif
|
2012-10-22 23:18:44 +02:00
|
|
|
else {
|
2014-05-20 19:04:57 +02:00
|
|
|
errorstream << "Migration to " << migrate_to
|
2014-06-01 00:55:23 +02:00
|
|
|
<< " is not supported" << std::endl;
|
2012-10-22 23:18:44 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-09-06 18:22:12 +02:00
|
|
|
std::list<v3s16> blocks;
|
2012-10-22 23:18:44 +02:00
|
|
|
ServerMap &old_map = ((ServerMap&)server.getMap());
|
|
|
|
old_map.listAllLoadableBlocks(blocks);
|
|
|
|
int count = 0;
|
|
|
|
new_db->beginSave();
|
2014-06-01 00:55:23 +02:00
|
|
|
for (std::list<v3s16>::iterator i = blocks.begin(); i != blocks.end(); i++) {
|
2012-10-22 23:18:44 +02:00
|
|
|
MapBlock *block = old_map.loadBlock(*i);
|
2014-07-08 20:04:37 +02:00
|
|
|
if (!block) {
|
|
|
|
errorstream << "Failed to load block " << PP(*i) << ", skipping it.";
|
|
|
|
} else {
|
|
|
|
old_map.saveBlock(block, new_db);
|
|
|
|
MapSector *sector = old_map.getSectorNoGenerate(v2s16(i->X, i->Z));
|
|
|
|
sector->deleteBlock(block);
|
|
|
|
}
|
2012-10-22 23:18:44 +02:00
|
|
|
++count;
|
|
|
|
if (count % 500 == 0)
|
|
|
|
actionstream << "Migrated " << count << " blocks "
|
2013-11-23 16:09:38 +01:00
|
|
|
<< (100.0 * count / blocks.size()) << "% completed" << std::endl;
|
2012-10-22 23:18:44 +02:00
|
|
|
}
|
|
|
|
new_db->endSave();
|
2014-02-05 18:52:59 +01:00
|
|
|
delete new_db;
|
2012-10-22 23:18:44 +02:00
|
|
|
|
|
|
|
actionstream << "Successfully migrated " << count << " blocks" << std::endl;
|
2013-09-09 20:07:25 +02:00
|
|
|
world_mt.set("backend", migrate_to);
|
2014-06-01 00:55:23 +02:00
|
|
|
if (!world_mt.updateConfigFile((world_path + DIR_DELIM + "world.mt").c_str()))
|
|
|
|
errorstream << "Failed to update world.mt!" << std::endl;
|
2013-09-09 20:07:25 +02:00
|
|
|
else
|
2014-06-01 00:55:23 +02:00
|
|
|
actionstream << "world.mt updated" << std::endl;
|
2012-10-22 23:18:44 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-02-05 21:24:46 +01:00
|
|
|
server.start(bind_addr);
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
// Run server
|
|
|
|
dedicated_server_loop(server, kill);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-03-10 15:46:19 +01:00
|
|
|
#ifndef SERVER // Exclude from dedicated server build
|
2011-07-23 18:17:39 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
More parameters
|
|
|
|
*/
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2012-03-11 11:06:59 +01:00
|
|
|
std::string address = g_settings->get("address");
|
2014-06-01 00:55:23 +02:00
|
|
|
if (commanded_world != "")
|
2012-03-13 00:32:21 +01:00
|
|
|
address = "";
|
2014-06-01 00:55:23 +02:00
|
|
|
else if (cmd_args.exists("address"))
|
2011-07-23 18:17:39 +02:00
|
|
|
address = cmd_args.get("address");
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-10-12 12:53:38 +02:00
|
|
|
std::string playername = g_settings->get("name");
|
2014-06-01 00:55:23 +02:00
|
|
|
if (cmd_args.exists("name"))
|
2012-03-11 11:06:59 +01:00
|
|
|
playername = cmd_args.get("name");
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2012-03-11 11:06:59 +01:00
|
|
|
bool skip_main_menu = cmd_args.getFlag("go");
|
2011-07-23 18:17:39 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Device initialization
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Resolution selection
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2012-04-03 13:59:02 +02:00
|
|
|
bool fullscreen = g_settings->getBool("fullscreen");
|
2011-10-12 12:53:38 +02:00
|
|
|
u16 screenW = g_settings->getU16("screenW");
|
|
|
|
u16 screenH = g_settings->getU16("screenH");
|
2011-07-23 18:17:39 +02:00
|
|
|
|
2012-04-03 13:59:02 +02:00
|
|
|
// bpp, fsaa, vsync
|
|
|
|
|
|
|
|
bool vsync = g_settings->getBool("vsync");
|
|
|
|
u16 bits = g_settings->getU16("fullscreen_bpp");
|
|
|
|
u16 fsaa = g_settings->getU16("fsaa");
|
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
// Determine driver
|
2014-07-16 14:04:50 +02:00
|
|
|
video::E_DRIVER_TYPE driverType = video::EDT_OPENGL;
|
|
|
|
static const char* driverids[] = {
|
|
|
|
"null",
|
|
|
|
"software",
|
|
|
|
"burningsvideo",
|
|
|
|
"direct3d8",
|
|
|
|
"direct3d9",
|
|
|
|
"opengl"
|
2013-03-02 17:44:08 +01:00
|
|
|
#ifdef _IRR_COMPILE_WITH_OGLES1_
|
2014-07-16 14:04:50 +02:00
|
|
|
,"ogles1"
|
2013-03-02 17:44:08 +01:00
|
|
|
#endif
|
|
|
|
#ifdef _IRR_COMPILE_WITH_OGLES2_
|
2014-07-16 14:04:50 +02:00
|
|
|
,"ogles2"
|
2013-03-02 17:44:08 +01:00
|
|
|
#endif
|
2014-07-16 14:04:50 +02:00
|
|
|
,"invalid"
|
|
|
|
};
|
|
|
|
|
|
|
|
std::string driverstring = g_settings->get("video_driver");
|
|
|
|
for (unsigned int i = 0;
|
|
|
|
i < (sizeof(driverids)/sizeof(driverids[0]));
|
|
|
|
i++)
|
|
|
|
{
|
|
|
|
if (strcasecmp(driverstring.c_str(), driverids[i]) == 0) {
|
|
|
|
driverType = (video::E_DRIVER_TYPE) i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcasecmp("invalid", driverids[i]) == 0) {
|
|
|
|
errorstream << "WARNING: Invalid video_driver specified; defaulting "
|
|
|
|
<< "to opengl" << std::endl;
|
|
|
|
break;
|
|
|
|
}
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2013-05-09 15:53:29 +02:00
|
|
|
List video modes if requested
|
2011-07-23 18:17:39 +02:00
|
|
|
*/
|
2014-04-21 14:10:59 +02:00
|
|
|
MyEventReceiver* receiver = new MyEventReceiver();
|
2011-07-23 18:17:39 +02:00
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
if (cmd_args.getFlag("videomodes")) {
|
2013-05-09 15:53:29 +02:00
|
|
|
IrrlichtDevice *nulldevice;
|
|
|
|
|
|
|
|
SIrrlichtCreationParameters params = SIrrlichtCreationParameters();
|
|
|
|
params.DriverType = video::EDT_NULL;
|
|
|
|
params.WindowSize = core::dimension2d<u32>(640, 480);
|
|
|
|
params.Bits = 24;
|
|
|
|
params.AntiAlias = fsaa;
|
|
|
|
params.Fullscreen = false;
|
|
|
|
params.Stencilbuffer = false;
|
|
|
|
params.Vsync = vsync;
|
2014-04-21 14:10:59 +02:00
|
|
|
params.EventReceiver = receiver;
|
2013-08-25 16:25:01 +02:00
|
|
|
params.HighPrecisionFPU = g_settings->getBool("high_precision_fpu");
|
2013-05-09 15:53:29 +02:00
|
|
|
|
|
|
|
nulldevice = createDeviceEx(params);
|
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
if (nulldevice == 0)
|
2013-05-09 15:53:29 +02:00
|
|
|
return 1;
|
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
dstream << _("Available video modes (WxHxD):") << std::endl;
|
2013-05-09 15:53:29 +02:00
|
|
|
|
|
|
|
video::IVideoModeList *videomode_list =
|
|
|
|
nulldevice->getVideoModeList();
|
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
if (videomode_list == 0) {
|
2013-05-09 15:53:29 +02:00
|
|
|
nulldevice->drop();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
s32 videomode_count = videomode_list->getVideoModeCount();
|
|
|
|
core::dimension2d<u32> videomode_res;
|
|
|
|
s32 videomode_depth;
|
2014-06-01 00:55:23 +02:00
|
|
|
for (s32 i = 0; i < videomode_count; ++i) {
|
2013-05-09 15:53:29 +02:00
|
|
|
videomode_res = videomode_list->getVideoModeResolution(i);
|
|
|
|
videomode_depth = videomode_list->getVideoModeDepth(i);
|
2014-06-01 00:55:23 +02:00
|
|
|
dstream<<videomode_res.Width << "x" << videomode_res.Height
|
|
|
|
<< "x" << videomode_depth << std::endl;
|
2013-05-09 15:53:29 +02:00
|
|
|
}
|
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
dstream << _("Active video mode (WxHxD):") << std::endl;
|
2013-05-09 15:53:29 +02:00
|
|
|
videomode_res = videomode_list->getDesktopResolution();
|
|
|
|
videomode_depth = videomode_list->getDesktopDepth();
|
2014-06-01 00:55:23 +02:00
|
|
|
dstream << videomode_res.Width << "x" << videomode_res.Height
|
|
|
|
<< "x" << videomode_depth << std::endl;
|
2013-05-09 15:53:29 +02:00
|
|
|
|
|
|
|
nulldevice->drop();
|
|
|
|
|
2014-04-21 14:10:59 +02:00
|
|
|
delete receiver;
|
2013-05-09 15:53:29 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Create device and exit if creation failed
|
|
|
|
*/
|
2012-04-03 13:59:02 +02:00
|
|
|
SIrrlichtCreationParameters params = SIrrlichtCreationParameters();
|
|
|
|
params.DriverType = driverType;
|
|
|
|
params.WindowSize = core::dimension2d<u32>(screenW, screenH);
|
|
|
|
params.Bits = bits;
|
|
|
|
params.AntiAlias = fsaa;
|
|
|
|
params.Fullscreen = fullscreen;
|
|
|
|
params.Stencilbuffer = false;
|
|
|
|
params.Vsync = vsync;
|
2014-04-21 14:10:59 +02:00
|
|
|
params.EventReceiver = receiver;
|
2013-08-25 16:25:01 +02:00
|
|
|
params.HighPrecisionFPU = g_settings->getBool("high_precision_fpu");
|
2014-04-21 14:10:59 +02:00
|
|
|
#ifdef __ANDROID__
|
|
|
|
params.PrivateData = porting::app_global;
|
|
|
|
params.OGLES2ShaderPath = std::string(porting::path_user + DIR_DELIM +
|
|
|
|
"media" + DIR_DELIM + "Shaders" + DIR_DELIM).c_str();
|
|
|
|
#endif
|
2012-04-03 13:59:02 +02:00
|
|
|
|
2014-04-21 14:10:59 +02:00
|
|
|
IrrlichtDevice * device = createDeviceEx(params);
|
2011-07-23 18:17:39 +02:00
|
|
|
|
2014-04-05 14:12:36 +02:00
|
|
|
if (device == 0) {
|
2014-04-21 14:10:59 +02:00
|
|
|
delete receiver;
|
2011-07-23 18:17:39 +02:00
|
|
|
return 1; // could not create selected driver.
|
2014-04-05 14:12:36 +02:00
|
|
|
}
|
2014-05-08 00:58:00 +02:00
|
|
|
|
|
|
|
// Map our log level to irrlicht engine one.
|
|
|
|
static const irr::ELOG_LEVEL irr_log_level[5] = {
|
|
|
|
ELL_NONE,
|
|
|
|
ELL_ERROR,
|
|
|
|
ELL_WARNING,
|
|
|
|
ELL_INFORMATION,
|
2014-05-20 19:04:57 +02:00
|
|
|
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
|
2014-05-08 00:58:00 +02:00
|
|
|
ELL_INFORMATION
|
|
|
|
#else
|
|
|
|
ELL_DEBUG
|
|
|
|
#endif
|
|
|
|
};
|
2014-05-20 19:04:57 +02:00
|
|
|
|
2014-05-08 00:58:00 +02:00
|
|
|
ILogger* irr_logger = device->getLogger();
|
|
|
|
irr_logger->setLogLevel(irr_log_level[loglevel]);
|
2014-05-20 19:04:57 +02:00
|
|
|
|
2014-04-05 14:12:36 +02:00
|
|
|
porting::initIrrlicht(device);
|
2014-06-14 11:22:09 +02:00
|
|
|
late_init_default_settings(g_settings);
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-11-03 19:17:18 +01:00
|
|
|
/*
|
|
|
|
Continue initialization
|
|
|
|
*/
|
|
|
|
|
|
|
|
video::IVideoDriver* driver = device->getVideoDriver();
|
|
|
|
|
|
|
|
/*
|
|
|
|
This changes the minimum allowed number of vertices in a VBO.
|
|
|
|
Default is 500.
|
|
|
|
*/
|
|
|
|
//driver->setMinHardwareBufferVertexCount(50);
|
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
// Create time getter
|
|
|
|
g_timegetter = new IrrlichtTimeGetter(device);
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
// Create game callback for menus
|
|
|
|
g_gamecallback = new MainGameCallback(device);
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
/*
|
|
|
|
Speed tests (done after irrlicht is loaded to get timer)
|
|
|
|
*/
|
2014-06-01 00:55:23 +02:00
|
|
|
if (cmd_args.getFlag("speedtests"))
|
2011-07-23 18:17:39 +02:00
|
|
|
{
|
2014-06-01 00:55:23 +02:00
|
|
|
dstream << "Running speed tests" << std::endl;
|
2011-07-23 18:17:39 +02:00
|
|
|
SpeedTests();
|
2013-05-09 15:48:35 +02:00
|
|
|
device->drop();
|
2011-07-23 18:17:39 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
device->setResizable(true);
|
|
|
|
|
2011-10-12 12:53:38 +02:00
|
|
|
bool random_input = g_settings->getBool("random_input")
|
2011-07-23 18:17:39 +02:00
|
|
|
|| cmd_args.getFlag("random-input");
|
|
|
|
InputHandler *input = NULL;
|
2014-04-21 14:10:59 +02:00
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
if (random_input) {
|
2011-07-23 18:17:39 +02:00
|
|
|
input = new RandomInputHandler();
|
2014-04-06 15:12:04 +02:00
|
|
|
} else {
|
2014-04-21 14:10:59 +02:00
|
|
|
input = new RealInputHandler(device,receiver);
|
2014-04-06 15:12:04 +02:00
|
|
|
}
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
scene::ISceneManager* smgr = device->getSceneManager();
|
|
|
|
|
|
|
|
guienv = device->getGUIEnvironment();
|
|
|
|
gui::IGUISkin* skin = guienv->getSkin();
|
2013-02-03 13:19:09 +01:00
|
|
|
std::string font_path = g_settings->get("font_path");
|
2013-08-04 20:18:56 +02:00
|
|
|
gui::IGUIFont *font;
|
|
|
|
#if USE_FREETYPE
|
2013-09-17 05:52:42 +02:00
|
|
|
bool use_freetype = g_settings->getBool("freetype");
|
2013-08-04 20:18:56 +02:00
|
|
|
if (use_freetype) {
|
2013-09-07 18:06:00 +02:00
|
|
|
std::string fallback;
|
|
|
|
if (is_yes(gettext("needs_fallback_font")))
|
|
|
|
fallback = "fallback_";
|
|
|
|
u16 font_size = g_settings->getU16(fallback + "font_size");
|
|
|
|
font_path = g_settings->get(fallback + "font_path");
|
2013-12-12 18:47:54 +01:00
|
|
|
u32 font_shadow = g_settings->getU16(fallback + "font_shadow");
|
2013-12-12 21:02:09 +01:00
|
|
|
u32 font_shadow_alpha = g_settings->getU16(fallback + "font_shadow_alpha");
|
2014-06-01 00:55:23 +02:00
|
|
|
font = gui::CGUITTFont::createTTFont(guienv, font_path.c_str(), font_size,
|
|
|
|
true, true, font_shadow, font_shadow_alpha);
|
2013-08-04 20:18:56 +02:00
|
|
|
} else {
|
|
|
|
font = guienv->getFont(font_path.c_str());
|
|
|
|
}
|
2013-02-03 13:19:09 +01:00
|
|
|
#else
|
2013-08-04 20:18:56 +02:00
|
|
|
font = guienv->getFont(font_path.c_str());
|
2013-02-03 13:19:09 +01:00
|
|
|
#endif
|
2014-06-01 00:55:23 +02:00
|
|
|
if (font)
|
2011-07-23 18:17:39 +02:00
|
|
|
skin->setFont(font);
|
|
|
|
else
|
2014-06-01 00:55:23 +02:00
|
|
|
errorstream << "WARNING: Font file was not found."
|
|
|
|
<< " Using default font." << std::endl;
|
2011-07-23 18:17:39 +02:00
|
|
|
// If font was not found, this will get us one
|
|
|
|
font = skin->getFont();
|
|
|
|
assert(font);
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
u32 text_height = font->getDimension(L"Hello, world!").Height;
|
2014-06-01 00:55:23 +02:00
|
|
|
infostream << "text_height=" << text_height << std::endl;
|
2011-07-23 18:17:39 +02:00
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255, 255, 255, 255));
|
|
|
|
skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255, 0, 0, 0));
|
|
|
|
skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255, 0, 0, 0));
|
|
|
|
skin->setColor(gui::EGDC_HIGH_LIGHT, video::SColor(255, 70, 100, 50));
|
|
|
|
skin->setColor(gui::EGDC_HIGH_LIGHT_TEXT, video::SColor(255, 255, 255, 255));
|
2012-12-06 18:35:40 +01:00
|
|
|
|
|
|
|
#if (IRRLICHT_VERSION_MAJOR >= 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR >= 2
|
|
|
|
// Irrlicht 1.8 input colours
|
2014-06-01 00:55:23 +02:00
|
|
|
skin->setColor(gui::EGDC_EDITABLE, video::SColor(255, 128, 128, 128));
|
|
|
|
skin->setColor(gui::EGDC_FOCUSED_EDITABLE, video::SColor(255, 96, 134, 49));
|
2012-12-06 18:35:40 +01:00
|
|
|
#endif
|
|
|
|
|
2013-05-09 18:23:48 +02:00
|
|
|
|
|
|
|
// Create the menu clouds
|
|
|
|
if (!g_menucloudsmgr)
|
|
|
|
g_menucloudsmgr = smgr->createNewSceneManager();
|
|
|
|
if (!g_menuclouds)
|
|
|
|
g_menuclouds = new Clouds(g_menucloudsmgr->getRootSceneNode(),
|
|
|
|
g_menucloudsmgr, -1, rand(), 100);
|
2014-06-01 00:55:23 +02:00
|
|
|
g_menuclouds->update(v2f(0, 0), video::SColor(255, 200, 200, 255));
|
2013-05-09 18:23:48 +02:00
|
|
|
scene::ICameraSceneNode* camera;
|
|
|
|
camera = g_menucloudsmgr->addCameraSceneNode(0,
|
2014-06-01 00:55:23 +02:00
|
|
|
v3f(0, 0, 0), v3f(0, 60, 100));
|
2013-05-09 18:23:48 +02:00
|
|
|
camera->setFarValue(10000);
|
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
/*
|
|
|
|
GUI stuff
|
|
|
|
*/
|
|
|
|
|
2011-12-03 09:01:14 +01:00
|
|
|
ChatBackend chat_backend;
|
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
/*
|
|
|
|
If an error occurs, this is set to something and the
|
|
|
|
menu-game loop is restarted. It is then displayed before
|
|
|
|
the menu.
|
|
|
|
*/
|
|
|
|
std::wstring error_message = L"";
|
|
|
|
|
|
|
|
// The password entered during the menu screen,
|
|
|
|
std::string password;
|
|
|
|
|
2012-03-11 20:41:32 +01:00
|
|
|
bool first_loop = true;
|
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
/*
|
|
|
|
Menu-game loop
|
|
|
|
*/
|
2014-04-21 14:10:59 +02:00
|
|
|
while (device->run() && (kill == false) &&
|
|
|
|
(g_gamecallback->shutdown_requested == false))
|
2011-07-23 18:17:39 +02:00
|
|
|
{
|
2012-03-11 13:54:23 +01:00
|
|
|
// Set the window caption
|
2013-04-07 19:15:17 +02:00
|
|
|
wchar_t* text = wgettext("Main Menu");
|
2014-06-01 00:55:23 +02:00
|
|
|
device->setWindowCaption((std::wstring(L"Minetest [") + text + L"]").c_str());
|
2013-04-07 19:15:17 +02:00
|
|
|
delete[] text;
|
2011-07-23 18:17:39 +02:00
|
|
|
|
|
|
|
// This is used for catching disconnects
|
|
|
|
try
|
|
|
|
{
|
|
|
|
|
|
|
|
/*
|
|
|
|
Clear everything from the GUIEnvironment
|
|
|
|
*/
|
|
|
|
guienv->clear();
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
/*
|
|
|
|
We need some kind of a root node to be able to add
|
|
|
|
custom gui elements directly on the screen.
|
|
|
|
Otherwise they won't be automatically drawn.
|
|
|
|
*/
|
|
|
|
guiroot = guienv->addStaticText(L"",
|
2014-06-01 00:55:23 +02:00
|
|
|
core::rect<s32>(0, 0, 10000, 10000));
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2012-03-11 19:45:14 +01:00
|
|
|
SubgameSpec gamespec;
|
|
|
|
WorldSpec worldspec;
|
2012-03-15 14:20:20 +01:00
|
|
|
bool simple_singleplayer_mode = false;
|
|
|
|
|
|
|
|
// These are set up based on the menu and other things
|
|
|
|
std::string current_playername = "inv£lid";
|
|
|
|
std::string current_password = "";
|
|
|
|
std::string current_address = "does-not-exist";
|
|
|
|
int current_port = 0;
|
2012-03-11 19:45:14 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
/*
|
|
|
|
Out-of-game menu loop.
|
|
|
|
|
|
|
|
Loop quits when menu returns proper parameters.
|
|
|
|
*/
|
2014-06-01 00:55:23 +02:00
|
|
|
while (kill == false) {
|
2012-03-11 20:41:32 +01:00
|
|
|
// If skip_main_menu, only go through here once
|
2014-06-01 00:55:23 +02:00
|
|
|
if (skip_main_menu && !first_loop) {
|
2012-03-11 20:41:32 +01:00
|
|
|
kill = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
first_loop = false;
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
// Cursor can be non-visible when coming from the game
|
2014-04-21 14:10:59 +02:00
|
|
|
#ifndef ANDROID
|
2011-07-23 18:17:39 +02:00
|
|
|
device->getCursorControl()->setVisible(true);
|
2014-04-21 14:10:59 +02:00
|
|
|
#endif
|
2011-07-23 18:17:39 +02:00
|
|
|
// Some stuff are left to scene manager when coming from the game
|
|
|
|
// (map at least?)
|
|
|
|
smgr->clear();
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
// Initialize menu data
|
|
|
|
MainMenuData menudata;
|
2013-06-23 18:30:21 +02:00
|
|
|
menudata.address = address;
|
|
|
|
menudata.name = playername;
|
|
|
|
menudata.port = itos(port);
|
|
|
|
menudata.errormessage = wide_to_narrow(error_message);
|
|
|
|
error_message = L"";
|
2014-06-01 00:55:23 +02:00
|
|
|
if (cmd_args.exists("password"))
|
2013-06-23 18:30:21 +02:00
|
|
|
menudata.password = cmd_args.get("password");
|
|
|
|
|
|
|
|
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, g_settings->getBool("mip_map"));
|
|
|
|
|
2013-02-23 22:48:02 +01:00
|
|
|
menudata.enable_public = g_settings->getBool("server_announce");
|
2013-06-23 18:30:21 +02:00
|
|
|
|
2012-03-12 23:48:02 +01:00
|
|
|
std::vector<WorldSpec> worldspecs = getAvailableWorlds();
|
2013-06-23 18:30:21 +02:00
|
|
|
|
2012-03-11 19:45:14 +01:00
|
|
|
// If a world was commanded, append and select it
|
2014-05-20 19:04:57 +02:00
|
|
|
if(commanded_world != "") {
|
|
|
|
worldspec.gameid = getWorldGameId(commanded_world, true);
|
|
|
|
worldspec.name = _("[--world parameter]");
|
|
|
|
if(worldspec.gameid == "") {
|
|
|
|
worldspec.gameid = g_settings->get("default_game");
|
|
|
|
worldspec.name += " [new]";
|
2012-03-13 00:45:38 +01:00
|
|
|
}
|
2014-05-20 19:04:57 +02:00
|
|
|
worldspec.path = commanded_world;
|
2013-02-15 20:13:53 +01:00
|
|
|
}
|
2013-05-04 09:03:56 +02:00
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
if (skip_main_menu == false) {
|
2012-03-26 01:19:41 +02:00
|
|
|
video::IVideoDriver* driver = device->getVideoDriver();
|
2013-06-23 18:30:21 +02:00
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
infostream << "Waiting for other menus" << std::endl;
|
|
|
|
while (device->run() && kill == false) {
|
|
|
|
if (noMenuActive())
|
2012-03-26 01:19:41 +02:00
|
|
|
break;
|
|
|
|
driver->beginScene(true, true,
|
2014-06-01 00:55:23 +02:00
|
|
|
video::SColor(255, 128, 128, 128));
|
2012-03-26 01:19:41 +02:00
|
|
|
guienv->drawAll();
|
|
|
|
driver->endScene();
|
|
|
|
// On some computers framerate doesn't seem to be
|
|
|
|
// automatically limited
|
|
|
|
sleep_ms(25);
|
|
|
|
}
|
2014-06-01 00:55:23 +02:00
|
|
|
infostream << "Waited for other menus" << std::endl;
|
2012-03-26 01:19:41 +02:00
|
|
|
|
2014-04-21 14:10:59 +02:00
|
|
|
/* show main menu */
|
|
|
|
GUIEngine mymenu(device, guiroot, &g_menumgr,smgr,&menudata,kill);
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2013-06-23 18:30:21 +02:00
|
|
|
//once finished you'll never end up here
|
|
|
|
smgr->clear();
|
|
|
|
}
|
2013-01-31 18:03:14 +01:00
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
if (menudata.errormessage != "") {
|
2013-08-11 04:09:45 +02:00
|
|
|
error_message = narrow_to_wide(menudata.errormessage);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-06-23 18:30:21 +02:00
|
|
|
//update worldspecs (necessary as new world may have been created)
|
|
|
|
worldspecs = getAvailableWorlds();
|
2011-07-23 18:17:39 +02:00
|
|
|
|
2013-06-23 18:30:21 +02:00
|
|
|
if (menudata.name == "")
|
|
|
|
menudata.name = std::string("Guest") + itos(myrand_range(1000,9999));
|
|
|
|
else
|
|
|
|
playername = menudata.name;
|
2012-03-11 19:45:14 +01:00
|
|
|
|
2013-06-23 18:30:21 +02:00
|
|
|
password = translatePassword(playername, narrow_to_wide(menudata.password));
|
2012-03-15 13:17:05 +01:00
|
|
|
//infostream<<"Main: password hash: '"<<password<<"'"<<std::endl;
|
|
|
|
|
2013-06-23 18:30:21 +02:00
|
|
|
address = menudata.address;
|
2014-02-05 06:05:58 +01:00
|
|
|
int newport = stoi(menudata.port);
|
2014-06-01 00:55:23 +02:00
|
|
|
if (newport != 0)
|
2014-02-05 06:05:58 +01:00
|
|
|
port = newport;
|
2013-06-23 18:30:21 +02:00
|
|
|
|
2012-03-15 14:20:20 +01:00
|
|
|
simple_singleplayer_mode = menudata.simple_singleplayer_mode;
|
2013-06-23 18:30:21 +02:00
|
|
|
|
2012-03-15 13:17:05 +01:00
|
|
|
// Save settings
|
|
|
|
g_settings->set("name", playername);
|
2013-06-23 18:30:21 +02:00
|
|
|
|
2012-03-15 13:17:05 +01:00
|
|
|
// Break out of menu-game loop to shut down cleanly
|
2014-06-01 00:55:23 +02:00
|
|
|
if (device->run() == false || kill == true)
|
2012-03-15 13:17:05 +01:00
|
|
|
break;
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2012-03-15 14:20:20 +01:00
|
|
|
current_playername = playername;
|
|
|
|
current_password = password;
|
|
|
|
current_address = address;
|
|
|
|
current_port = port;
|
|
|
|
|
|
|
|
// If using simple singleplayer mode, override
|
2014-06-01 00:55:23 +02:00
|
|
|
if (simple_singleplayer_mode) {
|
2012-03-15 14:20:20 +01:00
|
|
|
current_playername = "singleplayer";
|
|
|
|
current_password = "";
|
|
|
|
current_address = "";
|
2013-07-12 13:26:25 +02:00
|
|
|
current_port = myrand_range(49152, 65535);
|
2014-06-01 00:55:23 +02:00
|
|
|
} else if (address != "") {
|
2012-12-25 12:20:51 +01:00
|
|
|
ServerListSpec server;
|
2013-02-21 23:00:44 +01:00
|
|
|
server["name"] = menudata.servername;
|
2013-06-23 18:30:21 +02:00
|
|
|
server["address"] = menudata.address;
|
|
|
|
server["port"] = menudata.port;
|
2013-02-21 23:00:44 +01:00
|
|
|
server["description"] = menudata.serverdescription;
|
2012-12-25 12:20:51 +01:00
|
|
|
ServerList::insert(server);
|
|
|
|
}
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2014-05-20 19:04:57 +02:00
|
|
|
if ((!skip_main_menu) &&
|
|
|
|
(menudata.selected_world >= 0) &&
|
|
|
|
(menudata.selected_world < (int)worldspecs.size())) {
|
|
|
|
g_settings->set("selected_world_path",
|
|
|
|
worldspecs[menudata.selected_world].path);
|
2012-03-11 19:45:14 +01:00
|
|
|
worldspec = worldspecs[menudata.selected_world];
|
2014-05-20 19:04:57 +02:00
|
|
|
|
2012-03-11 19:45:14 +01:00
|
|
|
}
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2014-05-20 19:04:57 +02:00
|
|
|
infostream <<"Selected world: " << worldspec.name
|
|
|
|
<< " ["<<worldspec.path<<"]" <<std::endl;
|
|
|
|
|
|
|
|
|
2012-03-11 19:45:14 +01:00
|
|
|
// If local game
|
2014-06-01 00:55:23 +02:00
|
|
|
if (current_address == "") {
|
2014-05-20 19:04:57 +02:00
|
|
|
if (worldspec.path == "") {
|
2012-06-04 22:24:31 +02:00
|
|
|
error_message = wgettext("No world selected and no address "
|
|
|
|
"provided. Nothing to do.");
|
2014-06-01 00:55:23 +02:00
|
|
|
errorstream << wide_to_narrow(error_message) << std::endl;
|
2012-03-11 19:45:14 +01:00
|
|
|
continue;
|
|
|
|
}
|
2014-05-20 19:04:57 +02:00
|
|
|
|
|
|
|
if (!fs::PathExists(worldspec.path)) {
|
|
|
|
error_message = wgettext("Provided world path doesn't exist: ")
|
|
|
|
+ narrow_to_wide(worldspec.path);
|
|
|
|
errorstream << wide_to_narrow(error_message) << std::endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-03-11 19:45:14 +01:00
|
|
|
// Load gamespec for required game
|
2012-04-08 22:15:50 +02:00
|
|
|
gamespec = findWorldSubgame(worldspec.path);
|
2014-06-01 00:55:23 +02:00
|
|
|
if (!gamespec.isValid() && !commanded_gamespec.isValid()) {
|
2012-06-04 22:24:31 +02:00
|
|
|
error_message = wgettext("Could not find or load game \"")
|
2012-03-11 19:45:14 +01:00
|
|
|
+ narrow_to_wide(worldspec.gameid) + L"\"";
|
2014-06-01 00:55:23 +02:00
|
|
|
errorstream << wide_to_narrow(error_message) << std::endl;
|
2012-03-11 19:45:14 +01:00
|
|
|
continue;
|
|
|
|
}
|
2014-06-01 00:55:23 +02:00
|
|
|
if (commanded_gamespec.isValid() &&
|
|
|
|
commanded_gamespec.id != worldspec.gameid) {
|
2012-03-11 19:45:14 +01:00
|
|
|
errorstream<<"WARNING: Overriding gamespec from \""
|
2014-06-01 00:55:23 +02:00
|
|
|
<< worldspec.gameid << "\" to \""
|
|
|
|
<< commanded_gamespec.id << "\"" << std::endl;
|
2012-03-11 19:45:14 +01:00
|
|
|
gamespec = commanded_gamespec;
|
|
|
|
}
|
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
if (!gamespec.isValid()) {
|
2012-06-04 22:24:31 +02:00
|
|
|
error_message = wgettext("Invalid gamespec.");
|
|
|
|
error_message += L" (world_gameid="
|
2014-06-01 00:55:23 +02:00
|
|
|
+ narrow_to_wide(worldspec.gameid) + L")";
|
|
|
|
errorstream << wide_to_narrow(error_message) << std::endl;
|
2012-03-11 19:45:14 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
// Continue to game
|
|
|
|
break;
|
|
|
|
}
|
2013-07-28 23:14:42 +02:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
// Break out of menu-game loop to shut down cleanly
|
2014-06-01 00:55:23 +02:00
|
|
|
if (device->run() == false || kill == true) {
|
|
|
|
if (g_settings_path != "") {
|
|
|
|
g_settings->updateConfigFile(g_settings_path.c_str());
|
2013-08-11 04:09:45 +02:00
|
|
|
}
|
2011-07-23 18:17:39 +02:00
|
|
|
break;
|
2013-06-23 18:30:21 +02:00
|
|
|
}
|
2012-03-15 14:20:20 +01:00
|
|
|
|
2014-08-22 14:03:04 +02:00
|
|
|
if (current_playername.length() > PLAYERNAME_SIZE-1) {
|
2014-08-22 21:51:20 +02:00
|
|
|
error_message = wgettext("Player name too long.");
|
2014-08-22 14:03:04 +02:00
|
|
|
playername = current_playername.substr(0,PLAYERNAME_SIZE-1);
|
|
|
|
g_settings->set("name", playername);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
/*
|
|
|
|
Run game
|
|
|
|
*/
|
2014-04-21 14:10:59 +02:00
|
|
|
#ifdef HAVE_TOUCHSCREENGUI
|
|
|
|
receiver->m_touchscreengui = new TouchScreenGUI(device, receiver);
|
|
|
|
g_touchscreengui = receiver->m_touchscreengui;
|
|
|
|
#endif
|
2011-07-23 18:17:39 +02:00
|
|
|
the_game(
|
Refactor the_game() to make it more understandable and maintainable.
The following is a record of 31 commits before squashing:
Revert "Remove m_ext_ptr in GUIFormSpecMenu, replaced by refcount mechanism"
This reverts commit b49e5cfc7013cef7e9af79d17e04f7e7e4c377d4.
Basic reformatting with astyle
-- additional formatting will be modified, manually, as the need for it is encountered
Start "outlining" what a MinetestApp class might look like
Add MinetestApp::shutdown()
Converted class member functions to camelCase and created protos for new functions
First stage of connect to server done
Add get itemdefs/nodedefs/media code
Init clouds, camera, sky, init GUI, HUD
Input handling
Client events, camera, sound, draw
Fix wield hand getting stuck digging and add debug text back
Fix FPS
Added profiler graph back
Fix FPS issue
Need to work out what went wrong and clean up the copy/paste stuff
Annotate
Various:
Rewrote limitFps()
Limited scope of some variables
Jitter calcs
Reduce scope of objects
Move some stuff out of ::run and minor formatting cleanup
Scope reduction
Function splits
Removed old (broken) limitFps()
Added exception handling back
Fixed some formatting
Reverted commented out unit tests (uncommented them)
Slow clouds down on loading and media screens so the behaviour is like the original the_game()
Formatting/style (no functional changes)
Manually reapply upstream b49e5cf: Remove m_ext_ptr in GUIFormSpecMenu, replaced by refcount mechanism
Fixed silly errors on my part
Minor formatting cleanups
Removed strange differentiation in FPS limiting when loading
FPS limiting was done differently if cloud_menu_background was true, which does not make sense
Cleaning up
Add some comments
2014-10-31 13:13:04 +01:00
|
|
|
&kill,
|
2011-07-23 18:17:39 +02:00
|
|
|
random_input,
|
|
|
|
input,
|
|
|
|
device,
|
|
|
|
font,
|
2012-03-11 19:45:14 +01:00
|
|
|
worldspec.path,
|
2012-03-15 14:20:20 +01:00
|
|
|
current_playername,
|
|
|
|
current_password,
|
|
|
|
current_address,
|
|
|
|
current_port,
|
2011-07-30 18:49:42 +02:00
|
|
|
error_message,
|
2012-03-11 13:54:23 +01:00
|
|
|
chat_backend,
|
2012-03-15 14:20:20 +01:00
|
|
|
gamespec,
|
|
|
|
simple_singleplayer_mode
|
2011-07-23 18:17:39 +02:00
|
|
|
);
|
2013-05-09 18:23:48 +02:00
|
|
|
smgr->clear();
|
2014-04-21 14:10:59 +02:00
|
|
|
#ifdef HAVE_TOUCHSCREENGUI
|
|
|
|
delete g_touchscreengui;
|
|
|
|
g_touchscreengui = NULL;
|
|
|
|
receiver->m_touchscreengui = NULL;
|
|
|
|
#endif
|
2011-07-23 18:17:39 +02:00
|
|
|
|
|
|
|
} //try
|
|
|
|
catch(con::PeerNotFoundException &e)
|
|
|
|
{
|
2012-06-04 22:24:31 +02:00
|
|
|
error_message = wgettext("Connection error (timed out?)");
|
2014-06-01 00:55:23 +02:00
|
|
|
errorstream << wide_to_narrow(error_message) << std::endl;
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
|
|
|
#ifdef NDEBUG
|
|
|
|
catch(std::exception &e)
|
|
|
|
{
|
2012-06-04 22:24:31 +02:00
|
|
|
std::string narrow_message = "Some exception: \"";
|
2011-07-23 18:17:39 +02:00
|
|
|
narrow_message += e.what();
|
|
|
|
narrow_message += "\"";
|
2014-06-01 00:55:23 +02:00
|
|
|
errorstream << narrow_message << std::endl;
|
2011-07-23 18:17:39 +02:00
|
|
|
error_message = narrow_to_wide(narrow_message);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-03-11 11:06:59 +01:00
|
|
|
// If no main menu, show error and exit
|
2014-06-01 00:55:23 +02:00
|
|
|
if (skip_main_menu) {
|
|
|
|
if (error_message != L"") {
|
|
|
|
verbosestream << "error_message = "
|
|
|
|
<< wide_to_narrow(error_message) << std::endl;
|
2012-03-11 11:06:59 +01:00
|
|
|
retval = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2011-07-23 18:17:39 +02:00
|
|
|
} // Menu-game loop
|
2013-06-23 18:30:21 +02:00
|
|
|
|
|
|
|
|
2013-05-09 18:23:48 +02:00
|
|
|
g_menuclouds->drop();
|
|
|
|
g_menucloudsmgr->drop();
|
2013-06-23 18:30:21 +02:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
delete input;
|
|
|
|
|
|
|
|
/*
|
|
|
|
In the end, delete the Irrlicht device.
|
|
|
|
*/
|
|
|
|
device->drop();
|
2012-03-10 15:46:19 +01:00
|
|
|
|
2013-05-16 02:19:32 +02:00
|
|
|
#if USE_FREETYPE
|
2013-08-04 20:18:56 +02:00
|
|
|
if (use_freetype)
|
|
|
|
font->drop();
|
2013-05-16 02:19:32 +02:00
|
|
|
#endif
|
2014-04-21 14:10:59 +02:00
|
|
|
delete receiver;
|
2012-03-10 15:46:19 +01:00
|
|
|
#endif // !SERVER
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2012-03-10 23:53:39 +01:00
|
|
|
// Update configuration file
|
2014-06-01 00:55:23 +02:00
|
|
|
if (g_settings_path != "")
|
2013-08-11 04:09:45 +02:00
|
|
|
g_settings->updateConfigFile(g_settings_path.c_str());
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2012-03-12 20:27:29 +01:00
|
|
|
// Print modified quicktune values
|
|
|
|
{
|
|
|
|
bool header_printed = false;
|
|
|
|
std::vector<std::string> names = getQuicktuneNames();
|
2014-06-01 00:55:23 +02:00
|
|
|
for(u32 i = 0; i < names.size(); i++) {
|
2012-03-12 20:27:29 +01:00
|
|
|
QuicktuneValue val = getQuicktuneValue(names[i]);
|
2014-06-01 00:55:23 +02:00
|
|
|
if (!val.modified)
|
2012-03-12 20:27:29 +01:00
|
|
|
continue;
|
2014-06-01 00:55:23 +02:00
|
|
|
if (!header_printed) {
|
|
|
|
dstream << "Modified quicktune values:" << std::endl;
|
2012-03-12 20:27:29 +01:00
|
|
|
header_printed = true;
|
|
|
|
}
|
2014-06-01 00:55:23 +02:00
|
|
|
dstream<<names[i] << " = " << val.getString() << std::endl;
|
2012-03-12 20:27:29 +01:00
|
|
|
}
|
|
|
|
}
|
2012-03-10 23:53:39 +01:00
|
|
|
|
2013-08-29 05:04:56 +02:00
|
|
|
// Stop httpfetch thread (if started)
|
|
|
|
httpfetch_cleanup();
|
|
|
|
|
2011-10-16 13:57:53 +02:00
|
|
|
END_DEBUG_EXCEPTION_HANDLER(errorstream)
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2011-07-23 18:17:39 +02:00
|
|
|
debugstreams_deinit();
|
2013-11-26 18:15:31 +01:00
|
|
|
|
2014-06-01 00:55:23 +02:00
|
|
|
|
2012-03-11 11:06:59 +01:00
|
|
|
return retval;
|
2011-07-23 18:17:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//END
|