diff --git a/src/Inventory.zig b/src/Inventory.zig index 68ed5b24e..92bec2bbb 100644 --- a/src/Inventory.zig +++ b/src/Inventory.zig @@ -682,6 +682,7 @@ pub const Command = struct { // MARK: Command }, kill: struct { target: ?*main.server.User, + spawnPoint: Vec3d, }, energy: struct { target: ?*main.server.User, @@ -727,8 +728,8 @@ pub const Command = struct { // MARK: Command .health => |health| { main.game.Player.super.health = std.math.clamp(main.game.Player.super.health + health.health, 0, main.game.Player.super.maxHealth); }, - .kill => { - main.game.Player.kill(); + .kill => |kill| { + main.game.Player.kill(kill.spawnPoint); }, .energy => |energy| { main.game.Player.super.energy = std.math.clamp(main.game.Player.super.energy + energy.energy, 0, main.game.Player.super.maxEnergy); @@ -798,6 +799,7 @@ pub const Command = struct { // MARK: Command .kill => { return .{.kill = .{ .target = null, + .spawnPoint = try reader.readVec(Vec3d), }}; }, .energy => { @@ -831,7 +833,9 @@ pub const Command = struct { // MARK: Command .health => |health| { writer.writeFloat(f32, health.health); }, - .kill => {}, + .kill => |kill| { + writer.writeVec(Vec3d, kill.spawnPoint); + }, .energy => |energy| { writer.writeFloat(f32, energy.energy); }, @@ -1053,6 +1057,7 @@ pub const Command = struct { // MARK: Command self.syncOperations.append(allocator, .{.kill = .{ .target = info.target.?, + .spawnPoint = info.target.?.spawnPos, }}); } else { self.syncOperations.append(allocator, .{.health = .{ diff --git a/src/game.zig b/src/game.zig index 443540071..9e7ec0067 100644 --- a/src/game.zig +++ b/src/game.zig @@ -544,8 +544,8 @@ pub const Player = struct { // MARK: Player inventory.placeBlock(selectedSlot); } - pub fn kill() void { - Player.super.pos = world.?.spawn; + pub fn kill(spawnPos: Vec3d) void { + Player.super.pos = spawnPos; Player.super.vel = .{0, 0, 0}; Player.super.health = Player.super.maxHealth; @@ -617,7 +617,6 @@ pub const World = struct { // MARK: World name: []const u8, milliTime: i64, gameTime: Atomic(i64) = .init(0), - spawn: Vec3f = undefined, connected: bool = true, blockPalette: *assets.Palette = undefined, itemPalette: *assets.Palette = undefined, @@ -691,7 +690,6 @@ pub const World = struct { // MARK: World errdefer self.itemPalette.deinit(); self.toolPalette = try assets.Palette.init(main.globalAllocator, zon.getChild("toolPalette"), null); errdefer self.toolPalette.deinit(); - self.spawn = zon.get(Vec3f, "spawn", .{0, 0, 0}); const path = std.fmt.allocPrint(main.stackAllocator.allocator, "{s}/serverAssets", .{main.files.cubyzDirStr()}) catch unreachable; defer main.stackAllocator.free(path); diff --git a/src/network/protocols.zig b/src/network/protocols.zig index ee2c6ac8e..71f5e2eda 100644 --- a/src/network/protocols.zig +++ b/src/network/protocols.zig @@ -202,7 +202,6 @@ pub const handShake = struct { // MARK: handShake defer zonObject.deinit(main.stackAllocator); zonObject.put("player", conn.user.?.player.save(main.stackAllocator)); zonObject.put("player_id", conn.user.?.id); - zonObject.put("spawn", main.server.world.?.spawn); zonObject.put("blockPalette", main.server.world.?.blockPalette.storeToZon(main.stackAllocator)); zonObject.put("itemPalette", main.server.world.?.itemPalette.storeToZon(main.stackAllocator)); zonObject.put("toolPalette", main.server.world.?.toolPalette.storeToZon(main.stackAllocator)); diff --git a/src/server/command/_list.zig b/src/server/command/_list.zig index 0704320f0..e6c2ef363 100644 --- a/src/server/command/_list.zig +++ b/src/server/command/_list.zig @@ -4,6 +4,7 @@ pub const help = @import("help.zig"); pub const invite = @import("invite.zig"); pub const kill = @import("kill.zig"); pub const particles = @import("particles.zig"); +pub const spawn = @import("spawn.zig"); pub const tickspeed = @import("tickspeed.zig"); pub const time = @import("time.zig"); pub const tp = @import("tp.zig"); diff --git a/src/server/command/spawn.zig b/src/server/command/spawn.zig new file mode 100644 index 000000000..b95293224 --- /dev/null +++ b/src/server/command/spawn.zig @@ -0,0 +1,51 @@ +const std = @import("std"); + +const main = @import("main"); +const User = main.server.User; + +pub const description = "Get or set the player spawn point"; +pub const usage = + \\/spawn + \\/spawn + \\/spawn +; + +pub fn execute(args: []const u8, source: *User) void { + var x: ?f64 = null; + var y: ?f64 = null; + var z: ?f64 = null; + var split = std.mem.splitScalar(u8, args, ' '); + while(split.next()) |arg| { + if(arg.len == 0) break; + const num: f64 = std.fmt.parseFloat(f64, arg) catch { + source.sendMessage("#ff0000Expected number, found \"{s}\"", .{arg}); + return; + }; + if(x == null) { + x = num; + } else if(y == null) { + y = num; + } else if(z == null) { + z = num; + } else { + source.sendMessage("#ff0000Too many arguments for command /spawn", .{}); + return; + } + } + if(x == null) { + source.sendMessage("#ffff00{}", .{source.spawnPos}); + return; + } + if(y == null) { + source.sendMessage("#ff0000Invalid number of arguments for /spawn.\nUsage: \n" ++ usage, .{}); + return; + } + if(z == null) { + z = source.player.pos[2]; + } + x = std.math.clamp(x.?, -1e9, 1e9); // TODO: Remove after #310 is implemented + y = std.math.clamp(y.?, -1e9, 1e9); + z = std.math.clamp(z.?, -1e9, 1e9); + + source.spawnPos = .{x.?, y.?, z.?}; +} diff --git a/src/server/server.zig b/src/server/server.zig index 628bf95cc..c74aa8212 100644 --- a/src/server/server.zig +++ b/src/server/server.zig @@ -112,6 +112,7 @@ pub const User = struct { // MARK: User lastRenderDistance: u16 = 0, lastPos: Vec3i = @splat(0), gamemode: std.atomic.Value(main.game.Gamemode) = .init(.creative), + spawnPos: Vec3d = .{0, 0, 0}, worldEditData: WorldEditData = undefined, lastSentBiomeId: u32 = 0xffffffff, diff --git a/src/server/world.zig b/src/server/world.zig index cc708c1eb..2c28fceb2 100644 --- a/src/server/world.zig +++ b/src/server/world.zig @@ -862,6 +862,8 @@ pub const ServerWorld = struct { // MARK: ServerWorld } user.inventory = loadPlayerInventory(main.game.Player.inventorySize, playerData.get([]const u8, "playerInventory", ""), .{.playerInventory = user.id}, path); user.handInventory = loadPlayerInventory(1, playerData.get([]const u8, "hand", ""), .{.hand = user.id}, path); + + user.spawnPos = playerData.get(Vec3d, "playerSpawnPos", @as(Vec3d, @floatFromInt(self.spawn))); } fn loadPlayerInventory(size: usize, base64EncodedData: []const u8, source: main.items.Inventory.Source, playerDataFilePath: []const u8) main.items.Inventory.InventoryId { @@ -925,6 +927,8 @@ pub const ServerWorld = struct { // MARK: ServerWorld } else @panic("The player hand inventory wasn't found. Cannot save player data."); } + playerZon.put("playerSpawnPos", user.spawnPos); + const playerPath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/players", .{self.path}) catch unreachable; defer main.stackAllocator.free(playerPath);