FOUNDATION · SAVED TARGET RESOLUTION

Resolve a Saved Screeps Target Without Guessing Why It Is Missing

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

Resolve IDs from Room Event LogPractical useCheck visibility when an object is missingVisibility boundaryPersist stable IDs instead of live objectsState design
Verification statusChinese source article: Reviewed in full · Official documentation: Checked against Game.getObjectById(), Game.rooms, and Memory object-ID guidance · Technical correction: Object lookup, visibility interpretation, type validation, invalidation, reselection, and actions are separated

VERIFICATION

Evidence and test status

Chinese source article
Reviewed in full
Official documentation
Checked against Game.getObjectById(), Game.rooms, and Memory object-ID guidance
Technical correction
Object lookup, visibility interpretation, type validation, invalidation, reselection, and actions are separated
JavaScript syntax
Passed by the editorial batch gate
Evidence level
Official documentation review, repository review, syntax checks, and static analysis only
Screeps Console test
Pending
Live multi-tick verification
Pending
Live local, remote-vision, removed-object, and wrong-type test
Pending
Last editorial review
July 31, 2026

Use this guide when

Use this page when Memory already contains a target reference and the current tick must decide whether that reference is usable. Target restoration should answer one question: what can be proven about this saved reference now? It should not also select a replacement, move a Creep, or delete task state.

Use the Memory guide when the first problem is deciding what data may be stored across ticks.

Store enough context to explain a null result

function saveStaticTarget(target, kind, assignmentVersion) {
  if (
    !target
    || typeof target.id !== 'string'
    || !target.pos
    || typeof kind !== 'string'
    || !Number.isInteger(assignmentVersion)
  ) {
    return null;
  }

  return {
    id: target.id,
    roomName: target.pos.roomName,
    kind,
    assignmentVersion,
    selectedAt: Game.time
  };
}

The API needs only the ID. The room name, kind, assignment version, and selection tick are project metadata. They make validation and diagnostics possible without serializing the live object.

A stored room name is most reliable for static targets such as Sources, Structures, and Construction Sites. A moving Creep can leave that room, so its lifecycle usually needs a name-based or movement-aware policy.

Return explicit restoration states

StatusWhat is knownSafe default
invalid-recordThe saved data does not match the project schema.Quarantine or clear this owned record.
wrong-kindAnother task schema is being read.Do not reinterpret it silently.
readyA current visible object passed the expected validator.Return it to task logic.
wrong-typeAn object was found, but it is not the expected target type.Clear or migrate the owned record.
vision-unavailableNo object was returned and the recorded room is not visible.Keep the reference until vision policy decides.
missing-visible-roomNo object was returned while the recorded room is visible.Invalidate a static-target reference.
missing-without-room-contextNo object was returned and the record cannot explain visibility.Require an explicit project policy.

Resolve first, then interpret null

function resolveSavedTarget(record, expectedKind, isExpectedObject) {
  if (
    !record
    || typeof record !== 'object'
    || typeof record.id !== 'string'
    || record.id.length === 0
  ) {
    return {
      status: 'invalid-record',
      target: null
    };
  }

  if (record.kind !== expectedKind) {
    return {
      status: 'wrong-kind',
      target: null
    };
  }

  const target = Game.getObjectById(record.id);

  if (target !== null) {
    return isExpectedObject(target)
      ? { status: 'ready', target }
      : { status: 'wrong-type', target: null };
  }

  if (
    typeof record.roomName !== 'string'
    || record.roomName.length === 0
  ) {
    return {
      status: 'missing-without-room-context',
      target: null
    };
  }

  return Game.rooms[record.roomName]
    ? {
        status: 'missing-visible-room',
        target: null
      }
    : {
        status: 'vision-unavailable',
        target: null
      };
}

The object lookup happens before the visibility interpretation. This allows a moving object that is currently visible somewhere else to be returned instead of being rejected solely because an older recorded room is not visible.

Validate the object required by this task

function isSource(target) {
  return Boolean(
    target
    && typeof target.id === 'string'
    && target.pos
    && Number.isFinite(target.energy)
    && Number.isFinite(target.energyCapacity)
    && Number.isInteger(target.ticksToRegeneration)
  );
}

This guard checks the fields used by a Source task. A Structure task should validate structureType; a Construction Site task should validate its progress fields. Do not accept any object merely because the ID resolved.

Keep cleanup and reselection in the caller

function getAssignedSource(creep) {
  const result = resolveSavedTarget(
    creep.memory.target,
    'source',
    isSource
  );

  if (result.status === 'ready') {
    return result;
  }

  if (result.status === 'vision-unavailable') {
    return result;
  }

  if (
    result.status === 'invalid-record'
    || result.status === 'wrong-kind'
    || result.status === 'wrong-type'
    || result.status === 'missing-visible-room'
  ) {
    delete creep.memory.target;
  }

  return result;
}

The resolver reports evidence; the caller owns mutation. This separation prevents a generic helper from selecting a new Source, deleting a remote assignment, or changing role state without the scheduler's consent.

Do not confuse target identity with temporary state

An empty Source still exists. A full Container still exists. A damaged Structure still exists. Resource amount, cooldown, ownership, reservation, and task suitability belong to business rules after identity restoration.

For example, a fixed miner can keep an empty Source assignment and wait for regeneration, while a dynamic harvester may ask the room scheduler for another active Source. Neither policy changes what Game.getObjectById() proved.

Use the identifier that matches the object lifecycle

TargetDurable referenceExtra context
Source, Structure, Construction SiteidRoom name, kind, assignment version
CreepUsually nameRole, assignment identity, expected owner
FlagnameExpected room and configuration version
RoomroomNameIntel timestamp and visibility state
PositionroomName, x, yPurpose and version

Verify each branch across real ticks

Capture one valid local target, one remote target without vision, one static target removed while its room is visible, one wrong-kind record, and one wrong-type record. Record only the status and the saved metadata needed to reproduce the branch. This revision contains static review and syntax checks; it does not contain a fabricated remote-vision transcript.

Choose another guide when

Use the dead-Creep Memory guide when a Creep name no longer exists. Use the global-cache guide when IDs are derived acceleration data rather than durable task assignments. Use the RoomVisual guide to draw the resolver status without changing it.

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.