package joshie.harvest.npcs.entity.ai; import joshie.harvest.buildings.BuildingStage; import joshie.harvest.buildings.placeable.Placeable; import joshie.harvest.core.helpers.EntityHelper; import joshie.harvest.npcs.entity.EntityNPCBuilder; import joshie.harvest.town.TownHelper; import joshie.harvest.town.data.TownDataServer; import net.minecraft.block.material.Material; import net.minecraft.entity.ai.EntityAIBase; import net.minecraft.entity.ai.RandomPositionGenerator; import net.minecraft.pathfinding.Path; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; public class EntityAIBuild extends EntityAIBase { private final EntityNPCBuilder npc; private int teleportTimer; private int buildingTimer; private int stuckTimer; private BlockPos prev; public EntityAIBuild(EntityNPCBuilder npc) { this.npc = npc; this.setMutexBits(1); } @Override public boolean shouldExecute() { if (npc.getBuilding() != null) { npc.stepHeight = 1F; return true; } else return false; } @Override public boolean continueExecuting() { if (npc.getBuilding() == null) { teleportTimer = 0; return false; } else return true; } private void attemptToTeleportToSafety(BlockPos go) { Vec3d vec = RandomPositionGenerator.findRandomTargetBlockTowards(npc, 3, 32, new Vec3d((double) go.getX() + 0.5D, (double) go.getY() + 1D, (double) go.getZ() + 0.5D)); if (vec != null) { BlockPos pos = new BlockPos(vec); if (EntityHelper.isSpawnable(npc.worldObj, pos) && EntityHelper.isSpawnable(npc.worldObj, pos.up()) && npc.worldObj.getBlockState(pos.down()).isSideSolid(npc.worldObj, pos.down(), EnumFacing.UP)) { npc.setPositionAndUpdate(pos.getX() + 0.5D, pos.getY() + 1D, pos.getZ() + 0.5D); } } } @Override public void updateTask() { BuildingStage building = npc.getBuilding(); if (buildingTimer % building.getTickTime() == 0) { Placeable placeable = building.next(); if (placeable != null) { BlockPos go = building.getPos(building.previous()); double distance = npc.getDistanceSq(go); boolean tooFar = distance >= building.getDistance(placeable); if (tooFar) { //Teleportation if (teleportTimer >= 200 || distance >= 4096D || npc.fallDistance > 32) { npc.fallDistance = 0F; teleportTimer = 0; npc.attemptTeleport(go.getX() + 0.5D, go.getY() + 1D, go.getZ() + 0.5D); tooFar = false; //Force the placement of the block } BlockPos current = new BlockPos(npc); teleportTimer += current.equals(prev) ? 10: 1; prev = current; //Update the path Path path = npc.getNavigator().getPathToPos(go); if (path == null) { Vec3d vec = RandomPositionGenerator.findRandomTargetBlockTowards(npc, 32, 5, new Vec3d((double) go.getX() + 0.5D, (double) go.getY() + 1D, (double) go.getZ() + 0.5D)); if (vec != null) { path = npc.getNavigator().getPathToPos(new BlockPos(vec)); } } npc.getNavigator().setPath(path, 0.6F); } else teleportTimer = 0; //If the NPC is close the where they need to build if (!tooFar) { if (building.build(npc.worldObj)) { npc.getNavigator().setPath(npc.getNavigator().getPathToPos(go), 0.85D); stuckTimer = 0; } else { Vec3d vec = RandomPositionGenerator.findRandomTargetBlockTowards(npc, 1, 1, new Vec3d((double) go.getX() + 0.5D, (double) go.getY() + 1D, (double) go.getZ() + 0.5D)); if (vec != null) { npc.getNavigator().setPath(npc.getNavigator().getPathToPos(new BlockPos(vec)), 0.85F); } stuckTimer++; if (stuckTimer >= 100) { stuckTimer = 0; building.build(npc.worldObj); attemptToTeleportToSafety(go); } } //Finish the building if (building.isFinished()) { TownDataServer data = TownHelper.getClosestTownToBlockPos(npc.worldObj, new BlockPos(npc), false); data.finishBuilding(); //Remove the building from the queue data.addBuilding(npc.worldObj, building.building, building.rotation, building.pos); data.syncBuildings(npc.worldObj); npc.finishBuilding(); } } //If we're suffocating BlockPos pos = new BlockPos(npc); if (!npc.isInsideOfMaterial(Material.AIR)) { attemptToTeleportToSafety(go); } else if (npc.worldObj.getBlockState(pos).getBlock().isPassable(npc.worldObj, pos)) { npc.setJumping(true); } } } buildingTimer++; } }