mt-lang 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/docs/index.html +4 -3
- data/lib/milk_tea/base.rb +1 -1
- data/std/asset_pack.mt +267 -0
- data/std/async/libuv_runtime.mt +539 -0
- data/std/async/mailbox.mt +191 -0
- data/std/async/runtime.mt +87 -0
- data/std/async.mt +87 -0
- data/std/base64.mt +185 -0
- data/std/behavior_tree.mt +396 -0
- data/std/binary.mt +314 -0
- data/std/binary_heap.mt +157 -0
- data/std/bitset.mt +239 -0
- data/std/box2d.mt +535 -0
- data/std/bytes.mt +46 -0
- data/std/c/box2d.mt +1254 -0
- data/std/c/cgltf.mt +647 -0
- data/std/c/cjson.mt +106 -0
- data/std/c/crypto.mt +11 -0
- data/std/c/crypto_support.h +51 -0
- data/std/c/ctype.mt +19 -0
- data/std/c/ctype_bindgen.h +29 -0
- data/std/c/curl.mt +1223 -0
- data/std/c/enet.mt +473 -0
- data/std/c/errno.mt +41 -0
- data/std/c/errno_bindgen.h +53 -0
- data/std/c/flecs.mt +2945 -0
- data/std/c/fs.linux.mt +43 -0
- data/std/c/fs.windows.mt +43 -0
- data/std/c/fs_support.h +954 -0
- data/std/c/gl.mt +2065 -0
- data/std/c/gl_registry_helpers.h +10748 -0
- data/std/c/glfw.mt +499 -0
- data/std/c/libc.mt +167 -0
- data/std/c/libuv.mt +1491 -0
- data/std/c/math.mt +22 -0
- data/std/c/math_bindgen.h +31 -0
- data/std/c/miniaudio.mt +3420 -0
- data/std/c/pcre2.mt +735 -0
- data/std/c/process.mt +58 -0
- data/std/c/process_support.h +1147 -0
- data/std/c/raygui.mt +1602 -0
- data/std/c/raylib.mt +1245 -0
- data/std/c/raymath.mt +163 -0
- data/std/c/rlgl.mt +434 -0
- data/std/c/rpng.mt +60 -0
- data/std/c/rres.mt +187 -0
- data/std/c/sdl3.mt +4132 -0
- data/std/c/sqlite3.mt +951 -0
- data/std/c/stb_image.mt +52 -0
- data/std/c/stb_image_resize2.mt +128 -0
- data/std/c/stb_image_write.mt +19 -0
- data/std/c/stb_rect_pack.mt +38 -0
- data/std/c/stb_truetype.mt +175 -0
- data/std/c/stb_vorbis.mt +31 -0
- data/std/c/stdio.mt +90 -0
- data/std/c/steamworks.h +5769 -0
- data/std/c/steamworks.mt +4771 -0
- data/std/c/string.mt +16 -0
- data/std/c/string_bindgen.h +36 -0
- data/std/c/sync.mt +33 -0
- data/std/c/sync_support.h +219 -0
- data/std/c/terminal.mt +24 -0
- data/std/c/terminal_support.h +408 -0
- data/std/c/time.mt +26 -0
- data/std/c/tls.mt +24 -0
- data/std/c/tls_support.h +626 -0
- data/std/c/tracy.mt +53 -0
- data/std/c/zlib.mt +20 -0
- data/std/c/zlib_support.h +239 -0
- data/std/c/zstd.mt +231 -0
- data/std/cell.mt +60 -0
- data/std/cgltf.mt +115 -0
- data/std/cjson.mt +90 -0
- data/std/cli.mt +768 -0
- data/std/cookie.mt +198 -0
- data/std/counter.mt +160 -0
- data/std/crypto.mt +74 -0
- data/std/cstring.mt +13 -0
- data/std/ctype.mt +52 -0
- data/std/curl/runtime.mt +261 -0
- data/std/curl.mt +38 -0
- data/std/deque.mt +348 -0
- data/std/encoding.mt +93 -0
- data/std/enet.mt +133 -0
- data/std/env.mt +41 -0
- data/std/errno.mt +47 -0
- data/std/flecs.mt +978 -0
- data/std/fmt.mt +271 -0
- data/std/fs.linux.mt +696 -0
- data/std/fs.windows.mt +711 -0
- data/std/fsm.mt +267 -0
- data/std/gl.mt +2062 -0
- data/std/glfw.mt +471 -0
- data/std/goap.mt +342 -0
- data/std/graph.mt +521 -0
- data/std/gzip.mt +77 -0
- data/std/hash.mt +429 -0
- data/std/http/server.mt +810 -0
- data/std/http.mt +1227 -0
- data/std/intern.mt +53 -0
- data/std/jobs.mt +288 -0
- data/std/json.mt +627 -0
- data/std/libc.mt +34 -0
- data/std/libuv.mt +554 -0
- data/std/linear_algebra.mt +243 -0
- data/std/linked_map.mt +372 -0
- data/std/linked_map_view.mt +49 -0
- data/std/linked_set.mt +117 -0
- data/std/log.mt +69 -0
- data/std/map.mt +418 -0
- data/std/math.mt +24 -0
- data/std/mem/arena.mt +137 -0
- data/std/mem/endian.mt +51 -0
- data/std/mem/heap.mt +298 -0
- data/std/mem/pool.mt +164 -0
- data/std/mem/stack.mt +47 -0
- data/std/mem/tracking.mt +119 -0
- data/std/miniaudio.mt +1299 -0
- data/std/multiset.mt +191 -0
- data/std/net/channel.mt +727 -0
- data/std/net/clock.mt +237 -0
- data/std/net/discovery.mt +277 -0
- data/std/net/lobby.mt +813 -0
- data/std/net/manager.mt +539 -0
- data/std/net/mux.mt +839 -0
- data/std/net/nat.mt +122 -0
- data/std/net/packet.mt +219 -0
- data/std/net/punch.mt +162 -0
- data/std/net/rpc.mt +119 -0
- data/std/net/session.mt +1157 -0
- data/std/net/stun.mt +252 -0
- data/std/net/sync.mt +183 -0
- data/std/net/turn.mt +459 -0
- data/std/net.mt +2944 -0
- data/std/oauth2.mt +408 -0
- data/std/option.mt +51 -0
- data/std/ordered_map.mt +497 -0
- data/std/ordered_set.mt +348 -0
- data/std/path.mt +368 -0
- data/std/pcre2/runtime.mt +35 -0
- data/std/pcre2.mt +78 -0
- data/std/priority_queue.mt +55 -0
- data/std/process.mt +837 -0
- data/std/queue.mt +55 -0
- data/std/random.mt +146 -0
- data/std/raygui.mt +99 -0
- data/std/raylib/debug_console.mt +71 -0
- data/std/raylib/easing.mt +388 -0
- data/std/raylib/packed_assets.mt +255 -0
- data/std/raylib/runtime.mt +30 -0
- data/std/raylib/tracy_gpu.mt +37 -0
- data/std/raylib.mt +1510 -0
- data/std/raymath.mt +153 -0
- data/std/result.mt +89 -0
- data/std/rlgl.mt +268 -0
- data/std/rpng.mt +46 -0
- data/std/rres.mt +36 -0
- data/std/sdl3/runtime.mt +54 -0
- data/std/sdl3.mt +1731 -0
- data/std/serialize.mt +68 -0
- data/std/set.mt +124 -0
- data/std/spatial.mt +176 -0
- data/std/sqlite3.mt +151 -0
- data/std/stack.mt +55 -0
- data/std/stb_image.mt +47 -0
- data/std/stb_image_resize2.mt +41 -0
- data/std/stb_image_write.mt +17 -0
- data/std/stb_rect_pack.mt +15 -0
- data/std/stb_truetype.mt +77 -0
- data/std/stb_vorbis.mt +16 -0
- data/std/stdio.mt +88 -0
- data/std/steamworks.mt +1542 -0
- data/std/str.mt +293 -0
- data/std/string.mt +234 -0
- data/std/sync.mt +194 -0
- data/std/tar.mt +704 -0
- data/std/terminal.mt +1002 -0
- data/std/testing.mt +266 -0
- data/std/thread.mt +120 -0
- data/std/time.mt +105 -0
- data/std/tls.mt +616 -0
- data/std/toml.mt +1310 -0
- data/std/tracy.mt +42 -0
- data/std/uri.mt +118 -0
- data/std/url.mt +372 -0
- data/std/vec.mt +433 -0
- data/std/zstd.mt +94 -0
- metadata +187 -2
data/std/net/lobby.mt
ADDED
|
@@ -0,0 +1,813 @@
|
|
|
1
|
+
import std.async as aio
|
|
2
|
+
import std.binary as bin
|
|
3
|
+
import std.bytes as bytes
|
|
4
|
+
import std.deque as deque
|
|
5
|
+
import std.net as net
|
|
6
|
+
import std.net.mux as mux
|
|
7
|
+
import std.net.session as sess
|
|
8
|
+
import std.str as text
|
|
9
|
+
import std.string as string
|
|
10
|
+
import std.vec as vec
|
|
11
|
+
|
|
12
|
+
const lobby_channel: ubyte = 0
|
|
13
|
+
const type_join_request: ushort = 0x0001
|
|
14
|
+
const type_join_accept: ushort = 0x0002
|
|
15
|
+
const type_join_reject: ushort = 0x0003
|
|
16
|
+
const type_player_joined: ushort = 0x0004
|
|
17
|
+
const type_player_left: ushort = 0x0005
|
|
18
|
+
const type_lobby_info: ushort = 0x0006
|
|
19
|
+
const type_discover_request: ushort = 0x0007
|
|
20
|
+
const type_discover_response: ushort = 0x0008
|
|
21
|
+
|
|
22
|
+
const reject_reason_full: ubyte = 1
|
|
23
|
+
const reject_reason_banned: ubyte = 2
|
|
24
|
+
const reject_reason_invalid: ubyte = 3
|
|
25
|
+
|
|
26
|
+
public struct LobbyInfo:
|
|
27
|
+
name: string.String
|
|
28
|
+
player_count: ubyte
|
|
29
|
+
max_players: ubyte
|
|
30
|
+
player_names: vec.Vec[string.String]
|
|
31
|
+
game_data: bytes.Bytes
|
|
32
|
+
|
|
33
|
+
public struct LobbyEvent:
|
|
34
|
+
kind: LobbyEventKind
|
|
35
|
+
player_id: uint
|
|
36
|
+
player_name: string.String
|
|
37
|
+
slot: ubyte
|
|
38
|
+
reason: ubyte
|
|
39
|
+
|
|
40
|
+
public enum LobbyEventKind: ubyte
|
|
41
|
+
player_joined = 0
|
|
42
|
+
player_left = 1
|
|
43
|
+
lobby_info_updated = 2
|
|
44
|
+
joined = 3
|
|
45
|
+
join_rejected = 4
|
|
46
|
+
|
|
47
|
+
public struct LobbyHost:
|
|
48
|
+
mux: mux.MuxedSession
|
|
49
|
+
info: LobbyInfo
|
|
50
|
+
slots: vec.Vec[PlayerSlot]
|
|
51
|
+
event_queue: deque.Deque[LobbyEvent]
|
|
52
|
+
|
|
53
|
+
struct PlayerSlot:
|
|
54
|
+
player_id: uint
|
|
55
|
+
player_name: string.String
|
|
56
|
+
occupied: bool
|
|
57
|
+
|
|
58
|
+
public struct LobbyClient:
|
|
59
|
+
mux: mux.MuxedConnection
|
|
60
|
+
assigned_slot: ubyte
|
|
61
|
+
assigned_id: uint
|
|
62
|
+
lobby_info: LobbyInfo
|
|
63
|
+
event_queue: deque.Deque[LobbyEvent]
|
|
64
|
+
pending_join: bool
|
|
65
|
+
pending_name: string.String
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
extending LobbyInfo:
|
|
69
|
+
public editable function release() -> void:
|
|
70
|
+
this.name.release()
|
|
71
|
+
var i: ptr_uint = 0
|
|
72
|
+
while i < this.player_names.len():
|
|
73
|
+
let p = this.player_names.get(i) else:
|
|
74
|
+
return
|
|
75
|
+
unsafe: read(p).release()
|
|
76
|
+
i += 1
|
|
77
|
+
this.player_names.release()
|
|
78
|
+
this.game_data.release()
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
extending LobbyEvent:
|
|
82
|
+
public editable function release() -> void:
|
|
83
|
+
this.player_name.release()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
extending LobbyHost:
|
|
87
|
+
public editable function release() -> void:
|
|
88
|
+
release_lobby_queue(ref_of(this.event_queue))
|
|
89
|
+
this.event_queue.release()
|
|
90
|
+
release_slots(ref_of(this.slots))
|
|
91
|
+
this.slots.release()
|
|
92
|
+
this.info.release()
|
|
93
|
+
this.mux.release()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
public function local_address() -> Result[net.SocketAddress, net.Error]:
|
|
97
|
+
return this.mux.session.local_address()
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
public async editable function tick(frame: uint) -> Result[bool, net.Error]:
|
|
101
|
+
let mux_result = await this.mux.tick(frame)
|
|
102
|
+
await drain_lobby_host(ref_of(this))
|
|
103
|
+
match mux_result:
|
|
104
|
+
Result.failure as p:
|
|
105
|
+
return Result[bool, net.Error].failure(error = p.error)
|
|
106
|
+
Result.success as p:
|
|
107
|
+
return Result[bool, net.Error].success(value = p.value)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
public editable function try_recv() -> Option[LobbyEvent]:
|
|
111
|
+
return this.event_queue.pop_front()
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
public function info() -> LobbyInfo:
|
|
115
|
+
return this.info
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
public async editable function kick_player(player_id: uint, reason: ubyte) -> Result[bool, net.Error]:
|
|
119
|
+
match await this.mux.kick(player_id, reason):
|
|
120
|
+
Result.failure as p:
|
|
121
|
+
return Result[bool, net.Error].failure(error = p.error)
|
|
122
|
+
Result.success as p:
|
|
123
|
+
return Result[bool, net.Error].success(value = p.value)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
extending LobbyClient:
|
|
127
|
+
public editable function release() -> void:
|
|
128
|
+
release_lobby_queue(ref_of(this.event_queue))
|
|
129
|
+
this.event_queue.release()
|
|
130
|
+
this.lobby_info.release()
|
|
131
|
+
this.pending_name.release()
|
|
132
|
+
this.mux.release()
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
public function state() -> sess.ConnectionState:
|
|
136
|
+
return this.mux.state()
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
public function assigned_slot() -> ubyte:
|
|
140
|
+
return this.assigned_slot
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
public function assigned_id() -> uint:
|
|
144
|
+
return this.assigned_id
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
public function lobby_info() -> LobbyInfo:
|
|
148
|
+
return this.lobby_info
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
public async editable function tick(frame: uint) -> Result[bool, net.Error]:
|
|
152
|
+
let mux_result = await this.mux.tick(frame)
|
|
153
|
+
await drain_lobby_client(ref_of(this))
|
|
154
|
+
match mux_result:
|
|
155
|
+
Result.failure as p:
|
|
156
|
+
return Result[bool, net.Error].failure(error = p.error)
|
|
157
|
+
Result.success as p:
|
|
158
|
+
return Result[bool, net.Error].success(value = p.value)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
public editable function try_recv() -> Option[LobbyEvent]:
|
|
162
|
+
return this.event_queue.pop_front()
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
public async editable function leave() -> Result[bool, net.Error]:
|
|
166
|
+
match await this.mux.disconnect():
|
|
167
|
+
Result.failure as p:
|
|
168
|
+
return Result[bool, net.Error].failure(error = p.error)
|
|
169
|
+
Result.success as p:
|
|
170
|
+
return Result[bool, net.Error].success(value = p.value)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
public function create_lobby_on(
|
|
174
|
+
runtime: aio.Runtime,
|
|
175
|
+
local_address: net.SocketAddress,
|
|
176
|
+
info: LobbyInfo,
|
|
177
|
+
config: mux.MuxedConfig
|
|
178
|
+
) -> Result[LobbyHost, net.Error]:
|
|
179
|
+
match mux.mux_listen_on(runtime, local_address, config):
|
|
180
|
+
Result.failure as p:
|
|
181
|
+
return Result[LobbyHost, net.Error].failure(error = p.error)
|
|
182
|
+
Result.success as p:
|
|
183
|
+
var slots = vec.Vec[PlayerSlot].create()
|
|
184
|
+
var i: ubyte = 0
|
|
185
|
+
while i < info.max_players:
|
|
186
|
+
slots.push(PlayerSlot(player_id = 0u, player_name = string.String.create(), occupied = false))
|
|
187
|
+
i += 1
|
|
188
|
+
let host = LobbyHost(
|
|
189
|
+
mux = p.value,
|
|
190
|
+
info = info,
|
|
191
|
+
slots = slots,
|
|
192
|
+
event_queue = deque.Deque[LobbyEvent].create()
|
|
193
|
+
)
|
|
194
|
+
return Result[LobbyHost, net.Error].success(value = host)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
public function create_lobby(
|
|
198
|
+
local_address: net.SocketAddress,
|
|
199
|
+
info: LobbyInfo,
|
|
200
|
+
config: mux.MuxedConfig
|
|
201
|
+
) -> Result[LobbyHost, net.Error]:
|
|
202
|
+
return create_lobby_on(aio.current_runtime(), local_address, info, config)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
public async function join_lobby_on(
|
|
206
|
+
runtime: aio.Runtime,
|
|
207
|
+
local_address: net.SocketAddress,
|
|
208
|
+
remote_address: net.SocketAddress,
|
|
209
|
+
player_name: str,
|
|
210
|
+
config: mux.MuxedConfig
|
|
211
|
+
) -> Result[LobbyClient, net.Error]:
|
|
212
|
+
match mux.mux_connect_on(runtime, local_address, remote_address, config):
|
|
213
|
+
Result.failure as p:
|
|
214
|
+
return Result[LobbyClient, net.Error].failure(error = p.error)
|
|
215
|
+
Result.success as p:
|
|
216
|
+
var client = LobbyClient(
|
|
217
|
+
mux = p.value,
|
|
218
|
+
assigned_slot = 0,
|
|
219
|
+
assigned_id = 0,
|
|
220
|
+
lobby_info = LobbyInfo(
|
|
221
|
+
name = string.String.create(),
|
|
222
|
+
player_count = 0,
|
|
223
|
+
max_players = 0,
|
|
224
|
+
player_names = vec.Vec[string.String].create(),
|
|
225
|
+
game_data = bytes.Bytes.empty()
|
|
226
|
+
),
|
|
227
|
+
event_queue = deque.Deque[LobbyEvent].create(),
|
|
228
|
+
pending_join = true,
|
|
229
|
+
pending_name = string.String.from_str(player_name)
|
|
230
|
+
)
|
|
231
|
+
match await client.mux.connect_to_peer():
|
|
232
|
+
Result.failure as pe:
|
|
233
|
+
return Result[LobbyClient, net.Error].failure(error = pe.error)
|
|
234
|
+
Result.success:
|
|
235
|
+
pass
|
|
236
|
+
return Result[LobbyClient, net.Error].success(value = client)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
public async function join_lobby(
|
|
240
|
+
local_address: net.SocketAddress,
|
|
241
|
+
remote_address: net.SocketAddress,
|
|
242
|
+
player_name: str,
|
|
243
|
+
config: mux.MuxedConfig
|
|
244
|
+
) -> Result[LobbyClient, net.Error]:
|
|
245
|
+
return await join_lobby_on(aio.current_runtime(), local_address, remote_address, player_name, config)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
public async function discover_lobbies_on(
|
|
249
|
+
runtime: aio.Runtime,
|
|
250
|
+
local_address: net.SocketAddress,
|
|
251
|
+
remote_address: net.SocketAddress,
|
|
252
|
+
config: mux.MuxedConfig
|
|
253
|
+
) -> Result[vec.Vec[LobbyInfo], net.Error]:
|
|
254
|
+
match mux.mux_connect_on(runtime, local_address, remote_address, config):
|
|
255
|
+
Result.failure as p:
|
|
256
|
+
return Result[vec.Vec[LobbyInfo], net.Error].failure(error = p.error)
|
|
257
|
+
Result.success as p:
|
|
258
|
+
var conn = p.value
|
|
259
|
+
defer conn.release()
|
|
260
|
+
match await conn.connect_to_peer():
|
|
261
|
+
Result.failure as pe:
|
|
262
|
+
return Result[vec.Vec[LobbyInfo], net.Error].failure(error = pe.error)
|
|
263
|
+
Result.success:
|
|
264
|
+
pass
|
|
265
|
+
|
|
266
|
+
let empty = bytes.Bytes.empty()
|
|
267
|
+
let _ = await conn.mux_send(lobby_channel, type_discover_request, empty.as_span(), mux.flag_reliable)
|
|
268
|
+
|
|
269
|
+
var frame: uint = 0
|
|
270
|
+
var result = vec.Vec[LobbyInfo].create()
|
|
271
|
+
while frame < 120:
|
|
272
|
+
await conn.tick(frame)
|
|
273
|
+
|
|
274
|
+
var drain_rounds: uint = 0
|
|
275
|
+
while drain_rounds < 5:
|
|
276
|
+
let msg_opt = conn.try_recv()
|
|
277
|
+
match msg_opt:
|
|
278
|
+
Option.some as mp:
|
|
279
|
+
var msg = mp.value
|
|
280
|
+
if msg.channel_id == lobby_channel and msg.type_id == type_discover_response:
|
|
281
|
+
let info_result = decode_lobby_info_payload(msg.payload.as_span())
|
|
282
|
+
msg.release()
|
|
283
|
+
match info_result:
|
|
284
|
+
Result.success as ip:
|
|
285
|
+
result.push(ip.value)
|
|
286
|
+
Result.failure:
|
|
287
|
+
pass
|
|
288
|
+
var disconnect_frame: uint = 0
|
|
289
|
+
while disconnect_frame < 30:
|
|
290
|
+
await conn.tick(frame + disconnect_frame)
|
|
291
|
+
disconnect_frame += 1
|
|
292
|
+
return Result[vec.Vec[LobbyInfo], net.Error].success(value = result)
|
|
293
|
+
msg.release()
|
|
294
|
+
Option.none:
|
|
295
|
+
pass
|
|
296
|
+
drain_rounds += 1
|
|
297
|
+
frame += 1
|
|
298
|
+
|
|
299
|
+
return Result[vec.Vec[LobbyInfo], net.Error].success(value = result)
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
public async function discover_lobbies(
|
|
303
|
+
local_address: net.SocketAddress,
|
|
304
|
+
remote_address: net.SocketAddress,
|
|
305
|
+
config: mux.MuxedConfig
|
|
306
|
+
) -> Result[vec.Vec[LobbyInfo], net.Error]:
|
|
307
|
+
return await discover_lobbies_on(aio.current_runtime(), local_address, remote_address, config)
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
function encode_lobby_info_payload(w: ref[bin.Writer], info: ref[LobbyInfo]) -> void:
|
|
311
|
+
w.write_ubyte(info.player_count)
|
|
312
|
+
w.write_ubyte(info.max_players)
|
|
313
|
+
w.write_str(info.name.as_str())
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
function decode_lobby_info_payload(data: span[ubyte]) -> Result[LobbyInfo, net.Error]:
|
|
317
|
+
if data.len < 2:
|
|
318
|
+
return Result[LobbyInfo, net.Error].failure(error = net.Error(
|
|
319
|
+
code = -1,
|
|
320
|
+
message = string.String.from_str("lobby info payload truncated")
|
|
321
|
+
))
|
|
322
|
+
var r = bin.reader(data)
|
|
323
|
+
var player_count: ubyte = 0
|
|
324
|
+
match r.read_ubyte():
|
|
325
|
+
Result.failure:
|
|
326
|
+
return Result[LobbyInfo, net.Error].failure(error = net.Error(
|
|
327
|
+
code = -1,
|
|
328
|
+
message = string.String.from_str("lobby info malformed")
|
|
329
|
+
))
|
|
330
|
+
Result.success as pc:
|
|
331
|
+
player_count = pc.value
|
|
332
|
+
var max_players: ubyte = 0
|
|
333
|
+
match r.read_ubyte():
|
|
334
|
+
Result.failure:
|
|
335
|
+
return Result[LobbyInfo, net.Error].failure(error = net.Error(
|
|
336
|
+
code = -1,
|
|
337
|
+
message = string.String.from_str("lobby info malformed")
|
|
338
|
+
))
|
|
339
|
+
Result.success as mp:
|
|
340
|
+
max_players = mp.value
|
|
341
|
+
match r.read_str():
|
|
342
|
+
Result.failure:
|
|
343
|
+
return Result[LobbyInfo, net.Error].failure(error = net.Error(
|
|
344
|
+
code = -1,
|
|
345
|
+
message = string.String.from_str("lobby info malformed")
|
|
346
|
+
))
|
|
347
|
+
Result.success as sp:
|
|
348
|
+
return Result[LobbyInfo, net.Error].success(value = LobbyInfo(
|
|
349
|
+
name = sp.value,
|
|
350
|
+
player_count = player_count,
|
|
351
|
+
max_players = max_players,
|
|
352
|
+
player_names = vec.Vec[string.String].create(),
|
|
353
|
+
game_data = bytes.Bytes.empty()
|
|
354
|
+
))
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
function encode_string(value: str) -> bytes.Bytes:
|
|
358
|
+
var w = bin.Writer.with_capacity(4 + value.len)
|
|
359
|
+
w.write_str(value)
|
|
360
|
+
return w.finish()
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
function decode_string(data: span[ubyte]) -> Result[string.String, net.Error]:
|
|
364
|
+
var r = bin.reader(data)
|
|
365
|
+
match r.read_str():
|
|
366
|
+
Result.failure:
|
|
367
|
+
return Result[string.String, net.Error].failure(error = net.Error(
|
|
368
|
+
code = -1,
|
|
369
|
+
message = string.String.from_str("lobby malformed string")
|
|
370
|
+
))
|
|
371
|
+
Result.success as p:
|
|
372
|
+
return Result[string.String, net.Error].success(value = p.value)
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
async function drain_lobby_host(host: ref[LobbyHost]) -> void:
|
|
376
|
+
while true:
|
|
377
|
+
let ev = host.mux.try_recv()
|
|
378
|
+
match ev:
|
|
379
|
+
Option.none:
|
|
380
|
+
break
|
|
381
|
+
Option.some as p:
|
|
382
|
+
var msg = p.value
|
|
383
|
+
await process_lobby_msg_host(host, ref_of(msg))
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
async function drain_lobby_client(client: ref[LobbyClient]) -> void:
|
|
387
|
+
if client.pending_join:
|
|
388
|
+
let conn_state = client.mux.state()
|
|
389
|
+
if conn_state == sess.ConnectionState.connected:
|
|
390
|
+
client.pending_join = false
|
|
391
|
+
var encoded = encode_string(client.pending_name.as_str())
|
|
392
|
+
defer encoded.release()
|
|
393
|
+
let _ = await client.mux.mux_send(lobby_channel, type_join_request, encoded.as_span(), mux.flag_reliable)
|
|
394
|
+
|
|
395
|
+
while true:
|
|
396
|
+
let ev = client.mux.try_recv()
|
|
397
|
+
match ev:
|
|
398
|
+
Option.none:
|
|
399
|
+
break
|
|
400
|
+
Option.some as p:
|
|
401
|
+
var msg = p.value
|
|
402
|
+
process_lobby_msg_client(client, ref_of(msg))
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
async function process_lobby_msg_host(host: ref[LobbyHost], msg: ref[mux.MuxedMessage]) -> void:
|
|
406
|
+
if msg.channel_id != lobby_channel:
|
|
407
|
+
msg.release()
|
|
408
|
+
return
|
|
409
|
+
|
|
410
|
+
if msg.type_id == type_join_request:
|
|
411
|
+
await handle_join_request(host, msg)
|
|
412
|
+
return
|
|
413
|
+
|
|
414
|
+
if msg.type_id == type_discover_request:
|
|
415
|
+
await handle_discover_request(host, msg)
|
|
416
|
+
return
|
|
417
|
+
|
|
418
|
+
msg.release()
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
function process_lobby_msg_client(client: ref[LobbyClient], msg: ref[mux.MuxedMessage]) -> void:
|
|
422
|
+
if msg.channel_id != lobby_channel:
|
|
423
|
+
msg.release()
|
|
424
|
+
return
|
|
425
|
+
|
|
426
|
+
if msg.type_id == type_join_accept:
|
|
427
|
+
handle_join_accept(client, msg)
|
|
428
|
+
return
|
|
429
|
+
|
|
430
|
+
if msg.type_id == type_join_reject:
|
|
431
|
+
handle_join_reject_client(client, msg)
|
|
432
|
+
return
|
|
433
|
+
|
|
434
|
+
if msg.type_id == type_player_joined:
|
|
435
|
+
handle_player_joined_client(client, msg)
|
|
436
|
+
return
|
|
437
|
+
|
|
438
|
+
if msg.type_id == type_player_left:
|
|
439
|
+
handle_player_left_client(client, msg)
|
|
440
|
+
return
|
|
441
|
+
|
|
442
|
+
if msg.type_id == type_lobby_info:
|
|
443
|
+
handle_lobby_info_client(client, msg)
|
|
444
|
+
return
|
|
445
|
+
|
|
446
|
+
msg.release()
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
async function handle_join_request(host: ref[LobbyHost], msg: ref[mux.MuxedMessage]) -> void:
|
|
450
|
+
let data = msg.payload.as_span()
|
|
451
|
+
let name_result = decode_string(data)
|
|
452
|
+
match name_result:
|
|
453
|
+
Result.failure:
|
|
454
|
+
msg.release()
|
|
455
|
+
return
|
|
456
|
+
Result.success as name_payload:
|
|
457
|
+
var player_name = name_payload.value
|
|
458
|
+
defer player_name.release()
|
|
459
|
+
|
|
460
|
+
var first_free: int = -1
|
|
461
|
+
var slot_index: ubyte = 0
|
|
462
|
+
while slot_index < host.info.max_players:
|
|
463
|
+
let slot_ptr = host.slots.get(ptr_uint<-slot_index) else:
|
|
464
|
+
break
|
|
465
|
+
if not unsafe: read(slot_ptr).occupied:
|
|
466
|
+
first_free = slot_index
|
|
467
|
+
break
|
|
468
|
+
slot_index += 1
|
|
469
|
+
|
|
470
|
+
if first_free < 0:
|
|
471
|
+
var reject_data = encode_join_reject(reject_reason_full)
|
|
472
|
+
defer reject_data.release()
|
|
473
|
+
let _ = await host.mux.mux_send(
|
|
474
|
+
msg.peer_id,
|
|
475
|
+
lobby_channel,
|
|
476
|
+
type_join_reject,
|
|
477
|
+
reject_data.as_span(),
|
|
478
|
+
mux.flag_reliable
|
|
479
|
+
)
|
|
480
|
+
msg.release()
|
|
481
|
+
return
|
|
482
|
+
|
|
483
|
+
let slot = ubyte<-first_free
|
|
484
|
+
let slot_ptr = host.slots.get(ptr_uint<-slot) else:
|
|
485
|
+
msg.release()
|
|
486
|
+
return
|
|
487
|
+
unsafe: read(slot_ptr).player_id = msg.peer_id
|
|
488
|
+
unsafe: read(slot_ptr).player_name = string.String.from_str(player_name.as_str())
|
|
489
|
+
unsafe: read(slot_ptr).occupied = true
|
|
490
|
+
|
|
491
|
+
var accept_data = encode_join_accept(msg.peer_id, slot)
|
|
492
|
+
defer accept_data.release()
|
|
493
|
+
let _ = await host.mux.mux_send(
|
|
494
|
+
msg.peer_id,
|
|
495
|
+
lobby_channel,
|
|
496
|
+
type_join_accept,
|
|
497
|
+
accept_data.as_span(),
|
|
498
|
+
mux.flag_reliable
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
let other_id = msg.peer_id
|
|
502
|
+
msg.release()
|
|
503
|
+
|
|
504
|
+
await broadcast_player_joined(host, other_id, player_name.as_str(), slot)
|
|
505
|
+
|
|
506
|
+
host.event_queue.push_back(LobbyEvent(
|
|
507
|
+
kind = LobbyEventKind.player_joined,
|
|
508
|
+
player_id = other_id,
|
|
509
|
+
player_name = string.String.from_str(player_name.as_str()),
|
|
510
|
+
slot = slot,
|
|
511
|
+
reason = 0ub
|
|
512
|
+
))
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
async function handle_discover_request(host: ref[LobbyHost], msg: ref[mux.MuxedMessage]) -> void:
|
|
516
|
+
var w = bin.Writer.with_capacity(256)
|
|
517
|
+
encode_lobby_info_payload(ref_of(w), host.info)
|
|
518
|
+
var payload = w.finish()
|
|
519
|
+
defer payload.release()
|
|
520
|
+
let _ = await host.mux.mux_send(
|
|
521
|
+
msg.peer_id,
|
|
522
|
+
lobby_channel,
|
|
523
|
+
type_discover_response,
|
|
524
|
+
payload.as_span(),
|
|
525
|
+
mux.flag_reliable
|
|
526
|
+
)
|
|
527
|
+
msg.release()
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
function handle_join_accept(client: ref[LobbyClient], msg: ref[mux.MuxedMessage]) -> void:
|
|
531
|
+
let data = msg.payload.as_span()
|
|
532
|
+
if data.len < 5:
|
|
533
|
+
msg.release()
|
|
534
|
+
return
|
|
535
|
+
var r = bin.reader(data)
|
|
536
|
+
match r.read_uint():
|
|
537
|
+
Result.failure:
|
|
538
|
+
msg.release()
|
|
539
|
+
return
|
|
540
|
+
Result.success as id_payload:
|
|
541
|
+
match r.read_ubyte():
|
|
542
|
+
Result.failure:
|
|
543
|
+
msg.release()
|
|
544
|
+
return
|
|
545
|
+
Result.success as slot_payload:
|
|
546
|
+
client.assigned_id = id_payload.value
|
|
547
|
+
client.assigned_slot = slot_payload.value
|
|
548
|
+
msg.release()
|
|
549
|
+
client.event_queue.push_back(LobbyEvent(
|
|
550
|
+
kind = LobbyEventKind.joined,
|
|
551
|
+
player_id = id_payload.value,
|
|
552
|
+
player_name = string.String.create(),
|
|
553
|
+
slot = slot_payload.value,
|
|
554
|
+
reason = 0ub
|
|
555
|
+
))
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
function handle_join_reject_client(client: ref[LobbyClient], msg: ref[mux.MuxedMessage]) -> void:
|
|
559
|
+
let data = msg.payload.as_span()
|
|
560
|
+
var reason: ubyte = 0
|
|
561
|
+
if data.len > 0:
|
|
562
|
+
reason = unsafe: read(data.data)
|
|
563
|
+
msg.release()
|
|
564
|
+
client.event_queue.push_back(LobbyEvent(
|
|
565
|
+
kind = LobbyEventKind.join_rejected,
|
|
566
|
+
player_id = 0u,
|
|
567
|
+
player_name = string.String.create(),
|
|
568
|
+
slot = 0ub,
|
|
569
|
+
reason = reason
|
|
570
|
+
))
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
function handle_player_joined_client(client: ref[LobbyClient], msg: ref[mux.MuxedMessage]) -> void:
|
|
574
|
+
let data = msg.payload.as_span()
|
|
575
|
+
if data.len < 5:
|
|
576
|
+
msg.release()
|
|
577
|
+
return
|
|
578
|
+
var r = bin.reader(data)
|
|
579
|
+
match r.read_uint():
|
|
580
|
+
Result.failure:
|
|
581
|
+
msg.release()
|
|
582
|
+
return
|
|
583
|
+
Result.success as id_payload:
|
|
584
|
+
match r.read_ubyte():
|
|
585
|
+
Result.failure:
|
|
586
|
+
msg.release()
|
|
587
|
+
return
|
|
588
|
+
Result.success as slot_payload:
|
|
589
|
+
let name_data = unsafe: span[ubyte](data = data.data + 5, len = data.len - 5)
|
|
590
|
+
match decode_string(name_data):
|
|
591
|
+
Result.failure:
|
|
592
|
+
msg.release()
|
|
593
|
+
return
|
|
594
|
+
Result.success as name_payload:
|
|
595
|
+
let name = name_payload.value
|
|
596
|
+
msg.release()
|
|
597
|
+
client.event_queue.push_back(LobbyEvent(
|
|
598
|
+
kind = LobbyEventKind.player_joined,
|
|
599
|
+
player_id = id_payload.value,
|
|
600
|
+
player_name = name,
|
|
601
|
+
slot = slot_payload.value,
|
|
602
|
+
reason = 0ub
|
|
603
|
+
))
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
function handle_player_left_client(client: ref[LobbyClient], msg: ref[mux.MuxedMessage]) -> void:
|
|
607
|
+
let data = msg.payload.as_span()
|
|
608
|
+
if data.len < 5:
|
|
609
|
+
msg.release()
|
|
610
|
+
return
|
|
611
|
+
var r = bin.reader(data)
|
|
612
|
+
match r.read_uint():
|
|
613
|
+
Result.failure:
|
|
614
|
+
msg.release()
|
|
615
|
+
return
|
|
616
|
+
Result.success as id_payload:
|
|
617
|
+
var reason: ubyte = 0
|
|
618
|
+
if data.len > 4:
|
|
619
|
+
reason = unsafe: read(data.data + 4)
|
|
620
|
+
msg.release()
|
|
621
|
+
client.event_queue.push_back(LobbyEvent(
|
|
622
|
+
kind = LobbyEventKind.player_left,
|
|
623
|
+
player_id = id_payload.value,
|
|
624
|
+
player_name = string.String.create(),
|
|
625
|
+
slot = 0ub,
|
|
626
|
+
reason = reason
|
|
627
|
+
))
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
function handle_lobby_info_client(client: ref[LobbyClient], msg: ref[mux.MuxedMessage]) -> void:
|
|
631
|
+
msg.release()
|
|
632
|
+
client.event_queue.push_back(LobbyEvent(
|
|
633
|
+
kind = LobbyEventKind.lobby_info_updated,
|
|
634
|
+
player_id = 0u,
|
|
635
|
+
player_name = string.String.create(),
|
|
636
|
+
slot = 0ub,
|
|
637
|
+
reason = 0ub
|
|
638
|
+
))
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
async function broadcast_player_joined(
|
|
642
|
+
host: ref[LobbyHost],
|
|
643
|
+
new_player_id: uint,
|
|
644
|
+
new_player_name: str,
|
|
645
|
+
slot: ubyte
|
|
646
|
+
) -> void:
|
|
647
|
+
var w = bin.Writer.with_capacity(5 + new_player_name.len)
|
|
648
|
+
w.write_uint(new_player_id)
|
|
649
|
+
w.write_ubyte(slot)
|
|
650
|
+
w.write_uint(uint<-new_player_name.len)
|
|
651
|
+
w.write_bytes(text.as_byte_span(new_player_name))
|
|
652
|
+
var payload = w.finish()
|
|
653
|
+
defer payload.release()
|
|
654
|
+
|
|
655
|
+
var peer_index: ptr_uint = 0
|
|
656
|
+
let peer_count = host.mux.peer_count()
|
|
657
|
+
while peer_index < peer_count:
|
|
658
|
+
let peer_id = uint<-peer_index + 1
|
|
659
|
+
if peer_id != new_player_id:
|
|
660
|
+
let _ = await host.mux.mux_send(
|
|
661
|
+
peer_id,
|
|
662
|
+
lobby_channel,
|
|
663
|
+
type_player_joined,
|
|
664
|
+
payload.as_span(),
|
|
665
|
+
mux.flag_reliable
|
|
666
|
+
)
|
|
667
|
+
peer_index += 1
|
|
668
|
+
|
|
669
|
+
|
|
670
|
+
function encode_join_accept(player_id: uint, slot: ubyte) -> bytes.Bytes:
|
|
671
|
+
var w = bin.Writer.with_capacity(5)
|
|
672
|
+
w.write_uint(player_id)
|
|
673
|
+
w.write_ubyte(slot)
|
|
674
|
+
return w.finish()
|
|
675
|
+
|
|
676
|
+
|
|
677
|
+
function encode_join_reject(reason: ubyte) -> bytes.Bytes:
|
|
678
|
+
var w = bin.Writer.with_capacity(1)
|
|
679
|
+
w.write_ubyte(reason)
|
|
680
|
+
return w.finish()
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
function release_lobby_queue(queue: ref[deque.Deque[LobbyEvent]]) -> void:
|
|
684
|
+
while true:
|
|
685
|
+
let ev = queue.pop_front()
|
|
686
|
+
match ev:
|
|
687
|
+
Option.none:
|
|
688
|
+
break
|
|
689
|
+
Option.some as p:
|
|
690
|
+
var e = p.value
|
|
691
|
+
e.release()
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
function release_slots(slots: ref[vec.Vec[PlayerSlot]]) -> void:
|
|
695
|
+
var index: ptr_uint = 0
|
|
696
|
+
while index < slots.len():
|
|
697
|
+
let slot_ptr = slots.get(index) else:
|
|
698
|
+
return
|
|
699
|
+
unsafe: read(slot_ptr).player_name.release()
|
|
700
|
+
index += 1
|
|
701
|
+
|
|
702
|
+
const beacon_magic: array[ubyte, 8] = array[ubyte, 8](0x4D, 0x54, 0x4C, 0x42, 0x59, 0x00, 0x00, 0x00)
|
|
703
|
+
|
|
704
|
+
const beacon_probe_len: ptr_uint = 8
|
|
705
|
+
const beacon_recv_timeout: uint = 60
|
|
706
|
+
|
|
707
|
+
|
|
708
|
+
public function build_beacon_probe() -> bytes.Bytes:
|
|
709
|
+
var w = bin.Writer.with_capacity(beacon_probe_len)
|
|
710
|
+
w.write_bytes(beacon_magic.as_span())
|
|
711
|
+
return w.finish()
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
public function is_beacon_probe(data: span[ubyte]) -> bool:
|
|
715
|
+
if data.len < beacon_probe_len:
|
|
716
|
+
return false
|
|
717
|
+
return data[0] == beacon_magic[0] and data[1] == beacon_magic[1] and data[2] == beacon_magic[2] and data[3] == beacon_magic[3]
|
|
718
|
+
|
|
719
|
+
|
|
720
|
+
public function build_beacon_response(info: ref[LobbyInfo]) -> bytes.Bytes:
|
|
721
|
+
var w = bin.Writer.with_capacity(16)
|
|
722
|
+
w.write_bytes(beacon_magic.as_span())
|
|
723
|
+
encode_lobby_info_payload(ref_of(w), info)
|
|
724
|
+
return w.finish()
|
|
725
|
+
|
|
726
|
+
|
|
727
|
+
public function parse_beacon_response(data: span[ubyte]) -> Result[LobbyInfo, net.Error]:
|
|
728
|
+
if data.len < 10z:
|
|
729
|
+
return Result[LobbyInfo, net.Error].failure(
|
|
730
|
+
error = net.Error(code = -1, message = string.String.from_str("beacon response too short"))
|
|
731
|
+
)
|
|
732
|
+
var r = bin.reader(data)
|
|
733
|
+
match r.read_bytes(beacon_probe_len):
|
|
734
|
+
Result.failure:
|
|
735
|
+
return Result[LobbyInfo, net.Error].failure(
|
|
736
|
+
error = net.Error(code = -1, message = string.String.from_str("beacon response malformed"))
|
|
737
|
+
)
|
|
738
|
+
Result.success as bp:
|
|
739
|
+
bp.value.release()
|
|
740
|
+
return decode_lobby_info_payload_offset(data, beacon_probe_len)
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
function decode_lobby_info_payload_offset(data: span[ubyte], offset: ptr_uint) -> Result[LobbyInfo, net.Error]:
|
|
744
|
+
if data.len < offset + 2z:
|
|
745
|
+
return Result[LobbyInfo, net.Error].failure(error = net.Error(
|
|
746
|
+
code = -1,
|
|
747
|
+
message = string.String.from_str("lobby info payload truncated")
|
|
748
|
+
))
|
|
749
|
+
var r = bin.reader(data)
|
|
750
|
+
match r.read_bytes(offset):
|
|
751
|
+
Result.failure:
|
|
752
|
+
return Result[LobbyInfo, net.Error].failure(error = net.Error(
|
|
753
|
+
code = -1,
|
|
754
|
+
message = string.String.from_str("lobby info malformed")
|
|
755
|
+
))
|
|
756
|
+
Result.success:
|
|
757
|
+
pass
|
|
758
|
+
var player_count: ubyte = 0
|
|
759
|
+
match r.read_ubyte():
|
|
760
|
+
Result.failure:
|
|
761
|
+
return Result[LobbyInfo, net.Error].failure(error = net.Error(
|
|
762
|
+
code = -1,
|
|
763
|
+
message = string.String.from_str("lobby info malformed")
|
|
764
|
+
))
|
|
765
|
+
Result.success as pc:
|
|
766
|
+
player_count = pc.value
|
|
767
|
+
var max_players: ubyte = 0
|
|
768
|
+
match r.read_ubyte():
|
|
769
|
+
Result.failure:
|
|
770
|
+
return Result[LobbyInfo, net.Error].failure(error = net.Error(
|
|
771
|
+
code = -1,
|
|
772
|
+
message = string.String.from_str("lobby info malformed")
|
|
773
|
+
))
|
|
774
|
+
Result.success as mp:
|
|
775
|
+
max_players = mp.value
|
|
776
|
+
match r.read_str():
|
|
777
|
+
Result.failure:
|
|
778
|
+
return Result[LobbyInfo, net.Error].failure(error = net.Error(
|
|
779
|
+
code = -1,
|
|
780
|
+
message = string.String.from_str("lobby info malformed")
|
|
781
|
+
))
|
|
782
|
+
Result.success as sp:
|
|
783
|
+
return Result[LobbyInfo, net.Error].success(value = LobbyInfo(
|
|
784
|
+
name = sp.value,
|
|
785
|
+
player_count = player_count,
|
|
786
|
+
max_players = max_players,
|
|
787
|
+
player_names = vec.Vec[string.String].create(),
|
|
788
|
+
game_data = bytes.Bytes.empty()
|
|
789
|
+
))
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
public async function respond_to_beacon(
|
|
793
|
+
socket: net.UdpSocket,
|
|
794
|
+
info: ref[LobbyInfo]
|
|
795
|
+
) -> void:
|
|
796
|
+
let recv_task = socket.recv_from(1500)
|
|
797
|
+
var frame: uint = 0
|
|
798
|
+
while frame < beacon_recv_timeout:
|
|
799
|
+
if aio.completed(recv_task):
|
|
800
|
+
let recv_result = aio.result(recv_task)
|
|
801
|
+
match recv_result:
|
|
802
|
+
Result.success as dp:
|
|
803
|
+
var datagram = dp.value
|
|
804
|
+
defer datagram.data.release()
|
|
805
|
+
defer datagram.source.release()
|
|
806
|
+
if is_beacon_probe(datagram.data.as_span()):
|
|
807
|
+
var response = build_beacon_response(info)
|
|
808
|
+
defer response.release()
|
|
809
|
+
let _ = await socket.send_to(response.as_span(), datagram.source)
|
|
810
|
+
Result.failure:
|
|
811
|
+
pass
|
|
812
|
+
await aio.sleep(100)
|
|
813
|
+
frame += 1
|