From eeaa7915defc55053ae547b7163c4ab891743fb2 Mon Sep 17 00:00:00 2001 From: sli97 <775303361@qq.com> Date: Mon, 5 Dec 2022 21:46:02 +0800 Subject: [PATCH] binary optimization --- .../assets/Scripts/Global/DataManager.ts | 1 - .../assets/Scripts/Global/NetworkManager.ts | 5 +- apps/client/assets/Scripts/Utils/index.ts | 78 +----- apps/server/src/Common/Binary.ts | 240 ++++++++++++++---- apps/server/src/common/index.ts | 1 + apps/server/src/core/Connection.ts | 6 +- apps/server/src/utils/index.ts | 79 +----- test.js | 34 +-- 8 files changed, 208 insertions(+), 236 deletions(-) diff --git a/apps/client/assets/Scripts/Global/DataManager.ts b/apps/client/assets/Scripts/Global/DataManager.ts index 786a541..2469ad7 100644 --- a/apps/client/assets/Scripts/Global/DataManager.ts +++ b/apps/client/assets/Scripts/Global/DataManager.ts @@ -87,7 +87,6 @@ export default class DataManager extends Singleton { player.direction = { x, y } break } - case InputTypeEnum.WeaponShoot: { const { owner, position, direction } = input const bullet: IBullet = { diff --git a/apps/client/assets/Scripts/Global/NetworkManager.ts b/apps/client/assets/Scripts/Global/NetworkManager.ts index 6749b48..02548a4 100644 --- a/apps/client/assets/Scripts/Global/NetworkManager.ts +++ b/apps/client/assets/Scripts/Global/NetworkManager.ts @@ -1,7 +1,6 @@ import Singleton from '../Base/Singleton' import { ApiMsgEnum, IModel, strdecode, strencode } from '../Common'; -import { binaryEncode } from '../Common/Binary'; -import { binaryDecode } from '../Utils'; +import { binaryEncode, binaryDecode } from '../Common/Binary'; const TIMEOUT = 5000 @@ -94,8 +93,6 @@ export default class NetworkManager extends Singleton { sendMsg(name: T, data: IModel['msg'][T]) { const view = binaryEncode(name, data) - console.log("view", view.buffer); - this.ws.send(view.buffer) } diff --git a/apps/client/assets/Scripts/Utils/index.ts b/apps/client/assets/Scripts/Utils/index.ts index 405d8e6..5ccb01e 100644 --- a/apps/client/assets/Scripts/Utils/index.ts +++ b/apps/client/assets/Scripts/Utils/index.ts @@ -8,80 +8,4 @@ const getNumberWithinString = (str: string) => parseInt(str.match(INDEX_REG)?.[1 export const sortSpriteFrame = (spriteFrame: Array) => spriteFrame.sort((a, b) => getNumberWithinString(a.name) - getNumberWithinString(b.name)) -export const rad2Angle = (rad: number) => rad / Math.PI * 180 - -export const binaryDecode = (buffer: ArrayBuffer) => { - let index = 0 - const view = new DataView(buffer) - const type = view.getUint8(index++) - - if (type === ApiMsgEnum.MsgClientSync) { - const inputType = view.getUint8(index++) - if (inputType === InputTypeEnum.ActorMove) { - const id = view.getUint8(index++) - const directionX = view.getFloat32(index) - index += 4 - const directionY = view.getFloat32(index) - index += 4 - const dt = view.getFloat32(index) - index += 4 - const msg = { - name: ApiMsgEnum.MsgClientSync, - data: { - type: InputTypeEnum.ActorMove, - id, - direction: { - x: directionX, - y: directionY, - }, - dt - } - } - - return msg - } else if (inputType === InputTypeEnum.WeaponShoot) { - const id = view.getUint8(index++) - const positionX = view.getFloat32(index) - index += 4 - const positionY = view.getFloat32(index) - index += 4 - const directionX = view.getFloat32(index) - index += 4 - const directionY = view.getFloat32(index) - index += 4 - const msg = { - name: ApiMsgEnum.MsgClientSync, - data: { - type: InputTypeEnum.WeaponShoot, - id, - position: { - x: positionX, - y: positionY, - }, - direction: { - x: directionX, - y: directionY, - }, - } - } - - return msg - } else { - const dt = view.getFloat32(index) - index += 4 - const msg = { - name: ApiMsgEnum.MsgClientSync, - data: { - type: InputTypeEnum.TimePast, - dt, - } - } - return msg - } - } else { - return { - name: type, - data: JSON.parse(strdecode(new Uint8Array(buffer.slice(1)))) - } - } -} \ No newline at end of file +export const rad2Angle = (rad: number) => rad / Math.PI * 180 \ No newline at end of file diff --git a/apps/server/src/Common/Binary.ts b/apps/server/src/Common/Binary.ts index f6d2634..696a255 100644 --- a/apps/server/src/Common/Binary.ts +++ b/apps/server/src/Common/Binary.ts @@ -1,57 +1,92 @@ import { ApiMsgEnum, InputTypeEnum } from "./Enum"; -import { strencode } from "./Utils"; +import { strdecode, strencode } from "./Utils"; + +const encodeActorMove = (proto: ApiMsgEnum, data: any, view: DataView, index: number) => { + view.setUint8(index++, data.type) + view.setUint8(index++, data.id) + view.setFloat32(index, data.direction.x) + index += 4 + view.setFloat32(index, data.direction.y) + index += 4 + view.setFloat32(index, data.dt) + index += 4 +} + +const encodeWeaponShoot = (proto: ApiMsgEnum, data: any, view: DataView, index: number) => { + view.setUint8(index++, data.type) + view.setUint8(index++, data.owner) + view.setFloat32(index, data.position.x) + index += 4 + view.setFloat32(index, data.position.y) + index += 4 + view.setFloat32(index, data.direction.x) + index += 4 + view.setFloat32(index, data.direction.y) + index += 4 +} + +export const encdoeTimePast = (proto: ApiMsgEnum, data: any, view: DataView, index: number) => { + view.setUint8(index++, data.type) + view.setFloat32(index, data.dt) + index += 4 +} export const binaryEncode = (proto: ApiMsgEnum, data: any): DataView => { if (proto === ApiMsgEnum.MsgClientSync) { - switch (data.type) { - case InputTypeEnum.ActorMove: { - let index = 0 - const ab = new ArrayBuffer(3 + 12) - const view = new DataView(ab) - view.setUint8(index++, proto) - view.setUint8(index++, data.type) - view.setUint8(index++, data.id) - view.setFloat32(index, data.direction.x) - index += 4 - view.setFloat32(index, data.direction.y) - index += 4 - view.setFloat32(index, data.dt) - index += 4 - return view - } - case InputTypeEnum.WeaponShoot: { - let index = 0 - const ab = new ArrayBuffer(3 + 16) - const view = new DataView(ab) - view.setUint8(index++, proto) - view.setUint8(index++, data.type) - view.setUint8(index++, data.id) - view.setFloat32(index, data.position.x) - index += 4 - view.setFloat32(index, data.position.y) - index += 4 - view.setFloat32(index, data.direction.x) - index += 4 - view.setFloat32(index, data.direction.y) - index += 4 - return view - } - case InputTypeEnum.TimePast: { - let index = 0 - const ab = new ArrayBuffer(1 + 1 + 4) - const view = new DataView(ab) - view.setUint8(index++, proto) - view.setUint8(index++, data.type) - view.setFloat32(index, data.dt) - index += 4 - return view - } - default: { - const ab = new ArrayBuffer(0) - const view = new DataView(ab) - return view + if (data.type === InputTypeEnum.ActorMove) { + let index = 0 + const ab = new ArrayBuffer(3 + 12) + const view = new DataView(ab) + view.setUint8(index++, proto) + encodeActorMove(proto, data, view, index) + return view + } else if (data.type === InputTypeEnum.WeaponShoot) { + let index = 0 + const ab = new ArrayBuffer(3 + 16) + const view = new DataView(ab) + view.setUint8(index++, proto) + encodeWeaponShoot(proto, data, view, index) + return view + } else { + let index = 0 + const ab = new ArrayBuffer(2 + 4) + const view = new DataView(ab) + view.setUint8(index++, proto) + encdoeTimePast(proto, data, view, index) + return view + } + } else if (proto === ApiMsgEnum.MsgServerSync) { + let total = 0 + for (let i = 0; i < data.length; i++) { + const item = data[i]; + if (item.type === InputTypeEnum.ActorMove) { + total += 14 + } else if (item.type === InputTypeEnum.WeaponShoot) { + total += 18 + } else { + total += 5 } } + const ab = new ArrayBuffer(1 + 1 + total) + const view = new DataView(ab) + let index = 0 + view.setUint8(index++, proto) + view.setUint8(index++, data.length) + for (let i = 0; i < data.length; i++) { + const item = data[i]; + if (item.type === InputTypeEnum.ActorMove) { + encodeActorMove(proto, item, view, index) + index += 14 + } else if (item.type === InputTypeEnum.WeaponShoot) { + encodeWeaponShoot(proto, item, view, index) + index += 18 + } else { + encdoeTimePast(proto, item, view, index) + index += 5 + } + } + + return view } else { let index = 0 const str = JSON.stringify(data) @@ -64,4 +99,113 @@ export const binaryEncode = (proto: ApiMsgEnum, data: any): DataView => { } return view } +} + +const decodeActorMove = (view: DataView, index: number) => { + const id = view.getUint8(index++) + const directionX = view.getFloat32(index) + index += 4 + const directionY = view.getFloat32(index) + index += 4 + const dt = view.getFloat32(index) + index += 4 + const msg = { + name: ApiMsgEnum.MsgClientSync, + data: { + type: InputTypeEnum.ActorMove, + id, + direction: { + x: directionX, + y: directionY, + }, + dt + } + } + + return msg +} + +const decodeWeaponShoot = (view: DataView, index: number) => { + const owner = view.getUint8(index++) + const positionX = view.getFloat32(index) + index += 4 + const positionY = view.getFloat32(index) + index += 4 + const directionX = view.getFloat32(index) + index += 4 + const directionY = view.getFloat32(index) + index += 4 + const msg = { + name: ApiMsgEnum.MsgClientSync, + data: { + type: InputTypeEnum.WeaponShoot, + owner, + position: { + x: positionX, + y: positionY, + }, + direction: { + x: directionX, + y: directionY, + }, + } + } + + return msg +} + +const decodeTimePast = (view: DataView, index: number) => { + const dt = view.getFloat32(index) + index += 4 + const msg = { + name: ApiMsgEnum.MsgClientSync, + data: { + type: InputTypeEnum.TimePast, + dt, + } + } + return msg +} + +export const binaryDecode = (buffer: ArrayBuffer) => { + let index = 0 + const view = new DataView(buffer) + const proto = view.getUint8(index++) + + if (proto === ApiMsgEnum.MsgClientSync) { + const inputType = view.getUint8(index++) + if (inputType === InputTypeEnum.ActorMove) { + return decodeActorMove(view, index) + } else if (inputType === InputTypeEnum.WeaponShoot) { + return decodeWeaponShoot(view, index) + } else { + return decodeTimePast(view, index) + } + } else if (proto === ApiMsgEnum.MsgServerSync) { + const len = view.getUint8(index++) + const res = [] + for (let i = 0; i < len; i++) { + const inputType = view.getUint8(index++) + + if (inputType === InputTypeEnum.ActorMove) { + res.push(decodeActorMove(view, index).data) + index += 13 + } else if (inputType === InputTypeEnum.WeaponShoot) { + res.push(decodeWeaponShoot(view, index).data) + index += 17 + } else { + res.push(decodeTimePast(view, index).data) + index += 4 + } + } + return { + name: ApiMsgEnum.MsgServerSync, + data: res + } + } else { + return { + name: proto, + data: JSON.parse(strdecode(new Uint8Array(buffer.slice(1)))) + } + } } \ No newline at end of file diff --git a/apps/server/src/common/index.ts b/apps/server/src/common/index.ts index 9ace9d1..94f03e6 100644 --- a/apps/server/src/common/index.ts +++ b/apps/server/src/common/index.ts @@ -7,6 +7,7 @@ export * from './Enum' export * from './Model' export * from './State' export * from './Utils' +export * from './Binary' export interface IModel { api: { diff --git a/apps/server/src/core/Connection.ts b/apps/server/src/core/Connection.ts index 9046feb..313e8f0 100644 --- a/apps/server/src/core/Connection.ts +++ b/apps/server/src/core/Connection.ts @@ -1,9 +1,9 @@ import WebSocket from 'ws'; import { EventEmitter } from 'stream'; import { MyServer } from './MyServer'; -import { binaryDecode, getTime } from '../Utils'; +import { getTime, toArrayBuffer } from '../Utils'; import { ApiMsgEnum, IModel } from '../Common'; -import { binaryEncode } from '../Common/Binary'; +import { binaryEncode, binaryDecode } from '../Common/Binary'; export enum ConnectionEventEnum { Close = 'Close', @@ -27,7 +27,7 @@ export class Connection extends EventEmitter { this.ws.on('message', (buffer: Buffer) => { // const str = buffer.toString() try { - const json = binaryDecode(buffer) + const json = binaryDecode(toArrayBuffer(buffer)) const { name, data } = json // console.log(`${getTime()}接收|字节数${buffer.length}|${this.playerId || -1}|${str}`) console.log(`${getTime()}接收|字节数${buffer.length}|${this.playerId || -1}|${JSON.stringify(json)}`) diff --git a/apps/server/src/utils/index.ts b/apps/server/src/utils/index.ts index d5a5868..52c5c46 100644 --- a/apps/server/src/utils/index.ts +++ b/apps/server/src/utils/index.ts @@ -1,6 +1,5 @@ import fs from 'fs-extra' import path from 'path' -import { ApiMsgEnum, InputTypeEnum, strdecode } from '../Common' export const getTime = () => new Date().toLocaleString().split("├")[0] @@ -37,77 +36,11 @@ export const copyCommon = async () => { console.log('同步成功!') } -export const binaryDecode = (buffer: Buffer) => { - let index = 0 - const type = buffer.readUint8(index++) - - if (type === ApiMsgEnum.MsgClientSync) { - const inputType = buffer.readUint8(index++) - if (inputType === InputTypeEnum.ActorMove) { - const id = buffer.readUint8(index++) - const directionX = buffer.readFloatBE(index) - index += 4 - const directionY = buffer.readFloatBE(index) - index += 4 - const dt = buffer.readFloatBE(index) - index += 4 - const msg = { - name: ApiMsgEnum.MsgClientSync, - data: { - type: InputTypeEnum.ActorMove, - id, - direction: { - x: directionX, - y: directionY, - }, - dt - } - } - - return msg - } else if (inputType === InputTypeEnum.WeaponShoot) { - const id = buffer.readUint8(index++) - const positionX = buffer.readFloatBE(index) - index += 4 - const positionY = buffer.readFloatBE(index) - index += 4 - const directionX = buffer.readFloatBE(index) - index += 4 - const directionY = buffer.readFloatBE(index) - index += 4 - const msg = { - name: ApiMsgEnum.MsgClientSync, - data: { - type: InputTypeEnum.WeaponShoot, - id, - position: { - x: positionX, - y: positionY, - }, - direction: { - x: directionX, - y: directionY, - }, - } - } - - return msg - } else { - const dt = buffer.readFloatBE(index) - index += 4 - const msg = { - name: ApiMsgEnum.MsgClientSync, - data: { - type: InputTypeEnum.TimePast, - dt, - } - } - return msg - } - } else { - return { - name: type, - data: JSON.parse(strdecode(new Uint8Array(buffer.slice(1)))) - } +export const toArrayBuffer = (buffer: Buffer) => { + var ab = new ArrayBuffer(buffer.length); + var view = new Uint8Array(ab); + for (var i = 0; i < buffer.length; ++i) { + view[i] = buffer[i]; } + return ab; } \ No newline at end of file diff --git a/test.js b/test.js index 016d796..37ae539 100644 --- a/test.js +++ b/test.js @@ -1,30 +1,4 @@ -const msg = JSON.stringify({ - a: 123, - b: true, - c: "456" -}) - -const strencode = (str) => { - let byteArray = []; - for (let i = 0; i < str.length; i++) { - let charCode = str.charCodeAt(i); - if (charCode <= 0x7f) { - byteArray.push(charCode); - } else if (charCode <= 0x7ff) { - byteArray.push(0xc0 | (charCode >> 6), 0x80 | (charCode & 0x3f)); - } else if (charCode <= 0xffff) { - byteArray.push(0xe0 | (charCode >> 12), 0x80 | ((charCode & 0xfc0) >> 6), 0x80 | (charCode & 0x3f)); - } else { - byteArray.push(0xf0 | (charCode >> 18), 0x80 | ((charCode & 0x3f000) >> 12), 0x80 | ((charCode & 0xfc0) >> 6), 0x80 | (charCode & 0x3f)); - } - } - return byteArray; -} - -var arr = strencode(msg) -var buffer = Buffer.from(msg) - -console.log(buffer) -for (let i = 0; i < arr.length; i++) { - console.log(buffer[i], arr[i]); -} +const ab = new ArrayBuffer(10) +const view = new DataView(ab) +view.setFloat32(0, 0.0023) +console.log(view); \ No newline at end of file