OBSERVABILITY · ROOM EVENT LOG

How to Read Room.getEventLog() Without Mixing Up Ticks

CURATED PATH

These links are maintained for a concrete prerequisite, failure mode, debugging step, or next lesson instead of generic topic similarity.

Debugging / Observability

Recommended next steps

Connect event evidence to error isolationFailure boundaryResolve actor and target IDsObject lookupMap event objects back onto the RoomVisualizationPromote critical events to rate-limited alertsAlerting
Verification statusOfficial API: Checked — previous-tick timing, parsed and raw modes, event structure, and event-specific data · Timing boundary: Current action return codes remain separate from the next tick's event log · JavaScript syntax: Checked for the focused examples in this guide

VERIFICATION

Evidence and test status

Official API
Checked — previous-tick timing, parsed and raw modes, event structure, and event-specific data
Timing boundary
Current action return codes remain separate from the next tick's event log
JavaScript syntax
Checked for the focused examples in this guide
Screeps Console test
Pending
Live multi-tick event verification
Pending
Last verified
August 30, 2026

Quick answer

room.getEventLog() returns events that happened in that Room during the previous tick. The default call gives you the parsed event array; room.getEventLog(true) gives you the raw JSON string.

Start simple: read the array, filter the event type you care about, then compare objectId and event-specific data fields when attribution matters. Do not use the current tick's event array as proof for an action you just submitted.

The log belongs to the previous tick

If your code is running at tick T, the events returned by getEventLog() belong to tick T - 1.

tick 100: your Creep repairs a Road

tick 101: room.getEventLog() can contain that repair event
          a repair submitted during tick 101 is not in that same array

This timing rule is the most important debugging boundary on the page. An immediate API return code answers whether the current command was accepted. The next tick's event log can tell you what event the engine recorded for the prior tick.

Read the parsed event array first

For normal debugging, use parsed mode. The first parsed access has JSON parsing cost; later parsed calls in the same tick reuse the cached result.

const ROOM_NAME = 'W1N1';
const room = Game.rooms[ROOM_NAME];

if (!room) {
  console.log(ROOM_NAME + ' is not visible this tick.');
} else {
  const events = room.getEventLog();

  console.log(JSON.stringify({
    eventTick: Game.time - 1,
    roomName: room.name,
    eventCount: events.length,
    eventTypes: events.map(event => event.event)
  }, null, 2));
}

Replace W1N1 with a Room that is visible now. An empty array means no events were returned for that previous-tick Room window; it does not describe older missed ticks.

Event data depends on the event type

Every event has an event constant, an objectId, and a data object, but the fields inside data depend on the event type.

EventUseful fields from the official API
EVENT_ATTACKtargetId, damage, attackType
EVENT_BUILDtargetId, amount, structureType, coordinates
EVENT_REPAIRtargetId, amount, energySpent
EVENT_UPGRADE_CONTROLLERamount, energySpent
EVENT_EXITdestination room and coordinates

Do not assume every event has a targetId. Check event.event before reading type-specific fields.

Match one actor and target when attribution matters

Suppose you want to verify that one specific Creep repaired one specific structure during the previous tick. Match the repair event, actor ID, and target ID together:

function findRepairEvent(room, repairerId, targetId) {
  return room.getEventLog().find(event =>
    event.event === EVENT_REPAIR
    && event.objectId === repairerId
    && event.data?.targetId === targetId
  ) ?? null;
}

const room = Game.rooms.W1N1;
const event = room
  ? findRepairEvent(
      room,
      'REPAIRER_OBJECT_ID',
      'TARGET_OBJECT_ID'
    )
  : null;

console.log(event);

When a match exists, event.data.amount and event.data.energySpent describe the recorded repair event. Keep the IDs you submitted or logged during the action tick so you are not guessing which actor or target produced a later event.

Use raw mode only when you need the string

Passing a truthy argument returns raw JSON instead of the parsed array. That is useful when your own code deliberately controls parsing or forwards the serialized payload.

const room = Game.rooms.W1N1;

if (room) {
  const raw = room.getEventLog(true);
  const parsed = JSON.parse(raw);

  console.log({
    rawType: typeof raw,
    parsedIsArray: Array.isArray(parsed),
    eventCount: Array.isArray(parsed)
      ? parsed.length
      : 0
  });
}

Do not mix the raw string and the parsed array in the same variable. For ordinary inspection, the default parsed mode is simpler.

Keep historical IDs when objects disappear

A valid previous-tick event can reference an object that is unavailable now. A Creep may have died, a structure may have been destroyed, or the object may no longer be visible. Game.getObjectById() returning null now does not erase the historical event.

Use current object lookup only as enrichment. Preserve the event's recorded IDs and fields even when current lookup is unavailable, and do not treat current my state as proof of historical ownership.

A missed event window cannot be replayed later

getEventLog() exposes the previous tick, not an arbitrary historical range. If your code did not read a visible Room's event window when it was available, a later call does not reconstruct all skipped ticks.

If continuity matters, store the last event tick you successfully processed and mark a gap when the next observed tick is not consecutive. You usually do not need a full ingestion ledger just to debug one action.

Keep optional history bounded

If you need trends, store small summaries rather than every raw event forever. For example, keep the latest observed tick and a bounded count by event type:

function summarizePreviousTick(room) {
  const events = room.getEventLog();
  const counts = {};

  for (const event of events) {
    const key = String(event.event);
    counts[key] = (counts[key] || 0) + 1;
  }

  Memory.roomEventStats ??= {};
  Memory.roomEventStats[room.name] = {
    eventTick: Game.time - 1,
    counts
  };

  return counts;
}

This replaces the previous summary for that Room instead of growing an unbounded array. Add a bounded incident list only when your own debugging workflow actually needs one.

Keep current action results and previous-tick events separate

When causality matters, record the current call's return code with the actor and target IDs. On the next tick, use the event log as a second observation.

EvidenceWhen it existsWhat it tells you
Action return codeCurrent tickWhether the submitted command was accepted or rejected immediately
Room.getEventLog()Next script tickWhich events the engine recorded for the previous Room tick
Current object stateCurrent tickWhat is visible now, not necessarily historical ownership or exclusive causality

Debugging checklist

  • Confirm the Room is visible now.
  • Label the returned array with Game.time - 1.
  • Use parsed mode unless you specifically need raw JSON.
  • Filter by event.event before reading event-specific data.
  • Match objectId and targetId when the event type actually provides a target ID.
  • Keep current action return codes separate from previous-tick event evidence.
  • Preserve historical IDs when current objects are unavailable.
  • Mark missed windows honestly instead of inventing backfill.
  • Keep long-term summaries bounded.

Use the RoomVisual debugging guide when you need to display current targets and state in the Room. Visuals show what your code draws now; they do not replace event evidence.

Official documentation

SOURCE AND SCOPE

Review the source, evidence, or next system

This English guide keeps the technical scope and verification boundaries of its Chinese source. The verification record shows which checks were completed and which runtime observations are still pending.