#include #include #include #include #include #include #include #ifndef _WINDOWS # include #endif #include #include #include #include "ChunkMap.h" #include "Server.h" FactoryCraftServer* mserver = 0; void exit() { if (mserver) { std::cout << "The server terminated unexpectedly. Trying to save game " "progress.\n"; mserver->close(); } } bool exited = false; class DuplicatingStreamBuf : public std::stringbuf { private: std::ostream& console; std::ostream& file; bool hasFile = 0; Critical cs; int infoLength; public: DuplicatingStreamBuf(std::ostream& console, std::ostream& file) : std::stringbuf(), console(console), file(file), hasFile(1), infoLength(0) {} DuplicatingStreamBuf(std::ostream& console) : std::stringbuf(), console(console), file(console), hasFile(0), infoLength(0) {} int sync() override { cs.lock(); if (str().length() == 0 && !Game::INSTANCE) { cs.unlock(); return 0; } if (infoLength > 0) { console << /* store cursor position */ "\033[s" << /* move cursor a line up*/ "\033[1A" << /* clear the line */ "\x1b[2K" << /* return to beginning of line */ "\r"; } int newLines = Text(str().c_str()).anzahlVon('\n'); if (str().length() > 0) { console << str(); if (str().c_str()[str().length() - 1] != '\n') { console << "\n"; newLines++; } } if (!exited && Game::INSTANCE) { int tps = Game::INSTANCE->getTicksPerSecond(); Framework::Text infoLine = ""; infoLine.append() << "Players: " << Game::INSTANCE->getPlayerCount() << "\tChunks: " << Game::INSTANCE->getChunkCount() << "\ttps: "; if (tps < 15) { // red infoLine += "\033[1;31m"; } else if (tps < 20) { // yellow infoLine += "\033[1;33m"; } else { // green infoLine += "\033[1;32m"; } infoLine.append() << tps << /* reset color */ "\033[0m" << "\tAverage Tick Time: " << Game::INSTANCE->getAverageTickTime() << "\n"; if (infoLength > 0) { infoLine.append() << /* restore cursor position */ "\033[u" << /* set cursor down by amount of new lines */ (newLines > 0 ? (Text("\033[") + newLines + "B").getText() : ""); // << "\x1b[0K"; } infoLength = infoLine.getLength(); console << infoLine << std::flush; } else { infoLength = 0; } if (hasFile) file << str() << std::flush; str(""); cs.unlock(); return 0; } }; int main() { Framework::initFramework(); initializeBlockTypes(); initializeItemTypes(); initializeEntityTypes(); initializeDimensions(); initializeMultiblockTypes(); #ifndef _WINDOWS struct rlimit core_limits; core_limits.rlim_cur = core_limits.rlim_max = RLIM_INFINITY; setrlimit(RLIMIT_CORE, &core_limits); #endif Zeit* z = getZeit(); Text* pfad = new Text("log/"); pfad->append(z->getZeit("y-m-d_h-i-s.log")); z->release(); DateiPfadErstellen(pfad->getText()); std::ofstream file; std::streambuf* sbuf = std::cout.rdbuf(); #ifndef _DEBUG file.open(pfad->getText()); std::ostream newCout(sbuf); DuplicatingStreamBuf duplicator(newCout, file); std::cout.rdbuf(&duplicator); #else std::ostream newCout(sbuf); DuplicatingStreamBuf duplicator(newCout); std::cout.rdbuf(&duplicator); #endif pfad->release(); std::cout << "Starting...\n"; std::cout << "Loading config file fcInit.ini ...\n"; InitDatei* dat = new InitDatei("fcInit.ini"); if (!dat->laden()) { std::cout << "error: Datei konnte nicht gelesen werden. Das Programm " "wird geschlossen.\n"; dat->release(); #ifndef _DEBUG file.close(); #endif std::cout.rdbuf(sbuf); exit(1); } const char* wichtig[] = {"SSLPort", "SSLCert", "SSLKey", "SSLPasswort", "Port"}; for (const char* w : wichtig) { if (!dat->wertExistiert(w)) { std::cout << "error: The value '" << w << "' was not specified. The Server can not start.\n"; dat->release(); file.close(); std::cout.rdbuf(sbuf); exit(1); } } mserver = new FactoryCraftServer(dat); std::atexit(exit); signal(SIGTERM, exit); signal(SIGSEGV, exit); signal(SIGILL, exit); signal(SIGABRT, exit); signal(SIGFPE, exit); signal(SIGINT, exit); new Framework::AsynchronCall("Commander", []() { while (mserver) { std::string line; std::getline(std::cin, line); if (!mserver) return; std::cout << std::flush << "\033[1A" << "\x1b[2K" << "\x1b[0G" << line << "\n\033[1A\033[s" << std::flush; if (Text(line.c_str()) == Text("exit")) { std::cout << "The server will be terminated and the game " "progress will be saved.\n"; mserver->close(); return; } else if (Game::INSTANCE) { Game::INSTANCE->zChat()->zCommandExecutor()->execute( line.c_str(), 0); } } }); std::cout << "The Server is now running.\n"; mserver->run(); exited = 1; mserver->release(); mserver = 0; if (Game::INSTANCE) { Game* tmp = Game::INSTANCE; tmp->requestStop(); tmp->warteAufThread(100000000); tmp->release(); Game::INSTANCE = 0; } dat->release(); std::cout << "The server was shut down successfully.\n" << std::flush; #ifndef _DEBUG file.close(); #endif std::cout.rdbuf(sbuf); Framework::releaseFramework(); return 0; }