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

import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.text.Text;
import net.minecraft.util.Pair;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.LightType;
import net.minecraft.world.World;
import rearth.oritech.api.energy.EnergyApi;
import rearth.oritech.api.item.ItemApi;
import rearth.oritech.block.base.entity.MachineBlockEntity;
import rearth.oritech.block.base.entity.PassiveGeneratorBlockEntity;
import rearth.oritech.block.blocks.generators.BigSolarPanelBlock;
import rearth.oritech.init.BlockEntitiesContent;
import rearth.oritech.util.MultiblockMachineController;
import software.bernie.geckolib.animatable.GeoBlockEntity;
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
import software.bernie.geckolib.animation.AnimatableManager;
import software.bernie.geckolib.animation.AnimationController;
import software.bernie.geckolib.animation.RawAnimation;
import software.bernie.geckolib.util.GeckoLibUtil;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static rearth.oritech.block.base.block.MultiblockMachine.ASSEMBLED;

public class BigSolarPanelEntity extends PassiveGeneratorBlockEntity implements MultiblockMachineController, GeoBlockEntity {
    
    public static final RawAnimation FOLD = RawAnimation.begin().thenPlayAndHold("fold");
    public static final RawAnimation UNFOLD = RawAnimation.begin().thenPlayAndHold("unfold");
    
    // animation
    protected final AnimatableInstanceCache animatableInstanceCache = GeckoLibUtil.createInstanceCache(this);
    private final AnimationController<BigSolarPanelEntity> animationController = getAnimationController();
    
    // multiblock
    private final ArrayList<BlockPos> coreBlocksConnected = new ArrayList<>();
    private float coreQuality = 1f;
    
    // self
    private boolean isFolded;
    
    public BigSolarPanelEntity(BlockPos pos, BlockState state) {
        super(BlockEntitiesContent.BIG_SOLAR_ENTITY, pos, state);
    }
    
    @Override
    protected void writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
        super.writeNbt(nbt, registryLookup);
        addMultiblockToNbt(nbt);
        nbt.putBoolean("folded", isFolded);
    }
    
    @Override
    protected void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
        super.readNbt(nbt, registryLookup);
        loadMultiblockNbtData(nbt);
        isFolded = nbt.getBoolean("folded");
    }
    
    @Override
    public int getProductionRate() {
        var baseRate = ((BigSolarPanelBlock) this.getCachedState().getBlock()).productionRate;
        var skyLightLevel = world.getLightLevel(LightType.SKY, this.getPos());
        isFolded = world.isNight() && skyLightLevel < 12;
        return (int) (coreQuality * baseRate);
    }
    
    @Override
    public boolean isProducing() {
        var skyLightLevel = world.getLightLevel(LightType.SKY, this.getPos());
        return !world.isNight() && skyLightLevel >= 12 && isActive(getCachedState());
    }
    
    public void sendInfoMessageToPlayer(PlayerEntity player) {
        player.sendMessage(Text.translatable("message.oritech.generator.production_rate", getProductionRate(), getCoreQuality()));
    }
    
    // output only to north, down and south
    @Override
    protected Set<Pair<BlockPos, Direction>> getOutputTargets(BlockPos pos, World world) {
        
        var res = new HashSet<Pair<BlockPos, Direction>>();
        res.add(new Pair<>(pos.down(), Direction.DOWN));
        res.add(new Pair<>(pos.south(), Direction.NORTH));
        res.add(new Pair<>(pos.north(), Direction.SOUTH));
        
        return res;
        
    }
    
    //region multiblock
    @Override
    public ArrayList<BlockPos> getConnectedCores() {
        return coreBlocksConnected;
    }
    
    @Override
    public Direction getFacingForMultiblock() {
        return Direction.NORTH;
    }
    
    @Override
    public float getCoreQuality() {
        return this.coreQuality;
    }
    
    @Override
    public void setCoreQuality(float quality) {
        this.coreQuality = quality;
    }
    
    @Override
    public ItemApi.InventoryStorage getInventoryForMultiblock() {
        return null;
    }
    
    @Override
    public EnergyApi.EnergyStorage getEnergyStorageForMultiblock(Direction direction) {
        return null;
    }
    
    @Override
    public List<Vec3i> getCorePositions() {
        return List.of(
          // top
          new Vec3i(1, 1, 1),
          new Vec3i(0, 1, 1),
          new Vec3i(-1, 1, 1),
          new Vec3i(1, 1, 0),
          new Vec3i(0, 1, 0),
          new Vec3i(-1, 1, 0),
          new Vec3i(1, 1, -1),
          new Vec3i(0, 1, -1),
          new Vec3i(-1, 1, -1),
          // bottom
          new Vec3i(1, 0, 1),
          new Vec3i(0, 0, 1),
          new Vec3i(-1, 0, 1),
          new Vec3i(1, 0, -1),
          new Vec3i(0, 0, -1),
          new Vec3i(-1, 0, -1)
        );
    }
    //endregion
    
    
    @Override
    public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
        controllers.add(animationController);
    }
    
    @Override
    public AnimatableInstanceCache getAnimatableInstanceCache() {
        return animatableInstanceCache;
    }
    
    private AnimationController<BigSolarPanelEntity> getAnimationController() {
        return new AnimationController<>(this, state -> {
            
            if (!isActive(getCachedState()))
                return state.setAndContinue(MachineBlockEntity.PACKAGED);
            
            if (state.isCurrentAnimation(MachineBlockEntity.SETUP)) {
                if (state.getController().hasAnimationFinished()) {
                    return state.setAndContinue(MachineBlockEntity.IDLE);
                } else {
                    return state.setAndContinue(MachineBlockEntity.SETUP);
                }
            }
            
            // update correct state on client
            var timeOfDay = getAdjustedTimeOfDay();
            var skyLightLevel = world.getLightLevel(LightType.SKY, this.getPos());
            var isDay = timeOfDay > 0 && timeOfDay < 12500;
            isFolded = !isDay || skyLightLevel < 12;
            
            if (isFolded) {
                return state.setAndContinue(FOLD);
            } else {
                if (state.isCurrentAnimation(MachineBlockEntity.IDLE)) {
                    return state.setAndContinue(MachineBlockEntity.IDLE);
                } else {
                    return state.setAndContinue(UNFOLD);
                }
            }
        });
    }
    
    @Override
    public BlockPos getPosForMultiblock() {
        return getPos();
    }
    
    @Override
    public World getWorldForMultiblock() {
        return getWorld();
    }
    
    public long getAdjustedTimeOfDay() {
        return (world.getTimeOfDay() + getTimeOffset()) % 24000;
    }
    
    public int getTimeOffset() {
        var base = pos.getX() + pos.getZ();
        return (int) (Math.sin((double) base / 60) * 100);
    }
    
    public boolean isActive(BlockState state) {
        return state.get(ASSEMBLED);
    }
    
    @Override
    public void playSetupAnimation() {
        animationController.setAnimation(MachineBlockEntity.SETUP);
        animationController.forceAnimationReset();
    }
}