From 057425695e74b92ba99a40b9bc89f16d9f1172a6 Mon Sep 17 00:00:00 2001 From: Evert Prants Date: Sun, 10 Apr 2022 09:52:50 +0300 Subject: [PATCH] colorize --- assets/clean-pony2fix.glb | Bin 436748 -> 436748 bytes src/client/game.ts | 83 +++++++++++++++++++++-------- src/client/object/player-entity.ts | 7 ++- src/client/object/pony-loader.ts | 6 +++ src/client/object/pony.ts | 25 ++++++++- src/common/types/packet.ts | 5 ++ src/server/object/game.ts | 18 ++++++- 7 files changed, 120 insertions(+), 24 deletions(-) diff --git a/assets/clean-pony2fix.glb b/assets/clean-pony2fix.glb index a9ff5d61fdf68c00f0ffb2f9fcde23ad20b0739d..2cf27a8a66288ed4142b790f15db6bc1033d8eea 100644 GIT binary patch delta 7479 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 Cqu~<( diff --git a/src/client/game.ts b/src/client/game.ts index 5365a3a..d508ec3 100644 --- a/src/client/game.ts +++ b/src/client/game.ts @@ -1,7 +1,8 @@ import e from 'express'; import { Socket } from 'socket.io-client'; +import { Color } from 'three'; import { isMobileOrTablet } from '../common/helper'; -import { CompositePacket } from '../common/types/packet'; +import { CharacterPacket, CompositePacket } from '../common/types/packet'; import { IcyNetUser } from '../common/types/user'; import { ThirdPersonCamera } from './object/camera'; import { Chat } from './object/chat'; @@ -19,6 +20,7 @@ export class Game { public thirdPersonCamera!: ThirdPersonCamera; public joystick!: Joystick; public chat!: Chat; + private character: CharacterPacket = {}; private party: string[] = []; public renderer = new Renderer(); @@ -43,6 +45,11 @@ export class Game { 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) => { @@ -89,6 +96,7 @@ export class Game { 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( @@ -104,6 +112,8 @@ export class Game { if (isMobileOrTablet()) { this.joystick.show(); } + + this.socket.emit('character', this.character); }); this.socket.on('playerjoin', (user) => { @@ -119,6 +129,7 @@ export class Game { 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); } }); @@ -150,6 +161,17 @@ export class Game { }); }); + 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, @@ -167,32 +189,51 @@ export class Game { } private experimentalPlayerCmd(message: string, sender: IcyNetUser) { - if (message.startsWith('!party') && this.me.id === sender.id) { - const array = message.split(' '); - const name = array.slice(2).join(' '); + 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; + } - if (array[1] === 'join') { - this.party.push(name); - this.chat.addMessage(`Joined party of user "${name}".`); + this.player.setColor(color); + this.socket.emit('character', { color }); + localStorage.setItem('color', color); } - if (array[1] === 'leave') { - this.party.splice(this.party.indexOf(name), 1); - this.chat.addMessage(`Left party of user "${name}".`); - } + if (message.startsWith('!party')) { + const array = message.split(' '); + const name = array.slice(2).join(' '); - if (array[1] === 'clear') { - this.party.length = 0; - this.chat.addMessage('Cleared party list.'); - } + if (array[1] === 'join') { + this.party.push(name); + this.chat.addMessage(`Joined party of user "${name}".`); + } - if (array[1] === 'list') { - this.chat.addMessage( - `You have joined the watch party of: ${this.party.join(', ')}`, - ); - } + if (array[1] === 'leave') { + this.party.splice(this.party.indexOf(name), 1); + this.chat.addMessage(`Left party of user "${name}".`); + } - localStorage.setItem('party', this.party.join('|')); + 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 ( diff --git a/src/client/object/player-entity.ts b/src/client/object/player-entity.ts index e02ddc6..905191a 100644 --- a/src/client/object/player-entity.ts +++ b/src/client/object/player-entity.ts @@ -2,6 +2,7 @@ import { IcyNetUser } from '../../common/types/user'; import * as THREE from 'three'; import { PonyEntity } from './pony'; import { + CharacterPacket, FullStatePacket, PositionUpdatePacket, } from '../../common/types/packet'; @@ -101,13 +102,17 @@ export class PlayerEntity extends PonyEntity { ); } - public addUncommittedChanges(packet: PositionUpdatePacket) { + public addUncommittedChanges(packet: FullStatePacket) { const appendix = { ...packet, time: 0.1 }; this._updateQueue.push(appendix); if (!this._targetFrame) { this.setFromPacket(packet); this._targetFrame = appendix; } + + if (packet.character) { + this.setCharacter(packet.character); + } } public update(dt: number) { diff --git a/src/client/object/pony-loader.ts b/src/client/object/pony-loader.ts index b2d166f..82f7555 100644 --- a/src/client/object/pony-loader.ts +++ b/src/client/object/pony-loader.ts @@ -1,5 +1,6 @@ import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; +import { Color, Mesh, MeshStandardMaterial } from 'three'; // Instantiate a loader const loader = new GLTFLoader(); @@ -26,6 +27,11 @@ class PonyModel { // temp: disable frustum culling for eyes this.ponyModel.children[0].children[2].frustumCulled = false; + // ( + // (this.ponyModel.children[0].children[1] as Mesh) + // .material as MeshStandardMaterial + // ).color = new Color(0xffffff); + resolve(gltf.scene); // gltf.animations; // Array diff --git a/src/client/object/pony.ts b/src/client/object/pony.ts index 3d54538..0018091 100644 --- a/src/client/object/pony.ts +++ b/src/client/object/pony.ts @@ -1,9 +1,10 @@ import * as SkeletonUtils from 'three/examples/jsm/utils/SkeletonUtils'; import * as THREE from 'three'; import modelLoaderInstance from './pony-loader'; -import { FullStatePacket } from '../../common/types/packet'; +import { CharacterPacket, FullStatePacket } from '../../common/types/packet'; import { NameTag } from './nametag'; import { CanvasUtils } from './canvas-utils'; +import { Mesh, MeshStandardMaterial, Color } from 'three'; const nameTagBuilder = new CanvasUtils({ fill: false, @@ -19,6 +20,7 @@ export class PonyEntity { public mixer!: THREE.AnimationMixer; public container!: THREE.Object3D; public model!: THREE.Object3D; + public material!: THREE.MeshStandardMaterial; public walkAnimationState = 0; public idleAction: THREE.AnimationAction; public walkAction: THREE.AnimationAction; @@ -27,6 +29,11 @@ export class PonyEntity { initialize() { this.model = (SkeletonUtils as any).clone(modelLoaderInstance.ponyModel); + this.material = ( + (this.model.children[0].children[1] as Mesh) + .material as MeshStandardMaterial + ).clone(); + (this.model.children[0].children[1] as Mesh).material = this.material; this.mixer = new THREE.AnimationMixer(this.model); this.idleAction = this.mixer.clipAction(modelLoaderInstance.animations[0]); this.walkAction = this.mixer.clipAction(modelLoaderInstance.animations[2]); @@ -47,6 +54,12 @@ export class PonyEntity { this.mixer.update(dt); } + dispose() { + this.model = null; + this.material.dispose(); + this.nameTag?.dispose(); + } + public addNameTag(name: string) { this.nameTag = new NameTag(nameTagBuilder, name); this.nameTag.tag.position.set(0, 1.8, 0.5); @@ -68,4 +81,14 @@ export class PonyEntity { this.walkAction.crossFadeTo(this.idleAction.reset(), 0.5, false).play(); } } + + public setColor(color: number | string) { + this.material.color = new Color(color); + } + + public setCharacter(packet: CharacterPacket) { + if (packet.color) { + this.setColor(packet.color); + } + } } diff --git a/src/common/types/packet.ts b/src/common/types/packet.ts index dcf8605..1f5e52b 100644 --- a/src/common/types/packet.ts +++ b/src/common/types/packet.ts @@ -14,6 +14,11 @@ export interface FullStatePacket { position?: number[]; rotation?: (number | string)[]; animState?: number; + character?: CharacterPacket; +} + +export interface CharacterPacket { + color?: number | string; } export interface CompositePacket extends IcyNetUser, FullStatePacket {} diff --git a/src/server/object/game.ts b/src/server/object/game.ts index 3a44478..5c5878d 100644 --- a/src/server/object/game.ts +++ b/src/server/object/game.ts @@ -1,7 +1,10 @@ import { Server, Socket } from 'socket.io'; import { RequestHandler } from 'express'; import { IcyNetUser } from '../../common/types/user'; -import { PositionUpdatePacket } from '../../common/types/packet'; +import { + CharacterPacket, + PositionUpdatePacket, +} from '../../common/types/packet'; const PLACEHOLDER_USER = (socket: Socket): IcyNetUser => { const randomName = `player-${socket.id.substring(0, 8)}`; @@ -55,6 +58,7 @@ export class Game { position: [0, 0, 0], rotation: [0, 0, 0, 'XYZ'], animState: 0, + character: {}, }; socket.emit( @@ -78,6 +82,18 @@ export class Game { } }); + socket.on('character', (info: CharacterPacket) => { + socket.data.playerinfo.character = { + ...socket.data.playerinfo.character, + ...info, + }; + + this.io.emit('playercharacter', { + id: socket.data.user.id, + ...socket.data.playerinfo.character, + }); + }); + socket.on('chat-send', (raw) => { const message = raw.trim().substring(0, 260); this.io.emit('chat', { sender: publicUserInfo, message });