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