2022-04-09 11:29:54 +00:00
|
|
|
import { Server, Socket } from 'socket.io';
|
|
|
|
import { RequestHandler } from 'express';
|
2022-04-12 15:24:05 +00:00
|
|
|
import { IcyNetUser } from '../common/types/user';
|
|
|
|
import { CharacterPacket, PositionUpdatePacket } from '../common/types/packet';
|
2022-04-16 10:21:07 +00:00
|
|
|
import { Persistence } from './object/persistence';
|
2022-04-09 11:29:54 +00:00
|
|
|
|
|
|
|
const PLACEHOLDER_USER = (socket: Socket): IcyNetUser => {
|
|
|
|
const randomName = `player-${socket.id.substring(0, 8)}`;
|
|
|
|
return {
|
2022-04-12 15:24:05 +00:00
|
|
|
id: Math.floor(Math.random() * 1000 + 1000),
|
2022-04-09 11:29:54 +00:00
|
|
|
username: randomName,
|
|
|
|
display_name: randomName,
|
|
|
|
uuid: socket.id,
|
|
|
|
accessToken: 'player',
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
export class Game {
|
|
|
|
private _connections: Socket[] = [];
|
2022-04-09 14:49:30 +00:00
|
|
|
private _changedPlayers: number[] = [];
|
2022-04-16 10:21:07 +00:00
|
|
|
private _db = new Persistence();
|
2022-04-09 11:29:54 +00:00
|
|
|
|
|
|
|
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() {
|
2022-04-16 10:21:07 +00:00
|
|
|
await this._db.initialize();
|
|
|
|
|
2022-04-09 11:29:54 +00:00
|
|
|
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;
|
|
|
|
|
2022-04-12 15:24:05 +00:00
|
|
|
if (
|
|
|
|
user &&
|
2022-04-16 10:21:07 +00:00
|
|
|
this._connections.find((entry) => entry.data.user?.id === user.id)
|
2022-04-12 15:24:05 +00:00
|
|
|
) {
|
|
|
|
socket.emit('error.duplicate');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-04-09 11:29:54 +00:00
|
|
|
this._connections.push(socket);
|
|
|
|
|
2022-04-09 12:57:20 +00:00
|
|
|
if (user) {
|
|
|
|
socket.broadcast.emit('playerjoin', publicUserInfo);
|
2022-04-09 11:29:54 +00:00
|
|
|
|
2022-04-09 12:57:20 +00:00
|
|
|
socket.data.user = user;
|
2022-04-09 11:29:54 +00:00
|
|
|
socket.data.playerinfo = {
|
2022-04-09 12:57:20 +00:00
|
|
|
velocity: [0, 0, 0],
|
2022-04-09 14:49:30 +00:00
|
|
|
angular: [0, 0, 0, 'XYZ'],
|
2022-04-09 12:57:20 +00:00
|
|
|
position: [0, 0, 0],
|
2022-04-09 14:49:30 +00:00
|
|
|
rotation: [0, 0, 0, 'XYZ'],
|
2022-04-09 12:57:20 +00:00
|
|
|
animState: 0,
|
2022-04-10 06:52:50 +00:00
|
|
|
character: {},
|
2022-04-09 11:29:54 +00:00
|
|
|
};
|
2022-04-09 12:57:20 +00:00
|
|
|
|
|
|
|
socket.on('move', (packet) => {
|
|
|
|
socket.data.playerinfo = {
|
|
|
|
...socket.data.playerinfo,
|
|
|
|
...packet,
|
|
|
|
};
|
2022-04-09 11:29:54 +00:00
|
|
|
});
|
2022-04-10 06:52:50 +00:00
|
|
|
|
|
|
|
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,
|
|
|
|
});
|
|
|
|
});
|
2022-04-09 11:29:54 +00:00
|
|
|
|
2022-04-09 12:57:20 +00:00
|
|
|
socket.on('chat-send', (raw) => {
|
2022-04-10 12:54:29 +00:00
|
|
|
const message = raw.trim().substring(0, 280);
|
2022-04-09 12:57:20 +00:00
|
|
|
this.io.emit('chat', { sender: publicUserInfo, message });
|
|
|
|
});
|
2022-04-16 10:21:07 +00:00
|
|
|
|
|
|
|
this._db.upsertUser(user).then((user) => {
|
|
|
|
this._db.getUserPony(user).then((pony) => {
|
|
|
|
if (pony) {
|
|
|
|
socket.data.playerinfo.character =
|
|
|
|
(pony.character as CharacterPacket) || {};
|
|
|
|
|
|
|
|
socket.data.playerinfo.position = pony.position;
|
|
|
|
socket.data.playerinfo.rotation = pony.rotation;
|
|
|
|
} else {
|
|
|
|
this._db.upsertPony(user, socket.data.playerinfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
socket.emit('me', {
|
|
|
|
...publicUserInfo,
|
|
|
|
character: socket.data.playerinfo.character,
|
|
|
|
position: pony?.position,
|
|
|
|
rotation: pony?.rotation,
|
|
|
|
});
|
|
|
|
|
|
|
|
socket.emit(
|
|
|
|
'players',
|
|
|
|
this._connections
|
|
|
|
.filter((player) => player.data.user)
|
|
|
|
.map((conn) => ({
|
|
|
|
...this.mapPlayer(conn.data.user),
|
|
|
|
...conn.data.playerinfo,
|
|
|
|
})),
|
|
|
|
);
|
|
|
|
|
|
|
|
if (pony) {
|
|
|
|
this.io.emit('playercharacter', {
|
|
|
|
id: socket.data.user.id,
|
|
|
|
...socket.data.playerinfo.character,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
socket.emit('me', null);
|
2022-04-09 12:57:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
socket.on('disconnect', () => {
|
|
|
|
this._connections.splice(this._connections.indexOf(socket), 1);
|
|
|
|
|
|
|
|
if (user) {
|
|
|
|
this.io.emit('playerleave', publicUserInfo);
|
2022-04-16 10:21:07 +00:00
|
|
|
this._db.upsertPony(user, socket.data.playerinfo);
|
2022-04-09 12:57:20 +00:00
|
|
|
}
|
2022-04-09 11:29:54 +00:00
|
|
|
});
|
|
|
|
});
|
2022-04-09 14:49:30 +00:00
|
|
|
|
|
|
|
setInterval(() => {
|
|
|
|
const playerInfo: PositionUpdatePacket[] = [];
|
|
|
|
this._connections
|
|
|
|
.filter(
|
2022-04-12 15:24:05 +00:00
|
|
|
(conn) => conn.data.user, // && this._changedPlayers.includes(conn.data.user.id),
|
2022-04-09 14:49:30 +00:00
|
|
|
)
|
|
|
|
.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;
|
2022-04-09 16:06:53 +00:00
|
|
|
}, 1000 / 60);
|
2022-04-09 11:29:54 +00:00
|
|
|
}
|
|
|
|
}
|