Skip to content

Architecture Overview

This document describes the high-level architecture of Ansible Crafting, its package structure, key classes, and data flows.

See also: Development Guide for building and testing, Guidelines for coding conventions.


High-Level Architecture

Ansible Crafting is a client-server Fabric mod that scans nearby inventories on the server, syncs the data to the client for display, and handles crafting requests that pull items from remote containers.

flowchart TB
    subgraph Server Side
        SCANNER["InventoryScanner<br/>Scans nearby blocks"]
        AGG["AggregatedInventory<br/>Merges all inventories"]
        STATE["InventoryStateManager<br/>Persistent enable/disable"]
        CRAFT["RemoteCraftingHandler<br/>Extracts items from containers"]
        SESSION["CraftingSessionManager<br/>Tracks active crafting sessions"]
    end

    subgraph Network
        SYNC_PKT["InventorySyncPacket<br/>Item data → client"]
        STATE_PKT["InventoryStateSyncPacket<br/>Enable/disable states → client"]
        TOGGLE_PKT["InventoryToggleRequestPacket<br/>Toggle request → server"]
        RESYNC_PKT["StateResyncRequestPacket<br/>Resync request → server"]
    end

    subgraph Client Side
        CACHE["ClientInventoryCache<br/>Stores synced item data"]
        PANEL["InventoryPanelWidget<br/>Side panel UI"]
        HIGHLIGHT["HighlightRenderer<br/>Block outline highlights"]
        OVERLAY["InventoryOverlayRenderer<br/>Wifi status icons"]
        SHADER["ShaderCompat<br/>Shader mod detection"]
        TRACKER["InventoryPanelTracker<br/>Panel lifecycle"]
        TEXTURES["AnsibleCraftingTextures<br/>Texture identifiers"]
    end

    subgraph Integrations
        EMI["EMI Plugin<br/>Recipe transfer + exclusion zones"]
        REI["REI Plugin<br/>Recipe transfer + exclusion zones"]
    end

    SCANNER --> AGG
    AGG --> SYNC_PKT
    STATE --> STATE_PKT
    SYNC_PKT --> CACHE
    STATE_PKT --> CACHE
    CACHE --> PANEL
    PANEL --> HIGHLIGHT
    TOGGLE_PKT --> STATE
    RESYNC_PKT --> STATE
    EMI --> CRAFT
    REI --> CRAFT
    CRAFT --> SESSION

Package Structure

com.ansiblecrafting/
├── AnsibleCraftingMod              # Server-side mod entry point (ModInitializer)
├── client/                          # Client-only code (@Environment(CLIENT))
│   ├── AnsibleCraftingClient        # Client entry point (ClientModInitializer)
│   ├── AnsibleCraftingTextures      # Texture identifier constants
│   ├── ClientInventoryCache         # Stores synced inventory data on client
│   ├── HighlightRenderer            # Renders block outline highlights
│   ├── InventoryOverlayRenderer     # Renders wifi status icons on blocks
│   ├── ShaderCompat                 # Detects shader mods (Iris/Oculus) via reflection
│   └── ui/
│       ├── InventoryPanelWidget     # The side panel showing available items
│       └── InventoryPanelTracker    # Tracks panel lifecycle across screens
├── config/
│   ├── ModConfig                    # All configuration options (Cloth Config)
│   └── ModMenuIntegration           # Mod Menu config screen provider
├── crafting/
│   ├── CraftingSessionManager       # Manages active crafting sessions per player
│   ├── RemoteCraftingHandler        # Extracts/inserts items from remote containers
│   ├── CombinedPlayerInventory      # Merges player + remote inventories for recipes
│   ├── VirtualInventory             # Fake inventory for recipe viewer integration
│   ├── VirtualSlot                  # Fake slot for recipe viewer integration
│   └── GridSlotSourceHolder         # Interface for tracking grid slot item sources
├── integration/
│   ├── emi/
│   │   ├── AnsibleCraftingEmiPlugin         # EMI plugin registration
│   │   ├── AnsibleCraftingRecipeHandler     # EMI recipe transfer handler
│   │   └── AnsibleCraftingEmiExclusionArea  # EMI exclusion zone for panel
│   └── rei/
│       ├── ReiPlugin                        # REI plugin registration
│       ├── ReiTransferHandler               # REI recipe transfer handler
│       └── ReiExclusionZoneProvider         # REI exclusion zone for panel
├── inventory/
│   ├── InventoryScanner             # Scans nearby blocks for inventories
│   ├── AggregatedInventory          # Merges contents of all scanned inventories
│   ├── InventoryStateManager        # Persistent per-inventory enable/disable state
│   └── StorageBackedInventory       # Wraps Fabric Storage API as Inventory
├── mixin/
│   ├── CraftingScreenHandlerMixin           # Injects remote crafting into handler
│   ├── AbstractRecipeScreenHandlerMixin     # Extends recipe handler for remote items
│   └── client/
│       ├── CraftingScreenMixin              # Injects panel into crafting screen
│       └── ContainerScreenMixin             # Injects panel into container screens
└── network/
    ├── InventorySyncPacket          # Server → Client: synced item data
    ├── InventoryStateSyncPacket     # Server → Client: enable/disable states
    ├── InventoryToggleRequestPacket # Client → Server: toggle inventory
    └── StateResyncRequestPacket     # Client → Server: request state resync

