199 lines
4.8 KiB
C++
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:
|