import { getDependency , getVariable } from "@shoki/engine" ; import { OutgoingRegistry } from "@shoki/networking" ; import { all , call , race , take , select , delay , getContext } from "typed-redux-saga" ; import { PlayerVariables , PlayerEntity , PlayerEntitySelectors , PlayerActions , PlayerEntityDependencies , PlayerStateSelectors , PlayerState , PlayerCommands , GameEvents , Match , PlayerEvents } from "@creature-chess/gamemode" ; import { GameServerToClient } from "@creature-chess/networking" ; import { getPacketRegistries } from "../net/registries" ; import { subscribeToBoard } from "./subscribeToBoard" ; import { Task } from "redux-saga" ; const getSpectatingPlayer = function * ( ) { const spectatingId = yield * select ( ( state ) => state . spectating . id ) ; if ( ! spectatingId ) { return null ; } const game = yield * getDependency < PlayerEntityDependencies , "gamemode" > ( "gamemode" ) ; return game . getPlayerById ( spectatingId ) || null ; } ; const getMatch = ( ) => getVariable < PlayerVariables , Match | null > ( variables => variables . match ) ; const spectatePlayerBoard = function * ( registry ) { const playerId = yield * getContext < string > ( "id" ) ; const boardSlice = yield * PlayerEntitySelectors . getBoardSlice ( ) ; const benchSlice = yield * PlayerEntitySelectors . getBenchSlice ( ) ; const initialMatch = yield * getMatch ( ) ; if ( initialMatch ) { registry . send ( "matchBoardUpdate" , { turn : initialMatch . getTurn ( ) , board : initialMatch . getBoardForPlayer ( playerId ) } ) ; } yield all ( [ call ( function * ( ) { while ( true ) { yield take ( GameEvents . playerRunReadyPhaseEvent . toString ( ) ) ; yield delay ( 100 ) ; const match = yield * getMatch ( ) ; if ( match ) { registry . send ( "matchBoardUpdate" , { turn : null , board : match . getBoardForPlayer ( playerId ) } ) ; } yield take ( PlayerEvents . playerFinishMatchEvent . toString ( ) ) ; } } ) , call ( subscribeToBoard , boardSlice , PlayerStateSelectors . getPlayerBoard , board => registry . send ( "boardUpdate" , board ) ) , call ( subscribeToBoard , benchSlice , PlayerStateSelectors . getPlayerBench , bench => registry . send ( "benchUpdate" , bench ) ) ] ) ; } ; const spectateOtherPlayer = function * ( player ) { const { outgoing : registry } = yield * getPacketRegistries ( ) ; let task = null ; try { task = player . runSaga ( function * ( ) { yield call ( spectatePlayerBoard , registry ) ; } ) ; yield task . toPromise < void > ( ) ; } finally { task ?. cancel ( ) ; } } ; const spectateLocalPlayer = function * ( ) { const { outgoing : registry } = yield * getPacketRegistries ( ) ; yield call ( spectatePlayerBoard , registry ) ; } ; /**
 * Watch the local player board and bench, or that of the currently spectated player
 */ export const playerBoard = function * ( ) { yield delay ( 200 ) ; let spectating = yield * call ( getSpectatingPlayer ) ; while ( true ) { const { newSpectate } = yield * race ( { newSpectate : take < any > ( PlayerCommands . setSpectatingIdCommand . toString ( ) ) , forever : spectating ? call ( spectateOtherPlayer , spectating ) : call ( spectateLocalPlayer ) } ) ; if ( ! newSpectate ) { return ; } spectating = yield * call ( getSpectatingPlayer ) ; } } ;