Key Data Flows

Inventory Scanning and Sync

sequenceDiagram
    participant Server as Server (tick loop)
    participant Scanner as InventoryScanner
    participant Agg as AggregatedInventory
    participant Net as Network
    participant Cache as ClientInventoryCache
    participant Panel as InventoryPanelWidget

    Server->>Scanner: scanInventories(player) every N ticks
    Scanner->>Scanner: Find blocks with inventories within range
    Scanner->>Agg: Aggregate all inventory contents
    Agg->>Net: InventorySyncPacket (item stacks + positions)
    Net->>Cache: Update cached item data
    Cache->>Panel: Panel reads cache on render

Remote Crafting (via Recipe Viewer)

sequenceDiagram
    participant Player as Player
    participant EMI as EMI / REI
    participant Handler as RecipeHandler
    participant Mixin as CraftingScreenHandlerMixin
    participant Remote as RemoteCraftingHandler
    participant Container as Nearby Container

    Player->>EMI: Click recipe to craft
    EMI->>Handler: Transfer recipe to crafting grid
    Handler->>Mixin: fillInputSlots() with remote sources
    Mixin->>Remote: Extract items from remote inventories
    Remote->>Container: Remove items from container slots
    Remote->>Mixin: Place items in crafting grid
    Player->>Mixin: Take crafted result
    Mixin->>Remote: Return unused items to source containers

Inventory Toggle

sequenceDiagram
    participant Player as Player (Client)
    participant Net as Network
    participant State as InventoryStateManager
    participant PState as PersistentState (World Save)

    Player->>Net: InventoryToggleRequestPacket (blockPos, enabled)
    Net->>State: Toggle inventory at position
    State->>PState: Persist to world save data
    State->>Net: InventoryStateSyncPacket (updated states)
    Net->>Player: Client updates overlay icons

Mixin Strategy

The mod uses four mixins to hook into Minecraft's crafting system and screen rendering:

Mixin Target Purpose
CraftingScreenHandlerMixin CraftingScreenHandler Injects remote inventory support into the crafting handler; implements GridSlotSourceHolder
AbstractRecipeScreenHandlerMixin AbstractRecipeScreenHandler Extends recipe book to consider remote items
CraftingScreenMixin CraftingScreen Injects the inventory panel into the crafting table screen
ContainerScreenMixin HandledScreen Injects the inventory panel into container screens (chests, barrels, etc.)

Mixin policy: No empty stub mixins. Every mixin must contain at least one functional injection. See Guidelines — Mixin Best Practices.


Recipe Viewer Integration

Both EMI and REI integrations follow the same pattern:

flowchart LR
    PLUGIN["Plugin Registration<br/>EmiPlugin / REIClientPlugin"] --> HANDLER["Recipe Transfer Handler<br/>Fills crafting grid from remote items"]
    PLUGIN --> EXCLUSION["Exclusion Zone Provider<br/>Prevents recipe viewer overlapping panel"]
Component EMI REI
Plugin AnsibleCraftingEmiPlugin ReiPlugin
Transfer Handler AnsibleCraftingRecipeHandler ReiTransferHandler
Exclusion Zone AnsibleCraftingEmiExclusionArea ReiExclusionZoneProvider

JEI is not supported — see README for rationale.


Client-Server Boundary

All code is strictly separated by side:

Side Entry Point Packages
Server (both dedicated + integrated) AnsibleCraftingMod inventory, crafting, config, network, mixin
Client only AnsibleCraftingClient client/*, client/ui/*, mixin/client/*, integration/*

Client-only classes use @Environment(EnvType.CLIENT) to prevent loading on dedicated servers. Entry points are declared in fabric.mod.json:

{
  "entrypoints": {
    "main": ["com.ansiblecrafting.AnsibleCraftingMod"],
    "client": ["com.ansiblecrafting.client.AnsibleCraftingClient"]
  }
}

Persistent State

InventoryStateManager extends Minecraft's PersistentState to save per-inventory enable/disable toggles to the world save. This means:

  • Toggle states survive server restarts
  • Each world/dimension has its own state
  • States are synced to clients via InventoryStateSyncPacket