Skip to content

About

Keeps Echo VR playable on the community service: one drop-in BugSplat64.dll for PC (Windows or Wine) and a Quest build, with Discord sign-in, the social lobby, friends and party, plus a dedicated game server.

Resources

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

1 watching

Forks

Latest commit

 

History

2,235 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

nEVR Runtime

nEVR Runtime keeps Echo VR (echovr.exe) playable on the community game service (echovrce, Nakama-based). Drop two files, BugSplat64.dll and nevr-runtime.dll, into the game folder and the game signs in with your Discord account, reaches the social lobby and shows its friends and party. The Quest build does the same through a repacked APK. For contributors it is the C++17 source of those DLLs and of the Quest sentinel, plus the tooling and tests that keep both honest.

Part of the NEVR project, keeping Echo VR alive.

Working in this repo as an agent? Start at AGENTS.md.

Built on, and thanks

nEVR is a community project, built on other people's work and tested by the people who reported what broke. These are the projects and people it builds on, and what each did.

Projects

  • Xenomega: EchoRelay, a reimplementation of Echo VR's web services and dedicated game servers. The frozen v1 game server code in src/legacy/ was written for its ServerDB, and the legacy message translation in docs/reference/legacy-translator.md is read from its documentation.
  • kfc: Helped write a lot of EchoRelay.
  • Dualgame: echo-symbols, the recovered symbol names this repo pulls at a pinned commit for its log symbol cache, and echovr-modkit with its EchoRelay fork, which back invite codes and the early-quit lockout and which docs/engine/early-quit.md and the invite-code design (#906) draw on.
  • marshmallow-mia: The Echo VR Linux port, the Echo VR installer (PC and Quest) and EchoVR_Launcher (Windows and Linux). Reported #133 to #137, #495, #496, #511 to #513 and #719, and wrote the merged fixes #138 to #141, #500, #502, #514 to #516 and #721. Tested nevr-runtime in #nevr-runtime-testing.
  • Crafter: Quest-EchoVR-Installer, a 3D Quest installer for Echo VR built in Unity. Reported #621, the game sending a Quest 3 player back to Home at launch, with a full logcat. Tested nevr-runtime in #nevr-runtime-testing.
  • Ducky: The reverse engineer behind the Echo Combat Quest port.
  • babs: Echo Frenzy, a community game mode for Echo VR that paved the way for others making game modes; the pipeline for editing Echo's in-game screens (Doom on Echo is built on it); EchoCraft; and the moderator tablet for kicking players from lobbies. Has been there every step of the way, before and since Echo's shutdown.

People

  • Trodd-: Found the XInput fix that lets the spectator free cam see Xbox One and Series controllers, and brought it to the project (#877). Built the echovrce.com website. Tested nevr-runtime in #nevr-runtime-testing.
  • DinkyBoi: Reported a party of three queuing for arena with one member left out (#888), and the arm tablet's repeated "server full" message when joining a full social lobby (#889). Tested nevr-runtime in #nevr-runtime-testing.
  • berg: One of the party of three in #888: left out of the arena match once, and rejoined through a link. Tested nevr-runtime in #nevr-runtime-testing.
  • zebra: One of the party of three in #888, left out of the arena match. Tested nevr-runtime in #nevr-runtime-testing.
  • Nebula: Reported install.ps1 failing on a PC with no D: drive (#679) and the idea that it asks for the game folder (#680), the Quest game closing at start (#758), uninstall.ps1 refusing after an update (#759) and the tablet's missing Add friend button (#775). Tested nevr-runtime in #nevr-runtime-testing.
  • CyanoTex: Tested nevr-runtime in #nevr-runtime-testing.
  • spike4887: Tested nevr-runtime in #nevr-runtime-testing.
  • TekEmperor: Tested nevr-runtime in #nevr-runtime-testing.
  • arii: Tested nevr-runtime in #nevr-runtime-testing.
  • chinmayee5599: Opened #510, which renamed three TCP game message symbols in src/abi/symbols.h.
  • brysonak: Opened #12, which changed the server log file names and added a flag to keep the old names.
  • Furo: Supporter of nevr-runtime.

Thanks

  • AvaGoosa: Named in the thank-you strings of the Echo VR installer's patcher.
  • h4ck3r210: Named in the thank-you strings of the Echo VR installer's patcher.
  • Elominator: Named in the thank-you strings of the Echo VR installer's patcher.
  • sprockee: Named in the thank-you strings of the Echo VR installer's patcher.
  • he_is_the_cat: Named in the thank-you strings of the Echo VR installer's patcher. Tested nevr-runtime in #nevr-runtime-testing.

Thank you to everyone in #nevr-runtime-testing, named or not.

What it does

PC means the Windows or Wine game client, Quest means the Android sentinel, both means each. Every feature below is on main; docs/testing/smoke-checklist.md says how to check each one and which log line proves it.

Get in

  • Nothing to configure. The service endpoints and the public client keys are built in, so a game client with a build-embedded configuration signs in with no config.yaml. A config.yaml overrides them, on the PC next to the game and on the Quest in the app's files folder (docs/reference/example-config.yaml lists every key and which builds read it). (both)
  • Sign in with Discord. A device-code sign-in in your browser; the saved sign-in is reused on the next start and refreshed in the background. (PC)
  • Saved sign-in on the headset. The Quest build reuses its saved sign-in, and shows a sign-in code on the game's own login-error screen when it has none. (Quest)
  • Windowed, no headset. -windowed runs the game in a window with the headset checks patched out. (PC)
  • Works on Wine and Proton. Wine is detected; the _temp directory fix and -no-console default apply. (PC) Tested clean: Proton Experimental 11.0 and Wine 11. Proton 8.0 (8.0-103) crashes in its own dxgi.dll right after the graphics device is created, with the stock BugSplat64.dll too, so use Proton Experimental or a recent Wine (#673). The boot log's [NEVR.BOOT] host environment: line records the Wine version.
  • A wrong echovr.exe is refused. A wrong or damaged game image is refused instead of patched. (PC)

Friends, party and the social lobby

  • Social lobby. Log in and land in the social lobby through the community game service. (both)
  • Friends list. Names with online, busy and offline presence, plus status text under each friend. (PC)
  • Friend changes without a restart. Adds, accepts and removals made on the web site show in the game. (both)
  • Recently met. The recently-met list and its refresh. (both)
  • Party. A party exists after login; receive, accept and dismiss invites; promote a member; lock or unlock the party; join errors show the game's own popup. (both)
  • Send a party invite from a friend row. (PC)
  • New accounts can invite. The first-match gate reads as passed, so a fresh account can send a party invite. (both)

Matchmaking and play

  • Matchmaker library host. The matchmaker library's compiled service address is rewritten each time the library loads, because the game unloads and reloads it during a session. The live check that the PUBLIC MATCH terminal screen populates is still open (#18). (PC)
  • Service redirect. The game's hard-coded service addresses (HTTP and WebSocket) go to the community game service, over modern TLS 1.2/1.3. (PC)
  • Early-quit lockout. The lockout countdown shows when the game service sends a penalty. (PC)
  • Arena rules in config.yaml. Round time, celebration time and mercy score can be set under arena.*. (PC)

Voice

  • Microphone on Wine and Proton. A WASAPI capture provider feeds the game's own voice path, resampled to mono 48 kHz; it picks up the default capture device again after the device is invalidated. (PC)
  • Native Windows keeps the game's own microphone. The runtime installs its provider under Wine and Proton only. (PC)

Crash and exit handling

  • Crash recovery. The game's main loop is wrapped, the original crash reporter is blocked, and a crash writes a readable dump and a crash record. (PC)
  • Clean exit. Closing the window ends the process; Ctrl+C or a stop signal shuts down with a watchdog. (PC)
  • Guards. Null session pointers and broadcaster listener tables that used to crash the game are guarded and counted. (PC)
  • Local minidump. A Quest crash writes a minidump and the maps file locally. (Quest)

Diagnostics

  • Structured logs. One JSON line per event: nevr-boot.jsonl in logs\ of the game folder, a timestamped nevr-<timestamp>.jsonl under %LOCALAPPDATA%\EchoVR\logs and the host's nevr-bootstrap.jsonl under %LOCALAPPDATA%\nevr\echovr\logs on PC (every PC file is listed in "Files the runtime uses"); logcat tag NEVR-Sentinel and nevr-sentinel.log on Quest.
  • The game's own log, filtered. The built-in filter captures the game's log lines, folds repeats and reports its own health. (PC)
  • Hook accounting. Each hook reports whether it was ever entered; overwritten hooks are detected; counters are reported once the game runs. (both)
  • Export tracing. -trace-exports records the platform DLL calls. (PC)
  • Hardware dump. A one-time hardware and environment dump file on request. (Quest)

Game server mode

echovr.exe -server -headless -no-console boots, logs in, begins multiplayer, loads the in-process server library and registers with the game service. docs/testing/smoke-checklist.md (rows SV01 on) says how to check each item below.

  • Dedicated game server. -server implies headless and no OVR; headless graphics need no GPU; echovr_server.exe starts one. (PC)
  • Registers with the game service. Authenticates, registers (with guild and region filters), takes sessions and returns to the lobby after a round. (PC)
  • Operates unattended. Re-registers after a dropped connection, exits after the session so a fleet manager can respawn it, shuts down cleanly on Ctrl+C, and holds an empty game server for a configurable time. (PC)
  • Network. UPnP port mapping, internal and external address overrides, match telemetry streaming. (PC)

Quest

  • A sentinel loaded with the game. The redirect, the bridge, the login and the social façade follow from the embedded service endpoints and keys, with no switch of their own; social.facade, social.send_presence_to_meta and diagnostics.hardware_dump in config.yaml change the façade, the rich presence and the hardware dump (off by default). On every launch the sentinel answers the game's encrypted-OBB mount itself (docs/adr/0007-quest-obb-mount-skip.md); that the game then starts without the ~30 s wait is predicted and not yet shown on a headset (#572). (Quest)
  • Login and social on the headset. The game's login is rewritten into the NEVR login, and the social facade decodes friends, presence, recently-met and party frames from the game service. (Quest)

Known gaps

The issue tracker is the source of truth. On Quest the main-menu FRIENDS LIST (#391), QUIT (#392), the status text under your name (#393) and the party tab's Invite Members (#318) do not work yet. On PC:

  • the main menu shows no game service status, because the status request fails (#408);
  • the matchmaking screen's time remaining is always 0 (#414);
  • under Wine and Proton the microphone ring buffer overflows at the start of a capture and whether the game reads it at real time is still being measured (#95);
  • the party roster keeps a member who disconnected (#403);
  • party data sharing is refused (#398);
  • a friend request shows no prompt to the receiver (#405);
  • the PUBLIC MATCH terminal screen after a matchmaker library reload has not been checked live (#18).

Install for testers

  1. Sync the device clock first (PC: Windows time sync; Quest: automatic time on), so PC and Quest logs line up afterwards.
  2. Windows: take nevr-runtime-v<X.Y.Z>-windows.zip from the release (CI builds it from the tag vX.Y.Z), close the game, unzip it, and run install.ps1 from PowerShell (powershell -NoProfile -ExecutionPolicy Bypass -File install.ps1). It checks the package against SHA256SUMS, copies your original BugSplat64.dll to BugSplat64.dll.original-<timestamp>, renames a legacy dbgcore.dll to dbgcore.dll.legacy-<date> and installs the two new files. It deletes nothing.
  3. Uninstall: uninstall.ps1 -Dir <bin\win10> restores both and keeps the backups.
  4. Quest: a release is the Windows zip only: the APK repacks the store game, so it is not on GitHub. The development build (nevr-runtime-v<X.Y.Z-dev.N>-<sha7>-quest.apk, built by just package-dev) is published outside GitHub; download it and install it with adb install -r. It is signed with the same key as earlier test builds, so it installs over them and keeps your data.
  5. Windows Defender or SmartScreen may warn about a file that carries no signature. Get-AuthenticodeSignature .\BugSplat64.dll (PowerShell) says whether a file is signed.

Moving a Quest from the community installer to this APK

A headset whose Echo VR was installed by the community Quest installer cannot take this APK as an update. The installer's game is signed with the installer's key, and Android installs an update only from the key that signed the installed app, so adb install -r of this APK over it is refused with INSTALL_FAILED_UPDATE_INCOMPATIBLE. There is one way over:

  1. Uninstall Echo VR from the headset once (adb uninstall com.readyatdawn.r15, or from the headset's app library).
  2. Install this APK with adb install.

This APK's versionCode is set when it is built, from its version (tools/quest_apk_version.py), and is always above 4987570, the game build the installer pins. So the installer's own build never replaces this one, and a later build of this APK installs over an earlier one. The code is major*10^7 + minor*10^5 + patch*10^3 + slot; the slot is the development build's distance N from the last release, or 999 for a release (5.6.0 is 50600999). It carries no commit: two development builds from different branches at the same distance N have the same versionCode, so tell them apart by the commit in the file name (-<sha7>-quest.apk).

What the code shows about the game data and the sign-in, and what it does not:

  • With no OBB file, the game reads its data from /storage/emulated/0/readyatdawn and from no other folder (ADR 0013). A release build downloads nothing: when the data is not in that folder it shows "Echo VR game data is missing. Install Echo VR with Echo Launcher first, then start the game again." and ends. Data that sits only under Android/media/com.readyatdawn.r15/files is not read by a launch with no OBB file.
  • The refresh token is kept in the app's private storage (ADR 0003), which the uninstall removes, so the first launch of this APK starts the sign-in (docs/quest/SIGN-IN.md) (to be confirmed on the headset, below).
  • To be confirmed on a real installer-installed headset: which folder the installer puts the game data in, whether that folder is still there after the uninstall, whether the game starts after the move without a second data install, and what the first launch of this APK shows. The steps and predicted outcomes for that run are written down before it, in the headset check for the move.

The community beta guide for a manual install is docs/beta/INSTALL.md. The Quest sign-in flow is in docs/quest/SIGN-IN.md.

Files the runtime uses

Every path the Windows runtime reads or writes. An installer, an uninstaller or a support script builds to this list. The game folder is the folder that holds echovr.exe (<install>\bin\win10); the code finds it with GetModuleFileName on the game module. %LOCALAPPDATA% and %TEMP% are the Windows user's. Under Wine they are inside the prefix (<prefix>/drive_c/users/<user>/AppData/Local).

In the game folder

Path What it is Code
BugSplat64.dll The file the game imports: the thin host, with the game's 28 BugSplat64.dll exports, the rendezvous detour and the crash capture. It loads nevr-runtime.dll and, when that cannot be loaded after attach, stops the game with exit code 78, after one plain-words dialog on a client (a server or headless run gets the game_stop record only). OUTPUT_NAME "BugSplat64" of target nevr_host in src/runtime/CMakeLists.txt; RuntimeRendezvous::StopGame in src/runtime/host/runtime_rendezvous.cpp
nevr-runtime.dll The runtime: hooks, modes, server, bridge, plugin loader and the statically linked modules. The host's file loader opens it from the directory of BugSplat64.dll; install.ps1 puts it there with the host. OUTPUT_NAME "nevr-runtime" of target nevr_runtime in src/runtime/CMakeLists.txt; kRuntimeFileName and ResolveRuntimePath in src/runtime/host/runtime_load.cpp
BugSplat64.dll.original-<timestamp>, dbgcore.dll.legacy-<date>, nevr-install.txt What install.ps1 leaves: the game's own BugSplat64.dll, a legacy dbgcore.dll set aside, a pre-existing nevr-runtime.dll (nevr-runtime.dll.original-<timestamp>; uninstall.ps1 sets the installed one aside as nevr-runtime.dll.uninstalled-<timestamp>), and the state file uninstall.ps1 reads (renamed nevr-install.txt.undone-<timestamp> when it undoes the install, or nevr-install.txt.stale-<timestamp> when install.ps1 finds a record for a DLL that Verify Files has since restored). Both scripts append their runs to nevr-install.log beside the script, not in the game folder. tools/package-release/install.ps1, tools/package-release/uninstall.ps1
plugins\ Plugin DLLs. A plugin loads only when the ordered plugins: list in config.yaml names it; a DLL the list does not name is ignored. LoadPlugins (pluginDir) in src/runtime/ext/plugin_loader.cpp
_overrides\ Files registered as resource overrides at start. src/runtime/patch/resource_override.cpp
logs\nevr-boot.jsonl The boot log: one JSON line per event from before the log filter starts, appended across runs; the main log replays this run's lines. Created at start, with the logs folder. If the folder cannot be created or the file cannot be opened, the lines go to standard error only. nevr_boot_log_tee::Init in src/runtime/log/boot_log_tee.cpp
log_filter_config.yml, .yaml, .jsonc, .json Optional settings of the built-in log filter (file_dir, rotation). The first that exists is used, searched in this order, then in the working directory. FindConfigFile in src/runtime/log/builtin_filter.cpp

In _local

_local is searched as <game folder>\_local, then <game folder>\..\_local, then <game folder>\..\..\_local (the stock install keeps it beside bin). Only config.yaml also looks in the directory of a path named by -config or -config-path, and looks there first; .credentials.json does not.

Path What it is Code
_local\config.yaml Every nEVR setting: service addresses and keys, the plugins: list, arena rules. A missing file is a warning and a defaults-only run; a malformed one stops a dedicated server. FindNevrConfigYamlPath in src/runtime/lifecycle/service_config.cpp
_local\config.json Optional. Only the keys the stock engine reads. LoadEarlyConfig in src/runtime/lifecycle/config.cpp
_local\.credentials.json The cached refresh token and identity (the access token is never written). The function looks at <game folder>\_local, ..\_local and ..\..\_local only (it ignores -config and -config-path) and uses the first one that already holds a .credentials.json; if none does, the first of those three that holds a config.yaml; if none does, <game folder>\_local, which a write creates. A write goes to .credentials.json.tmp first, then replaces the cache. SelectCredentialCacheLocation in src/core/auth_token.h; TempPathFor in src/core/credential_write.h
_local\r14logs\*.log The game's own log. The runtime only reads the newest, relative to the working directory. src/runtime/lifecycle/state_machine.cpp

In %LOCALAPPDATA%\nevr\echovr\

Path What it is Code
logs\nevr-bootstrap.jsonl The host's own log: what it decided at attach, and its crash-dump records. Falls back to %TEMP%\nevr\echovr\logs, then the directory of BugSplat64.dll. kLogsSubdirectory, kBootstrapLogName in src/runtime/host/host_paths.h
crashes\nevr-<pid>-<n>.dmp A minidump written by the host's crash capture, with the same fallbacks (%TEMP%\nevr\echovr\crashes, then the directory of BugSplat64.dll). The game's crash handler reaches it through the exported BugSplat_createReport in src/runtime/host/minidmp_sender_exports.cpp. kCrashesSubdirectory in src/runtime/host/host_paths.h; CrashCapture::Capture in src/runtime/host/crash_capture.cpp
cache\<sha256>.blob, cache\index.json The content-addressed asset cache: the bytes under their own SHA-256, and the index that says which blob stands in for which resource. A write in progress is <sha256>.<pid>.<tick>.tmp. The cache is size-capped and evicts blobs the index does not name. Without LOCALAPPDATA there is no cache directory: the cache is disabled and the runtime logs [NEVR.RESOURCE] cache disabled reason=no cache directory (LOCALAPPDATA unset). src/runtime/patch/asset_cache.h, DefaultDir in src/runtime/patch/asset_cache.cpp

In %LOCALAPPDATA%\EchoVR\

This is the game's own folder, which the runtime also writes to.

Path What it is Code
logs\nevr-<timestamp>.jsonl The main run log (the built-in filter's output). Rotated by size and age; the newest rotate_keep files are kept. Without LOCALAPPDATA it is logs\ beside the game's executable. The file_dir setting of the filter config replaces the folder in both cases. GetDefaultLogDir, BuildLogFilePath in src/runtime/log/builtin_filter.cpp
logs\nevr-crash-<run id>.txt The crash record: the [NEVR.CRASH] lines, written only once a crash path is entered. Without LOCALAPPDATA (or when its value is MAX_PATH characters or longer) it is logs\nevr-crash-<run id>.txt beside the game's executable. Neither case creates the logs folder: if it does not exist the file is not written. PrepareCrashRecordPath in src/runtime/lifecycle/crash_recovery.cpp
cosmetics\v1\packages\ Downloaded cosmetic packages (client only). The folder is created on demand under the user's Local AppData known folder (not the LOCALAPPDATA variable); if that lookup or the creation fails, the error is logged and no package is stored. GetCacheDir in src/runtime/patch/asset_cdn.cpp

What gets built

The two DLLs

src/runtime/host/ → BugSplat64.dll (the host) and the rest of src/runtime/ → nevr-runtime.dll (the runtime). Both go in the game folder.

The game statically imports BugSplat64.dll (the original crash reporter), so replacing it gives the earliest possible hook point — it loads before WinMain. The host is deliberately small: the game's 28 BugSplat64.dll exports, the crash capture and the one hook on the game's main wrapper, where it loads nevr-runtime.dll and hands the game over to it. The runtime carries the boot hooks, CLI flags, headless/server mode patches, crash recovery, config and service redirection, the module and plugin loaders, the built-in log filter, and the in-process game server (src/runtime/server/).

Hooking is MinHook-based.

Command-line arguments

Arguments the runtime reads from the game's command line (--name works as well as -name). --help lists them.

Argument Effect
-server Run as a dedicated game server (implies headless)
-offline Run the game in offline mode
-windowed Run the game with no headset, in a window
-no-console Disable console window creation
-config, -config-path Path to a JSON file the game loads instead of _local/config.json; config.yaml is looked for in the same directory
-region Set the matchmaking region
-serverregion Set the server fleet region
-no-exit-on-error Keep a server running after a game service disconnect (default: exit)
-exit-on-error No effect: exiting on error is the default
-trace-exports Trace the export calls of platform DLLs (pnsrad, pnsovr, pnsdemo or all); off by default
-no-telemetry Disable telemetry streaming
-telemetry-rate Set the telemetry rate in Hz
-telemetry-diag Log telemetry diagnostics every second
-timestamps Prefix log lines with timestamps
-upnp Enable UPnP port forwarding
-require-signed-plugins Load only plugins signed through the release pipeline and refuse the rest. Without it, plugins load whether or not they are signed. The plugin trust: line in the log states which applied

Runtime-loaded modules

The platform_compat and token_auth modules are statically linked into nevr-runtime.dll; there are no separate module DLLs to deploy. They use NvrModuleContext, not the plugin interface.

Module Linked into Purpose
platform-compat nevr-runtime.dll Schannel TLS modernization, MSXML6 pass-through hook, Wine _temp fix
token-auth nevr-runtime.dll Device-code auth, token cache

The bridge is why the game never negotiates TLS for its WebSocket traffic: it speaks plaintext to a local proxy, and the proxy terminates TLS outbound.

Plugins

Optional, discovered from a plugins/ directory next to the game binary and loaded via the NvrPluginInterface lifecycle.

Plugin Output Purpose
example nevr_example.dll Reference implementation for new plugin authors
debug-lockout nevr_debug_lockout.dll Debug instrumentation for early-quit lockout state

Gameplay and tooling plugins live in the separate nevr-runtime-plugins repository. log-filter source remains in plugins/log-filter/, but it is not built or packaged; the loader rejects log_filter.dll because its filter is already built into the runtime.

Other targets

  • src/nevr_api/ — protobuf, generated into gen/cpp/ (just proto)
  • src/abi/ → libnevr_abi.a — the echovr.exe ABI surface: game types, function pointers, symbol IDs, CSymbol64 hashing
  • src/core/ → libnevr_core.a — our own primitives: logging, globals, base64, hooking, auth-token model, pch.h (links nevr_abi)
  • src/extension/ — header-only published C ABI for third-party plugins/modules
  • src/launcher/ → echovr_server.exe, a CreateProcess wrapper spawning echovr.exe -server -headless -no-console (a dedicated game server)
  • src/libovr-stub/ → LibOVRPlatform64_1.dll — Oculus platform stub, built separately from the community beta package
  • src/quest/ — separate Android/Quest arm64 target
  • src/legacy/ — frozen v1 implementations, self-contained; do not modify

Building

Requires CMake 4.0+, Ninja, and MinGW (x86_64-w64-mingw32-g++) to cross-compile from Linux. Dependencies come from the vcpkg manifest.

just                # list recipes
just build          # build desktop targets
just verify         # the full gate (main, release prep): build + tests under Wine + invariant sensors
just test-system-short        # quick Go system tests (needs the game binary)
just test-plugins-groundtruth # plugin tests without the game binary
just test-android              # Quest binary-shape checks
just dist           # the stripped release package (symbols split to dist/symbols/); a build with symbols is build/<preset>/bin/

Presets: mingw-debug, mingw-release (Linux default), debug, release (Windows). Output lands in build/<preset>/bin/.

just verify is the closed-loop gate for main when prepping a release (a PR runs the quick check, see AGENTS.md): it runs the build, C++ tests under Wine, Python harness tests, and source-invariant sensors.

Deployment

From build/mingw-release/bin/:

Artifact Destination
BugSplat64.dll game directory (replaces the crash reporter; the host)
nevr-runtime.dll game directory, beside BugSplat64.dll (the runtime)
echovr_server.exe game directory, alongside echovr.exe
Optional plugin DLLs plugins/ next to the game binary

The staged server package and its .tar.zst carry an empty plugins/ directory for optional operator plugins; the Windows zip (nevr-runtime-v<ver>-windows.zip) has no entry for it, so create plugins/ next to the game binary. Plugin DLLs are built separately and are not bundled. The community beta install guide covers installing the game client and uses BugSplat64.dll and nevr-runtime.dll.

For the community beta on Windows, follow docs/beta/INSTALL.md.

Repository layout

src/runtime/   nevr-runtime.dll — hooks, modes, crash recovery, gameserver; src/runtime/host/ is BugSplat64.dll
src/modules/       statically linked module implementations (platform-compat, token-auth)
src/abi/           libnevr_abi.a  — the echovr.exe ABI surface
src/core/          libnevr_core.a — our own primitives (links nevr_abi)
src/extension/     header-only C ABI published to third-party DLLs
src/nevr_api/      protobuf target
src/legacy/        FROZEN v1
src/legacy-compat/ two forwarding headers; frozen legacy needs them
plugins/           optional plugins
tools/             build and verify tooling
tests/             Go system suites (not part of `just verify`)
extern/            submodules: minhook, breakpad, lss
gen/               generated protobuf — do not hand-edit
docs/              see docs/README.md

Documentation

AGENTS.md Project conventions, build/test commands, and agent guardrails
CONTRIBUTING.md Build, verify, and submit a change
LICENSE Apache License 2.0
NOTICE Bundled third-party software notices
SECURITY.md Private vulnerability reporting
docs/ Standards, guides, reference, design, audits
docs/reference/verifying-a-release.md How an installer verifies a release: signed manifest, pinned keys, artifacts

Dependencies

vcpkg manifest (vcpkg.json): curl, gtest, ixwebsocket, nlohmann-json, miniupnpc, minhook, opus, protobuf.

Submodules in extern/: minhook, breakpad, lss.

Related projects

Project Description
nevr-runtime (this repo) Runtime patches for echovr.exe
nevr-runtime-plugins Gameplay and tooling plugins
nakama The community game service (echovrce)
revault Reverse-engineering data warehouse for the game binaries

Local configuration

The root CMakeLists.txt does not include cmake/local.cmake automatically. To use that file, enable its include in CMakeLists.txt; then a local post-build command can copy the DLL into a game directory:

set(GAME_DIR "/path/to/echovr/bin/win10")
add_custom_command(TARGET nevr_runtime POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:nevr_runtime> "${GAME_DIR}/nevr-runtime.dll"
    COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:nevr_host> "${GAME_DIR}/BugSplat64.dll")

About

Keeps Echo VR playable on the community service: one drop-in BugSplat64.dll for PC (Windows or Wine) and a Quest build, with Discord sign-in, the social lobby, friends and party, plus a dedicated game server.

Resources

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages