1
- import { Action , MutateActionResponseFn } from '@deities/apollo/Action.tsx' ;
1
+ import { Action } from '@deities/apollo/Action.tsx' ;
2
2
import { ActionResponse } from '@deities/apollo/ActionResponse.tsx' ;
3
+ import { MutateActionResponseFnName } from '@deities/apollo/ActionResponseMutator.tsx' ;
3
4
import encodeGameActionResponse from '@deities/apollo/actions/encodeGameActionResponse.tsx' ;
4
- import executeGameAction from '@deities/apollo/actions/executeGameAction.tsx' ;
5
- import { Effects } from '@deities/apollo/Effects.tsx' ;
5
+ import {
6
+ decodeEffects ,
7
+ Effects ,
8
+ EncodedEffects ,
9
+ encodeEffects ,
10
+ } from '@deities/apollo/Effects.tsx' ;
11
+ import {
12
+ decodeActionResponse ,
13
+ encodeAction ,
14
+ EncodedActionResponse ,
15
+ } from '@deities/apollo/EncodedActions.tsx' ;
16
+ import { decodeGameState } from '@deities/apollo/GameState.tsx' ;
6
17
import { computeVisibleEndTurnActionResponse } from '@deities/apollo/lib/computeVisibleActions.tsx' ;
7
18
import decodeGameActionResponse from '@deities/apollo/lib/decodeGameActionResponse.tsx' ;
8
19
import dropLabelsFromActionResponse from '@deities/apollo/lib/dropLabelsFromActionResponse.tsx' ;
9
20
import dropLabelsFromGameState from '@deities/apollo/lib/dropLabelsFromGameState.tsx' ;
10
- import { GameActionResponse , GameState } from '@deities/apollo/Types.tsx' ;
21
+ import {
22
+ EncodedGameState ,
23
+ GameActionResponse ,
24
+ GameState ,
25
+ } from '@deities/apollo/Types.tsx' ;
26
+ import { PlainMap } from '@deities/athena/map/PlainMap.tsx' ;
11
27
import MapData from '@deities/athena/MapData.tsx' ;
12
28
import { getHiddenLabels } from '@deities/athena/WinConditions.tsx' ;
13
- import AIRegistry from '@deities/dionysus/AIRegistry.tsx' ;
14
29
import onGameEnd from '@deities/hermes/game/onGameEnd.tsx' ;
15
30
import toClientGame , {
16
31
ClientGame ,
17
32
} from '@deities/hermes/game/toClientGame.tsx' ;
18
33
import { useCallback } from 'react' ;
34
+ import gameActionWorker from '../workers/gameAction.tsx?worker' ;
35
+
36
+ type ClientGameAction = [
37
+ actionResponse : EncodedActionResponse ,
38
+ map : PlainMap ,
39
+ gameState : EncodedGameState ,
40
+ effects : EncodedEffects ,
41
+ ] ;
19
42
20
43
const ActionError = ( action : Action ) =>
21
44
new Error ( `Map: Error executing remote '${ action . type } ' action.` ) ;
22
45
23
46
export default function useClientGameAction (
24
47
game : ClientGame | null ,
25
48
setGame : ( game : ClientGame ) => void ,
26
- mutateAction ?: MutateActionResponseFn ,
49
+ mutateAction ?: MutateActionResponseFnName | null ,
27
50
) {
28
51
return useCallback (
29
- ( action : Action ) : Promise < GameActionResponse > => {
52
+ async ( action : Action ) : Promise < GameActionResponse > => {
30
53
if ( ! game ) {
31
- return Promise . reject ( new Error ( 'Client Game: Map state is missing.' ) ) ;
54
+ throw new Error ( 'Client Game: Map state is missing.' ) ;
32
55
}
33
56
34
57
let actionResponse : ActionResponse | null ;
@@ -42,23 +65,35 @@ export default function useClientGameAction(
42
65
const isStart = action . type === 'Start' ;
43
66
44
67
if ( isStart === ! ! game . lastAction ) {
45
- return Promise . reject ( ActionError ( action ) ) ;
68
+ throw ActionError ( action ) ;
46
69
}
47
70
48
71
try {
49
- [ actionResponse , initialActiveMap , gameState , newEffects ] =
50
- executeGameAction (
51
- map ,
52
- vision ,
53
- game . effects ,
54
- action ,
55
- AIRegistry ,
72
+ const worker = new gameActionWorker ( ) ;
73
+ const [
74
+ encodedActionResponse ,
75
+ plainMap ,
76
+ encodedGameState ,
77
+ encodedEffects ,
78
+ ] = await new Promise < ClientGameAction > ( ( resolve ) => {
79
+ worker . postMessage ( [
80
+ map . toJSON ( ) ,
81
+ encodeEffects ( game . effects ) ,
82
+ encodeAction ( action ) ,
56
83
mutateAction ,
57
- ) || [ null , null , null ] ;
84
+ ] ) ;
85
+ worker . onmessage = ( event : MessageEvent < ClientGameAction > ) =>
86
+ resolve ( event . data ) ;
87
+ } ) ;
88
+
89
+ actionResponse = decodeActionResponse ( encodedActionResponse ) ;
90
+ initialActiveMap = MapData . fromObject ( plainMap ) ;
91
+ gameState = decodeGameState ( encodedGameState ) ;
92
+ newEffects = decodeEffects ( encodedEffects ) ;
58
93
} catch ( error ) {
59
- return Promise . reject (
60
- process . env . NODE_ENV === 'development' ? error : ActionError ( action ) ,
61
- ) ;
94
+ throw process . env . NODE_ENV === 'development'
95
+ ? error
96
+ : ActionError ( action ) ;
62
97
}
63
98
64
99
if ( actionResponse && initialActiveMap && gameState ) {
@@ -79,31 +114,25 @@ export default function useClientGameAction(
79
114
) ;
80
115
gameState = dropLabelsFromGameState ( gameState , hiddenLabels ) ;
81
116
82
- return Promise . resolve (
83
- decodeGameActionResponse (
84
- encodeGameActionResponse (
85
- map ,
86
- initialActiveMap ,
87
- vision ,
88
- onGameEnd (
89
- gameState ,
90
- newEffects || game . effects ,
91
- currentViewer . id ,
92
- ) ,
93
- null ,
94
- actionResponse ?. type === 'EndTurn'
95
- ? computeVisibleEndTurnActionResponse (
96
- actionResponse ,
97
- map ,
98
- initialActiveMap ,
99
- vision ,
100
- )
101
- : actionResponse ,
102
- ) ,
117
+ return decodeGameActionResponse (
118
+ encodeGameActionResponse (
119
+ map ,
120
+ initialActiveMap ,
121
+ vision ,
122
+ onGameEnd ( gameState , newEffects || game . effects , currentViewer . id ) ,
123
+ null ,
124
+ actionResponse ?. type === 'EndTurn'
125
+ ? computeVisibleEndTurnActionResponse (
126
+ actionResponse ,
127
+ map ,
128
+ initialActiveMap ,
129
+ vision ,
130
+ )
131
+ : actionResponse ,
103
132
) ,
104
133
) ;
105
134
}
106
- return Promise . reject ( ActionError ( action ) ) ;
135
+ throw ActionError ( action ) ;
107
136
} ,
108
137
[ game , mutateAction , setGame ] ,
109
138
) ;
0 commit comments