Accessing ExtendedBlockData async?

Hello guys :slight_smile:
I have a question, (and a half)…

I am currently working on a mapping-plugin. (Some of you might remember this ^^)
(Map example: https://bluecolored.de/bluemap … totally not showing off or anything :wink: )

So, i want to render those models on the running server (like e.g. dynmap does) to update them live and make the whole plugin pretty much “plug and play”…

Even after a lot of caching and tweaking, rendering of those map-tiles is not really fast, so i can’t render them on the server-thead without blocking it and/or slowing the render-process down to the time of a century. :sweat_smile:
So the best solution would be to do this async on multiple threads.
And you can guess the problem: Threads and Minecraft have never been friends.

The first thing i tried was copying/viewing the world-chunk i want to render to ImmutableBlockVolumes on the Server-Thread and then render the map-tile from that on an async thread. Copying took like 10ms so that was working fine. But the problem with that is, that i need the extended BlockState to have connected fences and redstone and such. I also need the SkyLuminanceProperty and GroundLuminanceProperty of those blocks to calculate shadows and to hide caves that are not exposed to the sunlight.
Both of those values are only accessible through a Location object and cannot be obtained from a BlockVolume.

The next thing i tried was beeing a really bad guy and just accessing Locations from my render thread, hoping (since i am only reading and not writing) that it would just work… And it did! Almost.
It was rendering the map (about 840 Chunks) without any errors on 7 render-threads in a bit over a minute, while I was placing and breaking blocks all over the place!
The only problems i am facing are a guilty conscience and the server thread sometimes randomly deciding to unload chunks i am currently reading ^^’
I was able to minimize that chunk-unloading to zero by just loading the chunk using World#loadChunkAsync every time before doing location.getBlock().withExtendedProperties(location) but that felt super hacky and i am not happy with that solution.

So:

  • Can someone think of any better way to get extendedBlockStates and light-info from an async thread?
  • Will chunks stay loaded if i just keep a reference to the chunk-object i am getting with loadChunkAsync?
  • Does someone know how to keep a chunk loaded asyncronously?
  • Am i even allowed to call loadChunkAsync asyncronously? (I am pretty sure i am not, since the docs say there might be implementations that do not support this and just load it syncrounously)
  • Am i allowed to read Locations asyncronously?

Thank you very much in advance, and much love for the Sponge-Team, you are doing such a great job! :slight_smile:

1 Like

Okay, I decided to stick to using Locations async until someone or i has a better idea :smiley:
And i wrote myself a method that ensures the chunk is loaded:

/**
 * Ensures that the chunk at that location is loaded and if not, tries to load it.
 * @return true if successful, false if not
 */
protected boolean ensureLoadedChunk(final Vector3i chunkPosition){
	final org.spongepowered.api.world.World world = getSpongeWorld();
		
	//most of the time it should be loaded and present
	if (world.getChunk(chunkPosition).isPresent()) return true;
		
	synchronized (this) { // "this" is in this case the same object per world
		//if not, start the chunk-loading on the server Thread, but try to do it async 
		Future<CompletableFuture<Optional<Chunk>>> futureFuture = blueMap.getSyncExecutor().submit(() -> {
			return world.loadChunkAsync(chunkPosition, false);
		});
	
		//wait for the futures to complete and return the result
		try {
			return futureFuture.get(10, TimeUnit.SECONDS).get(10, TimeUnit.SECONDS).isPresent();
		} catch (InterruptedException e) {
			return false;
		} catch (ExecutionException | TimeoutException e){
			blueMap.logError("Failed to load Chunk: " + chunkPosition, e);
			return false;
		}
	}
}

I think this wont cause any issues. Tests were good, and render performance is only going down if the chunk has to be loaded.

I know forge has forceloaded chunks which are never unloaded, and appreantly minecraft itself is getting those too in 1.13. Maybe you could use that to force the chunk to stay loaded while rendering it?

It should be possible in SpongeAPI using the ChunkTicketManager.

I don’t think that the loading tickets are implemented in SpongeVanilla.

Oh, i didn’t know about the ChunkTicketManager! Thats definitly worth testing :smiley:, thanks.
I probably should start testing with SpongeVanilla anyways ^^