Compare commits

..

No commits in common. "multiplayer" and "dev" have entirely different histories.

5 changed files with 250 additions and 344 deletions

View File

@ -1,6 +1,5 @@
allocator: std.mem.Allocator,
discovered: *Discovered,
hovered: usize,
pub const Discovered = struct {
allocator: std.mem.Allocator,
@ -15,7 +14,6 @@ pub fn create(allocator: std.mem.Allocator, discovered: *Discovered) !*@This() {
this.* = .{
.allocator = allocator,
.discovered = discovered,
.hovered = 0,
};
return this;
}
@ -52,45 +50,17 @@ pub fn element_render(pointer: ?*anyopaque, canvas: *seizer.Canvas, render_resou
this.discovered.mutex.lock();
defer this.discovered.mutex.unlock();
for (this.discovered.servers.keys(), 0..) |url, i| {
for (this.discovered.servers.keys()) |url| {
const text_size = canvas.writeText(pos, url, .{});
if (i == this.hovered) {
canvas.rect(pos, text_size, .{ .color = .{ 0xAA, 0xFF, 0xAA, 0x60 } });
}
pos[1] += text_size[1];
}
}
pub fn element_event(pointer: ?*anyopaque, event: Element.Event) ?Element.Command {
const this: *@This() = @ptrCast(@alignCast(pointer));
this.discovered.mutex.lock();
defer this.discovered.mutex.unlock();
std.log.debug("server list event = {}", .{event});
const new_hovered: usize = switch (event) {
.activate => if (this.hovered < this.discovered.servers.count()) {
var iter = std.mem.splitScalar(u8, this.discovered.servers.keys()[this.hovered], ':');
const domain_name = iter.next().?;
const port_str = iter.next().?;
std.debug.assert(std.mem.eql(u8, iter.rest(), ""));
const port = std.fmt.parseInt(u16, port_str, 10) catch return null;
const ip_addresses = std.net.getAddressList(this.allocator, domain_name, port) catch return null;
defer ip_addresses.deinit();
if (ip_addresses.addrs.len <= 0) return null;
return Element.Command{ .goto_reference = .{ .server = ip_addresses.addrs[0] } };
} else {
_ = this;
_ = event;
return null;
},
.down => if (this.hovered < this.discovered.servers.count() - 1) this.hovered + 1 else return null,
.up => if (this.hovered > 0) this.hovered - 1 else return null,
else => return null,
};
this.hovered = new_hovered;
return Element.Command.none;
}
const Element = @import("../Element.zig");

View File

@ -1,65 +1,27 @@
allocator: std.mem.Allocator,
reference: protocol.Reference,
state_info: ReferenceStateInfo,
handler_pointer: ?*anyopaque,
response: ?protocol.Response,
const ReferenceStateInfo = union(protocol.Reference.Tag) {
handler: struct {
pointer: ?*anyopaque,
},
server: struct {
client: *c.ENetHost,
peer: *c.ENetPeer,
},
};
const View = @This();
pub fn create(allocator: std.mem.Allocator, reference: protocol.Reference) !*@This() {
const this = try allocator.create(@This());
errdefer allocator.destroy(this);
const state_info = switch (reference) {
.handler => |interface| ReferenceStateInfo{
.handler = .{
.pointer = if (interface.create) |handler_create|
try handler_create(allocator)
else
null,
var handler_pointer: ?*anyopaque = null;
switch (reference) {
.handler => |interface| if (interface.create) |handler_create| {
handler_pointer = try handler_create(allocator);
},
},
.server => |address| create_enet_host: {
const client = c.enet_host_create(null, 1, 2, 0, 0);
if (client == null) {
std.log.warn("Failed to create ENetClient host", .{});
return error.OutOfMemory;
}
var enet_address: c.ENetAddress = .{
.host = address.in.sa.addr,
.port = address.in.getPort(),
};
const peer = c.enet_host_connect(client, &enet_address, 2, 0);
if (peer == null) {
std.log.warn("Failed to create ENetClient host", .{});
return error.OutOfMemory;
}
break :create_enet_host ReferenceStateInfo{
.server = .{
.client = client,
.peer = peer,
},
};
},
};
this.* = .{
.allocator = allocator,
.reference = reference,
.response = null,
.state_info = state_info,
.handler_pointer = handler_pointer,
};
return this;
}
@ -71,46 +33,17 @@ pub fn setReference(this: *@This(), reference: protocol.Reference) void {
}
switch (this.reference) {
.handler => |interface| if (interface.deinit) |deinit| deinit(this.state_info.handler.pointer),
// TODO
.server => {},
.handler => |interface| if (interface.deinit) |deinit| deinit(this.handler_pointer),
}
this.handler_pointer = null;
this.reference = reference;
this.state_info = switch (reference) {
.handler => |interface| ReferenceStateInfo{
.handler = .{
.pointer = if (interface.create) |handler_create|
handler_create(this.allocator) catch unreachable
else
null,
switch (this.reference) {
.handler => |interface| if (interface.create) |handler_create| {
this.handler_pointer = handler_create(this.allocator) catch unreachable;
},
},
.server => |address| create_enet_host: {
std.log.info("Connecting to {}", .{address});
const client = c.enet_host_create(null, 1, 2, 0, 0);
if (client == null) {
std.debug.panic("Failed to create ENetClient host", .{});
}
var enet_address: c.ENetAddress = .{
.host = address.in.sa.addr,
.port = address.in.getPort(),
};
const peer = c.enet_host_connect(client, &enet_address, 2, 0);
if (peer == null) {
std.debug.panic("Failed to connect to ENet peer", .{});
}
break :create_enet_host ReferenceStateInfo{
.server = .{
.client = client,
.peer = peer,
},
};
},
};
}
pub fn element(this: *@This()) Element {
@ -137,9 +70,7 @@ pub fn element_destroy(pointer: ?*anyopaque) void {
}
switch (this.reference) {
.handler => |interface| if (interface.deinit) |deinit| deinit(this.state_info.handler.pointer),
// TODO
.server => {},
.handler => |interface| if (interface.deinit) |deinit| deinit(this.handler_pointer),
}
this.allocator.destroy(this);
@ -160,29 +91,12 @@ pub fn element_render(pointer: ?*anyopaque, canvas: *seizer.Canvas, render_resou
const this: *@This() = @ptrCast(@alignCast(pointer));
if (this.response == null) {
switch (this.reference) {
.handler => |handler| {
const handler_pointer = this.state_info.handler.pointer;
this.response = handler.handle(handler_pointer, .{
this.response = this.reference.handler.handle(this.handler_pointer, .{
.allocator = this.allocator,
}) catch response_error: {
std.log.warn("Could not get response", .{});
break :response_error null;
};
},
.server => |address| {
const server = this.state_info.server;
var event: c.ENetEvent = undefined;
while (c.enet_host_service(server.client, &event, 0) > 0) {
switch (event.type) {
c.ENET_EVENT_TYPE_CONNECT => {
std.log.info("Connection to {} succeeded", .{address});
},
else => {},
}
}
},
}
}
if (this.response) |response| {
@ -214,7 +128,6 @@ pub fn element_event(pointer: ?*anyopaque, event: Element.Event) ?Element.Comman
const Element = @import("../Element.zig");
const protocol = @import("../protocol.zig");
const assets = @import("../assets.zig");
const c = @import("../c.zig");
const seizer = @import("seizer");
const gl = seizer.gl;

View File

@ -75,7 +75,7 @@ const JoinMultiplayerGame = struct {
var text = try Element.Text.create(arena.allocator(), try std.fmt.allocPrint(arena.allocator(), "Looking for multiplayer games", .{}));
var server_list = try Element.ServerList.create(this.allocator, this.discovered);
var server_list = try Element.ServerList.create(arena.allocator(), this.discovered);
var page = try Element.Page.create(request.allocator);
try page.addElement(.{ 0.5, 0.5 }, .{ 0.5, 0.5 }, text.element());
@ -230,7 +230,11 @@ const JoinMultiplayerGame = struct {
const HostMultiplayerGame = struct {
allocator: std.mem.Allocator,
mdns_sockets: []std.os.socket_t,
mdns_addr4_string: []u8,
mdns_addr6_string: []u8,
mdns_socket4: std.os.socket_t,
mdns_socket6: std.os.socket_t,
service_string: []const u8,
service_instance_string: []const u8,
@ -241,8 +245,6 @@ const HostMultiplayerGame = struct {
address: c.ENetAddress,
server: *c.ENetHost,
enet_thread: std.Thread,
enet_thread_should_stop: std.atomic.Value(bool),
pub const INTERFACE = &Handler.Interface{
.create = &create,
@ -268,149 +270,127 @@ const HostMultiplayerGame = struct {
// setup mDNS discovery service
const addresses = @import("./multiplayer.zig").getIPAddresses(allocator) catch return error.OutOfMemory;
defer this.allocator.free(addresses);
const mdns_socket = std.os.socket(std.os.AF.INET, std.os.SOCK.DGRAM, std.os.IPPROTO.UDP) catch |e| {
std.log.scoped(.mdns).err("failed to open mdns socket = {}", .{e});
return error.OutOfMemory;
};
var mdns_sockets = std.ArrayList(std.os.socket_t).init(allocator);
defer mdns_sockets.deinit();
std.os.setsockopt(
mdns_socket,
std.os.SOL.SOCKET,
std.os.SO.REUSEADDR,
&std.mem.toBytes(@as(c_int, 1)),
) catch unreachable;
std.os.setsockopt(
mdns_socket,
std.os.SOL.SOCKET,
std.os.SO.REUSEPORT,
&std.mem.toBytes(@as(c_int, 1)),
) catch unreachable;
std.os.setsockopt(
mdns_socket,
std.os.IPPROTO.IP,
std.os.linux.IP.MULTICAST_TTL,
&std.mem.toBytes(@as(c_int, 1)),
) catch unreachable;
std.os.setsockopt(
mdns_socket,
std.os.IPPROTO.IP,
std.os.linux.IP.MULTICAST_LOOP,
&std.mem.toBytes(@as(c_int, 1)),
) catch unreachable;
try mdns_sockets.ensureTotalCapacity(addresses.len);
for (addresses) |ip_address| {
switch (ip_address) {
.ipv4 => |ip| {
const std_address = std.net.Ip4Address.init(ip, c.MDNS_PORT);
const socket = c.mdns_socket_open_ipv4(@ptrCast(&std_address.sa));
mdns_sockets.appendAssumeCapacity(socket);
},
.ipv6 => |ip| {
const std_address = std.net.Ip6Address.init(ip, c.MDNS_PORT, 0, 0);
const socket = c.mdns_socket_open_ipv6(@ptrCast(&std_address.sa));
mdns_sockets.appendAssumeCapacity(socket);
},
}
}
const ip_mreq_t = extern struct {
multicast_address: [4]u8,
address: [4]u8,
};
std.os.setsockopt(
mdns_socket,
std.os.IPPROTO.IP,
std.os.linux.IP.ADD_MEMBERSHIP,
&std.mem.toBytes(ip_mreq_t{
.multicast_address = .{ 224, 0, 0, 251 },
.address = .{ 0, 0, 0, 0 },
}),
) catch unreachable;
// const mdns_socket = std.os.socket(std.os.AF.INET, std.os.SOCK.DGRAM, std.os.IPPROTO.UDP) catch |e| {
// std.log.scoped(.mdns).err("failed to open mdns socket = {}", .{e});
// return error.OutOfMemory;
// };
const mdns_sock_addr = std.net.Address.parseIp4("0.0.0.0", c.MDNS_PORT) catch unreachable;
std.os.bind(mdns_socket, @ptrCast(&mdns_sock_addr), mdns_sock_addr.getOsSockLen()) catch |e| {
std.log.scoped(.mdns).err("bind failed = {}", .{e});
return error.OutOfMemory;
};
// std.os.setsockopt(
// mdns_socket,
// std.os.SOL.SOCKET,
// std.os.SO.REUSEADDR,
// &std.mem.toBytes(@as(c_int, 1)),
// ) catch unreachable;
// std.os.setsockopt(
// mdns_socket,
// std.os.SOL.SOCKET,
// std.os.SO.REUSEPORT,
// &std.mem.toBytes(@as(c_int, 1)),
// ) catch unreachable;
// std.os.setsockopt(
// mdns_socket,
// std.os.IPPROTO.IP,
// std.os.linux.IP.MULTICAST_TTL,
// &std.mem.toBytes(@as(c_int, 1)),
// ) catch unreachable;
// std.os.setsockopt(
// mdns_socket,
// std.os.IPPROTO.IP,
// std.os.linux.IP.MULTICAST_LOOP,
// &std.mem.toBytes(@as(c_int, 1)),
// ) catch unreachable;
std.os.setsockopt(
mdns_socket,
std.os.IPPROTO.IP,
std.os.linux.IP.MULTICAST_IF,
&std.mem.toBytes(mdns_sock_addr.any),
) catch unreachable;
// const ip_mreq_t = extern struct {
// multicast_address: [4]u8,
// address: [4]u8,
// };
// std.os.setsockopt(
// mdns_socket,
// std.os.IPPROTO.IP,
// std.os.linux.IP.ADD_MEMBERSHIP,
// &std.mem.toBytes(ip_mreq_t{
// .multicast_address = .{ 224, 0, 0, 251 },
// .address = .{ 0, 0, 0, 0 },
// }),
// ) catch unreachable;
// ipv6 socket
const mdns_socket6 = std.os.socket(std.os.AF.INET6, std.os.SOCK.DGRAM, std.os.IPPROTO.UDP) catch |e| {
std.log.scoped(.mdns).err("failed to open mdns socket = {}", .{e});
return error.OutOfMemory;
};
// const mdns_sock_addr = std.net.Address.parseIp4("0.0.0.0", c.MDNS_PORT) catch unreachable;
// std.os.bind(mdns_socket, @ptrCast(&mdns_sock_addr), mdns_sock_addr.getOsSockLen()) catch |e| {
// std.log.scoped(.mdns).err("bind failed = {}", .{e});
// return error.OutOfMemory;
// };
std.os.setsockopt(
mdns_socket6,
std.os.SOL.SOCKET,
std.os.SO.REUSEADDR,
&std.mem.toBytes(@as(c_int, 1)),
) catch unreachable;
std.os.setsockopt(
mdns_socket6,
std.os.SOL.SOCKET,
std.os.SO.REUSEPORT,
&std.mem.toBytes(@as(c_int, 1)),
) catch unreachable;
std.os.setsockopt(
mdns_socket6,
std.os.IPPROTO.IPV6,
std.os.linux.IPV6.MULTICAST_HOPS,
&std.mem.toBytes(@as(c_int, 1)),
) catch unreachable;
std.os.setsockopt(
mdns_socket6,
std.os.IPPROTO.IPV6,
std.os.linux.IPV6.MULTICAST_LOOP,
&std.mem.toBytes(@as(c_int, 1)),
) catch unreachable;
std.os.setsockopt(
mdns_socket6,
std.os.IPPROTO.IPV6,
std.os.linux.IPV6.MULTICAST_IF,
&std.mem.toBytes(@as(c_int, 0)),
) catch unreachable;
// std.os.setsockopt(
// mdns_socket,
// std.os.IPPROTO.IP,
// std.os.linux.IP.MULTICAST_IF,
// &std.mem.toBytes(mdns_sock_addr.any),
// ) catch unreachable;
const ipv6_mreq_t = extern struct {
addr: [16]u8,
interface: c_int,
};
// // ipv6 socket
// const mdns_socket6 = std.os.socket(std.os.AF.INET6, std.os.SOCK.DGRAM, std.os.IPPROTO.UDP) catch |e| {
// std.log.scoped(.mdns).err("failed to open mdns socket = {}", .{e});
// return error.OutOfMemory;
// };
std.os.setsockopt(
mdns_socket6,
std.os.IPPROTO.IPV6,
std.os.linux.IPV6.ADD_MEMBERSHIP,
&std.mem.toBytes(ipv6_mreq_t{
.addr = .{ 0xFF, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB },
.interface = 0,
}),
) catch unreachable;
// std.os.setsockopt(
// mdns_socket6,
// std.os.SOL.SOCKET,
// std.os.SO.REUSEADDR,
// &std.mem.toBytes(@as(c_int, 1)),
// ) catch unreachable;
// std.os.setsockopt(
// mdns_socket6,
// std.os.SOL.SOCKET,
// std.os.SO.REUSEPORT,
// &std.mem.toBytes(@as(c_int, 1)),
// ) catch unreachable;
// std.os.setsockopt(
// mdns_socket6,
// std.os.IPPROTO.IPV6,
// std.os.linux.IPV6.MULTICAST_HOPS,
// &std.mem.toBytes(@as(c_int, 1)),
// ) catch unreachable;
// std.os.setsockopt(
// mdns_socket6,
// std.os.IPPROTO.IPV6,
// std.os.linux.IPV6.MULTICAST_LOOP,
// &std.mem.toBytes(@as(c_int, 1)),
// ) catch unreachable;
// std.os.setsockopt(
// mdns_socket6,
// std.os.IPPROTO.IPV6,
// std.os.linux.IPV6.MULTICAST_IF,
// &std.mem.toBytes(@as(c_int, 0)),
// ) catch unreachable;
const mdns_sock_addr6 = std.net.Address.parseIp6("::", c.MDNS_PORT) catch unreachable;
var socklen = mdns_sock_addr6.getOsSockLen();
std.os.bind(mdns_socket6, &mdns_sock_addr6.any, socklen) catch unreachable;
// const ipv6_mreq_t = extern struct {
// addr: [16]u8,
// interface: c_int,
// };
var mdns_listen_addr: std.net.Address = undefined;
std.os.getsockname(mdns_socket, &mdns_listen_addr.any, &socklen) catch unreachable;
const ipv4_sockaddr_string = try std.fmt.allocPrint(allocator, "{}", .{mdns_listen_addr});
// std.os.setsockopt(
// mdns_socket6,
// std.os.IPPROTO.IPV6,
// std.os.linux.IPV6.ADD_MEMBERSHIP,
// &std.mem.toBytes(ipv6_mreq_t{
// .addr = .{ 0xFF, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFB },
// .interface = 0,
// }),
// ) catch unreachable;
// const mdns_sock_addr6 = std.net.Address.parseIp6("::", c.MDNS_PORT) catch unreachable;
// var socklen = mdns_sock_addr6.getOsSockLen();
// std.os.bind(mdns_socket6, &mdns_sock_addr6.any, socklen) catch unreachable;
// var mdns_listen_addr: std.net.Address = undefined;
// std.os.getsockname(mdns_socket, &mdns_listen_addr.any, &socklen) catch unreachable;
// const ipv4_sockaddr_string = try std.fmt.allocPrint(allocator, "{}", .{mdns_listen_addr});
// socklen = mdns_sock_addr6.getOsSockLen();
// var mdns_listen_addr6: std.net.Address = undefined;
// std.os.getsockname(mdns_socket6, &mdns_listen_addr6.any, &socklen) catch unreachable;
// const ipv6_sockaddr_string = try std.fmt.allocPrint(allocator, "{}", .{mdns_listen_addr6});
socklen = mdns_sock_addr6.getOsSockLen();
var mdns_listen_addr6: std.net.Address = undefined;
std.os.getsockname(mdns_socket6, &mdns_listen_addr6.any, &socklen) catch unreachable;
const ipv6_sockaddr_string = try std.fmt.allocPrint(allocator, "{}", .{mdns_listen_addr6});
const service_string = try allocator.dupe(u8, SERVICE_NAME);
@ -456,7 +436,10 @@ const HostMultiplayerGame = struct {
.ttl = 0,
});
// turn the list of IP addresses into A and AAAA DNS records
// get a list of addresses to populate A and AAAA DNS records
const addresses = @import("./multiplayer.zig").getIPAddresses(allocator) catch return error.OutOfMemory;
defer this.allocator.free(addresses);
for (addresses) |ip_address| {
switch (ip_address) {
.ipv4 => |ipv4| {
@ -489,7 +472,10 @@ const HostMultiplayerGame = struct {
this.* = .{
.allocator = allocator,
.mdns_sockets = try mdns_sockets.toOwnedSlice(),
.mdns_addr4_string = ipv4_sockaddr_string,
.mdns_addr6_string = ipv6_sockaddr_string,
.mdns_socket4 = mdns_socket,
.mdns_socket6 = mdns_socket6,
.service_string = service_string,
.service_instance_string = service_instance_string,
.qualified_hostname = qualified_hostname,
@ -499,12 +485,9 @@ const HostMultiplayerGame = struct {
.address = address,
.server = server,
.enet_thread = undefined,
.enet_thread_should_stop = std.atomic.Value(bool).init(false),
};
this.mdns_thread = std.Thread.spawn(.{}, mdns_thread_main, .{this}) catch return error.OutOfMemory;
this.enet_thread = std.Thread.spawn(.{}, enet_thread_main, .{this}) catch return error.OutOfMemory;
return this;
}
@ -516,15 +499,15 @@ const HostMultiplayerGame = struct {
errdefer arena.deinit();
// var text = try Element.Text.create(arena.allocator(), try std.fmt.allocPrint(arena.allocator(), "Hosting Multiplayer Game at {}:{}", .{ this.address.host, this.address.port }));
// var mdns_addr4_string_text = try Element.Text.create(request.allocator, this.mdns_addr4_string);
// var mdns_addr6_string_text = try Element.Text.create(request.allocator, this.mdns_addr6_string);
var mdns_addr4_string_text = try Element.Text.create(request.allocator, this.mdns_addr4_string);
var mdns_addr6_string_text = try Element.Text.create(request.allocator, this.mdns_addr6_string);
var service_instance_string_text = try Element.Text.create(request.allocator, this.service_instance_string);
var qualified_hostname_text = try Element.Text.create(request.allocator, this.qualified_hostname);
var page = try Element.Page.create(request.allocator);
// try page.addElement(.{ 0.5, 0.5 }, .{ 0.5, 0.5 }, text.element());
// try page.addElement(.{ 0.3, 0.6 }, .{ 0.5, 0.5 }, mdns_addr4_string_text.element());
// try page.addElement(.{ 0.7, 0.6 }, .{ 0.5, 0.5 }, mdns_addr6_string_text.element());
try page.addElement(.{ 0.3, 0.6 }, .{ 0.5, 0.5 }, mdns_addr4_string_text.element());
try page.addElement(.{ 0.7, 0.6 }, .{ 0.5, 0.5 }, mdns_addr6_string_text.element());
try page.addElement(.{ 0.5, 0.7 }, .{ 0.5, 0.5 }, service_instance_string_text.element());
try page.addElement(.{ 0.5, 0.9 }, .{ 0.5, 0.5 }, qualified_hostname_text.element());
@ -540,9 +523,8 @@ const HostMultiplayerGame = struct {
this.mdns_thread.join();
this.allocator.free(this.mdns_records);
this.allocator.free(this.mdns_sockets);
// this.allocator.free(this.mdns_addr4_string);
// this.allocator.free(this.mdns_addr6_string);
this.allocator.free(this.mdns_addr4_string);
this.allocator.free(this.mdns_addr6_string);
this.allocator.free(this.service_string);
this.allocator.free(this.service_instance_string);
this.allocator.free(this.qualified_hostname);
@ -565,9 +547,18 @@ const HostMultiplayerGame = struct {
const log = std.log.scoped(.mdns);
log.info("mdns service started", .{});
for (this.mdns_sockets) |socket| {
_ = c.mdns_announce_multicast(
socket,
this.mdns_socket4,
buffer.ptr,
buffer.len,
this.mdns_records[0],
null,
0,
this.mdns_records[1..].ptr,
this.mdns_records[1..].len,
);
_ = c.mdns_announce_multicast(
this.mdns_socket6,
buffer.ptr,
buffer.len,
this.mdns_records[0],
@ -576,21 +567,15 @@ const HostMultiplayerGame = struct {
this.mdns_records[1..].ptr,
this.mdns_records[1..].len,
);
}
const pollfds = try this.allocator.alloc(std.os.pollfd, this.mdns_sockets.len);
defer this.allocator.free(pollfds);
for (pollfds, this.mdns_sockets) |*pollfd, socket| {
pollfd.* = .{ .fd = socket, .events = std.os.POLL.IN, .revents = undefined };
}
while (!this.mdns_thread_should_stop.load(.Monotonic)) {
for (pollfds) |*pollfd| {
pollfd.events = std.os.POLL.IN;
}
_ = std.os.poll(pollfds, 1000) catch break;
var pollfds = [_]std.os.pollfd{
.{ .fd = this.mdns_socket4, .events = std.os.POLL.IN, .revents = undefined },
.{ .fd = this.mdns_socket6, .events = std.os.POLL.IN, .revents = undefined },
};
_ = std.os.poll(&pollfds, 1000) catch break;
// listen for mdns messages
for (pollfds) |pollfd| {
for (pollfds[0..2]) |pollfd| {
if (pollfd.revents & std.os.POLL.IN == 0) continue;
_ = c.mdns_socket_listen(pollfd.fd, buffer.ptr, buffer.len, &mdns_thread_service_callback, this);
}
@ -599,31 +584,6 @@ const HostMultiplayerGame = struct {
log.info("mdns service stopping", .{});
}
fn enet_thread_main(this: *@This()) !void {
const log = std.log.scoped(.enet);
log.info("thread started", .{});
while (!this.mdns_thread_should_stop.load(.Monotonic)) {
var event: c.ENetEvent = undefined;
while (c.enet_host_service(this.server, &event, 1000) > 0) {
switch (event.type) {
c.ENET_EVENT_TYPE_CONNECT => {
std.log.info("New connection from {}:{}", .{ event.peer.*.address.host, event.peer.*.address.port });
},
c.ENET_EVENT_TYPE_RECEIVE => {
c.enet_packet_destroy(event.packet);
},
c.ENET_EVENT_TYPE_DISCONNECT => {
std.log.info("{}:{} disconnected", .{ event.peer.*.address.host, event.peer.*.address.port });
},
else => {},
}
}
}
log.info("thread stopped", .{});
}
fn mdns_thread_service_callback(
sock: c_int,
from: ?*const c.sockaddr,

View File

@ -586,6 +586,75 @@ fn endOfTurnConfirmHandler(arena: std.mem.Allocator, request: Request) Handler.E
return Response{ .page = page.element() };
}
fn mainMenuHandler(arena: std.mem.Allocator, request: Request) Handler.Error!Response {
if (request.command) |command| {
if (std.mem.eql(u8, command, "join-multiplayer-game")) {
var new_game_state = try request.game_state.clone(arena);
new_game_state.handler = &joinMultiplayerGameHandler;
return Response{ .transition = .{
.game_state = new_game_state,
.history_type = .start,
} };
} else if (std.mem.eql(u8, command, "host-multiplayer-game")) {
var new_game_state = try request.game_state.clone(arena);
new_game_state.handler = &hostMultiplayerGameHandler;
return Response{ .transition = .{
.game_state = new_game_state,
.history_type = .start,
} };
}
}
var join_multiplayer_text = try Element.Textcreate(arena, .{
.text = "Join Multiplayer Game",
.command = "join-multiplayer-game",
});
var host_multiplayer_text = try Element.Text.create(arena, .{
.text = "Host Multiplayer Game",
.command = "host-multiplayer-game",
});
var play_game_hbox = try Element.HBox.create(arena);
try play_game_hbox.addElement(join_multiplayer_text.element());
try play_game_hbox.addElement(host_multiplayer_text.element());
var page = try Element.Page.create(arena);
try page.addElement(.{ 0.5, 0.5 }, .{ 0.5, 0.5 }, play_game_hbox.element());
return Response{ .page = page.element() };
}
fn hostMultiplayerGameHandler(arena: std.mem.Allocator, request: Request) Handler.Error!Response {
_ = request;
var text = try Element.Text.create(arena, .{
.text = "Hosting Multiplayer Game",
.command = null,
});
var page = try Element.Page.create(arena);
try page.addElement(.{ 0.5, 0.5 }, .{ 0.5, 0.5 }, text.element());
return Response{ .page = page.element() };
}
fn joinMultiplayerGameHandler(arena: std.mem.Allocator, request: Request) Handler.Error!Response {
_ = request;
var text = try Element.Text.create(arena, .{
.text = "Joining Multiplayer Game",
.command = null,
});
var page = try Element.Page.create(arena);
try page.addElement(.{ 0.5, 0.5 }, .{ 0.5, 0.5 }, text.element());
return Response{ .page = page.element() };
}
fn isValidRummyMeld(cards: []const Card) bool {
std.debug.assert(std.sort.isSorted(Card, cards, {}, rummyHandSort));
if (cards.len < 3) {

View File

@ -11,14 +11,8 @@ pub const Handler = struct {
};
};
pub const Reference = union(Tag) {
pub const Reference = union(enum) {
handler: *const Handler.Interface,
server: std.net.Address,
pub const Tag = enum {
handler,
server,
};
};
pub const Request = struct {