dao-game / commit
PeerGame2 update:
src/game/remote-game-2.ts | 139 +++++++++++++--------------------------------- 1 file changed, 40 insertions(+), 99 deletions(-) diff --git a/src/game/remote-game-2.ts b/src/game/remote-game-2.ts index f570cad..11260dc 100644 --- a/src/game/remote-game-2.ts +++ b/src/game/remote-game-2.ts @@ -1,19 +1,10 @@ import Peer, { PeerJSOption } from 'peerjs'; -import { showModal } from '../utils/modal'; -import { useSessionStorage } from '../utils/storage'; -import { showSnackbar } from "../utils/snackbar"; import { Game, Move, MoveResult } from './game'; import { Coord } from './coord'; import { generateHash } from '../utils/hashing'; import { delay } from '../utils/delay'; -import { copyToClipboard } from '../utils/clipboard'; -import { detect } from 'detect-browser'; -interface LocalData { - id?: string; - peerId?: string; -} -interface Pos { +export interface Pos { x: number; y: number; } @@ -23,10 +14,6 @@ interface PeerData { } const peerOptions: PeerJSOption = { debug: 0 }; -const { getter: getData, setter: setData } = useSessionStorage<LocalData>('dao-game-2', { id: undefined, peerId: undefined }); -const otherMouseElement = document.getElementById('other-mouse')!; -const shareContainer = document.getElementById('share-container')!; -const shareLinkButton = document.getElementById('share-link')!; const minString = (a: string, b: string): string => (a < b ? a : b); const maxString = (a: string, b: string): string => (a > b ? a : b); const getFirstPlayerId = (playerId1: string, playerId2: string) => { @@ -37,18 +24,25 @@ const getFirstPlayerId = (playerId1: string, playerId2: string) => { const id = isEven ? minString(playerId1, playerId2) : maxString(playerId1, playerId2); return id; }; -const dropFileExtension = (path: string) => { - const lastSlashIndex = path.lastIndexOf('/'); - const dirName = path.substring(0, lastSlashIndex); - return dirName; + +export class MousePosEventEmitter { + private _cbs: ((pos: Pos) => void)[] = []; + public onData(callback: (pos: Pos) => void): void { + this._cbs.push(callback); + } + public sendData(pos: Pos): void { + this._cbs.forEach((cb) => cb(pos)); + } } -const showMessageAndLeave = async (title: string, text: string) => { - await showModal({ title, text, willBackgroundCancel: false }); - sessionStorage.clear(); - const { protocol, host, pathname } = location; - const dir = dropFileExtension(pathname); - const newUrl = `${protocol}//${host}${dir}` - document.location = newUrl; + +export interface PeerGameSettings { + id?: string; + peerId?: string; + onError: (type: string, error: any) => void; + onSetup: (selfId: string) => void; + onStart: (selfId: string, peerId: string) => void; + onPeerMouseMove: (unitPos: Pos) => void; + mouseEventEmitter: MousePosEventEmitter; } export class PeerGame2 extends Game { @@ -56,7 +50,7 @@ export class PeerGame2 extends Game { public selfId: string; public onMouseMoveCallback: (pos: Coord) => void = () => { }; public peerMousePositionCallback: (pos: Coord) => void = () => { }; - + public constructor(player1Id: string, player1Name: string, player2Id: string, player2Name: string, selfId: string, conn: Peer.DataConnection) { super(player1Id, player1Name, player2Id, player2Name); this.selfId = selfId; @@ -68,56 +62,35 @@ export class PeerGame2 extends Game { this.conn.send(JSON.stringify(peerData)); return result; } - public static async createPeerGame(): Promise<PeerGame2> { - let { id, peerId } = getData(); - const main = document.getElementsByTagName('main')[0]; + public static async createPeerGame(settings: PeerGameSettings): Promise<PeerGame2> { + let id: string = settings.id ? settings.id : ''; + let peerId: string = settings.peerId ? settings.peerId : ''; let game: PeerGame2 | undefined = undefined; const handleConn = async (conn: Peer.DataConnection) => { - shareContainer.classList.add('invisible'); - - await new Promise<void>((resolve) => { - conn.on('open', () => resolve()); - }); + // wait for connection to 'open' + await new Promise<void>((resolve) => conn.on('open', resolve)); id = peer.id; peerId = conn.peer; - setData({ id, peerId }); + settings.onStart(id, peerId); const isLocalP1 = getFirstPlayerId(id, peerId) === id; game = isLocalP1 ? new PeerGame2(id, "Local", peerId, "Remote", id, conn) : new PeerGame2(peerId, "Remote", id, "Local", id, conn); - - let lastTimerId: NodeJS.Timeout | undefined = undefined; conn.on('data', (data: string) => { - if (!game) return; + if (!game) { + console.warn({ warning: 'Receiving data, but there is no game', data }); + return; + } const peerData = JSON.parse(data) as PeerData; const { mousePos, move } = peerData; if (mousePos) { - const isValidPos = mousePos.x !== -1 && mousePos.y !== -1; - if (isValidPos) { - const xRatio = mousePos.x; - const yRatio = mousePos.y; - const xTable = xRatio * table.clientWidth; - const yTable = yRatio * table.clientHeight; - const x = table.offsetLeft + xTable; - const y = table.offsetTop + yTable; - const style = `left:${x - otherMouseElement.clientWidth / 2}px;top:${y}px;display:block;`; - otherMouseElement.setAttribute('style', style); - if (lastTimerId !== undefined) { - clearTimeout(lastTimerId); - } - lastTimerId = setTimeout(() => { - otherMouseElement.setAttribute('style', ''); - lastTimerId = undefined; - }, 3000); - } else if (lastTimerId !== undefined) { - otherMouseElement.setAttribute('style', ''); - } + settings.onPeerMouseMove(mousePos); } const isWaitingForRemoteMove = peerId === game.currentPlayerId; @@ -131,44 +104,34 @@ export class PeerGame2 extends Game { } }); conn.on('error', (err) => { - showMessageAndLeave(`Connection error`, err); + settings.onError(`Connection error`, err); }); conn.on('close', () => { - showMessageAndLeave(`Connection closed`, 'Connection closed for some reason') + settings.onError(`Connection closed`, 'Connection closed for some reason') + }); + settings.mouseEventEmitter.onData((pos) => { + const peerData: PeerData = { mousePos: pos }; + conn.send(JSON.stringify(peerData)); }); }; - const { host, protocol, pathname, search } = location; - const queryParams = new URLSearchParams(search); - const peer = id === undefined ? new Peer(peerOptions) : new Peer(id, peerOptions); - window.onunload = () => peer.destroy(); peer.on('connection', (conn) => handleConn(conn)); peer.on('error', async (err) => { - await showMessageAndLeave('Peer error encountered', err); + settings.onError('Peer error encountered', err); }); peer.on('open', (trueId) => { id = trueId; - peerId = queryParams.get('peerId') ?? peerId; - setData({ id, peerId }); + settings.onSetup(id); if (peerId) { console.log(`${id} connecting to peer "${peerId}"`); const conn = peer.connect(peerId); handleConn(conn); - } else { - queryParams.set('peerId', id); - const newSearch = queryParams.toString(); - const newUrl = `${protocol}//${host}${pathname}?${newSearch}`; - shareLinkButton.onclick = () => { - showSnackbar('Url copied to clipboard'); - copyToClipboard(newUrl); - }; - shareContainer.classList.remove('invisible'); } }); peer.on('disconnected', async () => { - await showMessageAndLeave('Peer disconnected', 'For some reason') + settings.onError('Peer disconnected', 'For some reason') }); while (game === undefined) { console.log('Waiting to connect to peer'); @@ -177,25 +140,3 @@ export class PeerGame2 extends Game { return game; } } - -const isBrowserSupported = () => { - const browser = detect(); - switch (browser && browser.name) { - case 'chrome': - case 'firefox': - return true; - default: - return false; - } -} -export const playGame = async () => { - if (isBrowserSupported()) { - await PeerGame.createPeerGame(); - } else { - showMessageAndLeave( - 'Unsupported browser', - '<p>Your current browser is not yet supported.</p>' + - '<p>This PeerJs issue is tracking support in Microsoft Edge and Safari: </p>' + - '<p><a href="https://github.com/peers/peerjs/issues/899" target="_blank">https://github.com/peers/peerjs/issues/899</a></p>') - } -};