import {Socket} from "socket.io"; import User from "./User"; import {getIndex, getNextShot, getTimeline, getTimelineNames, indexForTime} from "./timeline"; import {getCurrentTime} from "./util"; export interface RoomOptions { seekTime: number timelineName: string } export default class Room { id: number = 0; users: User[] = []; leader: User | null = null; running = false; startTime = 0; currentSeconds = 0; timelineIndex: number = 0; seekTime: number = 0; timelineName: string = 'Centurion'; // For debugging purposes speedFactor = 1; constructor(name: number) { this.id = name; } serialize(user: User) { return { 'id': this.id, 'userCount': this.users.length, 'isLeader': this.leader == user, 'running': this.running, 'startTime': this.startTime, 'timelineName': this.timelineName, 'seekTime': this.seekTime, 'readyToParticipate': user.readyToParticipate || this.leader == user, 'speedFactor': this.speedFactor } } serializeTimeline(user: User) { return getTimeline(this.timelineName); } sync() { this.users.forEach(u => u.sync()); } join(user: User) { this.users.push(user); user.setRoom(this); if (!this.hasLeader()) { this.setLeader(user); } this.sync(); } leave(user: User) { this.users.splice(this.users.indexOf(user), 1); user.setRoom(null); if (this.leader == user) { this.setRandomLeader(); } this.sync(); } onBeforeDelete() { } setOptions(options: any) { this.seekTime = Math.max(0, Math.min(options.seekTime, 250 * 60 * 1000)) if (getTimelineNames().indexOf(options.timelineName) >= 0) { this.timelineName = options.timelineName; } this.sync() } start() { this.running = true; this.startTime = getCurrentTime() - this.seekTime this.sync(); } run(io: Socket) { this.running = true; this.startTime = Date.now(); // io.to(this.id.toString()).emit('timeline', { // 'timeline': { // } // }); const doTick = () => { if (this.users.length === 0) { // this room is over. return; } const timestamp = getIndex(this.timelineIndex); const nextShot = getNextShot(this.timelineIndex); if (!timestamp) { // We are done. io.to(this.id.toString()).emit('tick_event', { tick: { current: this.currentSeconds } }); console.log("Done"); this.running = false; return; } console.log("ticking", this.currentSeconds); io.to(this.id.toString()).emit('tick_event', { tick: { current: this.currentSeconds, next: timestamp, nextShot: nextShot } }); if (this.currentSeconds >= timestamp.timestamp) { this.timelineIndex += 1; } this.currentSeconds += 1; // We spend some time processing, wait a bit less than 1000ms const nextTickTime = this.startTime + (1000 * this.currentSeconds / this.speedFactor); const waitTime = nextTickTime - Date.now(); console.log("waiting", waitTime); setTimeout(doTick, Math.floor(waitTime / this.speedFactor)); }; doTick(); } /** * * @param io * @param {number} time */ seek(io: Socket, time: number) { this.currentSeconds = time; this.startTime = Date.now() - time * 1000; this.timelineIndex = indexForTime(this.currentSeconds); io.to(this.id.toString()).emit('seek', time); } /** * * @returns {boolean} */ hasUsers() { return this.users.length !== 0; } setRandomLeader() { if (this.hasUsers()) { this.leader = this.users[0]; } } /** * * @param id * @returns {User|undefined} */ getUser(id: string) { return this.users.find(u => u.id === id); } /** * * @param {string} id */ removeUser(id: string) { this.users = this.users.filter(u => u.id !== id); } hasLeader(): boolean { return this.leader != null; } setLeader(user: User) { this.leader = user; } getLeader(): User | null { return this.leader; } };