mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-10-09 01:59:15 -04:00
138 lines
4.1 KiB
Lua
138 lines
4.1 KiB
Lua
local Loop = {}
|
|
Loop.__index = Loop
|
|
|
|
Loop.PEER_DIGEST = "00000000000000b2"
|
|
|
|
local function copy(v)
|
|
if type(v) ~= "table" then return v end
|
|
local out = {}
|
|
for k, x in pairs(v) do out[k] = copy(x) end
|
|
return out
|
|
end
|
|
|
|
function Loop.new(opts)
|
|
opts = opts or {}
|
|
local self = setmetatable({ seat = opts.seat or 0, rev = 0, inbox = {}, rosters = {}, sizeReq = {},
|
|
ready = {}, size = nil, rules = nil, closed = false, stage = "prep", sent = {} }, Loop)
|
|
local me = self
|
|
self.session = {
|
|
send = function(m)
|
|
me.sent[#me.sent + 1] = copy(m)
|
|
me:fromSeat(me.seat, m)
|
|
return not me.closed
|
|
end,
|
|
take = function(pred)
|
|
for i, m in ipairs(me.inbox) do
|
|
if pred(m) then return table.remove(me.inbox, i) end
|
|
end
|
|
return nil
|
|
end,
|
|
seat = function() return me.seat end,
|
|
open = function() return not me.closed or #me.inbox > 0 end,
|
|
leave = function() me.closed = true end,
|
|
}
|
|
return self
|
|
end
|
|
|
|
function Loop:peer() return 1 - self.seat end
|
|
|
|
function Loop:push(m)
|
|
m.relay = true
|
|
self.inbox[#self.inbox + 1] = m
|
|
end
|
|
|
|
function Loop:bump()
|
|
self.rev = self.rev + 1
|
|
self.ready = {}
|
|
end
|
|
|
|
function Loop:setRules(r)
|
|
self:bump()
|
|
self.rules = copy(r)
|
|
local m = copy(r)
|
|
m.type, m.rev = "xg_rules", self.rev
|
|
m.mode = m.mode or "battle"
|
|
self:push(m)
|
|
end
|
|
|
|
function Loop:sizeOf()
|
|
local a, b = self.rosters[0], self.rosters[1]
|
|
if not a or not b then return nil end
|
|
local q0, q1 = self.sizeReq[0], self.sizeReq[1]
|
|
if q0 and q0 == q1 and q0 <= a.size and q0 <= b.size then return q0 end
|
|
return math.min(a.size, b.size)
|
|
end
|
|
|
|
function Loop:nack(seat, kind, why, rev)
|
|
if seat == self.seat then
|
|
self:push({ type = "xg_nack", of = kind, why = why, rev = rev, current = self.rev })
|
|
end
|
|
end
|
|
|
|
function Loop:fromSeat(seat, m)
|
|
if self.closed or type(m) ~= "table" then return end
|
|
local kind = m.type
|
|
if kind == "xg_cancel" then return self:close("cancel", seat) end
|
|
if self.stage ~= "prep" then return end
|
|
if m.rev ~= self.rev then return self:nack(seat, kind, "stale_rev", m.rev) end
|
|
local fwd
|
|
if kind == "xg_roster" then
|
|
self.rosters[seat] = { size = m.size, digest16 = m.digest16 }
|
|
fwd = { type = kind, rev = m.rev, size = m.size, digest16 = m.digest16 }
|
|
elseif kind == "xg_size_req" then
|
|
self.sizeReq[seat] = m.size
|
|
fwd = { type = kind, rev = m.rev, size = m.size }
|
|
elseif kind == "xg_ready" then
|
|
if not self.rules then return self:nack(seat, kind, "no_rules", m.rev) end
|
|
if not self.size then return self:nack(seat, kind, "no_roster", m.rev) end
|
|
if self.ready[seat] then return end
|
|
self.ready[seat] = m.digest16
|
|
if seat ~= self.seat then self:push({ type = kind, rev = self.rev, digest16 = m.digest16 }) end
|
|
if self.ready[0] and self.ready[1] then self:go() end
|
|
return
|
|
else
|
|
return
|
|
end
|
|
self:bump()
|
|
if seat ~= self.seat then self:push(fwd) end
|
|
self:push({ type = "xg_rev", rev = self.rev, seat = seat, cause = kind })
|
|
self.size = self:sizeOf()
|
|
if self.size then self:push({ type = "xg_size", rev = self.rev, size = self.size }) end
|
|
end
|
|
|
|
function Loop:go()
|
|
self.stage = "battling"
|
|
local r = self.rules or {}
|
|
self:push({ type = "xg_go", rev = self.rev, seed = 777, match = "loop-m1", mode = "battle",
|
|
ruleset = r.ruleset, size = self.size, gen = r.gen, dexMax = r.dexMax, moveMax = r.moveMax, moveGen = r.moveGen })
|
|
end
|
|
|
|
function Loop:close(why, seat)
|
|
if self.closed then return end
|
|
self:push({ type = "xg_closed", why = why, seat = seat })
|
|
self.closed = true
|
|
end
|
|
|
|
function Loop:peerRoster(size, digest)
|
|
self:fromSeat(self:peer(), { type = "xg_roster", rev = self.rev, size = size, digest16 = digest or Loop.PEER_DIGEST })
|
|
end
|
|
|
|
function Loop:peerSizeReq(size)
|
|
self:fromSeat(self:peer(), { type = "xg_size_req", rev = self.rev, size = size })
|
|
end
|
|
|
|
function Loop:peerReady(digest)
|
|
self:fromSeat(self:peer(), { type = "xg_ready", rev = self.rev, digest16 = digest or Loop.PEER_DIGEST })
|
|
end
|
|
|
|
function Loop:peerCancel()
|
|
self:close("cancel", self:peer())
|
|
end
|
|
|
|
function Loop:prep()
|
|
local Prep = require("src.online.union.Prep")
|
|
return Prep.new(self.session, { mode = "battle" })
|
|
end
|
|
|
|
return Loop
|