testing idk
This commit is contained in:
parent
e2ec33f97c
commit
53181efb97
@ -2,11 +2,12 @@ import { Module } from '@nestjs/common';
|
|||||||
import { EventsModule } from './events/events.module';
|
import { EventsModule } from './events/events.module';
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import { world } from './config/world.config';
|
import { world } from './config/world.config';
|
||||||
|
import { server } from './config/server.config';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({
|
ConfigModule.forRoot({
|
||||||
load: [world],
|
load: [server, world],
|
||||||
}),
|
}),
|
||||||
EventsModule,
|
EventsModule,
|
||||||
],
|
],
|
||||||
|
7
src/config/server.config.ts
Normal file
7
src/config/server.config.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { registerAs } from '@nestjs/config';
|
||||||
|
|
||||||
|
export const server = registerAs('server', () => ({
|
||||||
|
gatewayPort: Number(process.env.GATEWAY_PORT || 8256),
|
||||||
|
statusPort: Number(process.env.PORT || 8255),
|
||||||
|
corsOrigin: process.env.CORS_ORIGIN || '*',
|
||||||
|
}));
|
@ -1,3 +1,4 @@
|
|||||||
|
import { Logger } from '@nestjs/common';
|
||||||
import {
|
import {
|
||||||
ConnectedSocket,
|
ConnectedSocket,
|
||||||
MessageBody,
|
MessageBody,
|
||||||
@ -8,6 +9,7 @@ import {
|
|||||||
WebSocketGateway,
|
WebSocketGateway,
|
||||||
WebSocketServer,
|
WebSocketServer,
|
||||||
} from '@nestjs/websockets';
|
} from '@nestjs/websockets';
|
||||||
|
import { Request } from 'express';
|
||||||
import { Packet } from 'src/net/packet';
|
import { Packet } from 'src/net/packet';
|
||||||
import { PlayerStoreService } from 'src/player/player-store.service';
|
import { PlayerStoreService } from 'src/player/player-store.service';
|
||||||
import { PlayerSocket } from 'src/types/data-socket';
|
import { PlayerSocket } from 'src/types/data-socket';
|
||||||
@ -17,14 +19,12 @@ import { getRandomId } from 'src/utils/random';
|
|||||||
import { WorldService } from 'src/world/world.service';
|
import { WorldService } from 'src/world/world.service';
|
||||||
import { Server } from 'ws';
|
import { Server } from 'ws';
|
||||||
|
|
||||||
@WebSocketGateway(8256, {
|
@WebSocketGateway()
|
||||||
cors: {
|
|
||||||
origin: '*',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
export class EventsGateway
|
export class EventsGateway
|
||||||
implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect
|
implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect
|
||||||
{
|
{
|
||||||
|
private readonly logger = new Logger(EventsGateway.name);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly players: PlayerStoreService,
|
private readonly players: PlayerStoreService,
|
||||||
private readonly world: WorldService,
|
private readonly world: WorldService,
|
||||||
@ -59,6 +59,9 @@ export class EventsGateway
|
|||||||
.toBuffer(),
|
.toBuffer(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
this.logger.log(
|
||||||
|
`Client ${client.id} (${client.ip}) has logged in as ${player.name} (${player.id})`,
|
||||||
|
);
|
||||||
await this.world.initializePlayer(player);
|
await this.world.initializePlayer(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,14 +71,19 @@ export class EventsGateway
|
|||||||
}
|
}
|
||||||
|
|
||||||
afterInit(server: Server) {
|
afterInit(server: Server) {
|
||||||
console.log('server init');
|
this.logger.log(
|
||||||
|
`>>> Game server is listening on port ${server.options.port} <<<`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleConnection(client: PlayerSocket, ...args: any[]) {
|
handleConnection(client: PlayerSocket, request: Request) {
|
||||||
client.id = getRandomId();
|
client.id = getRandomId();
|
||||||
|
client.ip = request.socket.remoteAddress;
|
||||||
|
this.logger.log(`Client ${client.id} connected from ${client.ip}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDisconnect(client: PlayerSocket) {
|
handleDisconnect(client: PlayerSocket) {
|
||||||
|
this.logger.log(`Client ${client.id} (${client.ip}) disconnected.`);
|
||||||
this.world.playerQuit(client);
|
this.world.playerQuit(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ export class Humanoid extends GameObject implements PhysicsTicking {
|
|||||||
private _appliedGravity = new Vector3(0, 0, 0);
|
private _appliedGravity = new Vector3(0, 0, 0);
|
||||||
private _grounded = true;
|
private _grounded = true;
|
||||||
private _lookAt = new Vector3(0, 0, 1);
|
private _lookAt = new Vector3(0, 0, 1);
|
||||||
|
private _lookAtTarget = new Vector3(0, 0, 1);
|
||||||
private _currentLookAt = new Vector3(0, 0, 1);
|
private _currentLookAt = new Vector3(0, 0, 1);
|
||||||
private _animState = 0;
|
private _animState = 0;
|
||||||
|
|
||||||
@ -108,7 +109,7 @@ export class Humanoid extends GameObject implements PhysicsTicking {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setLook(vector: Vector3) {
|
setLook(vector: Vector3) {
|
||||||
this._lookAt.lerp(vector, 0.15);
|
this._lookAtTarget.copy(vector);
|
||||||
}
|
}
|
||||||
|
|
||||||
jump() {
|
jump() {
|
||||||
@ -147,6 +148,7 @@ export class Humanoid extends GameObject implements PhysicsTicking {
|
|||||||
|
|
||||||
// Apply look vector
|
// Apply look vector
|
||||||
this._currentLookAt.copy(this.parent!.position);
|
this._currentLookAt.copy(this.parent!.position);
|
||||||
|
this._lookAt.lerp(this._lookAtTarget, 0.15);
|
||||||
this._currentLookAt.add(this._lookAt);
|
this._currentLookAt.add(this._lookAt);
|
||||||
this.parent?.lookAt(this._currentLookAt);
|
this.parent?.lookAt(this._currentLookAt);
|
||||||
|
|
||||||
|
18
src/main.ts
18
src/main.ts
@ -1,12 +1,24 @@
|
|||||||
import { NestFactory } from '@nestjs/core';
|
import { NestFactory } from '@nestjs/core';
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
import { WsAdapter } from './net/ws-adapter';
|
import { WsAdapter } from './net/ws-adapter';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { Logger } from '@nestjs/common';
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const app = await NestFactory.create(AppModule);
|
const app = await NestFactory.create(AppModule);
|
||||||
app.useWebSocketAdapter(new WsAdapter(app));
|
const config = app.get<ConfigService>(ConfigService);
|
||||||
|
const appPort = config.get<number>('server.statusPort');
|
||||||
|
const gatewayPort = config.get<number>('server.gatewayPort');
|
||||||
|
const corsOrigin = config.get('server.corsOrigin');
|
||||||
|
|
||||||
await app.listen(3000);
|
app.enableCors({
|
||||||
console.log(`Application is running on: ${await app.getUrl()}`);
|
origin: corsOrigin,
|
||||||
|
credentials: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
app.useWebSocketAdapter(new WsAdapter(app, gatewayPort, corsOrigin));
|
||||||
|
await app.listen(appPort);
|
||||||
|
|
||||||
|
Logger.log(`Server status API: ${await app.getUrl()}`, 'bootstrap');
|
||||||
}
|
}
|
||||||
bootstrap();
|
bootstrap();
|
||||||
|
@ -6,10 +6,18 @@ import { mergeMap, filter } from 'rxjs/operators';
|
|||||||
import { Packet } from './packet';
|
import { Packet } from './packet';
|
||||||
|
|
||||||
export class WsAdapter implements WebSocketAdapter {
|
export class WsAdapter implements WebSocketAdapter {
|
||||||
constructor(private app: INestApplicationContext) {}
|
constructor(
|
||||||
|
private app: INestApplicationContext,
|
||||||
|
private port: number,
|
||||||
|
private cors: string,
|
||||||
|
) {}
|
||||||
|
|
||||||
create(port: number, options: any = {}): any {
|
create(port: number, options: any = {}): any {
|
||||||
return new WebSocket.Server({ port, ...options });
|
return new WebSocket.Server({
|
||||||
|
port: this.port || port,
|
||||||
|
...options,
|
||||||
|
cors: { origin: this.cors },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bindClientConnect(
|
bindClientConnect(
|
||||||
|
@ -98,7 +98,9 @@ export class PlayerStoreService {
|
|||||||
|
|
||||||
if (player.controller) {
|
if (player.controller) {
|
||||||
player.controller.setVelocity(velocity);
|
player.controller.setVelocity(velocity);
|
||||||
|
if (!(velocity.x === 0 && velocity.y === 0 && velocity.z === 0)) {
|
||||||
player.controller.setLook(lookAt);
|
player.controller.setLook(lookAt);
|
||||||
|
}
|
||||||
if (jump) player.controller.jump();
|
if (jump) player.controller.jump();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2,4 +2,5 @@ import { WebSocket } from 'ws';
|
|||||||
|
|
||||||
export interface PlayerSocket extends WebSocket {
|
export interface PlayerSocket extends WebSocket {
|
||||||
id: string;
|
id: string;
|
||||||
|
ip: string;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ export enum PacketType {
|
|||||||
*/
|
*/
|
||||||
STREAM_START,
|
STREAM_START,
|
||||||
/**
|
/**
|
||||||
* [][Asset Name][Asset Type][Buffer]
|
* [][Asset Path][Asset Name][Asset Type][Buffer]
|
||||||
*/
|
*/
|
||||||
STREAM_ASSET,
|
STREAM_ASSET,
|
||||||
/**
|
/**
|
||||||
@ -37,7 +37,7 @@ export enum PacketType {
|
|||||||
*/
|
*/
|
||||||
STREAM_CHAT,
|
STREAM_CHAT,
|
||||||
/**
|
/**
|
||||||
* [][Player ID:Player Name]
|
* [][Player count][Player ID:Player Name]
|
||||||
*/
|
*/
|
||||||
PLAYER_LIST,
|
PLAYER_LIST,
|
||||||
/**
|
/**
|
||||||
@ -57,9 +57,13 @@ export enum PacketType {
|
|||||||
*/
|
*/
|
||||||
PLAYER_MOVEMENT,
|
PLAYER_MOVEMENT,
|
||||||
/**
|
/**
|
||||||
* [][Chat Type][Chat Message]
|
* [][Player ID][Chat Type][Chat Message]
|
||||||
*/
|
*/
|
||||||
PLAYER_CHAT,
|
PLAYER_CHAT,
|
||||||
|
/**
|
||||||
|
* [][Player ID][Object UUID][Event][JSON]
|
||||||
|
*/
|
||||||
|
PLAYER_EVENT,
|
||||||
/**
|
/**
|
||||||
* [][Error type]
|
* [][Error type]
|
||||||
*/
|
*/
|
||||||
|
@ -7,6 +7,9 @@ import { Object3D, Vector3 } from 'three';
|
|||||||
import { GameObject } from 'src/game/game-object';
|
import { GameObject } from 'src/game/game-object';
|
||||||
import { PhysicsTicking } from 'src/physics';
|
import { PhysicsTicking } from 'src/physics';
|
||||||
|
|
||||||
|
const PHYSICS_STEPPING = 1000 / 60;
|
||||||
|
const PHYSICS_STEPPING_S = 1 / 60;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PhysicsService {
|
export class PhysicsService {
|
||||||
private world!: World;
|
private world!: World;
|
||||||
@ -23,16 +26,16 @@ export class PhysicsService {
|
|||||||
if (!this.running) return;
|
if (!this.running) return;
|
||||||
this.physicsTicker = setInterval(() => {
|
this.physicsTicker = setInterval(() => {
|
||||||
this.physicsWorld.step();
|
this.physicsWorld.step();
|
||||||
for (const object of this.trackedObjects) object.tick(0.016);
|
for (const object of this.trackedObjects) object.tick(PHYSICS_STEPPING_S);
|
||||||
this.tickCallback?.();
|
this.tickCallback?.();
|
||||||
}, 16);
|
}, PHYSICS_STEPPING);
|
||||||
}
|
}
|
||||||
|
|
||||||
async start(world: World, cb?: () => void) {
|
async start(world: World, cb?: () => void) {
|
||||||
this.world = world;
|
this.world = world;
|
||||||
await RAPIER.init();
|
await RAPIER.init();
|
||||||
this.physicsWorld = new RAPIER.World(new Vector3(0, this.world.gravity, 0));
|
this.physicsWorld = new RAPIER.World(new Vector3(0, this.world.gravity, 0));
|
||||||
this.physicsWorld.timestep = 0.016;
|
this.physicsWorld.timestep = PHYSICS_STEPPING_S;
|
||||||
this.running = true;
|
this.running = true;
|
||||||
this.tickCallback = cb;
|
this.tickCallback = cb;
|
||||||
this.initializePhysicsScene();
|
this.initializePhysicsScene();
|
||||||
@ -54,10 +57,7 @@ export class PhysicsService {
|
|||||||
.write(object.uuid, String)
|
.write(object.uuid, String)
|
||||||
.write(body.translation(), 'vec3')
|
.write(body.translation(), 'vec3')
|
||||||
.write(body.rotation(), 'quat')
|
.write(body.rotation(), 'quat')
|
||||||
.write(
|
.write(body.linvel(), 'vec3')
|
||||||
object instanceof Humanoid ? body.nextTranslation() : body.linvel(),
|
|
||||||
'vec3',
|
|
||||||
)
|
|
||||||
.write(body.angvel(), 'vec3')
|
.write(body.angvel(), 'vec3')
|
||||||
.toBuffer(),
|
.toBuffer(),
|
||||||
);
|
);
|
||||||
|
@ -32,11 +32,11 @@ export class WorldService implements OnModuleInit {
|
|||||||
this.logger.log('Loading world file from environment');
|
this.logger.log('Loading world file from environment');
|
||||||
this.loadWorld()
|
this.loadWorld()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.logger.log('World file loaded');
|
this.logger.log('World file loaded!');
|
||||||
this.physics.start(this.world, () => {
|
this.physics.start(this.world, () => {
|
||||||
if (this.broadcastTick >= 0.25) {
|
|
||||||
this.broadcastTick = 0;
|
|
||||||
this.broadcastWorldState();
|
this.broadcastWorldState();
|
||||||
|
if (this.broadcastTick >= 0.5) {
|
||||||
|
this.broadcastTick = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.broadcastTick += 0.016;
|
this.broadcastTick += 0.016;
|
||||||
@ -71,6 +71,9 @@ export class WorldService implements OnModuleInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async initializePlayer(player: Player) {
|
public async initializePlayer(player: Player) {
|
||||||
|
this.logger.debug(
|
||||||
|
`Initializing player ${player.name} (${player.id}), sending world file..`,
|
||||||
|
);
|
||||||
// Streaming start
|
// Streaming start
|
||||||
player.send(
|
player.send(
|
||||||
new Packet(PacketType.STREAM_START)
|
new Packet(PacketType.STREAM_START)
|
||||||
@ -121,6 +124,10 @@ export class WorldService implements OnModuleInit {
|
|||||||
this.players
|
this.players
|
||||||
.getPlayerCharacterPackets(player)
|
.getPlayerCharacterPackets(player)
|
||||||
.forEach((packet) => player.send(packet));
|
.forEach((packet) => player.send(packet));
|
||||||
|
|
||||||
|
this.logger.log(
|
||||||
|
`PLAYER ${player.name} (${player.id}) has joined the game!`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeObject(object: Object3D) {
|
public removeObject(object: Object3D) {
|
||||||
@ -197,6 +204,7 @@ export class WorldService implements OnModuleInit {
|
|||||||
);
|
);
|
||||||
this.removeObject(player.controller);
|
this.removeObject(player.controller);
|
||||||
this.removeObject(player.character);
|
this.removeObject(player.character);
|
||||||
|
this.logger.log(`PLAYER ${player.name} (${player.id}) has left the game.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
private recursiveCreate(entry: SerializedObject, setParent?: Object3D) {
|
private recursiveCreate(entry: SerializedObject, setParent?: Object3D) {
|
||||||
|
Loading…
Reference in New Issue
Block a user