Commit b658bd0a authored by purerosefallen's avatar purerosefallen

fix menu and tcp

parent ab857f6c
...@@ -12,6 +12,7 @@ lerna-debug.log* ...@@ -12,6 +12,7 @@ lerna-debug.log*
# OS # OS
.DS_Store .DS_Store
._*
# Tests # Tests
/coverage /coverage
......
...@@ -36,6 +36,25 @@ export class TcpServer { ...@@ -36,6 +36,25 @@ export class TcpServer {
} }
private handleConnection(socket: Socket): void { private handleConnection(socket: Socket): void {
socket.on('error', (err: NodeJS.ErrnoException) => {
if (err.code === 'ECONNRESET') {
this.logger.debug(
{ remoteAddress: socket.remoteAddress, remotePort: socket.remotePort },
'TCP socket reset by peer',
);
return;
}
this.logger.warn(
{
err,
remoteAddress: socket.remoteAddress,
remotePort: socket.remotePort,
},
'TCP socket error',
);
});
const client = new TcpClient(this.ctx, socket); const client = new TcpClient(this.ctx, socket);
const handler = this.ctx.get(() => ClientHandler); const handler = this.ctx.get(() => ClientHandler);
handler.handleClient(client).catch((err) => { handler.handleClient(client).catch((err) => {
......
...@@ -168,7 +168,11 @@ export class CloudReplayService { ...@@ -168,7 +168,11 @@ export class CloudReplayService {
player.score = resolvePlayerScore(room, client); player.score = resolvePlayerScore(room, client);
player.startDeckBuffer = encodeDeckBase64(client.startDeck); player.startDeckBuffer = encodeDeckBase64(client.startDeck);
player.startDeckMainc = resolveStartDeckMainc(client); player.startDeckMainc = resolveStartDeckMainc(client);
player.currentDeckBuffer = encodeCurrentDeckBase64(room, client, wasSwapped); player.currentDeckBuffer = encodeCurrentDeckBase64(
room,
client,
wasSwapped,
);
player.currentDeckMainc = resolveCurrentDeckMainc(room, client, wasSwapped); player.currentDeckMainc = resolveCurrentDeckMainc(room, client, wasSwapped);
player.ingameDeckBuffer = encodeIngameDeckBase64(room, client, wasSwapped); player.ingameDeckBuffer = encodeIngameDeckBase64(room, client, wasSwapped);
player.ingameDeckMainc = resolveIngameDeckMainc(room, client, wasSwapped); player.ingameDeckMainc = resolveIngameDeckMainc(room, client, wasSwapped);
...@@ -201,6 +205,7 @@ export class CloudReplayService { ...@@ -201,6 +205,7 @@ export class CloudReplayService {
} }
private async renderReplayListMenu(client: Client) { private async renderReplayListMenu(client: Client) {
await this.menuManager.launchMenu(client, async () => {
const page = await this.getReplayPage(client); const page = await this.getReplayPage(client);
if (!page.entries.length) { if (!page.entries.length) {
await client.die('#{cloud_replay_no}', ChatColor.RED); await client.die('#{cloud_replay_no}', ChatColor.RED);
...@@ -237,8 +242,8 @@ export class CloudReplayService { ...@@ -237,8 +242,8 @@ export class CloudReplayService {
}, },
}); });
} }
return menu;
await this.menuManager.launchMenu(client, menu); });
} }
private async renderReplayDetailMenu(client: Client, replayId: number) { private async renderReplayDetailMenu(client: Client, replayId: number) {
...@@ -297,10 +302,22 @@ export class CloudReplayService { ...@@ -297,10 +302,22 @@ export class CloudReplayService {
const score = this.formatReplayScore(replay); const score = this.formatReplayScore(replay);
const winners = this.formatReplayWinners(replay); const winners = this.formatReplayWinners(replay);
await client.sendChat(`#{cloud_replay_detail_time}${dateText}`, ChatColor.BABYBLUE); await client.sendChat(
await client.sendChat(`#{cloud_replay_detail_players}${versus}`, ChatColor.BABYBLUE); `#{cloud_replay_detail_time}${dateText}`,
await client.sendChat(`#{cloud_replay_detail_score}${score}`, ChatColor.BABYBLUE); ChatColor.BABYBLUE,
await client.sendChat(`#{cloud_replay_detail_winner}${winners}`, ChatColor.BABYBLUE); );
await client.sendChat(
`#{cloud_replay_detail_players}${versus}`,
ChatColor.BABYBLUE,
);
await client.sendChat(
`#{cloud_replay_detail_score}${score}`,
ChatColor.BABYBLUE,
);
await client.sendChat(
`#{cloud_replay_detail_winner}${winners}`,
ChatColor.BABYBLUE,
);
} }
private async playReplayStream( private async playReplayStream(
...@@ -440,11 +457,7 @@ export class CloudReplayService { ...@@ -440,11 +457,7 @@ export class CloudReplayService {
return { return {
...hostInfo, ...hostInfo,
mode: mode:
hostInfo.mode > 2 hostInfo.mode > 2 ? (this.isTagMode(hostInfo) ? 2 : 1) : hostInfo.mode,
? this.isTagMode(hostInfo)
? 2
: 1
: hostInfo.mode,
}; };
} }
...@@ -471,11 +484,7 @@ export class CloudReplayService { ...@@ -471,11 +484,7 @@ export class CloudReplayService {
for (const player of sortedPlayers) { for (const player of sortedPlayers) {
const deckBuffer = player.ingameDeckBuffer || player.currentDeckBuffer; const deckBuffer = player.ingameDeckBuffer || player.currentDeckBuffer;
const mainc = player.ingameDeckMainc ?? player.currentDeckMainc ?? 0; const mainc = player.ingameDeckMainc ?? player.currentDeckMainc ?? 0;
const ingamePos = resolveIngamePosBySeat( const ingamePos = resolveIngamePosBySeat(player.pos, isTag, wasSwapped);
player.pos,
isTag,
wasSwapped,
);
players[ingamePos] = { players[ingamePos] = {
name: player.name, name: player.name,
deck: decodeDeckBase64(deckBuffer, mainc), deck: decodeDeckBase64(deckBuffer, mainc),
...@@ -692,10 +701,10 @@ export class CloudReplayService { ...@@ -692,10 +701,10 @@ export class CloudReplayService {
const teamOffsetBit = isTag ? 1 : 0; const teamOffsetBit = isTag ? 1 : 0;
const team0 = sortedPlayers.filter( const team0 = sortedPlayers.filter(
(player) => ((player.pos & (0x1 << teamOffsetBit)) >> teamOffsetBit) === 0, (player) => (player.pos & (0x1 << teamOffsetBit)) >> teamOffsetBit === 0,
); );
const team1 = sortedPlayers.filter( const team1 = sortedPlayers.filter(
(player) => ((player.pos & (0x1 << teamOffsetBit)) >> teamOffsetBit) === 1, (player) => (player.pos & (0x1 << teamOffsetBit)) >> teamOffsetBit === 1,
); );
return [team0, team1] as const; return [team0, team1] as const;
} }
......
...@@ -12,12 +12,15 @@ import { Context } from '../app'; ...@@ -12,12 +12,15 @@ import { Context } from '../app';
import { Chnroute, Client, I18nService } from '../client'; import { Chnroute, Client, I18nService } from '../client';
import { DefaultHostinfo } from '../room'; import { DefaultHostinfo } from '../room';
import { resolvePanelPageLayout } from '../utility'; import { resolvePanelPageLayout } from '../utility';
import { Awaitable } from 'nfkit';
export type MenuEntry = { export type MenuEntry = {
title: string; title: string;
callback: (client: Client) => Promise<unknown> | unknown; callback: (client: Client) => Promise<unknown> | unknown;
}; };
export type MenuFactory = (client: Client) => Awaitable<MenuEntry[]>;
type MenuAction = type MenuAction =
| { | {
type: 'entry'; type: 'entry';
...@@ -79,10 +82,8 @@ export class MenuManager { ...@@ -79,10 +82,8 @@ export class MenuManager {
}); });
} }
async launchMenu(client: Client, menu: MenuEntry[]) { async launchMenu(client: Client, menu: MenuFactory | MenuEntry[]) {
client.currentMenu = menu.filter( client.currentMenu = Array.isArray(menu) ? () => menu : menu;
(entry): entry is MenuEntry => !!entry,
);
if (client.menuOffset == null) { if (client.menuOffset == null) {
client.menuOffset = 0; client.menuOffset = 0;
} }
...@@ -91,13 +92,12 @@ export class MenuManager { ...@@ -91,13 +92,12 @@ export class MenuManager {
clearMenu(client: Client) { clearMenu(client: Client) {
client.currentMenu = undefined; client.currentMenu = undefined;
client.currentMenuView = undefined;
client.menuOffset = undefined; client.menuOffset = undefined;
} }
private buildMenuView(client: Client): MenuView { private async buildMenuView(client: Client): Promise<MenuView> {
const menu = (client.currentMenu || []).filter( const menu = (await client.currentMenu!(client)) || [];
(entry): entry is MenuEntry => !!entry,
);
if (menu.length <= 2) { if (menu.length <= 2) {
return { return {
actions: menu.map((entry) => ({ type: 'entry', entry })), actions: menu.map((entry) => ({ type: 'entry', entry })),
...@@ -163,7 +163,13 @@ export class MenuManager { ...@@ -163,7 +163,13 @@ export class MenuManager {
return; return;
} }
const view = this.buildMenuView(client); const view = await this.buildMenuView(client);
client.currentMenuView = view;
if (
!client.maxRenderedMenuSlots ||
client.maxRenderedMenuSlots < view.slotCount
) {
client.maxRenderedMenuSlots = view.slotCount;
await client.send( await client.send(
new YGOProStocJoinGame().fromPartial({ new YGOProStocJoinGame().fromPartial({
info: { info: {
...@@ -177,9 +183,10 @@ export class MenuManager { ...@@ -177,9 +183,10 @@ export class MenuManager {
type: NetPlayerType.OBSERVER | 0x10, type: NetPlayerType.OBSERVER | 0x10,
}), }),
); );
}
const locale = this.chnroute.getLocale(client.ip); const locale = this.chnroute.getLocale(client.ip);
for (let i = 0; i < view.slotCount; i++) { for (let i = 0; i < client.maxRenderedMenuSlots; i++) {
const action = view.actions[i]; const action = view.actions[i];
const rawTitle = const rawTitle =
action?.type === 'entry' ? action.entry.title : action?.title || ''; action?.type === 'entry' ? action.entry.title : action?.title || '';
...@@ -196,11 +203,11 @@ export class MenuManager { ...@@ -196,11 +203,11 @@ export class MenuManager {
} }
private async handleKick(client: Client, index: number) { private async handleKick(client: Client, index: number) {
if (!client.currentMenu) { if (!client.currentMenuView) {
return; return;
} }
const view = this.buildMenuView(client); const view = client.currentMenuView;
const selected = view.actions[index]; const selected = view.actions[index];
if (!selected) { if (!selected) {
await this.renderMenu(client); await this.renderMenu(client);
...@@ -221,7 +228,9 @@ export class MenuManager { ...@@ -221,7 +228,9 @@ export class MenuManager {
declare module '../client' { declare module '../client' {
interface Client { interface Client {
currentMenu?: MenuEntry[]; currentMenu?: MenuFactory;
currentMenuView?: MenuView;
maxRenderedMenuSlots?: number;
menuOffset?: number; menuOffset?: number;
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment