diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..30561661 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "third_party/plog"] + path = third_party/plog + url = https://github.com/SergiusTheBest/plog.git diff --git a/CMakeLists.txt b/CMakeLists.txt index ca1a2d9e..8f299597 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,7 @@ option(ENABLE_MEM_RTL "Enable Real-time library memory management functions (dis option(FATAL_GL_ERRORS "Check OpenGL calls and raise exceptions on errors." OFF) option(FORCE_COLORED_OUTPUT "Always produce ANSI-colored compiler warnings/errors (GCC/Clang only; esp. useful with Ninja)." OFF) option(FORCE_PORTABLE_INSTALL "Install all files into local directory defined by CMAKE_INSTALL_PREFIX" ON) +option(USE_EXTERNAL_PLOG "Use system plog library instead bundled" OFF) set(USE_VCPKG "DEFAULT" CACHE STRING "Use vcpkg for dependency management. DEFAULT defers to existence of $VCPKG_ROOT environment variable.") set_property(CACHE USE_VCPKG PROPERTY STRINGS "DEFAULT" "ON" "OFF") @@ -136,7 +137,9 @@ find_package(glm REQUIRED) find_package(SDL2 REQUIRED) # Some versions of the SDL2 find_package set SDL2_INCLUDE_DIR and some set a plural SDL2_INCLUDE_DIRS. Check both. message("SDL2 Include Dir is ${SDL2_INCLUDE_DIR} ${SDL2_INCLUDE_DIRS}") - +if(USE_EXTERNAL_PLOG) + find_package(plog REQUIRED) +endif() if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") message("Building for Linux") diff --git a/Descent3/CMakeLists.txt b/Descent3/CMakeLists.txt index 8e46f6c1..b124cf26 100644 --- a/Descent3/CMakeLists.txt +++ b/Descent3/CMakeLists.txt @@ -315,7 +315,7 @@ file(GLOB_RECURSE INCS "../lib/*.h") add_executable(Descent3 WIN32 MACOSX_BUNDLE ${D3Icon} ${HEADERS} ${CPPS} ${INCS} ${MANIFEST} ${RC_FILE}) target_link_libraries(Descent3 PRIVATE 2dlib AudioEncode bitmap cfile dd_video ddebug ddio libmve libacm - fix grtext manage mem misc model module stream_audio linux SDL2::SDL2 + fix grtext manage mem misc model module stream_audio linux SDL2::SDL2 plog::plog music networking physics renderer rtperformance sndlib ui unzip vecmat md5 ${PLATFORM_LIBS}) target_include_directories(Descent3 PRIVATE ${PROJECT_BINARY_DIR}/lib) diff --git a/Descent3/init.cpp b/Descent3/init.cpp index 41a1a9d0..e41d15ea 100644 --- a/Descent3/init.cpp +++ b/Descent3/init.cpp @@ -1049,12 +1049,7 @@ void PreInitD3Systems() { bool debugging = false; #ifndef RELEASE - debugging = (FindArg("-debug") != 0); - - if (FindArg("-logfile")) - Debug_Logfile("d3.log"); - #endif #ifdef DAJ_DEBUG diff --git a/Descent3/sdlmain.cpp b/Descent3/sdlmain.cpp index 21935c18..a3c5549b 100644 --- a/Descent3/sdlmain.cpp +++ b/Descent3/sdlmain.cpp @@ -32,24 +32,33 @@ #include #endif -#include +#ifdef WIN32 +#include +#include +#endif -#include "program.h" -#include "dedicated_server.h" -#include "descent.h" +#include +// We use direct plog includes instead of log.h for logger instance initialization +#include +#include +#include + +#include "appdatabase.h" #include "ddio.h" #include "application.h" -#include "appdatabase.h" #include "args.h" +#include "d3_version.h" +#include "ddio.h" +#include "descent.h" +#include "dedicated_server.h" #include "init.h" -#include "debug.h" - #include "osiris_dll.h" std::filesystem::path orig_pwd; static volatile char already_tried_signal_cleanup = 0; + void just_exit(void) { ddio_InternalClose(); // try to reset serial port. @@ -75,10 +84,10 @@ void fatal_signal_handler(int signum) { case SIGVTALRM: case SIGINT: if (already_tried_signal_cleanup) - fprintf(stderr, "Recursive signal cleanup! Hard exit! AHHGGGG!\n"); + LOG_WARNING << "Recursive signal cleanup! Hard exit! AHHGGGG!"; else { already_tried_signal_cleanup = 1; - fprintf(stderr, "SIGNAL %d caught, aborting\n", signum); + LOG_WARNING.printf("SIGNAL %d caught, aborting", signum); just_exit(); } // else break; @@ -93,7 +102,7 @@ void fatal_signal_handler(int signum) { void safe_signal_handler(int signum) {} void install_signal_handlers() { - struct sigaction sact, fact; + struct sigaction sact{}, fact{}; memset(&sact, 0, sizeof(sact)); memset(&fact, 0, sizeof(fact)); @@ -215,6 +224,38 @@ int SDLCALL d3SDLEventFilter(void *userdata, SDL_Event *event) { return (1); } +/** + * Initialize logger facility. + * @param log_level desired log level (for example, plog::debug) + * @param enable_filelog enable logging into Descent.log + * @param enable_win_console enable console windows for WIN32 (no-op for POSIX systems) + */ +void InitLog(plog::Severity log_level, bool enable_filelog, bool enable_win_console) { + std::filesystem::path log_file = "Descent3.log"; + static plog::ColorConsoleAppender consoleAppender; + static plog::RollingFileAppender fileAppender(log_file.u8string().c_str()); + +#ifdef WIN32 + if (enable_win_console) { + // Open console window + AllocConsole(); + freopen("CONIN$", "r", stdin); + freopen("CONOUT$", "w", stdout); + freopen("CONOUT$", "w", stderr); + } +#endif + + plog::init(log_level, &consoleAppender); + if (enable_filelog) { + if (std::filesystem::is_regular_file(log_file)) { + // Delete old log + std::error_code ec; + std::filesystem::remove(log_file, ec); + plog::get()->addAppender(&fileAppender); + } + } +} + // --------------------------------------------------------------------------- // Main // creates all the OS objects and then runs Descent 3. @@ -224,15 +265,29 @@ int SDLCALL d3SDLEventFilter(void *userdata, SDL_Event *event) { int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR szCmdLine, int nCmdShow) { strupr(szCmdLine); GatherArgs(szCmdLine); + bool enable_winconsole = FindArg("-winconsole"); #else int main(int argc, char *argv[]) { GatherArgs(argv); + bool enable_winconsole = true; #endif orig_pwd = std::filesystem::current_path(); - setbuf(stdout, NULL); - setbuf(stderr, NULL); + /* Set up the logging system */ +#ifdef RELEASE + plog::Severity log_level = plog::info; +#else + plog::Severity log_level = plog::debug; +#endif + + int loglevel_farg = FindArg("-loglevel"); + if (loglevel_farg) { + log_level = plog::severityFromString(GameArgs[loglevel_farg + 1]); + } + InitLog(log_level, FindArg("-logfile"), enable_winconsole); + + LOG_INFO.printf("Welcome to Descent 3 v%d.%d.%d %s", D3_MAJORVER, D3_MINORVER, D3_BUILD, D3_GIT_HASH); #ifdef DEDICATED setenv("SDL_VIDEODRIVER", "dummy", 1); @@ -240,8 +295,7 @@ int main(int argc, char *argv[]) { int rc = SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO); if (rc != 0) { - fprintf(stderr, "SDL: SDL_Init() failed! rc == (%d).\n", rc); - fprintf(stderr, "SDL_GetError() reports \"%s\".\n", SDL_GetError()); + LOG_FATAL.printf("SDL: SDL_Init() failed: %d: %s!", rc, SDL_GetError()); return (0); } @@ -253,7 +307,7 @@ int main(int argc, char *argv[]) { int fsArg = FindArgChar("-fullscreen", 'f'); if ((fsArg) && (winArg)) { - fprintf(stderr, "ERROR: %s AND %s specified!\n", GameArgs[winArg], GameArgs[fsArg]); + LOG_FATAL.printf("ERROR: %s AND %s specified!", GameArgs[winArg], GameArgs[fsArg]); return (0); } // if @@ -277,11 +331,6 @@ int main(int argc, char *argv[]) { #ifndef DEDICATED // check for a renderer - if ((FindArgChar("-windowed", 'w')) && (FindArgChar("-fullscreen", 'f'))) { - fprintf(stderr, "Error: Both windowed and fullscreen mode requested."); - return 0; - } - if (FindArgChar("-nomousegrab", 'm')) { flags |= APPFLAG_NOMOUSECAPTURE; ddio_MouseSetGrab(false); @@ -293,7 +342,7 @@ int main(int argc, char *argv[]) { } flags |= APPFLAG_WINDOWEDMODE; #else - fprintf(stderr, "Error: \"--dedicated\" or \"-d\" flag required\n"); + LOG_FATAL << "Error: \"--dedicated\" or \"-d\" flag required"; return 0; #endif @@ -313,13 +362,13 @@ int main(int argc, char *argv[]) { run_d3 = false; pid_t np = fork(); if (np == -1) { - fprintf(stderr, "Unable to fork process\n"); + LOG_WARNING << "Unable to fork process"; } if (np == 0) { run_d3 = true; np = setsid(); pid_t pp = getpid(); - printf("Successfully forked process [new sid=%d pid=%d]\n", np, pp); + LOG_INFO.printf("Successfully forked process [new sid=%d pid=%d]", np, pp); } } #endif diff --git a/USAGE.md b/USAGE.md index a7f0dce0..956f03f0 100644 --- a/USAGE.md +++ b/USAGE.md @@ -34,3 +34,18 @@ Descent 3 Message(Error: Couldn't find the string table.) ``` This error means that game data could not be found. Make sure you copied all game files to the `D3-open-source` folder, and that you're running the game from this same folder. + +## Command line options + +Here brief usage of command line options, supported by game. + +| Option | Type | Default | Platform | Description | +|----------------------|---------|-------------------------------------|----------|-------------------------------------------------------------------| +| `-dedicated`, `-d` | boolean | Off | all | Run game in dedicated mode | +| `-fullscreen`, `-f` | boolean | On | all | Run game in fullscreen mode | +| `-logfile` | boolean | Off | all | Enable file logging to Descent3.log | +| `-loglevel ` | string | INFO (on Release), DEBUG (on Debug) | all | Set log level (NONE, VERBOSE, DEBUG, INFO, WARNING, ERROR, FATAL) | +| `-nomousegrab`, `-m` | boolean | Off | all | Disable mouse capture | +| `-service` | boolean | Off | all | Run game in service mode | +| `-winconsole` | boolean | Off | WIN | Enable windows console (off by default) | +| `-windowed`, `-w` | boolean | Off | all | Run game in windowed mode | diff --git a/lib/log.h b/lib/log.h new file mode 100644 index 00000000..53a278f2 --- /dev/null +++ b/lib/log.h @@ -0,0 +1,34 @@ +/* + * Descent 3 + * Copyright (C) 2024 Descent Developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +// This is interface header for chosen logger library. Currently, this is plog. +#include + +/* +In case of swapping to another solution here should be redefined following macros: + +#define LOG_VERBOSE PLOG(plog::verbose) +#define LOG_DEBUG PLOG(plog::debug) +#define LOG_INFO PLOG(plog::info) +#define LOG_WARNING PLOG(plog::warning) +#define LOG_ERROR PLOG(plog::error) +#define LOG_FATAL PLOG(plog::fatal) + +*/ diff --git a/misc/CMakeLists.txt b/misc/CMakeLists.txt index 54b83f02..557f4c4a 100644 --- a/misc/CMakeLists.txt +++ b/misc/CMakeLists.txt @@ -1,12 +1,10 @@ set(HEADERS - logfile.h pserror.h psglob.h psrand.h pstring.h) set(CPPS error.cpp - logfile.cpp psglob.cpp psrand.cpp pstring.cpp diff --git a/misc/logfile.cpp b/misc/logfile.cpp deleted file mode 100644 index fb8a42e7..00000000 --- a/misc/logfile.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* -* Descent 3 -* Copyright (C) 2024 Parallax Software -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -#include -#include - -#include "logfile.h" - -#ifdef _DEBUG -static bool log_enable = true; -#else -static bool log_enable = false; -#endif - -void log_Enable(bool enable) { log_enable = true; } - -void log_Disable() { log_enable = false; } - -logfile::logfile() { fp = NULL; } - -logfile::~logfile() { end(); } - -// restarts the logfile (opens a new one.) -void logfile::start(const char *fname, const char *longname) { - if (log_enable) { - try { - fp = (FILE *)fopen(fname, "wt"); - logfile::printf("%s\n", longname); - } catch (...) { - fp = NULL; - } - } -} - -void logfile::end() { - if (fp) { - try { - fclose((FILE *)fp); - fp = NULL; - } catch (...) { - fp = NULL; - } - } -} - -void logfile::printf(const char *fmt, ...) { - if (fp && fmt) { - char msg[256]; - std::va_list arglist; - va_start(arglist, fmt); - std::vsnprintf(msg, sizeof(msg), fmt, arglist); - va_end(arglist); - - logfile::puts(msg); - } -} - -void logfile::puts(const char *msg) { - if (fp && msg) { - try { - fputs(msg, (FILE *)fp); - } catch (...) { - end(); - } - } -} - -void logfile::update() { - if (fp) { - try { - fflush((FILE *)fp); - } catch (...) { - end(); - } - } -} diff --git a/misc/logfile.h b/misc/logfile.h deleted file mode 100644 index 70cdb9ce..00000000 --- a/misc/logfile.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -* Descent 3 -* Copyright (C) 2024 Parallax Software -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - - -#ifndef LOGFILE_H -#define LOGFILE_H - -void log_Enable(bool enable); -void log_Disable(); - -class logfile { - void *fp; - -public: - logfile(); // simple constructor - ~logfile(); - - void start(const char *fname, const char *longname = 0); // restarts the logfile (opens a new one.) - void end(); - - void printf(const char *fmt, ...); - void puts(const char *msg); - void update(); // call to update logfile on disk (done by OS otherwise) -}; - -#endif diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt index a98e85ab..06be77c1 100644 --- a/third_party/CMakeLists.txt +++ b/third_party/CMakeLists.txt @@ -2,3 +2,9 @@ set(CMAKE_FOLDER "third_party") add_subdirectory(libacm) add_subdirectory(stb) + +if(USE_EXTERNAL_PLOG) + find_package(plog REQUIRED) +else() + add_subdirectory(plog) +endif() diff --git a/third_party/plog b/third_party/plog new file mode 160000 index 00000000..85a871b1 --- /dev/null +++ b/third_party/plog @@ -0,0 +1 @@ +Subproject commit 85a871b13be0bd1a9e0110744fa60cc9bd1e8380