binary optimization

This commit is contained in:
sli97 2022-12-05 21:46:02 +08:00
parent c31af6b02a
commit eeaa7915de
8 changed files with 208 additions and 236 deletions

View File

@ -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 = {

View File

@ -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<T extends keyof IModel['msg']>(name: T, data: IModel['msg'][T]) {
const view = binaryEncode(name, data)
console.log("view", view.buffer);
this.ws.send(view.buffer)
}

View File

@ -8,80 +8,4 @@ const getNumberWithinString = (str: string) => parseInt(str.match(INDEX_REG)?.[1
export const sortSpriteFrame = (spriteFrame: Array<SpriteFrame>) =>
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))))
}
}
}
export const rad2Angle = (rad: number) => rad / Math.PI * 180

View File

@ -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))))
}
}
}

View File

@ -7,6 +7,7 @@ export * from './Enum'
export * from './Model'
export * from './State'
export * from './Utils'
export * from './Binary'
export interface IModel {
api: {

View File

@ -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)}`)

View File

@ -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;
}

34
test.js
View File

@ -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);