Getting player to teleport to each location in a list

Discussion in 'Spigot Plugin Development' started by ieatdiamond, Aug 5, 2018.

  1. I have 10 locations in my list and in my for loop I iterate through the lists and call the teleport function. But when I teleport it teleports me to the last location in the array I'm geussing it speeds through the whole array and I would need to call a delay or something but I have no idea how to implement it.
     
  2. To do a delay, there're two option.
    A) Use threads and call Thread.delay();
    B) Use Bukkit scheduler and run a repeating task, and in every task get a new location & teleport, then on the last location cancel the task.

    B is better as it doesn't involve threads although A is easier.
     
  3. this is what i have it densest work still teleports to the last quickly,
    Code (Text):
    for (int i = plugin.playerManager.getPlayerBlockMap().get(e.getPlayer()).size() - 1; i >= 0; i--) {
                    Block b = plugin.playerManager.getPlayerBlockMap().get(e.getPlayer()).get(i);
                    task = Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, new Runnable() {

                        @Override
                        public void run() {
                            if (isOnSameBlock(e.getPlayer().getLocation().getBlock(),
                                    plugin.playerManager.getPlayerBlockMap().get(e.getPlayer()).get(0))) {
                                Bukkit.getScheduler().cancelTask(task);
                            }

                            e.getPlayer().teleport(b.getLocation());
                        }

                    }, 0, 20L);
                }
     
  4. Save yourself the pain and use this
    Code (Java):
    for (Block b : plugin.playerManager.getPlayerBlockMap().get(e.getPlayer())) {
        // ...
    }
    Setting up a BukkitRunnable in a for loop isn't a good idea, because all runnables will start at the same time anyways unless you math your way out of that (not hard, but not needed here, and you haven't done that anyways).
     
    • Agree Agree x 1
  5. How would I math it lol I just wanna tell to each location for a quarter of a second
     
  6. It looks like they're reversing the order of the list of Blocks they're iterating over by counting down in their loop.
    So if the order is necessary, you'd either need to add them to the list the other way around, find a nifty method to reverse it (which seems like it should exist), or just stick with the current loop.

    You'd 'math' it by taking which position in the loop you're in, and calculating how much delay would be needed in order to not trigger it until the previous delay has finished. So the first one you may want to trigger immediately, then you'd want to have the next one wait for 5 ticks (quarter of a second), then the third would wait 5*2 ticks, etc. But there's very likely a better way to do it.
     
    • Agree Agree x 1
  7. FrostedSnowman

    Resource Staff

    threads are not cheap and shouldn't be used for this scenario.
    what you could do is put all the locations in a queue and poll each location every X ticks, teleport to that location, repeating until the queue is empty to cancel the task. or if you dont want a queue, keep track of the current index of the list and increase it until you hit the last element
     
  8. A is terrible advice and terrible practice. Never, ever, ever, ever, EVER, use Thread#sleep() or Thread#delay() on the main thread or you'll hold up the entire server. There are runnables for a reason, use them.
     
    • Agree Agree x 3
  9. Code (Text):

            Player player = e.getPlayer();
            BukkitTask teleportask =
            new BukkitRunnable() {
                HashMap<Player,List<Block>> map = plugin.playerManager.getPlayerBlockMap();
                int current = map.get(player).size() - 1;
                @Override
                public void run() {
                    if(current < 0) {
                        this.cancel();
                        return;
                    }
                    Block b = map.get(player).get(current);
                    player.teleport(b.getLocation());
                    current--;
                }
           
            }.runTaskTimer(this, 0, 20);
    Spoon feeding come
     
    • Optimistic Optimistic x 1
  10. FrostedSnowman

    Resource Staff

    use Map over HashMap.
    check to see if current < 0 before starting the task too, just to avoid starting it in the first place
     
  11. optimization come from the user itself, i'm just doing spoon feeding here;)
     
    • Optimistic Optimistic x 1
    • Like Like x 1
  12. You're welcome!
     
  13. Responding to @FrostedSnowman and @xMakerx

    No, thread.sleep() would not hold up the main theead, because it’s being ran in another thread itself. I know it’s bad, that’s why I said not to use it...
     
  14. Most bukkit API calls are not safe to be used outside of the server thread so delaying a different thread doesn't help much.
     
  15. FrostedSnowman

    Resource Staff

    i didnt at all say anything about that. i said creating threads isnt cheap and is overkill for this problem
     
    • Agree Agree x 1
  16. That wasn’t to you, the second sentence was smh.
     
  17. FrostedSnowman

    Resource Staff

    then dont recommend it in the first place?
     
  18. Just listing options. I don’t spoon feed, not that anybody here has before my words get spun. He asked for options, i listed them with a precautionary warning.
     
    • Funny Funny x 1