#include "servers/CNLoginServer.hpp" #include "servers/CNShardServer.hpp" #include "PlayerManager.hpp" #include "PlayerMovement.hpp" #include "BuiltinCommands.hpp" #include "Buddies.hpp" #include "CustomCommands.hpp" #include "Combat.hpp" #include "Items.hpp" #include "Missions.hpp" #include "Nanos.hpp" #include "NPCManager.hpp" #include "Transport.hpp" #include "Buddies.hpp" #include "db/Database.hpp" #include "TableData.hpp" #include "Groups.hpp" #include "servers/Monitor.hpp" #include "Racing.hpp" #include "Trading.hpp" #include "Email.hpp" #include "Vendors.hpp" #include "Chat.hpp" #include "Eggs.hpp" #include "Rand.hpp" #include "settings.hpp" #include "sandbox/Sandbox.hpp" #include "../version.h" #if defined(__MINGW32__) && !defined(_GLIBCXX_HAS_GTHREADS) #include "mingw/mingw.thread.h" #else #include #endif #include #include #include // HACK #ifdef __has_feature #if __has_feature(address_sanitizer) #define __SANITIZE_ADDRESS__ 1 #endif #endif CNShardServer *shardServer = nullptr; std::thread *shardThread = nullptr; void startShard(CNShardServer* server) { server->start(); } // terminate gracefully on SIGINT (for gprof & DB saving) void terminate(int arg) { std::cout << "OpenFusion: terminating." << std::endl; if (shardServer != nullptr && shardThread != nullptr) shardServer->kill(); Database::close(); exit(0); } #ifdef _WIN32 static BOOL WINAPI winTerminate(DWORD arg) { terminate(0); return FALSE; } #endif void initsignals() { #ifdef _WIN32 if (!SetConsoleCtrlHandler(winTerminate, TRUE)) { std::cerr << "[FATAL] Failed to set control handler" << std::endl; exit(1); } #else struct sigaction act; memset((void*)&act, 0, sizeof(act)); sigemptyset(&act.sa_mask); // tell the OS to not kill us if you use a broken pipe, just let us know thru recv() or send() act.sa_handler = SIG_IGN; if (sigaction(SIGPIPE, &act, NULL) < 0) { perror("sigaction"); exit(1); } act.sa_handler = terminate; if (sigaction(SIGINT, &act, NULL) < 0) { perror("sigaction"); exit(1); } #endif } int main() { std::cout << "[INFO] OpenFusion v" GIT_VERSION << std::endl; std::cout << "[INFO] Protocol version: " << PROTOCOL_VERSION << std::endl; #ifdef _WIN32 WSADATA wsaData; if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) { std::cerr << "OpenFusion: WSAStartup failed" << std::endl; exit(EXIT_FAILURE); } #endif initsignals(); settings::init(); Database::init(); Rand::init(getTime()); TableData::init(); std::cout << "[INFO] Intializing Packet Managers..." << std::endl; PlayerManager::init(); PlayerMovement::init(); BuiltinCommands::init(); Buddies::init(); CustomCommands::init(); Combat::init(); Chat::init(); Items::init(); Eggs::init(); Missions::init(); Nanos::init(); NPCManager::init(); Vendors::init(); Transport::init(); Buddies::init(); Email::init(); Groups::init(); Racing::init(); Trading::init(); Database::open(); switch (settings::EVENTMODE) { case 0: break; // no event case 1: std::cout << "[INFO] Event active. Hey, Hey It's Knishmas!" << std::endl; break; case 2: std::cout << "[INFO] Event active. Wishing you a spook-tacular Halloween!" << std::endl; break; case 3: std::cout << "[INFO] Event active. Have a very hoppy Easter!" << std::endl; break; default: std::cout << "[FATAL] Unknown event set in config file." << std::endl; exit(1); /* not reached */ } std::cout << "[INFO] Starting Server Threads..." << std::endl; CNLoginServer loginServer(settings::LOGINPORT); shardServer = new CNShardServer(settings::SHARDPORT); shardThread = new std::thread(startShard, (CNShardServer*)shardServer); sandbox_start(); loginServer.start(); shardServer->kill(); shardThread->join(); #ifdef _WIN32 WSACleanup(); #endif return 0; } // helper functions std::string U16toU8(char16_t* src, size_t max) { src[max-1] = '\0'; // force a NULL terminator try { std::wstring_convert,char16_t> convert; std::string ret = convert.to_bytes(src); if (ret.size() >= max) ret.resize(max-2); return ret; } catch(const std::exception& e) { return ""; } } // returns number of char16_t that was written at des size_t U8toU16(std::string src, char16_t* des, size_t max) { std::wstring_convert,char16_t> convert; std::u16string tmp = convert.from_bytes(src); // copy utf16 string to buffer if (sizeof(char16_t) * tmp.length() > max) // make sure we don't write outside the buffer memcpy(des, tmp.c_str(), sizeof(char16_t) * max); else memcpy(des, tmp.c_str(), sizeof(char16_t) * tmp.length()); des[tmp.length()] = '\0'; return tmp.length(); } time_t getTime() { using namespace std::chrono; milliseconds value = duration_cast((time_point_cast(steady_clock::now())).time_since_epoch()); return (time_t)value.count(); } // returns system time in seconds time_t getTimestamp() { using namespace std::chrono; seconds value = duration_cast((time_point_cast(system_clock::now())).time_since_epoch()); return (time_t)value.count(); } // convert integer timestamp (in s) to FF systime struct sSYSTEMTIME timeStampToStruct(uint64_t time) { const time_t timeProper = time; tm ts = *localtime(&timeProper); sSYSTEMTIME systime; systime.wMilliseconds = 0; systime.wSecond = ts.tm_sec; systime.wMinute = ts.tm_min; systime.wHour = ts.tm_hour; systime.wDay = ts.tm_mday; systime.wDayOfWeek = ts.tm_wday + 1; systime.wMonth = ts.tm_mon + 1; systime.wYear = ts.tm_year + 1900; return systime; }