buildat/src/server/main.cpp

199 lines
4.8 KiB
C++

// http://www.apache.org/licenses/LICENSE-2.0
// Copyright 2014 Perttu Ahola <celeron55@gmail.com>
#include "core/types.h"
#include "core/log.h"
#include "core/config.h"
#include "boot/basic_init.h"
#include "boot/autodetect.h"
#include "server/config.h"
#include "server/state.h"
#include "interface/server.h"
#include "interface/debug.h"
#include "interface/mutex.h"
#include "interface/os.h"
#include <c55/getopt.h>
#include <c55/os.h>
#include <iostream>
#include <climits>
#include <cstdlib> // srand()
#include <signal.h>
#include <string.h> // strerror()
#include <time.h> // struct timeval
#define MODULE "main"
server::Config g_server_config;
bool g_sigint_received = false;
interface::Mutex g_sigint_received_mutex;
void sigint_handler(int sig)
{
interface::MutexScope ms(g_sigint_received_mutex);
if(!g_sigint_received){
fprintf(stdout, "\n"); // Newline after "^C"
log_i("process", "SIGINT");
g_sigint_received = true;
} else {
(void)signal(SIGINT, SIG_DFL);
}
}
void signal_handler_init()
{
(void)signal(SIGINT, sigint_handler);
#ifndef _WIN32
(void)signal(SIGPIPE, SIG_IGN);
#endif
}
int main(int argc, char *argv[])
{
boot::BasicInitScope basic_init_scope;
server::Config &config = g_server_config;
std::string module_path;
const char opts[100] = "hm:r:i:S:U:c:l:L:C:";
const char usagefmt[1000] =
"Usage: %s [OPTION]...\n"
" -h Show this help\n"
" -m [module_path] Specify module path\n"
" -r [rccpp_build_path]Specify runtime compiled C++ build path\n"
" -i [interface_path] Specify path to interface headers\n"
" -S [share_path] Specify path to share/\n"
" -U [urho3d_path] Specify Urho3D path\n"
" -c [command] Set compiler command\n"
" -l [integer] Set maximum log level (0...5)\n"
" -L [log file path] Append log to a specified file\n"
" -C [module_name] Skip compiling specified module\n"
;
int c;
while((c = c55_getopt(argc, argv, opts)) != -1)
{
switch(c)
{
case 'h':
printf(usagefmt, argv[0]);
return 1;
case 'm':
log_i(MODULE, "module_path: %s", c55_optarg);
module_path = c55_optarg;
break;
case 'r':
log_i(MODULE, "config.rccpp_build_path: %s", c55_optarg);
config.set("rccpp_build_path", c55_optarg);
break;
case 'i':
log_i(MODULE, "config.interface_path: %s", c55_optarg);
config.set("interface_path", c55_optarg);
break;
case 'S':
log_i(MODULE, "config.share_path: %s", c55_optarg);
config.set("share_path", c55_optarg);
break;
case 'U':
log_i(MODULE, "config.urho3d_path: %s", c55_optarg);
config.set("urho3d_path", c55_optarg);
break;
case 'c':
log_i(MODULE, "config.compiler_command: %s", c55_optarg);
config.set("compiler_command", c55_optarg);
break;
case 'l':
log_set_max_level(atoi(c55_optarg));
break;
case 'L':
log_set_file(c55_optarg);
break;
case 'C':
log_i(MODULE, "config.skip_compiling_modules += %s",
c55_optarg);
{
auto v = config.get<json::Value>("skip_compiling_modules");
v.set(c55_optarg, json::Value(true));
config.set("skip_compiling_modules", v);
}
break;
default:
fprintf(stderr, "ERROR: Invalid command-line argument\n");
fprintf(stderr, usagefmt, argv[0]);
return 1;
}
}
std::cerr<<"Buildat server"<<std::endl;
if(!boot::autodetect::detect_server_paths(config))
return 1;
if(!config.check_paths()){
return 1;
}
if(module_path.empty()){
std::cerr<<"Module path (-m) is empty"<<std::endl;
return 1;
}
int exit_status = 0;
ss_ shutdown_reason;
try {
up_<server::State> state(server::createState());
state->load_modules(module_path);
// Main loop
uint64_t next_tick_us = get_timeofday_us();
uint64_t t_per_tick = 1000000 / 30; // Same as physics FPS
for(;;){
{
interface::MutexScope ms(g_sigint_received_mutex);
if(g_sigint_received)
break;
}
uint64_t current_us = get_timeofday_us();
int64_t delay_us = next_tick_us - current_us;
if(delay_us < 0)
delay_us = 0;
usleep(delay_us);
state->handle_events();
if(current_us >= next_tick_us){
next_tick_us += t_per_tick;
if(next_tick_us < current_us - 1000 * 1000){
log_w("main", "Skipping %zuus", current_us - next_tick_us);
next_tick_us = current_us;
}
interface::Event event("core:tick",
new interface::TickEvent(t_per_tick / 1e6));
state->emit_event(std::move(event));
}
if(state->is_shutdown_requested(&exit_status, &shutdown_reason))
break;
}
state->thread_request_stop();
state->thread_join();
} catch(server::ServerShutdownRequest &e){
log_v(MODULE, "ServerShutdownRequest: %s", e.what());
}
if(shutdown_reason != ""){
if(exit_status != 0)
log_w(MODULE, "Shutdown: %s", cs(shutdown_reason));
else
log_v(MODULE, "Shutdown: %s", cs(shutdown_reason));
}
return exit_status;
}
// vim: set noet ts=4 sw=4: