From 743b7a157613fb395c396b85370f2fe176505637 Mon Sep 17 00:00:00 2001 From: Bob Date: Sat, 30 Sep 2023 21:05:46 +0200 Subject: [PATCH] two weeks of agony are finally paying off --- .../hbm/entity/item/EntityRequestDrone.java | 173 ++++++++++-------- .../entity/item/RenderDeliveryDrone.java | 4 +- .../tileentity/network/RequestNetwork.java | 19 +- .../network/TileEntityDroneDock.java | 57 +++--- .../network/TileEntityRequestNetwork.java | 25 ++- src/main/java/com/hbm/util/HashedSet.java | 132 +++++++++++++ 6 files changed, 283 insertions(+), 127 deletions(-) create mode 100644 src/main/java/com/hbm/util/HashedSet.java diff --git a/src/main/java/com/hbm/entity/item/EntityRequestDrone.java b/src/main/java/com/hbm/entity/item/EntityRequestDrone.java index 90bd0adce..30d22ab20 100644 --- a/src/main/java/com/hbm/entity/item/EntityRequestDrone.java +++ b/src/main/java/com/hbm/entity/item/EntityRequestDrone.java @@ -21,6 +21,7 @@ public class EntityRequestDrone extends EntityDroneBase { public ItemStack heldItem; public List program = new ArrayList(); + int nextActionTimer = 0; public static enum DroneProgram { UNLOAD, DOCK @@ -37,92 +38,110 @@ public class EntityRequestDrone extends EntityDroneBase { if(!worldObj.isRemote) { if(Vec3.createVectorHelper(motionX, motionY, motionZ).lengthVector() < 0.01) { - if(program.isEmpty()) { - this.setDead(); //self-destruct if no further operations are pending - this.entityDropItem(new ItemStack(ModItems.drone, 1, EnumDroneType.REQUEST.ordinal()), 1F); - return; - } - Object next = program.get(0); - program.remove(0); - - if(next instanceof BlockPos) { - BlockPos pos = (BlockPos) next; - this.setTarget(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); - } else if(next instanceof AStack && heldItem == null) { + if(nextActionTimer > 0) { + nextActionTimer--; + } else { + nextActionTimer = 5; - AStack aStack = (AStack) next; - TileEntity tile = worldObj.getTileEntity((int) Math.floor(posX), (int) Math.floor(posY - 1), (int) Math.floor(posZ)); - - if(tile instanceof TileEntityDroneProvider) { - TileEntityDroneProvider provider = (TileEntityDroneProvider) tile; - - for(int i = 0; i < provider.slots.length; i++) { - ItemStack stack = provider.slots[i]; - - if(stack != null && aStack.matchesRecipe(stack, true)) { - this.heldItem = stack.copy(); - this.setAppearance(1); - provider.slots[i] = null; - provider.markDirty(); - break; - } - } - } - } else if(next == DroneProgram.UNLOAD && this.heldItem != null) { - - TileEntity tile = worldObj.getTileEntity((int) Math.floor(posX), (int) Math.floor(posY - 1), (int) Math.floor(posZ)); - if(tile instanceof TileEntityDroneRequester) { - TileEntityDroneRequester requester = (TileEntityDroneRequester) tile; - - for(int i = 9; i < 18; i++) { - ItemStack stack = requester.slots[i]; - if(stack != null && stack.getItem() == heldItem.getItem() && stack.getItemDamage() == heldItem.getItemDamage()) { - int toTransfer = Math.min(stack.getMaxStackSize() - stack.stackSize, heldItem.stackSize); - requester.slots[i].stackSize += toTransfer; - this.heldItem.stackSize -= toTransfer; - } - } - - if(this.heldItem.stackSize <= 0) this.heldItem = null; - - if(this.heldItem != null) for(int i = 9; i < 18; i++) { - if(requester.slots[i] == null) { - requester.slots[i] = this.heldItem.copy(); - this.heldItem = null; - break; - } - } - - if(this.heldItem == null) { - this.setAppearance(0); - } - - requester.markDirty(); - } - } else if(next == DroneProgram.DOCK) { - - TileEntity tile = worldObj.getTileEntity((int) Math.floor(posX), (int) Math.floor(posY - 1), (int) Math.floor(posZ)); - if(tile instanceof TileEntityDroneDock) { - TileEntityDroneDock dock = (TileEntityDroneDock) tile; - - for(int i = 0; i < dock.slots.length; i++) { - if(dock.slots[i] == null) { - this.setDead(); - dock.slots[i] = new ItemStack(ModItems.drone, 1, EnumDroneType.REQUEST.ordinal()); - } - } - } - - if(!this.isDead) { - this.setDead(); + if(program.isEmpty()) { + this.setDead(); //self-destruct if no further operations are pending this.entityDropItem(new ItemStack(ModItems.drone, 1, EnumDroneType.REQUEST.ordinal()), 1F); + return; + } + + Object next = program.get(0); + System.out.println("next action: " + next); + program.remove(0); + + if(next instanceof BlockPos) { + BlockPos pos = (BlockPos) next; + this.setTarget(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); + System.out.println("targetting"); + } else if(next instanceof AStack && heldItem == null) { + + AStack aStack = (AStack) next; + TileEntity tile = worldObj.getTileEntity((int) Math.floor(posX), (int) Math.floor(posY - 1), (int) Math.floor(posZ)); + + if(tile instanceof TileEntityDroneProvider) { + TileEntityDroneProvider provider = (TileEntityDroneProvider) tile; + + for(int i = 0; i < provider.slots.length; i++) { + ItemStack stack = provider.slots[i]; + + if(stack != null && aStack.matchesRecipe(stack, true)) { + this.heldItem = stack.copy(); + this.setAppearance(1); + provider.slots[i] = null; + provider.markDirty(); + break; + } + } + } + System.out.println("loading"); + } else if(next == DroneProgram.UNLOAD && this.heldItem != null) { + + TileEntity tile = worldObj.getTileEntity((int) Math.floor(posX), (int) Math.floor(posY - 1), (int) Math.floor(posZ)); + if(tile instanceof TileEntityDroneRequester) { + TileEntityDroneRequester requester = (TileEntityDroneRequester) tile; + + for(int i = 9; i < 18; i++) { + ItemStack stack = requester.slots[i]; + if(stack != null && stack.getItem() == heldItem.getItem() && stack.getItemDamage() == heldItem.getItemDamage()) { + int toTransfer = Math.min(stack.getMaxStackSize() - stack.stackSize, heldItem.stackSize); + requester.slots[i].stackSize += toTransfer; + this.heldItem.stackSize -= toTransfer; + } + } + + if(this.heldItem.stackSize <= 0) this.heldItem = null; + + if(this.heldItem != null) for(int i = 9; i < 18; i++) { + if(requester.slots[i] == null) { + requester.slots[i] = this.heldItem.copy(); + this.heldItem = null; + break; + } + } + + if(this.heldItem == null) { + this.setAppearance(0); + } + + requester.markDirty(); + } + System.out.println("unloading"); + } else if(next == DroneProgram.DOCK) { + + TileEntity tile = worldObj.getTileEntity((int) Math.floor(posX), (int) Math.floor(posY - 1), (int) Math.floor(posZ)); + if(tile instanceof TileEntityDroneDock) { + TileEntityDroneDock dock = (TileEntityDroneDock) tile; + + for(int i = 0; i < dock.slots.length; i++) { + if(dock.slots[i] == null) { + this.setDead(); + dock.slots[i] = new ItemStack(ModItems.drone, 1, EnumDroneType.REQUEST.ordinal()); + break; + } + } + } + + if(!this.isDead) { + this.setDead(); + this.entityDropItem(new ItemStack(ModItems.drone, 1, EnumDroneType.REQUEST.ordinal()), 1F); + } + System.out.println("docking"); } } } } } + @Override + public double getSpeed() { + return 0.5D; + } + @Override protected void readEntityFromNBT(NBTTagCompound nbt) { diff --git a/src/main/java/com/hbm/render/entity/item/RenderDeliveryDrone.java b/src/main/java/com/hbm/render/entity/item/RenderDeliveryDrone.java index 386235f40..04bbcf027 100644 --- a/src/main/java/com/hbm/render/entity/item/RenderDeliveryDrone.java +++ b/src/main/java/com/hbm/render/entity/item/RenderDeliveryDrone.java @@ -2,7 +2,7 @@ package com.hbm.render.entity.item; import org.lwjgl.opengl.GL11; -import com.hbm.entity.item.EntityDeliveryDrone; +import com.hbm.entity.item.EntityDroneBase; import com.hbm.entity.item.EntityRequestDrone; import com.hbm.main.ResourceManager; @@ -29,7 +29,7 @@ public class RenderDeliveryDrone extends Render { bindTexture(ResourceManager.delivery_drone_tex); ResourceManager.delivery_drone.renderPart("Drone"); - EntityDeliveryDrone drone = (EntityDeliveryDrone) entity; + EntityDroneBase drone = (EntityDroneBase) entity; int style = drone.getAppearance(); if(style == 1) ResourceManager.delivery_drone.renderPart("Crate"); diff --git a/src/main/java/com/hbm/tileentity/network/RequestNetwork.java b/src/main/java/com/hbm/tileentity/network/RequestNetwork.java index 6e01086a0..cb1116004 100644 --- a/src/main/java/com/hbm/tileentity/network/RequestNetwork.java +++ b/src/main/java/com/hbm/tileentity/network/RequestNetwork.java @@ -1,13 +1,12 @@ package com.hbm.tileentity.network; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; -import java.util.Set; import com.hbm.inventory.RecipesCommon.AStack; +import com.hbm.util.HashedSet; import com.hbm.util.fauxpointtwelve.BlockPos; import net.minecraft.item.ItemStack; @@ -17,7 +16,7 @@ import net.minecraft.world.World; public class RequestNetwork { private static int timer = 0; - public static HashMap>> activeWaypoints = new HashMap(); + public static HashMap>> activeWaypoints = new HashMap(); public static final int maxAge = 2_000; public static void updateEntries() { @@ -33,13 +32,13 @@ public class RequestNetwork { // iterate over each dim while(worldIt.hasNext()) { - Entry>> worldEntry = (Entry) worldIt.next(); + Entry>> worldEntry = (Entry) worldIt.next(); Iterator chunkIt = worldEntry.getValue().entrySet().iterator(); // iterate over each chunk while(chunkIt.hasNext()) { - Entry> chunkEntry = (Entry) chunkIt.next(); + Entry> chunkEntry = (Entry) chunkIt.next(); Iterator pathIt = chunkEntry.getValue().iterator(); // iterate over each path node @@ -71,10 +70,10 @@ public class RequestNetwork { public static class PathNode { public BlockPos pos; public long lease; - public Set reachableNodes = new HashSet(); - public PathNode(BlockPos pos, Set reachableNodes) { + public HashedSet reachableNodes = new HashedSet(); + public PathNode(BlockPos pos, HashedSet reachableNodes) { this.pos = pos; - this.reachableNodes = new HashSet(reachableNodes); + this.reachableNodes = new HashedSet(reachableNodes); this.lease = System.currentTimeMillis(); } @Override public int hashCode() { return pos.hashCode(); } @@ -84,7 +83,7 @@ public class RequestNetwork { /** Node created by providers, lists available items */ public static class OfferNode extends PathNode { public List offer; - public OfferNode(BlockPos pos, Set reachableNodes, List offer) { + public OfferNode(BlockPos pos, HashedSet reachableNodes, List offer) { super(pos, reachableNodes); this.offer = offer; } @@ -93,7 +92,7 @@ public class RequestNetwork { /** Node created by requesters, lists requested AStacks */ public static class RequestNode extends PathNode { public List request; - public RequestNode(BlockPos pos, Set reachableNodes, List request) { + public RequestNode(BlockPos pos, HashedSet reachableNodes, List request) { super(pos, reachableNodes); this.request = request; } diff --git a/src/main/java/com/hbm/tileentity/network/TileEntityDroneDock.java b/src/main/java/com/hbm/tileentity/network/TileEntityDroneDock.java index f190ea216..3aa212846 100644 --- a/src/main/java/com/hbm/tileentity/network/TileEntityDroneDock.java +++ b/src/main/java/com/hbm/tileentity/network/TileEntityDroneDock.java @@ -3,7 +3,6 @@ package com.hbm.tileentity.network; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Set; import com.hbm.entity.item.EntityRequestDrone; import com.hbm.entity.item.EntityRequestDrone.DroneProgram; @@ -16,6 +15,7 @@ import com.hbm.tileentity.IGUIProvider; import com.hbm.tileentity.network.RequestNetwork.OfferNode; import com.hbm.tileentity.network.RequestNetwork.PathNode; import com.hbm.tileentity.network.RequestNetwork.RequestNode; +import com.hbm.util.HashedSet; import com.hbm.util.fauxpointtwelve.BlockPos; import cpw.mods.fml.relauncher.Side; @@ -46,7 +46,7 @@ public class TileEntityDroneDock extends TileEntityRequestNetworkContainer imple if(!worldObj.isRemote && worldObj.getTotalWorldTime() % 100 == 0 && this.hasDrone()) { // grab all nodes in a 5 chunk radius - Set localNodes = this.getAllLocalNodes(worldObj, xCoord, zCoord, 5); + HashedSet localNodes = this.getAllLocalNodes(worldObj, xCoord, zCoord, 5); List requests = new ArrayList(); List offers = new ArrayList(); @@ -72,14 +72,14 @@ public class TileEntityDroneDock extends TileEntityRequestNetworkContainer imple if(firstRequest != null) { - PathNode own = createNode(new BlockPos(xCoord, yCoord + 1, zCoord)); + PathNode own = localNodes.getMap().get(new BlockPos(xCoord, yCoord + 1, zCoord).hashCode()); AStack request = firstRequest.request.get(worldObj.rand.nextInt(firstRequest.request.size())); outer: for(OfferNode offer : offers) { for(ItemStack stack : offer.offer) { if(stack != null && request.matchesRecipe(stack, true)) { - if(tryEmbark(own, firstRequest, offer, request)) break attempt; // if the drone can be pathed and spawned, stop doing more attempts + if(tryEmbark(own, firstRequest, offer, request, localNodes)) break attempt; // if the drone can be pathed and spawned, stop doing more attempts break outer; // if not, simply continue iterating over offer nodes } } @@ -89,13 +89,13 @@ public class TileEntityDroneDock extends TileEntityRequestNetworkContainer imple } } - public boolean tryEmbark(PathNode dock, RequestNode request, OfferNode offer, AStack item) { - - List dockToOffer = generatePath(dock, offer); + public boolean tryEmbark(PathNode dock, RequestNode request, OfferNode offer, AStack item, HashedSet localNodes) { + + List dockToOffer = generatePath(dock, offer, localNodes); if(dockToOffer == null) return false; - List offerToRequest = generatePath(offer, request); + List offerToRequest = generatePath(offer, request, localNodes); if(offerToRequest == null) return false; - List requestToDock = generatePath(request, dock); + List requestToDock = generatePath(request, dock, localNodes); if(requestToDock == null) return false; @@ -111,20 +111,22 @@ public class TileEntityDroneDock extends TileEntityRequestNetworkContainer imple drone.setPosition(xCoord + 0.5, yCoord + 1, zCoord + 0.5); // write programming - for(PathNode node : dockToOffer) drone.program.add(node); - drone.program.add(offer); + for(PathNode node : dockToOffer) drone.program.add(node.pos); + drone.program.add(offer.pos); drone.program.add(item); - for(PathNode node : offerToRequest) drone.program.add(node); - drone.program.add(request); + for(PathNode node : offerToRequest) drone.program.add(node.pos); + drone.program.add(request.pos); drone.program.add(DroneProgram.UNLOAD); - for(PathNode node : requestToDock) drone.program.add(node); - drone.program.add(dock); + for(PathNode node : requestToDock) drone.program.add(node.pos); + drone.program.add(dock.pos); drone.program.add(DroneProgram.DOCK); + worldObj.spawnEntityInWorld(drone); + return true; } - public List generatePath(PathNode start, PathNode end) { + public List generatePath(PathNode start, PathNode end, HashedSet localNodes) { List> paths = new ArrayList(); List init = new ArrayList(); @@ -137,17 +139,22 @@ public class TileEntityDroneDock extends TileEntityRequestNetworkContainer imple List> newPaths = new ArrayList(); for(List oldPath : paths) { - for(PathNode connected : oldPath.get(oldPath.size() - 1).reachableNodes) { - List newPath = new ArrayList(); - newPath.addAll(oldPath); + for(PathNode connectedUnsafe : oldPath.get(oldPath.size() - 1).reachableNodes) { - if(connected.hashCode() == end.hashCode()) { - newPath.remove(0); // we only want the in-betweens - return newPath; + PathNode connectedSafe = localNodes.getMap().get(connectedUnsafe.hashCode()); // lookup to translate potentially outdated nodes into current ones + if(connectedSafe != null) { + + List newPath = new ArrayList(); + newPath.addAll(oldPath); + + if(connectedSafe.hashCode() == end.hashCode()) { + newPath.remove(0); // we only want the in-betweens + return newPath; + } + + newPath.add(connectedSafe); + newPaths.add(newPath); } - - newPath.add(connected); - newPaths.add(newPath); } } diff --git a/src/main/java/com/hbm/tileentity/network/TileEntityRequestNetwork.java b/src/main/java/com/hbm/tileentity/network/TileEntityRequestNetwork.java index c64efc326..4e385f5d1 100644 --- a/src/main/java/com/hbm/tileentity/network/TileEntityRequestNetwork.java +++ b/src/main/java/com/hbm/tileentity/network/TileEntityRequestNetwork.java @@ -1,13 +1,12 @@ package com.hbm.tileentity.network; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; -import java.util.Set; import com.hbm.packet.AuxParticlePacketNT; import com.hbm.packet.PacketDispatcher; import com.hbm.tileentity.network.RequestNetwork.PathNode; +import com.hbm.util.HashedSet; import com.hbm.util.ParticleUtil; import com.hbm.util.fauxpointtwelve.BlockPos; @@ -31,8 +30,8 @@ import net.minecraft.world.World; */ public abstract class TileEntityRequestNetwork extends TileEntity { - public Set reachableNodes = new HashSet(); - public Set knownNodes = new HashSet(); + public HashedSet reachableNodes = new HashedSet(); + public HashedSet knownNodes = new HashedSet(); public static final int maxRange = 24; @Override @@ -48,7 +47,7 @@ public abstract class TileEntityRequestNetwork extends TileEntity { // remove known nodes that no longer exist // since we can assume a sane number of nodes to exist at any given time, we can run this check in full every second Iterator it = knownNodes.iterator(); - Set localNodes = this.getAllLocalNodes(worldObj, xCoord, zCoord, 2); // this bit may spiral into multiple nested hashtable lookups but it's limited to only a few chunks so it shouldn't be an issue + HashedSet localNodes = this.getAllLocalNodes(worldObj, xCoord, zCoord, 2); // this bit may spiral into multiple nested hashtable lookups but it's limited to only a few chunks so it shouldn't be an issue localNodes.remove(pos); while(it.hasNext()) { PathNode node = it.next(); @@ -136,7 +135,7 @@ public abstract class TileEntityRequestNetwork extends TileEntity { */ public static void push(World world, PathNode node) { - HashMap> coordMap = RequestNetwork.activeWaypoints.get(world); + HashMap> coordMap = RequestNetwork.activeWaypoints.get(world); if(coordMap == null) { coordMap = new HashMap(); @@ -144,10 +143,10 @@ public abstract class TileEntityRequestNetwork extends TileEntity { } ChunkCoordIntPair chunkPos = new ChunkCoordIntPair(node.pos.getX() >> 4, node.pos.getZ() >> 4); - Set posList = coordMap.get(chunkPos); + HashedSet posList = coordMap.get(chunkPos); if(posList == null) { - posList = new HashSet(); + posList = new HashedSet(); coordMap.put(chunkPos, posList); } @@ -162,22 +161,22 @@ public abstract class TileEntityRequestNetwork extends TileEntity { * @param z * @return */ - public static Set getAllLocalNodes(World world, int x, int z, int range) { + public static HashedSet getAllLocalNodes(World world, int x, int z, int range) { - Set nodes = new HashSet(); - Set pos = new HashSet(); + HashedSet nodes = new HashedSet(); + HashedSet pos = new HashedSet(); x >>= 4; z >>= 4; - HashMap> coordMap = RequestNetwork.activeWaypoints.get(world); + HashMap> coordMap = RequestNetwork.activeWaypoints.get(world); if(coordMap == null) return nodes; for(int i = -range; i <= range; i++) { for(int j = -range; j <= range; j++) { - Set nodeList = coordMap.get(new ChunkCoordIntPair(x + i, z + j)); + HashedSet nodeList = coordMap.get(new ChunkCoordIntPair(x + i, z + j)); if(nodeList != null) for(PathNode node : nodeList) { if(!pos.contains(node.pos)) { diff --git a/src/main/java/com/hbm/util/HashedSet.java b/src/main/java/com/hbm/util/HashedSet.java new file mode 100644 index 000000000..861862206 --- /dev/null +++ b/src/main/java/com/hbm/util/HashedSet.java @@ -0,0 +1,132 @@ +package com.hbm.util; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.Set; + +import org.apache.commons.lang3.NotImplementedException; + +/** + * Through whichever mechanism, HashSets allow for multiple instances with the same hash, even though they already has that hash during instantiation + * How is this possible? I don't know and I don't want to know. + * + * This is a crude recreation using a HashMap and, instead of whichever braindead bullshit HashSet does, this HashMap uses the hashCode() as the key and the object as the value. + * + * @author hbm + * + * @param + */ +public class HashedSet implements Set { + + HashMap map = new HashMap(); + + public static class HashedIterator implements Iterator { + + private Iterator> iterator; + + public HashedIterator(HashedSet set) { + this.iterator = set.map.entrySet().iterator(); + } + + @Override + public boolean hasNext() { + return this.iterator.hasNext(); + } + + @Override + public Object next() { + return this.iterator.next().getValue(); + } + + @Override + public void remove() { + this.iterator.remove(); + } + } + + public HashedSet() { } + + public HashedSet(Set reachableNodes) { + this.addAll(reachableNodes); + } + + public HashMap getMap() { + return this.map; + } + + @Override + public boolean add(Object e) { + boolean contains = this.contains(e); + this.map.put(e.hashCode(), (T) e); + return contains; + } + + @Override + public boolean addAll(Collection c) { + boolean ret = false; + for(Object o : c) if(add(o)) ret = true; + return ret; + } + + @Override + public void clear() { + this.map.clear(); + } + + @Override + public boolean contains(Object o) { + return this.map.containsKey(o.hashCode()); + } + + @Override + public boolean containsAll(Collection c) { + + for(Object o : c) { + if(!this.contains(o)) return false; + } + + return true; + } + + @Override + public boolean isEmpty() { + return this.map.isEmpty(); + } + + @Override + public Iterator iterator() { + return new HashedIterator(this); + } + + @Override + public boolean remove(Object o) { + return false; + } + + @Override + public boolean removeAll(Collection c) { + return false; + } + + @Override + public boolean retainAll(Collection c) { + throw new NotImplementedException("Fuck you"); + } + + @Override + public int size() { + return this.map.size(); + } + + @Override + public Object[] toArray() { + throw new NotImplementedException("Fuck you"); + } + + @Override + public Object[] toArray(Object[] a) { + throw new NotImplementedException("Fuck you"); + } +}