#include #include #include #include #include #include #include #include #include #include #include #include "DediRunner.h" #include #ifdef _WIN32 #include #pragma comment(lib, "Comctl32.lib") #elif defined(__linux__) #include #endif namespace { constexpr char kLogFileName[] = "STServerOut.log"; // Its fine for us if several potential server instances read this, since its a tilted platform thing // and therefore not considered game specific. constexpr char kEULAName[] = "EULA.txt"; constexpr char kEULAText[] = ";Please indicate your agreement to the Tilted platform service agreement\n" ";by setting bConfirmEULA to true\n" "[EULA]\n"; constexpr char kEULATextFalse[] = "bConfirmEULA=false"; constexpr char kEULATextTrue[] = "bConfirmEULA=true"; namespace fs = std::filesystem; Console::StringSetting sLogLevel{"sLogLevel", "Log level to print", "info"}; using namespace std::chrono_literals; } // namespace extern Console::Setting bConsole; GS_IMPORT void SetDefaultLogger(std::shared_ptr aLogger); GS_IMPORT void RegisterLogger(std::shared_ptr aLogger); struct LogInstance { static constexpr size_t kLogFileSizeCap = 1048576 * 5; LogInstance() { using namespace spdlog; std::error_code ec; fs::create_directory("logs", ec); auto consoleOut = spdlog::stdout_color_mt(KCompilerStopThisBullshit); consoleOut->set_pattern(">%$ %v"); // make the client aware of this logger. RegisterLogger(consoleOut); auto fileOut = std::make_shared(std::string("logs/") + kLogFileName, kLogFileSizeCap, 3); auto serverOut = std::make_shared(); serverOut->set_pattern("%^[%H:%M:%S.%e] [%l] [tid %t] %$ %v"); auto globalOut = std::make_shared("", sinks_init_list{serverOut, fileOut}); globalOut->set_level(level::from_str(sLogLevel.value())); // as the library is compiled into the client + server we have to do this twice spdlog::set_default_logger(globalOut); // also make the client aware of the file loggers SetDefaultLogger(globalOut); } ~LogInstance() { spdlog::shutdown(); } }; static bool RegisterQuitHandler() { #if defined(_WIN32) static auto CtrlHandler = ([](DWORD aType) { switch (aType) { case CTRL_C_EVENT: case CTRL_CLOSE_EVENT: case CTRL_BREAK_EVENT: case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: { if (auto* pRunner = GetDediRunner()) { pRunner->RequestKill(); return TRUE; } // if the user kills during the ctor we deny the request // to save our dear life. return FALSE; } default: return FALSE; } }); return SetConsoleCtrlHandler(CtrlHandler, TRUE); #elif defined(__linux__) static auto CtrlHandler = ([](int aSig) { if (auto* pRunner = GetDediRunner()) { pRunner->RequestKill(); } }); signal(SIGINT, CtrlHandler); signal(SIGTERM, CtrlHandler); signal(SIGKILL, CtrlHandler); #else return true; #endif } #ifdef _WIN32 static bool ShowEULADialog() { Base::TaskDialog dia(LoadIconW(GetModuleHandleW(nullptr), MAKEINTRESOURCEW(102)), L"Tilted Platform Agreement", L"Confirm the Tilted Platform EULA", L"TODO: Link to EULA", nullptr); dia.AppendButton(100, L"Accept EULA"); dia.AppendButton(101, L"Deny EULA"); dia.SetDefaultButton(101 /*So they have to think about it*/); return dia.Show() == 100; } #endif // The eula can be accepted in 3 ways: // - Either confirm the dialog on startup(windows only) // - Or signal agreement using an environment variable // - Or Simply set bConfirmEULA in EULA.txt to true static bool IsEULAAccepted() { const auto path = fs::current_path() / kConfigPathName / kEULAName; bool preAccept = false; if (char* pValue = std::getenv("TILTED_ACCEPT_EULA")) { std::string_view env(pValue); preAccept = env == "true" || env == "1" || env == "TRUE"; } auto saveFile = [&]() { #ifdef _WIN32 // try using the dialog if (!preAccept) preAccept = ShowEULADialog(); #endif fs::create_directory(fs::current_path() / kConfigPathName); TiltedPhoques::String eulaText = kEULAText; eulaText += preAccept ? kEULATextTrue : kEULATextFalse; TiltedPhoques::SaveFile(path, eulaText); return preAccept; }; if (!exists(path)) { return saveFile(); } const auto data = TiltedPhoques::LoadFile(path); CSimpleIni si; if (si.LoadData(data.c_str()) != SI_OK) return preAccept; if (!si.GetBoolValue("EULA", "bConfirmEULA", false)) { #ifdef _WIN32 preAccept = false; return saveFile(); #else return false; #endif } return true; } GS_IMPORT bool CheckBuildTag(const char* apBuildTag); void ConfigureConsoleMode() { #ifdef _WIN32 SetConsoleOutputCP(CP_UTF8); // Set the input code page to UTF-8 SetConsoleCP(CP_UTF8); #endif } int main(int argc, char** argv) { ConfigureConsoleMode(); // the binaries are not from the same commit. if (!CheckBuildTag(kBuildTag)) return 1; Base::SetCurrentThreadName("ServerRunnerMain"); LogInstance logger; (void)logger; // Disabled EULA check since we have no EULA contents yet /* if (!IsEULAAccepted()) { spdlog::error("Please accept the EULA by setting bConfirmEULA to true in EULA.txt"); return 2; } */ //ScopedCrashHandler _(true, true); // Note(Vince): This started crashing on 1.7+ lets disable it for now. // RegisterQuitHandler(); // Keep stack free. const auto cpRunner{std::make_unique(argc, argv)}; if (bConsole) { cpRunner->StartTerminalIO(); } cpRunner->RunGSThread(); return 0; }