icy3dw/src/server/game.ts

136 lines
3.7 KiB
TypeScript

import { Server, Socket } from 'socket.io';
import { RequestHandler } from 'express';
import { IcyNetUser } from '../common/types/user';
import { CharacterPacket, PositionUpdatePacket } from '../common/types/packet';
const PLACEHOLDER_USER = (socket: Socket): IcyNetUser => {
const randomName = `player-${socket.id.substring(0, 8)}`;
return {
id: Math.floor(Math.random() * 1000 + 1000),
username: randomName,
display_name: randomName,
uuid: socket.id,
accessToken: 'player',
};
};
export class Game {
private _connections: Socket[] = [];
private _changedPlayers: number[] = [];
constructor(private io: Server, private session: RequestHandler) {}
private mapPlayer(user: IcyNetUser): any {
return {
id: user.id,
username: user.username,
display_name: user.display_name,
};
}
async initialize() {
this.io.use((socket, next) =>
this.session(socket.request as any, {} as any, next as any),
);
this.io.on('connection', (socket) => {
const session = (socket.request as any).session;
const user =
process.env.SKIP_LOGIN === 'true'
? PLACEHOLDER_USER(socket)
: (session?.passport?.user as IcyNetUser);
const publicUserInfo = user ? this.mapPlayer(user) : null;
if (
user &&
this._connections.find((entry) => entry.data.user.id === user.id)
) {
socket.emit('error.duplicate');
return;
}
this._connections.push(socket);
socket.emit('me', publicUserInfo);
if (user) {
socket.broadcast.emit('playerjoin', publicUserInfo);
socket.data.user = user;
socket.data.playerinfo = {
velocity: [0, 0, 0],
angular: [0, 0, 0, 'XYZ'],
position: [0, 0, 0],
rotation: [0, 0, 0, 'XYZ'],
animState: 0,
character: {},
};
socket.emit(
'players',
this._connections
.filter((player) => player.data.user)
.map((conn) => ({
...this.mapPlayer(conn.data.user),
...conn.data.playerinfo,
})),
);
socket.on('move', (packet) => {
socket.data.playerinfo = {
...socket.data.playerinfo,
...packet,
};
// if (!this._changedPlayers.includes(socket.data.user.id)) {
// this._changedPlayers.push(socket.data.user.id);
// }
});
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, 280);
this.io.emit('chat', { sender: publicUserInfo, message });
});
}
socket.on('disconnect', () => {
this._connections.splice(this._connections.indexOf(socket), 1);
if (user) {
this.io.emit('playerleave', publicUserInfo);
}
});
});
setInterval(() => {
const playerInfo: PositionUpdatePacket[] = [];
this._connections
.filter(
(conn) => conn.data.user, // && this._changedPlayers.includes(conn.data.user.id),
)
.forEach((conn) =>
playerInfo.push({
position: conn.data.playerinfo.position,
rotation: conn.data.playerinfo.rotation,
animState: conn.data.playerinfo.animState,
id: conn.data.user.id,
}),
);
this.io.emit('playerupdate', playerInfo);
this._changedPlayers.length = 0;
}, 1000 / 60);
}
}