1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
// SPDX-License-Identifier: BSD-2-Clause
// Copyright (c) 2025 Kirill Dmitrievich
// File: game.cc
// Description: Shared initialization logic
#include "shared/pch.hh"
#include "shared/game.hh"
#include "core/io/cmdline.hh"
#include "core/io/physfs.hh"
static std::filesystem::path get_gamepath(void)
{
if(auto gamepath = cmdline::get_cstr("gamepath")) {
// Allow users and third-party launchers to override
// content location. Perhaps this would work to allow
// for a Minecraft-like versioning approach?
return std::filesystem::path(gamepath);
}
return std::filesystem::current_path() / "assets";
}
static std::filesystem::path get_userpath(void)
{
if(auto userpath = cmdline::get_cstr("userpath")) {
// Allow users and third-party launchers to override
// user data location. Perhaps this would work to allow
// for a Minecraft-like versioning approach?
return std::filesystem::path(userpath);
}
if(auto win_appdata = std::getenv("APPDATA")) {
// On pre-seven Windows systems it's just AppData
// On post-seven Windows systems it's AppData/Roaming
return std::filesystem::path(win_appdata) / "voxelius";
}
if(auto xdg_home = std::getenv("XDG_DATA_HOME")) {
// Systems with an active X11/Wayland session
// theoretically should have this defined, and
// it can be different from ${HOME} (I think).
return std::filesystem::path(xdg_home) / ".voxelius";
}
if(auto unix_home = std::getenv("HOME")) {
// Any spherical UNIX/UNIX-like system in vacuum
// has this defined for every single user process.
return std::filesystem::path(unix_home) / ".voxelius";
}
// Give up and save stuff into CWD
return std::filesystem::current_path();
}
void shared_game::init(int argc, char** argv, std::string_view logfile)
{
auto logger = spdlog::default_logger();
auto& logger_sinks = logger->sinks();
logger_sinks.clear();
logger_sinks.push_back(std::make_shared<spdlog::sinks::stderr_color_sink_mt>());
if(logfile.size()) {
logger_sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>(std::string(logfile), false));
}
#if defined(NDEBUG)
constexpr auto default_loglevel = spdlog::level::info;
#else
constexpr auto default_loglevel = spdlog::level::trace;
#endif
if(cmdline::contains("quiet")) {
logger->set_level(spdlog::level::warn);
}
else if(cmdline::contains("verbose")) {
logger->set_level(spdlog::level::trace);
}
else {
logger->set_level(default_loglevel);
}
logger->set_pattern("%H:%M:%S.%e %^[%L]%$ %v");
logger->flush();
if(!PHYSFS_init(argv[0])) {
spdlog::critical("physfs: init failed: {}", physfs::last_error());
std::terminate();
}
auto gamepath = get_gamepath();
auto userpath = get_userpath();
spdlog::info("shared_game: set gamepath to {}", gamepath.string());
spdlog::info("shared_game: set userpath to {}", userpath.string());
std::error_code ignore_error = {};
std::filesystem::create_directories(gamepath, ignore_error);
std::filesystem::create_directories(userpath, ignore_error);
if(!PHYSFS_mount(gamepath.string().c_str(), nullptr, false)) {
spdlog::critical("physfs: mount {} failed: {}", gamepath.string(), physfs::last_error());
std::terminate();
}
if(!PHYSFS_mount(userpath.string().c_str(), nullptr, false)) {
spdlog::critical("physfs: mount {} failed: {}", userpath.string(), physfs::last_error());
std::terminate();
}
if(!PHYSFS_setWriteDir(userpath.string().c_str())) {
spdlog::critical("physfs: setwritedir {} failed: {}", userpath.string(), physfs::last_error());
std::terminate();
}
if(enet_initialize()) {
spdlog::critical("enet: init failed");
std::terminate();
}
}
void shared_game::shutdown(void)
{
enet_deinitialize();
if(!PHYSFS_deinit()) {
spdlog::critical("physfs: deinit failed: {}", physfs::last_error());
std::terminate();
}
}
|