Modules for Aurora-based ports. Borealis provides cross-platform logging, updates, crash reporting, an HTTP client, Discord rich presence, data directory handling, and more.
Supported platforms: Windows, Linux, Android, macOS, iOS and tvOS.
| Target | Contents |
|---|---|
borealis::cli |
Standard options with cxxopts |
borealis::config |
ConfigVar system with JSON storage, observers & overrides |
borealis::core |
Shared utilities |
borealis::crash |
In-process crash handler with backtrace unwinding & logging |
borealis::data |
Data directory resolution, portable mode, data migration |
borealis::disc |
Disc inspection and hash verification |
borealis::discord |
Discord rich presence IPC client |
borealis::file_select |
Cross-platform file/folder selection |
borealis::http |
Asynchronous HTTPS client (HTTP/2, TLS 1.2+) |
borealis::io |
File I/O + paths, bookmarks (iOS), and document URIs (Android) |
borealis::log |
fmt-based logging + sinks (console, rotating file, logcat, ring buffer) |
borealis::net |
TCP, UDP, and asynchronous DNS |
borealis::presentation |
Android frame-rate configuration |
borealis::sentry |
Optional sentry-native/crashpad integration and consent state |
borealis::task |
Shared async task pool with cancellation and progress |
borealis::ui |
RmlUi UI framework, document system, and shared components |
borealis::update |
Update checks via GitHub releases |
borealis::ws |
WebSocket client over HTTPS |
Borealis also provides an Android platform layer that integrates SDL, Aurora and provides Java-side support for Borealis modules.
Add borealis as a submodule alongside aurora and link the targets you use:
add_subdirectory(extern/borealis EXCLUDE_FROM_ALL)
target_link_libraries(mygame PRIVATE borealis::log)#include <borealis/log.hpp>
namespace {
constexpr borealis::Log Log{"mygame::data"};
}
Log.info("Loaded {}", path);
Log.fatal("Unrecoverable: {}", err); // flushes all sinks, then Options::onFatalInitialize once at startup, before aurora_initialize:
borealis::log::init({
.level = borealis::LogLevel::Info,
.fileDirectory = cachePath / "logs",
.filePrefix = "mygame",
});
config.logCallback = borealis::log::aurora_callback();C code (e.g. OSReport shims) may use the printf-style bridge in <borealis/log_c.h>.
Define borealis::AppInfo for modules that need application identity. Version and build strings come from the generated
<borealis/version.h>.
inline constexpr borealis::AppInfo AppInfo{
.orgName = "Twilit Realm",
.appName = "Dusklight",
.githubOwner = "TwilitRealm",
.githubRepo = "dusklight",
.discordApplicationId = "1495632471994405035",
};borealis::http provides pollable asynchronous HTTPS requests using WinHTTP on Windows, NSURLSession on Apple, libcurl
on Linux or OkHttp on Android. The shared worker pool starts lazily, grows on demand, and releases idle threads
automatically. Call borealis::shutdown() during application shutdown to cancel and drain outstanding work.
Asynchronous operations return a Task<T>. Poll with ready() or try_take(), request cancellation with cancel()
and use map() to transform results.
auto check = borealis::update::start_latest_github_release_check(AppInfo);
// Poll from the main loop.
if (auto result = check.try_take();
result && result->status == borealis::update::Status::UpdateAvailable) {
show_update_prompt(result->latest.tagName, result->latest.htmlUrl);
}Status::Disabled indicates the build was compiled without an available HTTP backend.
borealis::net provides non-blocking TCP clients and listeners, UDP sockets, and asynchronous
DNS. A Context manages its sockets and event queue, which can be polled from any thread.
#include <borealis/net.hpp>
borealis::net::Context network;
const auto stream = network.connect("tcp://127.0.0.1:34197");
borealis::net::Event event;
while (network.poll(event)) {
if (event.id == stream && event.kind == borealis::net::Event::Kind::StreamData) {
consume(event.id, event.data);
}
}Endpoints use tcp://host:port or udp://host:port.
borealis::ws provides asynchronous WebSocket client connections. Poll each connection for Open,
Message, and Closed events.
#include <borealis/ws.hpp>
auto connection = borealis::ws::connect({
.url = "wss://example.com/events",
.protocols = {"events.v1"},
});
borealis::ws::Event event;
while (connection.poll(event)) {
if (event.kind == borealis::ws::Event::Kind::Message) {
consume(event.messageKind, event.data);
}
}Only wss:// is accepted by default.
Create a borealis::data::Manager with the application identity, portable path, legacy identities, and files eligible
for migration:
borealis::data::Manager dataManager{AppInfo, {
.portableRelativePath = std::filesystem::path{"data"},
.legacyApps = {
{
.orgName = "OldOrgName",
.appName = "OldAppName",
},
},
.migration = {
.directories = {"saves", "texture_replacements"},
.files = {"config.json"},
.extensions = {".gci"},
},
}};
const auto status = dataManager.initialize(userDirectoryOverride);
const auto& paths = dataManager.paths();borealis::config stores typed settings as flat keys in a JSON file. Declare Var<T> members in a settings struct
using <borealis/config.hpp>, and define their keys and defaults in a source file that includes
<borealis/config_codec.hpp>.
struct Settings {
struct {
Var<bool> fullscreen;
Var<Resampler> resampler; // enums need a constexpr config_enum_values(E) table next to them
} video;
struct {
Var<int> scale;
} ui;
};
Settings settings{
.video = {
.fullscreen{"video.fullscreen", false},
.resampler{"video.resampler", Resampler::Bilinear},
},
.ui = {
.scale{"ui.scale", 100, {.min = 50, .max = 200}},
},
};Load once at startup, call update() every frame to autosave changes after a short delay, and flush() on shutdown
and when entering background (for mobile). --cvar KEY=VALUE (from borealis::cli) sets session-only overrides:
borealis::config::apply_overrides(standardOptions.configOverrides);
borealis::config::load({.path = paths.userPath / "config.json", .version = 1});
borealis::config::update();
borealis::config::flush();Read vars directly (if (settings.video.fullscreen), *settings.ui.scale) and write them with set() and reset().
Only user values are saved, and unknown keys are preserved. Subsystems apply settings with observe(), which runs
immediately and on every change. Overlay temporarily overrides values, e.g. for a game mode that forces some
settings. <borealis/ui/config.hpp> provides binding helpers for controls.
auto binding = settings.video.resampler.observe(apply_resampler); // disconnects when destroyed, or use .release()
borealis::config::Overlay recording{"recording"};
recording.set(settings.video.fullscreen, true); // recording.clear() restores
pane.add_child<BoolButton>(bind(settings.video.fullscreen, {.key = "Fullscreen"}));borealis::disc inspects and verifies GameCube and Wii disc images.
constexpr std::array AcceptedDiscs{
borealis::disc::AcceptedDisc{
.gameId = "GZ2E01",
.expectedHash = borealis::disc::parse_xxh3_128("14e886f08e548a000afde98a3195e788"),
},
};
constexpr std::array<std::string_view, 1> RecognizedGameIds{"RZDE01"};
borealis::disc::Progress progress;
const borealis::disc::Result result = borealis::disc::verify(path,
{.acceptedDiscs = AcceptedDiscs, .recognizedGameIds = RecognizedGameIds}, &progress);Game ID, disc number, and revision must match an accepted record. IDs in another
record or recognizedGameIds return UnsupportedVersion; other IDs return
UnknownGame.
Verification uses XXH3-128. Progress can be polled or canceled from another thread.
Install the crash handler once, after logging is initialized:
#include <borealis/crash.hpp>
borealis::log::init(logOptions);
borealis::crash::install();Reports are written to stderr and the active log file. They include build identity, fault address, module build IDs, and relative virtual addresses for symbolication.
Set BOREALIS_ENABLE_SENTRY=ON to include sentry-native/crashpad. The DSN and environment are build inputs:
BOREALIS_SENTRY_DSN and BOREALIS_SENTRY_ENVIRONMENT. At runtime, BOREALIS_SENTRY_ENABLED, BOREALIS_SENTRY_DSN,
and BOREALIS_SENTRY_DEBUG can be used as overrides.
borealis::sentry::Options options{
.release = std::string(AppInfo.appName) + "@" + BOREALIS_APP_DESCRIBE,
.databaseDirectory = cachePath / "sentry",
};
if (const char* logPath = borealis::log::file_path()) {
options.attachments.emplace_back(logPath);
}
borealis::sentry::initialize(options);Reports require user consent through get_consent() and set_consent(). Call shutdown() before shutting down
logging.
borealis::discord uses Discord's local IPC protocol. Set the application ID in AppInfo:
borealis::discord::initialize(AppInfo, handlers);
borealis::discord::update_presence({
.details = "Ordon Village",
.largeImageKey = "icon",
.largeImageText = std::string(AppInfo.appName),
});Call run_callbacks() from the main loop and shutdown() during application teardown.
Borealis is licensed under the MIT License.