This commit is contained in:
Evert Prants 2022-04-10 09:52:50 +03:00
parent 43c1fe0f96
commit 057425695e
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
7 changed files with 120 additions and 24 deletions

Binary file not shown.

View File

@ -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 (

View File

@ -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) {

View File

@ -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<THREE.AnimationClip>

View File

@ -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);
}
}
}

View File

@ -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 {}

View File

@ -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 });