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 bound = Sets.newHashSet(), immutableBoundView = Collections.unmodifiableSet(bound); private final Set accessedPlayers = Sets.newHashSet(), immutableAccessedPlayersView = Collections.unmodifiableSet(accessedPlayers); private final List playerDiff = Lists.newArrayList(), immutablePlayerDiffView = Collections.unmodifiableList(playerDiff); private final List boundDiff = Lists.newArrayList(), immutableBoundDiffView = Collections.unmodifiableList(boundDiff); private final EnergyStorage energyStorage = new EnergyStorage(0); private final HashMap> 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 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 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 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 getPlayerDiff() { return immutablePlayerDiffView; //Unmodifiable set reflects all changes int base set } @Override public Set 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; } }