taisei/src/main.c
Andrei Alexeyev 3413bd92e7
many vfs improvements
* There's no distinction between "temp" and "perm" nodes anymore.
    All nodes are allocated with 1 reference belonging to the
    vfs_alloc() caller.

    * VFSNode pointers retrieved by any API that returns one (most
    notably vfs_locate) are guaranteed to have exactly one reference
    belonging to the caller. What this means is that you must always
    decref them when you're done using them.

    If you're implementing such an API (e.g. a custom locate), remember
    to incref any persistent nodes you return.

    * Passing a VFSNode* to anything that successfully consumes one (for
    example, vfs_mount) transfers ownership of the reference to the
    consumer. In other words, consumers do not incref your nodes, but
    they will decref them once they don't need them anymore. If you want
    to keep the node around, then you must incref it first.

    * Bunch of other stuff.

"Ownership" is an abstract concept in this context. Basically it just
means "cleanup responsibility".
2017-11-10 21:49:54 +02:00

251 lines
5.2 KiB
C

/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (c) 2011-2017, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2017, Andrei Alexeyev <akari@alienslab.net>.
*/
#include <locale.h>
#include "global.h"
#include "video.h"
#include "audio.h"
#include "stage.h"
#include "menu/mainmenu.h"
#include "gamepad.h"
#include "resource/bgm.h"
#include "progress.h"
#include "hashtable.h"
#include "log.h"
#include "cli.h"
#include "vfs/setup.h"
#include "version.h"
#include "credits.h"
static void taisei_shutdown(void) {
log_info("Shutting down");
config_save();
progress_save();
progress_unload();
free_all_refs();
free_resources(true);
uninit_fonts();
audio_shutdown();
video_shutdown();
gamepad_shutdown();
stage_free_array();
config_shutdown();
vfs_shutdown();
events_shutdown();
time_shutdown();
log_info("Good bye");
SDL_Quit();
log_shutdown();
}
static void init_log(void) {
LogLevel lvls_console = log_parse_levels(LOG_DEFAULT_LEVELS_CONSOLE, getenv("TAISEI_LOGLVLS_CONSOLE"));
LogLevel lvls_stdout = lvls_console & log_parse_levels(LOG_DEFAULT_LEVELS_STDOUT, getenv("TAISEI_LOGLVLS_STDOUT"));
LogLevel lvls_stderr = lvls_console & log_parse_levels(LOG_DEFAULT_LEVELS_STDERR, getenv("TAISEI_LOGLVLS_STDERR"));
LogLevel lvls_backtrace = log_parse_levels(LOG_DEFAULT_LEVELS_BACKTRACE, getenv("TAISEI_LOGLVLS_BACKTRACE"));
log_init(LOG_DEFAULT_LEVELS, lvls_backtrace);
log_add_output(lvls_stdout, SDL_RWFromFP(stdout, false));
log_add_output(lvls_stderr, SDL_RWFromFP(stderr, false));
}
static void init_log_file(void) {
LogLevel lvls_file = log_parse_levels(LOG_DEFAULT_LEVELS_FILE, getenv("TAISEI_LOGLVLS_FILE"));
log_add_output(lvls_file, vfs_open("storage/log.txt", VFS_MODE_WRITE));
}
static int run_tests(void) {
if(tsrand_test()) {
return 1;
}
if(zrwops_test()) {
return 1;
}
if(hashtable_test()) {
return 1;
}
if(color_test()) {
return 1;
}
return 0;
}
static void init_sdl(void) {
SDL_version v;
if(SDL_Init(SDL_INIT_EVENTS) < 0)
log_fatal("SDL_Init() failed: %s", SDL_GetError());
log_info("SDL initialized");
SDL_VERSION(&v);
log_info("Compiled against SDL %u.%u.%u", v.major, v.minor, v.patch);
SDL_GetVersion(&v);
log_info("Using SDL %u.%u.%u", v.major, v.minor, v.patch);
}
static void log_lib_versions(void) {
log_info("Compiled against zlib %s", ZLIB_VERSION);
log_info("Using zlib %s", zlibVersion());
log_info("Compiled against libpng %s", PNG_LIBPNG_VER_STRING);
log_info("Using libpng %s", png_get_header_ver(NULL));
}
int main(int argc, char **argv) {
setlocale(LC_ALL, "C");
Replay replay = {0};
int replay_idx = 0;
init_log();
if(run_tests()) {
return 0;
}
log_info("%s %s", TAISEI_VERSION_FULL, TAISEI_VERSION_BUILD_TYPE);
stage_init_array(); // cli_args depends on this
// commandline arguments should be parsed as early as possible
CLIAction a;
cli_args(argc, argv, &a); // stage_init_array goes first!
if(a.type == CLI_Quit) {
free_cli_action(&a);
return 1;
}
if(a.type == CLI_DumpStages) {
for(StageInfo *stg = stages; stg->procs; ++stg) {
tsfprintf(stdout, "%x %s: %s\n", stg->id, stg->title, stg->subtitle);
}
free_cli_action(&a);
return 0;
} else if(a.type == CLI_PlayReplay) {
if(!replay_load_syspath(&replay, a.filename, REPLAY_READ_ALL)) {
free_cli_action(&a);
return 1;
}
replay_idx = a.stageid ? replay_find_stage_idx(&replay, a.stageid) : 0;
if(replay_idx < 0) {
free_cli_action(&a);
return 1;
}
} else if(a.type == CLI_DumpVFSTree) {
vfs_setup(true);
SDL_RWops *rwops = SDL_RWFromFP(stdout, false);
if(!rwops) {
log_fatal("SDL_RWFromFP() failed: %s", SDL_GetError());
}
if(!vfs_print_tree(rwops, a.filename)) {
log_warn("VFS error: %s", vfs_get_error());
SDL_RWclose(rwops);
free_cli_action(&a);
return 1;
}
SDL_RWclose(rwops);
vfs_shutdown();
free_cli_action(&a);
return 0;
}
free_cli_action(&a);
vfs_setup(false);
init_log_file();
config_load();
log_lib_versions();
init_sdl();
time_init();
init_global(&a);
events_init();
init_fonts();
video_init();
init_resources();
draw_loading_screen();
audio_init();
load_resources();
gamepad_init();
progress_load();
set_transition(TransLoader, 0, FADE_TIME*2);
log_info("Initialization complete");
atexit(taisei_shutdown);
if(a.type == CLI_PlayReplay) {
replay_play(&replay, replay_idx);
replay_destroy(&replay);
return 0;
}
if(a.type == CLI_Credits) {
credits_loop();
return 0;
}
#ifdef DEBUG
log_warn("Compiled with DEBUG flag!");
if(a.type == CLI_SelectStage) {
log_info("Entering stage skip mode: Stage %x", a.stageid);
StageInfo* stg = stage_get(a.stageid);
assert(stg); // properly checked before this
global.diff = stg->difficulty;
if(a.diff) {
global.diff = a.diff;
log_info("Setting difficulty to %s", difficulty_name(global.diff));
} else if(!global.diff) {
global.diff = D_Easy;
}
log_info("Entering %s", stg->title);
do {
global.game_over = 0;
player_init(&global.plr);
if(a.plrmode) {
global.plr.mode = a.plrmode;
}
stage_loop(stg);
} while(global.game_over == GAMEOVER_RESTART);
return 0;
}
#endif
MenuData menu;
create_main_menu(&menu);
menu_loop(&menu);
return 0;
}