Commit 6a8271cd authored by nanahira's avatar nanahira

finish

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