feat: add export / file packing

This commit is contained in:
2026-10-30 15:42:08 +01:00
parent de7e489cc0
commit 0fbc023018
28 changed files with 782 additions and 157 deletions
+3
View File
@@ -28,9 +28,11 @@ set(GAME_SRC
add_executable(lightkeeper ${GAME_SRC})
# Release is what gets exported, players shouldn't get a console next to the game (it logs to a file too)
set_target_properties(lightkeeper PROPERTIES
CXX_STANDARD 20
CXX_EXTENSIONS OFF
WIN32_EXECUTABLE $<CONFIG:Release,MinSizeRel>
)
#target_add_extra_warnings(lightkeeper)
@@ -108,6 +110,7 @@ add_dependencies(lightkeeper _internal_cook_game_assets)
destrum_cook_engine_assets(lightkeeper "${CMAKE_CURRENT_BINARY_DIR}")
destrum_copy_runtime_dlls(lightkeeper)
destrum_add_export(lightkeeper "${ASSETS_RUNTIME_DIR}")
install(TARGETS lightkeeper RUNTIME DESTINATION bin)
install(DIRECTORY "${ASSETS_RUNTIME_DIR}/" DESTINATION "bin/assets/game")
+42 -2
View File
@@ -1,4 +1,5 @@
#include <algorithm>
#include <filesystem>
#include <memory>
#include <span>
#include <stdexcept>
@@ -6,15 +7,52 @@
#include <string_view>
#include <SDL.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/spdlog.h>
#include <destrum/FS/AssetFS.h>
#include <editor/Editor.h>
#include "Lightkeeper.h"
namespace {
// Release builds have no console, so players only have this file to send when something goes wrong
std::filesystem::path addFileLog() {
char* prefPath = SDL_GetPrefPath("Destrum", "Lightkeeper");
if (prefPath == nullptr) {
spdlog::warn("No folder to write the log to: {}", SDL_GetError());
return {};
}
const std::filesystem::path logPath = std::filesystem::path{prefPath} / "lightkeeper.log";
SDL_free(prefPath);
try {
spdlog::default_logger()->sinks().push_back(
std::make_shared<spdlog::sinks::basic_file_sink_mt>(logPath.string(), true));
} catch (const spdlog::spdlog_ex& exception) {
spdlog::warn("Can't write the log to {}: {}", logPath.string(), exception.what());
return {};
}
// Every line, so the log survives a hard crash
spdlog::flush_on(spdlog::level::trace);
return logPath;
}
void showError(const std::string& message, const std::filesystem::path& logPath) {
std::string text = message;
if (!logPath.empty()) {
text += "\n\nThe log is at " + logPath.string();
}
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Lightkeeper", text.c_str(), nullptr);
}
}
int main(int argc, char* argv[]) {
const std::filesystem::path logPath = addFileLog();
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", SDL_GetError(), nullptr);
spdlog::critical("SDL_Init failed: {}", SDL_GetError());
showError(std::string{"Couldn't start SDL: "} + SDL_GetError(), logPath);
return 1;
}
@@ -39,7 +77,8 @@ int main(int argc, char* argv[]) {
.windowTitle = "Lightkeeper",
.exeDir = exeDir,
});
if (!runGameOnly) {
// Exported builds only ship the cooked asset pack, the editor needs the source folders
if (!runGameOnly && !AssetFS::GetInstance().IsPacked()) {
app.attachLayer(std::make_unique<Editor>(app, EditorSettings{
.gameAssetsSource = LIGHTKEEPER_ASSETS_SRC_DIR,
.scenePath = std::string{LightKeeper::MainScenePath},
@@ -49,6 +88,7 @@ int main(int argc, char* argv[]) {
app.cleanup();
} catch (const std::exception& exception) {
spdlog::critical("Lightkeeper terminated with an error: {}", exception.what());
showError(std::string{"Lightkeeper ran into an error and has to close.\n\n"} + exception.what(), logPath);
SDL_Quit();
return 1;
}