Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
33 changes: 33 additions & 0 deletions src/Inventory.zig
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,24 @@ pub const Sync = struct { // MARK: Sync
commands.pushBack(cmd);
}
}

fn setSpawn(newSpawnPoint: Vec3d) void {
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we should synchronize the spawn point with the client. I think the client shouldn't even know the spawn point. Instead I'd prefer if the client gets its respawn point sent by the server together with the kill packet.

mutex.lock();
defer mutex.unlock();
main.game.Player.setSpawn(newSpawnPoint);
var tempData = main.List(Command).init(main.stackAllocator);
defer tempData.deinit();
while(commands.popBack()) |_cmd| {
var cmd = _cmd;
cmd.undo();
tempData.append(cmd);
}
while(tempData.popOrNull()) |_cmd| {
var cmd = _cmd;
cmd.do(main.globalAllocator, .client, null, main.game.Player.gamemode.raw) catch unreachable;
commands.pushBack(cmd);
}
}
};

pub const ServerSide = struct { // MARK: ServerSide
Expand Down Expand Up @@ -498,6 +516,13 @@ pub const Sync = struct { // MARK: Sync
user.gamemode.store(gamemode, .monotonic);
main.network.protocols.genericUpdate.sendGamemode(user.conn, gamemode);
}

fn setSpawn(user: *main.server.User, newSpawnPoint: Vec3d) void {
mutex.lock();
defer mutex.unlock();
user.playerSpawnPos = newSpawnPoint;
main.network.protocols.genericUpdate.sendSpawnPoint(user.conn, newSpawnPoint);
}
};

pub fn addHealth(health: f32, cause: main.game.DamageType, side: Side, userId: u32) void {
Expand All @@ -522,6 +547,14 @@ pub const Sync = struct { // MARK: Sync
ServerSide.setGamemode(user.?, gamemode);
}
}

pub fn setSpawn(user: ?*main.server.User, newSpawnPoint: Vec3d) void {
if(user == null) {
ClientSide.setSpawn(newSpawnPoint);
} else {
ServerSide.setSpawn(user.?, newSpawnPoint);
}
}
};

pub const Command = struct { // MARK: Command
Expand Down
7 changes: 6 additions & 1 deletion src/game.zig
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,7 @@ pub const Player = struct { // MARK: Player
desiredPos: Vec3d = .{0, 0, 1.7 - standingBoundingBoxExtent[2]},
};
pub var super: main.server.Entity = .{};
pub var playerSpawnPos: Vec3d = .{0, 0, 0};
Copy link
Contributor

Choose a reason for hiding this comment

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

It's better to rename it to spawnPos, player prefix is redundant

pub var eye: EyeData = .{};
pub var crouching: bool = false;
pub var id: u32 = 0;
Expand Down Expand Up @@ -512,6 +513,10 @@ pub const Player = struct { // MARK: Player
}
}

pub fn setSpawn(newSpawnpoint: Vec3d) void {
playerSpawnPos = newSpawnpoint;
}

pub fn isCreative() bool {
return gamemode.load(.monotonic) == .creative;
}
Expand Down Expand Up @@ -544,7 +549,7 @@ pub const Player = struct { // MARK: Player
}

pub fn kill() void {
Player.super.pos = world.?.spawn;
Player.super.pos = Player.playerSpawnPos;
Copy link
Member

Choose a reason for hiding this comment

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

Why did you add a second variable to store the spawn point?

Following on my comment above, please remove both of them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

one for the user/server one for the game/client

Copy link
Member

Choose a reason for hiding this comment

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

Is the other one used for anything else?

Player.super.vel = .{0, 0, 0};

Player.super.health = Player.super.maxHealth;
Expand Down
17 changes: 16 additions & 1 deletion src/network/protocols.zig
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ pub const genericUpdate = struct { // MARK: genericUpdate
time = 3,
biome = 4,
particles = 5,
setSpawn = 6,
Copy link
Member

Choose a reason for hiding this comment

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

not needed, see my comment above,

};

const WorldEditPosition = enum(u2) {
Expand Down Expand Up @@ -579,12 +580,16 @@ pub const genericUpdate = struct { // MARK: genericUpdate
const emitter: particles.Emitter = .init(particleId, collides);
particles.ParticleSystem.addParticlesFromNetwork(emitter, pos, count);
},
.setSpawn => {
if(conn.isServerSide()) return error.InvalidPacket;
game.Player.setSpawn(try reader.readVec(Vec3d));
},
}
}

