From d1e4d1572fe5709b037c8426541a0c12ca773ff0 Mon Sep 17 00:00:00 2001 From: KellenHurrey Date: Tue, 11 Mar 2025 22:28:00 -0700 Subject: [PATCH] wholy shit i actually fixed chunkloading drones (and added a new util class) --- .../hbm/entity/item/EntityDeliveryDrone.java | 50 ++++---- .../com/hbm/entity/item/EntityDroneBase.java | 35 +++--- .../java/com/hbm/util/ChunkShapeHelper.java | 113 ++++++++++++++++++ 3 files changed, 155 insertions(+), 43 deletions(-) create mode 100644 src/main/java/com/hbm/util/ChunkShapeHelper.java diff --git a/src/main/java/com/hbm/entity/item/EntityDeliveryDrone.java b/src/main/java/com/hbm/entity/item/EntityDeliveryDrone.java index d26e96767..1d3e9674b 100644 --- a/src/main/java/com/hbm/entity/item/EntityDeliveryDrone.java +++ b/src/main/java/com/hbm/entity/item/EntityDeliveryDrone.java @@ -7,6 +7,7 @@ import com.hbm.inventory.fluid.Fluids; import com.hbm.items.ModItems; import com.hbm.main.MainRegistry; +import com.hbm.util.ChunkShapeHelper; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; @@ -20,13 +21,13 @@ import net.minecraftforge.common.ForgeChunkManager.Ticket; import net.minecraftforge.common.ForgeChunkManager.Type; public class EntityDeliveryDrone extends EntityDroneBase implements IInventory, IChunkLoader { - + protected ItemStack[] slots = new ItemStack[this.getSizeInventory()]; public FluidStack fluid; - + protected boolean chunkLoading = false; private Ticket loaderTicket; - + public EntityDeliveryDrone(World world) { super(world); } @@ -60,32 +61,22 @@ public class EntityDeliveryDrone extends EntityDroneBase implements IInventory, super.entityInit(); this.dataWatcher.addObject(11, new Byte((byte) 0)); } - - public EntityDeliveryDrone setChunkLoading() { + + public void setChunkLoading() { init(ForgeChunkManager.requestTicket(MainRegistry.instance, worldObj, Type.ENTITY)); this.chunkLoading = true; - return this; } - @Override - public void onUpdate() { - - if(!worldObj.isRemote) { - loadNeighboringChunks((int)Math.floor(posX / 16D), (int)Math.floor(posZ / 16D)); - } - - super.onUpdate(); - } @Override public double getSpeed() { return this.dataWatcher.getWatchableObjectByte(11) == 1 ? 0.375 * 3 : 0.375; } - + @Override protected void writeEntityToNBT(NBTTagCompound nbt) { super.writeEntityToNBT(nbt); - + NBTTagList nbttaglist = new NBTTagList(); for(int i = 0; i < this.slots.length; ++i) { @@ -98,7 +89,7 @@ public class EntityDeliveryDrone extends EntityDroneBase implements IInventory, } nbt.setTag("Items", nbttaglist); - + if(fluid != null) { nbt.setInteger("fluidType", fluid.type.getID()); nbt.setInteger("fluidAmount", fluid.fill); @@ -111,7 +102,7 @@ public class EntityDeliveryDrone extends EntityDroneBase implements IInventory, @Override protected void readEntityFromNBT(NBTTagCompound nbt) { super.readEntityFromNBT(nbt); - + NBTTagList nbttaglist = nbt.getTagList("Items", 10); this.slots = new ItemStack[this.getSizeInventory()]; @@ -123,14 +114,14 @@ public class EntityDeliveryDrone extends EntityDroneBase implements IInventory, this.slots[j] = ItemStack.loadItemStackFromNBT(nbttagcompound1); } } - + if(nbt.hasKey("fluidType")) { FluidType type = Fluids.fromNameCompat(nbt.getString("fluidType")); if(type != Fluids.NONE) { nbt.removeTag(nbt.getString("fluidType")); } else type = Fluids.fromID(nbt.getInteger("fluidType")); - + this.fluid = new FluidStack(type, nbt.getInteger("fluidAmount")); } @@ -142,7 +133,7 @@ public class EntityDeliveryDrone extends EntityDroneBase implements IInventory, public ItemStack getStackInSlot(int slot) { return slots[slot]; } - + @Override public ItemStack decrStackSize(int slot, int amount) { if(this.slots[slot] != null) { @@ -197,20 +188,23 @@ public class EntityDeliveryDrone extends EntityDroneBase implements IInventory, @Override public void openInventory() { } @Override public void closeInventory() { } - public void loadNeighboringChunks(int newChunkX, int newChunkZ) { + @Override + protected void loadNeighboringChunks() { if(!worldObj.isRemote && loaderTicket != null) { clearChunkLoader(); - ForgeChunkManager.forceChunk(loaderTicket, new ChunkCoordIntPair(newChunkX, newChunkZ)); - ForgeChunkManager.forceChunk(loaderTicket, new ChunkCoordIntPair((int) Math.ceil((this.posX + this.motionX) / 16D), (int) Math.ceil((this.posZ + this.motionZ) / 16D))); + // This is the lowest padding that worked with my drone waypoint path. if they stop getting loaded crank up paddingSize + for (ChunkCoordIntPair chunk : ChunkShapeHelper.getChunksAlongLineSegment((int) this.posX, (int) this.posZ, (int) (this.posX + this.motionX), (int) (this.posZ + this.motionZ), 4)){ + ForgeChunkManager.forceChunk(loaderTicket, chunk); + } } } - + @Override public void setDead() { super.setDead(); this.clearChunkLoader(); } - + public void clearChunkLoader() { if(!worldObj.isRemote && loaderTicket != null) { for(ChunkCoordIntPair chunk : loaderTicket.getChunkList()) { @@ -227,7 +221,7 @@ public class EntityDeliveryDrone extends EntityDroneBase implements IInventory, loaderTicket.bindEntity(this); loaderTicket.getModData(); } - ForgeChunkManager.forceChunk(loaderTicket, new ChunkCoordIntPair(chunkCoordX, chunkCoordZ)); + this.loadNeighboringChunks(); } } } diff --git a/src/main/java/com/hbm/entity/item/EntityDroneBase.java b/src/main/java/com/hbm/entity/item/EntityDroneBase.java index b6e269869..cdd8c000b 100644 --- a/src/main/java/com/hbm/entity/item/EntityDroneBase.java +++ b/src/main/java/com/hbm/entity/item/EntityDroneBase.java @@ -9,7 +9,7 @@ import net.minecraft.util.Vec3; import net.minecraft.world.World; public abstract class EntityDroneBase extends Entity { - + protected int turnProgress; protected double syncPosX; protected double syncPosY; @@ -26,7 +26,7 @@ public abstract class EntityDroneBase extends Entity { super(world); this.setSize(1.5F, 2.0F); } - + public void setTarget(double x, double y, double z) { this.targetX = x; this.targetY = y; @@ -49,7 +49,7 @@ public abstract class EntityDroneBase extends Entity { if(attacker instanceof EntityPlayer) { this.setDead(); } - + return false; } @@ -62,7 +62,7 @@ public abstract class EntityDroneBase extends Entity { protected void entityInit() { this.dataWatcher.addObject(10, new Byte((byte) 0)); } - + /** * 0: Empty
* 1: Crate
@@ -71,14 +71,14 @@ public abstract class EntityDroneBase extends Entity { public void setAppearance(int style) { this.dataWatcher.updateObject(10, (byte) style); } - + public int getAppearance() { return this.dataWatcher.getWatchableObjectByte(10); } - + @Override public void onUpdate() { - + if(worldObj.isRemote) { if(this.turnProgress > 0) { double interpX = this.posX + (this.syncPosX - this.posX) / (double) this.turnProgress; @@ -99,12 +99,12 @@ public abstract class EntityDroneBase extends Entity { this.motionX = 0; this.motionY = 0; this.motionZ = 0; - + if(this.targetY != -1) { - + Vec3 dist = Vec3.createVectorHelper(targetX - posX, targetY - posY, targetZ - posZ); double speed = Math.min(getSpeed(), dist.lengthVector()); - + dist = dist.normalize(); this.motionX = dist.xCoord * speed; this.motionY = dist.yCoord * speed; @@ -113,21 +113,26 @@ public abstract class EntityDroneBase extends Entity { if(isCollidedHorizontally){ motionY += 1; } + this.loadNeighboringChunks(); this.moveEntity(motionX, motionY, motionZ); } + + super.onUpdate(); } - + + protected void loadNeighboringChunks() {} + public double getSpeed() { return 0.125D; } - + @SideOnly(Side.CLIENT) public void setVelocity(double motionX, double motionY, double motionZ) { this.velocityX = this.motionX = motionX; this.velocityY = this.motionY = motionY; this.velocityZ = this.motionZ = motionZ; } - + @SideOnly(Side.CLIENT) public void setPositionAndRotation2(double x, double y, double z, float yaw, float pitch, int theNumberThree) { this.syncPosX = x; @@ -138,7 +143,7 @@ public abstract class EntityDroneBase extends Entity { this.motionY = this.velocityY; this.motionZ = this.velocityZ; } - + @Override protected void writeEntityToNBT(NBTTagCompound nbt) { @@ -157,7 +162,7 @@ public abstract class EntityDroneBase extends Entity { this.targetY = nbt.getDouble("tY"); this.targetZ = nbt.getDouble("tZ"); } - + this.dataWatcher.updateObject(10, nbt.getByte("app")); } } diff --git a/src/main/java/com/hbm/util/ChunkShapeHelper.java b/src/main/java/com/hbm/util/ChunkShapeHelper.java new file mode 100644 index 000000000..6722d5422 --- /dev/null +++ b/src/main/java/com/hbm/util/ChunkShapeHelper.java @@ -0,0 +1,113 @@ +package com.hbm.util; + +import java.util.List; +import java.util.ArrayList; + +import net.minecraft.world.ChunkCoordIntPair; + +public class ChunkShapeHelper { + + + // Help what are projections + private static double pointSegmentDist(int x1, int z1, int x2, int z2, int px, int pz) { + int dx = x2 - x1; + int dz = z2 - z1; + + // The segment is just a point + if (dx == 0 && dz == 0) { + // intellij is telling me that this is duplicated, but it would be more expensive to move it out of the if statements + return Math.sqrt((px - x1) * (px - x1) + (pz - z1) * (pz - z1)); + } + + // Calculate the projection t of point P onto the infinite line through A and B + double t = ((px - x1) * dx + (pz - z1) * dz) / (double) (dx * dx + dz * dz); + + + // Closest to point (x1, z1) + if (t < 0) { + return Math.sqrt((px - x1) * (px - x1) + (pz - z1) * (pz - z1)); + } else if (t > 1) { + // Closest to point (x2, z2) + return Math.sqrt((px - x2) * (px - x2) + (pz - z2) * (pz - z2)); + } + // Projection is within the segment + + double projX = x1 + t * dx; + double projZ = z1 + t * dz; + + // Magic math + return Math.sqrt((px - projX) * (px - projX) + (pz - projZ) * (pz - projZ)); + } + + // Loop through the corners of the box and check their distances (yes I know that this doest work with the endpoints very well, but fuck off ive done too much math today) + private static double boxLineDist(int lineX0, int lineZ0, int lineX1, int lineZ1, int boxX, int boxZ) { + double minDist = Double.MAX_VALUE; + + int[][] corners = {{0, 0}, {0, 16}, {16, 0}, {16, 16}}; + for (int[] corner : corners) { + minDist = Math.min(minDist, pointSegmentDist(lineX0, lineZ0, lineX1, lineZ1, boxX + corner[0], boxZ + corner[1])); + } + + return minDist; + } + + // 90% of this is Bresenham's Line Algorithm, and the other part is messy padding + // The xs and zs are the endpoints fo the line segment, and paddingSize is how many blocks away a chunk needs to be to not be included + // Dont give chunk coords + public static List getChunksAlongLineSegment(int x0, int z0, int x1, int z1, double paddingSize) { + int dx = Math.abs(x1 - x0); + int sx = x0 < x1 ? 1 : -1; + int dz = -Math.abs(z1 - z0); + int sz = z0 < z1 ? 1 : -1; + int error = dx + dz; + + // Just store the original starting point because we fuck with it in the loop + int originalX = x0; + int originalZ = z0; + + // The chunks we are returning + List out = new ArrayList<>(); + // The chunks we have aready checked for their distance so we dont run it over and over + List checked = new ArrayList<>(); + + // Ahhh scary while true + while (true) { + // Add the current chunk coords, if they havent already been added + ChunkCoordIntPair coords = new ChunkCoordIntPair(x0 >> 4, z0 >> 4); + if (!out.contains(coords)) { + out.add(coords); + } + + // My messy padding code: loop over each of the chunks next to the one we just added + int[][] corners = {{-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}}; + for (int[] corner : corners) { + + // If we already checked this one keep going + ChunkCoordIntPair cornerCoords = new ChunkCoordIntPair((x0 >> 4) + corner[0], (z0 >> 4) + corner[1]); + if (checked.contains(cornerCoords)) continue; + checked.add(cornerCoords); + + // If this box isn't already added, and it is closer than paddingSize, then add it + if (!out.contains(cornerCoords) && boxLineDist(originalX, originalZ, x1, z1, cornerCoords.chunkXPos * 16, cornerCoords.chunkZPos * 16) < paddingSize) { + out.add(cornerCoords); + } + } + + // Wikipedia take the wheel + int e2 = 2 * error; + if (e2 >= dz) { + if (x0 == x1) break; + error += dz; + x0 += sx; + } + if (e2 <= dx) { + if (z0 == z1) break; + error += dx; + z0 += sz; + } + } + + return out; + + } +}