Add the player inventory(no gui yet), fix compile errors from last commit and fix a data race.

This commit is contained in:
IntegratedQuantum 2022-11-22 15:46:04 +01:00
parent 0f0b0b6ac4
commit df36109ee5
10 changed files with 449 additions and 301 deletions

View File

@ -450,7 +450,7 @@ pub const meshing = struct {
pub const ChunkMesh = struct {
pos: ChunkPosition,
size: ChunkCoordinate,
chunk: ?*Chunk,
chunk: std.atomic.Atomic(?*Chunk),
faces: std.ArrayList(u32),
faceData: SSBO,
coreCount: u31 = 0,
@ -465,7 +465,7 @@ pub const meshing = struct {
.pos = pos,
.size = chunkSize*pos.voxelSize,
.faces = std.ArrayList(u32).init(allocator),
.chunk = null,
.chunk = std.atomic.Atomic(?*Chunk).init(null),
.faceData = SSBO.init(),
};
}
@ -473,7 +473,7 @@ pub const meshing = struct {
pub fn deinit(self: *ChunkMesh) void {
self.faceData.deinit();
self.faces.deinit();
if(self.chunk) |ch| {
if(self.chunk.load(.Monotonic)) |ch| {
renderer.RenderStructure.allocator.destroy(ch);
}
}
@ -544,10 +544,10 @@ pub const meshing = struct {
}
}
if(self.chunk) |oldChunk| {
if(self.chunk.load(.Monotonic)) |oldChunk| {
renderer.RenderStructure.allocator.destroy(oldChunk);
}
self.chunk = chunk;
self.chunk.store(chunk, .Monotonic);
self.coreCount = @intCast(u31, self.faces.items.len);
self.neighborStart = [_]u31{self.coreCount} ** 7;
}
@ -625,7 +625,7 @@ pub const meshing = struct {
self.mutex.lock();
defer self.mutex.unlock();
if(!self.generated) return;
const oldBlock = self.chunk.?.blocks[getIndex(x, y, z)];
const oldBlock = self.chunk.load(.Monotonic).?.blocks[getIndex(x, y, z)];
for(Neighbors.iterable) |neighbor| {
var neighborMesh = self;
var nx = x + Neighbors.relX[neighbor];
@ -640,7 +640,7 @@ pub const meshing = struct {
nx &= chunkMask;
ny &= chunkMask;
nz &= chunkMask;
const neighborBlock = neighborMesh.chunk.?.blocks[getIndex(nx, ny, nz)];
const neighborBlock = neighborMesh.chunk.load(.Monotonic).?.blocks[getIndex(nx, ny, nz)];
{
{ // The face of the changed block
const newVisibility = canBeSeenThroughOtherBlock(newBlock, neighborBlock, neighbor);
@ -701,7 +701,7 @@ pub const meshing = struct {
}
if(neighborMesh != self) neighborMesh.uploadData();
}
self.chunk.?.blocks[getIndex(x, y, z)] = newBlock;
self.chunk.load(.Monotonic).?.blocks[getIndex(x, y, z)] = newBlock;
self.uploadData();
}
@ -712,7 +712,7 @@ pub const meshing = struct {
pub fn uploadDataAndFinishNeighbors(self: *ChunkMesh) !void {
std.debug.assert(!self.mutex.tryLock()); // The mutex should be locked when calling this function.
if(self.chunk == null) return; // In the mean-time the mesh was discarded and recreated and all the data was lost.
const chunk = self.chunk.load(.Monotonic) orelse return; // In the mean-time the mesh was discarded and recreated and all the data was lost.
self.faces.shrinkRetainingCapacity(self.coreCount);
for(Neighbors.iterable) |neighbor| {
self.neighborStart[neighbor] = @intCast(u31, self.faces.items.len);
@ -748,8 +748,8 @@ pub const meshing = struct {
var otherX = @intCast(u8, x+%Neighbors.relX[neighbor] & chunkMask);
var otherY = @intCast(u8, y+%Neighbors.relY[neighbor] & chunkMask);
var otherZ = @intCast(u8, z+%Neighbors.relZ[neighbor] & chunkMask);
var block = (&self.chunk.?.blocks)[getIndex(x, y, z)]; // a temporary fix to a compiler performance bug. TODO: check if this was fixed.
var otherBlock = (&neighborMesh.chunk.?.blocks)[getIndex(otherX, otherY, otherZ)]; // a temporary fix to a compiler performance bug. TODO: check if this was fixed.
var block = (&chunk.blocks)[getIndex(x, y, z)]; // a temporary fix to a compiler performance bug. TODO: check if this was fixed.
var otherBlock = (&neighborMesh.chunk.load(.Monotonic).?.blocks)[getIndex(otherX, otherY, otherZ)]; // a temporary fix to a compiler performance bug. TODO: check if this was fixed.
if(canBeSeenThroughOtherBlock(block, otherBlock, neighbor)) {
const normal: u32 = neighbor;
const position: u32 = @as(u32, otherX) | @as(u32, otherY)<<5 | @as(u32, otherZ)<<10 | normal<<24;
@ -810,8 +810,8 @@ pub const meshing = struct {
var otherX = @intCast(u8, (x+%Neighbors.relX[neighbor]+%offsetX >> 1) & chunkMask);
var otherY = @intCast(u8, (y+%Neighbors.relY[neighbor]+%offsetY >> 1) & chunkMask);
var otherZ = @intCast(u8, (z+%Neighbors.relZ[neighbor]+%offsetZ >> 1) & chunkMask);
var block = (&self.chunk.?.blocks)[getIndex(x, y, z)]; // a temporary fix to a compiler performance bug. TODO: check if this was fixed.
var otherBlock = (&neighborMesh.chunk.?.blocks)[getIndex(otherX, otherY, otherZ)]; // a temporary fix to a compiler performance bug. TODO: check if this was fixed.
var block = (&chunk.blocks)[getIndex(x, y, z)]; // a temporary fix to a compiler performance bug. TODO: check if this was fixed.
var otherBlock = (&neighborMesh.chunk.load(.Monotonic).?.blocks)[getIndex(otherX, otherY, otherZ)]; // a temporary fix to a compiler performance bug. TODO: check if this was fixed.
if(canBeSeenThroughOtherBlock(otherBlock, block, neighbor ^ 1)) {
const normal: u32 = neighbor ^ 1;
const position: u32 = @as(u32, x) | @as(u32, y)<<5 | @as(u32, z)<<10 | normal<<24;

View File

@ -2,6 +2,8 @@ const std = @import("std");
const assets = @import("assets.zig");
const chunk = @import("chunk.zig");
const items = @import("items.zig");
const Inventory = items.Inventory;
const json = @import("json.zig");
const JsonElement = json.JsonElement;
const main = @import("main.zig");
@ -46,7 +48,8 @@ pub const Player = struct {
var vel: Vec3d = Vec3d{0, 0, 0};
pub var id: u32 = 0;
pub var isFlying: std.atomic.Atomic(bool) = std.atomic.Atomic(bool).init(true);
var mutex: std.Thread.Mutex = std.Thread.Mutex{};
pub var mutex: std.Thread.Mutex = std.Thread.Mutex{};
pub var inventory__SEND_CHANGES_TO_SERVER: Inventory = undefined;
pub fn setPosBlocking(newPos: Vec3d) void {
mutex.lock();
@ -92,6 +95,7 @@ pub const World = struct {
.name = "client",
.milliTime = std.time.milliTimestamp(),
};
Player.inventory__SEND_CHANGES_TO_SERVER = try Inventory.init(renderer.RenderStructure.allocator, 32);
// TODO:
// super.itemEntityManager = new InterpolatedItemEntityManager(this);
// player = new ClientPlayer(this, 0);
@ -100,6 +104,7 @@ pub const World = struct {
pub fn deinit(self: *World) void {
self.conn.deinit();
Player.inventory__SEND_CHANGES_TO_SERVER.deinit(renderer.RenderStructure.allocator);
}
pub fn finishHandshake(self: *World, jsonObject: JsonElement) !void {

View File

@ -660,6 +660,12 @@ pub const Image = struct {
stb_image.stbi_image_free(data);
return result;
}
pub fn setRGB(self: Image, x: usize, y: usize, rgb: Color) void {
std.debug.assert(x < self.width);
std.debug.assert(y < self.height);
const index = x + y*self.width;
self.imageData[index] = rgb;
}
};
pub const Fog = struct {

File diff suppressed because it is too large Load Diff

View File

@ -136,7 +136,7 @@ pub const JsonElement = union(JsonType) {
.Null => return JsonElement{.JsonNull={}},
.Bool => return JsonElement{.JsonBool=value},
.Int, .ComptimeInt => return JsonElement{.JsonInt=@intCast(i64, value)},
.Float, .ComptimeFloat => return JsonElement{.JsonInt=@floatCast(f64, value)},
.Float, .ComptimeFloat => return JsonElement{.JsonFloat=@floatCast(f64, value)},
.Union => {
if(@TypeOf(value) == JsonElement) {
return value;
@ -144,6 +144,14 @@ pub const JsonElement = union(JsonType) {
@compileError("Unknown value type.");
}
},
.Pointer => |ptr| {
if(ptr.child == u8 and ptr.size == .Slice) {
std.log.info("String: {s}", .{value});
return JsonElement{.JsonString=value};
} else {
@compileError("Unknown value type.");
}
},
else => {
@compileError("Unknown value type.");
},
@ -152,7 +160,7 @@ pub const JsonElement = union(JsonType) {
pub fn put(self: *const JsonElement, key: []const u8, value: anytype) !void {
const result = createElementFromRandomType(value);
try self.JsonObject.put(key, result);
try self.JsonObject.put(try self.JsonObject.allocator.dupe(u8, key), result);
}
pub fn free(self: *const JsonElement, allocator: Allocator) void {
@ -185,7 +193,6 @@ pub const JsonElement = union(JsonType) {
return self.* == JsonType.JsonNull;
}
// TODO: toString()
fn escape(string: []const u8, allocator: Allocator) ![]const u8 {
var out = std.ArrayList(u8).init(allocator);
for(string) |char| {

View File

@ -22,6 +22,7 @@ pub const c = @cImport ({
});
pub threadlocal var threadAllocator: std.mem.Allocator = undefined;
pub var globalAllocator: std.mem.Allocator = undefined;
pub var threadPool: utils.ThreadPool = undefined;
var logFile: std.fs.File = undefined;
@ -218,6 +219,11 @@ pub fn main() !void {
defer if(gpa.deinit()) {
@panic("Memory leak");
};
var global_gpa = std.heap.GeneralPurposeAllocator(.{.thread_safe=true}){};
globalAllocator = global_gpa.allocator();
defer if(global_gpa.deinit()) {
@panic("Memory leak");
};
// init logging.
try std.fs.cwd().makePath("logs");

View File

@ -5,15 +5,19 @@ const assets = @import("assets.zig");
const Block = @import("blocks.zig").Block;
const chunk = @import("chunk.zig");
const entity = @import("entity.zig");
const items = @import("items.zig");
const Inventory = items.Inventory;
const ItemStack = items.ItemStack;
const json = @import("json.zig");
const main = @import("main.zig");
const game = @import("game.zig");
const settings = @import("settings.zig");
const json = @import("json.zig");
const JsonElement = json.JsonElement;
const renderer = @import("renderer.zig");
const utils = @import("utils.zig");
const vec = @import("vec.zig");
const Vec3d = vec.Vec3d;
const Vec3f = vec.Vec3f;
//TODO: Might want to use SSL or something similar to encode the message
@ -977,7 +981,7 @@ pub const Protocols: struct {
const type_itemStackDrop: u8 = 6;
const type_itemStackCollect: u8 = 7;
const type_timeAndBiome: u8 = 8;
fn receive(_: *Connection, data: []const u8) !void {
fn receive(conn: *Connection, data: []const u8) !void {
switch(data[0]) {
type_renderDistance => {
const renderDistance = std.mem.readIntBig(i32, data[1..5]);
@ -1047,18 +1051,18 @@ pub const Protocols: struct {
// );
},
type_itemStackCollect => {
// TODO:
// JsonObject json = JsonParser.parseObjectFromString(new String(data, offset + 1, length - 1, StandardCharsets.UTF_8));
// Item item = Item.load(json, Cubyz.world.registries);
// if (item == null) {
// break;
// }
// int remaining = Cubyz.player.getInventory_AND_DONT_FORGET_TO_SEND_CHANGES_TO_THE_SERVER().addItem(item, json.getInt("amount", 1));
// sendInventory_full(Cubyz.world.serverConnection, Cubyz.player.getInventory_AND_DONT_FORGET_TO_SEND_CHANGES_TO_THE_SERVER());
// if(remaining != 0) {
// // Couldn't collect everything drop it again.
// itemStackDrop(Cubyz.world.serverConnection, new ItemStack(item, remaining), Cubyz.player.getPosition(), Camera.getDirection(), 0);
// }
const jsonObject = json.parseFromString(main.threadAllocator, data[1..]);
defer jsonObject.free(main.threadAllocator);
const item = try items.Item.init(jsonObject);
game.Player.mutex.lock();
defer game.Player.mutex.unlock();
const remaining = game.Player.inventory__SEND_CHANGES_TO_SERVER.addItem(item, jsonObject.get(u16, "amount", 0));
try sendInventory_full(conn, game.Player.inventory__SEND_CHANGES_TO_SERVER);
if(remaining != 0) {
// Couldn't collect everything drop it again.
try itemStackDrop(conn, ItemStack{.item=item, .amount=remaining}, game.Player.getPosBlocking(), Vec3f{0, 0, 0}, 0);
}
},
type_timeAndBiome => {
if(game.world) |world| {
@ -1134,10 +1138,14 @@ pub const Protocols: struct {
try conn.sendImportant(id, &data);
}
// TODO:
// public void sendInventory_full(ServerConnection conn, Inventory inv) {
// addHeaderAndSendImportant(conn, INVENTORY_FULL, inv.save().toString().getBytes(StandardCharsets.UTF_8));
// }
pub fn sendInventory_full(conn: *Connection, inv: Inventory) !void {
const jsonObject = try inv.save(main.threadAllocator);
defer jsonObject.free(main.threadAllocator);
const string = try jsonObject.toString(main.threadAllocator);
defer main.threadAllocator.free(string);
try addHeaderAndSendImportant(conn, type_inventoryFull, string);
}
pub fn clearInventory(conn: *Connection) !void {
var data: [1]u8 = undefined;
@ -1145,23 +1153,28 @@ pub const Protocols: struct {
try conn.sendImportant(id, &data);
}
// TODO:
// public void itemStackDrop(ServerConnection conn, ItemStack stack, Vector3d pos, Vector3f dir, float vel) {
// JsonObject json = stack.store();
// json.put("x", pos.x);
// json.put("y", pos.y);
// json.put("z", pos.z);
// json.put("dirX", dir.x);
// json.put("dirY", dir.y);
// json.put("dirZ", dir.z);
// json.put("vel", vel);
// addHeaderAndSendImportant(conn, ITEM_STACK_DROP, json.toString().getBytes(StandardCharsets.UTF_8));
// }
pub fn itemStackDrop(conn: *Connection, stack: ItemStack, pos: Vec3d, dir: Vec3f, vel: f32) !void {
var jsonObject = try stack.store(main.threadAllocator);
defer jsonObject.free(main.threadAllocator);
try jsonObject.put("x", pos[0]);
try jsonObject.put("y", pos[1]);
try jsonObject.put("z", pos[2]);
try jsonObject.put("dirX", dir[0]);
try jsonObject.put("dirY", dir[1]);
try jsonObject.put("dirZ", dir[2]);
try jsonObject.put("vel", vel);
const string = try jsonObject.toString(main.threadAllocator);
defer main.threadAllocator.free(string);
try addHeaderAndSendImportant(conn, type_itemStackDrop, string);
}
// TODO:
// public void itemStackCollect(User user, ItemStack stack) {
// addHeaderAndSendImportant(user, ITEM_STACK_COLLECT, stack.store().toString().getBytes(StandardCharsets.UTF_8));
// }
pub fn itemStackCollect(conn: *Connection, stack: ItemStack) !void {
var jsonObject = try stack.store(main.threadAllocator);
defer jsonObject.free(main.threadAllocator);
const string = try jsonObject.toString(main.threadAllocator);
defer main.threadAllocator.free(string);
try addHeaderAndSendImportant(conn, type_itemStackCollect, string);
}
// TODO:
// public void sendTimeAndBiome(User user, ServerWorld world) {

View File

@ -10,16 +10,16 @@ pub fn scrambleSeed(seed: *u64) void {
seed.* = (seed.* ^ multiplier) & mask;
}
fn nextWithBitSize(T: type, seed: *u64, bitSize: u6) T {
fn nextWithBitSize(comptime T: type, seed: *u64, bitSize: u6) T {
seed.* = ((seed.*)*multiplier + addend) & mask;
return @intCast(T, (seed >> (48 - bitSize)) & std.math.maxInt(T));
return @intCast(T, (seed.* >> (48 - bitSize)) & std.math.maxInt(T));
}
fn next(T: type, seed: *u64) T {
nextWithBitSize(T, seed, @bitSizeOf(T));
fn next(comptime T: type, seed: *u64) T {
return nextWithBitSize(T, seed, @bitSizeOf(T));
}
pub fn nextInt(T: type, seed: *u64) T {
pub fn nextInt(comptime T: type, seed: *u64) T {
if(@bitSizeOf(T) > 48) {
@compileError("Did not yet implement support for bigger numbers.");
} else {
@ -27,8 +27,8 @@ pub fn nextInt(T: type, seed: *u64) T {
}
}
pub fn nextIntBounded(T: type, seed: *u64, bound: T) T {
var bitSize = std.math.log2_int_ceil(bound);
pub fn nextIntBounded(comptime T: type, seed: *u64, bound: T) T {
var bitSize = std.math.log2_int_ceil(T, bound);
var result = nextWithBitSize(T, seed, bitSize);
while(result >= bound) {
result = nextWithBitSize(T, seed, bitSize);

View File

@ -877,7 +877,7 @@ pub const RenderStructure = struct {
pub fn getBlock(x: chunk.ChunkCoordinate, y: chunk.ChunkCoordinate, z: chunk.ChunkCoordinate) ?blocks.Block {
const node = RenderStructure._getNode(.{.wx = x, .wy = y, .wz = z, .voxelSize=1}) orelse return null;
const block = (node.mesh.chunk orelse return null).getBlock(x & chunk.chunkMask, y & chunk.chunkMask, z & chunk.chunkMask);
const block = (node.mesh.chunk.load(.Monotonic) orelse return null).getBlock(x & chunk.chunkMask, y & chunk.chunkMask, z & chunk.chunkMask);
return block;
}

View File

@ -22,8 +22,8 @@ pub fn length(self: anytype) @typeInfo(@TypeOf(self)).Vector.child {
return @sqrt(@reduce(.Add, self*self));
}
pub fn normalize(self: anytype) @typeInfo(@TypeOf(self)).Vector.child {
return self/length(self);
pub fn normalize(self: anytype) @TypeOf(self) {
return self/@splat(@typeInfo(@TypeOf(self)).Vector.len, length(self));
}
pub fn cross(self: anytype, other: @TypeOf(self)) @TypeOf(self) {