Skip to content

Commit ea714ac

Browse files
committed
Use MessageChannel for communication, don't recreate workers, tighten up types.
GitOrigin-RevId: d97f45eab7ac4297d7bfa5d6d9186e5ab2f537c1
1 parent 637fdcd commit ea714ac

File tree

3 files changed

+81
-49
lines changed

3 files changed

+81
-49
lines changed

hera/hooks/useClientGameAction.tsx

+39-27
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,18 @@ import encodeGameActionResponse from '@deities/apollo/actions/encodeGameActionRe
55
import {
66
decodeEffects,
77
Effects,
8-
EncodedEffects,
98
encodeEffects,
109
} from '@deities/apollo/Effects.tsx';
1110
import {
1211
decodeActionResponse,
1312
encodeAction,
14-
EncodedActionResponse,
1513
} from '@deities/apollo/EncodedActions.tsx';
1614
import { decodeGameState } from '@deities/apollo/GameState.tsx';
1715
import { computeVisibleEndTurnActionResponse } from '@deities/apollo/lib/computeVisibleActions.tsx';
1816
import decodeGameActionResponse from '@deities/apollo/lib/decodeGameActionResponse.tsx';
1917
import dropLabelsFromActionResponse from '@deities/apollo/lib/dropLabelsFromActionResponse.tsx';
2018
import dropLabelsFromGameState from '@deities/apollo/lib/dropLabelsFromGameState.tsx';
21-
import {
22-
EncodedGameState,
23-
GameActionResponse,
24-
GameState,
25-
} from '@deities/apollo/Types.tsx';
26-
import { PlainMap } from '@deities/athena/map/PlainMap.tsx';
19+
import { GameActionResponse, GameState } from '@deities/apollo/Types.tsx';
2720
import MapData from '@deities/athena/MapData.tsx';
2821
import { getHiddenLabels } from '@deities/athena/WinConditions.tsx';
2922
import onGameEnd from '@deities/hermes/game/onGameEnd.tsx';
@@ -32,17 +25,27 @@ import toClientGame, {
3225
} from '@deities/hermes/game/toClientGame.tsx';
3326
import { useCallback } from 'react';
3427
import gameActionWorker from '../workers/gameAction.tsx?worker';
35-
36-
type ClientGameAction = [
37-
actionResponse: EncodedActionResponse,
38-
map: PlainMap,
39-
gameState: EncodedGameState,
40-
effects: EncodedEffects,
41-
];
28+
import {
29+
ClientGameActionRequest,
30+
ClientGameActionResponse,
31+
} from '../workers/Types.tsx';
4232

4333
const ActionError = (action: Action) =>
4434
new Error(`Map: Error executing remote '${action.type}' action.`);
4535

