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.
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.
- 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 indocs/reference/legacy-translator.mdis 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.mdand 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.
- 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.
- 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.
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.
- 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. Aconfig.yamloverrides them, on the PC next to the game and on the Quest in the app's files folder (docs/reference/example-config.yamllists 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.
-windowedruns the game in a window with the headset checks patched out. (PC) - Works on Wine and Proton. Wine is detected; the
_tempdirectory fix and-no-consoledefault apply. (PC) Tested clean: Proton Experimental 11.0 and Wine 11. Proton 8.0 (8.0-103) crashes in its owndxgi.dllright after the graphics device is created, with the stockBugSplat64.dlltoo, 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.exeis refused. A wrong or damaged game image is refused instead of patched. (PC)
- 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)
- 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 underarena.*. (PC)
- 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 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)
- Structured logs. One JSON line per event:
nevr-boot.jsonlinlogs\of the game folder, a timestampednevr-<timestamp>.jsonlunder%LOCALAPPDATA%\EchoVR\logsand the host'snevr-bootstrap.jsonlunder%LOCALAPPDATA%\nevr\echovr\logson PC (every PC file is listed in "Files the runtime uses"); logcat tagNEVR-Sentinelandnevr-sentinel.logon 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-exportsrecords the platform DLL calls. (PC) - Hardware dump. A one-time hardware and environment dump file on request. (Quest)
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.
-serverimplies headless and no OVR; headless graphics need no GPU;echovr_server.exestarts 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)
- 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_metaanddiagnostics.hardware_dumpinconfig.yamlchange 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)
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).
- Sync the device clock first (PC: Windows time sync; Quest: automatic time on), so PC and Quest logs line up afterwards.
- Windows: take
nevr-runtime-v<X.Y.Z>-windows.zipfrom the release (CI builds it from the tagvX.Y.Z), close the game, unzip it, and runinstall.ps1from PowerShell (powershell -NoProfile -ExecutionPolicy Bypass -File install.ps1). It checks the package againstSHA256SUMS, copies your originalBugSplat64.dlltoBugSplat64.dll.original-<timestamp>, renames a legacydbgcore.dlltodbgcore.dll.legacy-<date>and installs the two new files. It deletes nothing. - Uninstall:
uninstall.ps1 -Dir <bin\win10>restores both and keeps the backups. - 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 byjust package-dev) is published outside GitHub; download it and install it withadb install -r. It is signed with the same key as earlier test builds, so it installs over them and keeps your data. - Windows Defender or SmartScreen may warn about a file that carries no signature.
Get-AuthenticodeSignature .\BugSplat64.dll(PowerShell) says whether a file is signed.
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:
- Uninstall Echo VR from the headset once (
adb uninstall com.readyatdawn.r15, or from the headset's app library). - 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/readyatdawnand 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 underAndroid/media/com.readyatdawn.r15/filesis 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.
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).
| 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 |
_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 |
| 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 |
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 |
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.
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 |
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.
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.
src/nevr_api/— protobuf, generated intogen/cpp/(just proto)src/abi/→libnevr_abi.a— the echovr.exe ABI surface: game types, function pointers, symbol IDs, CSymbol64 hashingsrc/core/→libnevr_core.a— our own primitives: logging, globals, base64, hooking, auth-token model,pch.h(linksnevr_abi)src/extension/— header-only published C ABI for third-party plugins/modulessrc/launcher/→echovr_server.exe, aCreateProcesswrapper spawningechovr.exe -server -headless -no-console(a dedicated game server)src/libovr-stub/→LibOVRPlatform64_1.dll— Oculus platform stub, built separately from the community beta packagesrc/quest/— separate Android/Quest arm64 targetsrc/legacy/— frozen v1 implementations, self-contained; do not modify
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.
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.
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
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 |
vcpkg manifest (vcpkg.json): curl, gtest, ixwebsocket, nlohmann-json,
miniupnpc, minhook, opus, protobuf.
Submodules in extern/: minhook, breakpad, lss.
| 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 |
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")