DFO STUFF/Field notesAdd an idea
SOURCE REVIEW / 29 OCTOBER 2026

Where DFO Online can use fewer resources.

A closer look at repeated work on the client, database pressure on the server, and the changes worth measuring next.

Independent technical write-up·Source: a5604a632b ↗

The cost of asking again.

The strongest efficiency concern is repeated work: rediscovering what is nearby, visible, changed, or already known.

On the client, that work consumes the time available to draw a frame. On the server, it creates database traffic, processing that grows with crowds, and billable time spent awake. Large functions make improvements harder to isolate, but function length alone does not tell us where the resources go.

Reproduced: exercised in a local checkSource: visible in the pinned codeRecorded: measurements reported by the project
The useful question

What answer can be reused until the inputs change?

Spend the frame on what changes.

These five paths have concrete opportunities. The mechanisms are confirmed in the source; their relative impact on current hardware still needs profiling.

C1

Enemy obstacle probes multiply quickly.

Reproduced

A capsule probe is approximated with 27 rays: three points along the capsule, with nine rays at each point. An obstacle check can cast twice, and a fully blocked detour can try ten directions. Using the current enemy AI and collider against a small room with four blocking walls reproduced 540 ray queries in one detour call.

10directions×2capsule casts×27rays=540queries

This establishes a possible blocked case, not the cost of every corner encounter. It does not establish how many milliseconds those queries take in the live game.

Worth testing: reuse obstacle results within a step, budget detour searches across updates, and compare the ray bundle with a suitable swept-volume query. Thin walls, slopes, ledges, and corners need regression checks.

C2

One door can invalidate a shared index.

Reproduced

Removing a door’s collision bucket invalidates the collider-wide broad-phase spatial index. The next relevant query walks the remaining buckets to rebuild it, although their geometry did not change. A direct check confirmed that the dungeon’s triangle data and other buckets remain intact.

Worth testing: incrementally update the affected bucket’s index entries, or separate static geometry from frequently changing objects. “Rebuilding the entire dungeon’s collisions” overstates what currently happens.

C3

Indoor levels are submitted whole.

Source

The ordinary dungeon path submits its entire static batch and unbatched draw list without camera visibility culling. The building path has the same general shape. GPU clipping does not eliminate CPU submission and vertex-processing work.

Worth testing: partition large levels into spatial chunks or rooms and cull the camera’s draw set. Shadow visibility needs its own set; something outside the view can still cast a visible shadow.

Dungeon submission path ↗
C4

Cached shadows still need repeated bookkeeping.

Source

Shadow images are cached, but _staticSignatures still scans recorded geometry against selected lights every frame to decide whether those images changed. Candidate lists are rebuilt when needed in that frame. Additional indoor lights also perform signature scans.

Worth testing: retain spatial candidate sets between frames and invalidate them with geometry and light change generations. Preserve the existing fixes for shadow flicker, moved lights, and newly visible casters.

C5

Billboard batches still cost separate draws.

Source

Visible ordinary billboard batches are sorted by texture key, then each batch receives a draw call. Shared buffers and sorting reduce state changes, but do not combine those submissions. The source has a separate instanced low-poly-tree path; this observation concerns ordinary billboards.

Worth testing: merge compatible batches across pixels, or use texture arrays and instancing where appropriate. Transparency order, animation, and shadow behavior constrain which batches can share a draw.

Billboard draw and batch loop ↗

Fewer queries. Less time awake.

Server efficiency has at least three separate budgets: database work, relay processing, and active infrastructure time. A low-CPU service can still be expensive if its objects cannot sleep.

S1

Shared state is repeatedly read through personalized queries.

Source

Clients retrieve shared town state on their own schedules. Homes have a 60-second client cache, while homesInTown reconstructs town data alongside tenancy, guild, vote, and offer information. Different players pay much of the same query work to see the same town.

Worth testing: separate versioned shared snapshots from personal access information, refreshing the shared portion on changes. Personal responses cannot simply be cached for everybody, and authoritative checks must remain on actions.

S2

Established facts are reconstructed from witness records.

Source

regionGroundRead retrieves witness records, groups them, and interprets them in JavaScript. Today’s caching fix reduces repetition, but the cache is per isolate, expires after ten minutes, and does not retain empty results. Cold isolates can repeat the aggregation.

Worth testing: maintain a durable, incrementally updated summary of established regional facts. Ordinary reads can use that summary instead of reconstructing it from reports.

Ground cache and aggregation ↗
Recorded incident

The project’s October 29 record reports roughly 45,000–50,000 primary statements per minute during overload, and a regional-ground query reading about 123,000 rows per execution before the caching fix. Several fixes landed afterward. These are incident figures, not a fresh measurement of current service usage.

Read the incident record ↗
S3

Crowded relay rooms still multiply work.

Source + model

