import net.minecraft.core.BlockPosition; import net.minecraft.tags.TagsBlock; import net.minecraft.tags.TagsFluid; import net.minecraft.world.entity.EntityInsentient; import net.minecraft.world.level.IBlockAccess; import net.minecraft.world.level.block.*; import net.minecraft.world.level.block.state.IBlockData; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Material; import net.minecraft.world.level.pathfinder.PathMode; import net.minecraft.world.level.pathfinder.PathType; import net.minecraft.world.level.pathfinder.PathfinderNormal; import org.bukkit.Location; import org.bukkit.World; /** * For future maintainers: *
* This class was a pain in the ass (yay)! *
* The general idea is to override PathfinderNormal * (or PathfinderAbstract), and modify the method that * calculates the PathType (mappings commented in overriden method) * to account for GameDoors present in the zombie's game. *
* Given that we need to pass extra context to these static methods, * we must add the context as params and modify every single call * to the modified method by overriding each individual method and passing the * content defined in the constructor. * * @author Illusion * @see net.minecraft.world.level.pathfinder.PathfinderNormal */ public class CustomPathfinderNormal extends PathfinderNormal { private ZombiesPlugin main; private EntityInsentient entity; public CustomPathfinderNormal() { } protected static PathType b(IBlockAccess var0, BlockPosition var1, ZombiesPlugin main, EntityInsentient entity) { IBlockData blockData = var0.a_(var1); Block blockState = blockData.b(); Material blockType = blockData.c(); // PATHTYPE MAPPINGS (might not be exact): /* a - blocked b - open c - walkable d - walkable_door e - trapdoor f - powder_snow g - danger_powder_snow h - fence i - lava j - water k - water_border l - rail m - unpassable_rail n - danger-fire o - damage-fire p - danger-cactus q - damage-cactus r - danger-other s - damage-other t - door_open u - door_wood_closed v - door_iron_closed w - breach x - leaves y - sticky_honey z - cocoa */ if (blockData.g()) { // isAir if (main == null) return PathType.b; // Method called before main is set in the constructor Game game = main.getGameManager().getGameFromMob(entity.getBukkitEntity()); if (game == null) return PathType.b; World world = game.getGameMapData().getMapTemplate().getSpawnPoint().getWorld(); Location location = new Location(world, var1.u(), var1.v(), var1.w()); GameDoor door = game.getGameMapData().getDoor(location); if (door == null) return PathType.b; if (game.getGameMapData().getOpenDoors().contains(door)) return PathType.a; return PathType.b; } else if (!blockData.a(TagsBlock.J) && !blockData.a(Blocks.ed) && !blockData.a(Blocks.pI)) { if (blockData.a(Blocks.oO)) { // powder snow return PathType.f; } else if (blockData.a(Blocks.cN)) { // cactus return PathType.p; } else if (blockData.a(Blocks.mu)) { // sweet berry bush return PathType.r; } else if (blockData.a(Blocks.ns)) { // honey block return PathType.x; } else if (blockData.a(Blocks.et)) { // cocoa return PathType.y; } else { Fluid var5 = var0.b_(var1); if (var5.a(TagsFluid.c)) { return PathType.h; } else if (a(blockData)) { return PathType.n; } else if (BlockDoor.n(blockData) && !(Boolean) blockData.c(BlockDoor.b)) { return PathType.t; } else if (blockState instanceof BlockDoor && blockType == Material.K && !(Boolean) blockData.c(BlockDoor.b)) { return PathType.u; } else if (blockState instanceof BlockDoor && blockData.c(BlockDoor.b)) { return PathType.s; } else if (blockState instanceof BlockMinecartTrackAbstract) { return PathType.k; } else if (blockState instanceof BlockLeaves) { return PathType.w; } else if (blockData.a(TagsBlock.M) || blockData.a(TagsBlock.F) || blockState instanceof BlockFenceGate && !(Boolean) blockData.c(BlockFenceGate.a)) { return PathType.g; } else if (!blockData.a(var0, var1, PathMode.a)) { return PathType.a; } else { return var5.a(TagsFluid.b) ? PathType.i : PathType.b; } } } else { return PathType.e; } } public static PathType a(IBlockAccess var0, BlockPosition.MutableBlockPosition var1, ZombiesPlugin main, EntityInsentient insentient) { int x = var1.u(); int y = var1.v(); int z = var1.w(); PathType pathType = b(var0, var1); if (pathType == PathType.b && y >= var0.u_() + 1) { PathType detectedType = b(var0, var1.d(x, y - 1, z), main, insentient); pathType = detectedType != PathType.c && detectedType != PathType.b && detectedType != PathType.i && detectedType != PathType.h ? PathType.c : PathType.b; if (detectedType == PathType.n) { pathType = PathType.n; } if (detectedType == PathType.p) { pathType = PathType.p; } if (detectedType == PathType.r) { pathType = PathType.r; } if (detectedType == PathType.x) { pathType = PathType.x; } } if (pathType == PathType.c) { pathType = a(var0, var1.d(x, y, z), pathType); } return pathType; } public void setValues(ZombiesPlugin main, EntityInsentient entity) { this.main = main; this.entity = entity; } public PathType a(IBlockAccess var0, int var1, int var2, int var3) { return a(var0, new BlockPosition.MutableBlockPosition(var1, var2, var3), main, entity); } }