Read and manipulate blocks from a background thread

Discussion in 'Plugin Development' started by FloydATC, Aug 1, 2012.

Thread Status:
Not open for further replies.
  1. Offline

    FloydATC

    First off, I fully understand why I can't call world.getBlockAt() and the block.setBlock* family of methods from a background thread as they're not thread safe. Please don't explain this to me.

    Plugins such as dynmap seem to somehow work around this, and I'm curious as to how it can be done. I've been thinking of maybe hooking some random events that occur all the time and stalling the main thread for a few ms at a time on purpose to give the background thread slices of time where it can safely access the plugin API? Perhaps the background thread can generate "work events" to be executed in the main thread? Or is there some secret API call that does exactly what I need? Does anyone know a proper way to do it?

    This is ofcourse complicated by the fact that the plugin tutorial simply gives an incomplete list of thread safe API calls and instructs plugin writer to check if other calls are safe. How does one check this if the list is incomplete? Is there another, complete list somewhere?
     
  2. Offline

    Wolvereness Bukkit Team Member

    Chunk Snapshot
     
  3. Offline

    FloydATC

    Aha, I didn't know about this.
    As far as I can tell, snapshots allow me to read blocks but not update them, correct? So that's half my problem solved, I want to update them as well.
     
  4. Offline

    Taco

    The developer of SurvivalGames helped me with this one. You can safely edit blocks by using your thread to schedule a repeating task to safely edit ~100 blocks per tick.
     
  5. world.getBlockAt() is not threadsafe because it returns an Block object which holds alot of other data... but world.getBlockTypeAt() is threadsafe because it only returns the block type, a number... so dynmap doesn't work around anything.

    As for updating, you need to do it in the main thread anyways but more slowly (queue blocks) if there are alot of blocks to update.

    EDIT:
    scheduleSync*() are ran in the main thread, they're not diferent threads.
    Only the scheduleAsync*() ones are new threads which will have problems if you've used them to set blocks.

    But yeah, setting a task to set a few blocks per tick is what WorldEdit also does (it's what I also suggested above, queue blocks), but the problem is he's reading them in a diferent thread.
     
  6. Offline

    FloydATC

    In order to render different wool colors dynmap has to access the block data somehow and not just the id, I can't see how that can be done with just world.getBlockTypeAt(). Also, if WorldEdit had actually set just a few blocks per tick then the server wouldn't drop all connections when doing huge copy/paste ops. Try copying 10 million blocks between worlds and watch the server go off the air for several minutes.

    But I see your point, scheduleSyncRepeatingTask() might be a better solution than doing things in a separate thread if it allows me to do things in the main thread for a bit, return control and then have the main thread call me up at regular intervals. Does anyone have example code showing typical/proper use?
     
  7. Well, I guess they're using ChunkSnapshot because that provides getBlockData(x,y,z), getBlockSkylight(x,y,z), getHighestBlockYAt(x,y,z) and more, which are very useful for overview maps.

    WorldEdit does that task thing, you can look how they do it :}
     
Thread Status:
Not open for further replies.

Share This Page