ludic/packages/ludic.net/tick.ludic

112 lines
3.8 KiB
Text

# 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(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(net_st)
}
export function net_update(net_st: mut NetState, dt: float) -> void {
if not net_active(net_st) { return }
net__room_tick(net_st, dt)
if net_st.net__state == NET_JOINING {
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(net_st, NET_WHY_HOST_SILENT)
return
}
let gone = p.pid
np_close(net_st, i)
net__fact(net_st, NET_GONE, i, gone, 0, "")
}
}
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
np_queue(net_st, 0, NET_HELLO, true)
net_st.net__hello_t = 0.0
}
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(net_st, NET_WHY_NO_ANSWER)
return
}
np_flush(net_st, 0)
}
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 }
for i in 0 .. NET_PEERS {
let p = net_st.net__peers[i]
if not p.on { continue }
if beat {
nw_begin(net_st)
np_queue(net_st, i, NET_BEAT, false)
}
np_flush(net_st, i)
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(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(net_st: mut NetState) -> void {
if not net_live(net_st) { return }
net__pump(net_st)
for i in 0 .. NET_PEERS {
let p = net_st.net__peers[i]
if p.on {
p.heard = net_st.net__time
nw_begin(net_st)
np_queue(net_st, i, NET_BEAT, false)
np_flush(net_st, i)
}
}
}
# every queue to its peer now, three times over (a machine about to let go)
export function net_flush_all(net_st: mut NetState) -> void {
for t in 0 .. 3 { for i in 0 .. NET_PEERS { np_flush(net_st, i) } }
}
# the session is over for this machine: every slot, the socket and the matchmaker let go
export function net_reset(net_st: mut NetState) -> void {
if net_st.net__peers != null { for i in 0 .. NET_PEERS { np_close(net_st, i) } }
if net_st.net__sock > 0 {
NetSocket.close(net_st.net__sock)
net_st.net__sock = 0
}
net_st.net__state = NET_IDLE
net_st.net__my_pid = 0
net_st.net__wait_more = 0
net__room_reset(net_st)
}
# out of the session, and why: the game hears NET_DOWN and says so in its own words
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)
@alloc_ok("once, when the party is lost")
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(net_st, NET_DOWN, -1, 0, why, text)
}
# a lost session read and done with: idle again
export function net_fresh(net_st: mut NetState) -> void { if net_st.net__state == NET_LOST { net_st.net__state = NET_IDLE } }