Skip to content
 
 

Repository files navigation

⚠️ THIS REPOSITORY IS DEFUNCT

All active development has moved to the OpenWorld Discord server: https://discord.gg/5XzwZHFv

This repo is kept online as a historical reference only. It is no longer monitored, PRs and issues will not be reviewed here, and the information below may be out of date. If you want to contribute, capture traffic, or follow progress, please join the Discord linked above — that's where the project lives now.


OpenWorld Discord: Active New World Private Server Development

New World: First Light

Beware Aeternum Legacy

Tests Pages Test count Codecs Live decoder

A community effort to build a private server emulator for New World before Amazon shuts down the live service (~Dec 2026). The goal is to accept the real unmodified client binary, pass auth, and let a player enter a static world. No combat, NPCs, or persistence required for MVP. First Light is in reference to the territory "First Light" that was eventually removed from the game.

Live dashboard: nw-private-server.github.io/first-light — friendly project overview, captured-traffic charts, connection-state diagram, and the codec/decompile catalog. Mobile-friendly; auto-redeploys on push.

Recent milestones (newest first):

  • Destroy-event family sub-arc (wakes 278-285)0xFE476177 reframed from wake-9's "one writer, one hash, dead end" to a multi-handler picture: 4 emitter sites, 5 subscribers each writing distinct Carrier-state flags ([+0xcd] / [+0xcf] / [+0xda] / [+0xfd] / [+0x179]), and a ~50-hash event family constrained to the same EBus. Scheduler hypothesis at 1.5-2.0s delays (DAT_147efa330 is a float-delay table). 3 indirect-vtable walls now confirm the static-RE limit pattern for GridMate RPC (wakes 252/276/283). See state_machine_summary § A3.1 for the full hash list + flag map. Not a retrospective doc — sub-arc summarized in the live dashboard's Findings tab (cards: "Destroy-event scheduler", "Indirect-vtable wall pattern").
  • Fourth-stretch retrospective (wakes 228-253) — state-machine RE closure arc: all 4 post-V3 state-spawn transitions (10→11, 11→12, 12→13, 13→14) now have writers + trigger chains identified at static-RE level. Three Ghidra-driven findings (wakes 232/247/249), one documented wall (wake 252), and the candidate-triage methodology pattern proven. MVP server-side estimate: 3 messages minimum.
  • Third-stretch retrospective (wakes 197-227) — live-decoder coverage push to 90.0% (36/40) with the wake-221 floor decision, phase-2 emission swap + counter-advance extension, and the cross-check graph grown from 9 to 18 with five self-referential pins.
  • Second-stretch retrospective (wakes 151-196) — rep_responder ↔ dispatcher integration foundation, live-decoder coverage at 80% (32/40 captured wire-types decodable from the Explore tab), 7-test cross-check graph. Frozen wake-196 snapshot.
  • 150-wake session retrospective — wakes 1-150: 40/40 codec coverage, central dispatcher, state-10 RE breakthrough, audit arcs, 100% decompile cross-link density.

Design decisions:


Why this exists

Once the official servers go down, all knowledge of the wire protocol becomes much harder to reconstruct without live traffic to sniff. Captures made while the servers are still up are the single most durable thing a contributor can produce. We have one full login-to-state=53 capture (info/nw-login-safe-20260502-153840/); we still need more from different regions, character states, and especially extended in-world traffic. See docs/capture-guide.md.


Current status (2026-05-11)

