diff --git a/src/client/Entity.zig b/src/client/Entity.zig index c7ce1070c4..a6305f0c49 100644 --- a/src/client/Entity.zig +++ b/src/client/Entity.zig @@ -30,7 +30,7 @@ rot: Vec3f = undefined, id: u32, name: []const u8, -playerIndex: usize, // TODO extract into own component #2760 +playerIndex: ?usize, // TODO extract into own component #2760 pub fn init(self: *@This(), zon: ZonElement, allocator: NeverFailingAllocator) void { self.* = @This(){ @@ -38,7 +38,7 @@ pub fn init(self: *@This(), zon: ZonElement, allocator: NeverFailingAllocator) v .width = zon.get(f64, "width", 1), .height = zon.get(f64, "height", 1), .name = allocator.dupe(u8, zon.get([]const u8, "name", "")), - .playerIndex = zon.get(usize, "playerIndex", std.math.maxInt(usize)), + .playerIndex = zon.get(?usize, "playerIndex", null), }; self._interpolationPos = [_]f64{ self.pos[0], @@ -75,9 +75,14 @@ pub fn update(self: *@This(), time: i16, lastTime: i16) void { } pub fn format(self: *const @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { - if (main.settings.showPlayerIndexWithName) { - try writer.print("{s}@{d}", .{self.name, self.playerIndex}); + if (main.settings.showPlayerIndexWithName and self.playerIndex != null) { + try self.formatWithPlayerIndex(writer); } else { try writer.print("{s}", .{self.name}); } } + +pub fn formatWithPlayerIndex(self: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { + std.debug.assert(self.playerIndex != null); + try writer.print("{s}@{d}", .{self.name, self.playerIndex.?}); +} diff --git a/src/gui/windows/_windowlist.zig b/src/gui/windows/_windowlist.zig index b8b5d8efa6..b05a494ca3 100644 --- a/src/gui/windows/_windowlist.zig +++ b/src/gui/windows/_windowlist.zig @@ -21,7 +21,7 @@ pub const inventory = @import("inventory.zig"); pub const inventory_crafting = @import("inventory_crafting.zig"); pub const invite = @import("invite.zig"); pub const main = @import("main.zig"); -pub const manage_players = @import("manage_players.zig"); +pub const players = @import("players.zig"); pub const multiplayer = @import("multiplayer.zig"); pub const notification = @import("notification.zig"); pub const pause = @import("pause.zig"); diff --git a/src/gui/windows/invite.zig b/src/gui/windows/invite.zig index 1a6c478447..16b4dc8559 100644 --- a/src/gui/windows/invite.zig +++ b/src/gui/windows/invite.zig @@ -74,7 +74,6 @@ pub fn onOpen() void { ipAddressEntry.obfuscated = main.settings.streamerMode; list.add(ipAddressEntry); list.add(Button.initText(.{0, 0}, 100, "Invite", .init(invite))); - list.add(Button.initText(.{0, 0}, 100, "Manage Players", gui.openWindowCallback("manage_players"))); list.add(CheckBox.init(.{0, 0}, width, "Allow anyone to join (requires a publicly visible IP address+port which may need some configuration in your router)", main.server.connectionManager.allowNewConnections.load(.monotonic), &makePublic)); list.finish(.center); window.rootComponent = list.toComponent(); diff --git a/src/gui/windows/manage_players.zig b/src/gui/windows/manage_players.zig deleted file mode 100644 index b5635acf64..0000000000 --- a/src/gui/windows/manage_players.zig +++ /dev/null @@ -1,77 +0,0 @@ -const std = @import("std"); - -const main = @import("main"); -const ConnectionManager = main.network.ConnectionManager; -const settings = main.settings; -const Vec2f = main.vec.Vec2f; - -const gui = @import("../gui.zig"); -const GuiComponent = gui.GuiComponent; -const GuiWindow = gui.GuiWindow; -const Button = @import("../components/Button.zig"); -const Label = @import("../components/Label.zig"); -const TextInput = @import("../components/TextInput.zig"); -const VerticalList = @import("../components/VerticalList.zig"); -const HorizontalList = @import("../components/HorizontalList.zig"); - -pub var window = GuiWindow{ - .contentSize = Vec2f{128, 256}, - .closeIfMouseIsGrabbed = true, -}; - -const padding: f32 = 8; -var userList: []*main.server.User = &.{}; - -fn kick(conn: *main.network.Connection) void { - conn.disconnect(); -} - -pub fn onOpen() void { - const list = VerticalList.init(.{padding, 16 + padding}, 300, 16); - { - main.server.connectionManager.mutex.lock(); - defer main.server.connectionManager.mutex.unlock(); - std.debug.assert(userList.len == 0); - userList = main.globalAllocator.alloc(*main.server.User, main.server.connectionManager.connections.items.len); - for (main.server.connectionManager.connections.items, 0..) |connection, i| { - userList[i] = connection.user.?; - userList[i].increaseRefCount(); - const row = HorizontalList.init(); - if (connection.user.?.name.len != 0) { - row.add(Label.init(.{0, 0}, 200, connection.user.?.name, .left)); - row.add(Button.initText(.{0, 0}, 100, "Kick", .initWithPtr(kick, connection))); - } else { - const ip = std.fmt.allocPrint(main.stackAllocator.allocator, "{f}", .{connection.remoteAddress}) catch unreachable; - defer main.stackAllocator.free(ip); - row.add(Label.init(.{0, 0}, 200, ip, .left)); - row.add(Button.initText(.{0, 0}, 100, "Cancel", .initWithPtr(kick, connection))); - } - list.add(row); - } - } - list.finish(.center); - window.rootComponent = list.toComponent(); - window.contentSize = window.rootComponent.?.pos() + window.rootComponent.?.size() + @as(Vec2f, @splat(padding)); - gui.updateWindowPositions(); -} - -pub fn onClose() void { - for (userList) |user| { - user.decreaseRefCount(); - } - main.globalAllocator.free(userList); - userList = &.{}; - if (window.rootComponent) |*comp| { - comp.deinit(); - } -} - -pub fn update() void { - main.server.connectionManager.mutex.lock(); - const serverListLen = main.server.connectionManager.connections.items.len; - main.server.connectionManager.mutex.unlock(); - if (userList.len != serverListLen) { - onClose(); - onOpen(); - } -} diff --git a/src/gui/windows/pause.zig b/src/gui/windows/pause.zig index d144df9e33..cb3fbde9bb 100644 --- a/src/gui/windows/pause.zig +++ b/src/gui/windows/pause.zig @@ -21,6 +21,7 @@ fn reorderHudCallbackFunction() void { } pub fn onOpen() void { const list = VerticalList.init(.{padding, 16 + padding}, 300, 16); + list.add(Button.initText(.{0, 0}, 128, "Players", gui.openWindowCallback("players"))); if (main.server.world != null) { list.add(Button.initText(.{0, 0}, 128, "Invite Player", gui.openWindowCallback("invite"))); } diff --git a/src/gui/windows/players.zig b/src/gui/windows/players.zig new file mode 100644 index 0000000000..194bcbf4f4 --- /dev/null +++ b/src/gui/windows/players.zig @@ -0,0 +1,115 @@ +const std = @import("std"); + +const main = @import("main"); +const ConnectionManager = main.network.ConnectionManager; +const settings = main.settings; +const Vec2f = main.vec.Vec2f; + +const gui = @import("../gui.zig"); +const GuiComponent = gui.GuiComponent; +const GuiWindow = gui.GuiWindow; +const Button = @import("../components/Button.zig"); +const Label = @import("../components/Label.zig"); +const TextInput = @import("../components/TextInput.zig"); +const VerticalList = @import("../components/VerticalList.zig"); +const HorizontalList = @import("../components/HorizontalList.zig"); + +pub var window = GuiWindow{ + .contentSize = Vec2f{128, 256}, + .closeIfMouseIsGrabbed = true, +}; + +const padding: f32 = 8; +var userList: []*main.server.User = &.{}; +var entityCount: u32 = 0; + +fn kickbyConnection(conn: *main.network.Connection) void { + conn.disconnect(); +} + +fn kickByPlayerIndex(playerIndex: usize) void { + const command = std.fmt.allocPrint(main.globalAllocator.allocator, "kick @{d}", .{playerIndex}) catch unreachable; + main.sync.ClientSide.executeCommand(.{.chatCommand = .{.message = command}}); +} + +pub fn onOpen() void { + const list = VerticalList.init(.{padding, 16 + padding}, 300, 16); + if (main.server.world == null) blk: { + entityCount = main.client.entity_manager.entities.len; + if (entityCount == 0) { + list.add(Label.init(.{0, 0}, 200, "No other players", .left)); + break :blk; + } + + for (main.client.entity_manager.entities.items()) |ent| { + if (ent.playerIndex == null) continue; + const row = HorizontalList.init(); + + const string = std.fmt.allocPrint(main.stackAllocator.allocator, "{f}", .{std.fmt.alt(ent, .formatWithPlayerIndex)}) catch unreachable; + defer main.stackAllocator.free(string); + row.add(Label.init(.{0, 0}, 200, string, .left)); + row.add(Button.initText(.{0, 0}, 100, "Kick", .initWithInt(kickByPlayerIndex, ent.playerIndex.?))); + list.add(row); + } + } else { + main.server.connectionManager.mutex.lock(); + defer main.server.connectionManager.mutex.unlock(); + std.debug.assert(userList.len == 0); + userList = main.globalAllocator.alloc(*main.server.User, main.server.connectionManager.connections.items.len); + for (main.server.connectionManager.connections.items, 0..) |connection, i| { + userList[i] = connection.user.?; + userList[i].increaseRefCount(); + if (userList[i].id == main.game.Player.id and connection.isConnected()) continue; + const row = HorizontalList.init(); + if (connection.handShakeState.load(.monotonic) == .complete) { + const string = std.fmt.allocPrint(main.stackAllocator.allocator, "{f}", .{connection.user.?}) catch unreachable; + defer main.stackAllocator.free(string); + row.add(Label.init(.{0, 0}, 200, string, .left)); + row.add(Button.initText(.{0, 0}, 100, "Kick", .initWithPtr(kickbyConnection, connection))); + } else { + const ip = std.fmt.allocPrint(main.stackAllocator.allocator, "{f}", .{connection.remoteAddress}) catch unreachable; + defer main.stackAllocator.free(ip); + row.add(Label.init(.{0, 0}, 200, ip, .left)); + row.add(Button.initText(.{0, 0}, 100, "Cancel", .initWithPtr(kickbyConnection, connection))); + } + list.add(row); + } + if (userList.len == 1) { + list.add(Label.init(.{0, 0}, 200, "No other players", .left)); + } + } + list.finish(.center); + window.rootComponent = list.toComponent(); + window.contentSize = window.rootComponent.?.pos() + window.rootComponent.?.size() + @as(Vec2f, @splat(padding)); + gui.updateWindowPositions(); +} + +pub fn onClose() void { + if (main.server.world != null) { + for (userList) |user| { + user.decreaseRefCount(); + } + main.globalAllocator.free(userList); + userList = &.{}; + } + if (window.rootComponent) |*comp| { + comp.deinit(); + } +} + +pub fn update() void { + if (main.server.world == null) { + if (main.client.entity_manager.entities.len != entityCount) { + onClose(); + onOpen(); + } + } else { + main.server.connectionManager.mutex.lock(); + const serverListLen = main.server.connectionManager.connections.items.len; + main.server.connectionManager.mutex.unlock(); + if (userList.len != serverListLen) { + onClose(); + onOpen(); + } + } +}