Commit 6a8271cd authored by nanahira's avatar nanahira

finish

parent 06448cb3
......@@ -28,7 +28,7 @@
"ygopro-cdb-encode": "^1.0.2",
"ygopro-deck-encode": "^1.0.15",
"ygopro-lflist-encode": "^1.0.3",
"ygopro-msg-encode": "^1.1.14",
"ygopro-msg-encode": "^1.1.17",
"ygopro-yrp-encode": "^1.0.1",
"yuzuthread": "^1.0.8"
},
......@@ -7448,9 +7448,9 @@
}
},
"node_modules/ygopro-msg-encode": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/ygopro-msg-encode/-/ygopro-msg-encode-1.1.14.tgz",
"integrity": "sha512-IUdzJThpZhHMY4y1ob4sYvgKrlyKghblZOdYuUUeta4ujzUsKqBCIaUXu67ypH/TTH541Nu5iLaBtWZ0HfZR8Q==",
"version": "1.1.17",
"resolved": "https://registry.npmjs.org/ygopro-msg-encode/-/ygopro-msg-encode-1.1.17.tgz",
"integrity": "sha512-pKEpSALssb7t+69dsXqMJy0sdazqY141Qyyr6tw8AVwRKD7oDKNFeAOP4Qo8QeJfYBmF3MrT4CqvAfbhg1WeLA==",
"license": "MIT",
"dependencies": {
"typed-reflector": "^1.0.14",
......
......@@ -32,7 +32,7 @@ import { OcgcoreWorkerOptions } from './ocgcore-worker-options';
import { Subject } from 'rxjs';
import { calculateDuelOptions } from '../utility/calculate-duel-options';
import initSqlJs from 'sql.js';
import { YGOProMessages } from 'ygopro-msg-encode';
import { YGOProMessages, YGOProMsgResponseBase, YGOProMsgRetry } from 'ygopro-msg-encode';
const { OcgcoreScriptConstants } = _OcgcoreConstants;
......@@ -308,11 +308,22 @@ export class OcgcoreWorker {
async *advance() {
while (true) {
const res = await this.process();
if (!res.raw.length) {
if (res.raw.length === 0) {
continue;
}
yield res;
if (res.status > 0) {
if (res.status === 2) {
break;
}
if (res.message instanceof YGOProMsgRetry) {
break;
}
if (res.message instanceof YGOProMsgResponseBase) {
break;
}
}
......
......@@ -84,6 +84,7 @@ import {
splitRefreshLocations,
} from '../utility/refresh-query';
import { shuffleDecksBySeed } from '../utility/shuffle-decks-by-seed';
import { isUpdateMessage } from '../utility/is-update-message';
const { OcgcoreScriptConstants } = _OcgcoreConstants;
......@@ -183,10 +184,7 @@ export class Room {
]);
}
private finalizors: RoomFinalizor[] = [
() => this.cleanPlayers(),
() => this.ocgcore?.dispose(),
];
private finalizors: RoomFinalizor[] = [() => this.ocgcore?.dispose()];
addFinalizor(finalizor: RoomFinalizor, atEnd = false) {
if (atEnd) {
......@@ -198,11 +196,12 @@ export class Room {
}
finalizing = false;
async finalize() {
async finalize(sendReplays = false) {
if (this.finalizing) {
return;
}
this.finalizing = true;
await this.cleanPlayers(sendReplays);
while (this.finalizors.length) {
const finalizor = this.finalizors.pop()!;
await finalizor(this);
......@@ -408,6 +407,9 @@ export class Room {
if (lastDuelRecord) {
lastDuelRecord.winPosition = duelPos;
}
this.logger.debug(
`Player ${duelPos} wins the duel. Current score: ${this.score.join('-')}`,
);
const winMatch = forceWinMatch || this.score[duelPos] >= this.winMatchCount;
if (!winMatch) {
await this.changeSide();
......@@ -417,8 +419,7 @@ export class Room {
this.getDuelPosPlayers(duelPos)[0],
);
if (winMatch) {
await this.cleanPlayers(true);
return this.finalize();
return this.finalize(true);
}
}
......@@ -1071,6 +1072,17 @@ export class Room {
this.getOpreatingPlayer(this.turnPos),
);
await Promise.all([
this.refreshLocations({
player: 0,
location: OcgcoreScriptConstants.LOCATION_EXTRA,
}),
this.refreshLocations({
player: 1,
location: OcgcoreScriptConstants.LOCATION_EXTRA,
}),
]);
return this.advance();
}
......@@ -1166,10 +1178,25 @@ export class Room {
}
}
private async refreshForMessage(message: YGOProMsgBase) {
await Promise.all([
...message.getRequireRefreshCards().map((loc) => this.refreshSingle(loc)),
...message
.getRequireRefreshZones()
.map((loc) => this.refreshLocations(loc)),
]);
}
private async routeGameMsg(message: YGOProMsgBase) {
if (!message) {
return;
}
const shouldRefreshFirst =
message instanceof YGOProMsgResponseBase && !isUpdateMessage(message);
if (shouldRefreshFirst) {
await this.refreshForMessage(message);
}
const sendTargets = message.getSendTargets();
const sendGameMsg = (c: Client, msg: YGOProMsgBase) =>
c.send(new YGOProStocGameMsg().fromPartial({ msg }));
......@@ -1181,32 +1208,25 @@ export class Room {
[...this.watchers].map((w) => sendGameMsg(w, observerView)),
);
} else {
const playerView = message.playerView(pos);
const players = this.getIngameDuelPosPlayers(pos);
const operatingPlayer = this.getOpreatingPlayer(pos);
await Promise.all(
players.map((c) =>
sendGameMsg(
players.map((c) => {
const duelPos = this.getIngameDuelPos(c);
const playerView = message.playerView(duelPos);
const operatingPlayer = this.getOpreatingPlayer(duelPos);
return sendGameMsg(
c,
c === operatingPlayer ? playerView : playerView.teammateView(),
),
),
);
}),
);
}
}),
);
if (
message instanceof YGOProMsgUpdateData ||
message instanceof YGOProMsgUpdateCard
) {
if (isUpdateMessage(message) || shouldRefreshFirst) {
return;
}
await Promise.all([
...message.getRequireRefreshCards().map((loc) => this.refreshSingle(loc)),
...message
.getRequireRefreshZones()
.map((loc) => this.refreshLocations(loc)),
]);
await this.refreshForMessage(message);
}
private async handleGameMsg(message: YGOProMsgBase, route = false) {
......@@ -1319,6 +1339,15 @@ export class Room {
}
}
if (message instanceof YGOProMsgUpdateCard) {
await this.refreshSingle({
player: message.controller,
location: message.location,
sequence: message.sequence,
});
continue;
}
const handled = await this.handleGameMsg(message);
if (handled instanceof YGOProMsgWin) {
return this.win(handled);
......@@ -1356,9 +1385,6 @@ export class Room {
return;
}
// TODO: teammate surrender in tag duel
return this.win(
{ player: 1 - this.getIngameDuelPos(client), type: 0x0 },
true,
);
return this.win({ player: 1 - this.getIngameDuelPos(client), type: 0x0 });
}
}
import {
YGOProMsgBase,
YGOProMsgUpdateCard,
YGOProMsgUpdateData,
} from 'ygopro-msg-encode';
export const isUpdateMessage = (message: YGOProMsgBase) =>
message instanceof YGOProMsgUpdateData ||
message instanceof YGOProMsgUpdateCard;
import YGOProDeck from 'ygopro-deck-encode';
const UINT32_RANGE = 0x1_0000_0000;
const createSeededRng = (seed: number[]) => {
let state = 0x9e37_79b9;
for (const value of seed) {
state = (Math.imul(state ^ (value >>> 0), 1664525) + 1013904223) >>> 0;
}
if (state === 0) {
state = 1;
}
return () => {
state ^= state << 13;
state >>>= 0;
state ^= state >>> 17;
state ^= state << 5;
return state >>> 0;
};
};
const nextInt = (nextU32: () => number, maxExclusive: number) => {
if (maxExclusive <= 1) {
return 0;
}
const bound = UINT32_RANGE - (UINT32_RANGE % maxExclusive);
let value = nextU32();
while (value >= bound) {
value = nextU32();
}
return value % maxExclusive;
};
const shuffleMainDeck = (main: number[], nextU32: () => number) => {
for (let i = main.length - 1; i > 0; --i) {
const j = nextInt(nextU32, i + 1);
[main[i], main[j]] = [main[j], main[i]];
}
};
export const shuffleDecksBySeed = (decks: YGOProDeck[], seed: number[]) => {
const nextU32 = createSeededRng(seed);
return decks.map((deck) => {
const cloned = new YGOProDeck(deck);
shuffleMainDeck(cloned.main, nextU32);
return cloned;
});
};
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