Gate Description Status
1 Auth flow (HTTPS / OmniSDK / character creation) Complete
2 Javelin REP — DTLS handshake + V3 registration V3 response accepted by client; rep.ready flips 0→1; client then re-sends V3 every ~500ms anyway and the session is destroyed after ~30s. That retry loop is the active blocker. Infrastructure for the next experiment landed since 2026-05-05: the rep_responder ↔ central-dispatcher integration arc is shipped behind two feature flags (heartbeat_use_dispatcher for emission swap, heartbeat_advance_counter for counter mutation), both default off and proven byte-equivalent to the captured replay path. Real-GPU validation will flip them and observe the retry loop. Post-V3 state-machine picture (wake 252 update): states 10→14 form the player-spawn ladder, and all 4 transition writers + trigger chains are now RE'd. State-10→11 (PlayerManagerSelfIdentificationMsg, wake 112), 11→12 auto-fires once 10→11 lands, 12→13 (LevelInfoChangedMsg primary path, wake 232/234), and 13→14 (wakes 247/249): writer FUN_142ffbc50 fires from 5 local state-update handlers; one explicitly copies a 0x70-stride collection from an upstream container into wrapper[+0x1b8] and re-evaluates the gate. MVP server-side estimate: SelfIdent + LevelInfoChanged + a replica-creation message (likely GridMate NewProxy carrying the player's actor) — 3 server messages minimum. Static-RE is now exhausted on this question (wake 252): tracing the upstream of the collection-copy handler hits an indirect-vtable wall at 0x14816cec0, so identifying the specific replica-creation wire-type is now a runtime-dependent step. The gating blocker is the same for both the phase-2D experiment and the NewProxy identification: a real-GPU Windows host running a Frida trace. See analysis/state_13_14_writer_investigation.md for the full wake-241 → 247 → 249 → 252 arc.
3 World streaming (post-registration server messages) Not started
4 Input / movement / actor replication Not started

For background, the running session log is in docs/progress.md and the latest blocker description is in docs/next-session.md. These are working notes for the maintainers' working sessions — read them for context, but don't worry about updating them.