Each incoming pose scans the room’s peers before selecting recipients. Enemy-state delivery also scans the room. Above 32 listeners, nearest-player selection adds another linear pass and temporary arrays. Across moving players, this is approximately quadratic work within a room.

39,800potential recipient checks when 200 players each send one pose
≈59,000logical pose deliveries per second at 200 players × 4 poses/second, before batching

These are counts from the current fan rule and an all-in-range crowd model. They are not CPU timings or a production load test. Batching reduces WebSocket messages; it does not remove the earlier recipient-selection work.

Worth testing: maintain spatial interest groups and reusable recipient sets. Update membership when location meaningfully changes. Dense events also need explicit update priorities; a spatial index alone cannot thin a crowd where everyone is nearby.

S4

Long polls can keep quiet infrastructure billable.

Source

Shards keep outgoing polls open while holding sockets; the receiving bus holds a request and timer. Where that topology is used, both objects can remain non-hibernating even when doing little CPU work. Existing sleep changes help, so current savings depend on the deployed topology and traffic.

Worth testing: measure active duration by room type, consolidate quiet rooms, and investigate hibernation-compatible delivery. Removing polling without replacing its delivery guarantees would break behavior.

A single D1 database instance processes queries sequentially, so unnecessary work in the primary queue affects other requests too. Read replicas and batching already exist in DFO; the remaining question is how much frequently requested display state needs to enter that queue at all. Cloudflare’s D1 capacity explanation ↗

Measure a small change against the same scene.

These are engineering priorities, not measured promises of savings.

  1. 01
    For server capacity: shared-state reads.

    Rank routes by primary trips, database wait, rows read, and requests per active player. Split one frequently polled shared response from its personal fields.

  2. 02
    For hosting cost: time spent awake.

    Compare active duration by room type with useful work delivered. A CPU-only profile misses quiet objects held awake by pending work.

  3. 03
    For broad client gains: visibility and shadows.

    Capture CPU and GPU frame times in a town, a large dungeon, and a furnished interior. Count geometry submissions and shadow scans before changing them.

  4. 04
    For dungeon stalls: probes and index invalidation.

    Replay the same blocked enemies and moving doors. Count rays and index rebuilds, then compare frame-time spikes and collision answers.

Hold the camera path, scene, settings, and hardware steady. Change one mechanism at a time. Record the median, slow frames, allocations, and correctness—not just an average FPS number.

What this review establishes.

The source review was checked on October 29, 2026 against upstream a5604a632b. Local checks exercised the actual enemy AI and collider, confirmed index invalidation without losing other geometry, and inspected the current pose-fan rule. Twenty-nine focused existing physics tests passed.

No new live-game allocation profile, production load test, hosting analytics export, or current bill was collected. Project-recorded timings and incident counts are labeled separately. These findings identify work to measure and improve; they do not certify the largest current bottleneck on every device or server.

How the original claims hold up

The giant world function is real. At the pinned revision, bootWorld spans 33,176 physical lines, including comments and blanks. It runs at startup; its nested frame function spans 3,280 lines and runs repeatedly.

Dozens of per-frame helpers are also real. Twenty-eight named stage closures were deliberately introduced to keep the frame’s bytecode small enough for V8 to optimize. Their existence alone does not prove waste. “Thousands of throwaway objects every frame” was not verified for current source.

The source-text testing concern has support. An inventory found 4,495 test files; 2,601 contain both file-reading calls and regex assertions, and 479 reference the host-source concatenation helper. Those are structural counts, not a count of individual source-only tests. The suite also contains behavioral tests, and refactoring tooling already exists.

Some old performance notes are stale. Unchanged yard data no longer gets stringified every half second: current code checks the source-list identity first. Yard polling also slows when push updates are healthy. Neither old behavior belongs on a list of unfixed current defects.

Spotted something worth a closer look?

Share a concrete performance idea, a reproducible case, or a file and function to investigate. Community tips are suggestions, not verified findings.

Community feed …

Connecting

Loading community tips…

Posting rules & privacy

Keep ideas constructive and specific to DFO. Do not post passwords, account identifiers, private information, harassment, advertising, links, or copied material you do not have permission to share. Community tips are unverified.

Server-side controls include posting caps, duplicate detection, a timed form token, a bot-trap field, and text validation. Three reports from distinct network identifiers hide a tip pending review. Anonymous controls reduce abuse; they cannot guarantee every submission is trustworthy.

The application stores your tip, optional display name, category, time, and a keyed hash derived from your network address for abuse prevention. It does not save the raw address. Network hashes and reports older than 48 hours are removed during successful-post cleanup; tips older than 90 days are removed then too. The host may separately process connection logs. No advertising analytics are installed.

The feed shows the latest 40 visible tips and checks for changes every 30 seconds while this page is visible. An unavailable database closes submissions rather than bypassing the limits.