Skip to content

Commit d6cc0d8

Browse files
committedNov 22, 2014
refactor main.cpp
1 parent cb2d467 commit d6cc0d8

File tree

1 file changed

+1219
-925
lines changed

1 file changed

+1219
-925
lines changed
 

‎src/main.cpp

+1,219-925
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
9393
#ifdef HAVE_TOUCHSCREENGUI
9494
#include "touchscreengui.h"
9595
#endif
96+
9697
/*
9798
Settings.
9899
These are loaded from the config file.
99100
*/
100-
Settings main_settings;
101+
static Settings main_settings;
101102
Settings *g_settings = &main_settings;
102103
std::string g_settings_path;
103104

@@ -125,6 +126,66 @@ std::ostream *derr_server_ptr = &errorstream;
125126
std::ostream *dout_client_ptr = &infostream;
126127
std::ostream *derr_client_ptr = &errorstream;
127128

129+
#define DEBUGFILE "debug.txt"
130+
#define DEFAULT_SERVER_PORT 30000
131+
132+
typedef std::map<std::string, ValueSpec> OptionList;
133+
134+
struct GameParams {
135+
u16 socket_port;
136+
std::string world_path;
137+
SubgameSpec game_spec;
138+
bool is_dedicated_server;
139+
int log_level;
140+
};
141+
142+
/**********************************************************************
143+
* Private functions
144+
**********************************************************************/
145+
146+
static bool get_cmdline_opts(int argc, char *argv[], Settings *cmd_args);
147+
static void set_allowed_options(OptionList *allowed_options);
148+
149+
static void print_help(const OptionList &allowed_options);
150+
static void print_allowed_options(const OptionList &allowed_options);
151+
static void print_version();
152+
static void print_worldspecs(const std::vector<WorldSpec> &worldspecs,
153+
std::ostream &os);
154+
static void print_modified_quicktune_values();
155+
156+
static void list_game_ids();
157+
static void list_worlds();
158+
static void setup_log_params(const Settings &cmd_args);
159+
static bool create_userdata_path();
160+
static bool init_common(int *log_level, const Settings &cmd_args);
161+
static void startup_message();
162+
static bool read_config_file(const Settings &cmd_args);
163+
static void init_debug_streams(int *log_level, const Settings &cmd_args);
164+
165+
static bool game_configure(GameParams *game_params, const Settings &cmd_args);
166+
static void game_configure_port(GameParams *game_params, const Settings &cmd_args);
167+
168+
static bool game_configure_world(GameParams *game_params, const Settings &cmd_args);
169+
static bool get_world_from_cmdline(GameParams *game_params, const Settings &cmd_args);
170+
static bool get_world_from_config(GameParams *game_params, const Settings &cmd_args);
171+
static bool auto_select_world(GameParams *game_params);
172+
static std::string get_clean_world_path(const std::string &path);
173+
174+
static bool game_configure_subgame(GameParams *game_params, const Settings &cmd_args);
175+
static bool get_game_from_cmdline(GameParams *game_params, const Settings &cmd_args);
176+
static bool determine_subgame(GameParams *game_params);
177+
178+
static bool run_dedicated_server(const GameParams &game_params, const Settings &cmd_args);
179+
static bool migrate_database(const GameParams &game_params, const Settings &cmd_args,
180+
Server *server);
181+
182+
#ifndef SERVER
183+
static bool print_video_modes();
184+
static void speed_tests();
185+
#endif
186+
187+
/**********************************************************************/
188+
128189
#ifndef SERVER
129190
/*
130191
Random stuff
@@ -285,7 +346,7 @@ class MyEventReceiver : public IEventReceiver
285346
}
286347
#endif
287348
// handle mouse events
288-
if(event.EventType == irr::EET_MOUSE_INPUT_EVENT) {
349+
if (event.EventType == irr::EET_MOUSE_INPUT_EVENT) {
289350
if (noMenuActive() == false) {
290351
left_active = false;
291352
middle_active = false;
@@ -312,8 +373,9 @@ class MyEventReceiver : public IEventReceiver
312373
}
313374
}
314375
}
315-
if(event.EventType == irr::EET_LOG_TEXT_EVENT) {
316-
dstream<< std::string("Irrlicht log: ") + std::string(event.LogEvent.Text)<<std::endl;
376+
if (event.EventType == irr::EET_LOG_TEXT_EVENT) {
377+
dstream << std::string("Irrlicht log: ") + std::string(event.LogEvent.Text)
378+
<< std::endl;
317379
return true;
318380
}
319381
/* always return false in order to continue processing events */
@@ -649,334 +711,447 @@ class RandomInputHandler : public InputHandler
649711
bool rightreleased;
650712
};
651713

714+
715+
class ClientLauncher
716+
{
717+
public:
718+
ClientLauncher() :
719+
list_video_modes(false),
720+
skip_main_menu(false),
721+
use_freetype(false),
722+
random_input(false),
723+
address(""),
724+
playername(""),
725+
password(""),
726+
device(NULL),
727+
input(NULL),
728+
receiver(NULL),
729+
skin(NULL),
730+
font(NULL),
731+
simple_singleplayer_mode(false),
732+
current_playername("inv£lid"),
733+
current_password(""),
734+
current_address("does-not-exist"),
735+
current_port(0)
736+
{}
737+
738+
~ClientLauncher();
739+
740+
bool run(GameParams &game_params, const Settings &cmd_args);
741+
742+
protected:
743+
void init_args(GameParams &game_params, const Settings &cmd_args);
744+
bool init_engine(int log_level);
745+
746+
bool launch_game(std::wstring *error_message, GameParams &game_params,
747+
const Settings &cmd_args);
748+
749+
void main_menu(MainMenuData *menudata);
750+
bool create_engine_device(int log_level);
751+
752+
bool list_video_modes;
753+
bool skip_main_menu;
754+
bool use_freetype;
755+
bool random_input;
756+
std::string address;
757+
std::string playername;
758+
std::string password;
759+
IrrlichtDevice *device;
760+
InputHandler *input;
761+
MyEventReceiver *receiver;
762+
gui::IGUISkin *skin;
763+
gui::IGUIFont *font;
764+
scene::ISceneManager *smgr;
765+
SubgameSpec gamespec;
766+
WorldSpec worldspec;
767+
bool simple_singleplayer_mode;
768+
769+
// These are set up based on the menu and other things
770+
// TODO: Are these required since there's already playername, password, etc
771+
std::string current_playername;
772+
std::string current_password;
773+
std::string current_address;
774+
int current_port;
775+
};
776+
652777
#endif // !SERVER
653778

654-
// These are defined global so that they're not optimized too much.
655-
// Can't change them to volatile.
656-
s16 temp16;
657-
f32 tempf;
658-
v3f tempv3f1;
659-
v3f tempv3f2;
660-
std::string tempstring;
661-
std::string tempstring2;
779+
static OptionList allowed_options;
662780

