Skip to content

Commit

Permalink
Add metadata layer.
Browse files Browse the repository at this point in the history
  • Loading branch information
MrSmith33 committed Jan 16, 2017
1 parent e75b370 commit 203fcfa
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 58 deletions.
1 change: 1 addition & 0 deletions plugins/voxelman/core/config.d
Expand Up @@ -9,6 +9,7 @@ import voxelman.math;
public import voxelman.globalconfig;

alias BlockId = ushort;
alias BlockMetadata = ubyte;
alias TimestampType = uint;
alias DimensionId = short;

Expand Down
17 changes: 11 additions & 6 deletions plugins/voxelman/world/clientworld.d
Expand Up @@ -55,7 +55,7 @@ string fmtDur(Duration dur)
import std.string : format;
int seconds, msecs, usecs;
dur.split!("seconds", "msecs", "usecs")(seconds, msecs, usecs);
return format("%s.%03s,%1s s", seconds, msecs, usecs);
return format("%s.%03s,%1ss", seconds, msecs, usecs);
}

//version = DBG_COMPR;
Expand Down Expand Up @@ -138,8 +138,7 @@ public:
worldAccess = new WorldAccess(chunkManager);
entityAccess = new BlockEntityAccess(chunkManager);

ubyte numLayers = 2;
chunkManager.setup(numLayers);
chunkManager.setup(NUM_CHUNK_LAYERS);
chunkManager.loadChunkHandler = &handleLoadChunk;
chunkManager.cancelLoadChunkHandler = &handleLoadChunk;
chunkManager.isLoadCancelingEnabled = true;
Expand Down Expand Up @@ -231,7 +230,7 @@ public:
private void onPrintChunkMeta(string) {
import voxelman.world.block : printChunkMetadata;
auto cwp = observerPosition;
auto snap = chunkManager.getChunkSnapshot(cwp, FIRST_LAYER);
auto snap = chunkManager.getChunkSnapshot(cwp, BLOCK_LAYER);

if (snap.isNull) {
infof("No snapshot for %s", cwp);
Expand Down Expand Up @@ -278,7 +277,7 @@ public:
vec3 blockPos = pos * CHUNK_SIZE;

auto snap = chunkManager.getChunkSnapshot(
ChunkWorldPos(pos, box.dimension), FIRST_LAYER);
ChunkWorldPos(pos, box.dimension), BLOCK_LAYER);

if (snap.isNull) continue;
foreach(ubyte side; 0..6)
Expand Down Expand Up @@ -448,8 +447,14 @@ public:
foreach(pos; box.positions) {
remeshedChunks.put(ChunkWorldPos(pos, box.dimension));
}

if (printTime)
chunkMeshMan.remeshChangedChunks(remeshedChunks, &onRemeshDone);
{
size_t numMeshed = chunkMeshMan.remeshChangedChunks(remeshedChunks, &onRemeshDone);
auto submitDuration = MonoTime.currTime - startTime;
auto avg = submitDuration / numMeshed;
infof("%s tasks submitted in %s, avg per task %s", numMeshed, fmtDur(submitDuration), avg);
}
else
chunkMeshMan.remeshChangedChunks(remeshedChunks);
}
Expand Down
2 changes: 1 addition & 1 deletion plugins/voxelman/world/gen/worker.d
Expand Up @@ -77,7 +77,7 @@ void genChunk(
ChunkGeneratorResult chunk = generator.generateChunk(
cwp.xyz, blocks);

enum layerId = FIRST_LAYER;
enum layerId = BLOCK_LAYER;
enum timestamp = 0;
enum numLayers = 1;

Expand Down
35 changes: 25 additions & 10 deletions plugins/voxelman/world/mesh/chunkmeshman.d
Expand Up @@ -120,10 +120,11 @@ struct ChunkMeshMan
meshWorkers.stop();
}

void remeshChangedChunks(HashSet!ChunkWorldPos modifiedChunks,
// Returns number of chunks sent to be meshed
size_t remeshChangedChunks(HashSet!ChunkWorldPos modifiedChunks,
MeshingPassDoneHandler onDone = null)
{
if (modifiedChunks.length == 0) return;
if (modifiedChunks.length == 0) return 0;

size_t numMeshed;
foreach(cwp; modifiedChunks)
Expand All @@ -132,10 +133,12 @@ struct ChunkMeshMan
++numMeshed;
}

if (numMeshed == 0) return;
if (numMeshed == 0) return 0;

meshingPasses ~= MeshingPass(numMeshed, currentMeshGroupId, onDone);
++currentMeshGroupId;

return numMeshed;
}

void update()
Expand Down Expand Up @@ -177,14 +180,16 @@ struct ChunkMeshMan
MeshVertex[][2] meshes = w.resultQueue.popItem!(MeshVertex[][2])();
uint[27] blockTimestamps = w.resultQueue.popItem!(uint[27])();
uint[27] entityTimestamps = w.resultQueue.popItem!(uint[27])();
uint[27] metadataTimestamps = w.resultQueue.popItem!(uint[27])();
meshingPasses[0].totalDuration += w.resultQueue.popItem!Duration();

// Remove users
auto positions = AdjChunkPositions27(taskHeader.cwp);
foreach(i, pos; positions.all)
{
chunkManager.removeSnapshotUser(pos, blockTimestamps[i], FIRST_LAYER);
chunkManager.removeSnapshotUser(pos, blockTimestamps[i], BLOCK_LAYER);
chunkManager.removeSnapshotUser(pos, entityTimestamps[i], ENTITY_LAYER);
chunkManager.removeSnapshotUser(pos, metadataTimestamps[i], METADATA_LAYER);
}

// save result for later. All new meshes are loaded at once to prevent holes in geometry.
Expand Down Expand Up @@ -315,10 +320,10 @@ struct ChunkMeshMan
AdjChunkLayers27 snapsBlocks;

// get compressed layers first to look at metadata.
snapsBlocks.central = chunkManager.getChunkSnapshot(snapsPositions.central, FIRST_LAYER);
snapsBlocks.central = chunkManager.getChunkSnapshot(snapsPositions.central, BLOCK_LAYER);
if (snapsBlocks.central.isNull())
return false;
snapsBlocks.adjacent6 = chunkManager.getChunkSnapshots(snapsPositions.adjacent6, FIRST_LAYER);
snapsBlocks.adjacent6 = chunkManager.getChunkSnapshots(snapsPositions.adjacent6, BLOCK_LAYER);

++numMeshChunkTasks;

Expand All @@ -340,14 +345,19 @@ struct ChunkMeshMan

// get uncompressed blocks to use for meshing
snapsBlocks.all = chunkManager.getChunkSnapshots(
snapsPositions.all, FIRST_LAYER, Yes.Uncompress);
snapsPositions.all, BLOCK_LAYER, Yes.Uncompress);

AdjChunkLayers27 snapsEntities;
snapsEntities.all = chunkManager.getChunkSnapshots(
snapsPositions.all, ENTITY_LAYER, Yes.Uncompress);

AdjChunkLayers27 snapsMetadatas;
snapsMetadatas.all = chunkManager.getChunkSnapshots(
snapsPositions.all, METADATA_LAYER, Yes.Uncompress);

ChunkLayerItem[27] blockLayers;
ChunkLayerItem[27] entityLayers;
ChunkLayerItem[27] metadataLayers;
foreach(i; 0..27)
{
if (!dimBorders.contains(snapsPositions.all[i].ivector3)) // out-of-border chunk
Expand All @@ -356,15 +366,17 @@ struct ChunkMeshMan
}
else
{
blockLayers[i] = ChunkLayerItem(snapsBlocks.all[i].get(), FIRST_LAYER);
blockLayers[i] = ChunkLayerItem(snapsBlocks.all[i].get(), BLOCK_LAYER);
entityLayers[i] = ChunkLayerItem(snapsEntities.all[i].get(), ENTITY_LAYER);
metadataLayers[i] = ChunkLayerItem(snapsMetadatas.all[i].get(), METADATA_LAYER);
}
}

