feedback5 WK: 自选编队 on the server — room.diy { picks } (lenient: illegal picks dropped, only malformed input is BAD_MSG; stored per session / seat; a match takes the picks its seat had at the start, a change during a match is for the next one; welcome lists diyKitted), PlayerState.diy with the player's data view (a slotted DIY slot is its operator for every rule: bonds from its factions, no 特质, the pick's skill and module, the slot's tier / price / merge), a per-player stock per slotted piece (8 at tier 5, 5 at tier 6 [ASSUMED]; never in the shared pool; none when every bond of it is banned), DIY pieces in that player's shop rolls and reward offers once the 调度中心 reaches the slot's level, battleInput diy, m.private.diy / diyBanned, prep scouting and results name the operator, 信标 never sends a 自选 piece to a teammate [ASSUMED]
The owner's decisions of 2026-10-05 (picks, slots, shop per player, bans); research 0.2.0 §2. Golden unchanged (no scenario slots a DIY pick). Tests: test/match/diy-shop.test.js (9), test/lobby-diy.test.js (4).
This commit is contained in:
1 parent
742f478526
commit
4bee542e61
26 files changed
+1026
-105
No files matched your search
+10
-4
@@ -29,6 +29,8 @@
|
||||
//
|
||||
// The handler object (implemented by server/lobby.js) receives:
|
||||
// onHello(session, { resumed, repeat }) after `welcome` was sent
|
||||
// welcomeInfo() → object (optional) extra fields of every `welcome` (never one of its own keys): the lobby's
|
||||
// `diyKitted` (0.2.0 自选编队 — which operators a DIY slot may field)
|
||||
// onMessage(session, msg) → { ok: true } | { error: ERR code, detail?: string } | undefined
|
||||
// routeGame(session, msg) → same (optional): client-side combat reports `b.progress` / `b.result` (DESIGN §14) go
|
||||
// straight to the running match through it; without it they reach onMessage
|
||||
@@ -61,10 +63,10 @@ export const NET_DEFAULTS = Object.freeze({
|
||||
/**
|
||||
* Intents that also draw from the per-connection heavy bucket: g.watch (its reply is a large state resend, m.field),
|
||||
* room.loadout (a ≤ 160-entry map validated against the game data; the client debounces its edits), room.ownership
|
||||
* (a ≤ 160-id list, the same way) and room.spectate
|
||||
* (a ≤ 160-id list, the same way), room.diy (≤ 8 自选 picks checked against the data, the same way) and room.spectate
|
||||
* (taking a spectator seat in a running match resends its state like a watcher's g.watch — server/lobby.js spectate).
|
||||
*/
|
||||
export const HEAVY_TYPES = new Set(['g.watch', 'room.loadout', 'room.ownership', 'room.spectate']);
|
||||
export const HEAVY_TYPES = new Set(['g.watch', 'room.loadout', 'room.ownership', 'room.diy', 'room.spectate']);
|
||||
|
||||
/** Close codes (see header). */
|
||||
export const CLOSE = Object.freeze({ REPLACED: 4001, HELLO_TIMEOUT: 4002, POLICY: 1008, SHUTDOWN: 1001 });
|
||||
@@ -109,6 +111,8 @@ export class Session {
|
||||
this.loadout = null;
|
||||
/** @type {readonly string[] | null} checked not-owned chess ids (干员持有, lobby-owned, 0.2.0 补位) */
|
||||
this.notOwned = null;
|
||||
/** @type {Readonly<Record<string, { charId: string, skillIndex: number, uniEquipId: string|null }>> | null} checked 自选 picks (lobby-owned, 0.2.0 自选编队) */
|
||||
this.diy = null;
|
||||
/** @type {string} client address of the latest connection (logging) */
|
||||
this.addr = '?';
|
||||
/** @type {string | null} per-network limit key of the latest connection (null = not limited), see clientAddress */
|
||||
@@ -500,7 +504,7 @@ export class Network {
|
||||
/**
|
||||
* @param {{
|
||||
* registry: SessionRegistry,
|
||||
* handler: { onHello?: Function, onMessage: Function, onDisconnect?: Function, onExpire?: Function },
|
||||
* handler: { onHello?: Function, onMessage: Function, onDisconnect?: Function, onExpire?: Function, welcomeInfo?: Function },
|
||||
* log?: { info: Function, warn: Function, error: Function, debug?: Function },
|
||||
* now?: () => number,
|
||||
* options?: Partial<typeof NET_DEFAULTS>,
|
||||
@@ -656,7 +660,9 @@ export class Network {
|
||||
session.addr = conn.ip;
|
||||
session.limitKey = conn.key;
|
||||
|
||||
const welcome = { t: 'welcome', playerId: session.playerId, token: session.token, name: session.name, serverNow: now, version: PROTOCOL_VERSION, resumed };
|
||||
let extra = null;
|
||||
try { extra = this.handler.welcomeInfo?.() ?? null; } catch (e) { this.log.error('[net] welcomeInfo crashed', e); }
|
||||
const welcome = { ...(extra && typeof extra === 'object' ? extra : null), t: 'welcome', playerId: session.playerId, token: session.token, name: session.name, serverNow: now, version: PROTOCOL_VERSION, resumed };
|
||||
if (validRid(rid)) welcome.rid = rid;
|
||||
this.reply(conn, welcome);
|
||||
try {
|
||||
|
||||
Reference in new issue
Block a user