Skip to content

Containers

containers is a finite-capacity holder for multiple content types. It owns capacity math only: fit checks, fills, partial fills and drains.

ts
import { containers, type ContainersData } from "@idlekitjs/mechanics/containers";

Mental model

A container has a finite capacity. Contents are stored by content id:

ts
type ContainerContents = Record<string, number>;
type ContainersData = Record<string, ContainerContents>;

Amount and occupied volume can differ. By default, one unit uses one capacity unit. A container can provide volumeOf(contentId, state) to make some content larger or smaller.

used = sum(amount * volumeOf(contentId))

Minimal example

ts
import { containers, type ContainersData } from "@idlekitjs/mechanics/containers";

interface State {
  storage: ContainersData;
  bonusCapacity: number;
}

const bins = containers<State>({
  definitions: [
    { id: "scrap-bin", capacity: 10 },
    {
      id: "vault",
      capacity: (state) => 6 + state.bonusCapacity,
      volumeOf: (contentId) => (contentId === "gem" ? 2 : 1),
    },
  ],
  getData: (state) => state.storage,
  setData: (state, storage) => {
    state.storage = storage;
  },
});

engine.use(bins);

bins.fill(state, "scrap-bin", "scrap", 3);
bins.used(state, "scrap-bin"); // 3
bins.free(state, "scrap-bin"); // 7

API

ts
bins.capacity(state, "scrap-bin");
bins.used(state, "scrap-bin");
bins.free(state, "scrap-bin");
bins.contents(state, "scrap-bin");

bins.canFit(state, "scrap-bin", "scrap", 2);
bins.fill(state, "scrap-bin", "scrap", 2);
bins.fillUpTo(state, "scrap-bin", "scrap", 20);
bins.drain(state, "scrap-bin");
bins.drain(state, "scrap-bin", { contentId: "scrap" });
bins.drain(state, "scrap-bin", { contentId: "scrap", amount: 2 });
MethodBehavior
capacityCurrent capacity. Dynamic capacities are evaluated from state.
usedOccupied capacity. Unknown containers report 0.
freecapacity - used. Can be negative if dynamic capacity shrank.
contentsSnapshot of current contents. Unknown containers report {}.
canFitWhether an amount fits now. Amount defaults to 1.
fillAll-or-nothing fill. Returns false without mutation when it does not fit.
fillUpToAdds what fits up to the requested amount and returns the accepted amount.
drainRemoves everything, one content type or up to an amount.

drain returns { removed, remaining }.

Runtime behavior

Definition mistakes throw at wiring time: duplicate container ids and invalid static capacities are bugs.

Unknown container ids are safe at runtime:

  • reads report empty or 0;
  • fill returns false;
  • fillUpTo returns 0;
  • drain removes nothing.

Bad fill amounts (0, negative, non-finite) fail without mutation. A dynamic capacity or volumeOf returning an invalid number throws at call time.

Economy adapter

The optional bridge lives at @idlekitjs/mechanics/containers/economy.

ts
import {
  containerContentResources,
  containerFreeSpaceResource,
  containerHasSpace,
} from "@idlekitjs/mechanics/containers/economy";

containerHasSpace(containers, containerId, contentId, amount?) is the natural requirement for deposit or collect transactions.

containerContentResources exposes stored content amounts as Economy resources. Credits go through fill, so transactions should gate capacity with containerHasSpace.

containerFreeSpaceResource exposes remaining capacity as a read-only resource.