my brain hurts

This commit is contained in:
Boblet 2026-05-13 11:25:40 +02:00
parent c7e5360380
commit 2cdaf9749f
8 changed files with 236 additions and 56 deletions

View File

@ -27,6 +27,15 @@ public interface ISlotMonitorProvider {
/** This allows slot monitors to find the network, and by extension all cached slots */
public PneumaticNetwork getRelevantNetwork();
/** Runs whenever a new stack cache user (i.e. an access point) joins the network in order to grab all the stack monitors */
public default void onNewCacheHasJoined(StackCache stackCache, PneumaticNetwork network) {
for(SlotMonitor monitor : getMonitors()) {
if(!stackCache.hasExpired && isAvailableToCache(stackCache)) {
stackCache.addToCache(monitor);
}
}
}
public default void updateMonitors() {
for(SlotMonitor monitor : getMonitors()) monitor.checkUpdate();
}

View File

@ -1,7 +1,12 @@
package api.hbm.ntl;
import java.util.Iterator;
import java.util.LinkedHashSet;
import javax.annotation.Nullable;
import com.hbm.uninos.networkproviders.PneumaticNetwork;
import api.hbm.ntl.StackCache.CacheSlot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
@ -26,42 +31,116 @@ public class SlotMonitor {
/** If this monitor detects a change, all cache slots need to be notified */
public LinkedHashSet<CacheSlot> viewedBy = new LinkedHashSet();
public Item item;
@Nullable public Item item;
public long stacksize;
public int meta;
public NBTTagCompound nbt;
protected boolean hasAvailabilityChanged = false;
public SlotMonitor(int index, ISlotMonitorProvider parent) {
this.hasAvailabilityChanged = true;
this.index = index;
this.parent = parent;
}
public ItemStack toZeroStack() {
if(item == null) return null;
ItemStack stack = new ItemStack(item, 0, meta);
stack.stackTagCompound = nbt;
return stack;
}
/**
* Monitor providers need to keep track of whether availability has changed, i.e. compair has run out, compression setting has changed, etc
* This means that we don't have to check availability every single tick, which potentially saves a fuckton of iterations.
*/
public void availabilityHasChanged() {
this.hasAvailabilityChanged = true;
}
public void checkUpdate() {
for(CacheSlot slot : viewedBy) { // we're gonna need an iterator for that
if(!parent.isAvailableToCache(slot.getStackCache())) {
// TODO: kill from that cache
PneumaticNetwork pneumoNet = this.parent.getRelevantNetwork();
if(hasAvailabilityChanged) {
if(pneumoNet != null) {
for(StackCache cache : pneumoNet.accessors) {
if(!cache.hasExpired && parent.isAvailableToCache(cache)) {
cache.addToCache(this);
}
}
}
// if this monitor is not available to some caches, remove them
Iterator<CacheSlot> iterator = viewedBy.iterator();
while(iterator.hasNext()) {
CacheSlot slot = iterator.next();
StackCache cache = slot.getStackCache();
if(cache.hasExpired || !parent.isAvailableToCache(cache)) {
slot.removeMonitor(this);
iterator.remove();
}
}
hasAvailabilityChanged = false;
}
ItemStack stack = parent.getSlotAt(index);
long amount = parent.getAmountAt(index);
boolean hasTypeChanged = false;
if(stack == null || item == null) {
if(stack == null && item != null) hasTypeChanged = true;
if(stack != null && item == null) hasTypeChanged = true;
} else {
if(item != stack.getItem() || meta != stack.getItemDamage()) hasTypeChanged = true;
else if(nbt == null && stack.hasTagCompound()) hasTypeChanged = true;
else if(nbt != null && !stack.hasTagCompound()) hasTypeChanged = true;
else if(nbt != null && stack.hasTagCompound() && !nbt.equals(stack.stackTagCompound)) hasTypeChanged = true;
}
if(hasTypeChanged) {
// TODO: find a bridge to the other CacheSlots, ideally over the pneumo network
// all viewing cache slots need their reference removed and a new cache slot needs to be found/created
// remove from all existing monitors
Iterator<CacheSlot> iterator = viewedBy.iterator();
while(iterator.hasNext()) {
CacheSlot slot = iterator.next();
slot.removeMonitor(this);
iterator.remove();
}
// set updated traits
if(stack == null) {
this.item = null;
this.stacksize = 0;
this.meta = 0;
this.nbt = null;
} else {
this.item = stack.getItem();
this.stacksize = amount;
this.meta = stack.getItemDamage();
this.nbt = stack.hasTagCompound() ? (NBTTagCompound) stack.stackTagCompound.copy() : null;
}
// find new monitors
if(pneumoNet != null) {
for(StackCache cache : pneumoNet.accessors) {
if(!cache.hasExpired && parent.isAvailableToCache(cache)) {
cache.addToCache(this);
}
}
}
return;
}
if(stacksize != amount) {
long delta = amount - stacksize;
for(CacheSlot slot : viewedBy) slot.changeAmounts(delta);
this.stacksize = amount;
}
}
}

View File

@ -2,6 +2,9 @@ package api.hbm.ntl;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map.Entry;
import javax.annotation.Nullable;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
@ -20,8 +23,10 @@ public class StackCache {
public int y;
public int z;
public boolean hasExpired = false;
/** Maps an identity number to the actual cache slot */
public LinkedHashMap<Integer, CacheSlot> cacheSlots = new LinkedHashMap();
public LinkedHashMap<Long, CacheSlot> cacheSlots = new LinkedHashMap();
public StackCache(int x, int y, int z) {
this.x = x;
@ -29,6 +34,26 @@ public class StackCache {
this.z = z;
}
public void addToCache(SlotMonitor monitor) {
long monitorIdentity = getStackIdentity(monitor.item, monitor.meta, monitor.nbt);
CacheSlot cache = cacheSlots.get(monitorIdentity);
if(cache == null) {
cache = new CacheSlot(monitor.toZeroStack());
cacheSlots.put(monitorIdentity, cache);
}
cache.addMonitor(monitor);
}
public void dissolveCache() {
for(Entry<Long, CacheSlot> cacheEntry : cacheSlots.entrySet()) {
cacheEntry.getValue().destroy();
}
this.cacheSlots.clear();
this.hasExpired = true;
}
/**
* A cache slot represents multiple accessible slots combined into one by type,
* in essence it's a single slot with an uncapped max stack size, which references
@ -38,23 +63,53 @@ public class StackCache {
*/
public class CacheSlot {
public final ItemStack displayStack;
@Nullable public final ItemStack displayStack;
public final int itemId;
public final int meta;
public final NBTTagCompound nbt;
public long stacksize;
public LinkedHashSet<SlotMonitor> monitors = new LinkedHashSet();
public CacheSlot(ItemStack stack) {
if(stack != null) {
this.displayStack = stack.copy();
this.stacksize = stack.stackSize;
this.displayStack.stackSize = 1;
this.itemId = Item.getIdFromItem(stack.getItem());
this.stacksize = stack.stackSize;
this.meta = stack.getItemDamage();
if(stack.hasTagCompound())
this.nbt = (NBTTagCompound) stack.stackTagCompound.copy();
else
this.nbt = null;
} else {
this.displayStack = null;
this.stacksize = 0;
this.itemId = 0;
this.meta = 0;
this.nbt = null;
}
}
public void addMonitor(SlotMonitor monitor) {
if(this.monitors.add(monitor)) {
this.changeAmounts(monitor.stacksize);
}
}
public void removeMonitor(SlotMonitor monitor) {
if(this.monitors.remove(monitor)) {
this.changeAmounts(-monitor.stacksize);
}
}
public void destroy() {
for(SlotMonitor monitor : monitors) {
monitor.viewedBy.remove(this);
}
this.stacksize = 0;
}
public void changeAmounts(long delta) {
@ -65,18 +120,18 @@ public class StackCache {
return StackCache.this;
}
// not actually used, and probably not needed. this would fix any inconsistencies with the sized,
// however we try to ensure that sizes are always correctly updated so this should never be the case.
public void reCount() {
this.stacksize = 0;
for(SlotMonitor monitor : monitors) {
this.stacksize += monitor.stacksize;
}
}
public LinkedHashSet<SlotMonitor> monitors = new LinkedHashSet();
}
public static int getStackIdentity(Item item, int meta, NBTTagCompound nbt) {
int identity = Item.getIdFromItem(item) * 27644437;
public static long getStackIdentity(Item item, int meta, NBTTagCompound nbt) {
long identity = Item.getIdFromItem(item) * 27644437;
identity += meta * 27644437;
if(nbt != null) identity += nbt.toString().hashCode();
return identity;

View File

@ -40,6 +40,9 @@ public class ContainerPneumoStorageAccess extends Container {
for(int i = 0; i < 9; i++) {
this.addSlotToContainer(new SlotNonRetarded(invPlayer, i, 8 + i * 18, 227));
}
inventory.updateListing();
this.detectAndSendChanges();
}
@Override
@ -64,6 +67,7 @@ public class ContainerPneumoStorageAccess extends Container {
}
public void updateListing() { // DEMO
if(this.cache == null) return;
List<CacheSlot> cacheSlots = new ArrayList(cache.cacheSlots.size());
cacheSlots.addAll(cache.cacheSlots.values());
Collections.sort(cacheSlots, SORT_BY_STACK_SIZE);

View File

@ -2,23 +2,21 @@ package com.hbm.tileentity.network.pneumatic;
import com.hbm.inventory.container.ContainerPneumoStorageAccess;
import com.hbm.inventory.gui.GUIPneumoStorageAccess;
import com.hbm.lib.Library;
import com.hbm.tileentity.IGUIProvider;
import com.hbm.tileentity.TileEntityLoadedBase;
import com.hbm.tileentity.network.pneumatic.TileEntityPneumoTube.PneumaticNode;
import com.hbm.uninos.UniNodespace;
import com.hbm.uninos.networkproviders.PneumaticNetworkProvider;
import com.hbm.util.fauxpointtwelve.BlockPos;
import com.hbm.util.fauxpointtwelve.DirPos;
import api.hbm.ntl.IPneumaticConnector;
import api.hbm.ntl.StackCache;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
public class TileEntityPneumoStorageAccess extends TileEntity implements IPneumaticConnector, IGUIProvider {
public class TileEntityPneumoStorageAccess extends TileEntityLoadedBase implements IPneumaticConnector, IGUIProvider {
protected PneumaticNode node;
public StackCache cache;
@ -26,25 +24,25 @@ public class TileEntityPneumoStorageAccess extends TileEntity implements IPneuma
@Override
public void updateEntity() {
if(this.cache == null) this.cache = new StackCache(xCoord, yCoord, zCoord);
if(!worldObj.isRemote) {
if(this.node == null || this.node.expired) {
if(this.cache != null) this.cache.dissolveCache();
this.node = (PneumaticNode) UniNodespace.getNode(worldObj, xCoord, yCoord, zCoord, PneumaticNetworkProvider.THE_PROVIDER);
if(this.node == null || this.node.expired) {
this.node = (PneumaticNode) new PneumaticNode(new BlockPos(xCoord, yCoord, zCoord)).setConnections(
new DirPos(xCoord + 1, yCoord, zCoord, Library.POS_X),
new DirPos(xCoord - 1, yCoord, zCoord, Library.NEG_X),
new DirPos(xCoord, yCoord + 1, zCoord, Library.POS_Y),
new DirPos(xCoord, yCoord - 1, zCoord, Library.NEG_Y),
new DirPos(xCoord, yCoord, zCoord + 1, Library.POS_Z),
new DirPos(xCoord, yCoord, zCoord - 1, Library.NEG_Z)
);
this.node = (PneumaticNode) new PneumaticNode(new BlockPos(xCoord, yCoord, zCoord)).setStandardConnections(xCoord, yCoord, zCoord);
UniNodespace.createNode(worldObj, this.node);
}
}
if(this.cache == null) {
this.cache = new StackCache(xCoord, yCoord, zCoord);
if(this.node != null && this.node.hasValidNet()) {
this.node.net.addStackCache(cache);
}
}
}
}
@ -52,11 +50,22 @@ public class TileEntityPneumoStorageAccess extends TileEntity implements IPneuma
public void invalidate() {
super.invalidate();
if(!worldObj.isRemote) {
if(this.node != null) {
if(!worldObj.isRemote && this.node != null) {
UniNodespace.destroyNode(worldObj, xCoord, yCoord, zCoord, PneumaticNetworkProvider.THE_PROVIDER);
}
if(this.cache != null) this.cache.dissolveCache();
}
@Override
public void onChunkUnload() {
super.onChunkUnload();
if(!worldObj.isRemote && this.node != null) {
UniNodespace.destroyNode(worldObj, xCoord, yCoord, zCoord, PneumaticNetworkProvider.THE_PROVIDER);
}
if(this.cache != null) this.cache.dissolveCache();
}
@Override

View File

@ -4,7 +4,6 @@ import com.hbm.inventory.container.ContainerPneumoStorageClutter;
import com.hbm.inventory.fluid.Fluids;
import com.hbm.inventory.fluid.tank.FluidTank;
import com.hbm.inventory.gui.GUIPneumoStorageClutter;
import com.hbm.lib.Library;
import com.hbm.tileentity.IGUIProvider;
import com.hbm.tileentity.TileEntityMachineBase;
import com.hbm.tileentity.network.pneumatic.TileEntityPneumoTube.PneumaticNode;
@ -12,7 +11,6 @@ import com.hbm.uninos.UniNodespace;
import com.hbm.uninos.networkproviders.PneumaticNetwork;
import com.hbm.uninos.networkproviders.PneumaticNetworkProvider;
import com.hbm.util.fauxpointtwelve.BlockPos;
import com.hbm.util.fauxpointtwelve.DirPos;
import api.hbm.fluidmk2.IFluidStandardReceiverMK2;
import api.hbm.ntl.ISlotMonitorProvider;
@ -29,6 +27,7 @@ public class TileEntityPneumoStorageClutter extends TileEntityMachineBase implem
public SlotMonitor[] monitors;
protected PneumaticNode node;
protected boolean wasAvailable = false;
public TileEntityPneumoStorageClutter() {
super(6 * 9);
@ -48,24 +47,24 @@ public class TileEntityPneumoStorageClutter extends TileEntityMachineBase implem
if(!worldObj.isRemote) {
boolean isAvailable = this.isAvailable();
if(isAvailable != wasAvailable) {
this.wasAvailable = isAvailable;
for(SlotMonitor monitor : monitors) monitor.availabilityHasChanged();
}
if(this.node == null || this.node.expired) {
this.node = (PneumaticNode) UniNodespace.getNode(worldObj, xCoord, yCoord, zCoord, PneumaticNetworkProvider.THE_PROVIDER);
if(this.node == null || this.node.expired) {
this.node = (PneumaticNode) new PneumaticNode(new BlockPos(xCoord, yCoord, zCoord)).setConnections(
new DirPos(xCoord + 1, yCoord, zCoord, Library.POS_X),
new DirPos(xCoord - 1, yCoord, zCoord, Library.NEG_X),
new DirPos(xCoord, yCoord + 1, zCoord, Library.POS_Y),
new DirPos(xCoord, yCoord - 1, zCoord, Library.NEG_Y),
new DirPos(xCoord, yCoord, zCoord + 1, Library.POS_Z),
new DirPos(xCoord, yCoord, zCoord - 1, Library.NEG_Z)
);
this.node = (PneumaticNode) new PneumaticNode(new BlockPos(xCoord, yCoord, zCoord)).setStandardConnections(xCoord, yCoord, zCoord);
UniNodespace.createNode(worldObj, this.node);
}
}
if(node != null && !node.expired && node.hasValidNet()) {
this.node.net.storages.put(this, worldObj.getTotalWorldTime());
this.node.net.storages.add(this);
}
this.updateMonitors();
@ -73,6 +72,10 @@ public class TileEntityPneumoStorageClutter extends TileEntityMachineBase implem
}
}
public boolean isAvailable() {
return this.isLoaded && !this.isInvalid();
}
@Override
public void invalidate() {
super.invalidate();
@ -119,6 +122,6 @@ public class TileEntityPneumoStorageClutter extends TileEntityMachineBase implem
@Override
public boolean isAvailableToCache(StackCache cache) {
return true;
return this.isLoaded && !this.isInvalid();
}
}

View File

@ -1,5 +1,6 @@
package com.hbm.uninos;
import com.hbm.lib.Library;
import com.hbm.util.fauxpointtwelve.BlockPos;
import com.hbm.util.fauxpointtwelve.DirPos;
@ -25,6 +26,16 @@ public class GenNode<N extends NodeNet> {
return this;
}
public GenNode<N> setStandardConnections(int xCoord, int yCoord, int zCoord) {
return this.setConnections(
new DirPos(xCoord + 1, yCoord, zCoord, Library.POS_X),
new DirPos(xCoord - 1, yCoord, zCoord, Library.NEG_X),
new DirPos(xCoord, yCoord + 1, zCoord, Library.POS_Y),
new DirPos(xCoord, yCoord - 1, zCoord, Library.NEG_Y),
new DirPos(xCoord, yCoord, zCoord + 1, Library.POS_Z),
new DirPos(xCoord, yCoord, zCoord - 1, Library.NEG_Z));
}
public GenNode<N> addConnection(DirPos connection) {
DirPos[] newCons = new DirPos[this.connections.length + 1];
for(int i = 0; i < this.connections.length; i++) newCons[i] = this.connections[i];

View File

@ -5,6 +5,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Random;
@ -17,6 +18,7 @@ import com.hbm.util.ItemStackUtil;
import com.hbm.util.Tuple.Triplet;
import api.hbm.ntl.ISlotMonitorProvider;
import api.hbm.ntl.StackCache;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.item.ItemStack;
@ -41,12 +43,19 @@ public class PneumaticNetwork extends NodeNet {
// it can actually handle non-TileEntities just fine.
public HashMap<IInventory, Triplet<ForgeDirection, Long, TileEntityPneumoTube>> receivers = new HashMap();
public HashMap<ISlotMonitorProvider, Long> storages = new HashMap();
public LinkedHashSet<StackCache> accessors = new LinkedHashSet();
public LinkedHashSet<ISlotMonitorProvider> storages = new LinkedHashSet();
public void addReceiver(IInventory inventory, ForgeDirection pipeDir, TileEntityPneumoTube endpoint) {
receivers.put(inventory, new Triplet(pipeDir, System.currentTimeMillis(), endpoint));
}
public void addStackCache(StackCache accessor) {
if(accessors.add(accessor)) {
for(ISlotMonitorProvider storage : storages) storage.onNewCacheHasJoined(accessor, this);
}
}
@Override public void update() {
// weeds out invalid targets
@ -54,6 +63,7 @@ public class PneumaticNetwork extends NodeNet {
// but we still want to reap garbage data that would otherwise accumulate
long timestamp = System.currentTimeMillis();
receivers.entrySet().removeIf(x -> { return (timestamp - x.getValue().getY() > timeout) || NodeNet.isBadLink(x.getKey()); });
accessors.removeIf(x -> { return x.hasExpired; });
}
public boolean send(IInventory source, TileEntityPneumoTube tube, ForgeDirection accessDir, int sendOrder, int receiveOrder, int maxRange, int nextReceiver) {