mt-lang 0.2.0 → 0.2.2
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/README.md +12 -0
- data/Rakefile +1 -1
- data/docs/index.html +13 -3
- data/lib/milk_tea/base.rb +7 -2
- 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/manager.mt
ADDED
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
import std.async as aio
|
|
2
|
+
import std.bytes as bytes
|
|
3
|
+
import std.deque as deque
|
|
4
|
+
import std.net as net
|
|
5
|
+
import std.net.clock as clock
|
|
6
|
+
import std.net.mux as mux
|
|
7
|
+
import std.net.session as sess
|
|
8
|
+
import std.string as string
|
|
9
|
+
import std.vec as vec
|
|
10
|
+
|
|
11
|
+
const channel_system: ubyte = 0
|
|
12
|
+
|
|
13
|
+
const type_assign_id: ushort = 0xF000
|
|
14
|
+
|
|
15
|
+
const assign_id_bytes: ptr_uint = 4
|
|
16
|
+
|
|
17
|
+
public struct NetworkConfig:
|
|
18
|
+
max_payload_bytes: ptr_uint
|
|
19
|
+
max_players: ubyte
|
|
20
|
+
|
|
21
|
+
public enum NetworkEventKind: ubyte
|
|
22
|
+
connected = 0
|
|
23
|
+
disconnected = 1
|
|
24
|
+
player_joined = 2
|
|
25
|
+
player_left = 3
|
|
26
|
+
message = 4
|
|
27
|
+
|
|
28
|
+
public struct NetworkEvent:
|
|
29
|
+
kind: NetworkEventKind
|
|
30
|
+
player_id: uint
|
|
31
|
+
channel_id: ubyte
|
|
32
|
+
type_id: ushort
|
|
33
|
+
payload: bytes.Bytes
|
|
34
|
+
|
|
35
|
+
public struct NetworkManager:
|
|
36
|
+
is_server: bool
|
|
37
|
+
max_players: ubyte
|
|
38
|
+
mux_session: mux.MuxedSession
|
|
39
|
+
mux_connection: mux.MuxedConnection
|
|
40
|
+
local_player_id: uint
|
|
41
|
+
players: vec.Vec[PlayerState]
|
|
42
|
+
next_player_id: uint
|
|
43
|
+
events: deque.Deque[NetworkEvent]
|
|
44
|
+
tick_clock: clock.TickClock
|
|
45
|
+
connected: bool
|
|
46
|
+
config: NetworkConfig
|
|
47
|
+
stored_peer_id_events: deque.Deque[PlayerJoinEvent]
|
|
48
|
+
|
|
49
|
+
struct PlayerState:
|
|
50
|
+
player_id: uint
|
|
51
|
+
connected: bool
|
|
52
|
+
|
|
53
|
+
struct PlayerJoinEvent:
|
|
54
|
+
player_id: uint
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
extending PlayerJoinEvent:
|
|
58
|
+
public editable function release() -> void:
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
extending NetworkConfig:
|
|
63
|
+
public static function default(max_payload_bytes: ptr_uint) -> NetworkConfig:
|
|
64
|
+
return NetworkConfig(
|
|
65
|
+
max_payload_bytes = max_payload_bytes,
|
|
66
|
+
max_players = 8
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
extending NetworkEvent:
|
|
71
|
+
public editable function release() -> void:
|
|
72
|
+
this.payload.release()
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
public static function connected(player_id: uint) -> NetworkEvent:
|
|
76
|
+
return NetworkEvent(
|
|
77
|
+
kind = NetworkEventKind.connected,
|
|
78
|
+
player_id = player_id,
|
|
79
|
+
channel_id = 0ub,
|
|
80
|
+
type_id = 0us,
|
|
81
|
+
payload = bytes.Bytes.empty()
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
public static function disconnected() -> NetworkEvent:
|
|
86
|
+
return NetworkEvent(
|
|
87
|
+
kind = NetworkEventKind.disconnected,
|
|
88
|
+
player_id = 0u,
|
|
89
|
+
channel_id = 0ub,
|
|
90
|
+
type_id = 0us,
|
|
91
|
+
payload = bytes.Bytes.empty()
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
public static function player_joined(player_id: uint) -> NetworkEvent:
|
|
96
|
+
return NetworkEvent(
|
|
97
|
+
kind = NetworkEventKind.player_joined,
|
|
98
|
+
player_id = player_id,
|
|
99
|
+
channel_id = 0ub,
|
|
100
|
+
type_id = 0us,
|
|
101
|
+
payload = bytes.Bytes.empty()
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
public static function player_left(player_id: uint) -> NetworkEvent:
|
|
106
|
+
return NetworkEvent(
|
|
107
|
+
kind = NetworkEventKind.player_left,
|
|
108
|
+
player_id = player_id,
|
|
109
|
+
channel_id = 0ub,
|
|
110
|
+
type_id = 0us,
|
|
111
|
+
payload = bytes.Bytes.empty()
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
public static function message_event(
|
|
116
|
+
player_id: uint,
|
|
117
|
+
channel_id: ubyte,
|
|
118
|
+
type_id: ushort,
|
|
119
|
+
payload: bytes.Bytes
|
|
120
|
+
) -> NetworkEvent:
|
|
121
|
+
return NetworkEvent(
|
|
122
|
+
kind = NetworkEventKind.message,
|
|
123
|
+
player_id = player_id,
|
|
124
|
+
channel_id = channel_id,
|
|
125
|
+
type_id = type_id,
|
|
126
|
+
payload = payload
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
function mux_config_for(config: NetworkConfig) -> mux.MuxedConfig:
|
|
131
|
+
return mux.MuxedConfig(
|
|
132
|
+
fragment_size = config.max_payload_bytes,
|
|
133
|
+
fragment_timeout_frames = 120
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
function build_assign_id(player_id: uint) -> bytes.Bytes:
|
|
138
|
+
let encoded = encode_uint(player_id)
|
|
139
|
+
return bytes.Bytes.copy(encoded.as_span())
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
function parse_assign_id(payload: span[ubyte]) -> Result[uint, net.Error]:
|
|
143
|
+
if payload.len < assign_id_bytes:
|
|
144
|
+
return Result[uint, net.Error].failure(error = net.net_error("assign id payload too short"))
|
|
145
|
+
return Result[uint, net.Error].success(value = decode_uint(payload, 0))
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
function encode_uint(value: uint) -> array[ubyte, 4]:
|
|
149
|
+
return array[ubyte, 4](
|
|
150
|
+
ubyte<-((value >> 24) & 255),
|
|
151
|
+
ubyte<-((value >> 16) & 255),
|
|
152
|
+
ubyte<-((value >> 8) & 255),
|
|
153
|
+
ubyte<-(value & 255)
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
function decode_uint(data: span[ubyte], offset: ptr_uint) -> uint:
|
|
158
|
+
return (
|
|
159
|
+
((uint<-data[offset]) << 24)
|
|
160
|
+
| ((uint<-data[offset + 1]) << 16)
|
|
161
|
+
| ((uint<-data[offset + 2]) << 8)
|
|
162
|
+
| (uint<-data[offset + 3])
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
extending NetworkManager:
|
|
167
|
+
public editable function release() -> void:
|
|
168
|
+
this.mux_session.release()
|
|
169
|
+
this.mux_connection.release()
|
|
170
|
+
|
|
171
|
+
while true:
|
|
172
|
+
let ev = this.events.pop_front()
|
|
173
|
+
match ev:
|
|
174
|
+
Option.none:
|
|
175
|
+
break
|
|
176
|
+
Option.some as p:
|
|
177
|
+
var e = p.value
|
|
178
|
+
e.release()
|
|
179
|
+
|
|
180
|
+
this.events.release()
|
|
181
|
+
|
|
182
|
+
while true:
|
|
183
|
+
let je = this.stored_peer_id_events.pop_front()
|
|
184
|
+
match je:
|
|
185
|
+
Option.none:
|
|
186
|
+
break
|
|
187
|
+
Option.some as p:
|
|
188
|
+
var j = p.value
|
|
189
|
+
j.release()
|
|
190
|
+
|
|
191
|
+
this.stored_peer_id_events.release()
|
|
192
|
+
|
|
193
|
+
this.players.release()
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
public function is_server() -> bool:
|
|
197
|
+
return this.is_server
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
public function is_connected() -> bool:
|
|
201
|
+
return this.connected
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
public function local_player_id() -> uint:
|
|
205
|
+
return this.local_player_id
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
public function player_count() -> ptr_uint:
|
|
209
|
+
return this.players.len()
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
public function get_player(player_id: uint) -> Option[PlayerState]:
|
|
213
|
+
var index: ptr_uint = 0
|
|
214
|
+
while index < this.players.len():
|
|
215
|
+
let player_ptr = this.players.get(index) else:
|
|
216
|
+
return Option[PlayerState].none
|
|
217
|
+
if unsafe: read(player_ptr).player_id == player_id:
|
|
218
|
+
return Option[PlayerState].some(value = unsafe: read(player_ptr))
|
|
219
|
+
index += 1
|
|
220
|
+
return Option[PlayerState].none
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
public function config() -> NetworkConfig:
|
|
224
|
+
return this.config
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
public async editable function tick(frame: uint) -> Result[bool, net.Error]:
|
|
228
|
+
this.tick_clock.advance()
|
|
229
|
+
|
|
230
|
+
if this.is_server:
|
|
231
|
+
return await tick_server(ref_of(this), frame)
|
|
232
|
+
return await tick_client(ref_of(this), frame)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
public editable function try_recv() -> Option[NetworkEvent]:
|
|
236
|
+
return this.events.pop_front()
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
public async editable function send_to_server(
|
|
240
|
+
channel_id: ubyte,
|
|
241
|
+
type_id: ushort,
|
|
242
|
+
payload: span[ubyte],
|
|
243
|
+
send_flags: ubyte
|
|
244
|
+
) -> Result[bool, net.Error]:
|
|
245
|
+
if this.is_server:
|
|
246
|
+
return Result[bool, net.Error].failure(
|
|
247
|
+
error = net.net_error("send_to_server requires a client manager")
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
match await this.mux_connection.mux_send(channel_id, type_id, payload, send_flags):
|
|
251
|
+
Result.failure as p:
|
|
252
|
+
return Result[bool, net.Error].failure(error = p.error)
|
|
253
|
+
Result.success:
|
|
254
|
+
return Result[bool, net.Error].success(value = true)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
public async editable function send_to(
|
|
258
|
+
player_id: uint,
|
|
259
|
+
channel_id: ubyte,
|
|
260
|
+
type_id: ushort,
|
|
261
|
+
payload: span[ubyte],
|
|
262
|
+
send_flags: ubyte
|
|
263
|
+
) -> Result[bool, net.Error]:
|
|
264
|
+
if not this.is_server:
|
|
265
|
+
return Result[bool, net.Error].failure(
|
|
266
|
+
error = net.net_error("send_to requires a server manager")
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
match await this.mux_session.mux_send(player_id, channel_id, type_id, payload, send_flags):
|
|
270
|
+
Result.failure as p:
|
|
271
|
+
return Result[bool, net.Error].failure(error = p.error)
|
|
272
|
+
Result.success:
|
|
273
|
+
return Result[bool, net.Error].success(value = true)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
public async editable function broadcast(
|
|
277
|
+
channel_id: ubyte,
|
|
278
|
+
type_id: ushort,
|
|
279
|
+
payload: span[ubyte],
|
|
280
|
+
send_flags: ubyte
|
|
281
|
+
) -> Result[bool, net.Error]:
|
|
282
|
+
if not this.is_server:
|
|
283
|
+
return Result[bool, net.Error].failure(
|
|
284
|
+
error = net.net_error("broadcast requires a server manager")
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
var index: ptr_uint = 0
|
|
288
|
+
while index < this.players.len():
|
|
289
|
+
let player_ptr = this.players.get(index) else:
|
|
290
|
+
break
|
|
291
|
+
|
|
292
|
+
if unsafe: read(player_ptr).connected:
|
|
293
|
+
let peer_id = unsafe: read(player_ptr).player_id
|
|
294
|
+
match await this.mux_session.mux_send(peer_id, channel_id, type_id, payload, send_flags):
|
|
295
|
+
Result.failure as p:
|
|
296
|
+
return Result[bool, net.Error].failure(error = p.error)
|
|
297
|
+
Result.success:
|
|
298
|
+
pass
|
|
299
|
+
|
|
300
|
+
index += 1
|
|
301
|
+
|
|
302
|
+
return Result[bool, net.Error].success(value = true)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
public async editable function rpc_server(rpc_id: ushort, data: span[ubyte]) -> Result[bool, net.Error]:
|
|
306
|
+
return await this.send_to_server(channel_system, rpc_id, data, mux.flag_reliable)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
public async editable function rpc_to(
|
|
310
|
+
player_id: uint,
|
|
311
|
+
rpc_id: ushort,
|
|
312
|
+
data: span[ubyte]
|
|
313
|
+
) -> Result[bool, net.Error]:
|
|
314
|
+
return await this.send_to(player_id, channel_system, rpc_id, data, mux.flag_reliable)
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
public async editable function rpc_all(rpc_id: ushort, data: span[ubyte]) -> Result[bool, net.Error]:
|
|
318
|
+
return await this.broadcast(channel_system, rpc_id, data, mux.flag_reliable)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
public function create_server(
|
|
322
|
+
address: net.SocketAddress,
|
|
323
|
+
config: NetworkConfig
|
|
324
|
+
) -> Result[NetworkManager, net.Error]:
|
|
325
|
+
let mux_config = mux_config_for(config)
|
|
326
|
+
match mux.mux_listen(address, mux_config):
|
|
327
|
+
Result.failure as p:
|
|
328
|
+
return Result[NetworkManager, net.Error].failure(error = p.error)
|
|
329
|
+
Result.success as session_p:
|
|
330
|
+
let mgr = NetworkManager(
|
|
331
|
+
is_server = true,
|
|
332
|
+
max_players = config.max_players,
|
|
333
|
+
mux_session = session_p.value,
|
|
334
|
+
mux_connection = unsafe: zero[mux.MuxedConnection],
|
|
335
|
+
local_player_id = 0u,
|
|
336
|
+
players = vec.Vec[PlayerState].create(),
|
|
337
|
+
next_player_id = 1u,
|
|
338
|
+
events = deque.Deque[NetworkEvent].create(),
|
|
339
|
+
tick_clock = clock.TickClock(tick = 0u, rate = 60u, epoch = clock.monotonic_ns()),
|
|
340
|
+
connected = true,
|
|
341
|
+
config = config,
|
|
342
|
+
stored_peer_id_events = deque.Deque[PlayerJoinEvent].create()
|
|
343
|
+
)
|
|
344
|
+
return Result[NetworkManager, net.Error].success(value = mgr)
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
public function create_client(
|
|
348
|
+
local_address: net.SocketAddress,
|
|
349
|
+
server_address: net.SocketAddress,
|
|
350
|
+
config: NetworkConfig
|
|
351
|
+
) -> Result[NetworkManager, net.Error]:
|
|
352
|
+
let mux_config = mux_config_for(config)
|
|
353
|
+
match mux.mux_connect_on(aio.current_runtime(), local_address, server_address, mux_config):
|
|
354
|
+
Result.failure as p:
|
|
355
|
+
return Result[NetworkManager, net.Error].failure(error = p.error)
|
|
356
|
+
Result.success as mux_conn_p:
|
|
357
|
+
let client_mgr = NetworkManager(
|
|
358
|
+
is_server = false,
|
|
359
|
+
max_players = config.max_players,
|
|
360
|
+
mux_session = unsafe: zero[mux.MuxedSession],
|
|
361
|
+
mux_connection = mux_conn_p.value,
|
|
362
|
+
local_player_id = 0u,
|
|
363
|
+
players = vec.Vec[PlayerState].create(),
|
|
364
|
+
next_player_id = 0u,
|
|
365
|
+
events = deque.Deque[NetworkEvent].create(),
|
|
366
|
+
tick_clock = clock.TickClock(tick = 0u, rate = 60u, epoch = clock.monotonic_ns()),
|
|
367
|
+
connected = false,
|
|
368
|
+
config = config,
|
|
369
|
+
stored_peer_id_events = deque.Deque[PlayerJoinEvent].create()
|
|
370
|
+
)
|
|
371
|
+
return Result[NetworkManager, net.Error].success(value = client_mgr)
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
async function tick_server(manager: ref[NetworkManager], frame: uint) -> Result[bool, net.Error]:
|
|
375
|
+
await process_stored_peer_id_events(manager)
|
|
376
|
+
|
|
377
|
+
match await manager.mux_session.tick(frame):
|
|
378
|
+
Result.failure as p:
|
|
379
|
+
return Result[bool, net.Error].failure(error = p.error)
|
|
380
|
+
Result.success:
|
|
381
|
+
pass
|
|
382
|
+
|
|
383
|
+
drain_mux_events_server(manager)
|
|
384
|
+
|
|
385
|
+
return Result[bool, net.Error].success(value = true)
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
async function tick_client(manager: ref[NetworkManager], frame: uint) -> Result[bool, net.Error]:
|
|
389
|
+
if manager.mux_connection.state() == sess.ConnectionState.disconnected:
|
|
390
|
+
match await manager.mux_connection.connect_to_peer():
|
|
391
|
+
Result.failure as p:
|
|
392
|
+
return Result[bool, net.Error].failure(error = p.error)
|
|
393
|
+
Result.success:
|
|
394
|
+
pass
|
|
395
|
+
|
|
396
|
+
match await manager.mux_connection.tick(frame):
|
|
397
|
+
Result.failure as p:
|
|
398
|
+
if manager.connected:
|
|
399
|
+
manager.connected = false
|
|
400
|
+
manager.events.push_back(NetworkEvent.disconnected())
|
|
401
|
+
return Result[bool, net.Error].failure(error = p.error)
|
|
402
|
+
Result.success:
|
|
403
|
+
pass
|
|
404
|
+
|
|
405
|
+
drain_mux_events_client(manager)
|
|
406
|
+
|
|
407
|
+
return Result[bool, net.Error].success(value = true)
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
async function process_stored_peer_id_events(manager: ref[NetworkManager]) -> void:
|
|
411
|
+
while true:
|
|
412
|
+
let je = manager.stored_peer_id_events.pop_front()
|
|
413
|
+
match je:
|
|
414
|
+
Option.none:
|
|
415
|
+
break
|
|
416
|
+
Option.some as p:
|
|
417
|
+
var join_event = p.value
|
|
418
|
+
let player_id = join_event.player_id
|
|
419
|
+
join_event.release()
|
|
420
|
+
var assign_data = build_assign_id(player_id)
|
|
421
|
+
defer assign_data.release()
|
|
422
|
+
let _ = await manager.mux_session.mux_send(
|
|
423
|
+
player_id,
|
|
424
|
+
channel_system,
|
|
425
|
+
type_assign_id,
|
|
426
|
+
assign_data.as_span(),
|
|
427
|
+
mux.flag_reliable
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
function drain_mux_events_server(manager: ref[NetworkManager]) -> void:
|
|
432
|
+
while true:
|
|
433
|
+
let ev = manager.mux_session.try_recv()
|
|
434
|
+
match ev:
|
|
435
|
+
Option.none:
|
|
436
|
+
break
|
|
437
|
+
Option.some as p:
|
|
438
|
+
var msg = p.value
|
|
439
|
+
handle_mux_message_server(manager, ref_of(msg))
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
function drain_mux_events_client(manager: ref[NetworkManager]) -> void:
|
|
443
|
+
while true:
|
|
444
|
+
let ev = manager.mux_connection.try_recv()
|
|
445
|
+
match ev:
|
|
446
|
+
Option.none:
|
|
447
|
+
break
|
|
448
|
+
Option.some as p:
|
|
449
|
+
var msg = p.value
|
|
450
|
+
handle_mux_message_client(manager, ref_of(msg))
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
function handle_mux_message_server(manager: ref[NetworkManager], msg: ref[mux.MuxedMessage]) -> void:
|
|
454
|
+
if msg.channel_id == mux.meta_channel:
|
|
455
|
+
if msg.type_id == mux.type_peer_joined:
|
|
456
|
+
let peer_id = msg.peer_id
|
|
457
|
+
msg.release()
|
|
458
|
+
|
|
459
|
+
ensure_player_slot(manager, peer_id)
|
|
460
|
+
manager.stored_peer_id_events.push_back(PlayerJoinEvent(player_id = peer_id))
|
|
461
|
+
return
|
|
462
|
+
|
|
463
|
+
if msg.type_id == mux.type_peer_left:
|
|
464
|
+
let peer_id = msg.peer_id
|
|
465
|
+
msg.release()
|
|
466
|
+
|
|
467
|
+
mark_player_disconnected(manager, peer_id)
|
|
468
|
+
manager.events.push_back(NetworkEvent.player_left(peer_id))
|
|
469
|
+
return
|
|
470
|
+
|
|
471
|
+
msg.release()
|
|
472
|
+
return
|
|
473
|
+
|
|
474
|
+
if msg.channel_id == channel_system and msg.type_id == type_assign_id:
|
|
475
|
+
msg.release()
|
|
476
|
+
return
|
|
477
|
+
|
|
478
|
+
manager.events.push_back(NetworkEvent.message_event(
|
|
479
|
+
msg.peer_id,
|
|
480
|
+
msg.channel_id,
|
|
481
|
+
msg.type_id,
|
|
482
|
+
msg.payload
|
|
483
|
+
))
|
|
484
|
+
|
|
485
|
+
unsafe:
|
|
486
|
+
read(ptr[mux.MuxedMessage]<-msg).payload = bytes.Bytes.empty()
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
function handle_mux_message_client(manager: ref[NetworkManager], msg: ref[mux.MuxedMessage]) -> void:
|
|
490
|
+
if msg.channel_id == mux.meta_channel:
|
|
491
|
+
msg.release()
|
|
492
|
+
return
|
|
493
|
+
|
|
494
|
+
if msg.channel_id == channel_system and msg.type_id == type_assign_id:
|
|
495
|
+
let id_result = parse_assign_id(msg.payload.as_span())
|
|
496
|
+
match id_result:
|
|
497
|
+
Result.success as p:
|
|
498
|
+
manager.local_player_id = p.value
|
|
499
|
+
manager.connected = true
|
|
500
|
+
manager.events.push_back(NetworkEvent.connected(p.value))
|
|
501
|
+
Result.failure:
|
|
502
|
+
pass
|
|
503
|
+
msg.release()
|
|
504
|
+
return
|
|
505
|
+
|
|
506
|
+
manager.events.push_back(NetworkEvent.message_event(
|
|
507
|
+
msg.peer_id,
|
|
508
|
+
msg.channel_id,
|
|
509
|
+
msg.type_id,
|
|
510
|
+
msg.payload
|
|
511
|
+
))
|
|
512
|
+
|
|
513
|
+
unsafe:
|
|
514
|
+
read(ptr[mux.MuxedMessage]<-msg).payload = bytes.Bytes.empty()
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
function ensure_player_slot(manager: ref[NetworkManager], player_id: uint) -> void:
|
|
518
|
+
var index: ptr_uint = 0
|
|
519
|
+
while index < manager.players.len():
|
|
520
|
+
let player_ptr = manager.players.get(index) else:
|
|
521
|
+
break
|
|
522
|
+
if unsafe: read(player_ptr).player_id == player_id:
|
|
523
|
+
unsafe: read(player_ptr).connected = true
|
|
524
|
+
return
|
|
525
|
+
index += 1
|
|
526
|
+
|
|
527
|
+
manager.players.push(PlayerState(player_id = player_id, connected = true))
|
|
528
|
+
manager.events.push_back(NetworkEvent.player_joined(player_id))
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
function mark_player_disconnected(manager: ref[NetworkManager], player_id: uint) -> void:
|
|
532
|
+
var index: ptr_uint = 0
|
|
533
|
+
while index < manager.players.len():
|
|
534
|
+
let player_ptr = manager.players.get(index) else:
|
|
535
|
+
break
|
|
536
|
+
if unsafe: read(player_ptr).player_id == player_id:
|
|
537
|
+
unsafe: read(player_ptr).connected = false
|
|
538
|
+
return
|
|
539
|
+
index += 1
|