diff --git a/src/chunk.zig b/src/chunk.zig index 2890af01..17e6ced0 100644 --- a/src/chunk.zig +++ b/src/chunk.zig @@ -794,7 +794,7 @@ pub const meshing = struct { var ny = y + Neighbors.relY[neighbor]; var nz = z + Neighbors.relZ[neighbor]; if(nx & chunkMask != nx or ny & chunkMask != ny or nz & chunkMask != nz) { // Outside this chunk. - neighborMesh = renderer.RenderStructure.getNeighbor(self.pos, self.pos.voxelSize, neighbor) orelse continue; + neighborMesh = renderer.RenderStructure.getNeighborFromRenderThread(self.pos, self.pos.voxelSize, neighbor) orelse continue; } nx &= chunkMask; ny &= chunkMask; @@ -902,7 +902,7 @@ pub const meshing = struct { self.opaqueMesh.startNeighbor(neighbor); self.voxelMesh.startNeighbor(neighbor); self.transparentMesh.startNeighbor(neighbor); - const nullNeighborMesh = renderer.RenderStructure.getNeighbor(self.pos, self.pos.voxelSize, neighbor); + const nullNeighborMesh = renderer.RenderStructure.getNeighborFromRenderThread(self.pos, self.pos.voxelSize, neighbor); if(nullNeighborMesh) |neighborMesh| { std.debug.assert(neighborMesh != self); var additionalNeighborFacesOpaque = std.ArrayList(FaceData).init(main.threadAllocator); @@ -974,7 +974,7 @@ pub const meshing = struct { } // lod border: if(self.pos.voxelSize == 1 << settings.highestLOD) continue; - const neighborMesh = renderer.RenderStructure.getNeighbor(self.pos, 2*self.pos.voxelSize, neighbor) orelse continue; + const neighborMesh = renderer.RenderStructure.getNeighborFromRenderThread(self.pos, 2*self.pos.voxelSize, neighbor) orelse continue; const x3: u8 = if(neighbor & 1 == 0) @intCast(chunkMask) else 0; const offsetX = @divExact(self.pos.wx, self.pos.voxelSize) & chunkSize; const offsetY = @divExact(self.pos.wy, self.pos.voxelSize) & chunkSize; diff --git a/src/game.zig b/src/game.zig index 82ea5f4c..fd5427d3 100644 --- a/src/game.zig +++ b/src/game.zig @@ -212,88 +212,6 @@ pub const World = struct { } try network.Protocols.playerPosition.send(self.conn, Player.getPosBlocking(), Player.getVelBlocking(), @intCast(newTime & 65535)); } - // TODO: -// public void drop(ItemStack stack, Vector3d pos, Vector3f dir, float velocity) { -// Protocols.GENERIC_UPDATE.itemStackDrop(serverConnection, stack, pos, dir, velocity); -// } -// public void updateBlock(int x, int y, int z, int newBlock) { -// NormalChunk ch = getChunk(x, y, z); -// if (ch != null) { -// int old = ch.getBlock(x & Chunk.chunkMask, y & Chunk.chunkMask, z & Chunk.chunkMask); -// if(old != newBlock) { -// ch.updateBlock(x & Chunk.chunkMask, y & Chunk.chunkMask, z & Chunk.chunkMask, newBlock); -// Protocols.BLOCK_UPDATE.send(serverConnection, x, y, z, newBlock); -// } -// } -// } -// /** -// * Block update that came from the server. In this case there needs to be no update sent to the server. -// */ -// public void remoteUpdateBlock(int x, int y, int z, int newBlock) { -// NormalChunk ch = getChunk(x, y, z); -// if (ch != null) { -// int old = ch.getBlock(x & Chunk.chunkMask, y & Chunk.chunkMask, z & Chunk.chunkMask); -// if(old != newBlock) { -// ch.updateBlock(x & Chunk.chunkMask, y & Chunk.chunkMask, z & Chunk.chunkMask, newBlock); -// } -// } -// } -// public void queueChunks(ChunkData[] chunks) { -// Protocols.CHUNK_REQUEST.sendRequest(serverConnection, chunks); -// } - pub fn getChunk(_: *World, x: i32, y: i32, z: i32) ?*chunk.Chunk { - return renderer.RenderStructure.getChunk(x, y, z); - } -// public void cleanup() { -// connectionManager.cleanup(); -// ThreadPool.clear(); -// } -// -// public final BlockInstance getBlockInstance(int x, int y, int z) { -// VisibleChunk ch = (VisibleChunk)getChunk(x, y, z); -// if (ch != null && ch.isLoaded()) { -// return ch.getBlockInstanceAt(Chunk.getIndex(x & Chunk.chunkMask, y & Chunk.chunkMask, z & Chunk.chunkMask)); -// } else { -// return null; -// } -// } -// -// public int getLight(int x, int y, int z, Vector3f sunLight, boolean easyLighting) { -// VisibleChunk ch = (VisibleChunk)getChunk(x, y, z); -// if (ch == null || !ch.isLoaded() || !easyLighting) -// return 0xffffffff; -// return ch.getLight(x & Chunk.chunkMask, y & Chunk.chunkMask, z & Chunk.chunkMask); -// } -// -// public void getLight(VisibleChunk ch, int x, int y, int z, int[] array) { -// int block = getBlock(x, y, z); -// if (block == 0) return; -// int selfLight = Blocks.light(block); -// x--; -// y--; -// z--; -// for(int ix = 0; ix < 3; ix++) { -// for(int iy = 0; iy < 3; iy++) { -// for(int iz = 0; iz < 3; iz++) { -// array[ix + iy*3 + iz*9] = getLight(ch, x+ix, y+iy, z+iz, selfLight); -// } -// } -// } -// } -// -// protected int getLight(VisibleChunk ch, int x, int y, int z, int minLight) { -// if (x - ch.wx != (x & Chunk.chunkMask) || y - ch.wy != (y & Chunk.chunkMask) || z - ch.wz != (z & Chunk.chunkMask)) -// ch = (VisibleChunk)getChunk(x, y, z); -// if (ch == null || !ch.isLoaded()) -// return 0xff000000; -// int light = ch.getLight(x & Chunk.chunkMask, y & Chunk.chunkMask, z & Chunk.chunkMask); -// // Make sure all light channels are at least as big as the minimum: -// if ((light & 0xff000000) >>> 24 < (minLight & 0xff000000) >>> 24) light = (light & 0x00ffffff) | (minLight & 0xff000000); -// if ((light & 0x00ff0000) < (minLight & 0x00ff0000)) light = (light & 0xff00ffff) | (minLight & 0x00ff0000); -// if ((light & 0x0000ff00) < (minLight & 0x0000ff00)) light = (light & 0xffff00ff) | (minLight & 0x0000ff00); -// if ((light & 0x000000ff) < (minLight & 0x000000ff)) light = (light & 0xffffff00) | (minLight & 0x000000ff); -// return light; -// } }; pub var testWorld: World = undefined; // TODO: pub var world: ?*World = null; diff --git a/src/network.zig b/src/network.zig index 0f4ce468..e829bdb7 100644 --- a/src/network.zig +++ b/src/network.zig @@ -834,18 +834,16 @@ pub const Protocols = struct { }; pub const blockUpdate = struct { const id: u8 = 7; - fn receive(_: *Connection, data: []const u8) !void { + fn receive(conn: *Connection, data: []const u8) !void { const x = std.mem.readIntBig(i32, data[0..4]); const y = std.mem.readIntBig(i32, data[4..8]); const z = std.mem.readIntBig(i32, data[8..12]); const newBlock = Block.fromInt(std.mem.readIntBig(u32, data[12..16])); - try renderer.RenderStructure.updateBlock(x, y, z, newBlock); - // TODO: -// if(conn instanceof User) { -// Server.world.updateBlock(x, y, z, newBlock); -// } else { -// Cubyz.world.remoteUpdateBlock(x, y, z, newBlock); -// } + if(conn.user != null) { + // TODO: Handle block update from the client. + } else { + try renderer.RenderStructure.updateBlock(x, y, z, newBlock); + } } pub fn send(conn: *Connection, x: i32, y: i32, z: i32, newBlock: Block) !void { var data: [16]u8 = undefined; diff --git a/src/renderer.zig b/src/renderer.zig index e0b63bdf..92ab50e0 100644 --- a/src/renderer.zig +++ b/src/renderer.zig @@ -267,7 +267,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo // Meshes.emissionTextureArray.bind(); // } - const playerBlock = RenderStructure.getBlockFromAnyLod(@intFromFloat(@floor(playerPos[0])), @intFromFloat(@floor(playerPos[1])), @intFromFloat(@floor(playerPos[2]))); + const playerBlock = RenderStructure.getBlockFromAnyLodFromRenderThread(@intFromFloat(@floor(playerPos[0])), @intFromFloat(@floor(playerPos[1])), @intFromFloat(@floor(playerPos[2]))); if(settings.bloom) { Bloom.render(lastWidth, lastHeight, playerBlock); @@ -728,7 +728,7 @@ pub const MeshSelection = struct { selectedBlockPos = null; while(total_tMax < closestDistance) { - const block = RenderStructure.getBlock(voxelPos[0], voxelPos[1], voxelPos[2]) orelse break; + const block = RenderStructure.getBlockFromRenderThread(voxelPos[0], voxelPos[1], voxelPos[2]) orelse break; if(block.typ != 0) { // Check the true bounding box (using this algorithm here: https://tavianator.com/2011/ray_box.html): const model = blocks.meshes.model(block); @@ -775,7 +775,7 @@ pub const MeshSelection = struct { pub fn placeBlock(inventoryStack: *main.items.ItemStack) !void { if(selectedBlockPos) |selectedPos| { - var block = RenderStructure.getBlock(selectedPos[0], selectedPos[1], selectedPos[2]) orelse return; + var block = RenderStructure.getBlockFromRenderThread(selectedPos[0], selectedPos[1], selectedPos[2]) orelse return; if(inventoryStack.item) |item| { switch(item) { .baseItem => |baseItem| { @@ -796,7 +796,7 @@ pub const MeshSelection = struct { const neighborPos = posBeforeBlock; neighborDir = selectedPos - posBeforeBlock; const relPos = lastPos - @as(Vec3d, @floatFromInt(neighborPos)); - block = RenderStructure.getBlock(neighborPos[0], neighborPos[1], neighborPos[2]) orelse return; + block = RenderStructure.getBlockFromRenderThread(neighborPos[0], neighborPos[1], neighborPos[2]) orelse return; if(block.typ == itemBlock) { if(rotationMode.generateData(main.game.world.?, neighborPos, relPos, lastDir, neighborDir, &block, false)) { // TODO: world.updateBlock(bi.x, bi.y, bi.z, block.data); (→ Sending it over the network) @@ -859,7 +859,7 @@ pub const MeshSelection = struct { c.glEnable(c.GL_POLYGON_OFFSET_LINE); defer c.glDisable(c.GL_POLYGON_OFFSET_LINE); c.glPolygonOffset(-2, 0); - const block = RenderStructure.getBlock(_selectedBlockPos[0], _selectedBlockPos[1], _selectedBlockPos[2]) orelse return; + const block = RenderStructure.getBlockFromRenderThread(_selectedBlockPos[0], _selectedBlockPos[1], _selectedBlockPos[2]) orelse return; const model = blocks.meshes.model(block); const voxelModel = &models.voxelModels.items[model.modelIndex]; const transformedMin = model.permutation.transform(voxelModel.min - @as(Vec3i, @splat(8))) + @as(Vec3i, @splat(8)); @@ -891,7 +891,6 @@ pub const RenderStructure = struct { var lastY: [settings.highestLOD + 1]i32 = [_]i32{0} ** (settings.highestLOD + 1); var lastZ: [settings.highestLOD + 1]i32 = [_]i32{0} ** (settings.highestLOD + 1); var lastSize: [settings.highestLOD + 1]i32 = [_]i32{0} ** (settings.highestLOD + 1); - var lodMutex: [settings.highestLOD + 1]std.Thread.Mutex = [_]std.Thread.Mutex{std.Thread.Mutex{}} ** (settings.highestLOD + 1); var mutex = std.Thread.Mutex{}; var blockUpdateMutex = std.Thread.Mutex{}; const BlockUpdate = struct { @@ -949,36 +948,17 @@ pub const RenderStructure = struct { return storageLists[lod][@intCast(index)]; } - fn _getNode(pos: chunk.ChunkPosition) ?*ChunkMeshNode { - const lod = std.math.log2_int(u31, pos.voxelSize); - lodMutex[lod].lock(); - defer lodMutex[lod].unlock(); - const xIndex = pos.wx-%(&lastX[lod]).* >> lod+chunk.chunkShift; - const yIndex = pos.wy-%(&lastY[lod]).* >> lod+chunk.chunkShift; - const zIndex = pos.wz-%(&lastZ[lod]).* >> lod+chunk.chunkShift; - if(xIndex < 0 or xIndex >= (&lastSize[lod]).*) return null; - if(yIndex < 0 or yIndex >= (&lastSize[lod]).*) return null; - if(zIndex < 0 or zIndex >= (&lastSize[lod]).*) return null; - const index = (xIndex*(&lastSize[lod]).* + yIndex)*(&lastSize[lod]).* + zIndex; - return storageLists[lod][@intCast(index)]; - } - - pub fn getChunk(x: i32, y: i32, z: i32) ?*chunk.Chunk { - const node = RenderStructure._getNode(.{.wx = x, .wy = y, .wz = z, .voxelSize=1}) orelse return null; - return &node.mesh.chunk; - } - - pub fn getBlock(x: i32, y: i32, z: i32) ?blocks.Block { - const node = RenderStructure._getNode(.{.wx = x, .wy = y, .wz = z, .voxelSize=1}) orelse return null; + fn getBlockFromRenderThread(x: i32, y: i32, z: i32) ?blocks.Block { + const node = RenderStructure.getNodeFromRenderThread(.{.wx = x, .wy = y, .wz = z, .voxelSize=1}) orelse return null; const mesh = node.mesh orelse return null; const block = mesh.chunk.getBlock(x & chunk.chunkMask, y & chunk.chunkMask, z & chunk.chunkMask); return block; } - pub fn getBlockFromAnyLod(x: i32, y: i32, z: i32) blocks.Block { + fn getBlockFromAnyLodFromRenderThread(x: i32, y: i32, z: i32) blocks.Block { var lod: u5 = 0; while(lod < settings.highestLOD) : (lod += 1) { - const node = RenderStructure._getNode(.{.wx = x, .wy = y, .wz = z, .voxelSize=@as(u31, 1) << lod}) orelse continue; + const node = RenderStructure.getNodeFromRenderThread(.{.wx = x, .wy = y, .wz = z, .voxelSize=@as(u31, 1) << lod}) orelse continue; const mesh = node.mesh orelse continue; const block = mesh.chunk.getBlock(x & chunk.chunkMask<