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.
| Event | Useful fields from the official API |
|---|---|
EVENT_ATTACK | targetId, damage, attackType |
EVENT_BUILD | targetId, amount, structureType, coordinates |
EVENT_REPAIR | targetId, amount, energySpent |
EVENT_UPGRADE_CONTROLLER | amount, energySpent |
EVENT_EXIT | destination 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.
| Evidence | When it exists | What it tells you |
|---|---|---|
| Action return code | Current tick | Whether the submitted command was accepted or rejected immediately |
Room.getEventLog() | Next script tick | Which events the engine recorded for the previous Room tick |
| Current object state | Current tick | What 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.eventbefore reading event-specificdata. - Match
objectIdandtargetIdwhen 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.