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:
parent
8cf4b3fed6
commit
71735b10a2
151 changed files with 58668 additions and 54719 deletions
|
|
@ -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 { }
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue