universo-platform-3d

Форк
0
270 строк · 6.7 Кб
1
import { InternalServerErrorException } from '@nestjs/common'
2
import { IBasis } from '../godot-types/basis.model'
3
import { ITransform } from '../godot-types/transform.model'
4
import { IVector3 } from '../godot-types/vector3.model'
5
import {
6
  getGodotPaddingByType,
7
  GodotTypes
8
} from './serialization/godot.mapping'
9

10
export default class ArrayReadStream {
11
  private index: number
12
  private dataView: DataView
13
  private buffer: Buffer
14

15
  constructor(buffer: Buffer) {
16
    this.buffer = buffer
17

18
    const uint8Array = new Uint8Array(buffer.length)
19
    for (let counter = 0; counter < buffer.length; counter++) {
20
      uint8Array[counter] = buffer[counter]
21
    }
22
    this.dataView = new DataView(uint8Array.buffer, 0, uint8Array.length)
23
    this.index = 0
24

25
    this.initBuffer()
26
  }
27

28
  private initBuffer() {
29
    this.readArray()
30
  }
31

32
  public getLength(): number {
33
    const lengthIndex = getGodotPaddingByType(GodotTypes.ARRAY) // Skip Array padding
34
    return this.dataView.getInt32(lengthIndex, true)
35
  }
36

37
  public getEventCode(): number {
38
    const eventCodeIndex =
39
      getGodotPaddingByType(GodotTypes.ARRAY) + // Skip Array padding
40
      getGodotPaddingByType(GodotTypes.INT) + // Skip Array length
41
      getGodotPaddingByType(GodotTypes.INT) // Skip Event code type
42
    return this.dataView.getInt32(eventCodeIndex, true)
43
  }
44

45
  public validateType(expectedType: GodotTypes) {
46
    const type = this.dataView.getInt32(this.index, true)
47
    if (type !== expectedType) {
48
      throw new InternalServerErrorException(
49
        `Data type ${type} does not match expected data type ${expectedType}`
50
      )
51
    }
52

53
    const padding = getGodotPaddingByType(type)
54
    this.index += padding
55
  }
56

57
  public readInt(validate = true): number {
58
    if (validate) {
59
      this.validateType(GodotTypes.INT)
60
    }
61
    if (this.dataView.byteLength > this.index) {
62
      const value = this.dataView.getInt32(this.index, true)
63
      this.index += 4
64
      return value
65
    } else {
66
      throw new InternalServerErrorException(
67
        'Could not read value of type "number"'
68
      )
69
    }
70
  }
71

72
  public readFloat(validate = true): number {
73
    if (validate) {
74
      this.validateType(GodotTypes.FLOAT)
75
    }
76
    if (this.dataView.byteLength > this.index) {
77
      const value = this.dataView.getFloat32(this.index, true)
78
      this.index += 4
79
      return value
80
    } else {
81
      throw new InternalServerErrorException(
82
        'Could not read value of type "float"'
83
      )
84
    }
85
  }
86

87
  private readStringLength(): number {
88
    const length = this.dataView.getInt32(this.index, true)
89
    this.index += 4
90
    return length
91
  }
92

93
  public readString(validate = true): string {
94
    if (validate) {
95
      this.validateType(GodotTypes.STRING)
96
    }
97
    const length = this.readStringLength()
98

99
    const textDecoder = new TextDecoder('ascii')
100
    const slice = this.dataView.buffer.slice(this.index, this.index + length)
101
    this.dataView.byteOffset
102
    const str = textDecoder.decode(slice)
103
    if (/[\u0080-\uffff]/.test(str)) {
104
      throw new Error('this string seems to contain (still encoded) multibytes')
105
    }
106
    this.index += Math.ceil(length / 4) * 4
107
    return str
108
  }
109

110
  public readVector3(validate = true): IVector3 {
111
    if (validate) {
112
      this.validateType(GodotTypes.VECTOR3)
113
    }
114
    const x = this.readFloat(false)
115
    const y = this.readFloat(false)
116
    const z = this.readFloat(false)
117
    return {
118
      x,
119
      y,
120
      z
121
    }
122
  }
123

124
  public readBasis(validate = true): IBasis {
125
    if (validate) {
126
      this.validateType(GodotTypes.BASIS)
127
    }
128
    const x1 = this.readFloat(false)
129
    const y1 = this.readFloat(false)
130
    const z1 = this.readFloat(false)
131
    const x2 = this.readFloat(false)
132
    const y2 = this.readFloat(false)
133
    const z2 = this.readFloat(false)
134
    const x3 = this.readFloat(false)
135
    const y3 = this.readFloat(false)
136
    const z3 = this.readFloat(false)
137
    return {
138
      x1,
139
      y1,
140
      z1,
141
      x2,
142
      y2,
143
      z2,
144
      x3,
145
      y3,
146
      z3
147
    }
148
  }
149

150
  public readBool(validate = true) {
151
    if (validate) {
152
      this.validateType(GodotTypes.BOOL)
153
    }
154

155
    const num = this.readInt(false)
156
    const bool = Boolean(num)
157
    return bool
158
  }
159

160
  public readPoolByteArray(): Uint8Array {
161
    this.validateType(GodotTypes.POOL_BYTE_ARRAY)
162
    let length = this.readInt(false)
163
    length = (length / 4) * 4
164
    const uint8Array = new Uint8Array(length)
165
    for (let i = 0; i < length; i++) {
166
      const byte = this.dataView.getUint8(this.index + i)
167
      uint8Array[i] = byte
168
    }
169
    this.index += length
170
    return uint8Array
171
  }
172

173
  public readTransform(validate = true) {
174
    if (validate) {
175
      this.validateType(GodotTypes.TRANSFORM)
176
    }
177
    const basis = this.readBasis(false)
178
    const origin = this.readVector3(false)
179

180
    return {
181
      basis,
182
      origin
183
    }
184
  }
185

186
  public readDictionary<K, T>(keyFunc: () => K, valueFunc: () => T) {
187
    this.validateType(GodotTypes.DICTIONARY)
188
    const length = this.readInt(false)
189

190
    const boundKeyFunc = keyFunc.bind(this)
191
    const boundValueFunc = valueFunc.bind(this)
192

193
    const dictionary = new Map<string, ITransform>()
194
    for (let i = 0; i < length; i++) {
195
      const key = boundKeyFunc()
196
      const transform = boundValueFunc()
197
      dictionary.set(key, transform)
198
    }
199

200
    return dictionary
201
  }
202

203
  // Validates array start
204
  // Returns length
205
  public readArray(validate = true): number {
206
    if (validate) {
207
      this.validateType(GodotTypes.ARRAY)
208
    }
209
    const length = this.readInt(false)
210
    return length
211
  }
212

213
  public readAll(): any[] {
214
    const array: any[] = []
215
    try {
216
      while (this.hasNext()) {
217
        const value = this.readNext()
218
        if (value) {
219
          array.push(value)
220
        }
221
      }
222
    } catch {
223
      return array
224
    }
225
  }
226

227
  public readNext(): any | any[] {
228
    const type = this.readInt(false)
229
    let value: any | any[]
230
    switch (type) {
231
      case GodotTypes.INT:
232
        value = this.readInt(false)
233
        break
234
      case GodotTypes.ARRAY:
235
        const arrayLength = this.readArray(false)
236
        value = []
237
        for (let i = 0; i < arrayLength; i++) {
238
          value = this.readNext()
239
        }
240
        break
241
      case GodotTypes.BOOL:
242
        value = this.readBool(false)
243
        break
244
      case GodotTypes.STRING:
245
        value = this.readString(false)
246
        break
247
      case GodotTypes.VECTOR3:
248
        value = this.readVector3(false)
249
        break
250
      case GodotTypes.TRANSFORM:
251
        value = this.readTransform(false)
252
        break
253
      case GodotTypes.FLOAT:
254
        value = this.readFloat(false)
255
        break
256
      case GodotTypes.BASIS:
257
        value = this.readBasis(false)
258
        break
259
    }
260
    return value
261
  }
262

263
  public hasNext(): boolean {
264
    return this.index <= this.buffer.length
265
  }
266

267
  public getBuffer(): Buffer {
268
    return this.buffer
269
  }
270
}
271

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.