Add character emotes across bot friend and ranked matches
This commit is contained in:
@@ -4,6 +4,8 @@ import type { ActiveMatch, LocalMatchState, MatchCheckpoint, RecordAck, ResultSu
|
||||
import type { ActionId } from '../shared/types.js';
|
||||
import type { SessionStorage } from './result-reporter.js';
|
||||
import { createFriendMatch, type GamePeer } from './friend-match.js';
|
||||
import { createEmotes } from '../shared/emotes.js';
|
||||
import type { EmoteId } from '../../constants/emotes.js';
|
||||
|
||||
export interface GameClock { now(): number; setTimeout(fn: () => void, ms: number): any; clearTimeout(id: any): void }
|
||||
export interface ControllerConfig {
|
||||
@@ -20,12 +22,14 @@ export function createMatchController(config: ControllerConfig) {
|
||||
const engine = createMatchEngine({ ...config.activeMatch, selfIndex: config.selfIndex, clock: { now: () => clock.now() + offset }, random: config.random });
|
||||
let friend: ReturnType<typeof createFriendMatch> | undefined;
|
||||
const listeners = new Set<(state: LocalMatchState) => void>();
|
||||
const emotes = createEmotes();
|
||||
const view = () => ({ ...engine.view(), appearances: config.activeMatch.appearances, emotes: emotes.view(clock.now() + offset) });
|
||||
let timer: any, destroyed = false, started = false, recording = false;
|
||||
function publish() {
|
||||
if (destroyed) return;
|
||||
const checkpoint: ControllerCheckpoint = { gameSessionId: config.gameSessionId, activeMatch: config.activeMatch, checkpoint: engine.checkpoint(), epoch: 0, ...friend?.snapshot() };
|
||||
config.storage.setItem(GAME_CHECKPOINT_KEY, JSON.stringify(checkpoint));
|
||||
for (const listener of listeners) listener({ ...engine.view(), appearances: config.activeMatch.appearances });
|
||||
for (const listener of listeners) listener(view());
|
||||
}
|
||||
async function record() {
|
||||
const state = engine.view(); if (!state.finished || state.finished.saved || recording || destroyed) return;
|
||||
@@ -63,7 +67,8 @@ export function createMatchController(config: ControllerConfig) {
|
||||
if (config.activeMatch.mode === 'friend') {
|
||||
if (!config.peer) throw new Error('PEER_REQUIRED');
|
||||
friend = createFriendMatch({ matchId: config.activeMatch.matchId, slot: config.selfIndex, engine, peer: config.peer, clock,
|
||||
setOffset: value => { offset = value; }, changed: publish, finished: () => { void record(); }, saved });
|
||||
setOffset: value => { offset = value; }, changed: publish, finished: () => { void record(); }, saved,
|
||||
onEmote: id => { if (emotes.send(config.selfIndex === 0 ? 1 : 0, id, clock.now() + offset)) publish(); } });
|
||||
await friend.start(); return;
|
||||
}
|
||||
if (!saved) engine.start();
|
||||
@@ -86,8 +91,16 @@ export function createMatchController(config: ControllerConfig) {
|
||||
await config.onRematch?.();
|
||||
if (!destroyed) friend?.requestRematch();
|
||||
},
|
||||
view: () => ({ ...engine.view(), appearances: config.activeMatch.appearances }),
|
||||
subscribe(listener: (state: LocalMatchState) => void) { listeners.add(listener); listener({ ...engine.view(), appearances: config.activeMatch.appearances }); return () => { listeners.delete(listener); }; },
|
||||
sendEmote(id: EmoteId) {
|
||||
if (destroyed || !started || engine.view().phase === 'finished' || friend?.recovering) return false;
|
||||
const now = clock.now() + offset;
|
||||
if (config.activeMatch.mode === 'friend' && !config.peer?.connected) return false;
|
||||
if (!emotes.send(config.selfIndex, id, now)) return false;
|
||||
if (friend && !friend.sendEmote(id)) return false;
|
||||
publish(); return true;
|
||||
},
|
||||
view,
|
||||
subscribe(listener: (state: LocalMatchState) => void) { listeners.add(listener); listener(view()); return () => { listeners.delete(listener); }; },
|
||||
retrySave: record,
|
||||
destroy() { destroyed = true; clock.clearTimeout(timer); friend?.destroy(); listeners.clear(); },
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user