RyanHub – file viewer
filename: fabric/src/main/java/rearth/oritech/fabric/FabricEnergyApiImpl.java
branch: 1.21
back to repo
package rearth.oritech.fabric;

import net.fabricmc.fabric.api.transfer.v1.context.ContainerItemContext;
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant;
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext;
import net.fabricmc.fabric.api.transfer.v1.transaction.base.SnapshotParticipant;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.component.ComponentType;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
import rearth.oritech.util.StackContext;
import rearth.oritech.api.energy.BlockEnergyApi;
import rearth.oritech.api.energy.EnergyApi;
import rearth.oritech.api.energy.ItemEnergyApi;
import rearth.oritech.api.energy.containers.SimpleEnergyItemStorage;
import team.reborn.energy.api.EnergyStorage;

import java.util.function.Supplier;

public class FabricEnergyApiImpl implements BlockEnergyApi, ItemEnergyApi {
    
    @Override
    public void registerBlockEntity(Supplier<BlockEntityType<?>> typeSupplier) {
        team.reborn.energy.api.EnergyStorage.SIDED.registerForBlockEntity((entity, direction) ->
                                                     ContainerStorageWrapper.of(((EnergyApi.BlockProvider) entity).getEnergyStorage(direction)), typeSupplier.get());
    }
    
    @Override
    public void registerForItem(Supplier<net.minecraft.item.Item> itemSupplier) {
        team.reborn.energy.api.EnergyStorage.ITEM.registerForItems((stack, context) ->
                                              ContainerStorageWrapper.of(((EnergyApi.ItemProvider) stack.getItem()).getEnergyStorage(stack), context, stack), itemSupplier.get());
    }
    
    @Override
    public ComponentType<Long> getEnergyComponent() {
        return team.reborn.energy.api.EnergyStorage.ENERGY_COMPONENT;
    }
    
    @Override
    public EnergyApi.EnergyStorage find(StackContext stack) {
        var context = ContainerItemContext.ofSingleSlot(new ItemStackStorage(stack));
        var candidate = team.reborn.energy.api.EnergyStorage.ITEM.find(stack.getValue(), context);
        if (candidate == null) return null;
        if (candidate instanceof ContainerStorageWrapper wrapper && wrapper.container instanceof SimpleEnergyItemStorage itemStorage)
            return itemStorage.withCallback(ignored -> stack.sync());
        return new FabricStorageWrapper(candidate, stack);
    }
    
    @Override
    public EnergyApi.EnergyStorage find(World world, BlockPos pos, @Nullable BlockState state, @Nullable BlockEntity entity, @Nullable Direction direction) {
        var candidate = team.reborn.energy.api.EnergyStorage.SIDED.find(world, pos, state, entity, direction);
        if (candidate == null) return null;
        if (candidate instanceof ContainerStorageWrapper wrapper) return wrapper.container;
        return new FabricStorageWrapper(candidate, null);
    }
    
    @Override
    public EnergyApi.EnergyStorage find(World world, BlockPos pos, @Nullable Direction direction) {
        return find(world, pos, null, null, direction);
    }
    
    // this is used to interact with energy storages from other mods
    public static class FabricStorageWrapper extends EnergyApi.EnergyStorage {
        
        public final EnergyStorage storage;
        public final @Nullable StackContext context;
        
        public FabricStorageWrapper(EnergyStorage storage, @Nullable StackContext context) {
            this.storage = storage;
            this.context = context;
        }
        
        @Override
        public long insert(long maxAmount, boolean simulate) {
            try (var transaction = Transaction.openOuter()) {
                var inserted = storage.insert(maxAmount, transaction);
                if (!simulate)
                    transaction.commit();
                return inserted;
            }
        }
        
        @Override
        public long extract(long maxAmount, boolean simulate) {
            try (var transaction = Transaction.openOuter()) {
                var extracted = storage.extract(maxAmount, transaction);
                if (!simulate)
                    transaction.commit();
                return extracted;
            }
        }
        
        @Override
        public long getAmount() {
            return storage.getAmount();
        }
        
        @Override
        public long getCapacity() {
            return storage.getCapacity();
        }
        
        @Override
        public void setAmount(long amount) {
        }
        
        @Override
        public void update() {
            if (context != null)
                context.sync();
        }
    }
    
    // this is used by other mods to interact with the oritech energy containers (machines/items)
    public static class ContainerStorageWrapper extends SnapshotParticipant<Long> implements EnergyStorage {
        
        public final EnergyApi.EnergyStorage container;
        @Nullable
        public final ContainerItemContext context;
        @Nullable
        public final ItemStack stack;
        
        public static ContainerStorageWrapper of(@Nullable EnergyApi.EnergyStorage container) {
            if (container == null) return null;
            return new ContainerStorageWrapper(container);
        }
        
        public static ContainerStorageWrapper of(@Nullable EnergyApi.EnergyStorage container, @Nullable ContainerItemContext context, @Nullable ItemStack stack) {
            if (container == null) return null;
            return new ContainerStorageWrapper(container, context, stack);
        }
        
        public ContainerStorageWrapper(EnergyApi.EnergyStorage container) {
            this.container = container;
            this.context = null;
            this.stack = null;
        }
        
        public ContainerStorageWrapper(EnergyApi.EnergyStorage container, @Nullable ContainerItemContext context, @Nullable ItemStack stack) {
            this.container = container;
            this.context = context;
            this.stack = stack;
        }
        
        @Override
        public boolean supportsInsertion() {
            return container.supportsInsertion();
        }
        
        @Override
        public long insert(long maxAmount, TransactionContext transaction) {
            updateSnapshots(transaction);
            transaction.addCloseCallback((transactionContext, result) -> {
                if (result.wasCommitted()) {
                    container.update();
                }
            });
            
            var inserted = container.insert(maxAmount, false);
            
            // no idea what this does, but it does seem to fix it
            if (context != null) {
                stack.set(EnergyApi.ITEM.getEnergyComponent(), container.getAmount());
                context.exchange(ItemVariant.of(stack), 1, transaction);
            }
            
            
            return inserted;
        }
        
        @Override
        public boolean supportsExtraction() {
            return container.supportsInsertion();
        }
        
        @Override
        public long extract(long maxAmount, TransactionContext transaction) {
            updateSnapshots(transaction);
            transaction.addCloseCallback((context, result) -> {
                if (result.wasCommitted()) {
                    container.update();
                }
            });
            return container.extract(maxAmount, false);
        }
        
        @Override
        public long getAmount() {
            return container.getAmount();
        }
        
        @Override
        public long getCapacity() {
            return container.getCapacity();
        }
        
        @Override
        protected Long createSnapshot() {
            return getAmount();
        }
        
        @Override
        protected void readSnapshot(Long snapshot) {
            container.setAmount(snapshot);
        }
    }
    
}