public void play(Player player, Runnable startCallback, Runnable endCallback, Consumer markerCallback) { if(player.getGameMode() != GameMode.SPECTATOR) { player.setGameMode(GameMode.SPECTATOR); } new BukkitRunnable() { int frameIndex = 0; @Override public void run() { Frame frame = animation.getFrames().get(this.frameIndex++); //Rework for all the versions (removed the player.teleport does the same thing as this but smoothly) /*TeleportUtils.teleport(player, new Location(startLocation.getWorld(), frame.getLocation().getX(), frame.getLocation().getY(), frame.getLocation().getZ(), frame.getRot().getX(), frame.getRot().getZ()));*/ MathUtils.corDir(player, new Location(startLocation.getWorld(), frame.getLocation().getX(), frame.getLocation().getY(), frame.getLocation().getZ(), frame.getRot().getX(), frame.getRot().getZ()), 1, 2); if (frameIndex <= 1) startCallback.run(); frame.getMarkers().forEach(markerCallback::accept); if (this.frameIndex >= animation.getFrames().size()) cancel(); //TODO: Fix out of bound error! } @Override public synchronized void cancel() throws IllegalStateException { if (endCallback != null) endCallback.run(); player.teleport(startLocation); player.setGameMode(GameMode.SURVIVAL); super.cancel(); } }.runTaskTimer(AlixAPI.getInstance(), 0, 1); }