import type { PJ } from '@lastres/pj' import type { Location } from '@lastres/location' import type InputPacket from '@lastres/input-packet' import type { LogLine } from '@lastres/log-line' import type { ActionHash } from '@lastres/action' import type { TalkNPCs } from '@lastres/talk-npc' import type { Words } from '@lastres/word' import InputPacketInfo from '@lastres/input-packet/info' import InputPacketPong from '@lastres/input-packet/pong' type SetTeamPJs = (set: PJ[] | null) => void type SetIsBattling = (set: boolean | null) => void type SetEnemyTeamPJs = (set: PJ[] | null) => void type SetCurrentLocation = (set: Location | null) => void type SetConnectedLocations = (set: Location[] | null) => void type DispatchHash = Record type SetLogLinesCallback = (set: LogLine[] | null) => LogLine[] type SetLogLines = (set: LogLine[] | SetLogLinesCallback | null) => void type SetError = (set: string | null) => void type SetScrollLogCallback = (set: number | null) => number | null type SetScrollLog = (set: number | null | SetScrollLogCallback) => void type LogPresentationRef = React.RefObject type SetMovingTo = (set: Location | null) => void type SetRemainingFrames = (set: number | null) => void type SetActionHash = (set: ActionHash | null) => void type SetTalkNPCs = (set: TalkNPCs | null) => void type SetWords = (set: Words | null) => void interface Packet { command: string data: any } type LogHash = Record export default class InputPackets { setTeamPJs: SetTeamPJs setEnemyTeamPJs: SetEnemyTeamPJs setIsBattling: SetIsBattling setCurrentLocation: SetCurrentLocation setConnectedLocations: SetConnectedLocations setLogLines: SetLogLines logLines: LogLine[] | null cachedHash: DispatchHash | null = null cachedArray: InputPacket[] | null = null setError: SetError setScrollLog: SetScrollLog logPresentationRef: LogPresentationRef setMovingTo: SetMovingTo setRemainingFrames: SetRemainingFrames setActionHash: SetActionHash setTalkNPCs: SetTalkNPCs setWords: SetWords constructor (setTeamPJs: SetTeamPJs, setEnemyTeamPJs: SetEnemyTeamPJs, setIsBattling: SetIsBattling, setCurrentLocation: SetCurrentLocation, setConnectedLocations: SetConnectedLocations, logLines: LogLine[] | null, setLogLines: SetLogLines, setError: SetError, setScrollLog: SetScrollLog, logPresentationRef: LogPresentationRef, setMovingTo: SetMovingTo, setRemainingFrames: SetRemainingFrames, setActionHash: SetActionHash, setTalkNPCs: SetTalkNPCs, setWords: SetWords) { this.setTeamPJs = setTeamPJs this.setEnemyTeamPJs = setEnemyTeamPJs this.setCurrentLocation = setCurrentLocation this.setConnectedLocations = setConnectedLocations this.logLines = logLines this.setLogLines = setLogLines this.setError = setError this.setScrollLog = setScrollLog this.logPresentationRef = logPresentationRef this.setMovingTo = setMovingTo this.setRemainingFrames = setRemainingFrames this.setIsBattling = setIsBattling this.setActionHash = setActionHash this.setTalkNPCs = setTalkNPCs this.setWords = setWords } handle (packet: Packet): void { const hash = this.hashAvailablePackets() const identifier = packet.command const inputPacket = hash[identifier] inputPacket.recv(packet) } listAvailablePackets (): InputPacket[] { let firstTime = true if (this.cachedArray === null) { const infoPacket = new InputPacketInfo() const pongPacket = new InputPacketPong() infoPacket.onReceive((data) => { const logPresentationRef = this.logPresentationRef let scrollData: number[] = [] function saveScroll (): void { if (logPresentationRef.current === null) { return } scrollData = [ logPresentationRef.current.scrollHeight, logPresentationRef.current.scrollTop, logPresentationRef.current.offsetHeight ] } function applyScroll (): void { if (scrollData.length < 3) { return } if (logPresentationRef.current === null) { console.log('Not defined') return } const logPresentation = logPresentationRef.current const [scrollHeight, scrollTop, offsetHeight] = scrollData if (firstTime) { firstTime = false logPresentation.scrollTo(0, logPresentation.scrollHeight) return } if (scrollHeight <= scrollTop + offsetHeight * (3 / 2)) { logPresentation.scrollTo(0, logPresentation.scrollHeight) } } if (data.error !== undefined) { this.setError(data.error) return } if (data.team_pjs !== undefined) { this.setTeamPJs(data.team_pjs) } if (data.enemy_team_pjs !== undefined) { this.setEnemyTeamPJs(data.enemy_team_pjs) } if (data.is_battling !== undefined) { this.setIsBattling(data.is_battling) } if (data.location_data !== undefined) { console.log(data.location_data) if (data.location_data.connected_places !== undefined) { this.setConnectedLocations(data.location_data.connected_places) } if (data.location_data.current !== undefined) { this.setCurrentLocation(data.location_data.current) } if (data.location_data.moving_to !== undefined) { this.setMovingTo(data.location_data.moving_to) } else { this.setMovingTo(null) } } if (data.npcs !== undefined) { this.setTalkNPCs(data.npcs) } if (data.remaining_frames !== undefined) { this.setRemainingFrames(data.remaining_frames) } if (data.set_log !== undefined) { saveScroll() this.setLogLines(data.set_log) window.setTimeout(() => { applyScroll() }, 10) } if (data.known_words !== undefined) { console.log(data.known_words); this.setWords(data.known_words) } if (data.append_log !== undefined) { const logHash: LogHash = {} saveScroll() this.setLogLines((logLines: LogLine[] | null): LogLine[] => { if (logLines !== null) { for (const item of logLines) { logHash[item.uuid] = item } logHash[data.append_log.uuid] = data.append_log const outputLog: LogLine[] = Object.keys(logHash).map((item, i): LogLine => { return logHash[item] }) return outputLog } return [] }) window.setTimeout(() => { applyScroll() }, 10) } if (data.available_actions !== undefined) { this.setActionHash(data.available_actions) } }) this.cachedArray = [infoPacket, pongPacket] } return this.cachedArray } hashAvailablePackets (): DispatchHash { if (this.cachedHash === null) { this.cachedHash = {} for (const inputPacket of this.listAvailablePackets()) { this.cachedHash[inputPacket.identifier()] = inputPacket } } return this.cachedHash } }