feat(base): 0.R4 - a queue keeps its own count, so every package verb takes only its own state; ludic migrate state --prune

ludic.base's Queue<T> carries a QueueTag (its name and pending count): queue_new(name), q_push(q, v),
q_drain(q), q_clear(q) take no BaseState, and core_undrained(tags) names the given queues still holding
facts. A reducer on a package's state can now call that package's verbs (wallet_earn(wallet_st, n)).

ludic migrate state --prune (ludicc --migrate-prune) takes out each state parameter a function no
longer uses, nor anything it calls, and the argument that fills it - including an argument for a
parameter the callee has dropped, which is taken out before the call is checked, so a generic's T is
told by the argument that says it. A reducer keeps its state. --dry-run now counts the edits it would
make. Every package was moved with it: 608 base_st parameters and their arguments, 1889 edits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-26 04:19:56 +03:00
parent 8cf4b3fed6
commit 71735b10a2
151 changed files with 58668 additions and 54719 deletions

View file

@ -66,19 +66,19 @@ function net__conf(net_st: mut NetState) -> NetConfig {
return net_st.net__cfg
}
export function net_facts(base_st: mut BaseState, net_st: mut NetState) -> Queue<NetFact> {
if net_st.net__facts == null { net_st.net__facts = queue_new(base_st, "net.facts") }
export function net_facts(net_st: mut NetState) -> Queue<NetFact> {
if net_st.net__facts == null { net_st.net__facts = queue_new("net.facts") }
return net_st.net__facts
}
function net__fact(base_st: mut BaseState, net_st: mut NetState, what: int, slot: int, pid: int, why: int, text: string) -> void {
function net__fact(net_st: mut NetState, what: int, slot: int, pid: int, why: int, text: string) -> void {
let f = new NetFact
f.what = what
f.slot = slot
f.pid = pid
f.why = why
f.text = text
q_push(base_st, net_facts(base_st, net_st), f)
q_push(net_facts(net_st), f)
}
function net__no_log(s: string) -> void { }

View file

@ -1,17 +1,17 @@
# receive.ludic - what arrived, unwrapped from the relay, checked, acknowledged and put in order
# on the inbox. A reliable message is taken strictly in order; one that arrives early is dropped
# and comes again.
function net__pump(base_st: mut BaseState, net_st: mut NetState) -> void {
function net__pump(net_st: mut NetState) -> void {
if net_st.net__sock <= 0 { return }
for guard in 0 .. 200 {
let n = NetSocket.recv(net_st.net__sock, net_st.net__in, NET_MTU + 64)
if n <= 0 { return }
let n2 = net__unwrap(net_st, n, NetSocket.from_ip(net_st.net__sock), NetSocket.from_port(net_st.net__sock))
if n2 > 0 { net__packet(base_st, net_st, n2, net_st.net__from_ip, net_st.net__from_port) }
if n2 > 0 { net__packet(net_st, n2, net_st.net__from_ip, net_st.net__from_port) }
}
}
function net__packet(base_st: mut BaseState, net_st: mut NetState, n: int, ip: int, port: int) -> void {
function net__packet(net_st: mut NetState, n: int, ip: int, port: int) -> void {
if NetWorld.trace() { net__log(`in {n} bytes from {Udp.ip_text(ip)}:{port}`) }
if n < 20 { return }
if net__stun_packet(net_st, n) { return } # what the router looks like from outside
@ -25,7 +25,7 @@ function net__packet(base_st: mut BaseState, net_st: mut NetState, n: int, ip: i
# (a re-join) carries the old numbers and would drop the new hello as already taken
let ack = nb_get32(net_st.net__in, 12)
if ack > p.acked and ack < p.next_id { p.acked = ack }
net__messages(base_st, net_st, slot, n)
net__messages(net_st, slot, n)
}
# the known peer at that address, a stranger's new slot (a host, and only with a hello), or -1
@ -47,7 +47,7 @@ function net__slot_for(net_st: mut NetState, n: int, ip: int, port: int) -> int
return -1
}
function net__messages(base_st: mut BaseState, net_st: mut NetState, slot: int, n: int) -> void {
function net__messages(net_st: mut NetState, slot: int, n: int) -> void {
let p = net_st.net__peers[slot]
let from = nb_get32(net_st.net__in, 8)
let count = nb_get32(net_st.net__in, 16)
@ -71,13 +71,13 @@ function net__messages(base_st: mut BaseState, net_st: mut NetState, slot: int,
p.ack_due = true
if id != p.recv_id + 1 { take = false } else { p.recv_id = id }
}
if take { net__deliver(base_st, net_st, slot, from, kind, o, ml) }
if take { net__deliver(net_st, slot, from, kind, o, ml) }
o += ml
}
}
# onto the inbox - except a heartbeat, and on a host anything but a hello before its welcome
function net__deliver(base_st: mut BaseState, net_st: mut NetState, slot: int, from: int, kind: int, o: int, ml: int) -> void {
function net__deliver(net_st: mut NetState, slot: int, from: int, kind: int, o: int, ml: int) -> void {
if kind == NET_BEAT { return }
if net_st.net__state == NET_HOSTING and net_st.net__peers[slot].pid < 2 and kind != NET_HELLO { return }
let m = new NetMessage
@ -87,5 +87,5 @@ function net__deliver(base_st: mut BaseState, net_st: mut NetState, slot: int, f
m.len = ml
m.data = buffer(ml)
nb_copy(m.data, 0, net_st.net__in, o, ml)
q_push(base_st, net_inbox(base_st, net_st), m)
q_push(net_inbox(net_st), m)
}

View file

@ -1,23 +1,23 @@
# room_connect.ludic - the matchmaker's answer: a guest dials the host it named (or is out),
# and leaving lets the room go
# the matchmaker let this machine down: a guest is out, a host keeps its code-less party
function net__room_fail(base_st: mut BaseState, net_st: mut NetState, why: int) -> void {
function net__room_fail(net_st: mut NetState, why: int) -> void {
net__log(`matchmaker: {why}`)
let was_guest = net_st.net__r_role == 2
let room = net_st.net__room
net_st.net__r_state = NET_R_IDLE
net_st.net__r_role = 0
if was_guest { net__lose_with(base_st, net_st, why, room) } else { net__fact(base_st, net_st, NET_ROOM_FAILED, -1, 0, why, room) }
if was_guest { net__lose_with(net_st, why, room) } else { net__fact(net_st, NET_ROOM_FAILED, -1, 0, why, room) }
}
# the guest: to the host's outside address, or its inside one behind the same router
function net__room_connect(base_st: mut BaseState, net_st: mut NetState, host_pub: string, host_local: string) -> void {
function net__room_connect(net_st: mut NetState, host_pub: string, host_local: string) -> void {
var target = host_pub
var same_router = false
if len(host_pub) > 0 and net_st.net__pub_ip != 0 and net_parse_code(net_st, host_pub) and net_st.net__code_ip == net_st.net__pub_ip { same_router = true }
if len(host_pub) == 0 or same_router { target = host_local }
if not net_parse_code(net_st, target) {
net__room_fail(base_st, net_st, NET_WHY_BAD_ADDRESS)
net__room_fail(net_st, NET_WHY_BAD_ADDRESS)
return
}
net_st.net__r_state = NET_R_DONE

View file

@ -1,6 +1,6 @@
# room_tick.ludic - the matchmaker's side of a frame: STUN asked three times, the room registered
# or asked for, the host's look at who has asked, and a guest's switch to the relay
function net__room_tick(base_st: mut BaseState, net_st: mut NetState, dt: float) -> void {
function net__room_tick(net_st: mut NetState, dt: float) -> void {
if net_st.net__r_state == NET_R_IDLE or net_st.net__r_role == 0 { return }
net_st.net__r_t = net_st.net__r_t + dt
if net_st.net__r_state == NET_R_STUN {
@ -8,7 +8,7 @@ function net__room_tick(base_st: mut BaseState, net_st: mut NetState, dt: float)
return
}
if net_st.net__r_state == NET_R_REGISTER or net_st.net__r_state == NET_R_ASK or (net_st.net__r_state == NET_R_ROOM and net_st.net__http != 0) {
net__room_answer(base_st, net_st)
net__room_answer(net_st)
return
}
if net_st.net__r_state == NET_R_DONE {
@ -42,13 +42,13 @@ function net__room_stun_tick(net_st: mut NetState) -> void {
net_st.net__r_t = 0.0
}
function net__room_answer(base_st: mut BaseState, net_st: mut NetState) -> void {
function net__room_answer(net_st: mut NetState) -> void {
let st = Http.poll(net_st.net__http)
if st < 0 {
if net_st.net__r_t > 12.0 {
Http.free(net_st.net__http)
net_st.net__http = 0
net__room_fail(base_st, net_st, NET_WHY_MATCHMAKER_SILENT)
net__room_fail(net_st, NET_WHY_MATCHMAKER_SILENT)
}
return
}
@ -59,7 +59,7 @@ function net__room_answer(base_st: mut BaseState, net_st: mut NetState) -> void
if net_st.net__r_state == NET_R_REGISTER {
let code = net__json_str(v, "code")
if len(code) == 0 {
net__room_fail(base_st, net_st, NET_WHY_NO_ROOM_GIVEN)
net__room_fail(net_st, NET_WHY_NO_ROOM_GIVEN)
return
}
net_st.net__room = code
@ -67,16 +67,16 @@ function net__room_answer(base_st: mut BaseState, net_st: mut NetState) -> void
net_st.net__r_state = NET_R_ROOM
net_st.net__poll_t = 0.0
net__log(`room {code}`)
net__fact(base_st, net_st, NET_ROOM, -1, 0, 0, code)
net__fact(net_st, NET_ROOM, -1, 0, 0, code)
return
}
if net_st.net__r_state == NET_R_ASK {
if v == null {
net__room_fail(base_st, net_st, NET_WHY_NO_ROOM)
net__room_fail(net_st, NET_WHY_NO_ROOM)
return
}
net__take_relay(net_st, v)
net__room_connect(base_st, net_st, net__json_str(v, "host"), net__json_str(v, "local"))
net__room_connect(net_st, net__json_str(v, "host"), net__json_str(v, "local"))
return
}
# the host's look at the room

View file

@ -107,8 +107,8 @@ export state NetState {
net__dice: Rng = null
}
export function net_inbox(base_st: mut BaseState, net_st: mut NetState) -> Queue<NetMessage> {
if net_st.net__inbox == null { net_st.net__inbox = queue_new(base_st, "net.inbox") }
export function net_inbox(net_st: mut NetState) -> Queue<NetMessage> {
if net_st.net__inbox == null { net_st.net__inbox = queue_new("net.inbox") }
return net_st.net__inbox
}

View file

@ -41,12 +41,12 @@ program NetTest {
}
bind NetSocket { open: fn fake_open, close: fn fake_close, send: fn fake_send, recv: fn fake_recv, from_ip: fn fake_from_ip, from_port: fn fake_from_port, port: fn fake_port, local_ip: fn fake_local }
function fresh(base_st: mut BaseState, net_st: mut NetState, net_test_st: mut NetTestState) -> void {
function fresh(net_st: mut NetState, net_test_st: mut NetTestState) -> void {
net_test_st.sent = new []Pkt
net_test_st.inbound = new []Pkt
net_reset(net_st)
q_clear(base_st, net_inbox(base_st, net_st))
q_clear(base_st, net_facts(base_st, net_st))
q_clear(net_inbox(net_st))
q_clear(net_facts(net_st))
}
# a packet from ip:port: token, pid, ack, then one message of `kind` (reliable with `id` > 0)
@ -80,32 +80,32 @@ program NetTest {
push(net_test_st.inbound, p)
}
function frame(base_st: mut BaseState, net_st: mut NetState, dt: float) -> void {
net_begin(base_st, net_st, dt)
net_update(base_st, net_st, dt)
net_end(base_st, net_st)
function frame(net_st: mut NetState, dt: float) -> void {
net_begin(net_st, dt)
net_update(net_st, dt)
net_end(net_st)
}
# the host with a guest let in at 10.0.0.9:5000 as pid 2
function host_with_guest(base_st: mut BaseState, net_st: mut NetState, net_test_st: mut NetTestState) -> int {
fresh(base_st, net_st, net_test_st)
function host_with_guest(net_st: mut NetState, net_test_st: mut NetTestState) -> int {
fresh(net_st, net_test_st)
expect(net_host(net_st, 27415, 77))
arrive(net_test_st, Udp.ip("10.0.0.9"), 5000, 0, 0, 0, NET_HELLO, 1, 42)
net_begin(base_st, net_st, 0.01)
let got = q_drain(base_st, net_inbox(base_st, net_st))
net_begin(net_st, 0.01)
let got = q_drain(net_inbox(net_st))
expect_eq(len(got), 1)
return net_accept(net_st, got[0].slot)
}
function facts_of(base_st: mut BaseState, net_st: mut NetState, what: int) -> []NetFact {
let all = q_drain(base_st, net_facts(base_st, net_st))
function facts_of(net_st: mut NetState, what: int) -> []NetFact {
let all = q_drain(net_facts(net_st))
let out = new []NetFact
for i in 0 .. len(all) { if all[i].what == what { push(out, all[i]) } }
return out
}
test "the codec carries ints, bools, floats and text, and a short message reads bad" (base_st: mut BaseState, net_st: mut NetState, net_test_st: mut NetTestState) {
fresh(base_st, net_st, net_test_st)
test "the codec carries ints, bools, floats and text, and a short message reads bad" (net_st: mut NetState, net_test_st: mut NetTestState) {
fresh(net_st, net_test_st)
nw_begin(net_st)
nw_i(net_st, -7)
nw_b(net_st, true)
@ -121,8 +121,8 @@ program NetTest {
expect(nr_bad(net_st))
}
test "a join code decodes to its address and port; an address and a room code are taken too" (base_st: mut BaseState, net_st: mut NetState, net_test_st: mut NetTestState) {
fresh(base_st, net_st, net_test_st)
test "a join code decodes to its address and port; an address and a room code are taken too" (net_st: mut NetState, net_test_st: mut NetTestState) {
fresh(net_st, net_test_st)
let ip = Udp.ip("192.168.1.20")
let code = net_code_of(ip, 27415)
expect_eq(len(code), 11)
@ -139,25 +139,25 @@ program NetTest {
expect(not net_is_room("ABCDE1"))
}
test "a host takes a stranger only with a hello, and hands out pids from 2" (base_st: mut BaseState, net_st: mut NetState, net_test_st: mut NetTestState) {
let pid = host_with_guest(base_st, net_st, net_test_st)
test "a host takes a stranger only with a hello, and hands out pids from 2" (net_st: mut NetState, net_test_st: mut NetTestState) {
let pid = host_with_guest(net_st, net_test_st)
expect_eq(pid, 2)
expect(net_hosting(net_st))
expect_eq(net_my_pid(net_st), 1)
arrive(net_test_st, Udp.ip("10.0.0.10"), 6000, 0, 0, 0, 9, 1, 1)
net_begin(base_st, net_st, 0.01)
expect_eq(q_len(net_inbox(base_st, net_st)), 0)
net_begin(net_st, 0.01)
expect_eq(q_len(net_inbox(net_st)), 0)
arrive(net_test_st, Udp.ip("10.0.0.11"), 6000, 0, 0, 0, NET_HELLO, 1, 1)
net_begin(base_st, net_st, 0.01)
let got = q_drain(base_st, net_inbox(base_st, net_st))
net_begin(net_st, 0.01)
let got = q_drain(net_inbox(net_st))
expect_eq(net_accept(net_st, got[0].slot), 3)
}
test "a message's payload reads back as it was written" (base_st: mut BaseState, net_st: mut NetState, net_test_st: mut NetTestState) {
host_with_guest(base_st, net_st, net_test_st)
test "a message's payload reads back as it was written" (net_st: mut NetState, net_test_st: mut NetTestState) {
host_with_guest(net_st, net_test_st)
arrive(net_test_st, Udp.ip("10.0.0.9"), 5000, 77, 2, 0, 9, 2, 1234)
net_begin(base_st, net_st, 0.01)
let got = q_drain(base_st, net_inbox(base_st, net_st))
net_begin(net_st, 0.01)
let got = q_drain(net_inbox(net_st))
expect_eq(len(got), 1)
expect_eq(got[0].kind, 9)
expect_eq(got[0].from, 2)
@ -168,73 +168,73 @@ program NetTest {
expect(nr_bad(net_st))
}
test "a reliable message that arrives early is dropped and taken in order" (base_st: mut BaseState, net_st: mut NetState, net_test_st: mut NetTestState) {
let slot = np_of_pid(net_st, host_with_guest(base_st, net_st, net_test_st))
test "a reliable message that arrives early is dropped and taken in order" (net_st: mut NetState, net_test_st: mut NetTestState) {
let slot = np_of_pid(net_st, host_with_guest(net_st, net_test_st))
arrive(net_test_st, Udp.ip("10.0.0.9"), 5000, 77, 2, 0, 9, 3, 30)
net_begin(base_st, net_st, 0.01)
expect_eq(q_len(net_inbox(base_st, net_st)), 0)
net_begin(net_st, 0.01)
expect_eq(q_len(net_inbox(net_st)), 0)
arrive(net_test_st, Udp.ip("10.0.0.9"), 5000, 77, 2, 0, 9, 2, 20)
arrive(net_test_st, Udp.ip("10.0.0.9"), 5000, 77, 2, 0, 9, 3, 30)
net_begin(base_st, net_st, 0.01)
let got = q_drain(base_st, net_inbox(base_st, net_st))
net_begin(net_st, 0.01)
let got = q_drain(net_inbox(net_st))
expect_eq(len(got), 2)
net_read(net_st, got[1])
expect_eq(nr_i(net_st), 30)
expect_eq(got[1].slot, slot)
}
test "a reliable message goes again until it is taken" (base_st: mut BaseState, net_st: mut NetState, net_test_st: mut NetTestState) {
let slot = np_of_pid(net_st, host_with_guest(base_st, net_st, net_test_st))
net_end(base_st, net_st)
test "a reliable message goes again until it is taken" (net_st: mut NetState, net_test_st: mut NetTestState) {
let slot = np_of_pid(net_st, host_with_guest(net_st, net_test_st))
net_end(net_st)
net_test_st.sent = new []Pkt
nw_begin(net_st)
nw_i(net_st, 5)
np_queue(net_st, slot, 9, true)
frame(base_st, net_st, 0.01)
frame(net_st, 0.01)
expect_eq(len(net_test_st.sent), 1)
frame(base_st, net_st, 0.1)
frame(net_st, 0.1)
expect_eq(len(net_test_st.sent), 1)
frame(base_st, net_st, 0.2)
frame(net_st, 0.2)
expect_eq(len(net_test_st.sent), 2)
arrive(net_test_st, Udp.ip("10.0.0.9"), 5000, 77, 2, 1, 9, 0, 0)
frame(base_st, net_st, 0.3)
frame(net_st, 0.3)
let n = len(net_test_st.sent)
frame(base_st, net_st, 0.3)
frame(net_st, 0.3)
expect_eq(len(net_test_st.sent), n)
}
test "an unreliable message half a second old is dropped" (base_st: mut BaseState, net_st: mut NetState, net_test_st: mut NetTestState) {
let slot = np_of_pid(net_st, host_with_guest(base_st, net_st, net_test_st))
net_end(base_st, net_st)
test "an unreliable message half a second old is dropped" (net_st: mut NetState, net_test_st: mut NetTestState) {
let slot = np_of_pid(net_st, host_with_guest(net_st, net_test_st))
net_end(net_st)
net_test_st.sent = new []Pkt
nw_begin(net_st)
np_queue(net_st, slot, 9, false)
net_begin(base_st, net_st, 0.6)
net_end(base_st, net_st)
net_begin(net_st, 0.6)
net_end(net_st)
expect_eq(len(net_test_st.sent), 0)
}
test "a guest sends its hello until nobody has answered for too long" (base_st: mut BaseState, net_st: mut NetState, net_test_st: mut NetTestState) {
fresh(base_st, net_st, net_test_st)
test "a guest sends its hello until nobody has answered for too long" (net_st: mut NetState, net_test_st: mut NetTestState) {
fresh(net_st, net_test_st)
nw_begin(net_st)
nw_s(net_st, "v1")
net_hello_set(net_st)
expect(net_join(net_st, Udp.ip("10.0.0.1"), 27415))
expect(net_joining(net_st))
frame(base_st, net_st, 0.1)
frame(net_st, 0.1)
expect_eq(len(net_test_st.sent), 1)
expect_eq(nb_get8(net_test_st.sent[0].data, 20), NET_HELLO)
for i in 0 .. 110 { frame(base_st, net_st, 0.1) }
for i in 0 .. 110 { frame(net_st, 0.1) }
expect_eq(net_state(net_st), NET_LOST)
let down = facts_of(base_st, net_st, NET_DOWN)
let down = facts_of(net_st, NET_DOWN)
expect_eq(len(down), 1)
expect_eq(down[0].why, NET_WHY_NO_ANSWER)
net_fresh(net_st)
expect_eq(net_state(net_st), NET_IDLE)
}
test "a welcome makes the guest that pid in that session" (base_st: mut BaseState, net_st: mut NetState, net_test_st: mut NetTestState) {
fresh(base_st, net_st, net_test_st)
test "a welcome makes the guest that pid in that session" (net_st: mut NetState, net_test_st: mut NetTestState) {
fresh(net_st, net_test_st)
nw_begin(net_st)
net_hello_set(net_st)
net_join(net_st, Udp.ip("10.0.0.1"), 27415)
@ -244,32 +244,32 @@ program NetTest {
expect_eq(net_token(net_st), 99)
}
test "a guest silent for the timeout is gone" (base_st: mut BaseState, net_st: mut NetState, net_test_st: mut NetTestState) {
let pid = host_with_guest(base_st, net_st, net_test_st)
test "a guest silent for the timeout is gone" (net_st: mut NetState, net_test_st: mut NetTestState) {
let pid = host_with_guest(net_st, net_test_st)
let slot = np_of_pid(net_st, pid)
for i in 0 .. 105 { frame(base_st, net_st, 0.1) }
let gone = facts_of(base_st, net_st, NET_GONE)
for i in 0 .. 105 { frame(net_st, 0.1) }
let gone = facts_of(net_st, NET_GONE)
expect_eq(len(gone), 1)
expect_eq(gone[0].pid, pid)
expect_eq(gone[0].slot, slot)
expect(not net_peer_on(net_st, slot))
}
test "a slot is let go once it has taken its last message" (base_st: mut BaseState, net_st: mut NetState, net_test_st: mut NetTestState) {
let slot = np_of_pid(net_st, host_with_guest(base_st, net_st, net_test_st))
test "a slot is let go once it has taken its last message" (net_st: mut NetState, net_test_st: mut NetTestState) {
let slot = np_of_pid(net_st, host_with_guest(net_st, net_test_st))
nw_begin(net_st)
np_queue(net_st, slot, 9, true)
net_close_when_sent(net_st, slot, 20.0)
frame(base_st, net_st, 0.01)
frame(net_st, 0.01)
expect(net_peer_on(net_st, slot))
arrive(net_test_st, Udp.ip("10.0.0.9"), 5000, 77, 2, 1, 9, 0, 0)
frame(base_st, net_st, 0.01)
frame(net_st, 0.01)
expect(not net_peer_on(net_st, slot))
expect_eq(len(facts_of(base_st, net_st, NET_CLOSED)), 1)
expect_eq(len(facts_of(net_st, NET_CLOSED)), 1)
}
test "with no matchmaker, a room code is refused" (base_st: mut BaseState, net_st: mut NetState, net_test_st: mut NetTestState) {
fresh(base_st, net_st, net_test_st)
test "with no matchmaker, a room code is refused" (net_st: mut NetState, net_test_st: mut NetTestState) {
fresh(net_st, net_test_st)
expect(not net_room_on(net_st))
expect(not net_room_join(net_st, "ABCDEF"))
expect_eq(net_why(net_st), NET_WHY_NO_MATCHMAKER)

View file

@ -1,33 +1,33 @@
# tick.ludic - a frame of the session, in three calls with the game's between them: net_begin
# (time, and what came in onto the inbox), net_update (the matchmaker, the hello, silence) and,
# once the game has queued its own, net_end (heartbeats, sending, letting slots go)
export function net_begin(base_st: mut BaseState, net_st: mut NetState, dt: float) -> void {
export function net_begin(net_st: mut NetState, dt: float) -> void {
if not net_active(net_st) { return }
net_st.net__time = net_st.net__time + dt
net__pump(base_st, net_st)
net__pump(net_st)
}
export function net_update(base_st: mut BaseState, net_st: mut NetState, dt: float) -> void {
export function net_update(net_st: mut NetState, dt: float) -> void {
if not net_active(net_st) { return }
net__room_tick(base_st, net_st, dt)
net__room_tick(net_st, dt)
if net_st.net__state == NET_JOINING {
net__hello_tick(base_st, net_st, dt)
net__hello_tick(net_st, dt)
return
}
for i in 0 .. NET_PEERS {
let p = net_st.net__peers[i]
if not p.on or net_st.net__time - p.heard <= float(NET_TIMEOUT) { continue }
if net_st.net__state == NET_JOINED {
net_lose(base_st, net_st, NET_WHY_HOST_SILENT)
net_lose(net_st, NET_WHY_HOST_SILENT)
return
}
let gone = p.pid
np_close(net_st, i)
net__fact(base_st, net_st, NET_GONE, i, gone, 0, "")
net__fact(net_st, NET_GONE, i, gone, 0, "")
}
}
function net__hello_tick(base_st: mut BaseState, net_st: mut NetState, dt: float) -> void {
function net__hello_tick(net_st: mut NetState, dt: float) -> void {
if net_st.net__hello_t < 0.0 {
nb_copy(net_st.net__wb, 0, net_st.net__hello_b, 0, net_st.net__hello_l)
net_st.net__wl = net_st.net__hello_l
@ -36,13 +36,13 @@ function net__hello_tick(base_st: mut BaseState, net_st: mut NetState, dt: float
}
net_st.net__hello_t = net_st.net__hello_t + dt
if net_st.net__hello_t > float(NET_TIMEOUT + net_st.net__wait_more) {
net_lose(base_st, net_st, NET_WHY_NO_ANSWER)
net_lose(net_st, NET_WHY_NO_ANSWER)
return
}
np_flush(net_st, 0)
}
export function net_end(base_st: mut BaseState, net_st: mut NetState) -> void {
export function net_end(net_st: mut NetState) -> void {
if not net_live(net_st) { return }
let beat = net_st.net__time - net_st.net__beat_t >= 1.0
if beat { net_st.net__beat_t = net_st.net__time }
@ -57,15 +57,15 @@ export function net_end(base_st: mut BaseState, net_st: mut NetState) -> void {
if p.closing and (p.acked >= p.close_id or net_st.net__time > p.close_t) {
let pid = p.pid
np_close(net_st, i)
net__fact(base_st, net_st, NET_CLOSED, i, pid, 0, "")
net__fact(net_st, NET_CLOSED, i, pid, 0, "")
}
}
}
# while a load holds the frame: keep answering, so nobody times out on this machine
export function net_keepalive(base_st: mut BaseState, net_st: mut NetState) -> void {
export function net_keepalive(net_st: mut NetState) -> void {
if not net_live(net_st) { return }
net__pump(base_st, net_st)
net__pump(net_st)
for i in 0 .. NET_PEERS {
let p = net_st.net__peers[i]
if p.on {
@ -96,15 +96,15 @@ export function net_reset(net_st: mut NetState) -> void {
}
# out of the session, and why: the game hears NET_DOWN and says so in its own words
export function net_lose(base_st: mut BaseState, net_st: mut NetState, why: int) -> void { net__lose_with(base_st, net_st, why, "") }
export function net_lose(net_st: mut NetState, why: int) -> void { net__lose_with(net_st, why, "") }
# ... with what the reason is about (the room code nobody had)
function net__lose_with(base_st: mut BaseState, net_st: mut NetState, why: int, text: string) -> void {
function net__lose_with(net_st: mut NetState, why: int, text: string) -> void {
net_reset(net_st)
net_st.net__state = NET_LOST
net_st.net__why = why
net__log(`lost ({why})`)
net__fact(base_st, net_st, NET_DOWN, -1, 0, why, text)
net__fact(net_st, NET_DOWN, -1, 0, why, text)
}
# a lost session read and done with: idle again