663-
void SpeedTests()
781+
int main(int argc, char *argv[])
664782
{
665-
{
666-
infostream << "The following test should take around 20ms." << std::endl;
667-
TimeTaker timer("Testing std::string speed");
668-
const u32 jj = 10000;
669-
for(u32 j = 0; j < jj; j++) {
670-
tempstring = "";
671-
tempstring2 = "";
672-
const u32 ii = 10;
673-
for(u32 i = 0; i < ii; i++) {
674-
tempstring2 += "asd";
675-
}
676-
for(u32 i = 0; i < ii+1; i++) {
677-
tempstring += "asd";
678-
if (tempstring == tempstring2)
679-
break;
680-
}
681-
}
682-
}
783+
int retval;
683784

684-
infostream << "All of the following tests should take around 100ms each."
685-
<< std::endl;
785+
log_add_output_maxlev(&main_stderr_log_out, LMT_ACTION);
786+
log_add_output_all_levs(&main_dstream_no_stderr_log_out);
686787

687-
{
688-
TimeTaker timer("Testing floating-point conversion speed");
689-
tempf = 0.001;
690-
for(u32 i = 0; i < 4000000; i++) {
691-
temp16 += tempf;
692-
tempf += 0.001;
693-
}
694-
}
788+
log_register_thread("main");
695789

696-
{
697-
TimeTaker timer("Testing floating-point vector speed");
790+
Settings cmd_args;
791+
bool cmd_args_ok = get_cmdline_opts(argc, argv, &cmd_args);
792+
if (!cmd_args_ok
793+
|| cmd_args.getFlag("help")
794+
|| cmd_args.exists("nonopt1")) {
795+
print_help(allowed_options);
796+
return cmd_args_ok ? 0 : 1;
797+
}
698798

699-
tempv3f1 = v3f(1, 2, 3);
700-
tempv3f2 = v3f(4, 5, 6);
701-
for(u32 i = 0; i < 10000000; i++) {
702-
tempf += tempv3f1.dotProduct(tempv3f2);
703-
tempv3f2 += v3f(7, 8, 9);
704-
}
799+
if (cmd_args.getFlag("version")) {
800+
print_version();
801+
return 0;
705802
}
706803

707-
{
708-
TimeTaker timer("Testing std::map speed");
804+
setup_log_params(cmd_args);
709805

710-
std::map<v2s16, f32> map1;
711-
tempf = -324;
712-
const s16 ii = 300;
713-
for(s16 y = 0; y < ii; y++) {
714-
for(s16 x = 0; x < ii; x++) {
715-
map1[v2s16(x, y)] = tempf;
716-
tempf += 1;
717-
}
718-
}
719-
for(s16 y = ii - 1; y >= 0; y--) {
720-
for(s16 x = 0; x < ii; x++) {
721-
tempf = map1[v2s16(x, y)];
722-
}
723-
}
806+
porting::signal_handler_init();
807+
porting::initializePaths();
808+
809+
if (!create_userdata_path()) {
810+
errorstream << "Cannot create user data directory" << std::endl;
811+
return 1;
724812
}
725813

726-
{
727-
infostream << "Around 5000/ms should do well here." << std::endl;
728-
TimeTaker timer("Testing mutex speed");
814+
// Initialize debug stacks
815+
debug_stacks_init();
816+
DSTACK(__FUNCTION_NAME);
729817

730-
JMutex m;
731-
u32 n = 0;
732-
u32 i = 0;
733-
do {
734-
n += 10000;
735-
for(; i < n; i++) {
736-
m.Lock();
737-
m.Unlock();
738-
}
739-
}
740-
// Do at least 10ms
741-
while(timer.getTimerTime() < 10);
818+
// Debug handler
819+
BEGIN_DEBUG_EXCEPTION_HANDLER
742820

743-
u32 dtime = timer.stop();
744-
u32 per_ms = n / dtime;
745-
infostream << "Done. " << dtime << "ms, " << per_ms << "/ms" << std::endl;
821+
// List gameids if requested
822+
if (cmd_args.exists("gameid") && cmd_args.get("gameid") == "list") {
823+
list_game_ids();
824+
return 0;
746825
}
747-
}
748826

749-
static void print_worldspecs(const std::vector<WorldSpec> &worldspecs, std::ostream &os)
750-
{
751-
for(u32 i = 0; i < worldspecs.size(); i++) {
752-
std::string name = worldspecs[i].name;
753-
std::string path = worldspecs[i].path;
754-
if (name.find(" ") != std::string::npos)
755-
name = std::string("'") + name + "'";
756-
path = std::string("'") + path + "'";
757-
name = padStringRight(name, 14);
758-
os << " " << name << " " << path << std::endl;
827+
// List worlds if requested
828+
if (cmd_args.exists("world") && cmd_args.get("world") == "list") {
829+
list_worlds();
830+
return 0;
831+
}
832+
833+
GameParams game_params;
834+
if (!init_common(&game_params.log_level, cmd_args))
835+
return 1;
836+
837+
#ifndef __ANDROID__
838+
// Run unit tests
839+
if ((ENABLE_TESTS && cmd_args.getFlag("disable-unittests") == false)
840+
|| cmd_args.getFlag("enable-unittests") == true) {
841+
run_tests();
759842
}
843+
#endif
844+
845+
#ifdef SERVER
846+
game_params.is_dedicated_server = true;
847+
#else
848+
game_params.is_dedicated_server = cmd_args.getFlag("server");
849+
#endif
850+
851+
if (!game_configure(&game_params, cmd_args))
852+
return 1;
853+
854+
assert(game_params.world_path != "");
855+
856+
infostream << "Using commanded world path ["
857+
<< game_params.world_path << "]" << std::endl;
858+
859+
//Run dedicated server if asked to or no other option
860+
g_settings->set("server_dedicated",
861+
game_params.is_dedicated_server ? "true" : "false");
862+
863+
if (game_params.is_dedicated_server)
864+
return run_dedicated_server(game_params, cmd_args) ? 0 : 1;
865+
866+
#ifndef SERVER
867+
ClientLauncher launcher;
868+
retval = launcher.run(game_params, cmd_args) ? 0 : 1;
869+
#else
870+
retval = 0;
871+
#endif
872+
873+
// Update configuration file
874+
if (g_settings_path != "")
875+
g_settings->updateConfigFile(g_settings_path.c_str());
876+
877+
print_modified_quicktune_values();
878+
879+
// Stop httpfetch thread (if started)
880+
httpfetch_cleanup();
881+
882+
END_DEBUG_EXCEPTION_HANDLER(errorstream)
883+
884+
return retval;
760885
}
761886

762-
int main(int argc, char *argv[])
763-
{
764-
int retval = 0;
765887

766-
/*
767-
Initialization
768-
*/
888+
/*****************************************************************************
889+
* Startup / Init
890+
*****************************************************************************/
769891

770-
log_add_output_maxlev(&main_stderr_log_out, LMT_ACTION);
771-
log_add_output_all_levs(&main_dstream_no_stderr_log_out);
772892

773-
log_register_thread("main");
774-
/*
775-
Parse command line
776-
*/
893+
static bool get_cmdline_opts(int argc, char *argv[], Settings *cmd_args)
894+
{
895+
set_allowed_options(&allowed_options);
896+
897+
return cmd_args->parseCommandLine(argc, argv, allowed_options);
898+
}
899+
900+
static void set_allowed_options(OptionList *allowed_options)
901+
{
902+
allowed_options->clear();
777903

778-
// List all allowed options
779-
std::map<std::string, ValueSpec> allowed_options;
780-
allowed_options.insert(std::make_pair("help", ValueSpec(VALUETYPE_FLAG,
904+
allowed_options->insert(std::make_pair("help", ValueSpec(VALUETYPE_FLAG,
781905
_("Show allowed options"))));
782-
allowed_options.insert(std::make_pair("version", ValueSpec(VALUETYPE_FLAG,
906+
allowed_options->insert(std::make_pair("version", ValueSpec(VALUETYPE_FLAG,
783907
_("Show version information"))));
784-
allowed_options.insert(std::make_pair("config", ValueSpec(VALUETYPE_STRING,
908+
allowed_options->insert(std::make_pair("config", ValueSpec(VALUETYPE_STRING,
785909
_("Load configuration from specified file"))));
786-
allowed_options.insert(std::make_pair("port", ValueSpec(VALUETYPE_STRING,
910+
allowed_options->insert(std::make_pair("port", ValueSpec(VALUETYPE_STRING,
787911
_("Set network port (UDP)"))));
788-
allowed_options.insert(std::make_pair("disable-unittests", ValueSpec(VALUETYPE_FLAG,
912+
allowed_options->insert(std::make_pair("disable-unittests", ValueSpec(VALUETYPE_FLAG,
789913
_("Disable unit tests"))));
790-
allowed_options.insert(std::make_pair("enable-unittests", ValueSpec(VALUETYPE_FLAG,
914+
allowed_options->insert(std::make_pair("enable-unittests", ValueSpec(VALUETYPE_FLAG,
791915
_("Enable unit tests"))));
792-
allowed_options.insert(std::make_pair("map-dir", ValueSpec(VALUETYPE_STRING,
916+
allowed_options->insert(std::make_pair("map-dir", ValueSpec(VALUETYPE_STRING,
793917
_("Same as --world (deprecated)"))));
794-
allowed_options.insert(std::make_pair("world", ValueSpec(VALUETYPE_STRING,
918+
allowed_options->insert(std::make_pair("world", ValueSpec(VALUETYPE_STRING,
795919
_("Set world path (implies local game) ('list' lists all)"))));
796-
allowed_options.insert(std::make_pair("worldname", ValueSpec(VALUETYPE_STRING,
920+
allowed_options->insert(std::make_pair("worldname", ValueSpec(VALUETYPE_STRING,
797921
_("Set world by name (implies local game)"))));
798-
allowed_options.insert(std::make_pair("quiet", ValueSpec(VALUETYPE_FLAG,
922+
allowed_options->insert(std::make_pair("quiet", ValueSpec(VALUETYPE_FLAG,
799923
_("Print to console errors only"))));
800-
allowed_options.insert(std::make_pair("info", ValueSpec(VALUETYPE_FLAG,
924+
allowed_options->insert(std::make_pair("info", ValueSpec(VALUETYPE_FLAG,
801925
_("Print more information to console"))));
802-
allowed_options.insert(std::make_pair("verbose", ValueSpec(VALUETYPE_FLAG,
926+
allowed_options->insert(std::make_pair("verbose", ValueSpec(VALUETYPE_FLAG,
803927
_("Print even more information to console"))));
804-
allowed_options.insert(std::make_pair("trace", ValueSpec(VALUETYPE_FLAG,
928+
allowed_options->insert(std::make_pair("trace", ValueSpec(VALUETYPE_FLAG,
805929
_("Print enormous amounts of information to log and console"))));
806-
allowed_options.insert(std::make_pair("logfile", ValueSpec(VALUETYPE_STRING,
930+
allowed_options->insert(std::make_pair("logfile", ValueSpec(VALUETYPE_STRING,
807931
_("Set logfile path ('' = no logging)"))));
808-
allowed_options.insert(std::make_pair("gameid", ValueSpec(VALUETYPE_STRING,
932+
allowed_options->insert(std::make_pair("gameid", ValueSpec(VALUETYPE_STRING,
809933
_("Set gameid (\"--gameid list\" prints available ones)"))));
810-
allowed_options.insert(std::make_pair("migrate", ValueSpec(VALUETYPE_STRING,
934+
allowed_options->insert(std::make_pair("migrate", ValueSpec(VALUETYPE_STRING,
811935
_("Migrate from current map backend to another (Only works when using minetestserver or with --server)"))));
812936
#ifndef SERVER
813-
allowed_options.insert(std::make_pair("videomodes", ValueSpec(VALUETYPE_FLAG,
937+
allowed_options->insert(std::make_pair("videomodes", ValueSpec(VALUETYPE_FLAG,
814938
_("Show available video modes"))));
815-
allowed_options.insert(std::make_pair("speedtests", ValueSpec(VALUETYPE_FLAG,
939+
allowed_options->insert(std::make_pair("speedtests", ValueSpec(VALUETYPE_FLAG,
816940
_("Run speed tests"))));
817-
allowed_options.insert(std::make_pair("address", ValueSpec(VALUETYPE_STRING,
941+
allowed_options->insert(std::make_pair("address", ValueSpec(VALUETYPE_STRING,
818942
_("Address to connect to. ('' = local game)"))));
819-
allowed_options.insert(std::make_pair("random-input", ValueSpec(VALUETYPE_FLAG,
943+
allowed_options->insert(std::make_pair("random-input", ValueSpec(VALUETYPE_FLAG,
820944
_("Enable random user input, for testing"))));
821-
allowed_options.insert(std::make_pair("server", ValueSpec(VALUETYPE_FLAG,
945+
allowed_options->insert(std::make_pair("server", ValueSpec(VALUETYPE_FLAG,
822946
_("Run dedicated server"))));
823-
allowed_options.insert(std::make_pair("name", ValueSpec(VALUETYPE_STRING,
947+
allowed_options->insert(std::make_pair("name", ValueSpec(VALUETYPE_STRING,
824948
_("Set player name"))));
825-
allowed_options.insert(std::make_pair("password", ValueSpec(VALUETYPE_STRING,
949+
allowed_options->insert(std::make_pair("password", ValueSpec(VALUETYPE_STRING,
826950
_("Set password"))));
827-
allowed_options.insert(std::make_pair("go", ValueSpec(VALUETYPE_FLAG,
951+
allowed_options->insert(std::make_pair("go", ValueSpec(VALUETYPE_FLAG,
828952
_("Disable main menu"))));
829953
#endif
830954

831-
Settings cmd_args;
955+
}
832956

833-
bool ret = cmd_args.parseCommandLine(argc, argv, allowed_options);
834-
835-
if (ret == false || cmd_args.getFlag("help") || cmd_args.exists("nonopt1")) {
836-
dstream << _("Allowed options:") << std::endl;
837-
for(std::map<std::string, ValueSpec>::iterator
838-
i = allowed_options.begin();
839-
i != allowed_options.end(); ++i) {
840-
std::ostringstream os1(std::ios::binary);
841-
os1 << " --"<<i->first;
842-
if (i->second.type == VALUETYPE_FLAG) {
843-
} else
844-
os1 << _(" <value>");
845-
dstream << padStringRight(os1.str(), 24);
846-
847-
if (i->second.help != NULL)
848-
dstream << i->second.help;
849-
dstream << std::endl;
850-
}
957+
static void print_help(const OptionList &allowed_options)
958+
{
959+
dstream << _("Allowed options:") << std::endl;
960+
print_allowed_options(allowed_options);
961+
}
962+
963+
static void print_allowed_options(const OptionList &allowed_options)
964+
{
965+
for (OptionList::const_iterator i = allowed_options.begin();
966+
i != allowed_options.end(); ++i) {
967+
std::ostringstream os1(std::ios::binary);
968+
os1 << " --" << i->first;
969+
if (i->second.type != VALUETYPE_FLAG)
970+
os1 << _(" <value>");
851971

852-
return cmd_args.getFlag("help") ? 0 : 1;
972+
dstream << padStringRight(os1.str(), 24);
973+
974+
if (i->second.help != NULL)
975+
dstream << i->second.help;
976+
977+
dstream << std::endl;
853978
}
979+
}
854980

855-
if (cmd_args.getFlag("version")) {
981+
static void print_version()
982+
{
856983
#ifdef SERVER
857-
dstream << "minetestserver " << minetest_version_hash << std::endl;
984+
dstream << "minetestserver " << minetest_version_hash << std::endl;
858985
#else
859-
dstream << "Minetest " << minetest_version_hash << std::endl;
860-
dstream << "Using Irrlicht " << IRRLICHT_SDK_VERSION << std::endl;
986+
dstream << "Minetest " << minetest_version_hash << std::endl;
987+
dstream << "Using Irrlicht " << IRRLICHT_SDK_VERSION << std::endl;
861988
#endif
862-
dstream << "Build info: " << minetest_build_info << std::endl;
863-
return 0;
989+
dstream << "Build info: " << minetest_build_info << std::endl;
990+
}
991+
992+
static void list_game_ids()
993+
{
994+
std::set<std::string> gameids = getAvailableGameIds();
995+
for (std::set<std::string>::const_iterator i = gameids.begin();
996+
i != gameids.end(); i++)
997+
dstream << (*i) <<std::endl;
998+
}
999+
1000+
static void list_worlds()
1001+
{
1002+
dstream << _("Available worlds:") << std::endl;
1003+
std::vector<WorldSpec> worldspecs = getAvailableWorlds();
1004+
print_worldspecs(worldspecs, dstream);
1005+
}
1006+
1007+
static void print_worldspecs(const std::vector<WorldSpec> &worldspecs,
1008+
std::ostream &os)
1009+
{
1010+
for (size_t i = 0; i < worldspecs.size(); i++) {
1011+
std::string name = worldspecs[i].name;
1012+
std::string path = worldspecs[i].path;
1013+
if (name.find(" ") != std::string::npos)
1014+
name = std::string("'") + name + "'";
1015+
path = std::string("'") + path + "'";
1016+
name = padStringRight(name, 14);
1017+
os << " " << name << " " << path << std::endl;
8641018
}
1019+
}
8651020

866-
/*
867-
Low-level initialization
868-
*/
1021+
static void print_modified_quicktune_values()
1022+
{
1023+
bool header_printed = false;
1024+
std::vector<std::string> names = getQuicktuneNames();
1025+
1026+
for (u32 i = 0; i < names.size(); i++) {
1027+
QuicktuneValue val = getQuicktuneValue(names[i]);
1028+
if (!val.modified)
1029+
continue;
1030+
if (!header_printed) {
1031+
dstream << "Modified quicktune values:" << std::endl;
1032+
header_printed = true;
1033+
}
1034+
dstream << names[i] << " = " << val.getString() << std::endl;
1035+
}
1036+
}
8691037

1038+
static void setup_log_params(const Settings &cmd_args)
1039+
{
8701040
// Quiet mode, print errors only
8711041
if (cmd_args.getFlag("quiet")) {
8721042
log_remove_output(&main_stderr_log_out);
8731043
log_add_output_maxlev(&main_stderr_log_out, LMT_ERROR);
8741044
}
1045+
8751046
// If trace is enabled, enable logging of certain things
8761047
if (cmd_args.getFlag("trace")) {
8771048
dstream << _("Enabling trace level debug output") << std::endl;
8781049
log_trace_level_enabled = true;
8791050
dout_con_ptr = &verbosestream; // this is somewhat old crap
8801051
socket_enable_debug_output = true; // socket doesn't use log.h
8811052
}
1053+
8821054
// In certain cases, output info level on stderr
8831055
if (cmd_args.getFlag("info") || cmd_args.getFlag("verbose") ||
8841056
cmd_args.getFlag("trace") || cmd_args.getFlag("speedtests"))
8851057
log_add_output(&main_stderr_log_out, LMT_INFO);
1058+
8861059
// In certain cases, output verbose level on stderr
8871060
if (cmd_args.getFlag("verbose") || cmd_args.getFlag("trace"))
8881061
log_add_output(&main_stderr_log_out, LMT_VERBOSE);
1062+
}
8891063

890-
porting::signal_handler_init();
891-
bool &kill = *porting::signal_handler_killstatus();
892-
893-
porting::initializePaths();
1064+
static bool create_userdata_path()
1065+
{
1066+
bool success;
8941067

8951068
#ifdef __ANDROID__
8961069
porting::initAndroid();
8971070

8981071
porting::setExternalStorageDir(porting::jnienv);
8991072
if (!fs::PathExists(porting::path_user)) {
900-
fs::CreateDir(porting::path_user);
1073+
success = fs::CreateDir(porting::path_user);
9011074
}
9021075
porting::copyAssets();
9031076
#else
9041077
// Create user data directory
905-
fs::CreateDir(porting::path_user);
1078+
success = fs::CreateDir(porting::path_user);
9061079
#endif
9071080

9081081
infostream << "path_share = " << porting::path_share << std::endl;
9091082
infostream << "path_user = " << porting::path_user << std::endl;
9101083

911-
// Initialize debug stacks
912-
debug_stacks_init();
913-
DSTACK(__FUNCTION_NAME);
1084+
return success;
1085+
}
9141086

915-
// Debug handler
916-
BEGIN_DEBUG_EXCEPTION_HANDLER
1087+
static bool init_common(int *log_level, const Settings &cmd_args)
1088+
{
1089+
startup_message();
1090+
set_default_settings(g_settings);
9171091

918-
// List gameids if requested
919-
if (cmd_args.exists("gameid") && cmd_args.get("gameid") == "list") {
920-
std::set<std::string> gameids = getAvailableGameIds();
921-
for(std::set<std::string>::const_iterator i = gameids.begin();
922-
i != gameids.end(); i++)
923-
dstream<<(*i)<<std::endl;
924-
return 0;
925-
}
1092+
// Initialize sockets
1093+
sockets_init();
1094+
atexit(sockets_cleanup);
9261095

927-
// List worlds if requested
928-
if (cmd_args.exists("world") && cmd_args.get("world") == "list") {
929-
dstream << _("Available worlds:") << std::endl;
930-
std::vector<WorldSpec> worldspecs = getAvailableWorlds();
931-
print_worldspecs(worldspecs, dstream);
932-
return 0;
933-
}
1096+
if (!read_config_file(cmd_args))
1097+
return false;
9341098

935-
// Print startup message
936-
infostream<<PROJECT_NAME << " "<< _("with") << " SER_FMT_VER_HIGHEST_READ="
937-
<< (int)SER_FMT_VER_HIGHEST_READ << ", " << minetest_build_info << std::endl;
1099+
init_debug_streams(log_level, cmd_args);
9381100

939-
/*
940-
Basic initialization
941-
*/
1101+
// Initialize random seed
1102+
srand(time(0));
1103+
mysrand(time(0));
9421104

943-
// Initialize default settings
944-
set_default_settings(g_settings);
1105+
// Initialize HTTP fetcher
1106+
httpfetch_init(g_settings->getS32("curl_parallel_limit"));
9451107

946-
// Initialize sockets
947-
sockets_init();
948-
atexit(sockets_cleanup);
1108+
#ifdef _MSC_VER
1109+
init_gettext((porting::path_share + DIR_DELIM + "locale").c_str(),
1110+
g_settings->get("language"), argc, argv);
1111+
#else
1112+
init_gettext((porting::path_share + DIR_DELIM + "locale").c_str(),
1113+
g_settings->get("language"));
1114+
#endif
9491115

950-
/*
951-
Read config file
952-
*/
1116+
return true;
1117+
}
1118+
1119+
static void startup_message()
1120+
{
1121+
infostream << PROJECT_NAME << " " << _("with")
1122+
<< " SER_FMT_VER_HIGHEST_READ="
1123+
<< (int)SER_FMT_VER_HIGHEST_READ << ", "
1124+
<< minetest_build_info << std::endl;
1125+
}
9531126

1127+
static bool read_config_file(const Settings &cmd_args)
1128+
{
9541129
// Path of configuration file in use
955-
g_settings_path = "";
1130+
assert(g_settings_path == ""); // Sanity check
9561131

9571132
if (cmd_args.exists("config")) {
9581133
bool r = g_settings->readConfigFile(cmd_args.get("config").c_str());
959-
if (r == false) {
1134+
if (!r) {
9601135
errorstream << "Could not read configuration from \""
961-
<< cmd_args.get("config") << "\"" << std::endl;
962-
return 1;
1136+
<< cmd_args.get("config") << "\"" << std::endl;
1137+
return false;
9631138
}
9641139
g_settings_path = cmd_args.get("config");
9651140
} else {
9661141
std::vector<std::string> filenames;
967-
filenames.push_back(porting::path_user +
968-
DIR_DELIM + "minetest.conf");
1142+
filenames.push_back(porting::path_user + DIR_DELIM + "minetest.conf");
9691143
// Legacy configuration file location
9701144
filenames.push_back(porting::path_user +
9711145
DIR_DELIM + ".." + DIR_DELIM + "minetest.conf");
1146+
9721147
#if RUN_IN_PLACE
9731148
// Try also from a lower level (to aid having the same configuration
9741149
// for many RUN_IN_PLACE installs)
9751150
filenames.push_back(porting::path_user +
9761151
DIR_DELIM + ".." + DIR_DELIM + ".." + DIR_DELIM + "minetest.conf");
9771152
#endif
9781153

979-
for(u32 i = 0; i < filenames.size(); i++) {
1154+
for (size_t i = 0; i < filenames.size(); i++) {
9801155
bool r = g_settings->readConfigFile(filenames[i].c_str());
9811156
if (r) {
9821157
g_settings_path = filenames[i];
@@ -989,566 +1164,474 @@ int main(int argc, char *argv[])
9891164
g_settings_path = filenames[0];
9901165
}
9911166

992-
// Initialize debug streams
993-
#define DEBUGFILE "debug.txt"
1167+
return true;
1168+
}
1169+
1170+
static void init_debug_streams(int *log_level, const Settings &cmd_args)
1171+
{
9941172
#if RUN_IN_PLACE
9951173
std::string logfile = DEBUGFILE;
9961174
#else
997-
std::string logfile = porting::path_user+DIR_DELIM+DEBUGFILE;
1175+
std::string logfile = porting::path_user + DIR_DELIM + DEBUGFILE;
9981176
#endif
9991177
if (cmd_args.exists("logfile"))
10001178
logfile = cmd_args.get("logfile");
10011179

10021180
log_remove_output(&main_dstream_no_stderr_log_out);
1003-
int loglevel = g_settings->getS32("debug_log_level");
1181+
*log_level = g_settings->getS32("debug_log_level");
10041182

1005-
if (loglevel == 0) //no logging
1183+
if (*log_level == 0) //no logging
10061184
logfile = "";
1007-
else if (loglevel > 0 && loglevel <= LMT_NUM_VALUES)
1008-
log_add_output_maxlev(&main_dstream_no_stderr_log_out,
1009-
(LogMessageLevel)(loglevel - 1));
1185+
if (*log_level < 0) {
1186+
dstream << "WARNING: Supplied debug_log_level < 0; Using 0" << std::endl;
1187+
*log_level = 0;
1188+
} else if (*log_level > LMT_NUM_VALUES) {
1189+
dstream << "WARNING: Supplied debug_log_level > " << LMT_NUM_VALUES
1190+
<< "; Using " << LMT_NUM_VALUES << std::endl;
1191+
*log_level = LMT_NUM_VALUES;
1192+
}
10101193

1011-
if (logfile != "")
1012-
debugstreams_init(false, logfile.c_str());
1013-
else
1014-
debugstreams_init(false, NULL);
1194+
log_add_output_maxlev(&main_dstream_no_stderr_log_out,
1195+
(LogMessageLevel)(*log_level - 1));
1196+
1197+
debugstreams_init(false, logfile == "" ? NULL : logfile.c_str());
10151198

10161199
infostream << "logfile = " << logfile << std::endl;
10171200

1018-
// Initialize random seed
1019-
srand(time(0));
1020-
mysrand(time(0));
1201+
atexit(debugstreams_deinit);
1202+
}
10211203

1022-
// Initialize HTTP fetcher
1023-
httpfetch_init(g_settings->getS32("curl_parallel_limit"));
1204+
static bool game_configure(GameParams *game_params, const Settings &cmd_args)
1205+
{
1206+
game_configure_port(game_params, cmd_args);
10241207

1025-
#ifndef __ANDROID__
1026-
/*
1027-
Run unit tests
1028-
*/
1029-
if ((ENABLE_TESTS && cmd_args.getFlag("disable-unittests") == false)
1030-
|| cmd_args.getFlag("enable-unittests") == true) {
1031-
run_tests();
1208+
if (!game_configure_world(game_params, cmd_args)) {
1209+
errorstream << "No world path specified or found." << std::endl;
1210+
return false;
10321211
}
1033-
#endif
1034-
#ifdef _MSC_VER
1035-
init_gettext((porting::path_share + DIR_DELIM + "locale").c_str(),
1036-
g_settings->get("language"), argc, argv);
1037-
#else
1038-
init_gettext((porting::path_share + DIR_DELIM + "locale").c_str(),
1039-
g_settings->get("language"));
1040-
#endif
10411212

1042-
/*
1043-
Game parameters
1044-
*/
1213+
game_configure_subgame(game_params, cmd_args);
1214+
1215+
return true;
1216+
}
10451217

1046-
// Port
1047-
u16 port = 30000;
1218+
static void game_configure_port(GameParams *game_params, const Settings &cmd_args)
1219+
{
10481220
if (cmd_args.exists("port"))
1049-
port = cmd_args.getU16("port");
1050-
else if (g_settings->exists("port"))
1051-
port = g_settings->getU16("port");
1052-
if (port == 0)
1053-
port = 30000;
1221+
game_params->socket_port = cmd_args.getU16("port");
1222+
else
1223+
game_params->socket_port = g_settings->getU16("port");
10541224

1055-
// World directory
1225+
if (game_params->socket_port == 0)
1226+
game_params->socket_port = DEFAULT_SERVER_PORT;
1227+
}
1228+
1229+
static bool game_configure_world(GameParams *game_params, const Settings &cmd_args)
1230+
{
1231+
if (get_world_from_cmdline(game_params, cmd_args))
1232+
return true;
1233+
if (get_world_from_config(game_params, cmd_args))
1234+
return true;
1235+
1236+
return auto_select_world(game_params);
1237+
}
1238+
1239+
static bool get_world_from_cmdline(GameParams *game_params, const Settings &cmd_args)
1240+
{
10561241
std::string commanded_world = "";
1057-
if (cmd_args.exists("world"))
1058-
commanded_world = cmd_args.get("world");
1059-
else if (cmd_args.exists("map-dir"))
1060-
commanded_world = cmd_args.get("map-dir");
1061-
else if (cmd_args.exists("nonopt0")) // First nameless argument
1062-
commanded_world = cmd_args.get("nonopt0");
1063-
else if (g_settings->exists("map-dir"))
1064-
commanded_world = g_settings->get("map-dir");
10651242

10661243
// World name
10671244
std::string commanded_worldname = "";
10681245
if (cmd_args.exists("worldname"))
10691246
commanded_worldname = cmd_args.get("worldname");
10701247

1071-
// Strip world.mt from commanded_world
1072-
{
1073-
std::string worldmt = "world.mt";
1074-
if (commanded_world.size() > worldmt.size() &&
1075-
commanded_world.substr(commanded_world.size() - worldmt.size())
1076-
== worldmt) {
1077-
dstream << _("Supplied world.mt file - stripping it off.") << std::endl;
1078-
commanded_world = commanded_world.substr(0,
1079-
commanded_world.size() - worldmt.size());
1080-
}
1081-
}
1082-
10831248
// If a world name was specified, convert it to a path
10841249
if (commanded_worldname != "") {
10851250
// Get information about available worlds
10861251
std::vector<WorldSpec> worldspecs = getAvailableWorlds();
10871252
bool found = false;
1088-
for(u32 i = 0; i < worldspecs.size(); i++) {
1253+
for (u32 i = 0; i < worldspecs.size(); i++) {
10891254
std::string name = worldspecs[i].name;
10901255
if (name == commanded_worldname) {
1091-
if (commanded_world != "") {
1092-
dstream << _("--worldname takes precedence over previously "
1093-
"selected world.") << std::endl;
1094-
}
1256+
dstream << _("Using world specified by --worldname on the "
1257+
"command line") << std::endl;
10951258
commanded_world = worldspecs[i].path;
10961259
found = true;
10971260
break;
10981261
}
10991262
}
11001263
if (!found) {
1101-
dstream << _("World") << " '"<<commanded_worldname << _("' not "
1102-
"available. Available worlds:") << std::endl;
1264+
dstream << _("World") << " '" << commanded_worldname
1265+
<< _("' not available. Available worlds:") << std::endl;
11031266
print_worldspecs(worldspecs, dstream);
1104-
return 1;
1267+
return false;
11051268
}
1269+
1270+
game_params->world_path = get_clean_world_path(commanded_world);
1271+
return commanded_world != "";
1272+
}
1273+
1274+
if (cmd_args.exists("world"))
1275+
commanded_world = cmd_args.get("world");
1276+
else if (cmd_args.exists("map-dir"))
1277+
commanded_world = cmd_args.get("map-dir");
1278+
else if (cmd_args.exists("nonopt0")) // First nameless argument
1279+
commanded_world = cmd_args.get("nonopt0");
1280+
1281+
game_params->world_path = get_clean_world_path(commanded_world);
1282+
return commanded_world != "";
1283+
}
1284+
1285+
static bool get_world_from_config(GameParams *game_params, const Settings &cmd_args)
1286+
{
1287+
// World directory
1288+
std::string commanded_world = "";
1289+
1290+
if (g_settings->exists("map-dir"))
1291+
commanded_world = g_settings->get("map-dir");
1292+
1293+
game_params->world_path = get_clean_world_path(commanded_world);
1294+
1295+
return commanded_world != "";
1296+
}
1297+
1298+
static bool auto_select_world(GameParams *game_params)
1299+
{
1300+
// No world was specified; try to select it automatically
1301+
// Get information about available worlds
1302+
1303+
verbosestream << _("Determining world path") << std::endl;
1304+
1305+
std::vector<WorldSpec> worldspecs = getAvailableWorlds();
1306+
std::string world_path;
1307+
1308+
// If there is only a single world, use it
1309+
if (worldspecs.size() == 1) {
1310+
world_path = worldspecs[0].path;
1311+
dstream <<_("Automatically selecting world at") << " ["
1312+
<< world_path << "]" << std::endl;
1313+
// If there are multiple worlds, list them
1314+
} else if (worldspecs.size() > 1 && game_params->is_dedicated_server) {
1315+
dstream << _("Multiple worlds are available.") << std::endl;
1316+
dstream << _("Please select one using --worldname <name>"
1317+
" or --world <path>") << std::endl;
1318+
print_worldspecs(worldspecs, dstream);
1319+
return false;
1320+
// If there are no worlds, automatically create a new one
1321+
} else {
1322+
// This is the ultimate default world path
1323+
world_path = porting::path_user + DIR_DELIM + "worlds" +
1324+
DIR_DELIM + "world";
1325+
infostream << "Creating default world at ["
1326+
<< world_path << "]" << std::endl;
1327+
}
1328+
1329+
assert(world_path != "");
1330+
game_params->world_path = world_path;
1331+
return true;
1332+
}
1333+
1334+
static std::string get_clean_world_path(const std::string &path)
1335+
{
1336+
const std::string worldmt = "world.mt";
1337+
std::string clean_path;
1338+
1339+
if (path.size() > worldmt.size()
1340+
&& path.substr(path.size() - worldmt.size()) == worldmt) {
1341+
dstream << _("Supplied world.mt file - stripping it off.") << std::endl;
1342+
clean_path = path.substr(0, path.size() - worldmt.size());
1343+
} else {
1344+
clean_path = path;
11061345
}
1346+
return path;
1347+
}
1348+
11071349

1108-
// Gamespec
1350+
static bool game_configure_subgame(GameParams *game_params, const Settings &cmd_args)
1351+
{
1352+
bool success;
1353+
1354+
success = get_game_from_cmdline(game_params, cmd_args);
1355+
if (!success)
1356+
success = determine_subgame(game_params);
1357+
1358+
return success;
1359+
}
1360+
1361+
static bool get_game_from_cmdline(GameParams *game_params, const Settings &cmd_args)
1362+
{
11091363
SubgameSpec commanded_gamespec;
1364+
11101365
if (cmd_args.exists("gameid")) {
11111366
std::string gameid = cmd_args.get("gameid");
11121367
commanded_gamespec = findSubgame(gameid);
11131368
if (!commanded_gamespec.isValid()) {
11141369
errorstream << "Game \"" << gameid << "\" not found" << std::endl;
1115-
return 1;
1370+
return false;
11161371
}
1372+
dstream << _("Using game specified by --gameid on the command line")
1373+
<< std::endl;
1374+
game_params->game_spec = commanded_gamespec;
1375+
return true;
11171376
}
11181377

1378+
return false;
1379+
}
11191380

1120-
/*
1121-
Run dedicated server if asked to or no other option
1122-
*/
1123-
#ifdef SERVER
1124-
bool run_dedicated_server = true;
1125-
#else
1126-
bool run_dedicated_server = cmd_args.getFlag("server");
1127-
#endif
1128-
g_settings->set("server_dedicated", run_dedicated_server ? "true" : "false");
1129-
if (run_dedicated_server)
1130-
{
1131-
DSTACK("Dedicated server branch");
1132-
// Create time getter if built with Irrlicht
1133-
#ifndef SERVER
1134-
g_timegetter = new SimpleTimeGetter();
1135-
#endif
1136-
1137-
// World directory
1138-
std::string world_path;
1139-
verbosestream << _("Determining world path") << std::endl;
1140-
bool is_legacy_world = false;
1141-
// If a world was commanded, use it
1142-
if (commanded_world != "") {
1143-
world_path = commanded_world;
1144-
infostream << "Using commanded world path [" << world_path << "]"
1145-
<< std::endl;
1146-
} else { // No world was specified; try to select it automatically
1147-
// Get information about available worlds
1148-
std::vector<WorldSpec> worldspecs = getAvailableWorlds();
1149-
// If a world name was specified, select it
1150-
if (commanded_worldname != "") {
1151-
world_path = "";
1152-
for(u32 i = 0; i < worldspecs.size(); i++) {
1153-
std::string name = worldspecs[i].name;
1154-
if (name == commanded_worldname) {
1155-
world_path = worldspecs[i].path;
1156-
break;
1157-
}
1158-
}
1159-
if (world_path == "") {
1160-
dstream << _("World") << " '" << commanded_worldname << "' " << _("not "
1161-
"available. Available worlds:") << std::endl;
1162-
print_worldspecs(worldspecs, dstream);
1163-
return 1;
1164-
}
1165-
}
1166-
// If there is only a single world, use it
1167-
if (worldspecs.size() == 1) {
1168-
world_path = worldspecs[0].path;
1169-
dstream <<_("Automatically selecting world at") << " ["
1170-
<< world_path << "]" << std::endl;
1171-
// If there are multiple worlds, list them
1172-
} else if (worldspecs.size() > 1) {
1173-
dstream << _("Multiple worlds are available.") << std::endl;
1174-
dstream << _("Please select one using --worldname <name>"
1175-
" or --world <path>") << std::endl;
1176-
print_worldspecs(worldspecs, dstream);
1177-
return 1;
1178-
// If there are no worlds, automatically create a new one
1179-
} else {
1180-
// This is the ultimate default world path
1181-
world_path = porting::path_user + DIR_DELIM + "worlds" +
1182-
DIR_DELIM + "world";
1183-
infostream << "Creating default world at ["
1184-
<< world_path << "]" << std::endl;
1185-
}
1186-
}
1187-
1188-
if (world_path == "") {
1189-
errorstream << "No world path specified or found." << std::endl;
1190-
return 1;
1381+
static bool determine_subgame(GameParams *game_params)
1382+
{
1383+
SubgameSpec gamespec;
1384+
1385+
assert(game_params->world_path != ""); // pre-condition
1386+
1387+
verbosestream << _("Determining gameid/gamespec") << std::endl;
1388+
// If world doesn't exist
1389+
if (game_params->world_path != ""
1390+
&& !getWorldExists(game_params->world_path)) {
1391+
// Try to take gamespec from command line
1392+
if (game_params->game_spec.isValid()) {
1393+
gamespec = game_params->game_spec;
1394+
infostream << "Using commanded gameid [" << gamespec.id << "]" << std::endl;
1395+
} else { // Otherwise we will be using "minetest"
1396+
gamespec = findSubgame(g_settings->get("default_game"));
1397+
infostream << "Using default gameid [" << gamespec.id << "]" << std::endl;
11911398
}
1192-
verbosestream << _("Using world path") << " [" << world_path << "]" << std::endl;
1193-
1194-
// We need a gamespec.
1195-
SubgameSpec gamespec;
1196-
verbosestream << _("Determining gameid/gamespec") << std::endl;
1197-
// If world doesn't exist
1198-
if (!getWorldExists(world_path)) {
1199-
// Try to take gamespec from command line
1200-
if (commanded_gamespec.isValid()) {
1201-
gamespec = commanded_gamespec;
1202-
infostream << "Using commanded gameid [" << gamespec.id << "]" << std::endl;
1203-
} else { // Otherwise we will be using "minetest"
1204-
gamespec = findSubgame(g_settings->get("default_game"));
1205-
infostream << "Using default gameid [" << gamespec.id << "]" << std::endl;
1206-
}
1207-
} else { // World exists
1208-
std::string world_gameid = getWorldGameId(world_path, is_legacy_world);
1209-
// If commanded to use a gameid, do so
1210-
if (commanded_gamespec.isValid()) {
1211-
gamespec = commanded_gamespec;
1212-
if (commanded_gamespec.id != world_gameid) {
1213-
errorstream << "WARNING: Using commanded gameid ["
1214-
<< gamespec.id << "]" << " instead of world gameid ["
1215-
<< world_gameid << "]" << std::endl;
1216-
}
1217-
} else {
1218-
// If world contains an embedded game, use it;
1219-
// Otherwise find world from local system.
1220-
gamespec = findWorldSubgame(world_path);
1221-
infostream << "Using world gameid [" << gamespec.id << "]" << std::endl;
1399+
} else { // World exists
1400+
std::string world_gameid = getWorldGameId(game_params->world_path, false);
1401+
// If commanded to use a gameid, do so
1402+
if (game_params->game_spec.isValid()) {
1403+
gamespec = game_params->game_spec;
1404+
if (game_params->game_spec.id != world_gameid) {
1405+
errorstream << "WARNING: Using commanded gameid ["
1406+
<< gamespec.id << "]" << " instead of world gameid ["
1407+
<< world_gameid << "]" << std::endl;
12221408
}
1409+
} else {
1410+
// If world contains an embedded game, use it;
1411+
// Otherwise find world from local system.
1412+
gamespec = findWorldSubgame(game_params->world_path);
1413+
infostream << "Using world gameid [" << gamespec.id << "]" << std::endl;
12231414
}
1224-
if (!gamespec.isValid()) {
1225-
errorstream << "Subgame [" << gamespec.id << "] could not be found."
1226-
<< std::endl;
1227-
return 1;
1228-
}
1229-
verbosestream << _("Using gameid") << " [" << gamespec.id<<"]" << std::endl;
1230-
1231-
// Bind address
1232-
std::string bind_str = g_settings->get("bind_address");
1233-
Address bind_addr(0, 0, 0, 0, port);
1234-
1235-
if (g_settings->getBool("ipv6_server")) {
1236-
bind_addr.setAddress((IPv6AddressBytes*) NULL);
1237-
}
1238-
try {
1239-
bind_addr.Resolve(bind_str.c_str());
1240-
} catch (ResolveError &e) {
1241-
infostream << "Resolving bind address \"" << bind_str
1242-
<< "\" failed: " << e.what()
1243-
<< " -- Listening on all addresses." << std::endl;
1244-
}
1245-
if (bind_addr.isIPv6() && !g_settings->getBool("enable_ipv6")) {
1246-
errorstream << "Unable to listen on "
1247-
<< bind_addr.serializeString()
1248-
<< L" because IPv6 is disabled" << std::endl;
1249-
return 1;
1250-
}
1251-
1252-
// Create server
1253-
Server server(world_path, gamespec, false, bind_addr.isIPv6());
1254-
1255-
// Database migration
1256-
if (cmd_args.exists("migrate")) {
1257-
std::string migrate_to = cmd_args.get("migrate");
1258-
Settings world_mt;
1259-
bool success = world_mt.readConfigFile((world_path + DIR_DELIM
1260-
+ "world.mt").c_str());
1261-
if (!success) {
1262-
errorstream << "Cannot read world.mt" << std::endl;
1263-
return 1;
1264-
}
1265-
if (!world_mt.exists("backend")) {
1266-
errorstream << "Please specify your current backend in world.mt file:"
1267-
<< std::endl << " backend = {sqlite3|leveldb|redis|dummy}" << std::endl;
1268-
return 1;
1269-
}
1270-
std::string backend = world_mt.get("backend");
1271-
Database *new_db;
1272-
if (backend == migrate_to) {
1273-
errorstream << "Cannot migrate: new backend is same"
1274-
<<" as the old one" << std::endl;
1275-
return 1;
1276-
}
1277-
if (migrate_to == "sqlite3")
1278-
new_db = new Database_SQLite3(&(ServerMap&)server.getMap(), world_path);
1279-
#if USE_LEVELDB
1280-
else if (migrate_to == "leveldb")
1281-
new_db = new Database_LevelDB(&(ServerMap&)server.getMap(), world_path);
1282-
#endif
1283-
#if USE_REDIS
1284-
else if (migrate_to == "redis")
1285-
new_db = new Database_Redis(&(ServerMap&)server.getMap(), world_path);
1286-
#endif
1287-
else {
1288-
errorstream << "Migration to " << migrate_to
1289-
<< " is not supported" << std::endl;
1290-
return 1;
1291-
}
1292-
1293-
std::list<v3s16> blocks;
1294-
ServerMap &old_map = ((ServerMap&)server.getMap());
1295-
old_map.listAllLoadableBlocks(blocks);
1296-
int count = 0;
1297-
new_db->beginSave();
1298-
for (std::list<v3s16>::iterator i = blocks.begin(); i != blocks.end(); i++) {
1299-
MapBlock *block = old_map.loadBlock(*i);
1300-
if (!block) {
1301-
errorstream << "Failed to load block " << PP(*i) << ", skipping it.";
1302-
} else {
1303-
old_map.saveBlock(block, new_db);
1304-
MapSector *sector = old_map.getSectorNoGenerate(v2s16(i->X, i->Z));
1305-
sector->deleteBlock(block);
1306-
}
1307-
++count;
1308-
if (count % 500 == 0)
1309-
actionstream << "Migrated " << count << " blocks "
1310-
<< (100.0 * count / blocks.size()) << "% completed" << std::endl;
1311-
}
1312-
new_db->endSave();
1313-
delete new_db;
1314-
1315-
actionstream << "Successfully migrated " << count << " blocks" << std::endl;
1316-
world_mt.set("backend", migrate_to);
1317-
if (!world_mt.updateConfigFile((world_path + DIR_DELIM + "world.mt").c_str()))
1318-
errorstream << "Failed to update world.mt!" << std::endl;
1319-
else
1320-
actionstream << "world.mt updated" << std::endl;
1415+
}
13211416

1322-
return 0;
1323-
}
1417+
if (!gamespec.isValid()) {
1418+
errorstream << "Subgame [" << gamespec.id << "] could not be found."
1419+
<< std::endl;
1420+
return false;
1421+
}
13241422

1325-
server.start(bind_addr);
1423+
game_params->game_spec = gamespec;
1424+
return true;
1425+
}
13261426

1327-
// Run server
1328-
dedicated_server_loop(server, kill);
13291427

1330-
return 0;
1428+
/*****************************************************************************
1429+
* Dedicated server
1430+
*****************************************************************************/
1431+
static bool run_dedicated_server(const GameParams &game_params, const Settings &cmd_args)
1432+
{
1433+
DSTACK("Dedicated server branch");
1434+
1435+
verbosestream << _("Using world path") << " ["
1436+
<< game_params.world_path << "]" << std::endl;
1437+
verbosestream << _("Using gameid") << " ["
1438+
<< game_params.game_spec.id << "]" << std::endl;
1439+
1440+
// Bind address
1441+
std::string bind_str = g_settings->get("bind_address");
1442+
Address bind_addr(0, 0, 0, 0, game_params.socket_port);
1443+
1444+
if (g_settings->getBool("ipv6_server")) {
1445+
bind_addr.setAddress((IPv6AddressBytes*) NULL);
1446+
}
1447+
try {
1448+
bind_addr.Resolve(bind_str.c_str());
1449+
} catch (ResolveError &e) {
1450+
infostream << "Resolving bind address \"" << bind_str
1451+
<< "\" failed: " << e.what()
1452+
<< " -- Listening on all addresses." << std::endl;
1453+
}
1454+
if (bind_addr.isIPv6() && !g_settings->getBool("enable_ipv6")) {
1455+
errorstream << "Unable to listen on "
1456+
<< bind_addr.serializeString()
1457+
<< L" because IPv6 is disabled" << std::endl;
1458+
return false;
13311459
}
13321460

1333-
#ifndef SERVER // Exclude from dedicated server build
1334-
1335-
/*
1336-
More parameters
1337-
*/
1461+
// Create server
1462+
Server server(game_params.world_path,
1463+
game_params.game_spec, false, bind_addr.isIPv6());
13381464

1339-
std::string address = g_settings->get("address");
1340-
if (commanded_world != "")
1341-
address = "";
1342-
else if (cmd_args.exists("address"))
1343-
address = cmd_args.get("address");
1465+
// Database migration
1466+
if (cmd_args.exists("migrate"))
1467+
return migrate_database(game_params, cmd_args, &server);
13441468

1345-
std::string playername = g_settings->get("name");
1346-
if (cmd_args.exists("name"))
1347-
playername = cmd_args.get("name");
1469+
server.start(bind_addr);
13481470

1349-
bool skip_main_menu = cmd_args.getFlag("go");
1471+
// Run server
1472+
bool &kill = *porting::signal_handler_killstatus();
1473+
dedicated_server_loop(server, kill);
13501474

1351-
/*
1352-
Device initialization
1353-
*/
1475+
return true;
1476+
}
13541477

1355-
// Resolution selection
1478+
static bool migrate_database(const GameParams &game_params, const Settings &cmd_args,
1479+
Server *server)
1480+
{
1481+
Settings world_mt;
1482+
bool success = world_mt.readConfigFile((game_params.world_path
1483+
+ DIR_DELIM + "world.mt").c_str());
1484+
if (!success) {
1485+
errorstream << "Cannot read world.mt" << std::endl;
1486+
return false;
1487+
}
13561488

1357-
bool fullscreen = g_settings->getBool("fullscreen");
1358-
u16 screenW = g_settings->getU16("screenW");
1359-
u16 screenH = g_settings->getU16("screenH");
1489+
if (!world_mt.exists("backend")) {
1490+
errorstream << "Please specify your current backend in world.mt file:"
1491+
<< std::endl << " backend = {sqlite3|leveldb|redis|dummy}"
1492+
<< std::endl;
1493+
return false;
1494+
}
13601495

1361-
// bpp, fsaa, vsync
1496+
std::string backend = world_mt.get("backend");
1497+
Database *new_db;
1498+
std::string migrate_to = cmd_args.get("migrate");
13621499

1363-
bool vsync = g_settings->getBool("vsync");
1364-
u16 bits = g_settings->getU16("fullscreen_bpp");
1365-
u16 fsaa = g_settings->getU16("fsaa");
1500+
if (backend == migrate_to) {
1501+
errorstream << "Cannot migrate: new backend is same as the old one"
1502+
<< std::endl;
1503+
return false;
1504+
}
13661505

1367-
// Determine driver
1368-
video::E_DRIVER_TYPE driverType = video::EDT_OPENGL;
1369-
static const char* driverids[] = {
1370-
"null",
1371-
"software",
1372-
"burningsvideo",
1373-
"direct3d8",
1374-
"direct3d9",
1375-
"opengl"
1376-
#ifdef _IRR_COMPILE_WITH_OGLES1_
1377-
,"ogles1"
1506+
if (migrate_to == "sqlite3")
1507+
new_db = new Database_SQLite3(&(ServerMap&)server->getMap(),
1508+
game_params.world_path);
1509+
#if USE_LEVELDB
1510+
else if (migrate_to == "leveldb")
1511+
new_db = new Database_LevelDB(&(ServerMap&)server->getMap(),
1512+
game_params.world_path);
13781513
#endif
1379-
#ifdef _IRR_COMPILE_WITH_OGLES2_
1380-
,"ogles2"
1514+
#if USE_REDIS
1515+
else if (migrate_to == "redis")
1516+
new_db = new Database_Redis(&(ServerMap&)server->getMap(),
1517+
game_params.requested_world_path);
13811518
#endif
1382-
,"invalid"
1383-
};
1519+
else {
1520+
errorstream << "Migration to " << migrate_to << " is not supported"
1521+
<< std::endl;
1522+
return false;
1523+
}
13841524

1385-
std::string driverstring = g_settings->get("video_driver");
1386-
for (unsigned int i = 0;
1387-
i < (sizeof(driverids)/sizeof(driverids[0]));
1388-
i++)
1389-
{
1390-
if (strcasecmp(driverstring.c_str(), driverids[i]) == 0) {
1391-
driverType = (video::E_DRIVER_TYPE) i;
1392-
break;
1525+
std::list<v3s16> blocks;
1526+
ServerMap &old_map = ((ServerMap&)server->getMap());
1527+
old_map.listAllLoadableBlocks(blocks);
1528+
int count = 0;
1529+
new_db->beginSave();
1530+
for (std::list<v3s16>::iterator i = blocks.begin(); i != blocks.end(); i++) {
1531+
MapBlock *block = old_map.loadBlock(*i);
1532+
if (!block) {
1533+
errorstream << "Failed to load block " << PP(*i) << ", skipping it.";
1534+
} else {
1535+
old_map.saveBlock(block, new_db);
1536+
MapSector *sector = old_map.getSectorNoGenerate(v2s16(i->X, i->Z));
1537+
sector->deleteBlock(block);
13931538
}
1539+
++count;
1540+
if (count % 500 == 0)
1541+
actionstream << "Migrated " << count << " blocks "
1542+
<< (100.0 * count / blocks.size()) << "% completed" << std::endl;
1543+
}
1544+
new_db->endSave();
1545+
delete new_db;
1546+
1547+
actionstream << "Successfully migrated " << count << " blocks" << std::endl;
1548+
world_mt.set("backend", migrate_to);
1549+
if (!world_mt.updateConfigFile(
1550+
(game_params.world_path+ DIR_DELIM + "world.mt").c_str()))
1551+
errorstream << "Failed to update world.mt!" << std::endl;
1552+
else
1553+
actionstream << "world.mt updated" << std::endl;
13941554

1395-
if (strcasecmp("invalid", driverids[i]) == 0) {
1396-
errorstream << "WARNING: Invalid video_driver specified; defaulting "
1397-
<< "to opengl" << std::endl;
1398-
break;
1399-
}
1400-
}
1555+
return true;
1556+
}
14011557

1402-
/*
1403-
List video modes if requested
1404-
*/
1405-
MyEventReceiver* receiver = new MyEventReceiver();
14061558

1407-
if (cmd_args.getFlag("videomodes")) {
1408-
IrrlichtDevice *nulldevice;
1559+
/*****************************************************************************
1560+
* Client
1561+
*****************************************************************************/
1562+
#ifndef SERVER
14091563

1410-
SIrrlichtCreationParameters params = SIrrlichtCreationParameters();
1411-
params.DriverType = video::EDT_NULL;
1412-
params.WindowSize = core::dimension2d<u32>(640, 480);
1413-
params.Bits = 24;
1414-
params.AntiAlias = fsaa;
1415-
params.Fullscreen = false;
1416-
params.Stencilbuffer = false;
1417-
params.Vsync = vsync;
1418-
params.EventReceiver = receiver;
1419-
params.HighPrecisionFPU = g_settings->getBool("high_precision_fpu");
1564+
ClientLauncher::~ClientLauncher()
1565+
{
1566+
if (receiver)
1567+
delete receiver;
14201568

1421-
nulldevice = createDeviceEx(params);
1569+
if (input)
1570+
delete input;
14221571

1423-
if (nulldevice == 0)
1424-
return 1;
1572+
if (device)
1573+
device->drop();
14251574

1426-
dstream << _("Available video modes (WxHxD):") << std::endl;
1575+
#if USE_FREETYPE
1576+
if (use_freetype && font != NULL)
1577+
font->drop();
1578+
#endif
1579+
}
14271580

1428-
video::IVideoModeList *videomode_list =
1429-
nulldevice->getVideoModeList();
1581+
bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
1582+
{
1583+
init_args(game_params, cmd_args);
14301584

1431-
if (videomode_list == 0) {
1432-
nulldevice->drop();
1433-
return 1;
1434-
}
1585+
// List video modes if requested
1586+
if (list_video_modes)
1587+
return print_video_modes();
14351588

1436-
s32 videomode_count = videomode_list->getVideoModeCount();
1437-
core::dimension2d<u32> videomode_res;
1438-
s32 videomode_depth;
1439-
for (s32 i = 0; i < videomode_count; ++i) {
1440-
videomode_res = videomode_list->getVideoModeResolution(i);
1441-
videomode_depth = videomode_list->getVideoModeDepth(i);
1442-
dstream<<videomode_res.Width << "x" << videomode_res.Height
1443-
<< "x" << videomode_depth << std::endl;
1444-
}
1589+
if (!init_engine(game_params.log_level)) {
1590+
errorstream << "Could not initialize game engine." << std::endl;
1591+
return false;
1592+
}
14451593

1446-
dstream << _("Active video mode (WxHxD):") << std::endl;
1447-
videomode_res = videomode_list->getDesktopResolution();
1448-
videomode_depth = videomode_list->getDesktopDepth();
1449-
dstream << videomode_res.Width << "x" << videomode_res.Height
1450-
<< "x" << videomode_depth << std::endl;
1594+
late_init_default_settings(g_settings);
14511595

1452-
nulldevice->drop();
1596+
// Speed tests (done after irrlicht is loaded to get timer)
1597+
if (cmd_args.getFlag("speedtests")) {
1598+
dstream << "Running speed tests" << std::endl;
1599+
speed_tests();
1600+
return true;
1601+
}
14531602

1454-
delete receiver;
1455-
return 0;
1603+
if (device->getVideoDriver() == NULL) {
1604+
errorstream << "Could not initialize video driver." << std::endl;
1605+
return false;
14561606
}
14571607

14581608
/*
1459-
Create device and exit if creation failed
1609+
This changes the minimum allowed number of vertices in a VBO.
1610+
Default is 500.
14601611
*/
1461-
SIrrlichtCreationParameters params = SIrrlichtCreationParameters();
1462-
params.DriverType = driverType;
1463-
params.WindowSize = core::dimension2d<u32>(screenW, screenH);
1464-
params.Bits = bits;
1465-
params.AntiAlias = fsaa;
1466-
params.Fullscreen = fullscreen;
1467-
params.Stencilbuffer = false;
1468-
params.Vsync = vsync;
1469-
params.EventReceiver = receiver;
1470-
params.HighPrecisionFPU = g_settings->getBool("high_precision_fpu");
1471-
#ifdef __ANDROID__
1472-
params.PrivateData = porting::app_global;
1473-
params.OGLES2ShaderPath = std::string(porting::path_user + DIR_DELIM +
1474-
"media" + DIR_DELIM + "Shaders" + DIR_DELIM).c_str();
1475-
#endif
1612+
//driver->setMinHardwareBufferVertexCount(50);
14761613

1477-
IrrlichtDevice * device = createDeviceEx(params);
1614+
// Create time getter
1615+
g_timegetter = new IrrlichtTimeGetter(device);
14781616

1479-
if (device == 0) {
1480-
delete receiver;
1481-
return 1; // could not create selected driver.
1482-
}
1483-
1484-
// Map our log level to irrlicht engine one.
1485-
static const irr::ELOG_LEVEL irr_log_level[5] = {
1486-
ELL_NONE,
1487-
ELL_ERROR,
1488-
ELL_WARNING,
1489-
ELL_INFORMATION,
1490-
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
1491-
ELL_INFORMATION
1492-
#else
1493-
ELL_DEBUG
1494-
#endif
1495-
};
1496-
1497-
ILogger* irr_logger = device->getLogger();
1498-
irr_logger->setLogLevel(irr_log_level[loglevel]);
1499-
1500-
porting::initIrrlicht(device);
1501-
late_init_default_settings(g_settings);
1502-
1503-
/*
1504-
Continue initialization
1505-
*/
1506-
1507-
video::IVideoDriver* driver = device->getVideoDriver();
1508-
1509-
/*
1510-
This changes the minimum allowed number of vertices in a VBO.
1511-
Default is 500.
1512-
*/
1513-
//driver->setMinHardwareBufferVertexCount(50);
1514-
1515-
// Create time getter
1516-
g_timegetter = new IrrlichtTimeGetter(device);
1517-
1518-
// Create game callback for menus
1519-
g_gamecallback = new MainGameCallback(device);
1520-
1521-
/*
1522-
Speed tests (done after irrlicht is loaded to get timer)
1523-
*/
1524-
if (cmd_args.getFlag("speedtests"))
1525-
{
1526-
dstream << "Running speed tests" << std::endl;
1527-
SpeedTests();
1528-
device->drop();
1529-
return 0;
1530-
}
1617+
// Create game callback for menus
1618+
g_gamecallback = new MainGameCallback(device);
15311619

15321620
device->setResizable(true);
15331621

1534-
bool random_input = g_settings->getBool("random_input")
1535-
|| cmd_args.getFlag("random-input");
1536-
InputHandler *input = NULL;
1537-
1538-
if (random_input) {
1622+
if (random_input)
15391623
input = new RandomInputHandler();
1540-
} else {
1541-
input = new RealInputHandler(device,receiver);
1542-
}
1624+
else
1625+
input = new RealInputHandler(device, receiver);
15431626

1544-
scene::ISceneManager* smgr = device->getSceneManager();
1627+
smgr = device->getSceneManager();
15451628

15461629
guienv = device->getGUIEnvironment();
1547-
gui::IGUISkin* skin = guienv->getSkin();
1630+
skin = guienv->getSkin();
15481631
std::string font_path = g_settings->get("font_path");
1549-
gui::IGUIFont *font;
1550-
#if USE_FREETYPE
1551-
bool use_freetype = g_settings->getBool("freetype");
1632+
1633+
#if USE_FREETYPE
1634+
15521635
if (use_freetype) {
15531636
std::string fallback;
15541637
if (is_yes(gettext("needs_fallback_font")))
@@ -1557,21 +1640,22 @@ int main(int argc, char *argv[])
15571640
font_path = g_settings->get(fallback + "font_path");
15581641
u32 font_shadow = g_settings->getU16(fallback + "font_shadow");
15591642
u32 font_shadow_alpha = g_settings->getU16(fallback + "font_shadow_alpha");
1560-
font = gui::CGUITTFont::createTTFont(guienv, font_path.c_str(), font_size,
1561-
true, true, font_shadow, font_shadow_alpha);
1643+
font = gui::CGUITTFont::createTTFont(guienv,
1644+
font_path.c_str(), font_size, true, true,
1645+
font_shadow, font_shadow_alpha);
15621646
} else {
15631647
font = guienv->getFont(font_path.c_str());
15641648
}
1565-
#else
1649+
#else
15661650
font = guienv->getFont(font_path.c_str());
1567-
#endif
1651+
#endif
15681652
if (font)
15691653
skin->setFont(font);
15701654
else
1571-
errorstream << "WARNING: Font file was not found."
1572-
<< " Using default font." << std::endl;
1573-
// If font was not found, this will get us one
1574-
font = skin->getFont();
1655+
errorstream << "WARNING: Font file was not found. Using default font."
1656+
<< std::endl;
1657+
1658+
font = skin->getFont(); // If font was not found, this will get us one
15751659
assert(font);
15761660

15771661
u32 text_height = font->getDimension(L"Hello, world!").Height;
@@ -1589,13 +1673,12 @@ int main(int argc, char *argv[])
15891673
skin->setColor(gui::EGDC_FOCUSED_EDITABLE, video::SColor(255, 96, 134, 49));
15901674
#endif
15911675

1592-
15931676
// Create the menu clouds
15941677
if (!g_menucloudsmgr)
15951678
g_menucloudsmgr = smgr->createNewSceneManager();
15961679
if (!g_menuclouds)
15971680
g_menuclouds = new Clouds(g_menucloudsmgr->getRootSceneNode(),
1598-
g_menucloudsmgr, -1, rand(), 100);
1681+
g_menucloudsmgr, -1, rand(), 100);
15991682
g_menuclouds->update(v2f(0, 0), video::SColor(255, 200, 200, 255));
16001683
scene::ICameraSceneNode* camera;
16011684
camera = g_menucloudsmgr->addCameraSceneNode(0,
@@ -1608,260 +1691,74 @@ int main(int argc, char *argv[])
16081691

16091692
ChatBackend chat_backend;
16101693

1611-
/*
1612-
If an error occurs, this is set to something and the
1613-
menu-game loop is restarted. It is then displayed before
1614-
the menu.
1615-
*/
1694+
// If an error occurs, this is set to something by menu().
1695+
// It is then displayed before the menu shows on the next call to menu()
16161696
std::wstring error_message = L"";
16171697

1618-
// The password entered during the menu screen,
1619-
std::string password;
1620-
16211698
bool first_loop = true;
16221699

16231700
/*
16241701
Menu-game loop
16251702
*/
1626-
while (device->run() && (kill == false) &&
1627-
(g_gamecallback->shutdown_requested == false))
1703+
bool retval = true;
1704+
bool *kill = porting::signal_handler_killstatus();
1705+
1706+
while (device->run() && !*kill && !g_gamecallback->shutdown_requested)
16281707
{
16291708
// Set the window caption
1630-
wchar_t* text = wgettext("Main Menu");
1709+
wchar_t *text = wgettext("Main Menu");
16311710
device->setWindowCaption((std::wstring(L"Minetest [") + text + L"]").c_str());
16321711
delete[] text;
16331712

1634-
// This is used for catching disconnects
1635-
try
1636-
{
1713+
try { // This is used for catching disconnects
16371714

1638-
/*
1639-
Clear everything from the GUIEnvironment
1640-
*/
16411715
guienv->clear();
16421716

16431717
/*
16441718
We need some kind of a root node to be able to add
16451719
custom gui elements directly on the screen.
16461720
Otherwise they won't be automatically drawn.
16471721
*/
1648-
guiroot = guienv->addStaticText(L"",
1649-
core::rect<s32>(0, 0, 10000, 10000));
1722+
guiroot = guienv->addStaticText(L"", core::rect<s32>(0, 0, 10000, 10000));
16501723

1651-
SubgameSpec gamespec;
1652-
WorldSpec worldspec;
1653-
bool simple_singleplayer_mode = false;
1724+
bool game_has_run = launch_game(&error_message, game_params, cmd_args);
16541725

1655-
// These are set up based on the menu and other things
1656-
std::string current_playername = "inv£lid";
1657-
std::string current_password = "";
1658-
std::string current_address = "does-not-exist";
1659-
int current_port = 0;
1726+
// If skip_main_menu, we only want to startup once
1727+
if (skip_main_menu && !first_loop)
1728+
break;
16601729

1661-
/*
1662-
Out-of-game menu loop.
1730+
first_loop = false;
16631731

1664-
Loop quits when menu returns proper parameters.
1665-
*/
1666-
while (kill == false) {
1667-
// If skip_main_menu, only go through here once
1668-
if (skip_main_menu && !first_loop) {
1669-
kill = true;
1732+
if (!game_has_run) {
1733+
if (skip_main_menu)
16701734
break;
1671-
}
1672-
first_loop = false;
1673-
1674-
// Cursor can be non-visible when coming from the game
1675-
#ifndef ANDROID
1676-
device->getCursorControl()->setVisible(true);
1677-
#endif
1678-
// Some stuff are left to scene manager when coming from the game
1679-
// (map at least?)
1680-
smgr->clear();
1681-
1682-
// Initialize menu data
1683-
MainMenuData menudata;
1684-
menudata.address = address;
1685-
menudata.name = playername;
1686-
menudata.port = itos(port);
1687-
menudata.errormessage = wide_to_narrow(error_message);
1688-
error_message = L"";
1689-
if (cmd_args.exists("password"))
1690-
menudata.password = cmd_args.get("password");
1691-
1692-
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, g_settings->getBool("mip_map"));
1693-
1694-
menudata.enable_public = g_settings->getBool("server_announce");
1695-
1696-
std::vector<WorldSpec> worldspecs = getAvailableWorlds();
1697-
1698-
// If a world was commanded, append and select it
1699-
if(commanded_world != "") {
1700-
worldspec.gameid = getWorldGameId(commanded_world, true);
1701-
worldspec.name = _("[--world parameter]");
1702-
if(worldspec.gameid == "") {
1703-
worldspec.gameid = g_settings->get("default_game");
1704-
worldspec.name += " [new]";
1705-
}
1706-
worldspec.path = commanded_world;
1707-
}
1708-
1709-
if (skip_main_menu == false) {
1710-
video::IVideoDriver* driver = device->getVideoDriver();
1711-
1712-
infostream << "Waiting for other menus" << std::endl;
1713-
while (device->run() && kill == false) {
1714-
if (noMenuActive())
1715-
break;
1716-
driver->beginScene(true, true,
1717-
video::SColor(255, 128, 128, 128));
1718-
guienv->drawAll();
1719-
driver->endScene();
1720-
// On some computers framerate doesn't seem to be
1721-
// automatically limited
1722-
sleep_ms(25);
1723-
}
1724-
infostream << "Waited for other menus" << std::endl;
1725-
1726-
/* show main menu */
1727-
GUIEngine mymenu(device, guiroot, &g_menumgr,smgr,&menudata,kill);
1728-
1729-
//once finished you'll never end up here
1730-
smgr->clear();
1731-
}
1732-
1733-
if (menudata.errormessage != "") {
1734-
error_message = narrow_to_wide(menudata.errormessage);
1735-
continue;
1736-
}
1737-
1738-
//update worldspecs (necessary as new world may have been created)
1739-
worldspecs = getAvailableWorlds();
1740-
1741-
if (menudata.name == "")
1742-
menudata.name = std::string("Guest") + itos(myrand_range(1000,9999));
17431735
else
1744-
playername = menudata.name;
1745-
1746-
password = translatePassword(playername, narrow_to_wide(menudata.password));
1747-
//infostream<<"Main: password hash: '"<<password<<"'"<<std::endl;
1748-
1749-
address = menudata.address;
1750-
int newport = stoi(menudata.port);
1751-
if (newport != 0)
1752-
port = newport;
1753-
1754-
simple_singleplayer_mode = menudata.simple_singleplayer_mode;
1755-
1756-
// Save settings
1757-
g_settings->set("name", playername);
1758-
1759-
// Break out of menu-game loop to shut down cleanly
1760-
if (device->run() == false || kill == true)
1761-
break;
1762-
1763-
current_playername = playername;
1764-
current_password = password;
1765-
current_address = address;
1766-
current_port = port;
1767-
1768-
// If using simple singleplayer mode, override
1769-
if (simple_singleplayer_mode) {
1770-
current_playername = "singleplayer";
1771-
current_password = "";
1772-
current_address = "";
1773-
current_port = myrand_range(49152, 65535);
1774-
} else if (address != "") {
1775-
ServerListSpec server;
1776-
server["name"] = menudata.servername;
1777-
server["address"] = menudata.address;
1778-
server["port"] = menudata.port;
1779-
server["description"] = menudata.serverdescription;
1780-
ServerList::insert(server);
1781-
}
1782-
1783-
if ((!skip_main_menu) &&
1784-
(menudata.selected_world >= 0) &&
1785-
(menudata.selected_world < (int)worldspecs.size())) {
1786-
g_settings->set("selected_world_path",
1787-
worldspecs[menudata.selected_world].path);
1788-
worldspec = worldspecs[menudata.selected_world];
1789-
1790-
}
1791-
1792-
infostream <<"Selected world: " << worldspec.name
1793-
<< " ["<<worldspec.path<<"]" <<std::endl;
1794-
1795-
1796-
// If local game
1797-
if (current_address == "") {
1798-
if (worldspec.path == "") {
1799-
error_message = wgettext("No world selected and no address "
1800-
"provided. Nothing to do.");
1801-
errorstream << wide_to_narrow(error_message) << std::endl;
1802-
continue;
1803-
}
1804-
1805-
if (!fs::PathExists(worldspec.path)) {
1806-
error_message = wgettext("Provided world path doesn't exist: ")
1807-
+ narrow_to_wide(worldspec.path);
1808-
errorstream << wide_to_narrow(error_message) << std::endl;
1809-
continue;
1810-
}
1811-
1812-
// Load gamespec for required game
1813-
gamespec = findWorldSubgame(worldspec.path);
1814-
if (!gamespec.isValid() && !commanded_gamespec.isValid()) {
1815-
error_message = wgettext("Could not find or load game \"")
1816-
+ narrow_to_wide(worldspec.gameid) + L"\"";
1817-
errorstream << wide_to_narrow(error_message) << std::endl;
1818-
continue;
1819-
}
1820-
if (commanded_gamespec.isValid() &&
1821-
commanded_gamespec.id != worldspec.gameid) {
1822-
errorstream<<"WARNING: Overriding gamespec from \""
1823-
<< worldspec.gameid << "\" to \""
1824-
<< commanded_gamespec.id << "\"" << std::endl;
1825-
gamespec = commanded_gamespec;
1826-
}
1827-
1828-
if (!gamespec.isValid()) {
1829-
error_message = wgettext("Invalid gamespec.");
1830-
error_message += L" (world_gameid="
1831-
+ narrow_to_wide(worldspec.gameid) + L")";
1832-
errorstream << wide_to_narrow(error_message) << std::endl;
1833-
continue;
1834-
}
1835-
}
1836-
1837-
// Continue to game
1838-
break;
1736+
continue;
18391737
}
18401738

18411739
// Break out of menu-game loop to shut down cleanly
1842-
if (device->run() == false || kill == true) {
1843-
if (g_settings_path != "") {
1740+
if (!device->run() || *kill) {
1741+
if (g_settings_path != "")
18441742
g_settings->updateConfigFile(g_settings_path.c_str());
1845-
}
18461743
break;
18471744
}
18481745

18491746
if (current_playername.length() > PLAYERNAME_SIZE-1) {
18501747
error_message = wgettext("Player name too long.");
1851-
playername = current_playername.substr(0,PLAYERNAME_SIZE-1);
1748+
playername = current_playername.substr(0, PLAYERNAME_SIZE-1);
18521749
g_settings->set("name", playername);
18531750
continue;
18541751
}
18551752

1856-
/*
1857-
Run game
1858-
*/
1753+
device->getVideoDriver()->setTextureCreationFlag(
1754+
video::ETCF_CREATE_MIP_MAPS, g_settings->getBool("mip_map"));
1755+
18591756
#ifdef HAVE_TOUCHSCREENGUI
1860-
receiver->m_touchscreengui = new TouchScreenGUI(device, receiver);
1861-
g_touchscreengui = receiver->m_touchscreengui;
1757+
receiver->m_touchscreengui = new TouchScreenGUI(device, receiver);
1758+
g_touchscreengui = receiver->m_touchscreengui;
18621759
#endif
18631760
the_game(
1864-
&kill,
1761+
kill,
18651762
random_input,
18661763
input,
18671764
device,
@@ -1877,21 +1774,21 @@ int main(int argc, char *argv[])
18771774
simple_singleplayer_mode
18781775
);
18791776
smgr->clear();
1777+
18801778
#ifdef HAVE_TOUCHSCREENGUI
1881-
delete g_touchscreengui;
1882-
g_touchscreengui = NULL;
1883-
receiver->m_touchscreengui = NULL;
1779+
delete g_touchscreengui;
1780+
g_touchscreengui = NULL;
1781+
receiver->m_touchscreengui = NULL;
18841782
#endif
18851783

18861784
} //try
1887-
catch(con::PeerNotFoundException &e)
1888-
{
1785+
catch (con::PeerNotFoundException &e) {
18891786
error_message = wgettext("Connection error (timed out?)");
18901787
errorstream << wide_to_narrow(error_message) << std::endl;
18911788
}
1789+
18921790
#ifdef NDEBUG
1893-
catch(std::exception &e)
1894-
{
1791+
catch (std::exception &e) {
18951792
std::string narrow_message = "Some exception: \"";
18961793
narrow_message += e.what();
18971794
narrow_message += "\"";
@@ -1904,60 +1801,457 @@ int main(int argc, char *argv[])
19041801
if (skip_main_menu) {
19051802
if (error_message != L"") {
19061803
verbosestream << "error_message = "
1907-
<< wide_to_narrow(error_message) << std::endl;
1908-
retval = 1;
1804+
<< wide_to_narrow(error_message) << std::endl;
1805+
retval = false;
19091806
}
19101807
break;
19111808
}
19121809
} // Menu-game loop
19131810

1914-
19151811
g_menuclouds->drop();
19161812
g_menucloudsmgr->drop();
19171813

1918-
delete input;
1814+
return retval;
1815+
}
1816+
1817+
void ClientLauncher::init_args(GameParams &game_params, const Settings &cmd_args)
1818+
{
1819+
address = g_settings->get("address");
1820+
if (game_params.world_path != "")
1821+
address = "";
1822+
else if (cmd_args.exists("address"))
1823+
address = cmd_args.get("address");
19191824

1920-
/*
1921-
In the end, delete the Irrlicht device.
1922-
*/
1923-
device->drop();
1825+
playername = g_settings->get("name");
1826+
if (cmd_args.exists("name"))
1827+
playername = cmd_args.get("name");
19241828

1925-
#if USE_FREETYPE
1926-
if (use_freetype)
1927-
font->drop();
1829+
skip_main_menu = cmd_args.getFlag("go");
1830+
1831+
list_video_modes = cmd_args.getFlag("videomodes");
1832+
1833+
use_freetype = g_settings->getBool("freetype");
1834+
1835+
random_input = g_settings->getBool("random_input")
1836+
|| cmd_args.getFlag("random-input");
1837+
}
1838+
1839+
bool ClientLauncher::init_engine(int log_level)
1840+
{
1841+
receiver = new MyEventReceiver();
1842+
create_engine_device(log_level);
1843+
return device != NULL;
1844+
}
1845+
1846+
bool ClientLauncher::launch_game(std::wstring *error_message,
1847+
GameParams &game_params, const Settings &cmd_args)
1848+
{
1849+
// Initialize menu data
1850+
MainMenuData menudata;
1851+
menudata.address = address;
1852+
menudata.name = playername;
1853+
menudata.port = itos(game_params.socket_port);
1854+
menudata.errormessage = wide_to_narrow(*error_message);
1855+
1856+
*error_message = L"";
1857+
1858+
if (cmd_args.exists("password"))
1859+
menudata.password = cmd_args.get("password");
1860+
1861+
menudata.enable_public = g_settings->getBool("server_announce");
1862+
1863+
// If a world was commanded, append and select it
1864+
if (game_params.world_path != "") {
1865+
worldspec.gameid = getWorldGameId(game_params.world_path, true);
1866+
worldspec.name = _("[--world parameter]");
1867+
1868+
if (worldspec.gameid == "") { // Create new
1869+
worldspec.gameid = g_settings->get("default_game");
1870+
worldspec.name += " [new]";
1871+
}
1872+
worldspec.path = game_params.world_path;
1873+
}
1874+
1875+
/* Show the GUI menu
1876+
*/
1877+
if (!skip_main_menu) {
1878+
main_menu(&menudata);
1879+
1880+
address = menudata.address;
1881+
int newport = stoi(menudata.port);
1882+
if (newport != 0)
1883+
game_params.socket_port = newport;
1884+
1885+
simple_singleplayer_mode = menudata.simple_singleplayer_mode;
1886+
1887+
std::vector<WorldSpec> worldspecs = getAvailableWorlds();
1888+
worldspecs = getAvailableWorlds();
1889+
1890+
if (menudata.selected_world >= 0
1891+
&& menudata.selected_world < (int)worldspecs.size()) {
1892+
g_settings->set("selected_world_path",
1893+
worldspecs[menudata.selected_world].path);
1894+
worldspec = worldspecs[menudata.selected_world];
1895+
}
1896+
}
1897+
1898+
if (menudata.errormessage != "") {
1899+
/* The calling function will pass this back into this function upon the
1900+
* next iteration (if any) causing it to be displayed by the GUI
1901+
*/
1902+
*error_message = narrow_to_wide(menudata.errormessage);
1903+
return false;
1904+
}
1905+
1906+
if (menudata.name == "")
1907+
menudata.name = std::string("Guest") + itos(myrand_range(1000, 9999));
1908+
else
1909+
playername = menudata.name;
1910+
1911+
password = translatePassword(playername, narrow_to_wide(menudata.password));
1912+
1913+
g_settings->set("name", playername);
1914+
1915+
current_playername = playername;
1916+
current_password = password;
1917+
current_address = address;
1918+
current_port = game_params.socket_port;
1919+
1920+
// If using simple singleplayer mode, override
1921+
if (simple_singleplayer_mode) {
1922+
assert(skip_main_menu == false);
1923+
current_playername = "singleplayer";
1924+
current_password = "";
1925+
current_address = "";
1926+
current_port = myrand_range(49152, 65535);
1927+
} else if (address != "") {
1928+
ServerListSpec server;
1929+
server["name"] = menudata.servername;
1930+
server["address"] = menudata.address;
1931+
server["port"] = menudata.port;
1932+
server["description"] = menudata.serverdescription;
1933+
ServerList::insert(server);
1934+
}
1935+
1936+
infostream << "Selected world: " << worldspec.name
1937+
<< " [" << worldspec.path << "]" << std::endl;
1938+
1939+
if (current_address == "") { // If local game
1940+
if (worldspec.path == "") {
1941+
*error_message = wgettext("No world selected and no address "
1942+
"provided. Nothing to do.");
1943+
errorstream << wide_to_narrow(*error_message) << std::endl;
1944+
return false;
1945+
}
1946+
1947+
if (!fs::PathExists(worldspec.path)) {
1948+
*error_message = wgettext("Provided world path doesn't exist: ")
1949+
+ narrow_to_wide(worldspec.path);
1950+
errorstream << wide_to_narrow(*error_message) << std::endl;
1951+
return false;
1952+
}
1953+
1954+
// Load gamespec for required game
1955+
gamespec = findWorldSubgame(worldspec.path);
1956+
if (!gamespec.isValid() && !game_params.game_spec.isValid()) {
1957+
*error_message = wgettext("Could not find or load game \"")
1958+
+ narrow_to_wide(worldspec.gameid) + L"\"";
1959+
errorstream << wide_to_narrow(*error_message) << std::endl;
1960+
return false;
1961+
}
1962+
if (game_params.game_spec.isValid() &&
1963+
game_params.game_spec.id != worldspec.gameid) {
1964+
errorstream << "WARNING: Overriding gamespec from \""
1965+
<< worldspec.gameid << "\" to \""
1966+
<< game_params.game_spec.id << "\"" << std::endl;
1967+
gamespec = game_params.game_spec;
1968+
}
1969+
1970+
if (!gamespec.isValid()) {
1971+
*error_message = wgettext("Invalid gamespec.");
1972+
*error_message += L" (world_gameid="
1973+
+ narrow_to_wide(worldspec.gameid) + L")";
1974+
errorstream << wide_to_narrow(*error_message) << std::endl;
1975+
return false;
1976+
}
1977+
}
1978+
1979+
return true;
1980+
}
1981+
1982+
void ClientLauncher::main_menu(MainMenuData *menudata)
1983+
{
1984+
bool *kill = porting::signal_handler_killstatus();
1985+
video::IVideoDriver *driver = device->getVideoDriver();
1986+
1987+
infostream << "Waiting for other menus" << std::endl;
1988+
while (device->run() && *kill == false) {
1989+
if (noMenuActive())
1990+
break;
1991+
driver->beginScene(true, true, video::SColor(255, 128, 128, 128));
1992+
guienv->drawAll();
1993+
driver->endScene();
1994+
// On some computers framerate doesn't seem to be automatically limited
1995+
sleep_ms(25);
1996+
}
1997+
infostream << "Waited for other menus" << std::endl;
1998+
1999+
// Cursor can be non-visible when coming from the game
2000+
#ifndef ANDROID
2001+
device->getCursorControl()->setVisible(true);
2002+
#endif
2003+
2004+
/* show main menu */
2005+
GUIEngine mymenu(device, guiroot, &g_menumgr, smgr, menudata, *kill);
2006+
2007+
smgr->clear(); /* leave scene manager in a clean state */
2008+
}
2009+
2010+
bool ClientLauncher::create_engine_device(int log_level)
2011+
{
2012+
static const char *driverids[] = {
2013+
"null",
2014+
"software",
2015+
"burningsvideo",
2016+
"direct3d8",
2017+
"direct3d9",
2018+
"opengl"
2019+
#ifdef _IRR_COMPILE_WITH_OGLES1_
2020+
,"ogles1"
2021+
#endif
2022+
#ifdef _IRR_COMPILE_WITH_OGLES2_
2023+
,"ogles2"
19282024
#endif
2025+
,"invalid"
2026+
};
2027+
2028+
static const irr::ELOG_LEVEL irr_log_level[5] = {
2029+
ELL_NONE,
2030+
ELL_ERROR,
2031+
ELL_WARNING,
2032+
ELL_INFORMATION,
2033+
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
2034+
ELL_INFORMATION
2035+
#else
2036+
ELL_DEBUG
2037+
#endif
2038+
};
2039+
2040+
// Resolution selection
2041+
bool fullscreen = g_settings->getBool("fullscreen");
2042+
u16 screenW = g_settings->getU16("screenW");
2043+
u16 screenH = g_settings->getU16("screenH");
2044+
2045+
// bpp, fsaa, vsync
2046+
bool vsync = g_settings->getBool("vsync");
2047+
u16 bits = g_settings->getU16("fullscreen_bpp");
2048+
u16 fsaa = g_settings->getU16("fsaa");
2049+
2050+
// Determine driver
2051+
video::E_DRIVER_TYPE driverType = video::EDT_OPENGL;
2052+
2053+
std::string driverstring = g_settings->get("video_driver");
2054+
for (size_t i = 0; i < sizeof driverids / sizeof driverids[0]; i++) {
2055+
if (strcasecmp(driverstring.c_str(), driverids[i]) == 0) {
2056+
driverType = (video::E_DRIVER_TYPE) i;
2057+
break;
2058+
}
2059+
2060+
if (strcasecmp("invalid", driverids[i]) == 0) {
2061+
errorstream << "WARNING: Invalid video_driver specified;"
2062+
<< " defaulting to opengl" << std::endl;
2063+
break;
2064+
}
2065+
}
2066+
2067+
SIrrlichtCreationParameters params = SIrrlichtCreationParameters();
2068+
params.DriverType = driverType;
2069+
params.WindowSize = core::dimension2d<u32>(screenW, screenH);
2070+
params.Bits = bits;
2071+
params.AntiAlias = fsaa;
2072+
params.Fullscreen = fullscreen;
2073+
params.Stencilbuffer = false;
2074+
params.Vsync = vsync;
2075+
params.EventReceiver = receiver;
2076+
params.HighPrecisionFPU = g_settings->getBool("high_precision_fpu");
2077+
#ifdef __ANDROID__
2078+
params.PrivateData = porting::app_global;
2079+
params.OGLES2ShaderPath = std::string(porting::path_user + DIR_DELIM +
2080+
"media" + DIR_DELIM + "Shaders" + DIR_DELIM).c_str();
2081+
#endif
2082+
2083+
device = createDeviceEx(params);
2084+
2085+
if (device) {
2086+
// Map our log level to irrlicht engine one.
2087+
ILogger* irr_logger = device->getLogger();
2088+
irr_logger->setLogLevel(irr_log_level[log_level]);
2089+
2090+
porting::initIrrlicht(device);
2091+
}
2092+
2093+
return device != NULL;
2094+
}
2095+
2096+
// Misc functions
2097+
2098+
static bool print_video_modes()
2099+
{
2100+
IrrlichtDevice *nulldevice;
2101+
2102+
bool vsync = g_settings->getBool("vsync");
2103+
u16 fsaa = g_settings->getU16("fsaa");
2104+
MyEventReceiver* receiver = new MyEventReceiver();
2105+
2106+
SIrrlichtCreationParameters params = SIrrlichtCreationParameters();
2107+
params.DriverType = video::EDT_NULL;
2108+
params.WindowSize = core::dimension2d<u32>(640, 480);
2109+
params.Bits = 24;
2110+
params.AntiAlias = fsaa;
2111+
params.Fullscreen = false;
2112+
params.Stencilbuffer = false;
2113+
params.Vsync = vsync;
2114+
params.EventReceiver = receiver;
2115+
params.HighPrecisionFPU = g_settings->getBool("high_precision_fpu");
2116+
2117+
nulldevice = createDeviceEx(params);
2118+
2119+
if (nulldevice == NULL) {
2120+
delete receiver;
2121+
return false;
2122+
}
2123+
2124+
dstream << _("Available video modes (WxHxD):") << std::endl;
2125+
2126+
video::IVideoModeList *videomode_list = nulldevice->getVideoModeList();
2127+
2128+
if (videomode_list != NULL) {
2129+
s32 videomode_count = videomode_list->getVideoModeCount();
2130+
core::dimension2d<u32> videomode_res;
2131+
s32 videomode_depth;
2132+
for (s32 i = 0; i < videomode_count; ++i) {
2133+
videomode_res = videomode_list->getVideoModeResolution(i);
2134+
videomode_depth = videomode_list->getVideoModeDepth(i);
2135+
dstream << videomode_res.Width << "x" << videomode_res.Height
2136+
<< "x" << videomode_depth << std::endl;
2137+
}
2138+
2139+
dstream << _("Active video mode (WxHxD):") << std::endl;
2140+
videomode_res = videomode_list->getDesktopResolution();
2141+
videomode_depth = videomode_list->getDesktopDepth();
2142+
dstream << videomode_res.Width << "x" << videomode_res.Height
2143+
<< "x" << videomode_depth << std::endl;
2144+
2145+
}
2146+
2147+
nulldevice->drop();
19292148
delete receiver;
2149+
2150+
return videomode_list != NULL;
2151+
}
2152+
19302153
#endif // !SERVER
19312154

1932-
// Update configuration file
1933-
if (g_settings_path != "")
1934-
g_settings->updateConfigFile(g_settings_path.c_str());
2155+
/*****************************************************************************
2156+
* Performance tests
2157+
*****************************************************************************/
2158+
#ifndef SERVER
2159+
static void speed_tests()
2160+
{
2161+
// volatile to avoid some potential compiler optimisations
2162+
volatile static s16 temp16;
2163+
volatile static f32 tempf;
2164+
static v3f tempv3f1;
2165+
static v3f tempv3f2;
2166+
static std::string tempstring;
2167+
static std::string tempstring2;
2168+
2169+
tempv3f1 = v3f();
2170+
tempv3f2 = v3f();
2171+
tempstring = std::string();
2172+
tempstring2 = std::string();
19352173

1936-
// Print modified quicktune values
19372174
{
1938-
bool header_printed = false;
1939-
std::vector<std::string> names = getQuicktuneNames();
1940-
for(u32 i = 0; i < names.size(); i++) {
1941-
QuicktuneValue val = getQuicktuneValue(names[i]);
1942-
if (!val.modified)
1943-
continue;
1944-
if (!header_printed) {
1945-
dstream << "Modified quicktune values:" << std::endl;
1946-
header_printed = true;
2175+
infostream << "The following test should take around 20ms." << std::endl;
2176+
TimeTaker timer("Testing std::string speed");
2177+
const u32 jj = 10000;
2178+
for (u32 j = 0; j < jj; j++) {
2179+
tempstring = "";
2180+
tempstring2 = "";
2181+
const u32 ii = 10;
2182+
for (u32 i = 0; i < ii; i++) {
2183+
tempstring2 += "asd";
2184+
}
2185+
for (u32 i = 0; i < ii+1; i++) {
2186+
tempstring += "asd";
2187+
if (tempstring == tempstring2)
2188+
break;
19472189
}
1948-
dstream<<names[i] << " = " << val.getString() << std::endl;
19492190
}
19502191
}
19512192

1952-
// Stop httpfetch thread (if started)
1953-
httpfetch_cleanup();
2193+
infostream << "All of the following tests should take around 100ms each."
2194+
<< std::endl;
19542195

1955-
END_DEBUG_EXCEPTION_HANDLER(errorstream)
2196+
{
2197+
TimeTaker timer("Testing floating-point conversion speed");
2198+
tempf = 0.001;
2199+
for (u32 i = 0; i < 4000000; i++) {
2200+
temp16 += tempf;
2201+
tempf += 0.001;
2202+
}
2203+
}
19562204

1957-
debugstreams_deinit();
2205+
{
2206+
TimeTaker timer("Testing floating-point vector speed");
19582207

2208+
tempv3f1 = v3f(1, 2, 3);
2209+
tempv3f2 = v3f(4, 5, 6);
2210+
for (u32 i = 0; i < 10000000; i++) {
2211+
tempf += tempv3f1.dotProduct(tempv3f2);
2212+
tempv3f2 += v3f(7, 8, 9);
2213+
}
2214+
}
19592215

1960-
return retval;
1961-
}
2216+
{
2217+
TimeTaker timer("Testing std::map speed");
2218+
2219+
std::map<v2s16, f32> map1;
2220+
tempf = -324;
2221+
const s16 ii = 300;
2222+
for (s16 y = 0; y < ii; y++) {
2223+
for (s16 x = 0; x < ii; x++) {
2224+
map1[v2s16(x, y)] = tempf;
2225+
tempf += 1;
2226+
}
2227+
}
2228+
for (s16 y = ii - 1; y >= 0; y--) {
2229+
for (s16 x = 0; x < ii; x++) {
2230+
tempf = map1[v2s16(x, y)];
2231+
}
2232+
}
2233+
}
19622234

1963-
//END
2235+
{
2236+
infostream << "Around 5000/ms should do well here." << std::endl;
2237+
TimeTaker timer("Testing mutex speed");
2238+
2239+
JMutex m;
2240+
u32 n = 0;
2241+
u32 i = 0;
2242+
do {
2243+
n += 10000;
2244+
for (; i < n; i++) {
2245+
m.Lock();
2246+
m.Unlock();
2247+
}
2248+
}
2249+
// Do at least 10ms
2250+
while(timer.getTimerTime() < 10);
2251+
2252+
u32 dtime = timer.stop();
2253+
u32 per_ms = n / dtime;
2254+
infostream << "Done. " << dtime << "ms, " << per_ms << "/ms" << std::endl;
2255+
}
2256+
}
2257+
#endif

0 commit comments

Comments
 (0)
Please sign in to comment.