[add] first templates
This commit is contained in:
		
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					node_modules
 | 
				
			||||||
 | 
					dist
 | 
				
			||||||
 | 
					.DS_STORE
 | 
				
			||||||
 | 
					*.meta
 | 
				
			||||||
							
								
								
									
										11
									
								
								.mocharc.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								.mocharc.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					    require: [
 | 
				
			||||||
 | 
					        'ts-node/register',
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    timeout: 999999,
 | 
				
			||||||
 | 
					    exit: true,
 | 
				
			||||||
 | 
					    spec: [
 | 
				
			||||||
 | 
					        './test/**/*.test.ts'
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    'preserve-symlinks': true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										30
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					    "configurations": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "type": "node",
 | 
				
			||||||
 | 
					            "request": "launch",
 | 
				
			||||||
 | 
					            "name": "mocha current file",
 | 
				
			||||||
 | 
					            "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
 | 
				
			||||||
 | 
					            "args": [
 | 
				
			||||||
 | 
					                "${file}"
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            "internalConsoleOptions": "openOnSessionStart",
 | 
				
			||||||
 | 
					            "cwd": "${workspaceFolder}"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "type": "node",
 | 
				
			||||||
 | 
					            "request": "launch",
 | 
				
			||||||
 | 
					            "name": "ts-node current file",
 | 
				
			||||||
 | 
					            "protocol": "inspector",
 | 
				
			||||||
 | 
					            "args": [
 | 
				
			||||||
 | 
					                "${relativeFile}"
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            "cwd": "${workspaceRoot}",
 | 
				
			||||||
 | 
					            "runtimeArgs": [
 | 
				
			||||||
 | 
					                "-r",
 | 
				
			||||||
 | 
					                "ts-node/register"
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            "internalConsoleOptions": "openOnSessionStart"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					    "typescript.tsdk": "node_modules\\typescript\\lib"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										30
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					FROM node
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 使用淘宝 NPM 镜像(国内机器构建推荐启用)
 | 
				
			||||||
 | 
					# RUN npm config set registry https://registry.npm.taobao.org/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# npm install
 | 
				
			||||||
 | 
					ADD package*.json /src/
 | 
				
			||||||
 | 
					WORKDIR /src
 | 
				
			||||||
 | 
					RUN npm i
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# build
 | 
				
			||||||
 | 
					ADD . /src
 | 
				
			||||||
 | 
					RUN npm run build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# clean
 | 
				
			||||||
 | 
					RUN npm prune --production
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# move
 | 
				
			||||||
 | 
					RUN rm -rf /app \
 | 
				
			||||||
 | 
					    && mv dist /app \
 | 
				
			||||||
 | 
					    && mv node_modules /app/ \
 | 
				
			||||||
 | 
					    && rm -rf /src
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ENV
 | 
				
			||||||
 | 
					ENV NODE_ENV production
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EXPOSE 3000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WORKDIR /app
 | 
				
			||||||
 | 
					CMD node index.js
 | 
				
			||||||
							
								
								
									
										49
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					# TSRPC Server
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Usage
 | 
				
			||||||
 | 
					### Local dev server
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Dev server would restart automatically when code changed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					npm run dev
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Run unit Test
 | 
				
			||||||
 | 
					Execute `npm run dev` first, then execute:
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					npm run test
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Build
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					npm run build
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Additional Scripts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Generate API document
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Generate API document in swagger/openapi and markdown format.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```shell
 | 
				
			||||||
 | 
					npm run doc
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Generate ServiceProto
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					npm run proto
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Generate API templates
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					npm run api
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Manually sync shared code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					npm run sync
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
							
								
								
									
										3672
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										3672
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										27
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "name": "backend-.",
 | 
				
			||||||
 | 
					  "version": "0.1.0",
 | 
				
			||||||
 | 
					  "main": "index.js",
 | 
				
			||||||
 | 
					  "private": true,
 | 
				
			||||||
 | 
					  "scripts": {
 | 
				
			||||||
 | 
					    "proto": "tsrpc proto",
 | 
				
			||||||
 | 
					    "sync": "tsrpc link",
 | 
				
			||||||
 | 
					    "api": "tsrpc api",
 | 
				
			||||||
 | 
					    "doc": "tsrpc doc",
 | 
				
			||||||
 | 
					    "dev": "tsrpc dev",
 | 
				
			||||||
 | 
					    "test": "mocha test/**/*.test.ts",
 | 
				
			||||||
 | 
					    "build": "tsrpc build"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "devDependencies": {
 | 
				
			||||||
 | 
					    "@types/mocha": "^8.2.3",
 | 
				
			||||||
 | 
					    "@types/node": "^15.14.9",
 | 
				
			||||||
 | 
					    "mocha": "^9.1.3",
 | 
				
			||||||
 | 
					    "onchange": "^7.1.0",
 | 
				
			||||||
 | 
					    "ts-node": "^10.4.0",
 | 
				
			||||||
 | 
					    "tsrpc-cli": "^2.2.2",
 | 
				
			||||||
 | 
					    "typescript": "^4.5.2"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "tsrpc": "^3.1.3"
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								src/api/ApiJoin.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/api/ApiJoin.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					import { ApiCallWs } from "tsrpc";
 | 
				
			||||||
 | 
					import { roomInstance } from "..";
 | 
				
			||||||
 | 
					import { ReqJoin, ResJoin } from "../shared/protocols/PtlJoin";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function ApiJoin(call: ApiCallWs<ReqJoin, ResJoin>) {
 | 
				
			||||||
 | 
					    let playerId = roomInstance.join(call.req, call.conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    call.succ({
 | 
				
			||||||
 | 
					        playerId: playerId,
 | 
				
			||||||
 | 
					        gameState: roomInstance.gameSystem.state
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										39
									
								
								src/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					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';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 创建 TSRPC WebSocket Server
 | 
				
			||||||
 | 
					export const server = new WsServer(serviceProto, {
 | 
				
			||||||
 | 
					    port: 3000,
 | 
				
			||||||
 | 
					    json: true
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 断开连接后退出房间
 | 
				
			||||||
 | 
					server.flows.postDisconnectFlow.push(v => {
 | 
				
			||||||
 | 
					    let conn = v.conn as WsConnection<ServiceType>;
 | 
				
			||||||
 | 
					    if (conn.playerId) {
 | 
				
			||||||
 | 
					        roomInstance.leave(conn.playerId, conn);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return v;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const roomInstance = new Room(server);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 初始化
 | 
				
			||||||
 | 
					async function init() {
 | 
				
			||||||
 | 
					    // 挂载 API 接口
 | 
				
			||||||
 | 
					    await server.autoImplementApi(path.resolve(__dirname, 'api'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO
 | 
				
			||||||
 | 
					    // Prepare something... (e.g. connect the db)
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 启动入口点
 | 
				
			||||||
 | 
					async function main() {
 | 
				
			||||||
 | 
					    await init();
 | 
				
			||||||
 | 
					    await server.start();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					main();
 | 
				
			||||||
							
								
								
									
										101
									
								
								src/models/Room.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								src/models/Room.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
				
			|||||||
 | 
					import { WsConnection, WsServer } from "tsrpc";
 | 
				
			||||||
 | 
					import { gameConfig } from "../shared/game/gameConfig";
 | 
				
			||||||
 | 
					import { GameSystem, GameSystemInput, PlayerJoin } from "../shared/game/GameSystem";
 | 
				
			||||||
 | 
					import { ReqJoin } from "../shared/protocols/PtlJoin";
 | 
				
			||||||
 | 
					import { ServiceType } from "../shared/protocols/serviceProto";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 服务端 - 房间 - 逻辑系统
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export class Room {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 帧同步频率,次数/秒
 | 
				
			||||||
 | 
					    syncRate = gameConfig.syncRate;
 | 
				
			||||||
 | 
					    nextPlayerId = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gameSystem = new GameSystem();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    server: WsServer<ServiceType>;
 | 
				
			||||||
 | 
					    conns: WsConnection<ServiceType>[] = [];
 | 
				
			||||||
 | 
					    pendingInputs: GameSystemInput[] = [];
 | 
				
			||||||
 | 
					    playerLastSn: { [playerId: number]: number | undefined } = {};
 | 
				
			||||||
 | 
					    lastSyncTime?: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(server: WsServer<ServiceType>) {
 | 
				
			||||||
 | 
					        this.server = server;
 | 
				
			||||||
 | 
					        setInterval(() => { this.sync() }, 1000 / this.syncRate);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 加入房间 */
 | 
				
			||||||
 | 
					    join(req: ReqJoin, conn: WsConnection<ServiceType>) {
 | 
				
			||||||
 | 
					        let input: 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 => {
 | 
				
			||||||
 | 
					            this.playerLastSn[input.playerId] = call.msg.sn;
 | 
				
			||||||
 | 
					            call.msg.inputs.forEach(v => {
 | 
				
			||||||
 | 
					                this.applyInput({
 | 
				
			||||||
 | 
					                    ...v,
 | 
				
			||||||
 | 
					                    playerId: input.playerId
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return input.playerId;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    applyInput(input: GameSystemInput) {
 | 
				
			||||||
 | 
					        this.pendingInputs.push(input);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sync() {
 | 
				
			||||||
 | 
					        let inputs = this.pendingInputs;
 | 
				
			||||||
 | 
					        this.pendingInputs = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Apply inputs
 | 
				
			||||||
 | 
					        inputs.forEach(v => {
 | 
				
			||||||
 | 
					            this.gameSystem.applyInput(v)
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Apply TimePast
 | 
				
			||||||
 | 
					        let now = process.uptime() * 1000;
 | 
				
			||||||
 | 
					        this.applyInput({
 | 
				
			||||||
 | 
					            type: 'TimePast',
 | 
				
			||||||
 | 
					            dt: now - (this.lastSyncTime ?? now)
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        this.lastSyncTime = now;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 发送同步帧
 | 
				
			||||||
 | 
					        this.conns.forEach(v => {
 | 
				
			||||||
 | 
					            v.sendMsg('server/Frame', {
 | 
				
			||||||
 | 
					                inputs: inputs,
 | 
				
			||||||
 | 
					                lastSn: this.playerLastSn[v.playerId!]
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 离开房间 */
 | 
				
			||||||
 | 
					    leave(playerId: number, conn: WsConnection<ServiceType>) {
 | 
				
			||||||
 | 
					        this.conns.removeOne(v => v.playerId === playerId);
 | 
				
			||||||
 | 
					        this.applyInput({
 | 
				
			||||||
 | 
					            type: 'PlayerLeave',
 | 
				
			||||||
 | 
					            playerId: playerId
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					declare module 'tsrpc' {
 | 
				
			||||||
 | 
					    export interface WsConnection {
 | 
				
			||||||
 | 
					        playerId?: number;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										143
									
								
								src/shared/game/GameSystem.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								src/shared/game/GameSystem.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,143 @@
 | 
				
			|||||||
 | 
					import { gameConfig } from "./gameConfig";
 | 
				
			||||||
 | 
					import { ArrowState } from "./state/ArrowState";
 | 
				
			||||||
 | 
					import { PlayerState } from "./state/PlayerState";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 状态定义
 | 
				
			||||||
 | 
					export interface GameSystemState {
 | 
				
			||||||
 | 
					    // 当前的时间(游戏时间)
 | 
				
			||||||
 | 
					    now: number,
 | 
				
			||||||
 | 
					    // 玩家
 | 
				
			||||||
 | 
					    players: PlayerState[],
 | 
				
			||||||
 | 
					    // 飞行中的箭矢
 | 
				
			||||||
 | 
					    arrows: ArrowState[],
 | 
				
			||||||
 | 
					    // 箭矢的 ID 生成
 | 
				
			||||||
 | 
					    nextArrowId: number
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 前后端复用的状态计算模块
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export class GameSystem {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 当前状态
 | 
				
			||||||
 | 
					    private _state: GameSystemState = {
 | 
				
			||||||
 | 
					        now: 0,
 | 
				
			||||||
 | 
					        players: [],
 | 
				
			||||||
 | 
					        arrows: [],
 | 
				
			||||||
 | 
					        nextArrowId: 1
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    get state(): Readonly<GameSystemState> {
 | 
				
			||||||
 | 
					        return this._state
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 重设状态
 | 
				
			||||||
 | 
					    reset(state: GameSystemState) {
 | 
				
			||||||
 | 
					        this._state = Object.merge({}, state);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 应用输入,计算状态变更
 | 
				
			||||||
 | 
					    applyInput(input: GameSystemInput) {
 | 
				
			||||||
 | 
					        if (input.type === 'PlayerMove') {
 | 
				
			||||||
 | 
					            let player = this._state.players.find(v => v.id === input.playerId);
 | 
				
			||||||
 | 
					            if (!player) {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (player.dizzyEndTime && player.dizzyEndTime > this._state.now) {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            player.pos.x += input.speed.x * input.dt;
 | 
				
			||||||
 | 
					            player.pos.y += input.speed.y * input.dt;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (input.type === 'PlayerAttack') {
 | 
				
			||||||
 | 
					            let player = this._state.players.find(v => v.id === input.playerId);
 | 
				
			||||||
 | 
					            if (player) {
 | 
				
			||||||
 | 
					                let newArrow: ArrowState = {
 | 
				
			||||||
 | 
					                    id: this._state.nextArrowId++,
 | 
				
			||||||
 | 
					                    fromPlayerId: input.playerId,
 | 
				
			||||||
 | 
					                    targetPos: { ...input.targetPos },
 | 
				
			||||||
 | 
					                    targetTime: input.targetTime
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                this._state.arrows.push(newArrow);
 | 
				
			||||||
 | 
					                this.onNewArrow.forEach(v => v(newArrow));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (input.type === 'PlayerJoin') {
 | 
				
			||||||
 | 
					            this.state.players.push({
 | 
				
			||||||
 | 
					                id: input.playerId,
 | 
				
			||||||
 | 
					                pos: { ...input.pos }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (input.type === 'PlayerLeave') {
 | 
				
			||||||
 | 
					            this.state.players.remove(v => v.id === input.playerId);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (input.type === 'TimePast') {
 | 
				
			||||||
 | 
					            this._state.now += input.dt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // 落地的 Arrow
 | 
				
			||||||
 | 
					            for (let i = this._state.arrows.length - 1; i > -1; --i) {
 | 
				
			||||||
 | 
					                let arrow = this._state.arrows[i];
 | 
				
			||||||
 | 
					                if (arrow.targetTime <= this._state.now) {
 | 
				
			||||||
 | 
					                    // 伤害判定
 | 
				
			||||||
 | 
					                    let damagedPlayers = this._state.players.filter(v => {
 | 
				
			||||||
 | 
					                        return (v.pos.x - arrow.targetPos.x) * (v.pos.x - arrow.targetPos.x) + (v.pos.y - arrow.targetPos.y) * (v.pos.y - arrow.targetPos.y) <= gameConfig.arrowAttackRadius * gameConfig.arrowAttackRadius
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                    damagedPlayers.forEach(p => {
 | 
				
			||||||
 | 
					                        // 设置击晕状态
 | 
				
			||||||
 | 
					                        p.dizzyEndTime = this._state.now + gameConfig.arrowDizzyTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        // Event
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    this._state.arrows.splice(i, 1);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * 事件
 | 
				
			||||||
 | 
					     * 某些转瞬即逝的事件,可能不会直观的体现在前后两帧状态的变化中,但表面层又需要知晓。
 | 
				
			||||||
 | 
					     * 例如一颗狙击枪的子弹,在少于一帧的时间内创建和销毁,前后两帧的状态中都不包含这颗子弹;但表现层却需要绘制出子弹的弹道。
 | 
				
			||||||
 | 
					     * 此时,可以通过事件的方式通知表现层。
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    // 发射箭矢
 | 
				
			||||||
 | 
					    onNewArrow: ((arrow: ArrowState) => void)[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface PlayerMove {
 | 
				
			||||||
 | 
					    type: 'PlayerMove',
 | 
				
			||||||
 | 
					    playerId: number,
 | 
				
			||||||
 | 
					    speed: { x: number, y: number },
 | 
				
			||||||
 | 
					    // 移动的时间 (秒)
 | 
				
			||||||
 | 
					    dt: number,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export interface PlayerAttack {
 | 
				
			||||||
 | 
					    type: 'PlayerAttack',
 | 
				
			||||||
 | 
					    playerId: number,
 | 
				
			||||||
 | 
					    // 落点坐标
 | 
				
			||||||
 | 
					    targetPos: { x: number, y: number },
 | 
				
			||||||
 | 
					    // 落点时间(游戏时间)
 | 
				
			||||||
 | 
					    targetTime: number
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export interface PlayerJoin {
 | 
				
			||||||
 | 
					    type: 'PlayerJoin',
 | 
				
			||||||
 | 
					    playerId: number,
 | 
				
			||||||
 | 
					    pos: { x: number, y: number }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export interface PlayerLeave {
 | 
				
			||||||
 | 
					    type: 'PlayerLeave',
 | 
				
			||||||
 | 
					    playerId: number
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// 时间流逝
 | 
				
			||||||
 | 
					export interface TimePast {
 | 
				
			||||||
 | 
					    type: 'TimePast',
 | 
				
			||||||
 | 
					    dt: number
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// 输入定义
 | 
				
			||||||
 | 
					export type GameSystemInput = PlayerMove
 | 
				
			||||||
 | 
					    | PlayerAttack
 | 
				
			||||||
 | 
					    | PlayerJoin
 | 
				
			||||||
 | 
					    | PlayerLeave
 | 
				
			||||||
 | 
					    | TimePast;
 | 
				
			||||||
							
								
								
									
										14
									
								
								src/shared/game/gameConfig.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/shared/game/gameConfig.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					export const gameConfig = {
 | 
				
			||||||
 | 
					    syncRate: 10,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    moveSpeed: 10,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 箭矢飞行时间(毫秒)
 | 
				
			||||||
 | 
					    arrowFlyTime: 500,
 | 
				
			||||||
 | 
					    // 箭矢投掷距离
 | 
				
			||||||
 | 
					    arrowDistance: 8,
 | 
				
			||||||
 | 
					    // 箭矢落地命中判定半径
 | 
				
			||||||
 | 
					    arrowAttackRadius: 2,
 | 
				
			||||||
 | 
					    // 被箭矢几种后的晕眩时间(毫秒)
 | 
				
			||||||
 | 
					    arrowDizzyTime: 1000
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/shared/game/state/ArrowState.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/shared/game/state/ArrowState.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					export type ArrowState = {
 | 
				
			||||||
 | 
					    id: number,
 | 
				
			||||||
 | 
					    // 谁发出的箭
 | 
				
			||||||
 | 
					    fromPlayerId: number,
 | 
				
			||||||
 | 
					    // 落地时间(游戏时间)
 | 
				
			||||||
 | 
					    targetTime: number,
 | 
				
			||||||
 | 
					    // 落点位置(游戏位置)
 | 
				
			||||||
 | 
					    targetPos: { x: number, y: number }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										7
									
								
								src/shared/game/state/PlayerState.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/shared/game/state/PlayerState.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					export interface PlayerState {
 | 
				
			||||||
 | 
					    id: number,
 | 
				
			||||||
 | 
					    // 位置
 | 
				
			||||||
 | 
					    pos: { x: number, y: number },
 | 
				
			||||||
 | 
					    // 晕眩结束时间
 | 
				
			||||||
 | 
					    dizzyEndTime?: number,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										15
									
								
								src/shared/protocols/PtlJoin.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/shared/protocols/PtlJoin.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					import { GameSystemState } from "../game/GameSystem";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 加入房间 */
 | 
				
			||||||
 | 
					export interface ReqJoin {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface ResJoin {
 | 
				
			||||||
 | 
					    /** 加入房间后,自己的 ID */
 | 
				
			||||||
 | 
					    playerId: number,
 | 
				
			||||||
 | 
					    /** 状态同步:一次性同步当前状态 */
 | 
				
			||||||
 | 
					    gameState: GameSystemState
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// export const conf = {}
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/shared/protocols/client/MsgClientInput.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/shared/protocols/client/MsgClientInput.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					import { PlayerAttack, PlayerMove } from "../../game/GameSystem";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 发送自己的输入 */
 | 
				
			||||||
 | 
					export interface MsgClientInput {
 | 
				
			||||||
 | 
					    sn: number,
 | 
				
			||||||
 | 
					    inputs: ClientInput[]
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type ClientInput = Omit<PlayerMove, 'playerId'> | Omit<PlayerAttack, 'playerId'>;
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/shared/protocols/server/MsgFrame.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/shared/protocols/server/MsgFrame.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					import { GameSystemInput } from "../../game/GameSystem";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
					 * 服务端定期广播的同步帧
 | 
				
			||||||
 | 
					 * 包含了这一段期间所有输入
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export interface MsgFrame {
 | 
				
			||||||
 | 
					    inputs: GameSystemInput[],
 | 
				
			||||||
 | 
					    /** 当前用户提交的,经服务端确认的最后一条输入的 SN */
 | 
				
			||||||
 | 
					    lastSn?: number
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										496
									
								
								src/shared/protocols/serviceProto.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										496
									
								
								src/shared/protocols/serviceProto.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,496 @@
 | 
				
			|||||||
 | 
					import { ServiceProto } from 'tsrpc-proto';
 | 
				
			||||||
 | 
					import { MsgClientInput } from './client/MsgClientInput';
 | 
				
			||||||
 | 
					import { ReqJoin, ResJoin } from './PtlJoin';
 | 
				
			||||||
 | 
					import { MsgFrame } from './server/MsgFrame';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface ServiceType {
 | 
				
			||||||
 | 
					    api: {
 | 
				
			||||||
 | 
					        "Join": {
 | 
				
			||||||
 | 
					            req: ReqJoin,
 | 
				
			||||||
 | 
					            res: ResJoin
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    msg: {
 | 
				
			||||||
 | 
					        "client/ClientInput": MsgClientInput,
 | 
				
			||||||
 | 
					        "server/Frame": MsgFrame
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const serviceProto: ServiceProto<ServiceType> = {
 | 
				
			||||||
 | 
					    "services": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "id": 0,
 | 
				
			||||||
 | 
					            "name": "client/ClientInput",
 | 
				
			||||||
 | 
					            "type": "msg"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "id": 1,
 | 
				
			||||||
 | 
					            "name": "Join",
 | 
				
			||||||
 | 
					            "type": "api"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "id": 2,
 | 
				
			||||||
 | 
					            "name": "server/Frame",
 | 
				
			||||||
 | 
					            "type": "msg"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "types": {
 | 
				
			||||||
 | 
					        "client/MsgClientInput/MsgClientInput": {
 | 
				
			||||||
 | 
					            "type": "Interface",
 | 
				
			||||||
 | 
					            "properties": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 0,
 | 
				
			||||||
 | 
					                    "name": "sn",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Number"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 1,
 | 
				
			||||||
 | 
					                    "name": "inputs",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Array",
 | 
				
			||||||
 | 
					                        "elementType": {
 | 
				
			||||||
 | 
					                            "type": "Reference",
 | 
				
			||||||
 | 
					                            "target": "client/MsgClientInput/ClientInput"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "client/MsgClientInput/ClientInput": {
 | 
				
			||||||
 | 
					            "type": "Union",
 | 
				
			||||||
 | 
					            "members": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 0,
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "target": {
 | 
				
			||||||
 | 
					                            "type": "Reference",
 | 
				
			||||||
 | 
					                            "target": "../game/GameSystem/PlayerMove"
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        "keys": [
 | 
				
			||||||
 | 
					                            "playerId"
 | 
				
			||||||
 | 
					                        ],
 | 
				
			||||||
 | 
					                        "type": "Omit"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 1,
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "target": {
 | 
				
			||||||
 | 
					                            "type": "Reference",
 | 
				
			||||||
 | 
					                            "target": "../game/GameSystem/PlayerAttack"
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        "keys": [
 | 
				
			||||||
 | 
					                            "playerId"
 | 
				
			||||||
 | 
					                        ],
 | 
				
			||||||
 | 
					                        "type": "Omit"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "../game/GameSystem/PlayerMove": {
 | 
				
			||||||
 | 
					            "type": "Interface",
 | 
				
			||||||
 | 
					            "properties": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 0,
 | 
				
			||||||
 | 
					                    "name": "type",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Literal",
 | 
				
			||||||
 | 
					                        "literal": "PlayerMove"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 1,
 | 
				
			||||||
 | 
					                    "name": "playerId",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Number"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 2,
 | 
				
			||||||
 | 
					                    "name": "speed",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Interface",
 | 
				
			||||||
 | 
					                        "properties": [
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                "id": 0,
 | 
				
			||||||
 | 
					                                "name": "x",
 | 
				
			||||||
 | 
					                                "type": {
 | 
				
			||||||
 | 
					                                    "type": "Number"
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                "id": 1,
 | 
				
			||||||
 | 
					                                "name": "y",
 | 
				
			||||||
 | 
					                                "type": {
 | 
				
			||||||
 | 
					                                    "type": "Number"
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        ]
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 3,
 | 
				
			||||||
 | 
					                    "name": "dt",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Number"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "../game/GameSystem/PlayerAttack": {
 | 
				
			||||||
 | 
					            "type": "Interface",
 | 
				
			||||||
 | 
					            "properties": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 0,
 | 
				
			||||||
 | 
					                    "name": "type",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Literal",
 | 
				
			||||||
 | 
					                        "literal": "PlayerAttack"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 1,
 | 
				
			||||||
 | 
					                    "name": "playerId",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Number"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 2,
 | 
				
			||||||
 | 
					                    "name": "targetPos",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Interface",
 | 
				
			||||||
 | 
					                        "properties": [
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                "id": 0,
 | 
				
			||||||
 | 
					                                "name": "x",
 | 
				
			||||||
 | 
					                                "type": {
 | 
				
			||||||
 | 
					                                    "type": "Number"
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                "id": 1,
 | 
				
			||||||
 | 
					                                "name": "y",
 | 
				
			||||||
 | 
					                                "type": {
 | 
				
			||||||
 | 
					                                    "type": "Number"
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        ]
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 3,
 | 
				
			||||||
 | 
					                    "name": "targetTime",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Number"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "PtlJoin/ReqJoin": {
 | 
				
			||||||
 | 
					            "type": "Interface"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "PtlJoin/ResJoin": {
 | 
				
			||||||
 | 
					            "type": "Interface",
 | 
				
			||||||
 | 
					            "properties": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 0,
 | 
				
			||||||
 | 
					                    "name": "playerId",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Number"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 1,
 | 
				
			||||||
 | 
					                    "name": "gameState",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Reference",
 | 
				
			||||||
 | 
					                        "target": "../game/GameSystem/GameSystemState"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "../game/GameSystem/GameSystemState": {
 | 
				
			||||||
 | 
					            "type": "Interface",
 | 
				
			||||||
 | 
					            "properties": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 0,
 | 
				
			||||||
 | 
					                    "name": "now",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Number"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 1,
 | 
				
			||||||
 | 
					                    "name": "players",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Array",
 | 
				
			||||||
 | 
					                        "elementType": {
 | 
				
			||||||
 | 
					                            "type": "Reference",
 | 
				
			||||||
 | 
					                            "target": "../game/state/PlayerState/PlayerState"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 2,
 | 
				
			||||||
 | 
					                    "name": "arrows",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Array",
 | 
				
			||||||
 | 
					                        "elementType": {
 | 
				
			||||||
 | 
					                            "type": "Reference",
 | 
				
			||||||
 | 
					                            "target": "../game/state/ArrowState/ArrowState"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 3,
 | 
				
			||||||
 | 
					                    "name": "nextArrowId",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Number"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "../game/state/PlayerState/PlayerState": {
 | 
				
			||||||
 | 
					            "type": "Interface",
 | 
				
			||||||
 | 
					            "properties": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 0,
 | 
				
			||||||
 | 
					                    "name": "id",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Number"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 1,
 | 
				
			||||||
 | 
					                    "name": "pos",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Interface",
 | 
				
			||||||
 | 
					                        "properties": [
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                "id": 0,
 | 
				
			||||||
 | 
					                                "name": "x",
 | 
				
			||||||
 | 
					                                "type": {
 | 
				
			||||||
 | 
					                                    "type": "Number"
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                "id": 1,
 | 
				
			||||||
 | 
					                                "name": "y",
 | 
				
			||||||
 | 
					                                "type": {
 | 
				
			||||||
 | 
					                                    "type": "Number"
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        ]
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 2,
 | 
				
			||||||
 | 
					                    "name": "dizzyEndTime",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Number"
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "optional": true
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "../game/state/ArrowState/ArrowState": {
 | 
				
			||||||
 | 
					            "type": "Interface",
 | 
				
			||||||
 | 
					            "properties": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 0,
 | 
				
			||||||
 | 
					                    "name": "id",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Number"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 1,
 | 
				
			||||||
 | 
					                    "name": "fromPlayerId",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Number"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 2,
 | 
				
			||||||
 | 
					                    "name": "targetTime",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Number"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 3,
 | 
				
			||||||
 | 
					                    "name": "targetPos",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Interface",
 | 
				
			||||||
 | 
					                        "properties": [
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                "id": 0,
 | 
				
			||||||
 | 
					                                "name": "x",
 | 
				
			||||||
 | 
					                                "type": {
 | 
				
			||||||
 | 
					                                    "type": "Number"
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                "id": 1,
 | 
				
			||||||
 | 
					                                "name": "y",
 | 
				
			||||||
 | 
					                                "type": {
 | 
				
			||||||
 | 
					                                    "type": "Number"
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        ]
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "server/MsgFrame/MsgFrame": {
 | 
				
			||||||
 | 
					            "type": "Interface",
 | 
				
			||||||
 | 
					            "properties": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 0,
 | 
				
			||||||
 | 
					                    "name": "inputs",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Array",
 | 
				
			||||||
 | 
					                        "elementType": {
 | 
				
			||||||
 | 
					                            "type": "Reference",
 | 
				
			||||||
 | 
					                            "target": "../game/GameSystem/GameSystemInput"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 1,
 | 
				
			||||||
 | 
					                    "name": "lastSn",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Number"
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    "optional": true
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "../game/GameSystem/GameSystemInput": {
 | 
				
			||||||
 | 
					            "type": "Union",
 | 
				
			||||||
 | 
					            "members": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 0,
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Reference",
 | 
				
			||||||
 | 
					                        "target": "../game/GameSystem/PlayerMove"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 1,
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Reference",
 | 
				
			||||||
 | 
					                        "target": "../game/GameSystem/PlayerAttack"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 2,
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Reference",
 | 
				
			||||||
 | 
					                        "target": "../game/GameSystem/PlayerJoin"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 3,
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Reference",
 | 
				
			||||||
 | 
					                        "target": "../game/GameSystem/PlayerLeave"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 4,
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Reference",
 | 
				
			||||||
 | 
					                        "target": "../game/GameSystem/TimePast"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "../game/GameSystem/PlayerJoin": {
 | 
				
			||||||
 | 
					            "type": "Interface",
 | 
				
			||||||
 | 
					            "properties": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 0,
 | 
				
			||||||
 | 
					                    "name": "type",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Literal",
 | 
				
			||||||
 | 
					                        "literal": "PlayerJoin"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 1,
 | 
				
			||||||
 | 
					                    "name": "playerId",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Number"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 2,
 | 
				
			||||||
 | 
					                    "name": "pos",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Interface",
 | 
				
			||||||
 | 
					                        "properties": [
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                "id": 0,
 | 
				
			||||||
 | 
					                                "name": "x",
 | 
				
			||||||
 | 
					                                "type": {
 | 
				
			||||||
 | 
					                                    "type": "Number"
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                "id": 1,
 | 
				
			||||||
 | 
					                                "name": "y",
 | 
				
			||||||
 | 
					                                "type": {
 | 
				
			||||||
 | 
					                                    "type": "Number"
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        ]
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "../game/GameSystem/PlayerLeave": {
 | 
				
			||||||
 | 
					            "type": "Interface",
 | 
				
			||||||
 | 
					            "properties": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 0,
 | 
				
			||||||
 | 
					                    "name": "type",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Literal",
 | 
				
			||||||
 | 
					                        "literal": "PlayerLeave"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 1,
 | 
				
			||||||
 | 
					                    "name": "playerId",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Number"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "../game/GameSystem/TimePast": {
 | 
				
			||||||
 | 
					            "type": "Interface",
 | 
				
			||||||
 | 
					            "properties": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 0,
 | 
				
			||||||
 | 
					                    "name": "type",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Literal",
 | 
				
			||||||
 | 
					                        "literal": "TimePast"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "id": 1,
 | 
				
			||||||
 | 
					                    "name": "dt",
 | 
				
			||||||
 | 
					                    "type": {
 | 
				
			||||||
 | 
					                        "type": "Number"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										39
									
								
								test/api/ApiSend.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								test/api/ApiSend.test.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					import assert from "assert";
 | 
				
			||||||
 | 
					import { TsrpcError, WsClient } from "tsrpc";
 | 
				
			||||||
 | 
					import { serviceProto, ServiceType } from "../../src/shared/protocols/serviceProto";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 1. EXECUTE `npm run dev` TO START A LOCAL DEV SERVER
 | 
				
			||||||
 | 
					// 2. EXECUTE `npm test` TO START UNIT TEST
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe("ApiSend", function (): void {
 | 
				
			||||||
 | 
					    let client: WsClient<ServiceType> = new WsClient(serviceProto, {
 | 
				
			||||||
 | 
					        server: "ws://127.0.0.1:3000",
 | 
				
			||||||
 | 
					        logger: console
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    before(async function (): Promise<void> {
 | 
				
			||||||
 | 
					        let res: any = await client.connect();
 | 
				
			||||||
 | 
					        assert.strictEqual(res.isSucc, true, "Failed to connect to server, have you executed `npm run dev` already?");
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it("Success", async function (): Promise<void> {
 | 
				
			||||||
 | 
					        let ret: any = await client.callApi("Send", {
 | 
				
			||||||
 | 
					            content: "Test"
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        assert.ok(ret.isSucc)
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it("Check content is empty", async function (): Promise<void> {
 | 
				
			||||||
 | 
					        let ret: any = await client.callApi("Send", {
 | 
				
			||||||
 | 
					            content: ""
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        assert.deepStrictEqual(ret, {
 | 
				
			||||||
 | 
					            isSucc: false,
 | 
				
			||||||
 | 
					            err: new TsrpcError("Content is empty")
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    after(async function () {
 | 
				
			||||||
 | 
					        await client.disconnect();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										15
									
								
								test/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								test/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "compilerOptions": {
 | 
				
			||||||
 | 
					    "lib": [
 | 
				
			||||||
 | 
					      "es2018"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "module": "commonjs",
 | 
				
			||||||
 | 
					    "target": "es2018",
 | 
				
			||||||
 | 
					    "outDir": "dist",
 | 
				
			||||||
 | 
					    "strict": true,
 | 
				
			||||||
 | 
					    "esModuleInterop": true,
 | 
				
			||||||
 | 
					    "skipLibCheck": true,
 | 
				
			||||||
 | 
					    "forceConsistentCasingInFileNames": true,
 | 
				
			||||||
 | 
					    "moduleResolution": "node"
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										18
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "compilerOptions": {
 | 
				
			||||||
 | 
					    "lib": [
 | 
				
			||||||
 | 
					      "es2018"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "module": "commonjs",
 | 
				
			||||||
 | 
					    "target": "es2018",
 | 
				
			||||||
 | 
					    "outDir": "dist",
 | 
				
			||||||
 | 
					    "strict": true,
 | 
				
			||||||
 | 
					    "esModuleInterop": true,
 | 
				
			||||||
 | 
					    "skipLibCheck": true,
 | 
				
			||||||
 | 
					    "forceConsistentCasingInFileNames": true,
 | 
				
			||||||
 | 
					    "moduleResolution": "node"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "include": [
 | 
				
			||||||
 | 
					    "src"
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										116
									
								
								tslint.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								tslint.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,116 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					    "defaultSeverity": "warning",
 | 
				
			||||||
 | 
					    "rules": {
 | 
				
			||||||
 | 
					        "ban": [
 | 
				
			||||||
 | 
					            true,
 | 
				
			||||||
 | 
					            [
 | 
				
			||||||
 | 
					                "_",
 | 
				
			||||||
 | 
					                "extend"
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            [
 | 
				
			||||||
 | 
					                "_",
 | 
				
			||||||
 | 
					                "isNull"
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            [
 | 
				
			||||||
 | 
					                "_",
 | 
				
			||||||
 | 
					                "isDefined"
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "class-name": false,
 | 
				
			||||||
 | 
					        "comment-format": [
 | 
				
			||||||
 | 
					            true,
 | 
				
			||||||
 | 
					            "check-space"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "curly": true,
 | 
				
			||||||
 | 
					        "eofline": false,
 | 
				
			||||||
 | 
					        "forin": false,
 | 
				
			||||||
 | 
					        "indent": [
 | 
				
			||||||
 | 
					            true,
 | 
				
			||||||
 | 
					            4
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "interface-name": [
 | 
				
			||||||
 | 
					            true,
 | 
				
			||||||
 | 
					            "never-prefix"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "jsdoc-format": true,
 | 
				
			||||||
 | 
					        "label-position": true,
 | 
				
			||||||
 | 
					        "label-undefined": true,
 | 
				
			||||||
 | 
					        "max-line-length": [
 | 
				
			||||||
 | 
					            false,
 | 
				
			||||||
 | 
					            140
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "no-arg": true,
 | 
				
			||||||
 | 
					        "no-bitwise": false,
 | 
				
			||||||
 | 
					        "no-console": [
 | 
				
			||||||
 | 
					            true,
 | 
				
			||||||
 | 
					            "debug",
 | 
				
			||||||
 | 
					            "info",
 | 
				
			||||||
 | 
					            "time",
 | 
				
			||||||
 | 
					            "timeEnd",
 | 
				
			||||||
 | 
					            "trace"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "no-construct": true,
 | 
				
			||||||
 | 
					        "no-debugger": true,
 | 
				
			||||||
 | 
					        "no-duplicate-key": true,
 | 
				
			||||||
 | 
					        "no-duplicate-variable": true,
 | 
				
			||||||
 | 
					        "no-empty": true,
 | 
				
			||||||
 | 
					        // "no-eval": true,
 | 
				
			||||||
 | 
					        "no-string-literal": false,
 | 
				
			||||||
 | 
					        "no-trailing-comma": true,
 | 
				
			||||||
 | 
					        "no-trailing-whitespace": true,
 | 
				
			||||||
 | 
					        "no-unused-expression": false,
 | 
				
			||||||
 | 
					        "no-unused-variable": true,
 | 
				
			||||||
 | 
					        "no-unreachable": true,
 | 
				
			||||||
 | 
					        "no-use-before-declare": false,
 | 
				
			||||||
 | 
					        "one-line": [
 | 
				
			||||||
 | 
					            true,
 | 
				
			||||||
 | 
					            "check-open-brace",
 | 
				
			||||||
 | 
					            "check-catch",
 | 
				
			||||||
 | 
					            "check-else",
 | 
				
			||||||
 | 
					            "check-whitespace"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "quotemark": [
 | 
				
			||||||
 | 
					            true,
 | 
				
			||||||
 | 
					            "double"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "radix": true,
 | 
				
			||||||
 | 
					        "semicolon": [
 | 
				
			||||||
 | 
					            true,
 | 
				
			||||||
 | 
					            "always"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "triple-equals": [
 | 
				
			||||||
 | 
					            true,
 | 
				
			||||||
 | 
					            "allow-null-check"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "typedef": [
 | 
				
			||||||
 | 
					            true,
 | 
				
			||||||
 | 
					            "call-signature",
 | 
				
			||||||
 | 
					            "parameter",
 | 
				
			||||||
 | 
					            "property-declaration",
 | 
				
			||||||
 | 
					            "variable-declaration"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "typedef-whitespace": [
 | 
				
			||||||
 | 
					            true,
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "call-signature": "nospace"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "index-signature": "space"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "use-strict": [
 | 
				
			||||||
 | 
					            true,
 | 
				
			||||||
 | 
					            "check-module",
 | 
				
			||||||
 | 
					            "check-function"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "variable-name": false,
 | 
				
			||||||
 | 
					        "whitespace": [
 | 
				
			||||||
 | 
					            false,
 | 
				
			||||||
 | 
					            "check-branch",
 | 
				
			||||||
 | 
					            "check-decl",
 | 
				
			||||||
 | 
					            "check-operator",
 | 
				
			||||||
 | 
					            "check-separator",
 | 
				
			||||||
 | 
					            "check-type"
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										39
									
								
								tsrpc.config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								tsrpc.config.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					import { TsrpcConfig } from 'tsrpc-cli';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const tsrpcConf: TsrpcConfig = {
 | 
				
			||||||
 | 
					    // Generate ServiceProto
 | 
				
			||||||
 | 
					    proto: [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            ptlDir: 'src/shared/protocols', // Protocol dir
 | 
				
			||||||
 | 
					            output: 'src/shared/protocols/serviceProto.ts', // Path for generated ServiceProto
 | 
				
			||||||
 | 
					            apiDir: 'src/api',   // API dir
 | 
				
			||||||
 | 
					            docDir: 'docs',     // API documents dir
 | 
				
			||||||
 | 
					            // ptlTemplate: CodeTemplate.getExtendedPtl(),
 | 
				
			||||||
 | 
					            // msgTemplate: CodeTemplate.getExtendedMsg(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    // Sync shared code
 | 
				
			||||||
 | 
					    sync: [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            from: 'src/shared',
 | 
				
			||||||
 | 
					            to: '../frontend/assets/scripts/shared',
 | 
				
			||||||
 | 
					            type: 'symlink'     // Change this to 'copy' if your environment not support symlink
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    // Dev server
 | 
				
			||||||
 | 
					    dev: {
 | 
				
			||||||
 | 
					        autoProto: true,        // Auto regenerate proto
 | 
				
			||||||
 | 
					        autoSync: true,         // Auto sync when file changed
 | 
				
			||||||
 | 
					        autoApi: true,          // Auto create API when ServiceProto updated
 | 
				
			||||||
 | 
					        watch: 'src',           // Restart dev server when these files changed
 | 
				
			||||||
 | 
					        entry: 'src/index.ts',  // Dev server command: node -r ts-node/register {entry}
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // Build config
 | 
				
			||||||
 | 
					    build: {
 | 
				
			||||||
 | 
					        autoProto: true,        // Auto generate proto before build
 | 
				
			||||||
 | 
					        autoSync: true,         // Auto sync before build
 | 
				
			||||||
 | 
					        autoApi: true,          // Auto generate API before build
 | 
				
			||||||
 | 
					        outDir: 'dist',         // Clean this dir before build
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export default tsrpcConf;
 | 
				
			||||||
		Reference in New Issue
	
	Block a user