36+
let worker: Worker | null = null;
37+
const getWorker = () => {
38+
if (worker) {
39+
return worker;
40+
}
41+
worker = new gameActionWorker();
42+
worker.onerror = () => {
43+
worker?.terminate();
44+
worker = null;
45+
};
46+
return worker;
47+
};
48+
4649
export default function useClientGameAction(
4750
game: ClientGame | null,
4851
setGame: (game: ClientGame) => void,
@@ -69,27 +72,36 @@ export default function useClientGameAction(
6972
}
7073

7174
try {
72-
const worker = new gameActionWorker();
75+
const message: ClientGameActionRequest = [
76+
map.toJSON(),
77+
encodeEffects(game.effects),
78+
encodeAction(action),
79+
mutateAction,
80+
];
81+
7382
const [
7483
encodedActionResponse,
7584
plainMap,
7685
encodedGameState,
7786
encodedEffects,
78-
] = await new Promise<ClientGameAction>((resolve) => {
79-
worker.postMessage([
80-
map.toJSON(),
81-
encodeEffects(game.effects),
82-
encodeAction(action),
83-
mutateAction,
84-
]);
85-
worker.onmessage = (event: MessageEvent<ClientGameAction>) =>
86-
resolve(event.data);
87+
] = await new Promise<ClientGameActionResponse>((resolve, reject) => {
88+
const { port1, port2 } = new MessageChannel();
89+
port1.onmessage = (
90+
event: MessageEvent<ClientGameActionResponse | null>,
91+
) => {
92+
if (event.data) {
93+
resolve(event.data);
94+
} else {
95+
reject();
96+
}
97+
};
98+
port1.onmessageerror = reject;
99+
getWorker().postMessage(message, [port2]);
87100
});
88-
89101
actionResponse = decodeActionResponse(encodedActionResponse);
90102
initialActiveMap = MapData.fromObject(plainMap);
91103
gameState = decodeGameState(encodedGameState);
92-
newEffects = decodeEffects(encodedEffects);
104+
newEffects = encodedEffects ? decodeEffects(encodedEffects) : null;
93105
} catch (error) {
94106
throw process.env.NODE_ENV === 'development'
95107
? error

hera/workers/Types.tsx

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { MutateActionResponseFnName } from '@deities/apollo/ActionResponseMutator.tsx';
2+
import { EncodedEffects } from '@deities/apollo/Effects.tsx';
3+
import {
4+
EncodedAction,
5+
EncodedActionResponse,
6+
} from '@deities/apollo/EncodedActions.tsx';
7+
import { EncodedGameState } from '@deities/apollo/Types.tsx';
8+
import { PlainMap } from '@deities/athena/map/PlainMap.tsx';
9+
10+
export type ClientGameActionResponse = [
11+
actionResponse: EncodedActionResponse,
12+
map: PlainMap,
13+
gameState: EncodedGameState,
14+
effects: EncodedEffects | null,
15+
];
16+
17+
export type ClientGameActionRequest = [
18+
map: PlainMap,
19+
encodedEffects: EncodedEffects,
20+
action: EncodedAction,
21+
mutateAction: MutateActionResponseFnName | undefined | null,
22+
];

hera/workers/gameAction.tsx

+20-22
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,23 @@
11
import './initializeWorker.tsx';
22
import { ActionResponse } from '@deities/apollo/ActionResponse.tsx';
3-
import ActionResponseMutator, {
4-
MutateActionResponseFnName,
5-
} from '@deities/apollo/ActionResponseMutator.tsx';
3+
import ActionResponseMutator from '@deities/apollo/ActionResponseMutator.tsx';
64
import executeGameAction from '@deities/apollo/actions/executeGameAction.tsx';
75
import {
86
decodeEffects,
97
Effects,
10-
EncodedEffects,
118
encodeEffects,
129
} from '@deities/apollo/Effects.tsx';
1310
import {
1411
decodeAction,
1512
encodeActionResponse,
16-
EncodedAction,
1713
} from '@deities/apollo/EncodedActions.tsx';
1814
import { encodeGameState } from '@deities/apollo/GameState.tsx';
1915
import { GameState } from '@deities/apollo/Types.tsx';
20-
import { PlainMap } from '@deities/athena/map/PlainMap.tsx';
2116
import MapData from '@deities/athena/MapData.tsx';
2217
import AIRegistry from '@deities/dionysus/AIRegistry.tsx';
18+
import { ClientGameActionRequest, ClientGameActionResponse } from './Types.tsx';
2319

24-
self.onmessage = function (
25-
event: MessageEvent<
26-
[
27-
map: PlainMap,
28-
encodedEffects: EncodedEffects,
29-
action: EncodedAction,
30-
mutateAction: MutateActionResponseFnName | undefined | null,
31-
]
32-
>,
33-
) {
20+
self.onmessage = function (event: MessageEvent<ClientGameActionRequest>) {
3421
const [plainMap, encodedEffects, action, mutateAction] = event.data;
3522
const map = MapData.fromObject(plainMap);
3623
const vision = map.createVisionObject(map.getCurrentPlayer());
@@ -49,10 +36,21 @@ self.onmessage = function (
4936
mutateAction ? ActionResponseMutator[mutateAction] : undefined,
5037
);
5138

52-
self.postMessage([
53-
actionResponse ? encodeActionResponse(actionResponse) : null,
54-
initialActiveMap ? initialActiveMap?.toJSON() : null,
55-
gameState ? encodeGameState(gameState) : null,
56-
newEffects ? encodeEffects(newEffects) : null,
57-
]);
39+
const message: ClientGameActionResponse | null =
40+
actionResponse && initialActiveMap && gameState
41+
? [
42+
encodeActionResponse(actionResponse),
43+
initialActiveMap?.toJSON(),
44+
encodeGameState(gameState),
45+
newEffects ? encodeEffects(newEffects) : null,
46+
]
47+
: null;
48+
49+
if (event.ports.length === 1) {
50+
event.ports[0].postMessage(message);
51+
} else {
52+
for (const port of event.ports) {
53+
port.postMessage(message);
54+
}
55+
}
5856
};

0 commit comments

Comments
 (0)