Solved Change sign's contents every x seconds?

Discussion in 'Spigot Plugin Development' started by konfiger, Aug 2, 2020 at 6:44 PM.

  1. Screenshot of code attached for context

    Whenever I place the Oak Log, the chat message works perfectly, It counts from 1 to 6 every second, but the sign only updates when it reaches 6/6 after the for loop finishes.
    Instead of the sign showing "1/6 gems" ... "2/6 gems" ... > "6/6 gems" every second, the sigh is empty and only updates with 6/6 gems after the 6 seconds pass.

    Is there a way to make it so I can physically see the sign changing every 1 second?
    Thanks. help.JPG
     
  2. Use the BukkitScheduler, not Thread#sleep(long)
     
  3. Thread#sleep freezes the main thread for a second, that means the server will not do ANYTHING for the second. No code executes.

    The (correct) alternative is BukkitScheduler#runTaskDelayed or BukkitScheduler#runTaskTimer.
     
  4. Been trying for 30 minutes now, I don't really know how BukkitScheduler works, this is as far as i've gotten but it still doesn't work.
    Can any of you type what the bukkitscheduler should look like and what do I need to type inside it please? newhelp.JPG
     
  5. You have to move your code inside the run method.
    Here’s some pseudocode for what I’d do:
    Code (Java):
    for (int i = 0; i < 7; i++) {
        Bukkit.getScheduler().runTaskDelayed(() -> {
          //Sign code here
        }, 20*i);
    }
     
  6. Code (Java):
    final AtomicInteger i = new AtomicInteger();
    Bukkit.getScheduler().runTaskTimer(plugin, () -> {
        mySign.setLine(2, ChatColor.GREEN + i.getAndIncrement() + "/6 Gems");
        mySign.update(true);
    }, 0, 20);
     
  7. You have to cancel it, so you have to make either a wrapper class for a self cancelable task or make an atomic long for the task id and if i < 7 call BukkitScheduler#cancelTask
     
  8. I tried with schedulesyncDelayedTask, runtasktimer and others, nothing inside the bukkit scheduler is ever being executed.
     
  9. latest one that doesn't work, nothing inside the scheduler is executed, not even the e.sendmessage. The sign just apears with 0/6.
    latest.JPG
     
  10. The only thing that smells a little is the cast to plugin. Is that event in the main class (the one that extends JavaPlugin)?
     
  11. Well yes, you need to do one of two things:
    Use a for loop and delayed tasks
    Use an atomic integer and a repeatable tasks
    Currently your making 6 different tasks that all try to set the sign every second (causing it to stay at 0).
     
  12. Strahan

    Benefactor

    There is no sense in doing the task within a for loop. The scheduler can repeat on its own, so just make a repeating task that will cancel itself out.

    So like if I wanted to do something six times, I could do:
    Code (Text):
    new BukkitRunnable() {
      int total = 1;
      @Override
      public void run() {
        Bukkit.broadcastMessage(total + " of 6 completed");
        if (total == 6) this.cancel();
        total++;
      }
    }.runTaskTimer(this, 0L, 20L);
     
    • Informative Informative x 1
  13. I pasted the code in and it asked me to cast (Plugin) to this. After running it, the sign appears with 0/6 but no broadcast messages are appearing, like the runnable doesn't exist.

    newhelppls.JPG
     
  14. Hi,

    "(Plugin) this" needs to be from you main class as @Schottky already said.

    You get either get it by dependency injection or static.
     
  15. Finally fixed the runnable, it works now. I just typed it in the main class where it extends JavaPlugin. Now I'm back to my original problem, it sends me messages perfectly every 1 second to counts from 1 to 6 but the sign stays blank. How do I make it so I visible see the sign changing?

    newnewhelp.JPG
     
  16. Strahan

    Benefactor

    You sure the sign is being gotten properly? I tried what you are doing, it and worked fine for me. Only diff is I didn't feel like placing a sign and static fixing coords to it so I am just getting the sign that was just placed.

    Code (Text):
    @EventHandler
    public void blah(BlockPlaceEvent e) {
      if (!(e.getBlockPlaced().getState() instanceof Sign)) return;

      new BukkitRunnable() {
        int total = 1;
        @Override
        public void run() {
          Sign s = (Sign)e.getBlockPlaced().getState();
          s.setLine(1, ChatColor.GREEN + "Level 1");
          s.setLine(2, ChatColor.GREEN + (total + "/6 Gems"));
          s.update();
       
          if (total == 6) this.cancel();
          total++;
        }
      }.runTaskTimer(this, 40L, 20L);
    }
     
  17. I copy pasted your code and the sign still stays blank. I added a message that counts and that works so the runnable is fine but the sign never changes, it's just blank. No idea why it isn't working for me.
     
  18. I was using .runTaskTimerAsynchronously thinking it would work with more signs at once but that was actually the problem that the signs kept staying blank. I Switched to .runTaskTimer and now it works fine. Thank you all for your help!
    Marking it as solved.
     
  19. Strahan

    Benefactor

    ;)

    Glad to hear it's working!