package com.thebrokenrail.energonrelics.energy.core; import com.thebrokenrail.energonrelics.component.NetworkComponent; import com.thebrokenrail.energonrelics.energy.core.util.Action; import com.thebrokenrail.energonrelics.energy.core.util.EnergyProvider; 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.Tickable; import net.minecraft.util.math.Vec3d; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; public abstract class EnergyReceiverBlockEntity extends EnergyProviderBlockEntity implements Tickable { private class SelfProvider implements EnergyProvider { @Override public void addPropagatedAction(Action.PropagatedAction action) { pendingActionsFromSelf.add(action); } @Override public boolean isNetwork(int network) { return true; } @Override public boolean isWithinDistance(Vec3d pos) { return true; } } public EnergyReceiverBlockEntity(BlockEntityType type) { super(type); } private final List pendingActions = new ArrayList<>(); private final List pendingActionsFromSelf = new ArrayList<>(); private final EnergyProvider selfProvider = new SelfProvider(); private final List providers = new ArrayList<>(); private final List networks = new ArrayList<>(); private long totalCost = 0; protected void propagateAction(Action.PropagatedAction action) { totalCost = totalCost + action.amountOwed(); action.expandPayments(providers.size()); pendingActions.add(action); } protected void addAction(Action action) { propagateAction(new Action.PropagatedActionImpl(action, getWorld(), getPos(), getCachedState().getBlock())); } @Override public void serverTick() { if (hasWorld() && !Objects.requireNonNull(getWorld()).isClient()) { // Every Action Must Be Paid At Least Once For a Failure State To Occur for (Action.PropagatedAction action : pendingActionsFromSelf) { action.pay(0); } pendingActionsFromSelf.clear(); ServerWorld world = (ServerWorld) getWorld(); NetworkComponent component = NetworkComponent.getInstance(world); providers.clear(); // At Least One Energy Provider Is Always Required providers.add(selfProvider); for (int network : networks) { List potentialProviders = component.getSource(world, network); for (EnergyProvider provider : potentialProviders) { Vec3d pos = new Vec3d(getPos().getX() + 0.5d, getPos().getY() + 0.5d, getPos().getZ() + 0.5d); if (provider.isWithinDistance(pos)) { providers.add(provider); } } } totalCost = 0; pendingActions.clear(); tickEnergy(); super.serverTick(); for (Action.PropagatedAction action : pendingActions) { for (EnergyProvider provider : providers) { provider.addPropagatedAction(action); } } } } public long getTotalCost() { return totalCost; } @Override protected void handlePropagatedAction(Action.PropagatedAction action) { // Propagate Action To Energy Providers if (isEnergyProviderActive()) { propagateAction(action); } else { action.pay(0); } } @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); } } protected boolean isEnergyProviderActive() { throw new UnsupportedOperationException(); } protected abstract void tickEnergy(); public void toggle(int network) { if (contains(network)) { networks.removeAll(Collections.singletonList(network)); } else { networks.add(network); } markDirty(); } public boolean contains(int network) { return networks.contains(network); } }