litenetlib-0952 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- litenetlib/__init__.py +66 -0
- litenetlib/channels/__init__.py +16 -0
- litenetlib/channels/base_channel.py +115 -0
- litenetlib/channels/reliable_channel.py +451 -0
- litenetlib/channels/sequenced_channel.py +239 -0
- litenetlib/core/__init__.py +53 -0
- litenetlib/core/connection_request.py +240 -0
- litenetlib/core/constants.py +186 -0
- litenetlib/core/events.py +336 -0
- litenetlib/core/internal_packets.py +358 -0
- litenetlib/core/manager.py +355 -0
- litenetlib/core/packet.py +457 -0
- litenetlib/core/peer.py +334 -0
- litenetlib/utils/__init__.py +21 -0
- litenetlib/utils/data_reader.py +447 -0
- litenetlib/utils/data_writer.py +402 -0
- litenetlib/utils/fast_bit_converter.py +199 -0
- litenetlib/utils/net_utils.py +165 -0
- litenetlib_0952-1.0.0.dist-info/METADATA +448 -0
- litenetlib_0952-1.0.0.dist-info/RECORD +23 -0
- litenetlib_0952-1.0.0.dist-info/WHEEL +5 -0
- litenetlib_0952-1.0.0.dist-info/licenses/LICENSE +21 -0
- litenetlib_0952-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Network data writer for serializing data to binary format.
|
|
3
|
+
|
|
4
|
+
Provides methods to write various data types in a compact binary format
|
|
5
|
+
compatible with LiteNetLib protocol.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import struct
|
|
9
|
+
import uuid
|
|
10
|
+
from typing import Union, Tuple, List, Optional
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class NetDataWriter:
|
|
14
|
+
"""
|
|
15
|
+
Binary data writer with auto-resizing buffer.
|
|
16
|
+
|
|
17
|
+
Uses little-endian byte order for multi-byte values.
|
|
18
|
+
All data is written as compactly as possible.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
__slots__ = ('_data', '_position', '_auto_resize', '_initial_size')
|
|
22
|
+
|
|
23
|
+
def __init__(self, auto_resize: bool = True, initial_size: int = 64):
|
|
24
|
+
"""
|
|
25
|
+
Create a new NetDataWriter.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
auto_resize: Automatically resize buffer when needed
|
|
29
|
+
initial_size: Initial buffer size in bytes
|
|
30
|
+
"""
|
|
31
|
+
self._data = bytearray(initial_size)
|
|
32
|
+
self._position = 0
|
|
33
|
+
self._auto_resize = auto_resize
|
|
34
|
+
self._initial_size = initial_size
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def from_bytes(cls, data: bytes, copy: bool = True) -> 'NetDataWriter':
|
|
38
|
+
"""
|
|
39
|
+
Create NetDataWriter from existing bytes.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
data: Source bytes
|
|
43
|
+
copy: Whether to copy the data or reuse the buffer
|
|
44
|
+
"""
|
|
45
|
+
writer = cls(auto_resize=True, initial_size=len(data) if copy else 0)
|
|
46
|
+
if copy:
|
|
47
|
+
writer._data = bytearray(data)
|
|
48
|
+
writer._position = len(data)
|
|
49
|
+
else:
|
|
50
|
+
writer._data = bytearray(data) # Still need to copy as bytearray
|
|
51
|
+
writer._position = len(data)
|
|
52
|
+
return writer
|
|
53
|
+
|
|
54
|
+
@classmethod
|
|
55
|
+
def from_string(cls, value: str) -> 'NetDataWriter':
|
|
56
|
+
"""Create NetDataWriter from a string."""
|
|
57
|
+
writer = cls()
|
|
58
|
+
writer.put(value)
|
|
59
|
+
return writer
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def capacity(self) -> int:
|
|
63
|
+
"""Get current buffer capacity."""
|
|
64
|
+
return len(self._data)
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def data(self) -> bytearray:
|
|
68
|
+
"""Get underlying data buffer."""
|
|
69
|
+
return self._data
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def length(self) -> int:
|
|
73
|
+
"""Get current data length (position)."""
|
|
74
|
+
return self._position
|
|
75
|
+
|
|
76
|
+
def reset(self, size: Optional[int] = None) -> None:
|
|
77
|
+
"""
|
|
78
|
+
Reset writer position.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
size: If provided, ensure buffer is at least this size
|
|
82
|
+
"""
|
|
83
|
+
if size is not None:
|
|
84
|
+
self._ensure_capacity(size)
|
|
85
|
+
self._position = 0
|
|
86
|
+
|
|
87
|
+
def set_position(self, position: int) -> int:
|
|
88
|
+
"""
|
|
89
|
+
Set writer position.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
position: New position
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
Previous position
|
|
96
|
+
"""
|
|
97
|
+
prev = self._position
|
|
98
|
+
self._position = position
|
|
99
|
+
return prev
|
|
100
|
+
|
|
101
|
+
def copy_data(self) -> bytes:
|
|
102
|
+
"""Copy written data to new bytes object."""
|
|
103
|
+
return bytes(self._data[:self._position])
|
|
104
|
+
|
|
105
|
+
def to_bytes(self) -> bytes:
|
|
106
|
+
"""Get written data as bytes."""
|
|
107
|
+
return bytes(self._data[:self._position])
|
|
108
|
+
|
|
109
|
+
def _ensure_capacity(self, size: int) -> None:
|
|
110
|
+
"""Ensure buffer has enough capacity."""
|
|
111
|
+
if len(self._data) < size:
|
|
112
|
+
new_size = max(size, len(self._data) * 2)
|
|
113
|
+
self._data.extend(b'\x00' * (new_size - len(self._data)))
|
|
114
|
+
|
|
115
|
+
def _resize_if_needed(self, additional_size: int) -> None:
|
|
116
|
+
"""Resize buffer if needed for additional data."""
|
|
117
|
+
if self._auto_resize:
|
|
118
|
+
self._ensure_capacity(self._position + additional_size)
|
|
119
|
+
|
|
120
|
+
# Basic types
|
|
121
|
+
|
|
122
|
+
def put_byte(self, value: int) -> None:
|
|
123
|
+
"""Write a single byte."""
|
|
124
|
+
self._resize_if_needed(1)
|
|
125
|
+
self._data[self._position] = value & 0xFF
|
|
126
|
+
self._position += 1
|
|
127
|
+
|
|
128
|
+
def put_sbyte(self, value: int) -> None:
|
|
129
|
+
"""Write a signed byte."""
|
|
130
|
+
self.put_byte(value & 0xFF)
|
|
131
|
+
|
|
132
|
+
def put_bool(self, value: bool) -> None:
|
|
133
|
+
"""Write a boolean as a single byte (0 or 1)."""
|
|
134
|
+
self.put_byte(1 if value else 0)
|
|
135
|
+
|
|
136
|
+
def put_short(self, value: int) -> None:
|
|
137
|
+
"""Write a 16-bit signed integer."""
|
|
138
|
+
self._resize_if_needed(2)
|
|
139
|
+
struct.pack_into('<h', self._data, self._position, value)
|
|
140
|
+
self._position += 2
|
|
141
|
+
|
|
142
|
+
def put_ushort(self, value: int) -> None:
|
|
143
|
+
"""Write a 16-bit unsigned integer."""
|
|
144
|
+
self._resize_if_needed(2)
|
|
145
|
+
struct.pack_into('<H', self._data, self._position, value)
|
|
146
|
+
self._position += 2
|
|
147
|
+
|
|
148
|
+
def put_int(self, value: int) -> None:
|
|
149
|
+
"""Write a 32-bit signed integer."""
|
|
150
|
+
self._resize_if_needed(4)
|
|
151
|
+
struct.pack_into('<i', self._data, self._position, value)
|
|
152
|
+
self._position += 4
|
|
153
|
+
|
|
154
|
+
def put_uint(self, value: int) -> None:
|
|
155
|
+
"""Write a 32-bit unsigned integer."""
|
|
156
|
+
self._resize_if_needed(4)
|
|
157
|
+
struct.pack_into('<I', self._data, self._position, value)
|
|
158
|
+
self._position += 4
|
|
159
|
+
|
|
160
|
+
def put_long(self, value: int) -> None:
|
|
161
|
+
"""Write a 64-bit signed integer."""
|
|
162
|
+
self._resize_if_needed(8)
|
|
163
|
+
struct.pack_into('<q', self._data, self._position, value)
|
|
164
|
+
self._position += 8
|
|
165
|
+
|
|
166
|
+
def put_ulong(self, value: int) -> None:
|
|
167
|
+
"""Write a 64-bit unsigned integer."""
|
|
168
|
+
self._resize_if_needed(8)
|
|
169
|
+
struct.pack_into('<Q', self._data, self._position, value)
|
|
170
|
+
self._position += 8
|
|
171
|
+
|
|
172
|
+
def put_float(self, value: float) -> None:
|
|
173
|
+
"""Write a 32-bit float."""
|
|
174
|
+
self._resize_if_needed(4)
|
|
175
|
+
struct.pack_into('<f', self._data, self._position, value)
|
|
176
|
+
self._position += 4
|
|
177
|
+
|
|
178
|
+
def put_double(self, value: float) -> None:
|
|
179
|
+
"""Write a 64-bit double."""
|
|
180
|
+
self._resize_if_needed(8)
|
|
181
|
+
struct.pack_into('<d', self._data, self._position, value)
|
|
182
|
+
self._position += 8
|
|
183
|
+
|
|
184
|
+
def put_char(self, value: str) -> None:
|
|
185
|
+
"""Write a single character as ushort."""
|
|
186
|
+
self.put_ushort(ord(value[0]) if len(value) > 0 else 0)
|
|
187
|
+
|
|
188
|
+
# String types
|
|
189
|
+
|
|
190
|
+
def put_string(self, value: str, max_length: int = 0) -> None:
|
|
191
|
+
"""
|
|
192
|
+
Write a string with length prefix.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
value: String to write
|
|
196
|
+
max_length: Maximum character length (0 = no limit)
|
|
197
|
+
"""
|
|
198
|
+
if not value:
|
|
199
|
+
self.put_ushort(0)
|
|
200
|
+
return
|
|
201
|
+
|
|
202
|
+
# Truncate if max_length specified
|
|
203
|
+
if max_length > 0 and len(value) > max_length:
|
|
204
|
+
value = value[:max_length]
|
|
205
|
+
|
|
206
|
+
encoded = value.encode('utf-8')
|
|
207
|
+
size = len(encoded)
|
|
208
|
+
|
|
209
|
+
if size == 0:
|
|
210
|
+
self.put_ushort(0)
|
|
211
|
+
return
|
|
212
|
+
|
|
213
|
+
self.put_ushort(size + 1) # Size + 1 for non-empty string
|
|
214
|
+
self._resize_if_needed(size)
|
|
215
|
+
self._data[self._position:self._position + size] = encoded
|
|
216
|
+
self._position += size
|
|
217
|
+
|
|
218
|
+
def put_large_string(self, value: str) -> None:
|
|
219
|
+
"""
|
|
220
|
+
Write a potentially large string with int length prefix.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
value: String to write
|
|
224
|
+
"""
|
|
225
|
+
if not value:
|
|
226
|
+
self.put_int(0)
|
|
227
|
+
return
|
|
228
|
+
|
|
229
|
+
encoded = value.encode('utf-8')
|
|
230
|
+
size = len(encoded)
|
|
231
|
+
|
|
232
|
+
if size == 0:
|
|
233
|
+
self.put_int(0)
|
|
234
|
+
return
|
|
235
|
+
|
|
236
|
+
self.put_int(size)
|
|
237
|
+
self._resize_if_needed(size)
|
|
238
|
+
self._data[self._position:self._position + size] = encoded
|
|
239
|
+
self._position += size
|
|
240
|
+
|
|
241
|
+
# Bytes and arrays
|
|
242
|
+
|
|
243
|
+
def put_bytes(self, data: bytes, offset: int = 0, length: Optional[int] = None) -> None:
|
|
244
|
+
"""
|
|
245
|
+
Write raw bytes.
|
|
246
|
+
|
|
247
|
+
Args:
|
|
248
|
+
data: Bytes to write
|
|
249
|
+
offset: Starting offset in data
|
|
250
|
+
length: Number of bytes to write (None = all remaining)
|
|
251
|
+
"""
|
|
252
|
+
if length is None:
|
|
253
|
+
length = len(data) - offset
|
|
254
|
+
self._resize_if_needed(length)
|
|
255
|
+
self._data[self._position:self._position + length] = data[offset:offset + length]
|
|
256
|
+
self._position += length
|
|
257
|
+
|
|
258
|
+
def put_bytes_with_length(self, data: bytes) -> None:
|
|
259
|
+
"""Write bytes with ushort length prefix."""
|
|
260
|
+
length = len(data)
|
|
261
|
+
self.put_ushort(length)
|
|
262
|
+
self.put_bytes(data)
|
|
263
|
+
|
|
264
|
+
def put_array(self, arr: Optional[List], element_size: int = 1) -> None:
|
|
265
|
+
"""
|
|
266
|
+
Write an array with length prefix.
|
|
267
|
+
|
|
268
|
+
Args:
|
|
269
|
+
arr: Array to write (None writes length 0)
|
|
270
|
+
element_size: Size of each element in bytes
|
|
271
|
+
"""
|
|
272
|
+
length = len(arr) if arr is not None else 0
|
|
273
|
+
total_size = length * element_size
|
|
274
|
+
self._resize_if_needed(2 + total_size)
|
|
275
|
+
self.put_ushort(length)
|
|
276
|
+
|
|
277
|
+
if arr and total_size > 0:
|
|
278
|
+
# Handle different element types
|
|
279
|
+
if element_size == 1:
|
|
280
|
+
# bytes or bool or small integers
|
|
281
|
+
for item in arr:
|
|
282
|
+
if isinstance(item, bool):
|
|
283
|
+
self.put_byte(1 if item else 0)
|
|
284
|
+
else:
|
|
285
|
+
# Preserve integer values (0-255)
|
|
286
|
+
self.put_byte(item & 0xFF)
|
|
287
|
+
elif element_size == 2:
|
|
288
|
+
# shorts or ushorts
|
|
289
|
+
for item in arr:
|
|
290
|
+
self.put_short(item) if isinstance(item, int) and item < 0 else self.put_ushort(item)
|
|
291
|
+
elif element_size == 4:
|
|
292
|
+
# ints or floats
|
|
293
|
+
for item in arr:
|
|
294
|
+
if isinstance(item, float):
|
|
295
|
+
self.put_float(item)
|
|
296
|
+
else:
|
|
297
|
+
self.put_int(item)
|
|
298
|
+
elif element_size == 8:
|
|
299
|
+
# longs, ulongs, or doubles
|
|
300
|
+
for item in arr:
|
|
301
|
+
if isinstance(item, float):
|
|
302
|
+
self.put_double(item)
|
|
303
|
+
else:
|
|
304
|
+
self.put_long(item)
|
|
305
|
+
|
|
306
|
+
def put_string_array(self, arr: Optional[List[str]], max_length: int = 0) -> None:
|
|
307
|
+
"""
|
|
308
|
+
Write an array of strings.
|
|
309
|
+
|
|
310
|
+
Args:
|
|
311
|
+
arr: Array of strings (None writes length 0)
|
|
312
|
+
max_length: Maximum length for each string
|
|
313
|
+
"""
|
|
314
|
+
length = len(arr) if arr is not None else 0
|
|
315
|
+
self.put_ushort(length)
|
|
316
|
+
|
|
317
|
+
if arr:
|
|
318
|
+
for s in arr:
|
|
319
|
+
self.put_string(s, max_length)
|
|
320
|
+
|
|
321
|
+
# Special types
|
|
322
|
+
|
|
323
|
+
def put_uuid(self, value: uuid.UUID) -> None:
|
|
324
|
+
"""Write a UUID (16 bytes)."""
|
|
325
|
+
self._resize_if_needed(16)
|
|
326
|
+
self._data[self._position:self._position + 16] = value.bytes
|
|
327
|
+
self._position += 16
|
|
328
|
+
|
|
329
|
+
def put_ip_end_point(self, address: str, port: int, family: str = 'IPv4') -> None:
|
|
330
|
+
"""
|
|
331
|
+
Write an IP endpoint.
|
|
332
|
+
|
|
333
|
+
Args:
|
|
334
|
+
address: IP address string
|
|
335
|
+
port: Port number
|
|
336
|
+
family: 'IPv4' or 'IPv6'
|
|
337
|
+
"""
|
|
338
|
+
import socket
|
|
339
|
+
|
|
340
|
+
# Normalize family string to handle both 'IPv4' and 'IPV4'
|
|
341
|
+
family_upper = family.upper()
|
|
342
|
+
if family_upper == 'IPV4':
|
|
343
|
+
family_upper = 'IPv4'
|
|
344
|
+
elif family_upper == 'IPV6':
|
|
345
|
+
family_upper = 'IPv6'
|
|
346
|
+
|
|
347
|
+
if family_upper == 'IPv4':
|
|
348
|
+
self.put_byte(0)
|
|
349
|
+
addr_bytes = socket.inet_pton(socket.AF_INET, address)
|
|
350
|
+
elif family_upper == 'IPv6':
|
|
351
|
+
self.put_byte(1)
|
|
352
|
+
addr_bytes = socket.inet_pton(socket.AF_INET6, address)
|
|
353
|
+
else:
|
|
354
|
+
raise ValueError(f"Unsupported address family: {family}")
|
|
355
|
+
|
|
356
|
+
self.put_bytes(addr_bytes)
|
|
357
|
+
self.put_ushort(port)
|
|
358
|
+
|
|
359
|
+
# Convenience methods
|
|
360
|
+
|
|
361
|
+
def put(self, value) -> None:
|
|
362
|
+
"""
|
|
363
|
+
Write a value based on its type.
|
|
364
|
+
|
|
365
|
+
This is a convenience method that automatically selects
|
|
366
|
+
the appropriate put_* method based on the value type.
|
|
367
|
+
"""
|
|
368
|
+
if isinstance(value, bool):
|
|
369
|
+
self.put_bool(value)
|
|
370
|
+
elif isinstance(value, int):
|
|
371
|
+
# Determine best integer size
|
|
372
|
+
if -128 <= value <= 127:
|
|
373
|
+
self.put_sbyte(value)
|
|
374
|
+
elif -32768 <= value <= 32767:
|
|
375
|
+
self.put_short(value)
|
|
376
|
+
elif -2147483648 <= value <= 2147483647:
|
|
377
|
+
self.put_int(value)
|
|
378
|
+
else:
|
|
379
|
+
self.put_long(value)
|
|
380
|
+
elif isinstance(value, float):
|
|
381
|
+
self.put_float(value)
|
|
382
|
+
elif isinstance(value, str):
|
|
383
|
+
self.put_string(value)
|
|
384
|
+
elif isinstance(value, bytes):
|
|
385
|
+
self.put_bytes_with_length(value)
|
|
386
|
+
elif isinstance(value, (list, tuple)):
|
|
387
|
+
# Try to determine element type and size
|
|
388
|
+
if value and isinstance(value[0], str):
|
|
389
|
+
self.put_string_array(list(value))
|
|
390
|
+
else:
|
|
391
|
+
# Default to int array
|
|
392
|
+
self.put_array(list(value), 4)
|
|
393
|
+
elif isinstance(value, uuid.UUID):
|
|
394
|
+
self.put_uuid(value)
|
|
395
|
+
else:
|
|
396
|
+
raise TypeError(f"Unsupported type: {type(value)}")
|
|
397
|
+
|
|
398
|
+
def __len__(self) -> int:
|
|
399
|
+
return self._position
|
|
400
|
+
|
|
401
|
+
def __repr__(self) -> str:
|
|
402
|
+
return f"NetDataWriter(position={self._position}, capacity={len(self._data)})"
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Fast binary converter for exact C# compatibility / 快速二进制转换器,与 C# 完全兼容
|
|
3
|
+
|
|
4
|
+
This module provides little-endian binary encoding that exactly matches
|
|
5
|
+
the C# FastBitConverter implementation. All multi-byte values use
|
|
6
|
+
little-endian byte order for protocol compatibility.
|
|
7
|
+
|
|
8
|
+
本模块提供与 C# FastBitConverter 实现完全匹配的小端二进制编码。
|
|
9
|
+
所有多字节值使用小端字节序以确保协议兼容性。
|
|
10
|
+
|
|
11
|
+
Ported from: LiteNetLib/Utils/FastBitConverter.cs
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import struct
|
|
15
|
+
from typing import Union
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class FastBitConverter:
|
|
19
|
+
"""
|
|
20
|
+
Fast little-endian binary converter / 快速小端二进制转换器
|
|
21
|
+
|
|
22
|
+
Provides methods to write primitive types to byte arrays in little-endian
|
|
23
|
+
format, exactly matching the C# implementation for protocol compatibility.
|
|
24
|
+
|
|
25
|
+
提供将基本类型以小端格式写入字节数组的方法,与 C# 实现完全匹配。
|
|
26
|
+
|
|
27
|
+
C# Reference: FastBitConverter.GetBytes(byte[], int, T value)
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
__slots__ = ()
|
|
31
|
+
|
|
32
|
+
@staticmethod
|
|
33
|
+
def get_bytes(buffer: bytearray, offset: int, value: int) -> None:
|
|
34
|
+
"""
|
|
35
|
+
Write integer (32-bit) to buffer at offset.
|
|
36
|
+
写入 32 位整数到缓冲区指定位置。
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
buffer: Target byte array / 目标字节数组
|
|
40
|
+
offset: Starting position in buffer / 缓冲区起始位置
|
|
41
|
+
value: Integer value to write / 要写入的整数值
|
|
42
|
+
|
|
43
|
+
C# Equivalent: GetBytes(byte[] bytes, int startIndex, int value)
|
|
44
|
+
"""
|
|
45
|
+
struct.pack_into('<i', buffer, offset, value)
|
|
46
|
+
|
|
47
|
+
@staticmethod
|
|
48
|
+
def get_bytes_uint(buffer: bytearray, offset: int, value: int) -> None:
|
|
49
|
+
"""
|
|
50
|
+
Write unsigned integer (32-bit) to buffer at offset.
|
|
51
|
+
写入 32 位无符号整数到缓冲区指定位置。
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
buffer: Target byte array / 目标字节数组
|
|
55
|
+
offset: Starting position in buffer / 缓冲区起始位置
|
|
56
|
+
value: Unsigned integer value to write / 要写入的无符号整数值
|
|
57
|
+
|
|
58
|
+
C# Equivalent: GetBytes(byte[] bytes, int startIndex, uint value)
|
|
59
|
+
"""
|
|
60
|
+
struct.pack_into('<I', buffer, offset, value)
|
|
61
|
+
|
|
62
|
+
@staticmethod
|
|
63
|
+
def get_bytes_ushort(buffer: bytearray, offset: int, value: int) -> None:
|
|
64
|
+
"""
|
|
65
|
+
Write unsigned short (16-bit) to buffer at offset.
|
|
66
|
+
写入 16 位无符号短整数到缓冲区指定位置。
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
buffer: Target byte array / 目标字节数组
|
|
70
|
+
offset: Starting position in buffer / 缓冲区起始位置
|
|
71
|
+
value: Unsigned short value to write / 要写入的无符号短整数值
|
|
72
|
+
|
|
73
|
+
C# Equivalent: GetBytes(byte[] bytes, int startIndex, ushort value)
|
|
74
|
+
"""
|
|
75
|
+
struct.pack_into('<H', buffer, offset, value)
|
|
76
|
+
|
|
77
|
+
@staticmethod
|
|
78
|
+
def get_bytes_short(buffer: bytearray, offset: int, value: int) -> None:
|
|
79
|
+
"""
|
|
80
|
+
Write short (16-bit) to buffer at offset.
|
|
81
|
+
写入 16 位短整数到缓冲区指定位置。
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
buffer: Target byte array / 目标字节数组
|
|
85
|
+
offset: Starting position in buffer / 缓冲区起始位置
|
|
86
|
+
value: Short value to write / 要写入的短整数值
|
|
87
|
+
|
|
88
|
+
C# Equivalent: GetBytes(byte[] bytes, int startIndex, short value)
|
|
89
|
+
"""
|
|
90
|
+
struct.pack_into('<h', buffer, offset, value)
|
|
91
|
+
|
|
92
|
+
@staticmethod
|
|
93
|
+
def get_bytes_long(buffer: bytearray, offset: int, value: int) -> None:
|
|
94
|
+
"""
|
|
95
|
+
Write long (64-bit) to buffer at offset.
|
|
96
|
+
写入 64 位长整数到缓冲区指定位置。
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
buffer: Target byte array / 目标字节数组
|
|
100
|
+
offset: Starting position in buffer / 缓冲区起始位置
|
|
101
|
+
value: Long value to write / 要写入的长整数值
|
|
102
|
+
|
|
103
|
+
C# Equivalent: GetBytes(byte[] bytes, int startIndex, long value)
|
|
104
|
+
"""
|
|
105
|
+
struct.pack_into('<q', buffer, offset, value)
|
|
106
|
+
|
|
107
|
+
@staticmethod
|
|
108
|
+
def get_bytes_ulong(buffer: bytearray, offset: int, value: int) -> None:
|
|
109
|
+
"""
|
|
110
|
+
Write unsigned long (64-bit) to buffer at offset.
|
|
111
|
+
写入 64 位无符号长整数到缓冲区指定位置。
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
buffer: Target byte array / 目标字节数组
|
|
115
|
+
offset: Starting position in buffer / 缓冲区起始位置
|
|
116
|
+
value: Unsigned long value to write / 要写入的无符号长整数值
|
|
117
|
+
|
|
118
|
+
C# Equivalent: GetBytes(byte[] bytes, int startIndex, ulong value)
|
|
119
|
+
"""
|
|
120
|
+
struct.pack_into('<Q', buffer, offset, value)
|
|
121
|
+
|
|
122
|
+
@staticmethod
|
|
123
|
+
def get_bytes_float(buffer: bytearray, offset: int, value: float) -> None:
|
|
124
|
+
"""
|
|
125
|
+
Write float (32-bit IEEE 754) to buffer at offset.
|
|
126
|
+
写入 32 位 IEEE 754 浮点数到缓冲区指定位置。
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
buffer: Target byte array / 目标字节数组
|
|
130
|
+
offset: Starting position in buffer / 缓冲区起始位置
|
|
131
|
+
value: Float value to write / 要写入的浮点数值
|
|
132
|
+
|
|
133
|
+
C# Equivalent: GetBytes(byte[] bytes, int startIndex, float value)
|
|
134
|
+
|
|
135
|
+
Note: Uses struct.pack with '<f' for exact IEEE 754 binary representation
|
|
136
|
+
matching C# float encoding.
|
|
137
|
+
注意:使用 struct.pack 的 '<f' 格式以实现与 C# float 编码完全匹配的 IEEE 754 二进制表示。
|
|
138
|
+
"""
|
|
139
|
+
struct.pack_into('<f', buffer, offset, value)
|
|
140
|
+
|
|
141
|
+
@staticmethod
|
|
142
|
+
def get_bytes_double(buffer: bytearray, offset: int, value: float) -> None:
|
|
143
|
+
"""
|
|
144
|
+
Write double (64-bit IEEE 754) to buffer at offset.
|
|
145
|
+
写入 64 位 IEEE 754 双精度浮点数到缓冲区指定位置。
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
buffer: Target byte array / 目标字节数组
|
|
149
|
+
offset: Starting position in buffer / 缓冲区起始位置
|
|
150
|
+
value: Double value to write / 要写入的双精度浮点数值
|
|
151
|
+
|
|
152
|
+
C# Equivalent: GetBytes(byte[] bytes, int startIndex, double value)
|
|
153
|
+
|
|
154
|
+
Note: Uses struct.pack with '<d' for exact IEEE 754 binary representation
|
|
155
|
+
matching C# double encoding.
|
|
156
|
+
注意:使用 struct.pack 的 '<d' 格式以实现与 C# double 编码完全匹配的 IEEE 754 二进制表示。
|
|
157
|
+
"""
|
|
158
|
+
struct.pack_into('<d', buffer, offset, value)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
# Convenience functions / 便捷函数
|
|
162
|
+
def write_int16(buffer: bytearray, offset: int, value: int) -> None:
|
|
163
|
+
"""Write signed 16-bit integer / 写入有符号 16 位整数"""
|
|
164
|
+
FastBitConverter.get_bytes_short(buffer, offset, value)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def write_uint16(buffer: bytearray, offset: int, value: int) -> None:
|
|
168
|
+
"""Write unsigned 16-bit integer / 写入无符号 16 位整数"""
|
|
169
|
+
FastBitConverter.get_bytes_ushort(buffer, offset, value)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def write_int32(buffer: bytearray, offset: int, value: int) -> None:
|
|
173
|
+
"""Write signed 32-bit integer / 写入有符号 32 位整数"""
|
|
174
|
+
FastBitConverter.get_bytes(buffer, offset, value)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def write_uint32(buffer: bytearray, offset: int, value: int) -> None:
|
|
178
|
+
"""Write unsigned 32-bit integer / 写入无符号 32 位整数"""
|
|
179
|
+
FastBitConverter.get_bytes_uint(buffer, offset, value)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def write_int64(buffer: bytearray, offset: int, value: int) -> None:
|
|
183
|
+
"""Write signed 64-bit integer / 写入有符号 64 位整数"""
|
|
184
|
+
FastBitConverter.get_bytes_long(buffer, offset, value)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def write_uint64(buffer: bytearray, offset: int, value: int) -> None:
|
|
188
|
+
"""Write unsigned 64-bit integer / 写入无符号 64 位整数"""
|
|
189
|
+
FastBitConverter.get_bytes_ulong(buffer, offset, value)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def write_float32(buffer: bytearray, offset: int, value: float) -> None:
|
|
193
|
+
"""Write 32-bit float / 写入 32 位浮点数"""
|
|
194
|
+
FastBitConverter.get_bytes_float(buffer, offset, value)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def write_float64(buffer: bytearray, offset: int, value: float) -> None:
|
|
198
|
+
"""Write 64-bit double / 写入 64 位双精度浮点数"""
|
|
199
|
+
FastBitConverter.get_bytes_double(buffer, offset, value)
|