Interface GameSnapshot


public interface GameSnapshot
Tick-scoped read view over the producer's published game snapshot.

Obtained from the host's snapshot accessor (slice 2 wires this through Client#snapshot()). All accessors read from the shared-memory buffer current at the time the snapshot was acquired. The producer flips buffers each tick, so a snapshot is only safe to use within the same logical work unit; do not cache across ticks or across acquisitions.

This interface intentionally exposes only what the producer publishes via SharedLayout.h — nothing here triggers an RPC. Mutations, config-type lookups, and anything that touches game logic live elsewhere.

  • Method Details

    • serverTick

      int serverTick()
      The server-tick counter: the 0.6-second game-logic step the server runs on.

      This is the clock to pace a script against. Respawn timers, cooldowns and drop cadence are all denominated in these ticks. Returns -1 until the producer has observed one (not yet in a world).

    • gameCycle

      int gameCycle()
      The client's own game-cycle counter: one per ~20 ms client main-loop iteration, roughly 30 per serverTick().

      This is the unit Projectile.startCycle() and Projectile.endCycle() are stamped in, so it is what ProjectileFilter.inFlightAt(int) expects. Reads 0 only until the client populates its transmission manager — it is already counting in the lobby, so 0 does not mean "not in a world"; serverTick() == -1 is that signal.

    • publishSeq

      long publishSeq()
      The producer's snapshot publish counter, incremented once per ~20 ms republish starting from 1 when the agent attached.

      Useful only for answering "has the snapshot advanced since I last looked". It shares gameCycle()'s cadence but not its number space, so the two must never be compared or subtracted, and it is not a tick — pacing off it runs ~30x fast. It was misnamed tickId() before wire protocol v18, which is exactly that bug.

    • gameState

      int gameState()
      Game client state. 10 = login, 20 = lobby, 30 = in-game; only at 30 is self() populated.
    • ownIndex

      int ownIndex()
      Local player's server index, or negative if not in-game.
    • self

      LocalPlayer self()
      The local player, or null if not currently in-game. Inspect gameState() or ownIndex() first if you need to distinguish login/lobby states.

      Read entirely out of shared memory, so LocalPlayer.currentHealth() / LocalPlayer.maxHealth() come back as LocalPlayer.HEALTH_UNKNOWN — those two live in varps and cost a pipe round-trip. Use GameAPI.getLocalPlayer() when you need health.

    • npcs

      NPC table accessor.
    • players

      Player table accessor.
    • locations

      Scene Location table accessor (doors / trees / rocks / scenery).
    • inventories

      Inventory table accessor.
    • groundItems

      Ground items table accessor (v15+).
    • projectiles

      In-flight projectiles table accessor (v17+).
    • sceneVersion

      int sceneVersion()
      Producer-side scene-shape version. Bumps whenever the streamed loaded_map_squares identity changes — region crossings, login, teleport. Use as a cache key on per-region structures derived from snapshot data; a change invalidates anything keyed on the prior scene.
    • dynamicRegion

      default DynamicRegion dynamicRegion()
      The scene's dynamic-region (instance) chunk-descriptor grid (v19+) — the table mapping each instance tile back to the static tile it was copied from. See DynamicRegion for what that buys you and for the units trap that catches everyone once.

      The returned region is a flyweight over the snapshot's shared memory and shares its tick lifetime; take a DynamicRegion.copyOf(DynamicRegion) if it has to outlive the tick.

      Defaults to DynamicRegion.STATIC so test doubles and hand-rolled stubs don't have to implement it. That default is the correct answer for a scene nobody modelled as an instance, not a placeholder; the live snapshot implementation overrides it.

    • isInterfaceOpen

      default boolean isInterfaceOpen(int ifaceId)
      Whether ifaceId is currently mounted in jag::InterfaceManager's open-subs hashmap — the engine's canonical "this interface is open right now" signal. Backed by the v14 SHM snapshot of the open-subs keyset (linear scan over a few dozen entries this tick); no RPC round-trip.

      A true is always conclusive. A false is conclusive only when isOpenInterfaceListComplete() holds: if the producer could not read the table, or the list was truncated, a missing id may still be open.

      Use this for chain gates that need to wait for a dialog to appear after a click that opens it (lodestone map, max-cape menu, dungeoneering cape teleport list). HUD-style interfaces that are always mounted while in-game (the minimap iface 1465 etc.) return true the whole session; a per-component "is this thing clickable" check is a separate question handled by Component.hidden().

      Defaults to false so test doubles / hand-rolled stubs don't have to implement it; the live GameSnapshotImpl overrides.

    • openInterfaceCount

      default int openInterfaceCount()
      How many open sub-interfaces this snapshot lists — the set isInterfaceOpen(int) searches. Never more than the producer's cap, so it can fall short of openInterfaceTotal().

      Defaults to 0 for test doubles; the live implementation overrides.

    • openInterfaceTotal

      default int openInterfaceTotal()
      How many sub-interfaces the client itself reports open this tick, or 0 when that could not be read. Compare with openInterfaceCount(), or use isOpenInterfaceListComplete().

      Defaults to 0 for test doubles; the live implementation overrides.

    • isOpenInterfaceListComplete

      default boolean isOpenInterfaceListComplete()
      Whether the open-interface list is known to be complete this tick: the client's count was readable and every entry made it into the snapshot. Only then is a false from isInterfaceOpen(int) proof that the interface is closed.
    • openInterfaces

      default List<OpenInterface> openInterfaces()
      Every open sub-interface this snapshot lists, with how each was opened (wire v23) — the same openInterfaceCount() entries isInterfaceOpen(int) searches, in the producer's order.

      The list is an immutable copy, so it may be kept past the tick. Like the ids, it can be incomplete; see isOpenInterfaceListComplete().

      Defaults to an empty list for test doubles; the live implementation overrides.

    • openInterface

      default Optional<OpenInterface> openInterface(int ifaceId)
      The open sub-interface ifaceId with its open type, or empty when it is not in this snapshot's list. api.snapshot().openInterface(517) .map(OpenInterface::isModal) asks whether the bank is open as a modal.

      Empty is conclusive only when isOpenInterfaceListComplete() holds, exactly as a false from isInterfaceOpen(int) is.

      Defaults to scanning openInterfaces().