diff --git a/.env b/.env new file mode 100644 index 0000000..418e1d0 --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +PORT = 3000 +TZ = Asia/Taipei \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 1f3a00e..5add0e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "backend-.", "version": "0.1.0", "dependencies": { + "dotenv": "^16.0.0", "tsrpc": "^3.1.3" }, "devDependencies": { @@ -533,6 +534,14 @@ "node": ">=0.3.1" } }, + "node_modules/dotenv": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz", + "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==", + "engines": { + "node": ">=12" + } + }, "node_modules/editorconfig": { "version": "0.15.3", "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", @@ -2504,6 +2513,11 @@ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", "dev": true }, + "dotenv": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz", + "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==" + }, "editorconfig": { "version": "0.15.3", "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", diff --git a/package.json b/package.json index 8bbb607..cd47d49 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "typescript": "^4.5.2" }, "dependencies": { + "dotenv": "^16.0.0", "tsrpc": "^3.1.3" } } diff --git a/src/api/ApiJoin.ts b/src/api/ApiJoin.ts index f03b9ce..f46e823 100644 --- a/src/api/ApiJoin.ts +++ b/src/api/ApiJoin.ts @@ -2,11 +2,11 @@ import { ApiCallWs } from "tsrpc"; import { roomInstance } from ".."; import { ReqJoin, ResJoin } from "../shared/protocols/PtlJoin"; -export async function ApiJoin(call: ApiCallWs) { - let playerId = roomInstance.join(call.req, call.conn); +export async function ApiJoin(call: ApiCallWs): Promise { + let playerId: number = roomInstance.join(call.req, call.conn); call.succ({ playerId: playerId, gameState: roomInstance.gameSystem.state - }) + }); } \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 9771703..e31e518 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,18 +1,19 @@ -import 'k8w-extend-native'; +import "k8w-extend-native"; import * as path from "path"; import { WsConnection, WsServer } from "tsrpc"; -import { Room } from './models/Room'; -import { serviceProto, ServiceType } from './shared/protocols/serviceProto'; +import { Room } from "./models/Room"; +import { serviceProto, ServiceType } from "./shared/protocols/serviceProto"; +require("dotenv").config(); // 创建 TSRPC WebSocket Server -export const server = new WsServer(serviceProto, { - port: 3000, +export const server: WsServer = new WsServer(serviceProto, { + port: +process.env.PORT! || 3000, json: true }); // 断开连接后退出房间 server.flows.postDisconnectFlow.push(v => { - let conn = v.conn as WsConnection; + let conn: WsConnection = v.conn as WsConnection; if (conn.playerId) { roomInstance.leave(conn.playerId, conn); } @@ -20,19 +21,19 @@ server.flows.postDisconnectFlow.push(v => { return v; }); -export const roomInstance = new Room(server); +export const roomInstance: Room = new Room(server); // 初始化 -async function init() { +async function init(): Promise { // 挂载 API 接口 - await server.autoImplementApi(path.resolve(__dirname, 'api')); + await server.autoImplementApi(path.resolve(__dirname, "api")); // TODO // Prepare something... (e.g. connect the db) -}; +} // 启动入口点 -async function main() { +async function main(): Promise { await init(); await server.start(); } diff --git a/src/models/Room.ts b/src/models/Room.ts index f0e7951..f104ddc 100644 --- a/src/models/Room.ts +++ b/src/models/Room.ts @@ -23,78 +23,78 @@ export class Room { constructor(server: WsServer) { this.server = server; - setInterval(() => { this.sync() }, 1000 / this.syncRate); + setInterval(() => { this.sync(); }, 1000 / this.syncRate); } /** 加入房间 */ - join(req: ReqJoin, conn: WsConnection) { + join(req: ReqJoin, conn: WsConnection): number { let input: PlayerJoin = { - type: 'PlayerJoin', + type: "PlayerJoin", playerId: this.nextPlayerId++, // 初始位置随机 pos: { x: Math.random() * 10 - 5, y: Math.random() * 10 - 5 } - } + }; this.applyInput(input); this.conns.push(conn); conn.playerId = input.playerId; - conn.listenMsg('client/ClientInput', call => { + conn.listenMsg("client/ClientInput", call => { this.playerLastSn[input.playerId] = call.msg.sn; call.msg.inputs.forEach(v => { this.applyInput({ ...v, playerId: input.playerId }); - }) + }); }); return input.playerId; } - applyInput(input: GameSystemInput) { + applyInput(input: GameSystemInput): void { this.pendingInputs.push(input); } - sync() { + sync(): void { let inputs = this.pendingInputs; this.pendingInputs = []; // Apply inputs inputs.forEach(v => { - this.gameSystem.applyInput(v) + this.gameSystem.applyInput(v); }); // Apply TimePast let now = process.uptime() * 1000; this.applyInput({ - type: 'TimePast', + type: "TimePast", dt: now - (this.lastSyncTime ?? now) }); this.lastSyncTime = now; // 发送同步帧 this.conns.forEach(v => { - v.sendMsg('server/Frame', { + v.sendMsg("server/Frame", { inputs: inputs, lastSn: this.playerLastSn[v.playerId!] - }) + }); }); } /** 离开房间 */ - leave(playerId: number, conn: WsConnection) { + leave(playerId: number, conn: WsConnection): void { this.conns.removeOne(v => v.playerId === playerId); this.applyInput({ - type: 'PlayerLeave', + type: "PlayerLeave", playerId: playerId }); } } -declare module 'tsrpc' { +declare module "tsrpc" { export interface WsConnection { playerId?: number; } diff --git a/src/shared/game/gameConfig.ts b/src/shared/game/gameConfig.ts index ba58c6f..a09b1ad 100644 --- a/src/shared/game/gameConfig.ts +++ b/src/shared/game/gameConfig.ts @@ -11,4 +11,4 @@ export const gameConfig = { arrowAttackRadius: 2, // 被箭矢几种后的晕眩时间(毫秒) arrowDizzyTime: 1000 -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/shared/protocols/PtlJoin.ts b/src/shared/protocols/PtlJoin.ts index 8b44363..fdc851b 100644 --- a/src/shared/protocols/PtlJoin.ts +++ b/src/shared/protocols/PtlJoin.ts @@ -7,9 +7,9 @@ export interface ReqJoin { export interface ResJoin { /** 加入房间后,自己的 ID */ - playerId: number, + playerId: number; /** 状态同步:一次性同步当前状态 */ - gameState: GameSystemState + gameState: GameSystemState; } // export const conf = {} \ No newline at end of file diff --git a/src/shared/protocols/serviceProto.ts b/src/shared/protocols/serviceProto.ts index 09ed1e8..f53f4bf 100644 --- a/src/shared/protocols/serviceProto.ts +++ b/src/shared/protocols/serviceProto.ts @@ -1,7 +1,7 @@ -import { ServiceProto } from 'tsrpc-proto'; -import { MsgClientInput } from './client/MsgClientInput'; -import { ReqJoin, ResJoin } from './PtlJoin'; -import { MsgFrame } from './server/MsgFrame'; +import { ServiceProto } from "tsrpc-proto"; +import { MsgClientInput } from "./client/MsgClientInput"; +import { ReqJoin, ResJoin } from "./PtlJoin"; +import { MsgFrame } from "./server/MsgFrame"; export interface ServiceType { api: { @@ -9,11 +9,11 @@ export interface ServiceType { req: ReqJoin, res: ResJoin } - }, + }; msg: { "client/ClientInput": MsgClientInput, "server/Frame": MsgFrame - } + }; } export const serviceProto: ServiceProto = { diff --git a/test/api/ApiSend.test.ts b/test/api/ApiSend.test.ts index d733be0..9a704a6 100644 --- a/test/api/ApiSend.test.ts +++ b/test/api/ApiSend.test.ts @@ -17,14 +17,14 @@ describe("ApiSend", function (): void { }); it("Success", async function (): Promise { - let ret: any = await client.callApi("Send", { + let ret: any = await client.callApi("Join", { content: "Test" }); - assert.ok(ret.isSucc) + assert.ok(ret.isSucc); }); it("Check content is empty", async function (): Promise { - let ret: any = await client.callApi("Send", { + let ret: any = await client.callApi("Join", { content: "" }); assert.deepStrictEqual(ret, { @@ -33,7 +33,7 @@ describe("ApiSend", function (): void { }); }); - after(async function () { + after(async function (): Promise { await client.disconnect(); }); }); \ No newline at end of file