Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/Inventory.zig
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,7 @@ pub const Command = struct { // MARK: Command
},
kill: struct {
target: ?*main.server.User,
spawnPoint: Vec3d,
},
energy: struct {
target: ?*main.server.User,
Expand Down Expand Up @@ -702,8 +703,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);
Expand Down Expand Up @@ -773,6 +774,7 @@ pub const Command = struct { // MARK: Command
.kill => {
return .{.kill = .{
.target = null,
.spawnPoint = try reader.readVec(Vec3d),
}};
},
.energy => {
Expand Down Expand Up @@ -806,7 +808,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);
},
Expand Down Expand Up @@ -1025,6 +1029,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 = .{
Expand Down
4 changes: 2 additions & 2 deletions src/game.zig
Original file line number Diff line number Diff line change
Expand Up @@ -543,8 +543,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;
Expand Down
1 change: 1 addition & 0 deletions src/server/command/_list.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
47 changes: 47 additions & 0 deletions src/server/command/spawn.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const std = @import("std");

const main = @import("main");
const User = main.server.User;

pub const description = "Get or set the player spawnPoint";
pub const usage =
\\/spawn
\\/spawn <x> <y>
\\/spawn <x> <y> <z>
;

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 or y == null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should only trigger when x is null, and needs a separate case for x != null and y == null

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be done, but cannot test because of #2485

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try it in a new world

Copy link
Contributor Author

@Wunka Wunka Jan 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with different world it worked. But I don't like the wording of the message (I changed it since my comment) maybe just send the usage?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, sending the usage would be good.

Also note that with #1425 we would also get more consistent error messages.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now its sending the usage

source.sendMessage("#ffff00{}", .{source.spawnPos});
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.?};
}
1 change: 1 addition & 0 deletions src/server/server.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions src/server/world.zig
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,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 {
Expand Down Expand Up @@ -943,6 +945,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);

Expand Down