package com.uadaf.astral.apiimpl;
import cofh.api.energy.EnergyStorage;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.uadaf.astral.AstralMod;
import com.uadaf.astral.api.energy.IAstralBindableTile;
import com.uadaf.astral.api.energy.IAstralEnergyStorer;
import com.uadaf.astral.api.energy.IAstralNetwork;
import com.uadaf.astral.api.event.network.AstralNetworkAccessBlockedEvent;
import com.uadaf.astral.api.event.network.AstralNetworkAccessGrantedEvent;
import com.uadaf.astral.utils.SideCheck;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import javax.annotation.Nullable;
import java.util.*;
class AstralNetworkImpl implements IAstralNetwork {
private final int color;
private final UUID owner;
private final Set<IAstralBindableTile> bound = Sets.newHashSet(), immutableBoundView = Collections.unmodifiableSet(bound);
private final Set<UUID> accessedPlayers = Sets.newHashSet(), immutableAccessedPlayersView = Collections.unmodifiableSet(accessedPlayers);
private final List<PlayerDiff> playerDiff = Lists.newArrayList(), immutablePlayerDiffView = Collections.unmodifiableList(playerDiff);
private final List<BoundDiff> boundDiff = Lists.newArrayList(), immutableBoundDiffView = Collections.unmodifiableList(boundDiff);
private final EnergyStorage energyStorage = new EnergyStorage(0);
private final HashMap<Integer, List<BoundDiff>> queuedBindings = Maps.newHashMap();
private int energyDiff = 0;
AstralNetworkImpl(int color, UUID owner) {
this.color = color;
this.owner = owner;
accessedPlayers.add(owner);
}
@Override
public int getNetworkColor() {
return color;
}
@Override
public void destroy() {
bound.forEach(b -> b.onUnbound(this));
bound.clear();
}
@Override
public Set<IAstralBindableTile> getBound() {
return immutableBoundView; //Unmodifiable set reflects all changes int base set
}
@Override
public void bind(IAstralBindableTile bindable) {
if(SideCheck.isServer() && bound.add(bindable)) {
bindable.onBound(this);
boundDiff.add(new BoundDiff(bindable.getPos(), true, bindable.getWorld().provider.getDimension()));
if(bindable instanceof IAstralEnergyStorer) {
recalculateStorage();
}
}
}
@Override
public void unbind(IAstralBindableTile bindable) {
if(SideCheck.isServer() && bound.remove(bindable)) {
bindable.onUnbound(this);
boundDiff.add(new BoundDiff(bindable.getPos(), false, bindable.getWorld().provider.getDimension()));
if(bindable instanceof IAstralEnergyStorer) {
recalculateStorage();
}
}
}
@Override
public void queueBinding(BoundDiff binding) {
queuedBindings.compute(binding.dimension, (dim, queue) -> {
if(queue == null) {
queue = Lists.newArrayList();
}
queue.add(binding);
return queue;
});
}
@Override
public void performQueue(World world) {
List<BoundDiff> queue = queuedBindings.get(world.provider.getDimension());
if(queue != null) {
queue.forEach(diff -> {
TileEntity t = world.getTileEntity(diff.pos);
if(!(t instanceof IAstralBindableTile)) {
AstralMod.log.warn("TileEntity " + t + "---" + diff.pos + " doesn't implement " + IAstralBindableTile.class + ", but was received from sync packet");
return;
}
bind((IAstralBindableTile) t);
});
}
}
@Override
public List<BoundDiff> getBoundDiff() {
return immutableBoundDiffView;
}
@Override
public void resetBoundDiff() {
boundDiff.clear();
}
private void recalculateStorage() {
int newCapacity = getBound().stream()
.filter(b -> b instanceof IAstralEnergyStorer)
.map(b -> (IAstralEnergyStorer) b)
.map(s -> {
AstralMod.log.info("Storer: " + s + ", en: " + s.getMaxStoredEnergy() + ", pos: " + s.getPos());
return s.getMaxStoredEnergy();
})
.reduce((i, j) -> i + j)
.orElse(0);
energyStorage.setCapacity(newCapacity);
energyStorage.setMaxTransfer(newCapacity);
}
@Override
public void modifyEnergy(int mod) {
energyDiff += mod;
energyStorage.modifyEnergyStored(mod);
}
@Override
public int getEnergyDiff() {
return energyDiff;
}
@Override
public void resetEnergyDiff() {
energyDiff = 0;
}
@Nullable
@Override
public UUID getOwner() {
return owner;
}
@Override
public List<PlayerDiff> getPlayerDiff() {
return immutablePlayerDiffView; //Unmodifiable set reflects all changes int base set
}
@Override
public Set<UUID> getAccessedPlayers() {
return immutableAccessedPlayersView; //Unmodifiable set reflects all changes int base set
}
@Override
public boolean allowAccess(UUID player) {
playerDiff.add(new PlayerDiff(player, true));
boolean ret = accessedPlayers.add(player);
if(ret) {
MinecraftForge.EVENT_BUS.post(new AstralNetworkAccessGrantedEvent(this, player));
}
return ret;
}
@Override
public boolean blockAccess(UUID player) {
playerDiff.add(new PlayerDiff(player, false));
boolean ret = accessedPlayers.remove(player);
if(ret) {
MinecraftForge.EVENT_BUS.post(new AstralNetworkAccessBlockedEvent(this, player));
}
return ret;
}
@Override
public boolean hasAccess(EntityPlayer player) {
return hasAccess(player.getGameProfile().getId());
}
@Override
public boolean hasAccess(UUID player) {
return accessedPlayers.contains(player);
}
@Override
public void resetPlayerDiff() {
playerDiff.clear();
}
@Override
public int receiveEnergy(int maxReceive, boolean simulate) {
int e = energyStorage.receiveEnergy(maxReceive, simulate);
if(!simulate) {
energyDiff += e;
}
return e;
}
@Override
public int extractEnergy(int maxExtract, boolean simulate) {
int e = energyStorage.extractEnergy(maxExtract, simulate);
if(!simulate) {
energyDiff -= maxExtract;
}
return e;
}
@Override
public int getEnergyStored() {
return energyStorage.getEnergyStored();
}
@Override
public int getMaxEnergyStored() {
return energyStorage.getMaxEnergyStored();
}
@Override
public boolean canExtract() {
return energyStorage.extractEnergy(1, true) == 1;
}
@Override
public boolean canReceive() {
return energyStorage.receiveEnergy(1, true) == 1;
}
}
Comments