From f5c17f8bd7b638eb3f483724919d519cea125c90 Mon Sep 17 00:00:00 2001 From: Bob Date: Sat, 23 Sep 2023 23:34:22 +0200 Subject: [PATCH] smart pathing waypoints --- src/main/java/com/hbm/blocks/ModBlocks.java | 3 + .../com/hbm/blocks/network/DroneCrate.java | 4 + .../blocks/network/DroneWaypointRequest.java | 100 +++++++++ .../hbm/entity/item/EntityDeliveryDrone.java | 146 +++++++------- .../com/hbm/entity/item/EntityDroneBase.java | 97 +++++++++ .../inventory/gui/GUIMachineTurbineGas.java | 4 - src/main/java/com/hbm/items/ModItems.java | 3 + .../com/hbm/items/special/ItemAntiCheat.java | 33 --- .../java/com/hbm/items/tool/ItemDrone.java | 50 +++++ .../java/com/hbm/main/ResourceManager.java | 1 + .../entity/item/RenderDeliveryDrone.java | 6 +- .../hbm/render/entity/mob/RenderGlyphid.java | 3 - .../entity/mob/RenderGlyphidNuclear.java | 2 - .../java/com/hbm/tileentity/TileMappings.java | 1 + .../network/TileEntityDroneWaypoint.java | 9 +- .../TileEntityDroneWaypointRequest.java | 189 ++++++++++++++++++ src/main/java/com/hbm/util/ParticleUtil.java | 18 ++ .../hbm/textures/blocks/diamond_block.png | Bin 469 -> 0 bytes .../hbm/textures/blocks/diamond_ore.png | Bin 262 -> 0 bytes .../blocks/drone_waypoint_request.png | Bin 0 -> 239 bytes .../blocks/drone_waypoint_request.png.mcmeta | 5 + .../hbm/textures/blocks/emerald_ore.png | Bin 364 -> 0 bytes .../{delivery_drone.png => drone.patrol.png} | Bin .../items/drone.patrol_chunkloading.png | Bin 0 -> 284 bytes .../textures/items/drone.patrol_express.png | Bin 0 -> 264 bytes .../drone.patrol_express_chunkloading.png | Bin 0 -> 281 bytes .../hbm/textures/items/drone.request.png | Bin 0 -> 262 bytes .../hbm/textures/models/machines/drone.png | Bin 2748 -> 2506 bytes .../models/machines/drone_express.png | Bin 0 -> 2744 bytes .../models/machines/drone_request.png | Bin 0 -> 2759 bytes 30 files changed, 550 insertions(+), 124 deletions(-) create mode 100644 src/main/java/com/hbm/blocks/network/DroneWaypointRequest.java create mode 100644 src/main/java/com/hbm/entity/item/EntityDroneBase.java delete mode 100644 src/main/java/com/hbm/items/special/ItemAntiCheat.java create mode 100644 src/main/java/com/hbm/items/tool/ItemDrone.java create mode 100644 src/main/java/com/hbm/tileentity/network/TileEntityDroneWaypointRequest.java delete mode 100644 src/main/resources/assets/hbm/textures/blocks/diamond_block.png delete mode 100644 src/main/resources/assets/hbm/textures/blocks/diamond_ore.png create mode 100644 src/main/resources/assets/hbm/textures/blocks/drone_waypoint_request.png create mode 100755 src/main/resources/assets/hbm/textures/blocks/drone_waypoint_request.png.mcmeta delete mode 100644 src/main/resources/assets/hbm/textures/blocks/emerald_ore.png rename src/main/resources/assets/hbm/textures/items/{delivery_drone.png => drone.patrol.png} (100%) create mode 100644 src/main/resources/assets/hbm/textures/items/drone.patrol_chunkloading.png create mode 100644 src/main/resources/assets/hbm/textures/items/drone.patrol_express.png create mode 100644 src/main/resources/assets/hbm/textures/items/drone.patrol_express_chunkloading.png create mode 100644 src/main/resources/assets/hbm/textures/items/drone.request.png create mode 100644 src/main/resources/assets/hbm/textures/models/machines/drone_express.png create mode 100644 src/main/resources/assets/hbm/textures/models/machines/drone_request.png diff --git a/src/main/java/com/hbm/blocks/ModBlocks.java b/src/main/java/com/hbm/blocks/ModBlocks.java index c348fc5b3..c297d4391 100644 --- a/src/main/java/com/hbm/blocks/ModBlocks.java +++ b/src/main/java/com/hbm/blocks/ModBlocks.java @@ -821,6 +821,7 @@ public class ModBlocks { public static Block crane_splitter; public static Block drone_waypoint; + public static Block drone_waypoint_request; public static Block drone_crate; public static Block fan; @@ -1994,6 +1995,7 @@ public class ModBlocks { piston_inserter = new PistonInserter().setBlockName("piston_inserter").setHardness(5.0F).setResistance(10.0F).setCreativeTab(MainRegistry.machineTab).setBlockTextureName(RefStrings.MODID + ":block_steel"); drone_waypoint = new DroneWaypoint().setBlockName("drone_waypoint").setHardness(0.1F).setResistance(10.0F).setCreativeTab(MainRegistry.machineTab).setBlockTextureName(RefStrings.MODID + ":drone_waypoint"); + drone_waypoint_request = new DroneWaypointRequest().setBlockName("drone_waypoint_request").setHardness(0.1F).setResistance(10.0F).setCreativeTab(MainRegistry.machineTab).setBlockTextureName(RefStrings.MODID + ":drone_waypoint_request"); drone_crate = new DroneCrate().setBlockName("drone_crate").setHardness(0.1F).setResistance(10.0F).setCreativeTab(MainRegistry.machineTab); chain = new BlockChain(Material.iron).setBlockName("dungeon_chain").setHardness(0.25F).setResistance(2.0F).setCreativeTab(MainRegistry.blockTab).setBlockTextureName(RefStrings.MODID + ":chain"); @@ -3256,6 +3258,7 @@ public class ModBlocks { register(conveyor_lift); register(crane_splitter); register(drone_waypoint); + register(drone_waypoint_request); register(drone_crate); register(fan); register(piston_inserter); diff --git a/src/main/java/com/hbm/blocks/network/DroneCrate.java b/src/main/java/com/hbm/blocks/network/DroneCrate.java index bd82c8d20..94641ed8f 100644 --- a/src/main/java/com/hbm/blocks/network/DroneCrate.java +++ b/src/main/java/com/hbm/blocks/network/DroneCrate.java @@ -6,6 +6,7 @@ import java.util.Random; import com.hbm.blocks.ILookOverlay; import com.hbm.blocks.ITooltipProvider; +import com.hbm.items.ModItems; import com.hbm.lib.RefStrings; import com.hbm.main.MainRegistry; import com.hbm.tileentity.network.TileEntityDroneCrate; @@ -59,6 +60,9 @@ public class DroneCrate extends BlockContainer implements ILookOverlay, ITooltip @Override public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float hitX, float hitY, float hitZ) { + + if(player.getHeldItem() != null && player.getHeldItem().getItem() == ModItems.drone_linker) return false; + if(world.isRemote) { return true; } else if(!player.isSneaking()) { diff --git a/src/main/java/com/hbm/blocks/network/DroneWaypointRequest.java b/src/main/java/com/hbm/blocks/network/DroneWaypointRequest.java new file mode 100644 index 000000000..a02b63a3c --- /dev/null +++ b/src/main/java/com/hbm/blocks/network/DroneWaypointRequest.java @@ -0,0 +1,100 @@ +package com.hbm.blocks.network; + +import com.hbm.tileentity.network.TileEntityDroneWaypointRequest; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.block.Block; +import net.minecraft.block.BlockContainer; +import net.minecraft.block.material.Material; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.Vec3; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +public class DroneWaypointRequest extends BlockContainer { + + public DroneWaypointRequest() { + super(Material.circuits); + } + + @Override + public TileEntity createNewTileEntity(World world, int meta) { + return new TileEntityDroneWaypointRequest(); + } + + @Override + public int getRenderType() { + return RadioTorchBase.renderID; + } + + @Override + public boolean isOpaqueCube() { + return false; + } + + @Override + public boolean renderAsNormalBlock() { + return false; + } + + @Override + @SideOnly(Side.CLIENT) + public boolean shouldSideBeRendered(IBlockAccess world, int x, int y, int z, int side) { + return true; + } + + @Override + public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int x, int y, int z) { + return null; + } + + @Override + public MovingObjectPosition collisionRayTrace(World world, int x, int y, int z, Vec3 vec0, Vec3 vec1) { + + int meta = world.getBlockMetadata(x, y, z) & 7; + ForgeDirection dir = ForgeDirection.getOrientation(meta); + + this.setBlockBounds( + dir.offsetX == 1 ? 0F : 0.375F, + dir.offsetY == 1 ? 0F : 0.375F, + dir.offsetZ == 1 ? 0F : 0.375F, + dir.offsetX == -1 ? 1F : 0.625F, + dir.offsetY == -1 ? 1F : 0.625F, + dir.offsetZ == -1 ? 1F : 0.625F + ); + + return super.collisionRayTrace(world, x, y, z, vec0, vec1); + } + + @Override + public int onBlockPlaced(World world, int x, int y, int z, int side, float fX, float fY, float fZ, int meta) { + return side; + } + + @Override + public void onNeighborBlockChange(World world, int x, int y, int z, Block block) { + + int meta = world.getBlockMetadata(x, y, z); + ForgeDirection dir = ForgeDirection.getOrientation(meta); + Block b = world.getBlock(x - dir.offsetX, y - dir.offsetY, z - dir.offsetZ); + + if(!b.isSideSolid(world, x - dir.offsetX, y - dir.offsetY, z - dir.offsetZ, dir) && (!b.renderAsNormalBlock() || b.isAir(world, x, y, z))) { + this.dropBlockAsItem(world, x, y, z, meta, 0); + world.setBlockToAir(x, y, z); + } + } + + @Override + public boolean canPlaceBlockOnSide(World world, int x, int y, int z, int side) { + if(!super.canPlaceBlockOnSide(world, x, y, z, side)) return false; + + ForgeDirection dir = ForgeDirection.getOrientation(side); + Block b = world.getBlock(x - dir.offsetX, y - dir.offsetY, z - dir.offsetZ); + + return b.isSideSolid(world, x - dir.offsetX, y - dir.offsetY, z - dir.offsetZ, dir) || (b.renderAsNormalBlock() && !b.isAir(world, x, y, z)); + } +} diff --git a/src/main/java/com/hbm/entity/item/EntityDeliveryDrone.java b/src/main/java/com/hbm/entity/item/EntityDeliveryDrone.java index d63dd43d3..eb4b6e603 100644 --- a/src/main/java/com/hbm/entity/item/EntityDeliveryDrone.java +++ b/src/main/java/com/hbm/entity/item/EntityDeliveryDrone.java @@ -1,28 +1,25 @@ package com.hbm.entity.item; +import com.hbm.entity.logic.IChunkLoader; import com.hbm.inventory.FluidStack; import com.hbm.inventory.fluid.Fluids; +import com.hbm.main.MainRegistry; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; -import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.util.Vec3; +import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.World; +import net.minecraftforge.common.ForgeChunkManager; +import net.minecraftforge.common.ForgeChunkManager.Ticket; +import net.minecraftforge.common.ForgeChunkManager.Type; -public class EntityDeliveryDrone extends Entity implements IInventory { - - protected int turnProgress; - protected double syncPosX; - protected double syncPosY; - protected double syncPosZ; - @SideOnly(Side.CLIENT) protected double velocityX; - @SideOnly(Side.CLIENT) protected double velocityY; - @SideOnly(Side.CLIENT) protected double velocityZ; +public class EntityDeliveryDrone extends EntityDroneBase implements IInventory, IChunkLoader { protected ItemStack[] slots = new ItemStack[this.getSizeInventory()]; public FluidStack fluid; @@ -31,10 +28,24 @@ public class EntityDeliveryDrone extends Entity implements IInventory { public double targetY = -1; public double targetZ = -1; + private Ticket loaderTicket; + public boolean isChunkLoading = false; + public EntityDeliveryDrone(World world) { super(world); this.setSize(1.5F, 2.0F); } + + @Override + protected void entityInit() { + super.entityInit(); + this.dataWatcher.addObject(11, new Byte((byte) 0)); + } + + public EntityDeliveryDrone setChunkLoading() { + init(ForgeChunkManager.requestTicket(MainRegistry.instance, worldObj, Type.ENTITY)); + return this; + } public void setTarget(double x, double y, double z) { this.targetX = x; @@ -42,68 +53,11 @@ public class EntityDeliveryDrone extends Entity implements IInventory { this.targetZ = z; } - @Override - public boolean canBeCollidedWith() { - return true; - } - - @Override - public boolean canAttackWithItem() { - return true; - } - - @Override - public boolean hitByEntity(Entity attacker) { - - if(attacker instanceof EntityPlayer) { - this.setDead(); - } - - return false; - } - - @Override - protected boolean canTriggerWalking() { - return true; - } - - @Override - protected void entityInit() { - this.dataWatcher.addObject(10, new Byte((byte) 0)); - } - - /** - * 0: Empty
- * 1: Crate
- * 2: Barrel
- */ - public void setAppearance(int style) { - this.dataWatcher.updateObject(10, (byte) style); - } - - public int getAppearance() { - return this.dataWatcher.getWatchableObjectByte(10); - } - @Override public void onUpdate() { + super.onUpdate(); - if(worldObj.isRemote) { - if(this.turnProgress > 0) { - double interpX = this.posX + (this.syncPosX - this.posX) / (double) this.turnProgress; - double interpY = this.posY + (this.syncPosY - this.posY) / (double) this.turnProgress; - double interpZ = this.posZ + (this.syncPosZ - this.posZ) / (double) this.turnProgress; - --this.turnProgress; - this.setPosition(interpX, interpY, interpZ); - } else { - this.setPosition(this.posX, this.posY, this.posZ); - } - - worldObj.spawnParticle("smoke", posX + 1.125, posY + 0.75, posZ, 0, -0.2, 0); - worldObj.spawnParticle("smoke", posX - 1.125, posY + 0.75, posZ, 0, -0.2, 0); - worldObj.spawnParticle("smoke", posX, posY + 0.75, posZ + 1.125, 0, -0.2, 0); - worldObj.spawnParticle("smoke", posX, posY + 0.75, posZ - 1.125, 0, -0.2, 0); - } else { + if(!worldObj.isRemote) { this.motionX = 0; this.motionY = 0; @@ -122,12 +76,15 @@ public class EntityDeliveryDrone extends Entity implements IInventory { } } + loadNeighboringChunks((int)Math.floor(posX / 16D), (int)Math.floor(posZ / 16D)); + this.moveEntity(motionX, motionY, motionZ); } } - + + @Override public double getSpeed() { - return 0.125D; + return this.dataWatcher.getWatchableObjectByte(11) == 1 ? 0.375 : 0.125; } @Override @@ -154,6 +111,9 @@ public class EntityDeliveryDrone extends Entity implements IInventory { nbt.setString("fluidType", fluid.type.getUnlocalizedName()); nbt.setInteger("fluidAmount", fluid.fill); } + + nbt.setByte("app", this.dataWatcher.getWatchableObjectByte(10)); + nbt.setByte("load", this.dataWatcher.getWatchableObjectByte(11)); } @Override @@ -180,13 +140,9 @@ public class EntityDeliveryDrone extends Entity implements IInventory { if(nbt.hasKey("fluidType")) { this.fluid = new FluidStack(Fluids.fromName(nbt.getString("fluidType")), nbt.getInteger("fluidAmount")); } - } - - @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; + + this.dataWatcher.updateObject(10, nbt.getByte("app")); + this.dataWatcher.updateObject(11, nbt.getByte("load")); } @SideOnly(Side.CLIENT) @@ -258,4 +214,38 @@ public class EntityDeliveryDrone extends Entity implements IInventory { @Override public void markDirty() { } @Override public void openInventory() { } @Override public void closeInventory() { } + + public void loadNeighboringChunks(int newChunkX, int newChunkZ) { + if(!worldObj.isRemote && loaderTicket != null) { + clearChunkLoader(); + ForgeChunkManager.forceChunk(loaderTicket, new ChunkCoordIntPair(newChunkX, newChunkZ)); + ForgeChunkManager.forceChunk(loaderTicket, new ChunkCoordIntPair(newChunkX + (int) Math.ceil((this.posX + this.motionX) / 16D), newChunkZ + (int) Math.ceil((this.posZ + this.motionZ) / 16D))); + } + } + + @Override + public void setDead() { + super.setDead(); + this.clearChunkLoader(); + } + + public void clearChunkLoader() { + if(!worldObj.isRemote && loaderTicket != null) { + for(ChunkCoordIntPair chunk : loaderTicket.getChunkList()) { + ForgeChunkManager.unforceChunk(loaderTicket, chunk); + } + } + } + + @Override + public void init(Ticket ticket) { + if(!worldObj.isRemote && ticket != null) { + if(loaderTicket == null) { + loaderTicket = ticket; + loaderTicket.bindEntity(this); + loaderTicket.getModData(); + } + ForgeChunkManager.forceChunk(loaderTicket, new ChunkCoordIntPair(chunkCoordX, chunkCoordZ)); + } + } } diff --git a/src/main/java/com/hbm/entity/item/EntityDroneBase.java b/src/main/java/com/hbm/entity/item/EntityDroneBase.java new file mode 100644 index 000000000..12969f711 --- /dev/null +++ b/src/main/java/com/hbm/entity/item/EntityDroneBase.java @@ -0,0 +1,97 @@ +package com.hbm.entity.item; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.World; + +public abstract class EntityDroneBase extends Entity { + + protected int turnProgress; + protected double syncPosX; + protected double syncPosY; + protected double syncPosZ; + @SideOnly(Side.CLIENT) protected double velocityX; + @SideOnly(Side.CLIENT) protected double velocityY; + @SideOnly(Side.CLIENT) protected double velocityZ; + + public EntityDroneBase(World world) { + super(world); + } + + @Override + public boolean canBeCollidedWith() { + return true; + } + + @Override + public boolean canAttackWithItem() { + return true; + } + + @Override + public boolean hitByEntity(Entity attacker) { + + if(attacker instanceof EntityPlayer) { + this.setDead(); + } + + return false; + } + + @Override + protected boolean canTriggerWalking() { + return true; + } + + @Override + protected void entityInit() { + this.dataWatcher.addObject(10, new Byte((byte) 0)); + } + + /** + * 0: Empty
+ * 1: Crate
+ * 2: Barrel
+ */ + 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; + double interpY = this.posY + (this.syncPosY - this.posY) / (double) this.turnProgress; + double interpZ = this.posZ + (this.syncPosZ - this.posZ) / (double) this.turnProgress; + --this.turnProgress; + this.setPosition(interpX, interpY, interpZ); + } else { + this.setPosition(this.posX, this.posY, this.posZ); + } + + worldObj.spawnParticle("smoke", posX + 1.125, posY + 0.75, posZ, 0, -0.2, 0); + worldObj.spawnParticle("smoke", posX - 1.125, posY + 0.75, posZ, 0, -0.2, 0); + worldObj.spawnParticle("smoke", posX, posY + 0.75, posZ + 1.125, 0, -0.2, 0); + worldObj.spawnParticle("smoke", posX, posY + 0.75, posZ - 1.125, 0, -0.2, 0); + } + } + + 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; + } +} diff --git a/src/main/java/com/hbm/inventory/gui/GUIMachineTurbineGas.java b/src/main/java/com/hbm/inventory/gui/GUIMachineTurbineGas.java index 724797310..eefdf12c1 100644 --- a/src/main/java/com/hbm/inventory/gui/GUIMachineTurbineGas.java +++ b/src/main/java/com/hbm/inventory/gui/GUIMachineTurbineGas.java @@ -225,10 +225,6 @@ public class GUIMachineTurbineGas extends GuiInfoContainer { int firstDigitX = 66; int firstDigitY = 62; - int width = 5; - int height = 11; - int spaceBetweenBumbers = 3; - int[] digit = new int[6]; for(int i = 5; i >= 0; i--) { //creates an array of digits that represent the numbers diff --git a/src/main/java/com/hbm/items/ModItems.java b/src/main/java/com/hbm/items/ModItems.java index bd693d645..784625ea1 100644 --- a/src/main/java/com/hbm/items/ModItems.java +++ b/src/main/java/com/hbm/items/ModItems.java @@ -1038,6 +1038,7 @@ public class ModItems { public static Item cart; public static Item train; + public static Item drone; public static Item coin_creeper; public static Item coin_radiation; @@ -3456,6 +3457,7 @@ public class ModItems { cart = new ItemModMinecart().setUnlocalizedName("cart"); train = new ItemTrain().setUnlocalizedName("train"); + drone = new ItemDrone().setUnlocalizedName("drone"); coin_creeper = new ItemCustomLore().setRarity(EnumRarity.uncommon).setUnlocalizedName("coin_creeper").setCreativeTab(MainRegistry.consumableTab).setTextureName(RefStrings.MODID + ":coin_creeper"); coin_radiation = new ItemCustomLore().setRarity(EnumRarity.uncommon).setUnlocalizedName("coin_radiation").setCreativeTab(MainRegistry.consumableTab).setTextureName(RefStrings.MODID + ":coin_radiation"); @@ -7696,6 +7698,7 @@ public class ModItems { //Minecarts GameRegistry.registerItem(cart, cart.getUnlocalizedName()); GameRegistry.registerItem(train, train.getUnlocalizedName()); + GameRegistry.registerItem(drone, drone.getUnlocalizedName()); //High Explosive Lenses GameRegistry.registerItem(early_explosive_lenses, early_explosive_lenses.getUnlocalizedName()); diff --git a/src/main/java/com/hbm/items/special/ItemAntiCheat.java b/src/main/java/com/hbm/items/special/ItemAntiCheat.java deleted file mode 100644 index ddb62457f..000000000 --- a/src/main/java/com/hbm/items/special/ItemAntiCheat.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.hbm.items.special; - -import com.hbm.items.ItemCustomLore; - -import net.minecraft.entity.Entity; -import net.minecraft.item.ItemStack; -import net.minecraft.world.World; - -public class ItemAntiCheat extends ItemCustomLore { - - @Override - public void onUpdate(ItemStack stack, World world, Entity entity, int j, boolean b) { - - /*if(stack.getItemDamage() != 34) { - - if(entity instanceof EntityPlayer) { - EntityPlayer player = (EntityPlayer)entity; - for(ItemStack s : player.inventory.mainInventory) { - player.inventory.consumeInventoryItem(ModItems.ingot_euphemium); - player.inventory.consumeInventoryItem(ModItems.nugget_euphemium); - } - } - - //entity.attackEntityFrom(ModDamageSource.cheater, Float.POSITIVE_INFINITY); - for(int i = 0; i < 100; i++) - entity.attackEntityFrom(ModDamageSource.cheater, 10000); - - //if(!world.isRemote) - // ExplosionChaos.antiCheat(world, (int)entity.posX, (int)entity.posY, (int)entity.posZ, 20); - }*/ - } - -} diff --git a/src/main/java/com/hbm/items/tool/ItemDrone.java b/src/main/java/com/hbm/items/tool/ItemDrone.java new file mode 100644 index 000000000..5ac0d79f0 --- /dev/null +++ b/src/main/java/com/hbm/items/tool/ItemDrone.java @@ -0,0 +1,50 @@ +package com.hbm.items.tool; + +import com.hbm.entity.item.EntityDeliveryDrone; +import com.hbm.items.ItemEnumMulti; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +public class ItemDrone extends ItemEnumMulti { + + public ItemDrone() { + super(EnumDroneType.class, true, true); + } + + public static enum EnumDroneType { + PATROL, + PATROL_CHUNKLOADING, + PATROL_EXPRESS, + PATROL_EXPRESS_CHUNKLOADING, + REQUEST + } + + @Override + public boolean onItemUse(ItemStack stack, EntityPlayer entity, World world, int x, int y, int z, int side, float fx, float fy, float fz) { + + if(side != 1) return false; + if(world.isRemote) return true; + + Entity toSpawn = null; + + if(stack.getItemDamage() < 4) { + toSpawn = new EntityDeliveryDrone(world); + if(stack.getItemDamage() % 2 == 0) { + ((EntityDeliveryDrone) toSpawn).setChunkLoading(); + } + if(stack.getItemDamage() > 1) { + ((EntityDeliveryDrone) toSpawn).getDataWatcher().updateObject(11, (byte) 1); + } + } + + if(toSpawn != null) { + toSpawn.setPosition(x + 0.5, y + 1, z + 0.5); + world.spawnEntityInWorld(toSpawn); + } + + return false; + } +} diff --git a/src/main/java/com/hbm/main/ResourceManager.java b/src/main/java/com/hbm/main/ResourceManager.java index 8f229cb16..18f7b0059 100644 --- a/src/main/java/com/hbm/main/ResourceManager.java +++ b/src/main/java/com/hbm/main/ResourceManager.java @@ -1371,6 +1371,7 @@ public class ResourceManager { //Drone public static final ResourceLocation delivery_drone_tex = new ResourceLocation(RefStrings.MODID, "textures/models/machines/drone.png"); + public static final ResourceLocation delivery_drone_express_tex = new ResourceLocation(RefStrings.MODID, "textures/models/machines/drone_express.png"); //ISBRHs public static final IModelCustom scaffold = AdvancedModelLoader.loadModel(new ResourceLocation(RefStrings.MODID, "models/blocks/scaffold.obj")); 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 0c7434688..4cf9e844c 100644 --- a/src/main/java/com/hbm/render/entity/item/RenderDeliveryDrone.java +++ b/src/main/java/com/hbm/render/entity/item/RenderDeliveryDrone.java @@ -19,7 +19,11 @@ public class RenderDeliveryDrone extends Render { GL11.glDisable(GL11.GL_CULL_FACE); GL11.glShadeModel(GL11.GL_SMOOTH); - bindTexture(ResourceManager.delivery_drone_tex); + + if(entity.getDataWatcher().getWatchableObjectByte(11) == 1) + bindTexture(ResourceManager.delivery_drone_express_tex); + else + bindTexture(ResourceManager.delivery_drone_tex); ResourceManager.delivery_drone.renderPart("Drone"); EntityDeliveryDrone drone = (EntityDeliveryDrone) entity; diff --git a/src/main/java/com/hbm/render/entity/mob/RenderGlyphid.java b/src/main/java/com/hbm/render/entity/mob/RenderGlyphid.java index c64649c77..49b0ea4f8 100644 --- a/src/main/java/com/hbm/render/entity/mob/RenderGlyphid.java +++ b/src/main/java/com/hbm/render/entity/mob/RenderGlyphid.java @@ -48,12 +48,9 @@ public class RenderGlyphid extends RenderLiving { EntityLivingBase living = (EntityLivingBase) entity; byte armor = living.getDataWatcher().getWatchableObjectByte(17); - //MainRegistry.proxy.displayTooltip("" + limbSwingAmount, 999); double walkCycle = limbSwing; - double speed = 100000D; - double chewing = 200000D; double cy0 = Math.sin(walkCycle % (Math.PI * 2)); double cy1 = Math.sin(walkCycle % (Math.PI * 2) - Math.PI * 0.5); double cy2 = Math.sin(walkCycle % (Math.PI * 2) - Math.PI); diff --git a/src/main/java/com/hbm/render/entity/mob/RenderGlyphidNuclear.java b/src/main/java/com/hbm/render/entity/mob/RenderGlyphidNuclear.java index 5c91e44a1..88c74cc21 100644 --- a/src/main/java/com/hbm/render/entity/mob/RenderGlyphidNuclear.java +++ b/src/main/java/com/hbm/render/entity/mob/RenderGlyphidNuclear.java @@ -108,8 +108,6 @@ public class RenderGlyphidNuclear extends RenderLiving { double walkCycle = limbSwing; - double speed = 100000D; - double chewing = 200000D; double cy0 = Math.sin(walkCycle % (Math.PI * 2)); double cy1 = Math.sin(walkCycle % (Math.PI * 2) - Math.PI * 0.5); double cy2 = Math.sin(walkCycle % (Math.PI * 2) - Math.PI); diff --git a/src/main/java/com/hbm/tileentity/TileMappings.java b/src/main/java/com/hbm/tileentity/TileMappings.java index 40b91f1a4..36e0d6df7 100644 --- a/src/main/java/com/hbm/tileentity/TileMappings.java +++ b/src/main/java/com/hbm/tileentity/TileMappings.java @@ -393,6 +393,7 @@ public class TileMappings { put(TileEntityRadioTelex.class, "tileentity_rtty_telex"); put(TileEntityDroneWaypoint.class, "tileentity_drone_waypoint"); + put(TileEntityDroneWaypointRequest.class, "tileentity_drone_waypoint_request"); put(TileEntityDroneCrate.class, "tileentity_drone_crate"); } diff --git a/src/main/java/com/hbm/tileentity/network/TileEntityDroneWaypoint.java b/src/main/java/com/hbm/tileentity/network/TileEntityDroneWaypoint.java index 99cddf18f..f14fb0f99 100644 --- a/src/main/java/com/hbm/tileentity/network/TileEntityDroneWaypoint.java +++ b/src/main/java/com/hbm/tileentity/network/TileEntityDroneWaypoint.java @@ -19,7 +19,8 @@ public class TileEntityDroneWaypoint extends TileEntity implements INBTPacketRec public int nextX = -1; public int nextY = -1; public int nextZ = -1; - + + @Override public void updateEntity() { ForgeDirection dir = ForgeDirection.getOrientation(this.getBlockMetadata()); @@ -82,7 +83,8 @@ public class TileEntityDroneWaypoint extends TileEntity implements INBTPacketRec @Override public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); - + + this.height = nbt.getInteger("height"); int[] pos = nbt.getIntArray("pos"); this.nextX = pos[0]; this.nextY = pos[1]; @@ -92,7 +94,8 @@ public class TileEntityDroneWaypoint extends TileEntity implements INBTPacketRec @Override public void writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); - + + nbt.setInteger("height", height); nbt.setIntArray("pos", new int[] {nextX, nextY, nextZ}); } } diff --git a/src/main/java/com/hbm/tileentity/network/TileEntityDroneWaypointRequest.java b/src/main/java/com/hbm/tileentity/network/TileEntityDroneWaypointRequest.java new file mode 100644 index 000000000..b7bb9e52d --- /dev/null +++ b/src/main/java/com/hbm/tileentity/network/TileEntityDroneWaypointRequest.java @@ -0,0 +1,189 @@ +package com.hbm.tileentity.network; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import com.hbm.util.ParticleUtil; +import com.hbm.util.fauxpointtwelve.BlockPos; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.MathHelper; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.Vec3; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +public class TileEntityDroneWaypointRequest extends TileEntity { + + public static HashMap>> activeWaypoints = new HashMap(); + public static HashMap lastActive = new HashMap(); + public static long lastWipe = 0; + + public Set reachableNodes = new HashSet(); + public Set knownNodes = new HashSet(); + public static final int maxRange = 24; + public static final int maxAge = 1_000; + + public int height = 5; + + @Override + public void updateEntity() { + + if(!worldObj.isRemote) { + + if(worldObj.getTotalWorldTime() % 20 == 0) { + BlockPos pos = getCoord(); + push(worldObj, pos); + + for(BlockPos known : knownNodes) { + ParticleUtil.spawnDebugLine(worldObj, + pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, + (known.getX() - pos.getX()) / 2D, (known.getY() - pos.getY()) / 2D, (known.getZ() - pos.getZ()) / 2D, + reachableNodes.contains(known) ? 0x00ff00 : 0xff0000); + } + + //rescan known nodes + if(worldObj.getTotalWorldTime() % 40 == 0 && knownNodes.size() > 0) { + + BlockPos node = (BlockPos) new ArrayList(knownNodes).get(knownNodes.size() > 1 ? worldObj.rand.nextInt(knownNodes.size() - 1) : 0); + + if(node != null) { + + Long timestamp = lastActive.get(node); + + if(timestamp == null || timestamp < System.currentTimeMillis() - maxAge) { + knownNodes.remove(node); + reachableNodes.remove(node); + lastActive.remove(node); + } else if(!hasPath(worldObj, pos, node)) { + reachableNodes.remove(node); + } else { + reachableNodes.add(node); + } + } + + //discover new nodes + } else { + + Set nodes = getAllLocalNodes(worldObj, pos.getX(), pos.getZ()); + + for(BlockPos node : nodes) { + + if(!knownNodes.contains(node) && !node.equals(pos)) { + knownNodes.add(node); + if(hasPath(worldObj, pos, node)) reachableNodes.add(node); + break; + } + } + } + } + } + } + + public BlockPos getCoord() { + ForgeDirection dir = ForgeDirection.getOrientation(this.getBlockMetadata()); + return new BlockPos(xCoord + dir.offsetX * height, yCoord + dir.offsetY * height, zCoord + dir.offsetZ * height); + } + + public static boolean hasPath(World world, BlockPos pos1, BlockPos pos2) { + Vec3 vec1 = Vec3.createVectorHelper(pos1.getX() + 0.5, pos1.getY() + 0.5, pos1.getZ() + 0.5); + Vec3 vec2 = Vec3.createVectorHelper(pos2.getX() + 0.5, pos2.getY() + 0.5, pos2.getZ() + 0.5); + Vec3 vec3 = vec1.subtract(vec2); + if(vec3.lengthVector() > maxRange) return false; + //for some fucking reason beyond any human comprehension, this function will randomly yield incorrect results but only from one side + //therefore we just run the stupid fucking thing twice and then compare the results + //thanks for this marvelous piece of programming, mojang + MovingObjectPosition mop0 = world.func_147447_a(vec1, vec2, false, true, false); + MovingObjectPosition mop2 = world.func_147447_a(vec2, vec1, false, true, false); + return (mop0 == null || mop0.typeOfHit == mop0.typeOfHit.MISS) && (mop2 == null || mop2.typeOfHit == mop2.typeOfHit.MISS); + } + + public void addHeight(int h) { + height += h; + height = MathHelper.clamp_int(height, 1, 15); + } + + @Override + public void readFromNBT(NBTTagCompound nbt) { + super.readFromNBT(nbt); + + this.height = nbt.getInteger("height"); + } + + @Override + public void writeToNBT(NBTTagCompound nbt) { + super.writeToNBT(nbt); + + nbt.setInteger("height", height); + } + + /** + * Adds the position to that chunk's node list. + * @param world + * @param x + * @param y + * @param z + */ + public static void push(World world, BlockPos pos) { + + HashMap> coordMap = activeWaypoints.get(world); + + if(coordMap == null) { + coordMap = new HashMap(); + activeWaypoints.put(world, coordMap); + } + + ChunkCoordIntPair chunkPos = new ChunkCoordIntPair(pos.getX() >> 4, pos.getZ() >> 4); + Set posList = coordMap.get(chunkPos); + + if(posList == null) { + posList = new HashSet(); + coordMap.put(chunkPos, posList); + } + + posList.add(pos); + + lastActive.put(pos, System.currentTimeMillis()); + } + + /** + * Gets all active nodes in a 5x5 chunk area, centered around the given position. + * Used for finding neighbors to check connections to. + * @param world + * @param x + * @param z + * @return + */ + public static Set getAllLocalNodes(World world, int x, int z) { + + Set nodes = new HashSet(); + + x >>= 4; + z >>= 4; + + HashMap> coordMap = activeWaypoints.get(world); + + if(coordMap == null) return nodes; + + for(int i = -2; i <= 2; i++) { + for(int j = -2; j <= 2; j++) { + + Set posList = coordMap.get(new ChunkCoordIntPair(x + i, z + j)); + + if(posList != null) for(BlockPos node : posList) { + Long timestamp = lastActive.get(node); + + if(timestamp != null && timestamp >= System.currentTimeMillis() - maxAge) { + nodes.add(node); + } + } + } + } + + return nodes; + } +} diff --git a/src/main/java/com/hbm/util/ParticleUtil.java b/src/main/java/com/hbm/util/ParticleUtil.java index 0428ec19b..f62efba92 100644 --- a/src/main/java/com/hbm/util/ParticleUtil.java +++ b/src/main/java/com/hbm/util/ParticleUtil.java @@ -27,4 +27,22 @@ public class ParticleUtil { PacketDispatcher.wrapper.sendToAllAround(new AuxParticlePacketNT(data, x, y, z), new TargetPoint(world.provider.dimensionId, x, y, z, 150)); } } + + public static void spawnDebugLine(World world, double x, double y, double z, double x0, double y0, double z0, int color) { + + NBTTagCompound data = new NBTTagCompound(); + data.setString("type", "debugline"); + data.setDouble("mX", x0); + data.setDouble("mY", y0); + data.setDouble("mZ", z0); + data.setInteger("color", color); + if(world.isRemote) { + data.setDouble("posX", x); + data.setDouble("posY", y); + data.setDouble("posZ", z); + MainRegistry.proxy.effectNT(data); + } else { + PacketDispatcher.wrapper.sendToAllAround(new AuxParticlePacketNT(data, x, y, z), new TargetPoint(world.provider.dimensionId, x, y, z, 150)); + } + } } diff --git a/src/main/resources/assets/hbm/textures/blocks/diamond_block.png b/src/main/resources/assets/hbm/textures/blocks/diamond_block.png deleted file mode 100644 index f2e2e771a6498eb87678fd201c2027a4b7eb7c01..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 469 zcmV;`0V@89P)mh0kz@<(`-8wB80g(5;djiC8fmLGwWL^a|J-szEwyoD|xzj&l3+>c|;@Gq<{|n?ja&k z$E0)Dn};z@KHfScGc|dsIKcfKBYGt^a80?@s4hj-{dA^qPhY_6a4y*ChD7+fb zqwe?>=sp3KK{Zd*i~{rp?1_PQ-qH6ZXU5^1MRN~;)lTL(>x>E@FLgR3?!Z-nzIXMp z!!HXqZhI1prX`-~ucVba(;@lHSry+wX7*Rc)hNR$uQXpRD>uOR13oyM5D0-qt^fc4 M07*qoM6N<$f^{iwX8-^I diff --git a/src/main/resources/assets/hbm/textures/blocks/drone_waypoint_request.png b/src/main/resources/assets/hbm/textures/blocks/drone_waypoint_request.png new file mode 100644 index 0000000000000000000000000000000000000000..730f2a0517ec05cee0a9f9aca9ea047523f65908 GIT binary patch literal 239 zcmeAS@N?(olHy`uVBq!ia0vp^0zj<5!3HFyJAa%3QY^(zo*^7SP{WbZ0pu_9ba4#v z=zKe6BQKL7k88a~@Wo)^R;wVl1mQN1QsoQEhEAu1y=7`QF)GIhKHc0nu|_2P$@XdU z|EktAJ6BIve&|v9xmHo%U-!tw_xzrDcbJw(-sDkOdPHI|hlPi0wrU?f?J) literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/hbm/textures/blocks/drone_waypoint_request.png.mcmeta b/src/main/resources/assets/hbm/textures/blocks/drone_waypoint_request.png.mcmeta new file mode 100755 index 000000000..92dd223c8 --- /dev/null +++ b/src/main/resources/assets/hbm/textures/blocks/drone_waypoint_request.png.mcmeta @@ -0,0 +1,5 @@ +{ + "animation": { + "frametime": 10 + } +} diff --git a/src/main/resources/assets/hbm/textures/blocks/emerald_ore.png b/src/main/resources/assets/hbm/textures/blocks/emerald_ore.png deleted file mode 100644 index a26c35f6a08d6c6c8d61c42a5157eac0d182bbdb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 364 zcmV-y0h9iTP)*~`q zU7{!oZ<@yEdG@aB{5TH3!y#w*K>#$4qnBmrd7k@^|M|yn?NwF99Rq}X1Ck&>lC1cT zM|f;spP_=)5PjcAj%QE0t5+&RoR6A@eDvv8SdeWDuY^6Lr|3f5+Mg*+qQur zF}*NW$6*+Tc%UBO%r;al4K=;ow#}DiIjd;3yAi&403iAVfGuQM7X2d6-B1GaK>%+XHl*^ z0CTnpi^gi>lcs6SO=~U7c}{)4yux-j!5Bl9WvUqVov%NOa%Ex07@&h+a7t_alE8J= iNrJb4s^dHN|IiaZhf+mj%47Nf0000G zO*{K?Ra+cufngNGw%4i*+keT*l;7~rU8>Y@{B-oJV}iX~w@pv$ndlsQ@%#30i}fbw zEWM&v9b419e*P`5${EFcKMw1&r1t!rrBL#1I;R`s-6I>nRK8#~Q+3VVCHS%(=oJP} LS3j3^P66}DNSL9Fs>U6vaU&*jP3$c zn(ohe`@8CYjy6M?lEvDoi?+{dm?yPWL0_S9{y_$pz%POZzfyj1O-P-&B=eS+_av8? z((L8S>K`qR3tM<#?Y*m|lBa6wt9~o87F=m$&`C>XIQR6h^}B3)v({M*G4Ia>nQmi| zNRG;k%Dy>;HMhRD^{~l-DDS+Y(3#BdUmsryUv++kTJbXO!k0T&bR6-8FlH^B1PLC2@;4TVyS0j#E)M$GH4?fYLTMt1Zs| zRr{yU|NnpT_k?Q#69SnsXYq0AxLL9^u3EK3=X76mpoq}90QQ>ClV`jV6V%)A?#l#Y zudh3~6fTD|Ua(_6kS*PNd;fO3aLxmtOW6}vMnB3bU$X9X-)uuSx#ipV{+t&!`z?LW zGN(9zflc^t?dxLEBXf!`_!zWm^!)S{czrOW+F;6~`M+&Gu${Z(a!)MlUj@)344$rj JF6*2UngC~pXuALa literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/hbm/textures/models/machines/drone.png b/src/main/resources/assets/hbm/textures/models/machines/drone.png index 56d1e7312ed1159a4d699f2efe572c103a39d04f..3e55db1657ed91302da4ddcf1b59cd44cc33f628 100644 GIT binary patch delta 2481 zcmV;i2~PIB70MHkGk*zzNkl=it1rp+wC&c~(tPn5oL=e)7szO5QB1(}8Dh9HIR@-!|s%dxQ z25;gx_Wa~wd?z!GojCE2xFTOE%FNtj-+RtI^F2R&1s(9-yMMD`r?Fw+jklM?Fz3^E z8$9`{;N{n})U(I;eV#0b9mn^=UY}2n4-<0eGma>B^@u0SAy1aQ1CQ^8UO(SY9Oyml z7k>u%6#eScpn7Sn>I(t+oY5bbQYyW7wFqTBE4w7&82@zh^0I8gXJNdAz-%dcrY zb4@j(T9=e=*b0) zN&(c0-PTvBRQfWT%`KAO_1qakaYDa5L4DtIXNY##Z+hL%h)0=a6Gw(< z;>Zw992ugCBSSQCWQZn?4AI1qA)45;A2A9zlzv3J$%j>mc2fAz`Vl)P9_)@N103eh z2|M}`t$(eu_uici2W6Ocinp78uYN>73a~x<5$zV%^Q^mke>)7aU!sio+*P0NzyE%0 zxL$h`J6d%IL9YbbuSjsvU$|Odrvv2?PnN@;6gjL@F}q>kdBhuUFNtBFkLa|%QmNGA zT4qDFhK_l}C}FSl^?H^IK=0+$$}lp%VV$ZuFn?K&k{9*kELKNrkJvd&wH7g;>*wQ~ zWwCiOrc^2o71qhiywb0oGwgo{nip^X9@sJ z7bd`mN9EO&@Z!BP^K+*Guq=y5DEY`A<`jI_|o}V>h*f8;B;XkR(!R(0T3H1Df6GQ&%Yl$!`gz+$!xz>PZ( z0OGN1)&wG>T)(x%>$9K5_dMSE&UXod0DmC_Qc8j#NKGV!KnQ{7c}OYw)z5!6cHI7J6S+L|bEolrpUurp!Z76c@#7Q< z1+v*Jg+hVx@o`R^I6*F#BcIPRIXTJH)D%)mG)-r8G7*sVdgPw9n!~l5cL6w8Jb#5{ zSuEa*ykhZQIp&KbZ&;QUaRLyAA)2NU1VQW(hG8J3MAvl;!@zZ2T-PNGLvpzsK`=U| zkPs;ZkpUL(m6^!psn_dVIzLOT=5ThV5D_SmC#cUnDzBpH29Dz*guro}Sn(hTP(}uD z90%X`@jMS9L~3jlAeBN2m(I_|ynpbhyc%;t^14=YQlHWFC<>dV85==LiEZ0)L@`Yh z-}hs0iMV1U0tNu``mH5^l)|u0lFA#@Yoea3d)W3UDJ9iv71K21`!EcVQsTNUwrykE zHb5LfMg_VeM2M7A_w#e7xpwm|=ZdG|@Tzi++ohE_toojd<1~Osal%Nl>$-Selt7tgh9C%2nd8HU4}sx@%p`PB?|qarSeC`@(h9594K80e!?l}t zxqRVF{7z37CgRXKU6^2bBjN}E&+}qZOcJD&l7HR20l=AaUjyixBb0FljX1@w)f_C# ziWeApM>M89Bk4U!S;Y|mjekZ1UDv5rs|X>;X0v>7>yP~PpC3@IR{6uV>%8^7?|01+ z!!m@NE=;7zv6UMj$}bcrB*UnZwJa+YC2ZR!o6Ta|HlF9PQK?X^Rsq=Dsw0Hh7e|!K z<$+#9Gml8_bn?1hug4@hKX*DskV@9~+*rv>CPNs8IF5r5BIbv$Tz`6l^_3OYS62AJ zPktKb9-|X8K({Q5Y0F|UTTUr@yR-sC(IlB>tLM{&2_BVKS^sYZ-}lgUowc>KICLhl zxw*;PKl~A47_zpuhOX<3jg9eaNJ@4CT@_Es%ClatbK}kfE}frE)RuEUe{nfD5 z2(X8O?vwC?kT1-CJ-%-jKAVk`!MExZDXPRu zDV~Hfh%&(ZTs}&osvFGC%*3hl`bHH^(>QfVt zy3UIyj`Q&+tK{oBeBV#W2a~7vV~2sE=YGV8A3X#?+8@x)s(>vUWJGy=6_lutU5mHKYDUnjdQ9w#bp-^CKYz)&h$>nnxh7pgo%8vqc z)sIl+b@IBkAE5|T;p|L-<@;so4F^q=arv!6rhjRgY;A2}+cuVM#pA8=?a;dOgU%;< z?neM|CbQzhekNxU?NUh1m9T)d*1Xqk{hdW-)SNKhY4700000NkvXXu0mjf#qr!q delta 2725 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 diff --git a/src/main/resources/assets/hbm/textures/models/machines/drone_express.png b/src/main/resources/assets/hbm/textures/models/machines/drone_express.png new file mode 100644 index 0000000000000000000000000000000000000000..e2150991008791ee30dd0ee295e5d543cd4bae04 GIT binary patch literal 2744 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 y7d_(VpMM4#F>z< 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 N002ovPDHLkV1o3YS|0!a literal 0 HcmV?d00001