Skip to content

🎛️ Crafting — Modifiers

The Modifiers folder contains runtime components that implement ICraftingModifier. Attach them to GameObjects (typically the crafter/owner or a parent in its hierarchy) to dynamically influence crafting behaviour.

Modifiers mutate CraftAdjustments, not the recipe itself.

Truth-pass note: This README describes the modifier behaviour implemented by the current Crafting service. Where behaviour depends on service settings, that dependency is stated explicitly.


🎯 Purpose

Modifiers allow runtime changes to craft behaviour by adjusting:

  • Craft duration (durationSeconds)
  • Currency cost scaling (currencyMultiplier)
  • Output multipliers (outputMultiplier)
  • Additional bonus outputs (deterministic or chance-based)
  • Any other property reachable through CraftAdjustments

Modifiers do not modify RecipeCore data and do not perform side effects.


⏱ When modifiers run

When modifiers are enabled on the service (EnableModifiers == true), adjustments are computed:

  • During preflight evaluation (used for duration, cost, output, and space budgeting)
  • During accept/enqueue
  • Again at delivery time (so mid-craft changes can affect delivery-time outcomes)

This is service behaviour; modifiers must not assume a single invocation per craft attempt and should be idempotent.

Important: Modifiers do not change input requirements or currency definitions. Inputs are consumed exactly as defined by the recipe; currency is only scaled via multipliers.


⚙️ Modifier pipeline (current service behaviour)

Modifiers are applied in two layers inside the service:

1) Component modifiers (owner hierarchy)

  • The service collects ICraftingModifier components from the owner and its parents using GetComponentsInParent(true, list).
  • Discovery is cached per frame to reduce allocations.
  • Use ctx.stationTag to gate station/bench-specific behaviour.

2) Service-registered modifier hooks (internal)

The service also supports internal modifier hooks registered via AddModifier/RemoveModifier. These are not a public consumer extension surface; external consumers should prefer component modifiers.


🔒 Clamping rules (enforced by the service)

After modifier application, the service defensively clamps:

  • durationSeconds >= 0
  • currencyMultiplier >= 0
  • outputMultiplier >= 1

This prevents invalid adjustment values from propagating into job timing and cost math.


📦 Included modifiers

AddChanceOutputModifier

Adds a probabilistic extra output by appending to adj.chanceOutputs.

Notes: - Uses EnsureChanceOutputs() before adding entries. - Chance entries are rolled by the service (once per craft; batched crafts may use approximation when enabled). - Optional station-tag filter (trimmed, case-insensitive).

SimpleStationBonus

Station-gated modifier that: - multiplies adj.durationSeconds, and - optionally adds a deterministic extra output (+1 of the recipe’s first output) per craft.

Notes: - Uses EnsureExtraOutputs() before adding entries. - Optional station-tag filter (trimmed, case-insensitive).


🧩 Writing your own modifier

Implement:

public interface ICraftingModifier
{
    void Apply(ref CraftContext ctx, ref CraftAdjustments adj);
}

Example — 50% currency discount:

[DisallowMultipleComponent]
public sealed class DiscountModifier : MonoBehaviour, ICraftingModifier
{
    [Range(0f, 1f)] public float discount = 0.5f;

    public void Apply(ref CraftContext ctx, ref CraftAdjustments adj)
    {
        adj.currencyMultiplier *= Mathf.Clamp01(discount);
    }
}

💡 Best practices

  • Call adj.EnsureExtraOutputs() / adj.EnsureChanceOutputs() before adding outputs.
  • Use ctx.stationTag to restrict effects to specific benches or stations.
  • Keep logic allocation-light — modifiers may be invoked multiple times.
  • Avoid relying on execution order; modifiers should be composable.
  • Keep any cross-craft state (“every N crafts”) outside modifiers unless you manage it explicitly.

📁 Folder contents

File Description
AddChanceOutputModifier.cs Probabilistic bonus output modifier
SimpleStationBonus.cs Station-based duration and per-craft output bonus
(your modifiers) Any component implementing ICraftingModifier

Summary

Modifiers are the recommended runtime layer for perks, buffs, station effects, and tuning. They are adapter-friendly, composable, and integrated into the service’s preflight and delivery flow.