#include #include #include #include #include #include #include #ifndef _WINDOWS # include # 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(); } } class DuplicatingStreamBuf : public std::stringbuf { private: std::ostream& console; std::ostream& file; bool hasFile = 0; Critical cs; int infoLength; int getCursorColumn() { #ifdef _WINDOWS CONSOLE_SCREEN_BUFFER_INFO csbi; int columns, rows; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); return csbi.dwCursorPosition.X; #else int x = getcurx(curscr); return x; #endif } 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; } int column = getCursorColumn(); if (infoLength > 0) { console << /* move cursor a line up*/ "\033[1A" << /* clear the line */ "\x1b[2K" << /* return to beginning of line */ "\r"; } if (str().length() > 0) { console << str(); if (str().c_str()[str().length() - 1] != '\n') { console << "\n"; } } if (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() << /* move cursor a line down */ "\033[1B" // << /* move cursor to beginning of line */ "\r" << /* set cursor position back */ "\033[" << column + 1 << "G"; infoLength = infoLine.getLength(); console << infoLine << std::flush; } if (hasFile) file << str() << std::flush; str(""); cs.unlock(); return 0; } }; int main() { Framework::initFramework(); initializeBlockTypes(); initializeItemTypes(); initializeEntityTypes(); initializeDimensions(); initializeMultiblockTypes(); #ifndef _WINDOWS initscr(); 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 << "\033[1A" << "\x1b[2K" << "\r" << line << 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(); mserver->release(); mserver = 0; if (Game::INSTANCE) { Game::INSTANCE->warteAufThread(100000000); Game::INSTANCE->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; }