icy3dw/src/client/object/player-entity.ts

185 lines
4.8 KiB
TypeScript
Raw Normal View History

2022-04-09 11:29:54 +00:00
import { IcyNetUser } from '../../common/types/user';
2022-04-12 15:24:05 +00:00
import { PonyEntity } from './model/pony';
2022-04-09 14:49:30 +00:00
import {
FullStatePacket,
PositionUpdatePacket,
} from '../../common/types/packet';
2022-04-09 12:57:20 +00:00
import { CanvasUtils } from './canvas-utils';
import { ChatBubble } from './chat-bubble';
2022-04-10 08:33:52 +00:00
import { Vector3, Scene, Euler } from 'three';
2022-04-09 12:57:20 +00:00
2022-04-09 16:06:53 +00:00
const chatBuilder = new CanvasUtils({
rounded: true,
roundedRadius: 8,
});
2022-04-09 11:29:54 +00:00
export class PlayerEntity extends PonyEntity {
2022-04-09 14:49:30 +00:00
private _updateQueue: PositionUpdatePacket[] = [];
private _targetFrame: any = null;
private _lastFrame: any = null;
2022-04-09 12:57:20 +00:00
private _chats: ChatBubble[] = [];
2022-04-10 08:33:52 +00:00
private _p1 = new Vector3();
private _p2 = new Vector3();
private _q1 = new Vector3();
private _q2 = new Vector3();
2022-04-09 14:49:30 +00:00
2022-04-10 08:33:52 +00:00
private _pf = new Vector3();
private _qf = new Vector3();
2022-04-09 14:49:30 +00:00
2022-04-09 11:29:54 +00:00
constructor(public user: IcyNetUser) {
super();
}
2022-04-10 08:33:52 +00:00
public static fromUser(user: IcyNetUser, scene: Scene): PlayerEntity {
2022-04-09 11:29:54 +00:00
const entity = new PlayerEntity(user);
entity.initialize();
entity.addNameTag(user.display_name);
scene.add(entity.container);
return entity;
}
2022-04-10 08:33:52 +00:00
public setVelocity(velocity: Vector3) {
2022-04-09 11:29:54 +00:00
this.velocity.copy(velocity);
}
2022-04-10 08:33:52 +00:00
public setAngularVelocity(velocity: Vector3) {
2022-04-09 11:29:54 +00:00
this.angularVelocity.copy(velocity);
}
2022-04-10 08:33:52 +00:00
public setPosition(pos: Vector3) {
2022-04-09 11:29:54 +00:00
this.container.position.copy(pos);
}
2022-04-09 12:57:20 +00:00
public addChat(message: string): void {
const lines = [];
let truncated = message;
while (truncated.length > 80) {
lines.push(truncated.substring(0, 80));
truncated = truncated.substring(80);
}
if (truncated) {
lines.push(truncated);
}
const newChat = new ChatBubble(chatBuilder, lines);
this._chats.forEach((item) => {
2022-04-09 15:17:07 +00:00
const scaled = item.tag.scale.y;
2022-04-10 08:33:52 +00:00
item.tag.position.add(new Vector3(0, scaled, 0));
2022-04-09 12:57:20 +00:00
});
this._chats.unshift(newChat);
2022-04-09 15:17:07 +00:00
newChat.tag.position.set(0, 1.8 + this.nameTag.tag.scale.y + 0.15, 0.5);
2022-04-09 12:57:20 +00:00
this.container.add(newChat.tag);
if (this._chats.length > 3) {
this._chats.splice(3, this._chats.length - 1).forEach((item) => {
this.container.remove(item.tag);
item.dispose();
});
}
setTimeout(() => {
const i = this._chats.indexOf(newChat);
if (i !== -1) {
this.container.remove(newChat.tag);
this._chats.splice(i, 1);
newChat.dispose();
}
}, 5000);
}
2022-04-10 08:33:52 +00:00
public setRotation(rot: Vector3 | Euler) {
2022-04-09 11:29:54 +00:00
this.container.rotation.copy(
2022-04-10 08:33:52 +00:00
rot instanceof Euler ? rot : new Euler(rot.x, rot.y, rot.z, 'XYZ'),
2022-04-09 11:29:54 +00:00
);
}
2022-04-10 06:52:50 +00:00
public addUncommittedChanges(packet: FullStatePacket) {
2022-04-09 14:49:30 +00:00
const appendix = { ...packet, time: 0.1 };
this._updateQueue.push(appendix);
if (!this._targetFrame) {
this.setFromPacket(packet);
this._targetFrame = appendix;
}
2022-04-10 06:52:50 +00:00
if (packet.character) {
this.setCharacter(packet.character);
}
2022-04-09 11:29:54 +00:00
}
public update(dt: number) {
2022-04-09 14:49:30 +00:00
this.commitServerUpdate(dt);
2022-04-09 13:23:46 +00:00
super.update(dt);
2022-04-09 11:29:54 +00:00
}
2022-04-09 14:49:30 +00:00
private setFromPacket(packet: FullStatePacket | PositionUpdatePacket) {
if ((packet as FullStatePacket).velocity) {
this.setVelocity(
2022-04-10 08:33:52 +00:00
new Vector3().fromArray((packet as FullStatePacket).velocity),
2022-04-09 14:49:30 +00:00
);
}
if ((packet as FullStatePacket).angular) {
this.setAngularVelocity(
2022-04-10 08:33:52 +00:00
new Vector3().fromArray((packet as FullStatePacket).angular),
2022-04-09 14:49:30 +00:00
);
2022-04-09 11:29:54 +00:00
}
if (packet.position) {
2022-04-10 08:33:52 +00:00
this.setPosition(new Vector3().fromArray(packet.position));
2022-04-09 11:29:54 +00:00
}
if (packet.rotation) {
2022-04-10 08:33:52 +00:00
this.setRotation(new Euler().fromArray(packet.rotation));
2022-04-09 11:29:54 +00:00
}
if (packet.animState) {
this.setWalkAnimationState(packet.animState);
}
}
2022-04-09 14:49:30 +00:00
private commitServerUpdate(dt: number) {
if (this._updateQueue.length == 0) {
return;
}
for (let i = 0; i < this._updateQueue.length; ++i) {
this._updateQueue[i].time -= dt;
}
while (this._updateQueue.length > 0 && this._updateQueue[0].time <= 0.0) {
this._lastFrame = {
animState: this._targetFrame.animState,
position: this.container.position.toArray(),
rotation: this.container.rotation.toArray(),
};
this._targetFrame = this._updateQueue.shift();
this._targetFrame.time = 0.0;
}
// Lerp the position and rotation
if (this._targetFrame && this._lastFrame) {
this._targetFrame.time += dt;
this._p1.fromArray(this._lastFrame.position);
this._p2.fromArray(this._targetFrame.position);
this._q1.fromArray(this._lastFrame.rotation);
this._q2.fromArray(this._targetFrame.rotation);
this._pf.copy(this._p1);
this._qf.copy(this._q1);
const t = Math.max(Math.min(this._targetFrame.time / 0.1, 1.0), 0.0);
this._pf.lerp(this._p2, t);
this._qf.lerp(this._q2, t);
this.setPosition(this._pf);
this.setRotation(this._qf);
this.setWalkAnimationState(this._lastFrame.animState);
}
2022-04-09 11:29:54 +00:00
}
}