Commit b658bd0a authored by purerosefallen's avatar purerosefallen

fix menu and tcp

parent ab857f6c
......@@ -12,6 +12,7 @@ lerna-debug.log*
# OS
.DS_Store
._*
# Tests
/coverage
......
......@@ -36,6 +36,25 @@ export class TcpServer {
}
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 handler = this.ctx.get(() => ClientHandler);
handler.handleClient(client).catch((err) => {
......
......@@ -168,7 +168,11 @@ export class CloudReplayService {
player.score = resolvePlayerScore(room, client);
player.startDeckBuffer = encodeDeckBase64(client.startDeck);
player.startDeckMainc = resolveStartDeckMainc(client);
player.currentDeckBuffer = encodeCurrentDeckBase64(room, client, wasSwapped);
player.currentDeckBuffer = encodeCurrentDeckBase64(
room,
client,
wasSwapped,
);
player.currentDeckMainc = resolveCurrentDeckMainc(room, client, wasSwapped);
player.ingameDeckBuffer = encodeIngameDeckBase64(room, client, wasSwapped);
player.ingameDeckMainc = resolveIngameDeckMainc(room, client, wasSwapped);
......@@ -201,44 +205,45 @@ export class CloudReplayService {
}
private async renderReplayListMenu(client: Client) {
const page = await this.getReplayPage(client);
if (!page.entries.length) {
await client.die('#{cloud_replay_no}', ChatColor.RED);
return;
}
const menu: MenuEntry[] = [];
if (!this.isFirstReplayPage(client)) {
menu.push({
title: '#{menu_prev_page}',
callback: async (currentClient) => {
this.goToPrevReplayPage(currentClient);
await this.renderReplayListMenu(currentClient);
},
});
}
await this.menuManager.launchMenu(client, async () => {
const page = await this.getReplayPage(client);
if (!page.entries.length) {
await client.die('#{cloud_replay_no}', ChatColor.RED);
return;
}
for (const replay of page.entries) {
menu.push({
title: this.formatDate(replay.endTime),
callback: async (currentClient) => {
currentClient.cloudReplaySelectedReplayId = replay.id;
await this.renderReplayDetailMenu(currentClient, replay.id);
},
});
}
const menu: MenuEntry[] = [];
if (!this.isFirstReplayPage(client)) {
menu.push({
title: '#{menu_prev_page}',
callback: async (currentClient) => {
this.goToPrevReplayPage(currentClient);
await this.renderReplayListMenu(currentClient);
},
});
}
if (page.hasNext && page.nextCursor != null) {
menu.push({
title: '#{menu_next_page}',
callback: async (currentClient) => {
this.goToNextReplayPage(currentClient, page.nextCursor!);
await this.renderReplayListMenu(currentClient);
},
});
}
for (const replay of page.entries) {
menu.push({
title: this.formatDate(replay.endTime),
callback: async (currentClient) => {
currentClient.cloudReplaySelectedReplayId = replay.id;
await this.renderReplayDetailMenu(currentClient, replay.id);
},
});
}
await this.menuManager.launchMenu(client, menu);
if (page.hasNext && page.nextCursor != null) {
menu.push({
title: '#{menu_next_page}',
callback: async (currentClient) => {
this.goToNextReplayPage(currentClient, page.nextCursor!);
await this.renderReplayListMenu(currentClient);
},
});
}
return menu;
});
}
private async renderReplayDetailMenu(client: Client, replayId: number) {
......@@ -297,10 +302,22 @@ export class CloudReplayService {
const score = this.formatReplayScore(replay);
const winners = this.formatReplayWinners(replay);
await client.sendChat(`#{cloud_replay_detail_time}${dateText}`, 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);
await client.sendChat(
`#{cloud_replay_detail_time}${dateText}`,
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(
......@@ -440,11 +457,7 @@ export class CloudReplayService {
return {
...hostInfo,
mode:
hostInfo.mode > 2
? this.isTagMode(hostInfo)
? 2
: 1
: hostInfo.mode,
hostInfo.mode > 2 ? (this.isTagMode(hostInfo) ? 2 : 1) : hostInfo.mode,
};
}
......@@ -471,11 +484,7 @@ export class CloudReplayService {
for (const player of sortedPlayers) {
const deckBuffer = player.ingameDeckBuffer || player.currentDeckBuffer;
const mainc = player.ingameDeckMainc ?? player.currentDeckMainc ?? 0;
const ingamePos = resolveIngamePosBySeat(
player.pos,
isTag,
wasSwapped,
);
const ingamePos = resolveIngamePosBySeat(player.pos, isTag, wasSwapped);
players[ingamePos] = {
name: player.name,
deck: decodeDeckBase64(deckBuffer, mainc),
......@@ -692,10 +701,10 @@ export class CloudReplayService {
const teamOffsetBit = isTag ? 1 : 0;
const team0 = sortedPlayers.filter(
(player) => ((player.pos & (0x1 << teamOffsetBit)) >> teamOffsetBit) === 0,
(player) => (player.pos & (0x1 << teamOffsetBit)) >> teamOffsetBit === 0,
);
const team1 = sortedPlayers.filter(
(player) => ((player.pos & (0x1 << teamOffsetBit)) >> teamOffsetBit) === 1,
(player) => (player.pos & (0x1 << teamOffsetBit)) >> teamOffsetBit === 1,
);
return [team0, team1] as const;
}
......
......@@ -12,12 +12,15 @@ import { Context } from '../app';
import { Chnroute, Client, I18nService } from '../client';
import { DefaultHostinfo } from '../room';
import { resolvePanelPageLayout } from '../utility';
import { Awaitable } from 'nfkit';
export type MenuEntry = {
title: string;
callback: (client: Client) => Promise<unknown> | unknown;
};
export type MenuFactory = (client: Client) => Awaitable<MenuEntry[]>;
type MenuAction =
| {
type: 'entry';
......@@ -79,10 +82,8 @@ export class MenuManager {
});
}
async launchMenu(client: Client, menu: MenuEntry[]) {
client.currentMenu = menu.filter(
(entry): entry is MenuEntry => !!entry,
);
async launchMenu(client: Client, menu: MenuFactory | MenuEntry[]) {
client.currentMenu = Array.isArray(menu) ? () => menu : menu;
if (client.menuOffset == null) {
client.menuOffset = 0;
}
......@@ -91,13 +92,12 @@ export class MenuManager {
clearMenu(client: Client) {
client.currentMenu = undefined;
client.currentMenuView = undefined;
client.menuOffset = undefined;
}
private buildMenuView(client: Client): MenuView {
const menu = (client.currentMenu || []).filter(
(entry): entry is MenuEntry => !!entry,
);
private async buildMenuView(client: Client): Promise<MenuView> {
const menu = (await client.currentMenu!(client)) || [];
if (menu.length <= 2) {
return {
actions: menu.map((entry) => ({ type: 'entry', entry })),
......@@ -163,23 +163,30 @@ export class MenuManager {
return;
}
const view = this.buildMenuView(client);
await client.send(
new YGOProStocJoinGame().fromPartial({
info: {
...DefaultHostinfo,
mode: view.mode,
},
}),
);
await client.send(
new YGOProStocTypeChange().fromPartial({
type: NetPlayerType.OBSERVER | 0x10,
}),
);
const view = await this.buildMenuView(client);
client.currentMenuView = view;
if (
!client.maxRenderedMenuSlots ||
client.maxRenderedMenuSlots < view.slotCount
) {
client.maxRenderedMenuSlots = view.slotCount;
await client.send(
new YGOProStocJoinGame().fromPartial({
info: {
...DefaultHostinfo,
mode: view.mode,
},
}),
);
await client.send(
new YGOProStocTypeChange().fromPartial({
type: NetPlayerType.OBSERVER | 0x10,
}),
);
}
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 rawTitle =
action?.type === 'entry' ? action.entry.title : action?.title || '';
......@@ -196,11 +203,11 @@ export class MenuManager {
}
private async handleKick(client: Client, index: number) {
if (!client.currentMenu) {
if (!client.currentMenuView) {
return;
}
const view = this.buildMenuView(client);
const view = client.currentMenuView;
const selected = view.actions[index];
if (!selected) {
await this.renderMenu(client);
......@@ -221,7 +228,9 @@ export class MenuManager {
declare module '../client' {
interface Client {
currentMenu?: MenuEntry[];
currentMenu?: MenuFactory;
currentMenuView?: MenuView;
maxRenderedMenuSlots?: 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