package com.thebrokenrail.energonrelics.api.block.entity.core; import com.thebrokenrail.energonrelics.api.energy.Action; import com.thebrokenrail.energonrelics.component.NetworkComponent; import com.thebrokenrail.energonrelics.api.energy.tick.EnergyTickable; import net.minecraft.block.BlockState; import net.minecraft.block.entity.BlockEntityType; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.IntArrayTag; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.Vec3d; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Block Entity That Receives Energy */ public abstract class EnergyReceiverBlockEntity extends EnergyProviderBlockEntity { public EnergyReceiverBlockEntity(BlockEntityType type) { super(type); } private final List providers = new ArrayList<>(); private final List networks = new ArrayList<>(); private long totalCost = 0; private long previousTotalCost = 0; private final List sent = new ArrayList<>(); /** * If The Specified Action Has Been Sent By This Block this Tick * @param action Action * @return If It Was Sent */ protected boolean hasSent(Action.PropagatedAction action) { return sent.contains(action); } /** * Propagate Action To The Network's Energy Providers * @param action Propagated Action */ protected void propagateAction(Action.PropagatedAction action) { sent.add(action); totalCost = totalCost + action.amountOwed(); if (providers.size() > 0) { action.expandPayments(providers.size()); for (EnergyProviderBlockEntity provider : providers) { provider.addPropagatedAction(action); } } else { action.pay(0); } } /** * Convert Action To A Propagated Action And Then Propagate It * @param action Action */ protected void addAction(Action action) { propagateAction(new Action.PropagatedActionImpl(action, getWorld(), getPos(), getCachedState())); } @Override public List startTick() { sent.clear(); List list = new ArrayList<>(super.startTick()); ServerWorld world = (ServerWorld) getWorld(); assert world != null; NetworkComponent component = NetworkComponent.getInstance(world); providers.clear(); for (int network : networks) { List potentialProviders = component.getSources(world, network); for (EnergyProviderBlockEntity provider : potentialProviders) { if (provider.getRegistryKey().equals(getWorld().getRegistryKey())) { Vec3d pos = new Vec3d(getPos().getX() + 0.5d, getPos().getY() + 0.5d, getPos().getZ() + 0.5d); if (provider.isWithinDistance(pos)) { providers.add(provider); } } } } previousTotalCost = totalCost; totalCost = 0; list.addAll(providers); return list; } @Override public void logicTick() { super.logicTick(); assert getWorld() != null; getWorld().getProfiler().push("energyTick"); energyTick(); getWorld().getProfiler().pop(); } /** * Get Total Cost In Energon * @return Cost */ public long getTotalCost() { return previousTotalCost; } @Override public CompoundTag toTag(CompoundTag tag) { super.toTag(tag); tag.put("Networks", new IntArrayTag(networks)); return tag; } @Override public void fromTag(BlockState state, CompoundTag tag) { super.fromTag(state, tag); int[] networksArray = tag.getIntArray("Networks"); networks.clear(); for (int network : networksArray) { networks.add(network); } } /** * Create And Propagate Actions */ protected abstract void energyTick(); /** * Toggle If This Is In The Specified Network * @param network Network ID */ public void toggle(int network) { if (contains(network)) { networks.removeAll(Collections.singletonList(network)); } else { networks.add(network); } markDirty(); } /** * Check If The Specified Network Contains This Block * @param network Network ID * @return If It Contains This Block */ public boolean contains(int network) { return networks.contains(network); } }