This commit is contained in:
sli97
2022-12-03 20:06:57 +08:00
parent bdead4a6d1
commit f3dc3ef7ba
110 changed files with 1347 additions and 1028 deletions

View File

@@ -0,0 +1,49 @@
import { IPlayer, IRoom } from "./Model"
export interface IApiPlayerListReq {
}
export interface IApiPlayerListRes {
list: Array<IPlayer>
}
export interface IApiPlayerJoinReq {
nickname: string
}
export interface IApiPlayerJoinRes {
player: IPlayer
}
export interface IApiRoomListReq {
}
export interface IApiRoomListRes {
list: Array<IRoom>
}
export interface IApiRoomCreateReq {
}
export interface IApiRoomCreateRes {
room: IRoom
}
export interface IApiRoomJoinReq {
rid: number
}
export interface IApiRoomJoinRes {
room: IRoom
}
export interface IApiRoomLeaveReq {
}
export interface IApiRoomLeaveRes { }
export interface IApiGameStartReq {
rid: number
}
export interface IApiGameStartRes { }

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "7b9c95da-edaa-4c0c-8e41-b135b9802b86",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,34 @@
export enum ApiMsgEnum {
ApiPlayerList = 'ApiPlayerList',
ApiPlayerJoin = 'ApiPlayerJoin',
ApiRoomList = 'ApiRoomList',
ApiRoomCreate = 'ApiRoomCreate',
ApiRoomJoin = 'ApiRoomJoin',
ApiRoomLeave = 'ApiRoomLeave',
ApiGameStart = 'ApiGameStart',
MsgPlayerList = 'MsgPlayerList',
MsgRoomList = 'MsgRoomList',
MsgRoom = 'MsgRoom',
MsgGameStart = 'MsgGameStart',
MsgClientSync = 'MsgClientSync',
MsgServerSync = 'MsgServerSync',
}
export enum InputTypeEnum {
ActorMove = 'ActorMove',
WeaponShoot = 'WeaponShoot',
TimePast = 'TimePast',
}
export enum EntityTypeEnum {
Map1 = 'Map1',
Actor1 = 'Actor1',
Actor2 = 'Actor2',
Weapon1 = 'Weapon1',
Weapon2 = 'Weapon2',
Bullet1 = 'Bullet1',
Bullet2 = 'Bullet2',
Explosion = 'Explosion',
JoyStick = 'JoyStick',
Shoot = 'Shoot',
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "2ba2bf1e-f8be-4a48-b759-666d5e757029",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,9 @@
export interface IPlayer {
id: number, nickname: string, rid: number
}
export interface IRoom {
id: number, players: Array<IPlayer>
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "87dc45aa-8878-48f4-9084-b4fd293a6414",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,23 @@
import { IPlayer, IRoom } from "./Model"
import { IState } from "./State"
export interface IMsgPlayerList {
list: Array<IPlayer>
}
export interface IMsgRoomList {
list: Array<IRoom>
}
export interface IMsgRoom {
room: IRoom
}
export interface IMsgGameStart {
state: IState
}
export interface IMsgGameStart {
state: IState
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "70de0494-112b-4a60-a266-3eadc82c20a4",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,56 @@
import { EntityTypeEnum, InputTypeEnum } from "./Enum"
export interface IActor {
id: number
nickname: string
type: EntityTypeEnum
weaponType: EntityTypeEnum
bulletType: EntityTypeEnum
//动态数据
hp: number
position: IVec2
direction: IVec2
}
export interface IBullet {
id: number
owner: number
type: EntityTypeEnum
//动态数据
position: IVec2
direction: IVec2
}
export interface IVec2 {
x: number;
y: number
}
export interface IState {
players: IActor[],
bullets: IBullet[],
nextBulletId: number
}
export type IClientInput = IActorMove | IWeaponShoot | ITimePast
export interface IActorMove {
type: InputTypeEnum.ActorMove
id: number;
direction: IVec2;
dt: number;
}
export interface IWeaponShoot {
type: InputTypeEnum.WeaponShoot
owner: number;
position: IVec2;
direction: IVec2;
}
export interface ITimePast {
type: InputTypeEnum.TimePast;
dt: number
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "5d81c809-0c6d-402c-a029-c92d96ced679",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "dfbf9e38-3546-4d54-9a00-515d6639c002",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -1,6 +1,4 @@
import Connection from '../core/Connection'
export type IPlayer = Pick<Player, 'id' | 'nickname' | 'connection'>
import Connection from '../Core/Connection'
export default class Player {
id: number
@@ -8,7 +6,7 @@ export default class Player {
connection: Connection
rid: number
constructor({ id, nickname, connection }: IPlayer) {
constructor({ id, nickname, connection }: Pick<Player, 'id' | 'nickname' | 'connection'>) {
this.id = id
this.nickname = nickname
this.connection = connection

View File

@@ -1,8 +1,8 @@
import { ApiMsgEnum } from '..'
import Singleton from '../base/Singleton'
import type { IPlayer } from './Player'
import Singleton from '../Base/Singleton'
import { ApiMsgEnum, IApiPlayerJoinReq } from '../Common'
import Player from './Player'
import RoomManager from './RoomManager'
import Connection from '../Core/Connection'
export default class PlayerManager extends Singleton {
static get Instance() {
@@ -13,7 +13,7 @@ export default class PlayerManager extends Singleton {
players: Set<Player> = new Set()
idMapPlayer: Map<number, Player> = new Map()
createPlayer({ connection, nickname }: Omit<IPlayer, 'id'>) {
createPlayer({ connection, nickname }: IApiPlayerJoinReq & { connection: Connection }) {
const player = new Player({ id: this.playerId++, connection, nickname })
this.players.add(player)
this.idMapPlayer.set(player.id, player)

View File

@@ -1,4 +1,4 @@
import { ApiMsgEnum } from '..'
import { ApiMsgEnum, EntityTypeEnum, IState } from '../Common'
import type Player from './Player'
import PlayerManager from './PlayerManager'
import RoomManager from './RoomManager'
@@ -11,6 +11,8 @@ export default class Room {
this.id = rid
}
private inputs = []
join(uid: number) {
const player = PlayerManager.Instance.getPlayerById(uid)
if (player) {
@@ -33,7 +35,46 @@ export default class Room {
sync() {
for (const player of this.players) {
player.connection.sendMsg(ApiMsgEnum.MsgRoom, RoomManager.Instance.getRoomView(this))
player.connection.sendMsg(ApiMsgEnum.MsgRoom, {
room: RoomManager.Instance.getRoomView(this)
})
}
}
start() {
const state: IState = {
players: [...this.players].map((player, index) => ({
id: player.id,
nickname: player.nickname,
position: {
x: -150 + index * 300,
y: -150 + index * 300,
},
direction: {
x: 1,
y: 0
},
hp: 100,
type: EntityTypeEnum.Actor1,
weaponType: EntityTypeEnum.Weapon1,
bulletType: EntityTypeEnum.Bullet1,
})),
bullets: [],
nextBulletId: 1
}
for (const player of this.players) {
player.connection.sendMsg(ApiMsgEnum.MsgGameStart, {
state
})
}
this.listenPlayer()
}
listenPlayer() {
for (const player of this.players) {
player.connection.listenMsg(ApiMsgEnum.MsgClientSync, () => { }
)
}
}
}

View File

@@ -1,6 +1,5 @@
import { ApiMsgEnum } from '..'
import Singleton from '../base/Singleton'
import Player from './Player'
import Singleton from '../Base/Singleton'
import { ApiMsgEnum } from '../Common'
import PlayerManager from './PlayerManager'
import Room from './Room'
@@ -43,6 +42,13 @@ export default class RoomManager extends Singleton {
}
}
startRoom(rid: number) {
const room = this.getRoomById(rid)
if (room) {
room.start()
}
}
getRoomById(id: number) {
return this.idMapRoom.get(id)
}

View File

@@ -1 +1,51 @@
console.log(112221);
import { IApiGameStartReq, IApiGameStartRes, IApiPlayerJoinReq, IApiPlayerJoinRes, IApiPlayerListReq, IApiPlayerListRes, IApiRoomCreateReq, IApiRoomCreateRes, IApiRoomJoinReq, IApiRoomJoinRes, IApiRoomLeaveReq, IApiRoomLeaveRes, IApiRoomListReq, IApiRoomListRes } from './Api'
import { ApiMsgEnum } from './Enum'
import { IMsgGameStart, IMsgPlayerList, IMsgRoom, IMsgRoomList } from './Msg'
import { IClientInput } from './State'
export * from './Api'
export * from './Msg'
export * from './Enum'
export * from './Model'
export * from './State'
export interface IModel {
api: {
[ApiMsgEnum.ApiPlayerJoin]: {
req: IApiPlayerJoinReq,
res: IApiPlayerJoinRes,
}
[ApiMsgEnum.ApiPlayerList]: {
req: IApiPlayerListReq,
res: IApiPlayerListRes,
}
[ApiMsgEnum.ApiRoomList]: {
req: IApiRoomListReq,
res: IApiRoomListRes,
}
[ApiMsgEnum.ApiRoomCreate]: {
req: IApiRoomCreateReq,
res: IApiRoomCreateRes,
}
[ApiMsgEnum.ApiRoomJoin]: {
req: IApiRoomJoinReq,
res: IApiRoomJoinRes,
}
[ApiMsgEnum.ApiRoomLeave]: {
req: IApiRoomLeaveReq,
res: IApiRoomLeaveRes,
}
[ApiMsgEnum.ApiGameStart]: {
req: IApiGameStartReq,
res: IApiGameStartRes,
}
},
msg: {
[ApiMsgEnum.MsgPlayerList]: IMsgPlayerList
[ApiMsgEnum.MsgRoomList]: IMsgRoomList,
[ApiMsgEnum.MsgRoom]: IMsgRoom,
[ApiMsgEnum.MsgGameStart]: IMsgGameStart,
[ApiMsgEnum.MsgClientSync]: IClientInput,
[ApiMsgEnum.MsgServerSync]: IMsgGameStart,
}
}

View File

@@ -1,7 +1,8 @@
import WebSocket from 'ws';
import { EventEmitter } from 'stream';
import MyServer, { IData } from '.';
import { getTime } from '../utils';
import { getTime } from '../Utils';
import { IModel } from '../Common';
export enum ConnectionEventEnum {
Close = 'Close',
@@ -68,7 +69,7 @@ export default class Connection extends EventEmitter {
}
}
sendMsg(name: string, data: IData) {
sendMsg<T extends keyof IModel['msg']>(name: T, data: IModel['msg'][T]) {
const msg = JSON.stringify({
name,
data

View File

@@ -1,23 +1,9 @@
import MyServer, { IData, MyServerEventEnum } from './core';
import Player from './biz/Player';
import PlayerManager from './biz/PlayerManager';
import RoomManager from './biz/RoomManager';
import Connection from './core/Connection';
import { copyCommon, getTime } from './utils';
export enum ApiMsgEnum {
ApiPlayerList = 'ApiPlayerList',
ApiPlayerJoin = 'ApiPlayerJoin',
ApiRoomList = 'ApiRoomList',
ApiRoomCreate = 'ApiRoomCreate',
ApiRoomJoin = 'ApiRoomJoin',
ApiRoomLeave = 'ApiRoomLeave',
MsgPlayerList = 'MsgPlayerList',
MsgRoomList = 'MsgRoomList',
MsgRoom = 'MsgRoom',
}
copyCommon()
import MyServer, { MyServerEventEnum } from './Core';
import PlayerManager from './Biz/PlayerManager';
import RoomManager from './Biz/RoomManager';
import Connection from './Core/Connection';
import { getTime, symlinkCommon } from './Utils';
import { ApiMsgEnum, IApiGameStartReq, IApiGameStartRes, IApiPlayerJoinReq, IApiPlayerJoinRes, IApiPlayerListReq, IApiPlayerListRes, IApiRoomCreateReq, IApiRoomCreateRes, IApiRoomJoinReq, IApiRoomJoinRes, IApiRoomLeaveReq, IApiRoomLeaveRes, IApiRoomListReq, IApiRoomListRes, IModel } from './Common';
const server = new MyServer({ port: 8888 })
@@ -34,28 +20,32 @@ server.on(MyServerEventEnum.DisConnect, (connection: Connection) => {
})
// api
server.setApi(ApiMsgEnum.ApiPlayerList, (connection: Connection, data: IData) => {
server.setApi(ApiMsgEnum.ApiPlayerList, (connection: Connection, data: IApiPlayerListReq): IApiPlayerListRes => {
return { list: PlayerManager.Instance.getPlayersView() }
})
server.setApi(ApiMsgEnum.ApiPlayerJoin, (connection: Connection, data: IData) => {
const nickname = data.nickname
server.setApi(ApiMsgEnum.ApiPlayerJoin, (connection: Connection, { nickname }: IApiPlayerJoinReq): IApiPlayerJoinRes => {
const player = PlayerManager.Instance.createPlayer({ connection, nickname })
PlayerManager.Instance.syncPlayers()
return PlayerManager.Instance.getPlayerView(player)
return {
player: PlayerManager.Instance.getPlayerView(player)
}
})
server.setApi(ApiMsgEnum.ApiRoomList, (connection: Connection, data: IData) => {
server.setApi(ApiMsgEnum.ApiRoomList, (connection: Connection, data: IApiRoomListReq): IApiRoomListRes => {
return { list: RoomManager.Instance.getRoomsView() }
})
server.setApi(ApiMsgEnum.ApiRoomCreate, (connection: Connection, data: IData) => {
server.setApi(ApiMsgEnum.ApiRoomCreate, (connection: Connection, data: IApiRoomCreateReq): IApiRoomCreateRes => {
if (connection.playerId) {
const room = RoomManager.Instance.joinRoom(RoomManager.Instance.createRoom().id, connection.playerId)
if (room) {
RoomManager.Instance.syncRooms()
PlayerManager.Instance.syncPlayers()
return RoomManager.Instance.getRoomView(room)
return {
room: RoomManager.Instance.getRoomView(room)
}
} else {
throw new Error("ApiRoomCreate room不存在")
}
@@ -64,14 +54,16 @@ server.setApi(ApiMsgEnum.ApiRoomCreate, (connection: Connection, data: IData) =>
}
})
server.setApi(ApiMsgEnum.ApiRoomJoin, (connection: Connection, data: IData) => {
server.setApi(ApiMsgEnum.ApiRoomJoin, (connection: Connection, data: IApiRoomJoinReq): IApiRoomJoinRes => {
if (connection.playerId) {
const room = RoomManager.Instance.joinRoom(data.rid, connection.playerId)
if (room) {
RoomManager.Instance.syncRooms()
PlayerManager.Instance.syncPlayers()
RoomManager.Instance.syncRoom(room.id)
return RoomManager.Instance.getRoomView(room)
return {
room: RoomManager.Instance.getRoomView(room)
}
} else {
throw new Error("ApiRoomJoin room不存在")
}
@@ -80,7 +72,7 @@ server.setApi(ApiMsgEnum.ApiRoomJoin, (connection: Connection, data: IData) => {
}
})
server.setApi(ApiMsgEnum.ApiRoomLeave, (connection: Connection, data: IData) => {
server.setApi(ApiMsgEnum.ApiRoomLeave, (connection: Connection, data: IApiRoomLeaveReq): IApiRoomLeaveRes => {
if (connection.playerId) {
const player = PlayerManager.Instance.getPlayerById(connection.playerId)
if (player) {
@@ -90,6 +82,28 @@ server.setApi(ApiMsgEnum.ApiRoomLeave, (connection: Connection, data: IData) =>
PlayerManager.Instance.syncPlayers()
RoomManager.Instance.syncRooms()
RoomManager.Instance.syncRoom(rid)
return {}
} else {
throw new Error("ApiRoomLeave 玩家不在房间")
}
} else {
throw new Error("ApiRoomLeave 玩家不存在")
}
} else {
throw new Error("ApiRoomLeave 玩家未登录")
}
})
server.setApi(ApiMsgEnum.ApiGameStart, (connection: Connection, data: IApiGameStartReq): IApiGameStartRes => {
if (connection.playerId) {
const player = PlayerManager.Instance.getPlayerById(connection.playerId)
if (player) {
const rid = player.rid
if (rid) {
RoomManager.Instance.startRoom(rid)
// PlayerManager.Instance.syncPlayers()
// RoomManager.Instance.syncRooms()
return {}
} else {
throw new Error("ApiRoomLeave 玩家不在房间")
}
@@ -103,6 +117,7 @@ server.setApi(ApiMsgEnum.ApiRoomLeave, (connection: Connection, data: IData) =>
// start!!
server.start().then(() => {
symlinkCommon()
console.log("服务启动!")
}).catch((e) => {
console.log("服务异常", e)

View File

@@ -3,10 +3,26 @@ import path from 'path'
export const getTime = () => new Date().toLocaleString().split("├")[0]
export async function copyCommon() {
const src = path.resolve('./common')
const dst = path.resolve('../client/assets/Scripts/common')
//symlink同步
export const symlinkCommon = async () => {
const src = path.resolve(__dirname, '../Common')
const dst = path.resolve(__dirname, '../../../client/assets/Scripts/Common')
if (await fs.lstat(dst).then(v => v.isSymbolicLink()).catch(() => false) && await fs.readlink(dst) === src) {
console.log('同步成功!')
} else {
fs.symlink(src, dst).then(() => {
console.log('同步成功!')
}).catch((e) => {
console.log('同步失败!', e)
})
}
}
//copy同步
export const copyCommon = async () => {
const src = path.resolve(__dirname, '../Common')
const dst = path.resolve(__dirname, '../../../client/assets/Scripts/Common')
console.log(src, dst);
// clean
@@ -17,6 +33,5 @@ export async function copyCommon() {
// copy
await fs.copy(src, dst)
console.log('同步成功')
}
console.log('同步成功')
}