import e from 'express'; import { Socket } from 'socket.io-client'; import { Color } from 'three'; import { isMobileOrTablet } from '../common/helper'; import { CharacterPacket, CompositePacket } from '../common/types/packet'; import { IcyNetUser } from '../common/types/user'; import { ThirdPersonCamera } from './object/camera'; import { Chat } from './object/chat'; import { Joystick } from './object/joystick'; import { VideoPlayer } from './object/other/video-player'; import { Player } from './object/player'; import { PlayerEntity } from './object/player-entity'; import modelLoaderInstance from './object/pony-loader'; import { Renderer } from './renderer'; export class Game { public players: (Player | PlayerEntity)[] = []; public player!: Player; public me!: IcyNetUser; public thirdPersonCamera!: ThirdPersonCamera; public joystick!: Joystick; public chat!: Chat; private character: CharacterPacket = {}; private party: string[] = []; public renderer = new Renderer(); private videoTest = new VideoPlayer(24, 12); constructor(public socket: Socket) {} async initialize(): Promise { await modelLoaderInstance.loadPonyModel(); this.renderer.initialize(); this.bindSocket(); this.chat = new Chat(); this.chat.initialize(); this.socket.connect(); // experimental this.videoTest.initialize(); this.videoTest.mesh.position.set(0, 6, -20); this.renderer.scene.add(this.videoTest.mesh); this.party = (localStorage.getItem('party')?.split('|') || []).filter( (item) => item, ); const colorGet = localStorage.getItem('color'); if (colorGet) { this.character.color = colorGet; } // end of this.chat.registerSendFunction((message) => { this.socket.emit('chat-send', message); }); this.renderer.registerUpdateFunction((dt: number) => { this.update(dt); }); } public dispose() { this.players.forEach((player) => { this.renderer.scene.remove(player.container); }); this.thirdPersonCamera?.dispose(); this.joystick?.dispose(); this.players.length = 0; } public update(dt: number) { this.players.forEach((player) => player.update(dt)); this.player?.createPacket(this.socket); this.thirdPersonCamera?.update(dt); this.joystick?.update(dt); } bindSocket() { this.socket.on('connect', () => { this.dispose(); console.log('connected'); }); this.socket.on('me', (user) => { console.log(user); if (!user) { window.location.href = '/login'; return; } this.me = user; const player = Player.fromUser(user, this.renderer.scene); player.setCharacter(this.character); this.players.push(player); this.player = player; this.thirdPersonCamera = new ThirdPersonCamera( this.renderer.camera, this.player.container, this.renderer.canvas, ); this.thirdPersonCamera.initialize(); this.joystick = new Joystick(player); this.joystick.initialize(); if (isMobileOrTablet()) { this.joystick.show(); } this.socket.emit('character', this.character); }); this.socket.on('playerjoin', (user) => { if (user.id === this.me.id) { return; } const newplayer = PlayerEntity.fromUser(user, this.renderer.scene); this.players.push(newplayer); }); this.socket.on('playerleave', (user) => { const findPlayer = this.players.find((item) => item.user.id === user.id); if (findPlayer) { this.renderer.scene.remove(findPlayer.container); findPlayer.dispose(); this.players.splice(this.players.indexOf(findPlayer), 1); } }); this.socket.on('players', (list: CompositePacket[]) => { list.forEach((player) => { if (player.id === this.me.id) { return; } const newplayer = PlayerEntity.fromUser(player, this.renderer.scene); newplayer.addUncommittedChanges(player); this.players.push(newplayer); }); }); this.socket.on('playerupdate', (data) => { data.forEach((item) => { const player = this.players.find( (player) => player.user.id === item.id, ); if ( player && player instanceof PlayerEntity && player.user.id !== this.me.id ) { player.addUncommittedChanges(item); } }); }); this.socket.on('playercharacter', (data) => { const player = this.players.find((player) => player.user.id === data.id); if ( player && player instanceof PlayerEntity && player.user.id !== this.me.id ) { player.setCharacter(data); } }); this.socket.on('chat', (event) => { const player = this.players.find( (item) => item.user.id === event.sender.id, ); if (player && player.user.id !== this.me.id) { (player as PlayerEntity).addChat(event.message); } this.chat.addMessage(event.message, event.sender.display_name); // experimental stuff this.experimentalPlayerCmd(event.message, event.sender); }); } private experimentalPlayerCmd(message: string, sender: IcyNetUser) { if (this.me.id === sender.id) { if (message.startsWith('!color')) { const [cmd, color] = message.split(' '); try { const colorr = new Color(color); if (!colorr) { throw 'invalid'; } } catch (e: any) { this.chat.addMessage('Invalid color.'); return; } this.player.setColor(color); this.socket.emit('character', { color }); localStorage.setItem('color', color); } if (message.startsWith('!party')) { const array = message.split(' '); const name = array.slice(2).join(' '); if (array[1] === 'join') { this.party.push(name); this.chat.addMessage(`Joined party of user "${name}".`); } if (array[1] === 'leave') { this.party.splice(this.party.indexOf(name), 1); this.chat.addMessage(`Left party of user "${name}".`); } if (array[1] === 'clear') { this.party.length = 0; this.chat.addMessage('Cleared party list.'); } if (array[1] === 'list') { this.chat.addMessage( `You have joined the watch party of: ${this.party.join(', ')}`, ); } localStorage.setItem('party', this.party.join('|')); } } if ( !( sender.display_name === this.me.display_name || this.party.includes(sender.display_name) ) ) { return; } if (message.startsWith('!play')) { const [cmd, src] = message.split(' '); if (src) { this.videoTest.setSource(src, true); } else { this.videoTest.play(); } return; } if (message.startsWith('!stop') || message.startsWith('!pause')) { this.videoTest.stop(); return; } if (message.startsWith('!volume')) { const [cmd, vol] = message.split(' '); if (!vol) { this.chat.addMessage( `Current volume: ${Math.floor(this.videoTest.video.volume * 100)}`, ); return; } this.videoTest.setVolume(parseInt(vol.replace('%', ''), 10)); } } }