[mod]
This commit is contained in:
12
backend1/src/api/ApiJoin.ts
Normal file
12
backend1/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>): Promise<void> {
|
||||
let playerId: number = roomInstance.join(call.req, call.conn);
|
||||
|
||||
call.succ({
|
||||
playerId: playerId,
|
||||
gameState: roomInstance.gameSystem.state
|
||||
});
|
||||
}
|
||||
40
backend1/src/index.ts
Normal file
40
backend1/src/index.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
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";
|
||||
require("dotenv").config();
|
||||
|
||||
// 创建 TSRPC WebSocket Server
|
||||
export const server: WsServer<ServiceType> = new WsServer(serviceProto, {
|
||||
port: +process.env.PORT! || 3000,
|
||||
json: true
|
||||
});
|
||||
|
||||
// 断开连接后退出房间
|
||||
server.flows.postDisconnectFlow.push(v => {
|
||||
let conn: WsConnection<ServiceType> = v.conn as WsConnection<ServiceType>;
|
||||
if (conn.playerId) {
|
||||
roomInstance.leave(conn.playerId, conn);
|
||||
}
|
||||
|
||||
return v;
|
||||
});
|
||||
|
||||
export const roomInstance: Room = new Room(server);
|
||||
|
||||
// 初始化
|
||||
async function init(): Promise<void> {
|
||||
// 挂载 API 接口
|
||||
await server.autoImplementApi(path.resolve(__dirname, "api"));
|
||||
|
||||
// TODO
|
||||
// Prepare something... (e.g. connect the db)
|
||||
}
|
||||
|
||||
// 启动入口点
|
||||
async function main(): Promise<void> {
|
||||
await init();
|
||||
await server.start();
|
||||
}
|
||||
main();
|
||||
101
backend1/src/models/Room.ts
Normal file
101
backend1/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>): number {
|
||||
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): void {
|
||||
this.pendingInputs.push(input);
|
||||
}
|
||||
|
||||
sync(): void {
|
||||
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>): void {
|
||||
this.conns.removeOne(v => v.playerId === playerId);
|
||||
this.applyInput({
|
||||
type: "PlayerLeave",
|
||||
playerId: playerId
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
declare module "tsrpc" {
|
||||
export interface WsConnection {
|
||||
playerId?: number;
|
||||
}
|
||||
}
|
||||
143
backend1/src/shared/game/GameSystem.ts
Normal file
143
backend1/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
backend1/src/shared/game/gameConfig.ts
Normal file
14
backend1/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
backend1/src/shared/game/state/ArrowState.ts
Normal file
9
backend1/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
backend1/src/shared/game/state/PlayerState.ts
Normal file
7
backend1/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
backend1/src/shared/protocols/PtlJoin.ts
Normal file
15
backend1/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
backend1/src/shared/protocols/client/MsgClientInput.ts
Normal file
9
backend1/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
backend1/src/shared/protocols/server/MsgFrame.ts
Normal file
11
backend1/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
backend1/src/shared/protocols/serviceProto.ts
Normal file
496
backend1/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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user