RyanHub – file viewer
filename: common/src/main/java/rearth/oritech/block/entity/addons/RedstoneAddonBlockEntity.java
branch: 1.21
back to repo
package rearth.oritech.block.entity.addons;

import dev.architectury.registry.menu.ExtendedMenuProvider;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntityTicker;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.text.Text;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
import rearth.oritech.block.blocks.addons.MachineAddonBlock;
import rearth.oritech.client.ui.RedstoneAddonScreenHandler;
import rearth.oritech.init.BlockEntitiesContent;
import rearth.oritech.network.NetworkContent;
import rearth.oritech.util.ComparatorOutputProvider;

public class RedstoneAddonBlockEntity extends AddonBlockEntity implements BlockEntityTicker<RedstoneAddonBlockEntity>, ExtendedMenuProvider, ComparatorOutputProvider {
    
    private RedstoneControllable cachedController;
    public RedstoneMode activeMode = RedstoneMode.INPUT_CONTROL;
    public int monitoredSlot = 0;
    
    public int currentOutput;
    
    public RedstoneAddonBlockEntity(BlockPos pos, BlockState state) {
        super(BlockEntitiesContent.REDSTONE_ADDON_ENTITY, pos, state);
    }
    
    @Override
    public void tick(World world, BlockPos pos, BlockState state, RedstoneAddonBlockEntity blockEntity) {
        if (world.isClient || !isConnected() || activeMode == RedstoneMode.INPUT_CONTROL) return;
        
        var lastOutput = currentOutput;
        
        switch (activeMode) {
            case OUTPUT_POWER -> currentOutput = cachedController.getComparatorEnergyAmount();
            case OUTPUT_SLOT -> currentOutput = cachedController.getComparatorSlotAmount(monitoredSlot);
            case OUTPUT_PROGRESS -> currentOutput = cachedController.getComparatorProgress();
            case OUTPUT_ACTIVE -> currentOutput = cachedController.getComparatorActiveState();
            case INPUT_CONTROL -> currentOutput = 0;
        }
        
        if (currentOutput != lastOutput) {
            this.markDirty();
        }
        
    }
    
    @Override
    protected void writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
        super.writeNbt(nbt, registryLookup);
        nbt.putInt("slot", monitoredSlot);
        nbt.putInt("mode", activeMode.ordinal());
    }
    
    @Override
    protected void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
        super.readNbt(nbt, registryLookup);
        monitoredSlot = nbt.getInt("slot");
        activeMode = RedstoneMode.values()[nbt.getInt("mode")];
    }
    
    public void sendDataToClient() {
        NetworkContent.MACHINE_CHANNEL.serverHandle(this).send(new NetworkContent.RedstoneAddonSyncPacket(pos, getControllerPos(), monitoredSlot, activeMode.ordinal(), currentOutput));
    }
    
    public void sendDataToServer() {
        NetworkContent.UI_CHANNEL.clientHandle().send(new NetworkContent.RedstoneAddonSyncPacket(pos, getControllerPos(), monitoredSlot, activeMode.ordinal(), currentOutput));
    }
    
    private boolean isConnected() {
        var isUsed = this.getCachedState().get(MachineAddonBlock.ADDON_USED);
        return isUsed && getCachedController() != null;
    }
    
    public RedstoneControllable getCachedController() {
        
        if (cachedController != null)
            return cachedController;
        
        if (world.getBlockEntity(getControllerPos()) instanceof RedstoneControllable redstoneControllable) {
            cachedController = redstoneControllable;
        }
        
        return cachedController;
    }
    
    public void setRedstonePowered(boolean isPowered) {
        this.markDirty();
        
        if (activeMode != RedstoneMode.INPUT_CONTROL) return;
        
        if (getCachedController() != null)
            cachedController.onRedstoneEvent(isPowered);
        
    }

    @Override
    public int getComparatorOutput() {
        return currentOutput;
    }
    
    @Override
    public void saveExtraData(PacketByteBuf buf) {
        sendDataToClient();
        buf.writeBlockPos(pos);
    }
    
    @Nullable
    @Override
    public ScreenHandler createMenu(int syncId, PlayerInventory playerInventory, PlayerEntity player) {
        return new RedstoneAddonScreenHandler(syncId, playerInventory, this);
    }
    
    @Override
    public Text getDisplayName() {
        return Text.literal("");
    }
    
    public void handleClientBound(NetworkContent.RedstoneAddonSyncPacket message) {
        this.currentOutput = message.currentOutput();
        this.activeMode = RedstoneMode.values()[message.targetMode()];
        this.monitoredSlot = message.targetSlot();
        this.setControllerPos(message.controllerPos());
    }
    
    public void handleServerBound(NetworkContent.RedstoneAddonSyncPacket message) {
        this.activeMode = RedstoneMode.values()[message.targetMode()];
        this.monitoredSlot = message.targetSlot();
    }
    
    public enum RedstoneMode {
        OUTPUT_POWER, OUTPUT_SLOT, OUTPUT_PROGRESS, OUTPUT_ACTIVE, INPUT_CONTROL
    }
    
    public interface RedstoneControllable extends ComparatorOutputProvider {
        int getComparatorEnergyAmount();
        int getComparatorSlotAmount(int slot);
        int getComparatorProgress();
        int getComparatorActiveState();
        void onRedstoneEvent(boolean isPowered);

        /**
         * A redstone controllable machine only outputs a readable comparator signal from the controller addon block.
         * @return 0
         */
        @Override
        default int getComparatorOutput() {
            return 0;
        }
    }
    
}