fn serverReceive(conn: *Connection, reader: *utils.BinaryReader) !void {
switch(try reader.readEnum(UpdateType)) {
.gamemode, .teleport, .time, .biome, .particles => return error.InvalidSide,
.gamemode, .teleport, .time, .biome, .particles, .setSpawn => return error.InvalidSide,
.worldEditPos => {
const typ = try reader.readEnum(WorldEditPosition);
const pos: ?Vec3i = switch(typ) {
Expand All @@ -607,6 +612,16 @@ pub const genericUpdate = struct { // MARK: genericUpdate
conn.send(.fast, id, &.{@intFromEnum(UpdateType.gamemode), @intFromEnum(gamemode)});
}

pub fn sendSpawnPoint(conn: *Connection, pos: Vec3d) void {
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, 25);
defer writer.deinit();

writer.writeEnum(UpdateType, .setSpawn);
writer.writeVec(Vec3d, pos);

conn.send(.fast, id, writer.data.items);
}

pub fn sendTPCoordinates(conn: *Connection, pos: Vec3d) void {
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, 25);
defer writer.deinit();
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 @@ -3,6 +3,7 @@ pub const gamemode = @import("gamemode.zig");
pub const help = @import("help.zig");
pub const invite = @import("invite.zig");
pub const kill = @import("kill.zig");
pub const setSpawn = @import("setSpawn.zig");
Copy link
Member

Choose a reason for hiding this comment

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

Please keep this sorted alphabetically.
Also please call it just spawn it can also serve as a way to query the spawn position.

pub const particles = @import("particles.zig");
pub const tickspeed = @import("tickspeed.zig");
pub const time = @import("time.zig");
Expand Down
42 changes: 42 additions & 0 deletions src/server/command/setSpawn.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const std = @import("std");

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

pub const description = "Sets the spawn point for the player";
pub const usage = "/setSpawn";

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| {
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 /setspawn", .{});
return;
}
}
if(x == null or y == null) {
source.sendMessage("#ff0000Too few arguments for command /setspawn", .{});
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);

main.items.Inventory.Sync.setSpawn(source, .{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),
playerSpawnPos: Vec3d = .{0, 0, 0},
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need two separate spawn points?

worldEditData: WorldEditData = undefined,

lastSentBiomeId: u32 = 0xffffffff,
Expand Down
6 changes: 6 additions & 0 deletions src/server/world.zig
Original file line number Diff line number Diff line change
Expand Up @@ -872,13 +872,17 @@ pub const ServerWorld = struct { // MARK: ServerWorld
player.pos = @floatFromInt(self.spawn);

main.items.Inventory.Sync.setGamemode(user, self.defaultGamemode);
main.items.Inventory.Sync.setSpawn(user, @as(Vec3d, @floatFromInt(self.spawn)));
} else {
player.loadFrom(playerData.getChild("entity"));

main.items.Inventory.Sync.setGamemode(user, std.meta.stringToEnum(main.game.Gamemode, playerData.get([]const u8, "gamemode", @tagName(self.defaultGamemode))) orelse self.defaultGamemode);
main.items.Inventory.Sync.setSpawn(user, playerData.get(Vec3d, "playerSpawnPos", @as(Vec3d, @floatFromInt(self.spawn))));
}
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.playerSpawnPos = playerData.get(Vec3d, "playerSpawnPos", @splat(0));
}

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 +947,8 @@ pub const ServerWorld = struct { // MARK: ServerWorld
} else @panic("The player hand inventory wasn't found. Cannot save player data.");
}

playerZon.put("playerSpawnPos", user.playerSpawnPos);

const playerPath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/players", .{self.path}) catch unreachable;
defer main.stackAllocator.free(playerPath);

Expand Down