[SOLVED] Schedule task to run every 20 milliseconds

Discussion in 'Plugin Development' started by iKeirNez, Aug 14, 2012.

Thread Status:
Not open for further replies.
  1. As part of my plugin, I need to be able to run a task every 20 milliseconds but I have no idea how I would do that. I know that

    20 ticks = 1 second
    1 tick = 50 milliseconds
    1 second = 1000 milliseconds

    but I don't know if it would be possible to get any lower than 50. Please help as this is CRITICAL to my plugin.
     
  2. Offline

    Courier

    Well yeah, it would have to by async.
    Code:java
    1. boolean running = false;
    2. ...
    3. running = true;
    4. (new Thread()
    5. {
    6. @Override
    7. public void run()
    8. {
    9. while(true)
    10. {
    11. long startTime = System.currentTimeMillis();
    12. synchronized(this)
    13. {
    14. if(!running)
    15. return;
    16. }
    17. //do stuff
    18. //pause for 20 milliseconds minus time already taken
    19. long pauseTime = 20 + startTime - System.currentTimeMillis();
    20. if(pauseTime <= 0)
    21. continue;
    22. try
    23. {
    24. Thread.sleep(pauseTime);
    25. }
    26. {
    27. //this shouldn't happen
    28. //unless something is wrong
    29. //or you purposely call "interrupt();"
    30. return;
    31. }
    32. }
    33. }
    34. }).start();
    35. ...
    36. //when you want to stop it
    37. synchronized(this)
    38. {
    39. running = false;
    40. }
     
  3. Will that work with Bukkit methods though?
     
  4. Offline

    Courier

    What do you mean by bukkit methods? I'm pretty sure you can use the bukkit scheduler from any thread, but anything that does anything with the server is not thread-safe, so no.

    If you want to change anything on the server, it can only happen during a tick anyway, so you can schedule something to run on the next tick.

    Can I ask what you're trying to do?
     
  5. Offline

    theguynextdoor

    I'm not so sure about this. I'm no expert on threads, but in my experience, Thread.sleep puts the main thread to sleep. Which is not what you want.
     
  6. I am playing MIDI files through Noteblocks. I can get it to work perfectly with a TimerTask but after a certain amount of time I get a concurrent modification exception which crashes the server.

    Thats why I need to use the Bukkit scheduler.
     
  7. Offline

    Courier

    Thread.sleep() puts the thread which called Thread.sleep() to sleep.
    Yup. You could still use the async thread in my example, and in your "//do stuff", schedule a sync event. Notes may play at the same time though, since they can only play on a tick. It would probably be better to not use a separate thread though, since you can't gain any time-resolution.
     
  8. So replace //do stuff with:

    getServer().getScheduler().scheduleAsync...

    I'm just checking because I don't have access to an IDE ATM.
     
  9. Offline

    Courier

    Yes, except scheduleSync... not scheduleAsync.

    Sync means it will run on the same thread as the server, during a tick. Async means it will run on its own thread, so it could be trying to access a resource at the same time as the server (which can crash).
     
  10. Ah ok thanks for telling me, never knew that. Will try this later and get back to you. You may have saved my plugin :D
     
  11. Offline

    Major

    I'm sorry if this comes off as rude, but do you appreciate just how frequent 20ms is? Even something as simple as adding a block can become an expensive operation when it's done 50 times a second.
     
  12. I know but there is no other way to do it and it won't be running all the time, only when a song is playing.

    Unless you can think of a better way to update and play a noteblock every 20 milliseconds.
     
  13. Offline

    Major

    Why do you need it to play so frequently?
     
  14. I'm playing a MIDI file via noteblocks.
     
  15. Offline

    Major

    Actually a cool idea. What's written above is probably your best bet - try it and see what happens.

    Edit: just noticed you actually said what this was for above. Sorry.
     
  16. Offline

    Courier

    Well, like I said earlier, this won't actually play a note every 20ms... that is not possible. Minecraft ticks 20 times a second, note blocks can only play on a tick. If you have three notes, each 20ms apart, and you try to play them, two will end up on the same tick, playing at the exact same time.
    EDIT: If you are trying to play both of them from the same exact block, I'm not sure if they'd both play, or just one. My guess is just one.

    Talking between threads every 20ms is not efficient, monitor locking comes with a substantial overhead. All this method would do is play all queued notes every tick.

    You could achieve the same result by looking every tick for all midi note-ons within a 20ms section, play them all, and move the pointer 20ms ahead for the next tick. This could all by on the main thread, with a repeating sync task.

    Music will play best if its tempo is a factor of 1200 bpm, since that's the tickrate of Minecraft.
     
  17. Haha its fine!

    Thanks it works! A few tweaks and it will be perfect!

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 27, 2016
  18. Offline

    Sagacious_Zed Bukkit Docs

    It is not possible to play a note block every 20ms since each tick is 50ms. If you schedule in between ticks you will play the next tick.
     
  19. Offline

    Major

    Refer to above posts.
     
Thread Status:
Not open for further replies.

Share This Page