foreach(i, pos; snapsPositions.all)
{
blockLayers[i].timestamp = chunkManager.addCurrentSnapshotUser(pos, FIRST_LAYER);
blockLayers[i].timestamp = chunkManager.addCurrentSnapshotUser(pos, BLOCK_LAYER);
entityLayers[i].timestamp = chunkManager.addCurrentSnapshotUser(pos, ENTITY_LAYER);
metadataLayers[i].timestamp = chunkManager.addCurrentSnapshotUser(pos, METADATA_LAYER);
}

// debug
Expand All @@ -377,8 +389,10 @@ struct ChunkMeshMan
assert(length == BLOCKS_DATA_LENGTH, format("Wrong length of %s: %s", snapsPositions.all[i], length));
}
}
foreach (i, layer; entityLayers)
foreach (layer; entityLayers)
assert(layer.type != StorageType.compressedArray, "[MESHING] Data needs to be uncompressed 2");
foreach (layer; metadataLayers)
assert(layer.type != StorageType.compressedArray, "[MESHING] Data needs to be uncompressed 3");

// send mesh task
auto header = MeshGenTaskHeader(MeshGenTaskType.genMesh, currentMeshGroupId, cwp);
Expand All @@ -387,6 +401,7 @@ struct ChunkMeshMan
taskQueue.pushMessagePart(header);
taskQueue.pushMessagePart(blockLayers);
taskQueue.pushMessagePart(entityLayers);
taskQueue.pushMessagePart(metadataLayers);
taskQueue.endMessage();
notify();
}
Expand Down
4 changes: 4 additions & 0 deletions plugins/voxelman/world/mesh/meshgen.d
Expand Up @@ -76,6 +76,7 @@ void meshWorkerThread(shared(Worker)* workerInfo, SeparatedBlockInfoTable blockI
// get mesh task.
auto blockLayers = workerInfo.taskQueue.popItem!(ChunkLayerItem[27]);
auto entityLayers = workerInfo.taskQueue.popItem!(ChunkLayerItem[27]);
auto metadataLayers = workerInfo.taskQueue.popItem!(ChunkLayerItem[27]);

chunkMeshWorker(blockLayers, entityLayers, blockInfos, beInfos, geometry);

Expand All @@ -90,8 +91,10 @@ void meshWorkerThread(shared(Worker)* workerInfo, SeparatedBlockInfoTable blockI

uint[27] blockTimestamps;
uint[27] entityTimestamps;
uint[27] metadataTimestamps;
foreach(i; 0..27) blockTimestamps[i] = blockLayers[i].timestamp;
foreach(i; 0..27) entityTimestamps[i] = entityLayers[i].timestamp;
foreach(i; 0..27) metadataTimestamps[i] = metadataLayers[i].timestamp;

auto duration = MonoTime.currTime - taskStartTime;

Expand All @@ -100,6 +103,7 @@ void meshWorkerThread(shared(Worker)* workerInfo, SeparatedBlockInfoTable blockI
workerInfo.resultQueue.pushMessagePart(meshes);
workerInfo.resultQueue.pushMessagePart(blockTimestamps);
workerInfo.resultQueue.pushMessagePart(entityTimestamps);
workerInfo.resultQueue.pushMessagePart(metadataTimestamps);
workerInfo.resultQueue.pushMessagePart(duration);
workerInfo.resultQueue.endMessage();
}
Expand Down
3 changes: 1 addition & 2 deletions plugins/voxelman/world/serverworld.d
Expand Up @@ -132,8 +132,7 @@ public:
entityAccess = new BlockEntityAccess(chunkManager);
chunkObserverManager = new ChunkObserverManager();

ubyte numLayers = 2;
chunkManager.setup(numLayers);
chunkManager.setup(NUM_CHUNK_LAYERS);
chunkManager.isChunkSavingEnabled = true;

// Component connections
Expand Down
6 changes: 4 additions & 2 deletions plugins/voxelman/world/storage/chunk.d
Expand Up @@ -21,11 +21,13 @@ import voxelman.world.storage.coordinates;
import voxelman.world.storage.utils;
import voxelman.utils.compression;

enum FIRST_LAYER = 0;
enum BLOCK_LAYER = 0;
enum ENTITY_LAYER = 1;
enum METADATA_LAYER = 2;
enum NUM_CHUNK_LAYERS = 3;
enum BLOCKS_DATA_LENGTH = CHUNK_SIZE_CUBE * BlockId.sizeof;
enum BLOCKID_UNIFORM_FILL_BITS = bitsToUniformLength(BlockId.sizeof * 8);

enum BLOCK_METADATA_UNIFORM_FILL_BITS = bitsToUniformLength(BlockMetadata.sizeof * 8);

ubyte bitsToUniformLength(ubyte bits) {
if (bits == 1)
Expand Down
54 changes: 27 additions & 27 deletions plugins/voxelman/world/storage/chunkmanager.d
Expand Up @@ -750,9 +750,9 @@ version(unittest) {
break;
case removed_loaded_used:
gotoState(cm, ChunkState.added_loaded);
cm.getOrCreateWriteBuffer(ZERO_CWP, FIRST_LAYER, WriteBufferPolicy.copySnapshotArray);
cm.getOrCreateWriteBuffer(ZERO_CWP, BLOCK_LAYER, WriteBufferPolicy.copySnapshotArray);
cm.commitSnapshots(1);
TimestampType timestamp = cm.addCurrentSnapshotUser(ZERO_CWP, FIRST_LAYER);
TimestampType timestamp = cm.addCurrentSnapshotUser(ZERO_CWP, BLOCK_LAYER);
cm.save();
cm.setExternalChunkObservers(ZERO_CWP, 0);
cm.onSnapshotSaved(ZERO_CWP, [ChunkLayerTimestampItem(timestamp, 0)]);
Expand All @@ -768,7 +768,7 @@ version(unittest) {
if (state == ChunkState.added_loaded)
{
gotoState(cm, ChunkState.added_loaded);
cm.getOrCreateWriteBuffer(ZERO_CWP, FIRST_LAYER, WriteBufferPolicy.copySnapshotArray);
cm.getOrCreateWriteBuffer(ZERO_CWP, BLOCK_LAYER, WriteBufferPolicy.copySnapshotArray);
cm.commitSnapshots(1);
cm.save();
}
Expand Down Expand Up @@ -800,19 +800,19 @@ unittest {
}

void assertHasOldSnapshot(TimestampType timestamp) {
assert(timestamp in cm.oldSnapshots[FIRST_LAYER][ZERO_CWP]);
assert(timestamp in cm.oldSnapshots[BLOCK_LAYER][ZERO_CWP]);
}

void assertNoOldSnapshots() {
assert(ZERO_CWP !in cm.oldSnapshots[FIRST_LAYER]);
assert(ZERO_CWP !in cm.oldSnapshots[BLOCK_LAYER]);
}

void assertHasSnapshot() {
assert(!cm.getChunkSnapshot(ZERO_CWP, FIRST_LAYER).isNull);
assert(!cm.getChunkSnapshot(ZERO_CWP, BLOCK_LAYER).isNull);
}

void assertHasNoSnapshot() {
assert( cm.getChunkSnapshot(ZERO_CWP, FIRST_LAYER).isNull);
assert( cm.getChunkSnapshot(ZERO_CWP, BLOCK_LAYER).isNull);
}

void resetHandlersState() {
Expand Down Expand Up @@ -888,7 +888,7 @@ unittest {
//--------------------------------------------------------------------------
setupState(ChunkState.added_loaded);
// added_loaded -> removed_loaded_used
cm.getOrCreateWriteBuffer(ZERO_CWP, FIRST_LAYER, WriteBufferPolicy.copySnapshotArray);
cm.getOrCreateWriteBuffer(ZERO_CWP, BLOCK_LAYER, WriteBufferPolicy.copySnapshotArray);
cm.commitSnapshots(TimestampType(1));
cm.setExternalChunkObservers(ZERO_CWP, 0);
assertState(ChunkState.removed_loaded_used);
Expand All @@ -897,7 +897,7 @@ unittest {
//--------------------------------------------------------------------------
setupState(ChunkState.added_loaded);
// added_loaded -> added_loaded
cm.getOrCreateWriteBuffer(ZERO_CWP, FIRST_LAYER, WriteBufferPolicy.copySnapshotArray);
cm.getOrCreateWriteBuffer(ZERO_CWP, BLOCK_LAYER, WriteBufferPolicy.copySnapshotArray);
cm.commitSnapshots(TimestampType(1));
cm.save();
assertState(ChunkState.added_loaded);
Expand All @@ -906,8 +906,8 @@ unittest {
//--------------------------------------------------------------------------
setupState(ChunkState.added_loaded);
// added_loaded with user -> added_loaded no user after commit
cm.addCurrentSnapshotUser(ZERO_CWP, FIRST_LAYER);
cm.getOrCreateWriteBuffer(ZERO_CWP, FIRST_LAYER, WriteBufferPolicy.copySnapshotArray);
cm.addCurrentSnapshotUser(ZERO_CWP, BLOCK_LAYER);
cm.getOrCreateWriteBuffer(ZERO_CWP, BLOCK_LAYER, WriteBufferPolicy.copySnapshotArray);
cm.commitSnapshots(TimestampType(1));
assertState(ChunkState.added_loaded);
h.assertCalled(0b0000_0000);
Expand Down Expand Up @@ -938,7 +938,7 @@ unittest {
//--------------------------------------------------------------------------
setupStateSaving(ChunkState.added_loaded);
// removed_loaded_used saving -> removed_loaded_used
cm.addCurrentSnapshotUser(ZERO_CWP, FIRST_LAYER);
cm.addCurrentSnapshotUser(ZERO_CWP, BLOCK_LAYER);
cm.setExternalChunkObservers(ZERO_CWP, 0);
assertState(ChunkState.removed_loaded_used); // & saving
cm.onSnapshotSaved(ZERO_CWP, [ChunkLayerTimestampItem(1)]);
Expand All @@ -955,7 +955,7 @@ unittest {
//--------------------------------------------------------------------------
setupState(ChunkState.removed_loaded_used);
// removed_loaded_used -> non_loaded
cm.removeSnapshotUser(ZERO_CWP, TimestampType(1), FIRST_LAYER);
cm.removeSnapshotUser(ZERO_CWP, TimestampType(1), BLOCK_LAYER);
assertState(ChunkState.non_loaded);
h.assertCalled(0b0000_0000);

Expand All @@ -971,39 +971,39 @@ unittest {
//--------------------------------------------------------------------------
// test unload of old chunk when it has users. No prev snapshots for given pos.
setupState(ChunkState.added_loaded);
TimestampType timestamp = cm.addCurrentSnapshotUser(ZERO_CWP, FIRST_LAYER);
TimestampType timestamp = cm.addCurrentSnapshotUser(ZERO_CWP, BLOCK_LAYER);
assert(timestamp == TimestampType(0));
cm.getOrCreateWriteBuffer(ZERO_CWP, FIRST_LAYER, WriteBufferPolicy.copySnapshotArray);
cm.getOrCreateWriteBuffer(ZERO_CWP, BLOCK_LAYER, WriteBufferPolicy.copySnapshotArray);
cm.commitSnapshots(1);
assert(timestamp in cm.oldSnapshots[FIRST_LAYER][ZERO_CWP]);
cm.removeSnapshotUser(ZERO_CWP, timestamp, FIRST_LAYER);
assert(timestamp in cm.oldSnapshots[BLOCK_LAYER][ZERO_CWP]);
cm.removeSnapshotUser(ZERO_CWP, timestamp, BLOCK_LAYER);
assertNoOldSnapshots();

//--------------------------------------------------------------------------
// test unload of old chunk when it has users. Already has snapshot for earlier timestamp.
setupState(ChunkState.added_loaded);

TimestampType timestamp0 = cm.addCurrentSnapshotUser(ZERO_CWP, FIRST_LAYER);
cm.getOrCreateWriteBuffer(ZERO_CWP, FIRST_LAYER, WriteBufferPolicy.copySnapshotArray);
TimestampType timestamp0 = cm.addCurrentSnapshotUser(ZERO_CWP, BLOCK_LAYER);
cm.getOrCreateWriteBuffer(ZERO_CWP, BLOCK_LAYER, WriteBufferPolicy.copySnapshotArray);
cm.commitSnapshots(1); // commit adds timestamp 0 to oldSnapshots
assert(timestamp0 in cm.oldSnapshots[FIRST_LAYER][ZERO_CWP]);
assert(timestamp0 in cm.oldSnapshots[BLOCK_LAYER][ZERO_CWP]);

TimestampType timestamp1 = cm.addCurrentSnapshotUser(ZERO_CWP, FIRST_LAYER);
cm.getOrCreateWriteBuffer(ZERO_CWP, FIRST_LAYER, WriteBufferPolicy.copySnapshotArray);
TimestampType timestamp1 = cm.addCurrentSnapshotUser(ZERO_CWP, BLOCK_LAYER);
cm.getOrCreateWriteBuffer(ZERO_CWP, BLOCK_LAYER, WriteBufferPolicy.copySnapshotArray);
cm.commitSnapshots(2); // commit adds timestamp 1 to oldSnapshots
assert(timestamp1 in cm.oldSnapshots[FIRST_LAYER][ZERO_CWP]);
assert(timestamp1 in cm.oldSnapshots[BLOCK_LAYER][ZERO_CWP]);

cm.removeSnapshotUser(ZERO_CWP, timestamp0, FIRST_LAYER);
cm.removeSnapshotUser(ZERO_CWP, timestamp1, FIRST_LAYER);
cm.removeSnapshotUser(ZERO_CWP, timestamp0, BLOCK_LAYER);
cm.removeSnapshotUser(ZERO_CWP, timestamp1, BLOCK_LAYER);
assertNoOldSnapshots();

//--------------------------------------------------------------------------
// test case where old snapshot was saved and current snapshot is added_loaded
setupState(ChunkState.added_loaded);
cm.getOrCreateWriteBuffer(ZERO_CWP, FIRST_LAYER, WriteBufferPolicy.copySnapshotArray);
cm.getOrCreateWriteBuffer(ZERO_CWP, BLOCK_LAYER, WriteBufferPolicy.copySnapshotArray);
cm.commitSnapshots(1);
cm.save();
cm.getOrCreateWriteBuffer(ZERO_CWP, FIRST_LAYER, WriteBufferPolicy.copySnapshotArray);
cm.getOrCreateWriteBuffer(ZERO_CWP, BLOCK_LAYER, WriteBufferPolicy.copySnapshotArray);
cm.commitSnapshots(2); // now, snap that is saved is old.
cm.onSnapshotSaved(ZERO_CWP, [ChunkLayerTimestampItem(1)]);
assertNoOldSnapshots();
Expand Down
2 changes: 1 addition & 1 deletion plugins/voxelman/world/storage/storageworker.d
Expand Up @@ -132,7 +132,7 @@ void sendEmptyChunk(TaskId taskId, shared SharedQueue* queue, ulong cwp)
queue.startMessage();
queue.pushMessagePart(taskId);
queue.pushMessagePart(ChunkHeaderItem(ChunkWorldPos(cwp), 1/*numLayers*/, 0));
queue.pushMessagePart(ChunkLayerItem(FIRST_LAYER,
queue.pushMessagePart(ChunkLayerItem(BLOCK_LAYER,
BLOCKID_UNIFORM_FILL_BITS/*dataLength*/, 0/*timestamp*/, 0/*uniformData*/,
SOLID_CHUNK_METADATA));
queue.endMessage();
Expand Down

0 comments on commit 203fcfa

Please sign in to comment.