Haul system¶
Haul jobs move stackable resources (wood_log, stone_brick) from the map into storage zones or from storage to buildings.
Flow¶
- Job creation – HaulJobCreator creates haul jobs when:
- Resources appear on the map after chop/mine (gather completion handler).
- Orphan resources are found outside storage (periodic scan, e.g. every 5s).
-
A building needs delivery (createResourceDeliveryJobs).
-
Reservation – Before creating a haul job, the client reserves space in a storage zone via ZoneManager.reserveStorageSpace(). The zone (StorageZoneDefinition) returns:
- Drop tile (where the colonist should deliver).
- Reservation id (released when the job completes or is cancelled).
-
Quantity – how much space was actually reserved (may be less than requested if the zone has limited room).
-
Job – HaulJob is created with that quantity as deliveryQty. The colonist will pick up only that amount from the source stack (partial pickup when storage has limited room).
-
Pickup – JobWorkExecution: colonist goes to the source tile and picks up. If deliveryQty is set and less than the stack size, the stack is split: the colonist carries deliveryQty, the rest stays on the ground. addHaulJobForLeftover() is called so the remaining stack gets its own haul job(s) later.
-
Drop – Colonist moves to the reserved drop tile. Drop logic (haulDropAndComplete):
- Merges into existing same-type stacks at the destination.
- If there is remainder and the colonist is not already on the reserved tile: tries reserveStorageSpace with preferTile (current position) so the colonist can drop in place when possible; otherwise redirects to another storage tile or to the nearest free tile outside all storage zones (findNearestFreeTileOutsideStorage) when no zone has room.
- If the colonist is already on the reserved tile (has reservation and same (x,y)): does not re-reserve (zone may report “full” due to other reservations); places remainder at that tile immediately.
- Reservation is released when the job completes or is cancelled.
Storage reservation (ZoneManager + StorageZoneDefinition)¶
- Full reservation – ZoneManager first tries zones that can fit the full requested quantity (by distance). If one accepts, that zone’s reserve() is used.
- Partial reservation – If no zone fits the full amount, it tries any zone with at least 1 free space. The zone may reserve less than requested (e.g. 10 when 30 was requested); the returned quantity is used as deliveryQty so the colonist only picks up 10 and leaves 20 on the ground.
- preferTile – When reserving from the drop path (remainder after merge), reserveStorageSpace is called with options.preferTile = colonist’s current tile. The zone prefers that tile when it has room, avoiding redirects when the colonist is already on a valid drop tile (e.g. single-tile or two-tile zones).
- Reserved state – reserved/reservations are in-memory only; they are cleared when zones are loaded from session and are not persisted on save.
- Reconciliation – Every 5s (IsometricMap tick), the client collects all storage reservation ids from active haul jobs and calls reconcileStorageReservations(activeReservationIds). Any reservation not in that set is released so stale reservations do not block space.
Edge cases¶
- Limited room (e.g. 10 free, 30 to pick up) – One job is created with deliveryQty = 10. Colonist picks up 10, delivers, and 20 stays at the source; a follow-up haul job for the leftover is created when the colonist does the partial pickup (addHaulJobForLeftover).
- Redirect – If the colonist has remainder and is not on the reserved tile, drop logic tries to reserve (with preferTile), then redirects to another storage tile or to the nearest free tile outside storage when no zone has room.
- Already at reserved tile – If the colonist has a reservation and is standing on the reserved drop tile with remainder, the code does not call reserveStorageSpace again (to avoid “no zone accepted” when the zone is full of other reservations); it places the remainder at that tile and releases the reservation.
- Drop outside storage – When no zone can accept the remainder, findNearestFreeTileOutsideStorage returns the nearest walkable tile outside all storage zones; the job’s destination is updated and the colonist drops there (no storage reservation).