This commit is contained in:
Evert Prants 2022-05-15 13:54:15 +03:00
parent 78374144a8
commit f9d6329e4a
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
9 changed files with 109 additions and 34 deletions

View File

@ -1,7 +1,11 @@
import { Socket } from 'socket.io-client';
import { Color, DoubleSide, MeshBasicMaterial, Vector3 } from 'three';
import { isMobileOrTablet } from '../common/helper';
import { CharacterPacket, CompositePacket } from '../common/types/packet';
import {
CharacterPacket,
CompositePacket,
PositionUpdatePacket,
} from '../common/types/packet';
import { IcyNetUser } from '../common/types/user';
import { Chat } from './object/chat';
import { Joystick } from './object/joystick';
@ -18,6 +22,10 @@ import { ClientWorld } from './object/world/client-world';
import { ClientWorldManifest } from './object/world/client-world-manifest';
import { ClientWorldLoader } from './object/world/client-world-loader';
import { LoadingManagerWrapper } from './object/resource/loading-manager';
import {
ClientToServerEvents,
ServerToClientEvents,
} from '../common/types/socket';
export class Game {
public players: (Player | PlayerEntity)[] = [];
@ -35,7 +43,9 @@ export class Game {
private videoTest = new VideoPlayer(24, 12);
constructor(public socket: Socket) {}
constructor(
public socket: Socket<ServerToClientEvents, ClientToServerEvents>,
) {}
async initialize(): Promise<void> {
this._loading.initialize();
@ -75,7 +85,7 @@ export class Game {
// end of
this.chat.registerSendFunction((message) => {
this.socket.emit('chat-send', message);
this.socket.emit('set.chat', message);
});
this.renderer.registerUpdateFunction((dt: number) => {
@ -187,7 +197,7 @@ export class Game {
);
});
this.socket.on('me', (user) => {
this.socket.on('set.me', (user) => {
if (!user) {
this._loading.showError('Error: You need to log in!');
window.location.href = '/login';
@ -223,10 +233,10 @@ export class Game {
this.joystick.show();
}
this.socket.emit('character', this.character);
this.socket.emit('set.character', this.character);
});
this.socket.on('playerjoin', (user) => {
this.socket.on('player.join', (user) => {
if (user.id === this.me.id) {
return;
}
@ -239,7 +249,7 @@ export class Game {
this.players.push(newplayer);
});
this.socket.on('playerleave', (user) => {
this.socket.on('player.leave', (user) => {
const findPlayer = this.players.find((item) => item.user.id === user.id);
if (findPlayer) {
this.chat.addMessage(`${user.display_name} has left the game.`, null, {
@ -252,7 +262,7 @@ export class Game {
}
});
this.socket.on('players', (list: CompositePacket[]) => {
this.socket.on('player.list', (list: CompositePacket[]) => {
list.forEach((player) => {
if (player.id === this.me.id) {
return;
@ -273,8 +283,8 @@ export class Game {
);
});
this.socket.on('playerupdate', (data) => {
data.forEach((item) => {
this.socket.on('player.update', (data) => {
data.forEach((item: PositionUpdatePacket) => {
const player = this.players.find(
(player) => player.user.id === item.id,
);
@ -288,7 +298,7 @@ export class Game {
});
});
this.socket.on('playercharacter', (data) => {
this.socket.on('player.character', (data) => {
const player = this.players.find((player) => player.user.id === data.id);
if (
player &&
@ -299,7 +309,7 @@ export class Game {
}
});
this.socket.on('chat', (event) => {
this.socket.on('player.chat', (event) => {
const player = this.players.find(
(item) => item.user.id === event.sender.id,
);
@ -325,7 +335,7 @@ export class Game {
});
}
private experimentalPlayerCmd(message: string, sender: IcyNetUser) {
private experimentalPlayerCmd(message: string, sender: Partial<IcyNetUser>) {
if (this.me.id === sender.id) {
if (message.startsWith('!color')) {
const [cmd, color] = message.split(' ');
@ -341,7 +351,7 @@ export class Game {
this.character = { ...this.character, color };
this.player.setColor(color);
this.socket.emit('character', this.character);
this.socket.emit('set.character', this.character);
}
if (message.startsWith('!eyecolor')) {
@ -358,8 +368,8 @@ export class Game {
this.character = { ...this.character, eyeColor };
this.player.setEyeColor(eyeColor);
this.socket.emit('character', this.character);
localStorage.setItem('character', JSON.stringify(this.character));
this.socket.emit('set.character', this.character);
localStorage.setItem('set.character', JSON.stringify(this.character));
}
if (message.startsWith('!party')) {

View File

@ -90,7 +90,7 @@ export class Player extends PonyEntity {
public createPacket(socket: Socket): void {
if (Object.keys(this.changes).length) {
socket.emit('move', this.changes);
socket.emit('set.move', this.changes);
this.changes = {};
}
}

View File

@ -0,0 +1,27 @@
import {
CharacterPacket,
CompositePacket,
FullStatePacket,
PositionUpdatePacket,
} from './packet';
import { IcyNetUser } from './user';
export interface ServerToClientEvents {
'set.me': (player: CompositePacket | null) => void;
'error.duplicate': () => void;
'player.list': (players: Partial<CompositePacket[]>) => void;
'player.chat': (data: {
sender: Partial<IcyNetUser>;
message: string;
}) => void;
'player.join': (player: IcyNetUser) => void;
'player.leave': (player: Partial<IcyNetUser>) => void;
'player.update': (packet: Partial<PositionUpdatePacket[]>) => void;
'player.character': (packet: CharacterPacket & { id: number }) => void;
}
export interface ClientToServerEvents {
'set.chat': (message: string) => void;
'set.character': (packet: CharacterPacket) => void;
'set.move': (packet: FullStatePacket) => void;
}

View File

@ -7,6 +7,12 @@ import { ServerWorld } from './world/server-world';
import { ServerWorldLoader } from './world/server-world-loader';
import { ServerWorldManifest } from './world/server-world-manifest';
import { Player } from './object/player';
import {
ServerToClientEvents,
ClientToServerEvents,
} from '../common/types/socket';
import { InterServerEvents, SocketData } from './types/socket';
import { CompositePacket } from '../common/types/packet';
const PLACEHOLDER_USER = (socket: Socket): IcyNetUser => {
const randomName = `player-${socket.id.substring(0, 8)}`;
@ -25,7 +31,15 @@ export class Game {
private _log = new Logger();
private _world!: ServerWorld;
constructor(private io: Server, private session: RequestHandler) {}
constructor(
private io: Server<
ClientToServerEvents,
ServerToClientEvents,
InterServerEvents,
SocketData
>,
private session: RequestHandler,
) {}
async initialize() {
const manifest = await ServerWorldManifest.loadManifest();
@ -61,26 +75,26 @@ export class Game {
player.initialize().then(() => {
// Send player list to new player
socket.emit(
'players',
'player.list',
this._players
.filter((player) => player.user)
.map((player) => ({
...player.getPublicUserProfile(),
...player.toSave(),
...(player.toSave() as CompositePacket),
})),
);
});
socket.on('chat-send', (raw) => {
socket.on('set.chat', (raw) => {
const message = raw.trim().substring(0, 280);
this._log.writeChat(user, message);
this.io.emit('chat', {
this.io.emit('player.chat', {
sender: player.getPublicUserProfile(),
message,
});
});
} else {
socket.emit('me', null);
socket.emit('set.me', null);
}
socket.on('disconnect', () => {
@ -93,7 +107,7 @@ export class Game {
return;
}
this.io.emit('playerleave', player.getPublicUserProfile());
this.io.emit('player.leave', player.getPublicUserProfile());
this._log.writeEvent(
'PlayerLeave',
@ -109,7 +123,7 @@ export class Game {
setInterval(() => {
this._players.forEach((player) => player.update(1000 / 60));
this.io.emit(
'playerupdate',
'player.update',
this._players.map((player) => player.toUpdatePacket()),
);
}, 1000 / 60);

View File

@ -9,9 +9,14 @@ import http from 'http';
import { join } from 'path';
import { Server } from 'socket.io';
import { IcyNetUser } from '../common/types/user';
import {
ServerToClientEvents,
ClientToServerEvents,
} from '../common/types/socket';
import { config } from './config';
import { Game } from './game';
import { InterServerEvents, SocketData } from './types/socket';
const RedisStore = connectRedis(session);
const redisClient = config.redis?.enabled ? redis.createClient() : undefined;
@ -63,7 +68,12 @@ if (process.env.NODE_ENV === 'production') {
}
const server = http.createServer(app);
const io = new Server(server);
const io = new Server<
ClientToServerEvents,
ServerToClientEvents,
InterServerEvents,
SocketData
>(server);
const checkAuth: RequestHandler = (req, res, next) => {
if (req.isAuthenticated()) {

View File

@ -0,0 +1,5 @@
export class Minigame {
public readonly name = 'game';
public readonly requiredPlayers = 2;
public readonly maxPlayers = 2;
}

View File

@ -73,10 +73,11 @@ export class Persistence {
const keys = this.filterPonyKeys(updateData);
const insert = Array.from({ length: keys.length }, () => '?').join(',');
await this.db.run(
const res = await this.db.run(
`INSERT INTO Pony (${keys.join(',')}) VALUES (${insert})`,
keys.map((key) => (updateData as any)[key]),
);
updateData.id = res.lastID;
return this.deserializePony(updateData);
}
@ -127,7 +128,7 @@ export class Persistence {
'display_name',
'position',
'rotation',
'character',
'set.character',
'created_at',
'user_id',
];

View File

@ -10,6 +10,7 @@ import { DatabasePony } from '../types/database';
import { Persistence } from './persistence';
export class Player {
public id!: number;
public position = new Vector3();
public rotation = new Vector3();
public velocity = new Vector3();
@ -24,14 +25,14 @@ export class Player {
) {}
async initialize() {
this.socket.on('move', (packet: FullStatePacket) => {
this.socket.on('set.move', (packet: FullStatePacket) => {
this.fromPacket(packet);
});
this.socket.on('character', (info: CharacterPacket) => {
this.socket.on('set.character', (info: CharacterPacket) => {
this.setCharacter(info);
this.socket.broadcast.emit('playercharacter', {
this.socket.broadcast.emit('player.character', {
id: this.user.id,
...this.getCharacter(),
});
@ -46,15 +47,15 @@ export class Player {
await this.db.upsertPony(user, this.toSave());
}
this.socket.emit('me', {
this.socket.emit('set.me', {
...this.getPublicUserProfile(),
...this.toSave(),
});
this.socket.broadcast.emit('playerjoin', this.getPublicUserProfile());
this.socket.broadcast.emit('player.join', this.getPublicUserProfile());
if (pony && pony.character) {
this.socket.broadcast.emit('playercharacter', {
this.socket.broadcast.emit('player.character', {
id: this.user.id,
character: this.getCharacter(),
});

View File

@ -0,0 +1,7 @@
import { Player } from '../object/player';
export interface SocketData {
player: Player;
}
export interface InterServerEvents {}