Bomberman Multiplayer
Authoritative multiplayer networking layer for Bomberman.
Loading...
Searching...
No Matches
CliCommon.h
1#ifndef BOMBERMAN_UTIL_CLICOMMON_H
2#define BOMBERMAN_UTIL_CLICOMMON_H
3
4#include <charconv>
5#include <limits>
6#include <string>
7#include <string_view>
8#include <cstdint>
9
10#include <spdlog/spdlog.h>
11
12#ifndef BOMBERMAN_DEFAULT_LOG_LEVEL
13#define BOMBERMAN_DEFAULT_LOG_LEVEL SPDLOG_LEVEL_INFO
14#endif
15
20{
21#if defined(BOMBERMAN_ENABLE_NET_DIAG) && BOMBERMAN_ENABLE_NET_DIAG
22 inline constexpr bool kNetDiagAvailable = true;
23#else
24 inline constexpr bool kNetDiagAvailable = false;
25#endif
26
27#if defined(BOMBERMAN_ENABLE_CLIENT_NETCODE_DEBUG_OPTIONS) && BOMBERMAN_ENABLE_CLIENT_NETCODE_DEBUG_OPTIONS
28 inline constexpr bool kClientNetcodeDebugOptionsAvailable = true;
29#else
30 inline constexpr bool kClientNetcodeDebugOptionsAvailable = false;
31#endif
32
34 {
35 spdlog::level::level_enum logLevel = static_cast<spdlog::level::level_enum>(BOMBERMAN_DEFAULT_LOG_LEVEL);
36 std::string logFile;
37
38 bool hasLogLevelOverride = false;
39 bool hasLogFileOverride = false;
40 };
41
44 {
45 bool netDiagEnabled = false;
46 };
47
48 // string_view needs size declared as constexpr, else it goes through char_traits::length()
49 inline constexpr std::string_view kLoggingUsageArgs{
50 "[--log-level <trace|debug|info|warn|error>] [--log-file <path>]",
51 sizeof("[--log-level <trace|debug|info|warn|error>] [--log-file <path>]") - 1
52 };
53
54 inline constexpr std::string_view kDiagnosticsUsageArgs{
55 "[--net-diag]",
56 sizeof("[--net-diag]") - 1
57 };
58
59 inline constexpr std::string_view kClientNetcodeDebugUsageArgs{
60 "[--no-prediction] [--no-remote-smoothing]",
61 sizeof("[--no-prediction] [--no-remote-smoothing]") - 1
62 };
63
65 inline bool parseLogLevel(std::string_view text, spdlog::level::level_enum& outLevel)
66 {
67 if (text == "trace") { outLevel = spdlog::level::trace; return true; }
68 if (text == "debug") { outLevel = spdlog::level::debug; return true; }
69 if (text == "info") { outLevel = spdlog::level::info; return true; }
70 if (text == "warn") { outLevel = spdlog::level::warn; return true; }
71 if (text == "error") { outLevel = spdlog::level::err; return true; }
72 return false;
73 }
74
76 inline bool parsePort(std::string_view text, uint16_t& outPort)
77 {
78 unsigned int value = 0;
79 const char* begin = text.data();
80 const char* end = begin + text.size();
81
82 // from_chars is better than stoi here.
83 const auto [ptr, ec] = std::from_chars(begin, end, value);
84 if (ec != std::errc{} || ptr != end || value == 0 ||
85 value > std::numeric_limits<uint16_t>::max())
86 {
87 return false;
88 }
89
90 outPort = static_cast<uint16_t>(value);
91 return true;
92 }
93
95 inline bool parseUint32(std::string_view text, uint32_t& outValue)
96 {
97 uint32_t value = 0;
98 const char* begin = text.data();
99 const char* end = begin + text.size();
100
101 const auto [ptr, ec] = std::from_chars(begin, end, value);
102
103 if (ec != std::errc{} || ptr != end)
104 return false;
105
106 outValue = value;
107 return true;
108 }
109
120 inline bool tryParseLoggingOption(int argc, char** argv, int& ioIndex, LoggingCliOptions& outOptions, std::string& outError)
121 {
122 const std::string_view arg = argv[ioIndex];
123
124 if (arg == "--log-level")
125 {
126 if (ioIndex + 1 >= argc)
127 {
128 outError = "Missing value for --log-level";
129 return true;
130 }
131
132 const std::string_view value = argv[++ioIndex];
133 if (!parseLogLevel(value, outOptions.logLevel))
134 {
135 outError = "Invalid log level: " + std::string(value);
136 return true;
137 }
138
139 outOptions.hasLogLevelOverride = true;
140 outError.clear();
141 return true;
142 }
143
144 if (arg == "--log-file")
145 {
146 if (ioIndex + 1 >= argc)
147 {
148 outError = "Missing value for --log-file";
149 return true;
150 }
151
152 // File validation is not performed here, just accept the string. If the file cannot be opened later, spdlog will report an error.
153 outOptions.logFile = argv[++ioIndex];
154 outOptions.hasLogFileOverride = true;
155 outError.clear();
156 return true;
157 }
158
159 return false;
160 }
161
163 inline bool tryParseDiagnosticsOption([[maybe_unused]] int argc, char** argv, int& ioIndex, DiagnosticsCliOptions& outOptions, std::string& outError)
164 {
165 const std::string_view arg = argv[ioIndex];
166
167 if (arg == "--net-diag")
168 {
169 if constexpr (kNetDiagAvailable)
170 {
171 outOptions.netDiagEnabled = true;
172 outError.clear();
173 }
174 else
175 {
176 outError = "--net-diag is not available in this build";
177 }
178
179 return true;
180 }
181
182 return false;
183 }
184
186 inline bool tryParseClientNetcodeDebugOption([[maybe_unused]] int argc, char** argv, int& ioIndex,
187 bool& ioPredictionEnabled, bool& ioRemoteSmoothingEnabled,
188 std::string& outError)
189 {
190 const std::string_view arg = argv[ioIndex];
191
192 if (arg == "--no-prediction")
193 {
194 if constexpr (kClientNetcodeDebugOptionsAvailable)
195 {
196 ioPredictionEnabled = false;
197 outError.clear();
198 }
199 else
200 {
201 outError = "--no-prediction is not available in this build";
202 }
203
204 return true;
205 }
206
207 if (arg == "--no-remote-smoothing")
208 {
209 if constexpr (kClientNetcodeDebugOptionsAvailable)
210 {
211 ioRemoteSmoothingEnabled = false;
212 outError.clear();
213 }
214 else
215 {
216 outError = "--no-remote-smoothing is not available in this build";
217 }
218
219 return true;
220 }
221
222 return false;
223 }
224} // namespace bomberman::cli
225
226#endif // BOMBERMAN_UTIL_CLICOMMON_H
Shared CLI parsing utilities for the project.
Definition CliCommon.h:20
bool parsePort(std::string_view text, uint16_t &outPort)
Parses and validates a network port in range [1, 65535].
Definition CliCommon.h:76
bool tryParseDiagnosticsOption(int argc, char **argv, int &ioIndex, DiagnosticsCliOptions &outOptions, std::string &outError)
Tries to parse one shared diagnostics-related CLI option.
Definition CliCommon.h:163
bool tryParseLoggingOption(int argc, char **argv, int &ioIndex, LoggingCliOptions &outOptions, std::string &outError)
Tries to parse one shared logging-related CLI option.
Definition CliCommon.h:120
bool tryParseClientNetcodeDebugOption(int argc, char **argv, int &ioIndex, bool &ioPredictionEnabled, bool &ioRemoteSmoothingEnabled, std::string &outError)
Tries to parse one client-only debug netcode option.
Definition CliCommon.h:186
bool parseLogLevel(std::string_view text, spdlog::level::level_enum &outLevel)
Parses a textual log level into a spdlog level enum. Case-sensitive.
Definition CliCommon.h:65
bool parseUint32(std::string_view text, uint32_t &outValue)
Parses a uint32_t from text, with full validation.
Definition CliCommon.h:95
Diagnostics-related CLI options.
Definition CliCommon.h:44
Definition CliCommon.h:34