Skip to content

christophstrasen/WorldObserver

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

147 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

WorldObserver

A shared observation layer for Project Zomboid (Build 42) mods. - part of the DREAM family.

CI


Steam Workshop → [42SP] WorldObserver


WorldObserver is a cooperative world-sensing engine for Project Zomboid mods. Instead of hand-rolling OnTick scan batches, stitching together event listeners, and managing your own cache invalidation, you declare interestwhat should we observe, what guarantees for scope and freshness do we need?—and subscribe to ready-made observation streams.

This makes world-observation code compact and declarative. You compose readable pipelines and let the engine handle the execution.

The result is signal over noise: rather than processing raw world state, you consume fewer, more actionable observations that directly express what you actually care about.

Tradeoffs

With "WO", as with most high-level frameworks, you sacrifice some control over scope and timing that hand-rolled world-sensing logic provides, in exchange for a more compact, convenient, and expressive way to access a broad range of observations.

Use it for features like “corpse squares near the player”, “chef zombies in kitchens”, or “cars under attack”—and other situations that benefit from rich data and can tolerate asynchronous behavior.

Good for the players

When multiple mods would otherwise perform heavy scanning in parallel, WorldObserver can help them cooperate by merging overlapping interests, sharing the probing work, enforcing budgets and fairness, and keeping frame time predictable.


System Overview

Architecture overview

Quickstart

This example shows how you

  1. declare an interest (so WorldObserver knows what facts to gather)
  2. subscribe to a base observation stream
  3. stop cleanly (unsubscribe + stop lease)

Full walkthrough:

local WorldObserver = require("WorldObserver")

local MOD_ID = "YourModId"

-- note: duration in in-game seconds
local lease = WorldObserver.factInterest:declare(MOD_ID, "quickstart.squares", {
  type = "squares",
  scope = "near",
  target = { player = { id = 0 } }, 
  radius = { desired = 8 },     --tiles
  staleness = { desired = 4 },  -- typical duration between refresh
  cooldown = { desired = 10 },   -- time window in which emissions are suppressed
})

local corpseSquares = WorldObserver.observations:squares()
  :squareHasCorpse()          -- try removing this line if you see no output
  :distinct("square", 10)
  :subscribe(function(observation)
    local s = observation.square
    print(("[WO] squareId=%s x=%s y=%s z=%s source=%s"):format(
      tostring(s.squareId),
      tostring(s.x),
      tostring(s.y),
      tostring(s.z),
      tostring(s.source)
    ))

    -- Optional: brief visual feedback for the found square
    WorldObserver.highlight(s, 750, { color = { 1.0, 0.2, 0.2 }, alpha = 0.9 })
  end)

_G.WOHello = {
  stop = function()
    if corpseSquares then corpseSquares:unsubscribe(); corpseSquares = nil end
    if lease then lease:stop(); lease = nil end
  end,
}

The model (facts → observations → your logic)

  • Facts are discovered by WorldObserver (listeners + probes) into which your mod declared an interest.
  • Observation streams then emit plain Lua tables (“observations”) such as observation.square or observation.zombie
  • These can be used as-is or further refined by your mod

What you get (that’s painful to hand-roll)

  • Shared work and fairness: when multiple mods declare overlapping interests, WorldObserver merges leases and runs shared probing/listening work.
  • Safety settings: radius, staleness, cooldown let you express quality expectations while WorldObserver stays within budgets.
  • Signal over noise: helpers + distinct let you compact raw updates into “interesting observations” your mod can act on.
  • Composability: build derived streams by combining base streams (joins, windows, distinct). Start here: Derived streams.

Under the hood, WorldObserver is powered by LQR + lua-reactivex, but you can ignore that until you need derived streams:

Status and scope

  • Build: Project Zomboid Build 42 only.
  • Scope: v0 is singleplayer-first (player id 0).
  • Stability: approaching alpha; naming and shapes may still change.
  • Location in this repo: Contents/mods/WorldObserver/42/.

Documentation

Docs:

Internal docs:

  • docs_internal/vision.md
  • docs_internal/logbook.md

License

MIT

About

LQR‑powered world observation layer as modding resource for Project Zomboid lua mods

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors