Croparia IF Docs

|

General

Section
Developers
10 TOP-LEVEL ITEMS
    Developers
    Core Modules

      Crop Transmuter

    Repo API

Tutorial: Repo API

This page walks through the usual beginner path for implementing multi-platform storage interaction with Repo API.

1. Create a resource repo

This step decides what kind of resource you want to store and how your storage should expose it.

1.1 Vanilla-backed storage with ContainerRepo<ItemSpec>

The fastest path is to reuse the vanilla Container model. The following fragment shows part of the Greenhouse block entity:

public class GreenhouseBlockEntity extends BlockEntity implements Container {
    private final NonNullList<ItemStack> inventory; // Vanilla container
    private final ContainerRepo repo = new ContainerRepo<>(this);   // Create a repo
    
    // example of implementing BlockEntity 
    @Override
    protected void loadAdditional(@NonNull ValueInput input) {
        super.loadAdditional(input);
        ContainerHelper.loadAllItems(input, this.inventory);
    }
 
    @Override
    protected void saveAdditional(@NonNull ValueOutput output) {
        ContainerHelper.saveAllItems(output, this.inventory);
        super.saveAdditional(output);
    }
 
    // example of implementing Container
    @Override
    public int getContainerSize() {
        return this.inventory.size();
    }
 
    @Override
    public boolean isEmpty() {
        return this.inventory.stream().allMatch(ItemStack::isEmpty);
    }
    
    // ...
}

1.2 Custom storage with Repo<T>

You can also implement Repo directly if you need more specialized behavior.

Basic storage interaction methods:

  • int size
    • number of storage units
  • boolean isEmpty
    • whether the whole repo or one slot is empty
  • TypeToken<T> getType
  • T resourceFor
    • resource kind inside one slot
  • long simConsume
    • simulate extraction and return the simulated extracted amount
  • long consume
    • perform extraction and return the real extracted amount
  • long simAccept
    • simulate insertion and return the simulated accepted amount
  • long accept
    • perform insertion and return the real accepted amount
  • long capacityFor
    • query the maximum capacity for one resource or one slot
  • long amountFor
    • query the stored amount for one resource or one slot

Lock views (these return wrapped views and do not mutate the original repo):

  • boolean isAcceptLocked(int i)
    • whether one slot refuses insertion
  • boolean isConsumeLocked(int i)
    • whether one slot refuses extraction
  • DelegateRepo<T> lockAccept(Integer... idx)
    • lock insertion on specific slots
  • DelegateRepo<T> lockAccept()
    • lock insertion on all slots
  • DelegateRepo<T> lockConsume(Integer... idx)
    • lock extraction on specific slots
  • DelegateRepo<T> lockConsume()
    • lock extraction on all slots
  • DelegateRepo<T> lock(Integer... idx)
    • lock both insertion and extraction on specific slots
  • DelegateRepo<T> lock()
    • lock both insertion and extraction on all slots
  • DelegateRepo<T> trim()
    • flatten a chain of DelegateRepo wrappers into one layer

One important detail is easy to miss:

  • locking only affects accept / simAccept / consume / simConsume
  • capacityFor(...) and amountFor(...) still report the raw values from the underlying repo
  • if the caller needs to know both "can I insert here?" and "what is the slot capacity?", those checks still need to be done separately

2. Register a repo proxy

To make the repo interact safely with other storage systems, you need to wrap it in a RepoProxy.

public class GreenhouseBlockEntity extends BlockEntity implements Container {
    private final RepoProxy<ItemSpec> proxy = RepoProxy.item(this.repo);
    
    public RepoProxy<ItemSpec> visitItem() {
        return this.proxy;
    }
    
    // ...
}

Note: RepoProxy is instantiated automatically by Croparia IF per modding platform. Manually writing new RepoProxy<>(...) will not behave correctly on real platform targets.

In practice, a common pattern is to build a locked repo view first and only then wrap that view in RepoProxy. For example, the Crop Transmuter exports separate input and output views:

private final RepoProxy<ItemSpec> inputProxy = RepoProxy.item(
    repo.lockConsume(INPUT_SLOT, OUTPUT_SLOT).lockAccept(OUTPUT_SLOT).trim()
);
private final RepoProxy<ItemSpec> outputProxy = RepoProxy.item(
    repo.lockAccept(INPUT_SLOT, OUTPUT_SLOT).lockConsume(INPUT_SLOT).trim()
);

In behavior terms, this means:

  • inputProxy
    • refuses extraction from every slot
    • refuses insertion into the output slot
    • ultimately allows insertion only into the input slot
  • outputProxy
    • refuses insertion into every slot
    • refuses extraction from the input slot
    • ultimately allows extraction only from the output slot

Once the proxy exists, register it through ProxyProvider so external storage systems can discover it:

public class Greenhouse extends BaseEntityBlock {
    public Greenhouse(Properties settings) {
        super(settings);
        ProxyProvider.registerItem(
            // Query Function
            (world, pos, state, be, direction) -> {
                if (be instanceof GreenhouseBlockEntity gbe) {
                    return gbe.visitItem();
                } else {
                    return null;
                }
            },
            // Blocks
            this
        );
    }
    
    // ...
}

After registration, the platform resolves the block type first and then calls your query function to obtain the corresponding RepoProxy.

3. Query other storage repos

You can query other storage systems through ProxyProvider, which returns a wrapper in RepoProxy form.

Optional<PlatformItemProxy> itemProxy = ProxyProvider.findItem(world, pos, direction);
Optional<PlatformFluidProxy> fluidProxy = ProxyProvider.findFluid(world, pos, direction);
 
itemProxy.ifPresent(proxy -> {
    // use proxy as a Repo<ItemSpec>
});

Note: because platform capabilities differ, some Repo methods are not equally reliable across all implementations. When behavior matters, check the interface javadocs for PlatformItemProxy and PlatformFluidProxy.

In This Page
Tutorial: Repo API
NO EXTRACTED HEADINGS