Quick answer
Recover one owned active Factory, resolve the requested product through COMMODITIES, require every component amount, enough output capacity, zero cooldown, the correct Factory level, and the required active PWR_OPERATE_FACTORY effect for level commodities. Disable the one-time request before factory.produce(resourceType), then compare output, component Stores, and cooldown afterward.
Read the recipe from COMMODITIES
function getCommodityRecipe(resourceType) {
if (typeof resourceType !== 'string') {
return null;
}
const recipe = COMMODITIES[resourceType];
return recipe
&& Number.isInteger(recipe.amount)
&& recipe.amount > 0
&& recipe.components
? recipe
: null;
}
The recipe may include level and cooldown. Use the current constant rather than copying a static table into Memory.
Check every component
function getMissingComponents(factory, recipe) {
return Object.entries(recipe.components)
.map(([resourceType, required]) => ({
resourceType,
required,
available:
factory.store.getUsedCapacity(resourceType)
}))
.filter(item => item.available < item.required);
}
The Factory Store is shared by components and products. Component logistics must not remove required inputs after the preflight snapshot.
Check output capacity
function canStoreCommodity(
factory,
resourceType,
amount
) {
return factory.store.getFreeCapacity(resourceType)
>= amount;
}
Even with every component present, production fails when the Store cannot receive the recipe output amount.
Match Factory level and Power effect
function getOperateFactoryEffect(factory) {
return factory.effects?.find(effect =>
effect.effect === PWR_OPERATE_FACTORY
&& effect.ticksRemaining > 0
) ?? null;
}
function hasRequiredFactoryLevel(factory, recipe) {
if (!Number.isInteger(recipe.level)) {
return true;
}
const effect = getOperateFactoryEffect(factory);
return factory.level === recipe.level
&& effect?.level === recipe.level;
}
Level-less commodities do not require an operated Factory. Level commodities require both the Factory level and the matching active effect.
Build a testable production plan
function evaluateProduction(factory, resourceType) {
if (!factory) {
return { ready: false, reason: 'factory-missing' };
}
const recipe = getCommodityRecipe(resourceType);
if (!recipe) {
return { ready: false, reason: 'recipe-invalid' };
}
if (factory.cooldown > 0) {
return { ready: false, reason: 'factory-cooling-down', recipe };
}
if (!hasRequiredFactoryLevel(factory, recipe)) {
return { ready: false, reason: 'factory-level-mismatch', recipe };
}
const missing = getMissingComponents(factory, recipe);
if (missing.length > 0) {
return {
ready: false,
reason: 'components-insufficient',
recipe,
missing
};
}
if (!canStoreCommodity(
factory,
resourceType,
recipe.amount
)) {
return { ready: false, reason: 'output-full', recipe };
}
return {
ready: true,
reason: 'ready',
recipe,
missing: []
};
}
Complete one-time produce example
State impact: this code may schedule one real Factory production action and writes a request snapshot. It never retries automatically.
function getOwnedActiveFactory(id) {
const factory = typeof id === 'string'
? Game.getObjectById(id)
: null;
return factory
&& factory.structureType === STRUCTURE_FACTORY
&& factory.my === true
&& factory.isActive() === true
? factory
: null;
}
module.exports.loop = function () {
const request = Memory.factoryProduceRequest;
if (!request || request.enabled !== true) {
return;
}
const factory = getOwnedActiveFactory(request.factoryId);
const plan = evaluateProduction(
factory,
request.resourceType
);
request.lastCheckedAt = Game.time;
request.lastStatus = plan.reason;
if (!plan.ready) {
request.preview = {
missing: plan.missing ?? [],
recipeLevel: plan.recipe?.level ?? null,
factoryLevel: factory?.level ?? null,
cooldown: factory?.cooldown ?? null
};
return;
}
request.enabled = false;
request.submittedAt = Game.time;
request.snapshot = {
factoryId: factory.id,
resourceType: request.resourceType,
outputAmount: plan.recipe.amount,
outputBefore:
factory.store.getUsedCapacity(request.resourceType),
componentsBefore: Object.fromEntries(
Object.keys(plan.recipe.components).map(type => [
type,
factory.store.getUsedCapacity(type)
])
),
cooldownBefore: factory.cooldown,
factoryLevel: factory.level,
effect: getOperateFactoryEffect(factory)
};
const result = factory.produce(request.resourceType);
request.result = result;
request.resultAt = Game.time;
request.status = result === OK
? 'accepted-pending-verification'
: 'failed-review-required';
};
Verify Store and cooldown afterward
function verifyProduction(request) {
const snapshot = request?.snapshot;
const factory = getOwnedActiveFactory(
snapshot?.factoryId
);
if (!snapshot || !factory) {
return { verified: false, reason: 'snapshot-or-factory-missing' };
}
const outputNow = factory.store.getUsedCapacity(
snapshot.resourceType
);
return {
verified:
request.result === OK
&& outputNow >= snapshot.outputBefore
+ snapshot.outputAmount,
outputDelta: outputNow - snapshot.outputBefore,
cooldownNow: factory.cooldown
};
}
Haulers or another production module can change the Store before verification. Coordinate ownership of Factory actions and component logistics.
Handle return codes
| Code | Meaning |
|---|---|
OK | Production scheduled |
ERR_NOT_ENOUGH_RESOURCES | A required component is missing |
ERR_INVALID_TARGET | The Factory cannot produce that level commodity |
ERR_FULL | The Store cannot receive the product |
ERR_INVALID_ARGS | The resource is not a valid commodity |
ERR_TIRED | The Factory is cooling down |
ERR_RCL_NOT_ENOUGH | The Factory is inactive at the current RCL |
Debugging checklist
- Recover an owned active Factory.
- Read the current recipe from
COMMODITIES. - Check every component.
- Check product capacity.
- Check cooldown.
- Match recipe level, Factory level, and active Power effect.
- Disable before calling.
- Save component and output snapshots.
- Record the exact return code.
- Verify Store delta and cooldown later.
Scope and next steps
This guide does not implement commodity chains, component hauling, Power Creep scheduling, market profitability, multi-Factory allocation, or production forecasting.
Frequently asked questions
Can a level-zero Factory produce level commodities?
No. It needs the matching Factory level and active Power effect.
Can a Factory level be changed?
The official API says it cannot be changed after it is set.
Should a failed production request retry every tick?
No. Review current components, capacity, cooldown, and Power state first.
Does recipe cooldown prove success?
It supports verification, but compare Store deltas as well.