What the project needs most right now

  1. Real-GPU Windows host with Frida — the single highest-leverage unblocker. The Gate-2 row above explains why: static-RE on the state-spawn ladder is exhausted (all 4 transition writers + trigger chains are RE'd; the wake-252 indirect-vtable wall is the limit). Two open questions both need runtime traces on a real-GPU host — (a) does the wake-204/208 phase-2D dispatcher emission affect the retry loop? (b) which specific wire-type carries the NewProxy/replica-creation message that fires state-13→14? AWS g4dn.xlarge is the recommended path (Tesla T4, Windows Server license, ~$0.75/hr); a physical Windows host works equally well.
  2. Captures with in-world traffic. Our existing capture goes through state=53 (past WaitingForPlayerSpawn) but stops before extended in-world activity. A session that loads into a running world AND captures movement/combat/zone-transition messages is the single most useful new capture. See docs/capture-guide.md for the priority list.
  3. Identify the 0xFE476177 broadcast-event name — either via runtime Frida hook OR via an O3DE-source corpus brute-force (wakes 278-280 reshaped this from a one-shot dead end to a tractable multi-prize hunt). The picture as of wake 280: 0xFE476177 is a general-purpose Carrier lifecycle event fired from at least 4 emitter sites (all using the pattern local=0xFE476177; vtable+0x608(arg, DAT_147efa330)) and received by at least 5 subscribers each writing a distinct Carrier-state flag at offsets [+0xcd], [+0xcf], [+0xda], [+0xfd] (the wake-8 destroy flag — one subscriber response among many), and [+0x179]. The full event family spans ~50 related AZ::Crc32 hashes. A Frida hook on any emitter or subscriber would log all family event names from a live session; alternatively, analysis/crc32_FE476177_brute_force.py is ready to take a wordlist grep'd from public O3DE source. See analysis/state_machine_summary.md § A3.1 for the full hash list + Ghidra decomps.
  4. Python/server contributors. SelfIdent codec wired at wake 112; phase-2D dispatcher emission shipped behind heartbeat_use_dispatcher (wake 204) + heartbeat_advance_counter (wake 208) flags awaiting real-GPU validation. Remaining: multi-peer support in server/rep_responder.py (currently single-peer); Carrier-level reliable ACK on the V3 request itself (a 5-line experiment that may be the entire fix); next wire-type promotion candidate beyond heartbeat (search _shadow_decode_record callers in test_shadow_decode.py).

Repository layout

server/          Core server implementation
  auth_mock.py     HTTPS auth gateway mock (handles all client auth endpoints)
  rep_responder.py DTLS-terminating Javelin REP server (the game server stub)
  javelin/         Javelin protocol library
    frame.py         Message framing — parse_datagram / marshal_datagram
    bitstream.py     Bit-level I/O (aligned + unaligned)
    v3_request.py    RegistrationRequestV3Msg parser
    v3_response.py   RegistrationResponseMsg encoder
    replay_store.py  Loads captured message dumps for replay

tools/           Standalone utilities (capture, analysis, RE helpers)
  client-hooks/    Game-binary-interacting tools (Frida, d3d11 proxy) — kept separate from the server code
docs/            Protocol documentation and session notes
analysis/        Ghidra findings, decompilation artifacts, hex decode notes
capture/         Local session logs (not committed — see .gitignore)
info/            Community-shared captures and reference data

Quick start

Prerequisites

  • Windows, x64. The full capture flow targets the Windows build (the server stack itself runs anywhere Python does).
  • Python 3.11 or 3.12 (python3-dtls is broken on 3.13).
  • A non-EAC build of New World — the live Steam build refuses runtime instrumentation. Any copy of NewWorld.exe that you launch directly via frida.spawn(NewWorld.exe) works (skipping the launcher chain skips EAC). Steam still needs to be running and logged in.
  • OpenSSL on PATH (one-time, for cert generation).
  • Admin PowerShell for the certutil and hosts-file steps.

Set up once

# Project root, Administrator PowerShell:
python3.12 -m venv .venv
.venv\Scripts\Activate.ps1
pip install frida-tools pyOpenSSL pytest pytest-timeout

# Generate the self-signed CA + auth/server certs the local stack uses:
python tools\generate_auth_certs.py
python tools\generate_cert.py

# Trust the CA so the game's HTTPS client accepts the auth_mock:
certutil -addstore -f "ROOT" server\certs\newworld_ca.crt

# Redirect Amazon's auth hostnames to 127.0.0.1 (i.e. the local auth_mock):
python tools\setup_hosts.py --apply

Run the mock stack and capture packets

# Terminal 1 — HTTPS auth mock on port 443 (admin)
python -m server.auth_mock --port 443

# Terminal 2 — Javelin REP server on UDP 24083
python -m server.rep_responder

# Terminal 3 — the game, spawned under Frida with the trust bypass
python tools\client-hooks\frida_capture.py `
    --exe "C:\path\to\NewWorld\Bin64\NewWorld.exe" `
    --name session1

Captured packets land in capture/<timestamp>_session1/packets/ (one binary file per packet), packets.jsonl (metadata), and session.log (event timeline).

For the full step-by-step capture walkthrough including the gotchas (Steam launch-context, Frida 17 API, expected hook output), see tools/client-hooks/README.md. For what to capture, what to redact before sharing, and how to submit captures back, see docs/capture-guide.md.

Run the tests

pip install pytest
pytest

CI runs the same suite on Python 3.11 and 3.12 for every push and PR (see .github/workflows/tests.yml). New captures dropped under info/<name>/messages-redacted.txt are auto-validated by server/test_captures.py — no test registration needed.


Key protocol references


Mirrors and resilience

This repository is the primary home for the project, but the code should outlive any single hosting platform. If you want to keep a mirror:

Codeberg (EU non-profit, recommended):

git remote add codeberg https://codeberg.org/<your-org>/first-light.git
git push codeberg main

Self-hosted Forgejo/Gitea:

git remote add self https://<your-host>/first-light.git
git push self main

You can push to multiple remotes at once by adding them all to the origin push URL:

git remote set-url --add --push origin https://codeberg.org/<your-org>/first-light.git

If you maintain a mirror, please keep the info/ captures synced — that data is the hardest to reconstruct after shutdown.


Contributing

See CONTRIBUTING.md — has a quick-start (clone → venv → pytest → decode_message.py) plus the reference doc list. The short version:

  • Have a game capture? → Follow docs/capture-guide.md and open a PR or share in the community channel.
  • Have RE findings? → Drop them in analysis/ as a new .md or .txt file (look at existing entries for the format).
  • Writing code? → One function at a time; keep changes testable. See analysis/codec_library_overview.md for the codec library structure and "how to add a new codec" walkthrough.

About

No description, website, or topics provided.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages