further online junk

This commit is contained in:
bryanthaboi
2026-08-28 15:43:13 -04:00
parent 8b9c8fe416
commit 71200f21dc
7 changed files with 262 additions and 30 deletions
+72 -13
View File
@@ -1403,7 +1403,8 @@ function OnlinePanel.remoteConfirm(imp, yes)
end
function OnlinePanel.pumpRemoteTrade(imp)
local tr = OnlinePanel.state(imp).trade
local st = OnlinePanel.state(imp)
local tr = st.trade
if not tr or not tr.remote then return end
local ok, stage = pcall(function() return tr.remote:update() end)
if not ok then
@@ -1424,9 +1425,12 @@ function OnlinePanel.pumpRemoteTrade(imp)
pcall(require("src.online.Trade").pruneBackups,
tr.remote.handle.path, 3)
tr.remoteResult = Strings("Trade complete.")
else
tr.remoteResult = tostring(result)
OnlinePanel.endRemoteTrade(imp)
OnlinePanel.home(imp)
st.status, st.statusOk = tr.remoteResult, true
return
end
tr.remoteResult = tostring(result)
OnlinePanel.endRemoteTrade(imp)
elseif stage == "cancelled" then
tr.remoteDone = true
@@ -1679,6 +1683,8 @@ ensureHooks = function()
OnlinePanel._pendingStart = payload
end)
client.on("match_end", function(msg)
local room = client.room()
if room and room.intent == "trade" then return end
OnlinePanel.lastResult = OnlinePanel.resultText(msg)
end)
client.on("tour_match", function(payload)
@@ -1924,10 +1930,14 @@ local function entered(imp, id)
imp._pcPicker = nil
st.status, st.statusOk = nil, false
st.confirmLeave = nil
if id == "play" or id == "watch" then
if id == "play" or id == "watch" or id == "tournament" then
c.dirty.lobby = true
elseif id == "trade" then
c.dirty.trade = true
local tr = st.trade
if tr and not tr.remote then
tr.status, tr.remoteResult, tr.remoteError = nil, nil, nil
end
elseif id == "wizard" then
c.dirty.slots, c.dirty.party = true, true
end
@@ -2064,7 +2074,16 @@ function OnlinePanel.wizardReady(imp)
local id = OnlinePanel.wizardStep(imp)
if id == "game" then return OnlinePanel.selectedVersion(imp) ~= nil end
if id == "save" then return st.slotId ~= nil end
if id == "team" then return #(st.team or {}) > 0 end
if id == "team" then
local n = #(st.team or {})
if n == 0 then return false end
local w, target = st.wizard, st.joinTarget
if w and w.kind == "join" and type(target) == "table"
and type(target.rule) == "table" and tonumber(target.rule.partySize) then
return n == OnlinePanel.teamCap(imp)
end
return true
end
if id == "role" then
if st.tradeRole == "join" then
return #OnlinePanel.sanitizeCode(OnlinePanel.tradeState(imp).code or "")
@@ -2236,11 +2255,30 @@ function OnlinePanel.startJoin(imp, code, rule, as, tournament)
st.status, st.statusOk = Strings("Room codes are 6 characters."), false
return false
end
if type(rule) ~= "table" then
for _, entry in ipairs(Client().lobby() or {}) do
if entry.code == code then
rule = entry.profile and entry.profile.rule or nil
if entry.intent == "tournament" then tournament = true end
end
end
end
st.joinTarget = { code = code, rule = rule, as = as or "player",
tournament = tournament == true }
return OnlinePanel.startWizard(imp, "join")
end
function OnlinePanel.teamCap(imp)
local st = OnlinePanel.state(imp)
local w, target = st.wizard, st.joinTarget
if w and w.kind == "join" and type(target) == "table"
and type(target.rule) == "table" then
local n = tonumber(target.rule.partySize)
if n then return math.max(1, math.min(n, OnlinePanel.TEAM_MAX)) end
end
return OnlinePanel.TEAM_MAX
end
function OnlinePanel.startJoinTournament(imp, code, rule)
return OnlinePanel.startJoin(imp, code, rule, "player", true)
end
@@ -2459,7 +2497,7 @@ local function newCache()
dirty = { slots = true, carts = true, party = true, lobby = true,
trade = true, summary = true },
slots = {}, carts = {}, party = {}, pc = {}, team = {},
rooms = {}, watch = {}, mine = nil,
rooms = {}, watch = {}, tours = {}, mine = nil,
tradeSlots = {}, tradeRows = { a = {}, b = {} },
tradePc = EMPTY, tradePcKey = nil,
counts = { players = 0, lobbies = 0 },
@@ -2679,11 +2717,14 @@ local function refreshLobby(imp, c)
c.lobbyKey = key
local filter = OnlinePanel.filter(imp)
local me = OnlinePanel.mySeatId()
c.rooms, c.watch = {}, {}
c.rooms, c.watch, c.tours = {}, {}, {}
for _, entry in ipairs(open) do
if entry.id ~= me and entry.intent ~= "tournament"
and OnlinePanel.entryPasses(filter, entry) then
c.rooms[#c.rooms + 1] = roomRow(imp, entry, profile)
if entry.id ~= me and OnlinePanel.entryPasses(filter, entry) then
if entry.intent == "tournament" then
c.tours[#c.tours + 1] = roomRow(imp, entry, profile)
else
c.rooms[#c.rooms + 1] = roomRow(imp, entry, profile)
end
end
end
for _, entry in ipairs(watch) do
@@ -2839,10 +2880,14 @@ function OnlinePanel.update(imp, dt)
OnlinePanel._joinError = nil
end
if st.pending and st.pending.done then
if st.pending.error then
st.status, st.statusOk = tostring(st.pending.error), false
end
local pending = st.pending
st.pending = nil
if pending.error and pending.tourFallback
and pending.reason == "not_found" then
OnlinePanel.joinTournamentByCode(imp, pending.code, "spectator")
elseif pending.error then
st.status, st.statusOk = tostring(pending.error), false
end
end
local room = Client().room()
local tour = Client().tournament()
@@ -2903,6 +2948,20 @@ function OnlinePanel.autoReadyTrade(imp, room)
return OnlinePanel.sendReady(imp)
end
function OnlinePanel.spectateByCode(imp, code)
local st = OnlinePanel.state(imp)
code = OnlinePanel.sanitizeCode(code)
for _, entry in ipairs(Client().lobby() or {}) do
if entry.code == code and entry.intent == "tournament" then
return OnlinePanel.joinTournamentByCode(imp, code, "spectator")
end
end
if not OnlinePanel.joinByCode(imp, code, "spectator") then return false end
if st.pending then st.pending.tourFallback = true end
OnlinePanel.go(imp, "room")
return true
end
function OnlinePanel.joinByCode(imp, code, as)
local st = OnlinePanel.state(imp)
code = OnlinePanel.sanitizeCode(code)
+40 -2
View File
@@ -87,6 +87,8 @@ local function lobbyView(imp, x, y, w, m)
local version = OnlinePanel.engineVersion(imp)
local canPlay = online and profile ~= nil
and OnlinePanel.canBattleWith(version)
local c = OnlinePanel.cache(imp)
local rowH = math.max(m.rowH, Kit.tapMin())
local cy = y
LV().btn(imp, x, cy, w, btnH, "online-tour-host",
@@ -117,8 +119,44 @@ local function lobbyView(imp, x, y, w, m)
action = function()
OnlinePanel.joinTournamentByCode(imp, st.joinCode, "spectator")
end })
cy = cy + btnH + tiny
return cy - y
cy = cy + btnH + gap
local rows = c.tours or {}
cy = cy + Ui.label(Strings("Open tournaments"), x, cy) + tiny
if #rows == 0 then
Kit.emptyBox(x, cy, w, rowH, online
and Strings("No public tournaments right now.")
or Strings("Connect to see open tournaments."))
return (cy + rowH + gap) - y
end
local actW = math.floor(64 * m.s)
for _, row in ipairs(rows) do
local ink = LV().rowHit(imp, x, cy, w, rowH, false,
"online-tour-row-" .. row.id, nil)
local tx = x + math.floor(10 * m.s)
local textW = w - 2 * actW - math.floor(30 * m.s)
Kit.text("small", Kit.ellipsize("small", row.name, textW), tx,
cy + math.floor(5 * m.s), ink or PAL.heading)
Kit.text("micro", Kit.ellipsize("micro", row.sub, textW), tx,
cy + rowH - Kit.textHeight("micro") - math.floor(5 * m.s), PAL.muted)
local code, rule = row.code, row.ruleTable
LV().btn(imp, x + w - 2 * actW - gap - math.floor(6 * m.s),
cy + (rowH - btnH) / 2, actW, btnH, "online-tour-join-" .. row.id,
Strings("Join"),
{ kind = "accent", font = "small",
enabled = canPlay and row.stage == "waiting" and row.reason == nil,
action = function()
OnlinePanel.startJoinTournament(imp, code, rule)
end })
LV().btn(imp, x + w - actW - math.floor(6 * m.s), cy + (rowH - btnH) / 2,
actW, btnH, "online-tour-watch-" .. row.id, Strings("Watch"),
{ kind = "ghost", font = "small", enabled = online,
action = function()
OnlinePanel.joinTournamentByCode(imp, code, "spectator")
end })
cy = cy + rowH + tiny
end
return (cy + gap) - y
end
function Tournaments.draw(imp, x, y, w, availH, m)
+2 -2
View File
@@ -163,7 +163,7 @@ local function remoteTrade(imp, x, y, w, m)
end
local refusal = OnlinePanel.remoteTradeRefusal(imp)
if refusal then
if refusal and st.slotId then
cy = cy + Kit.textWrapped("small", refusal, x, cy, w, PAL.yellow, 3) + tiny
end
LV().btn(imp, x, cy, w, rowH, "online-trade-remote-start",
@@ -172,7 +172,7 @@ local function remoteTrade(imp, x, y, w, m)
action = function() OnlinePanel.startWizard(imp, "tradeRemote") end })
cy = cy + rowH + tiny
local note = tr.remoteError or tr.remoteResult or tr.status or st.status
local note = tr.remoteError or tr.remoteResult or tr.status
if note then
cy = cy + Kit.textWrapped("small", tostring(note), x, cy, w,
tr.remoteError and PAL.red or PAL.muted, 3) + tiny
+2 -12
View File
@@ -32,11 +32,7 @@ function Watch.draw(imp, x, y, w, availH, m)
"online-spectate-code", Strings("Spectate"),
{ kind = "primary", font = "small",
enabled = online and #st.joinCode == OnlinePanel.CODE_LEN,
action = function()
if OnlinePanel.joinByCode(imp, st.joinCode, "spectator") then
OnlinePanel.go(imp, "room")
end
end })
action = function() OnlinePanel.spectateByCode(imp, st.joinCode) end })
cy = cy + btnH + gap
local rows = c.watch
@@ -74,13 +70,7 @@ function Watch.draw(imp, x, y, w, availH, m)
cy + (rowH - btnH) / 2, watchW, btnH, "online-watch-go-" .. row.id,
tournament and Strings("Watch") or Strings("Spectate"),
{ kind = "accent", font = "small", enabled = online,
action = function()
if tournament then
OnlinePanel.joinTournamentByCode(imp, code, "spectator")
elseif OnlinePanel.joinByCode(imp, code, "spectator") then
OnlinePanel.go(imp, "room")
end
end })
action = function() OnlinePanel.spectateByCode(imp, code) end })
cy = cy + rowH + tiny
end
if #rows > perPage then
+9 -1
View File
@@ -182,6 +182,14 @@ local function stepTeam(imp, x, y, w, m)
x, cy, w, PAL.yellow, 2) + tiny
end
local target = st.wizard and st.wizard.kind == "join" and st.joinTarget
if target and type(target.rule) == "table" then
local want, have = OnlinePanel.teamCap(imp), #(st.team or {})
cy = cy + Kit.textWrapped("small",
Strings("Pick %d POKeMON (%d of %d picked) - %s", want, have, want,
OnlinePanel.ruleText(target.rule)),
x, cy, w, have == want and PAL.green or PAL.yellow, 2) + tiny
end
cy = cy + Ui.label(Strings("Your party"), x, cy) + tiny
if #c.party == 0 then
Kit.emptyBox(x, cy, w, rowH,
@@ -196,7 +204,7 @@ local function stepTeam(imp, x, y, w, m)
cy = cy + Wizard.monRow(imp, row, x, cy, listW, m, function()
st.focusMon = row.key
if row.refused then return end
OnlinePanel.toggleTeam(st.team, ref, OnlinePanel.TEAM_MAX)
OnlinePanel.toggleTeam(st.team, ref, OnlinePanel.teamCap(imp))
st.ready = false
OnlinePanel.invalidate(imp, "party", "summary")
end) + tiny
+7
View File
@@ -610,6 +610,13 @@ end
function Remote:update()
if self.link.update then self.link:update() end
local session = self.session
if (self.link.closed or self.link.paired == false)
and session.stage ~= "done" and session.stage ~= "cancelled" then
session.stage = "cancelled"
session.error = "the other trainer left"
return session.stage
end
local messages = self.link:poll() or {}
for _, msg in ipairs(messages) do
if type(msg) == "table" and type(msg.type) == "string" then
+130
View File
@@ -1699,4 +1699,134 @@ do
Client.room, Client.leaveRoom, Client.you = savedRoom, savedLeave, savedYou2
end
do
local simp = { ready = { red = true }, activeSlot = {}, slots = {}, pulse = 0,
_pages = {}, _uiActions = {}, _actAt = {} }
local sst = OnlinePanel.state(simp)
sst.version, sst.ready = "red", true
local savedJoin, savedTour, savedLobby =
Client.joinRoom, Client.joinTournament, Client.lobby
local roomJoins, tourJoins = {}, {}
local pendingRoom
Client.joinRoom = function(code, as)
roomJoins[#roomJoins + 1] = { code = code, as = as }
pendingRoom = { code = code, done = false }
return pendingRoom
end
Client.joinTournament = function(code, as)
tourJoins[#tourJoins + 1] = { code = code, as = as }
return { code = code, done = false }
end
Client.lobby = function()
return { { id = "t1", code = "TQURA2", intent = "tournament" } }
end
T.check(OnlinePanel.spectateByCode(simp, "tqura2"),
"spectating a listed tournament code")
T.eq(#tourJoins, 1, "goes straight to tour_join")
T.eq(tourJoins[1] and tourJoins[1].as, "spectator", "as a spectator")
T.eq(#roomJoins, 0, "with no room_join")
T.check(OnlinePanel.spectateByCode(simp, "RMBC23"),
"spectating an unlisted code")
T.eq(#roomJoins, 1, "tries the room first")
T.eq(OnlinePanel.screen(simp), "room", "on the Room screen")
pendingRoom.error, pendingRoom.reason, pendingRoom.done =
"That room code wasn't found.", "not_found", true
OnlinePanel.update(simp, 1 / 60)
T.eq(#tourJoins, 2, "and a not_found answer retries it as a tournament")
T.eq(tourJoins[2] and tourJoins[2].code, "RMBC23", "with the same code")
T.eq(sst.status, nil, "without surfacing the room miss as an error")
T.check(OnlinePanel.spectateByCode(simp, "RMCD34"), "another unlisted code")
pendingRoom.error, pendingRoom.reason, pendingRoom.done =
"That room is full.", "full", true
OnlinePanel.update(simp, 1 / 60)
T.eq(#tourJoins, 2, "other join errors do not retry")
T.eq(sst.status, "That room is full.", "and are shown")
Client.joinRoom, Client.joinTournament, Client.lobby =
savedJoin, savedTour, savedLobby
OnlinePanel.home(simp)
end
do
local jimp = { ready = { red = true }, activeSlot = {}, slots = {}, pulse = 0,
_pages = {}, _uiActions = {}, _actAt = {} }
local jst = OnlinePanel.state(jimp)
jst.version, jst.ready = "red", true
local savedLobby = Client.lobby
Client.lobby = function()
return { { id = "t1", code = "TQURA2", intent = "tournament",
profile = { rule = { partySize = 3 } } } }
end
T.check(OnlinePanel.startJoin(jimp, "tqura2"), "joining a listed code")
T.eq(jst.joinTarget.tournament, true, "learns it is a tournament")
T.eq(jst.joinTarget.rule.partySize, 3, "and picks up its rule")
T.eq(OnlinePanel.teamCap(jimp), 3, "so the team step caps at the rule")
local team = {}
for i = 1, 5 do
OnlinePanel.toggleTeam(team, { where = "party", index = i },
OnlinePanel.teamCap(jimp))
end
T.eq(#team, 3, "and refuses a fourth pick")
OnlinePanel.wizardTo(jimp, "team")
jst.team = { { where = "party", index = 1 } }
T.check(not OnlinePanel.wizardReady(jimp),
"the team step will not advance short of the count")
jst.team = team
T.check(OnlinePanel.wizardReady(jimp), "and advances at exactly the count")
OnlinePanel.home(jimp)
T.eq(OnlinePanel.teamCap(jimp), OnlinePanel.TEAM_MAX,
"outside the join wizard the cap is the full party")
Client.lobby = savedLobby
end
do
local dimp = { ready = { red = true }, activeSlot = {}, slots = {}, pulse = 0,
_pages = {}, _uiActions = {}, _actAt = {} }
local dst = OnlinePanel.state(dimp)
dst.version, dst.ready = "red", true
local tr = OnlinePanel.tradeState(dimp)
local closed, left = 0, 0
local savedLeave, savedRoom = Client.leaveRoom, Client.room
Client.leaveRoom = function() left = left + 1 return true end
Client.room = function() return nil end
tr.mode, tr.chosen = "remote", true
OnlinePanel.go(dimp, "trade")
tr.remote = { handle = { path = "x", version = "red", party = {} },
session = {},
update = function() return "done" end,
commit = function() return true end,
close = function() closed = closed + 1 end }
OnlinePanel.pumpRemoteTrade(dimp)
T.eq(tr.remote, nil, "a finished trade closes the remote session")
T.eq(closed, 1, "closing the link")
T.eq(left, 1, "and leaving the room")
T.eq(OnlinePanel.screen(dimp), "home", "then lands on Home")
T.eq(dst.status, "Trade complete.", "saying the trade completed")
T.eq(dst.statusOk, true, "as good news")
OnlinePanel.go(dimp, "trade")
T.eq(tr.remoteResult, nil, "reopening Trade forgets the old result")
T.eq(tr.status, nil, "and any stale trade status")
Client.leaveRoom, Client.room = savedLeave, savedRoom
end
do
local Trade = require("src.online.Trade")
local link = { closed = false, paired = true, sent = {},
send = function(self, m) self.sent[#self.sent + 1] = m end,
poll = function() return {} end, close = function() end }
local Protocol = require("src.link.Protocol")
local remote = setmetatable({
handle = { generation = 1, party = {} }, link = link,
session = { stage = "waitPick", handle = function() return nil end },
}, getmetatable(Trade.remote({ data = {}, party = {} }, link) or {}))
T.eq(remote:update(), "waitPick", "a live link keeps the trade going")
link.paired = false
T.eq(remote:update(), "cancelled", "the other trainer leaving calls it off")
T.eq(remote.session.error, "the other trainer left", "with a reason")
link.paired, link.closed = true, true
remote.session.stage = "done"
T.eq(remote:update(), "done", "but a finished trade stays finished")
end
T.finish("online panel")