Add an option to allow people to join without being invited (requires a public IP address).

Due to the non-obvious technical requirements, I decided to hide it a bit.

fixes #618
This commit is contained in:
IntegratedQuantum 2025-02-16 16:23:39 +01:00
parent 8aa0e9101b
commit ca0a37cabb
2 changed files with 36 additions and 13 deletions

View File

@ -9,6 +9,7 @@ const gui = @import("../gui.zig");
const GuiComponent = gui.GuiComponent;
const GuiWindow = gui.GuiWindow;
const Button = @import("../components/Button.zig");
const CheckBox = @import("../components/CheckBox.zig");
const Label = @import("../components/Label.zig");
const TextInput = @import("../components/TextInput.zig");
const VerticalList = @import("../components/VerticalList.zig");
@ -59,8 +60,22 @@ fn copyIp(_: usize) void {
main.Window.setClipboardString(ipAddress);
}
fn inviteFromExternal(address: main.network.Address) void {
const ip = std.fmt.allocPrint(main.stackAllocator.allocator, "{}", .{address}) catch unreachable;
defer main.stackAllocator.free(ip);
const user = main.server.User.initAndIncreaseRefCount(main.server.connectionManager, ip) catch |err| {
std.log.err("Cannot connect user from external IP {}: {s}", .{address, @errorName(err)});
return;
};
user.decreaseRefCount();
}
fn makePublic(public: bool) void {
main.server.connectionManager.newConnectionCallback.store(if(public) &inviteFromExternal else null, .monotonic);
}
pub fn onOpen() void {
const list = VerticalList.init(.{padding, 16 + padding}, 300, 16);
const list = VerticalList.init(.{padding, 16 + padding}, 260, 16);
list.add(Label.init(.{0, 0}, width, "Please send your IP to the player who wants to join and enter their IP below.", .center));
// 255.255.255.255:?65536 (longest possible ip address)
ipAddressLabel = Label.init(.{0, 0}, width, " ", .center);
@ -70,6 +85,7 @@ pub fn onOpen() void {
list.add(ipAddressEntry);
list.add(Button.initText(.{0, 0}, 100, "Invite", .{.callback = &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.newConnectionCallback.load(.monotonic) != null, &makePublic));
list.finish(.center);
window.rootComponent = list.toComponent();
window.contentSize = window.rootComponent.?.pos() + window.rootComponent.?.size() + @as(Vec2f, @splat(padding));

View File

@ -126,7 +126,7 @@ pub fn init() void {
}
}
const Address = struct {
pub const Address = struct {
ip: u32,
port: u16,
isSymmetricNAT: bool = false,
@ -368,6 +368,7 @@ pub const ConnectionManager = struct { // MARK: ConnectionManager
mutex: std.Thread.Mutex = .{},
waitingToFinishReceive: std.Thread.Condition = std.Thread.Condition{},
newConnectionCallback: Atomic(?*const fn(Address) void) = .init(null),
receiveBuffer: [Connection.maxPacketSize]u8 = undefined,
@ -533,19 +534,25 @@ pub const ConnectionManager = struct { // MARK: ConnectionManager
}
}
}
defer self.mutex.unlock();
// Check if it's part of an active request:
for(self.requests.items) |request| {
if(request.address.ip == source.ip and request.address.port == source.port) {
request.data = main.globalAllocator.dupe(u8, data);
request.requestNotifier.signal();
return;
{
defer self.mutex.unlock();
// Check if it's part of an active request:
for(self.requests.items) |request| {
if(request.address.ip == source.ip and request.address.port == source.port) {
request.data = main.globalAllocator.dupe(u8, data);
request.requestNotifier.signal();
return;
}
}
if(self.online.load(.acquire) and source.ip == self.externalAddress.ip and source.port == self.externalAddress.port) return;
}
if(self.newConnectionCallback.load(.monotonic)) |callback| {
callback(source);
} else {
// TODO: Reduce the number of false alarms in the short period after a disconnect.
std.log.warn("Unknown connection from address: {}", .{source});
std.log.debug("Message: {any}", .{data});
}
if(self.online.load(.acquire) and source.ip == self.externalAddress.ip and source.port == self.externalAddress.port) return;
// TODO: Reduce the number of false alarms in the short period after a disconnect.
std.log.warn("Unknown connection from address: {}", .{source});
std.log.debug("Message: {any}", .{data});
}
pub fn run(self: *ConnectionManager) void {